mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-12-16 17:12:53 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34c3147264 | ||
|
|
1cf57c822d | ||
|
|
edfac357b9 | ||
|
|
2e5dfd8bab | ||
|
|
53da79ae46 | ||
|
|
e258772242 | ||
|
|
0a5bf9cf03 | ||
|
|
ac7c865b67 | ||
|
|
ff6a8fa4d7 | ||
|
|
802d6136d6 | ||
|
|
7e8bb9752c | ||
|
|
3fb0197e99 | ||
|
|
7127b2da93 | ||
|
|
48b3699591 |
@@ -1,13 +1,13 @@
|
|||||||
from django_filters import rest_framework as drf_filters
|
from django_filters import rest_framework as drf_filters
|
||||||
|
|
||||||
from assets.const import Protocol
|
|
||||||
from accounts import serializers
|
from accounts import serializers
|
||||||
from accounts.models import AccountTemplate
|
from accounts.models import AccountTemplate
|
||||||
from orgs.mixins.api import OrgBulkModelViewSet
|
from assets.const import Protocol
|
||||||
from rbac.permissions import RBACPermission
|
from common.drf.filters import BaseFilterSet
|
||||||
from common.permissions import UserConfirmation, ConfirmType
|
from common.permissions import UserConfirmation, ConfirmType
|
||||||
from common.views.mixins import RecordViewLogMixin
|
from common.views.mixins import RecordViewLogMixin
|
||||||
from common.drf.filters import BaseFilterSet
|
from orgs.mixins.api import OrgBulkModelViewSet
|
||||||
|
from rbac.permissions import RBACPermission
|
||||||
|
|
||||||
|
|
||||||
class AccountTemplateFilterSet(BaseFilterSet):
|
class AccountTemplateFilterSet(BaseFilterSet):
|
||||||
@@ -27,6 +27,8 @@ class AccountTemplateFilterSet(BaseFilterSet):
|
|||||||
continue
|
continue
|
||||||
_st = protocol_secret_type_map[p].get('secret_types', [])
|
_st = protocol_secret_type_map[p].get('secret_types', [])
|
||||||
secret_types.update(_st)
|
secret_types.update(_st)
|
||||||
|
if not secret_types:
|
||||||
|
secret_types = ['password']
|
||||||
queryset = queryset.filter(secret_type__in=secret_types)
|
queryset = queryset.filter(secret_type__in=secret_types)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ class ChangeSecretMixin(models.Model):
|
|||||||
default=SSHKeyStrategy.add, verbose_name=_('SSH key change strategy')
|
default=SSHKeyStrategy.add, verbose_name=_('SSH key change strategy')
|
||||||
)
|
)
|
||||||
|
|
||||||
accounts: list[str] # account usernames
|
|
||||||
get_all_assets: callable # get all assets
|
get_all_assets: callable # get all assets
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ from rest_framework import serializers
|
|||||||
|
|
||||||
from acls.models.base import ActionChoices
|
from acls.models.base import ActionChoices
|
||||||
from common.serializers.fields import LabeledChoiceField, ObjectRelatedField
|
from common.serializers.fields import LabeledChoiceField, ObjectRelatedField
|
||||||
|
from jumpserver.utils import has_valid_xpack_license
|
||||||
from orgs.models import Organization
|
from orgs.models import Organization
|
||||||
from users.models import User
|
from users.models import User
|
||||||
|
|
||||||
@@ -51,7 +52,26 @@ class ACLAccountsSerializer(serializers.Serializer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BaseUserAssetAccountACLSerializerMixin(serializers.Serializer):
|
class ActionAclSerializer(serializers.Serializer):
|
||||||
|
action = LabeledChoiceField(
|
||||||
|
choices=ActionChoices.choices, default=ActionChoices.reject, label=_("Action")
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.set_action_choices()
|
||||||
|
|
||||||
|
def set_action_choices(self):
|
||||||
|
action = self.fields.get("action")
|
||||||
|
if not action:
|
||||||
|
return
|
||||||
|
choices = action.choices
|
||||||
|
if not has_valid_xpack_license():
|
||||||
|
choices.pop(ActionChoices.review, None)
|
||||||
|
action._choices = choices
|
||||||
|
|
||||||
|
|
||||||
|
class BaseUserAssetAccountACLSerializerMixin(ActionAclSerializer, serializers.Serializer):
|
||||||
users = ACLUsersSerializer(label=_('User'))
|
users = ACLUsersSerializer(label=_('User'))
|
||||||
assets = ACLAssestsSerializer(label=_('Asset'))
|
assets = ACLAssestsSerializer(label=_('Asset'))
|
||||||
accounts = ACLAccountsSerializer(label=_('Account'))
|
accounts = ACLAccountsSerializer(label=_('Account'))
|
||||||
@@ -77,9 +97,6 @@ class BaseUserAssetAccountACLSerializerMixin(serializers.Serializer):
|
|||||||
reviewers_amount = serializers.IntegerField(
|
reviewers_amount = serializers.IntegerField(
|
||||||
read_only=True, source="reviewers.count", label=_('Reviewers amount')
|
read_only=True, source="reviewers.count", label=_('Reviewers amount')
|
||||||
)
|
)
|
||||||
action = LabeledChoiceField(
|
|
||||||
choices=ActionChoices.choices, default=ActionChoices.reject, label=_("Action")
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
fields_mini = ["id", "name"]
|
fields_mini = ["id", "name"]
|
||||||
|
|||||||
@@ -2,12 +2,11 @@ from django.utils.translation import ugettext as _
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from common.serializers import BulkModelSerializer, MethodSerializer
|
from common.serializers import BulkModelSerializer, MethodSerializer
|
||||||
from common.serializers.fields import ObjectRelatedField, LabeledChoiceField
|
from common.serializers.fields import ObjectRelatedField
|
||||||
from jumpserver.utils import has_valid_xpack_license
|
|
||||||
from users.models import User
|
from users.models import User
|
||||||
|
from .base import ActionAclSerializer
|
||||||
from .rules import RuleSerializer
|
from .rules import RuleSerializer
|
||||||
from ..models import LoginACL
|
from ..models import LoginACL
|
||||||
from ..models.base import ActionChoices
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"LoginACLSerializer",
|
"LoginACLSerializer",
|
||||||
@@ -18,12 +17,11 @@ common_help_text = _(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class LoginACLSerializer(BulkModelSerializer):
|
class LoginACLSerializer(ActionAclSerializer, BulkModelSerializer):
|
||||||
user = ObjectRelatedField(queryset=User.objects, label=_("User"))
|
user = ObjectRelatedField(queryset=User.objects, label=_("User"))
|
||||||
reviewers = ObjectRelatedField(
|
reviewers = ObjectRelatedField(
|
||||||
queryset=User.objects, label=_("Reviewers"), many=True, required=False
|
queryset=User.objects, label=_("Reviewers"), many=True, required=False
|
||||||
)
|
)
|
||||||
action = LabeledChoiceField(choices=ActionChoices.choices, label=_('Action'))
|
|
||||||
reviewers_amount = serializers.IntegerField(
|
reviewers_amount = serializers.IntegerField(
|
||||||
read_only=True, source="reviewers.count", label=_("Reviewers amount")
|
read_only=True, source="reviewers.count", label=_("Reviewers amount")
|
||||||
)
|
)
|
||||||
@@ -45,18 +43,5 @@ class LoginACLSerializer(BulkModelSerializer):
|
|||||||
"is_active": {"default": True},
|
"is_active": {"default": True},
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
self.set_action_choices()
|
|
||||||
|
|
||||||
def set_action_choices(self):
|
|
||||||
action = self.fields.get("action")
|
|
||||||
if not action:
|
|
||||||
return
|
|
||||||
choices = action.choices
|
|
||||||
if not has_valid_xpack_license():
|
|
||||||
choices.pop(LoginACL.ActionChoices.review, None)
|
|
||||||
action._choices = choices
|
|
||||||
|
|
||||||
def get_rules_serializer(self):
|
def get_rules_serializer(self):
|
||||||
return RuleSerializer()
|
return RuleSerializer()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ from rest_framework.decorators import action
|
|||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from common.api import JMSGenericViewSet
|
from common.api import JMSGenericViewSet
|
||||||
|
from common.permissions import IsValidUser
|
||||||
from assets.serializers import CategorySerializer, TypeSerializer
|
from assets.serializers import CategorySerializer, TypeSerializer
|
||||||
from assets.const import AllTypes
|
from assets.const import AllTypes
|
||||||
|
|
||||||
@@ -14,7 +15,7 @@ class CategoryViewSet(ListModelMixin, JMSGenericViewSet):
|
|||||||
'default': CategorySerializer,
|
'default': CategorySerializer,
|
||||||
'types': TypeSerializer
|
'types': TypeSerializer
|
||||||
}
|
}
|
||||||
permission_classes = ()
|
permission_classes = (IsValidUser,)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return AllTypes.categories()
|
return AllTypes.categories()
|
||||||
|
|||||||
@@ -57,11 +57,23 @@ class SerializeToTreeNodeMixin:
|
|||||||
]
|
]
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@lazyproperty
|
||||||
|
def support_types(self):
|
||||||
|
from assets.const import AllTypes
|
||||||
|
return AllTypes.get_types_values(exclude_custom=True)
|
||||||
|
|
||||||
|
def get_icon(self, asset):
|
||||||
|
if asset.type in self.support_types:
|
||||||
|
return asset.type
|
||||||
|
else:
|
||||||
|
return 'file'
|
||||||
|
|
||||||
@timeit
|
@timeit
|
||||||
def serialize_assets(self, assets, node_key=None):
|
def serialize_assets(self, assets, node_key=None):
|
||||||
sftp_enabled_platform = PlatformProtocol.objects \
|
sftp_enabled_platform = PlatformProtocol.objects \
|
||||||
.filter(name='ssh', setting__sftp_enabled=True) \
|
.filter(name='ssh', setting__sftp_enabled=True) \
|
||||||
.values_list('platform', flat=True).distinct()
|
.values_list('platform', flat=True) \
|
||||||
|
.distinct()
|
||||||
if node_key is None:
|
if node_key is None:
|
||||||
get_pid = lambda asset: getattr(asset, 'parent_key', '')
|
get_pid = lambda asset: getattr(asset, 'parent_key', '')
|
||||||
else:
|
else:
|
||||||
@@ -75,7 +87,7 @@ class SerializeToTreeNodeMixin:
|
|||||||
'pId': get_pid(asset),
|
'pId': get_pid(asset),
|
||||||
'isParent': False,
|
'isParent': False,
|
||||||
'open': False,
|
'open': False,
|
||||||
'iconSkin': asset.type,
|
'iconSkin': self.get_icon(asset),
|
||||||
'chkDisabled': not asset.is_active,
|
'chkDisabled': not asset.is_active,
|
||||||
'meta': {
|
'meta': {
|
||||||
'type': 'asset',
|
'type': 'asset',
|
||||||
|
|||||||
@@ -163,8 +163,10 @@ class CategoryTreeApi(SerializeToTreeNodeMixin, generics.ListAPIView):
|
|||||||
# 资源数量统计可选项 (asset, account)
|
# 资源数量统计可选项 (asset, account)
|
||||||
count_resource = self.request.query_params.get('count_resource', 'asset')
|
count_resource = self.request.query_params.get('count_resource', 'asset')
|
||||||
|
|
||||||
if include_asset and self.request.query_params.get('key'):
|
if not self.request.query_params.get('key'):
|
||||||
|
nodes = AllTypes.to_tree_nodes(include_asset, count_resource=count_resource)
|
||||||
|
elif include_asset:
|
||||||
nodes = self.get_assets()
|
nodes = self.get_assets()
|
||||||
else:
|
else:
|
||||||
nodes = AllTypes.to_tree_nodes(include_asset, count_resource=count_resource)
|
nodes = []
|
||||||
return Response(data=nodes)
|
return Response(data=nodes)
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ def get_platform_automation_methods(path):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
with open(path, 'r') as f:
|
with open(path, 'r') as f:
|
||||||
print("path: ", path)
|
|
||||||
manifest = yaml_load_with_i18n(f)
|
manifest = yaml_load_with_i18n(f)
|
||||||
check_platform_method(manifest, path)
|
check_platform_method(manifest, path)
|
||||||
manifest['dir'] = os.path.dirname(path)
|
manifest['dir'] = os.path.dirname(path)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class CustomTypes(BaseType):
|
|||||||
platforms = list(cls.get_custom_platforms())
|
platforms = list(cls.get_custom_platforms())
|
||||||
except Exception:
|
except Exception:
|
||||||
return []
|
return []
|
||||||
types = [p.type for p in platforms]
|
types = set([p.type for p in platforms])
|
||||||
return [(t, t) for t in types]
|
return [(t, t) for t in types]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -48,11 +48,7 @@ class CustomTypes(BaseType):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def internal_platforms(cls):
|
def internal_platforms(cls):
|
||||||
return {
|
return {}
|
||||||
# cls.PUBLIC: [],
|
|
||||||
# cls.PRIVATE: [{'name': 'Vmware-vSphere'}],
|
|
||||||
# cls.K8S: [{'name': 'Kubernetes'}],
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_custom_platforms(cls):
|
def get_custom_platforms(cls):
|
||||||
|
|||||||
@@ -151,15 +151,18 @@ class AllTypes(ChoicesMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_types(cls):
|
def get_types(cls, exclude_custom=False):
|
||||||
choices = []
|
choices = []
|
||||||
for i in dict(cls.category_types()).values():
|
|
||||||
choices.extend(i.get_types())
|
for name, tp in dict(cls.category_types()).items():
|
||||||
|
if name == Category.CUSTOM and exclude_custom:
|
||||||
|
continue
|
||||||
|
choices.extend(tp.get_types())
|
||||||
return choices
|
return choices
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_types_values(cls):
|
def get_types_values(cls, exclude_custom=False):
|
||||||
choices = cls.get_types()
|
choices = cls.get_types(exclude_custom=exclude_custom)
|
||||||
return [c.value for c in choices]
|
return [c.value for c in choices]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@@ -20,12 +20,13 @@ def get_prop_name_id(apps, app, category):
|
|||||||
|
|
||||||
|
|
||||||
def migrate_database_to_asset(apps, *args):
|
def migrate_database_to_asset(apps, *args):
|
||||||
|
node_model = apps.get_model('assets', 'Node')
|
||||||
app_model = apps.get_model('applications', 'Application')
|
app_model = apps.get_model('applications', 'Application')
|
||||||
db_model = apps.get_model('assets', 'Database')
|
db_model = apps.get_model('assets', 'Database')
|
||||||
platform_model = apps.get_model('assets', 'Platform')
|
platform_model = apps.get_model('assets', 'Platform')
|
||||||
|
|
||||||
applications = app_model.objects.filter(category='db')
|
applications = app_model.objects.filter(category='db')
|
||||||
platforms = platform_model.objects.all().filter(internal=True)
|
platforms = platform_model.objects.all().filter(internal=True).exclude(name='Redis6+')
|
||||||
platforms_map = {p.type: p for p in platforms}
|
platforms_map = {p.type: p for p in platforms}
|
||||||
print()
|
print()
|
||||||
|
|
||||||
@@ -84,11 +85,18 @@ def create_app_nodes(apps, org_id):
|
|||||||
node_keys = node_model.objects.filter(org_id=org_id) \
|
node_keys = node_model.objects.filter(org_id=org_id) \
|
||||||
.filter(key__regex=child_pattern) \
|
.filter(key__regex=child_pattern) \
|
||||||
.values_list('key', flat=True)
|
.values_list('key', flat=True)
|
||||||
if not node_keys:
|
if node_keys:
|
||||||
return
|
node_key_split = [key.split(':') for key in node_keys]
|
||||||
node_key_split = [key.split(':') for key in node_keys]
|
next_value = max([int(k[1]) for k in node_key_split]) + 1
|
||||||
next_value = max([int(k[1]) for k in node_key_split]) + 1
|
parent_key = node_key_split[0][0]
|
||||||
parent_key = node_key_split[0][0]
|
else:
|
||||||
|
root_node = node_model.objects.filter(org_id=org_id)\
|
||||||
|
.filter(parent_key='', key__regex=r'^[0-9]+$').exclude(key__startswith='-').first()
|
||||||
|
if not root_node:
|
||||||
|
return
|
||||||
|
parent_key = root_node.key
|
||||||
|
next_value = 0
|
||||||
|
|
||||||
next_key = '{}:{}'.format(parent_key, next_value)
|
next_key = '{}:{}'.format(parent_key, next_value)
|
||||||
name = 'Apps'
|
name = 'Apps'
|
||||||
parent = node_model.objects.get(key=parent_key)
|
parent = node_model.objects.get(key=parent_key)
|
||||||
|
|||||||
@@ -161,11 +161,12 @@ def migrate_db_accounts(apps, schema_editor):
|
|||||||
name = f'{username}(token)'
|
name = f'{username}(token)'
|
||||||
else:
|
else:
|
||||||
secret_type = attr
|
secret_type = attr
|
||||||
name = username
|
name = username or f'{username}(password)'
|
||||||
auth_infos.append((name, secret_type, secret))
|
auth_infos.append((name, secret_type, secret))
|
||||||
|
|
||||||
if not auth_infos:
|
if not auth_infos:
|
||||||
auth_infos.append((username, 'password', ''))
|
name = username or f'{username}(password)'
|
||||||
|
auth_infos.append((name, 'password', ''))
|
||||||
|
|
||||||
for name, secret_type, secret in auth_infos:
|
for name, secret_type, secret in auth_infos:
|
||||||
values['name'] = name
|
values['name'] = name
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ class AssetSerializer(BulkOrgResourceModelSerializer, WritableNestedModelSeriali
|
|||||||
'name': {'label': _("Name")},
|
'name': {'label': _("Name")},
|
||||||
'address': {'label': _('Address')},
|
'address': {'label': _('Address')},
|
||||||
'nodes_display': {'label': _('Node path')},
|
'nodes_display': {'label': _('Node path')},
|
||||||
|
'nodes': {'allow_empty': True},
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from assets.const.web import FillType
|
from assets.const.web import FillType
|
||||||
from common.serializers import WritableNestedModelSerializer
|
from common.serializers import WritableNestedModelSerializer, type_field_map
|
||||||
from common.serializers.fields import LabeledChoiceField
|
from common.serializers.fields import LabeledChoiceField
|
||||||
from common.utils import lazyproperty
|
from common.utils import lazyproperty
|
||||||
from ..const import Category, AllTypes
|
from ..const import Category, AllTypes
|
||||||
@@ -88,14 +88,7 @@ class PlatformProtocolSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
|
|
||||||
class PlatformCustomField(serializers.Serializer):
|
class PlatformCustomField(serializers.Serializer):
|
||||||
TYPE_CHOICES = [
|
TYPE_CHOICES = [(t, t) for t, c in type_field_map.items()]
|
||||||
("str", "str"),
|
|
||||||
("text", "text"),
|
|
||||||
("int", "int"),
|
|
||||||
("bool", "bool"),
|
|
||||||
("choice", "choice"),
|
|
||||||
("list", "list"),
|
|
||||||
]
|
|
||||||
name = serializers.CharField(label=_("Name"), max_length=128)
|
name = serializers.CharField(label=_("Name"), max_length=128)
|
||||||
label = serializers.CharField(label=_("Label"), max_length=128)
|
label = serializers.CharField(label=_("Label"), max_length=128)
|
||||||
type = serializers.ChoiceField(choices=TYPE_CHOICES, label=_("Type"), default='str')
|
type = serializers.ChoiceField(choices=TYPE_CHOICES, label=_("Type"), default='str')
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ example_info = [
|
|||||||
|
|
||||||
type_field_map = {
|
type_field_map = {
|
||||||
"str": serializers.CharField,
|
"str": serializers.CharField,
|
||||||
|
"password": serializers.CharField,
|
||||||
"int": serializers.IntegerField,
|
"int": serializers.IntegerField,
|
||||||
"bool": serializers.BooleanField,
|
"bool": serializers.BooleanField,
|
||||||
"text": serializers.CharField,
|
"text": serializers.CharField,
|
||||||
@@ -27,6 +28,8 @@ def set_default_if_need(data, i):
|
|||||||
def set_default_by_type(tp, data, field_info):
|
def set_default_by_type(tp, data, field_info):
|
||||||
if tp == 'str':
|
if tp == 'str':
|
||||||
data['max_length'] = 4096
|
data['max_length'] = 4096
|
||||||
|
elif tp == 'password':
|
||||||
|
data['write_only'] = True
|
||||||
elif tp == 'choice':
|
elif tp == 'choice':
|
||||||
choices = field_info.pop('choices', [])
|
choices = field_info.pop('choices', [])
|
||||||
if isinstance(choices, str):
|
if isinstance(choices, str):
|
||||||
|
|||||||
@@ -175,6 +175,8 @@ def _parse_ssh_private_key(text, password=None):
|
|||||||
dsa.DSAPrivateKey,
|
dsa.DSAPrivateKey,
|
||||||
ed25519.Ed25519PrivateKey,
|
ed25519.Ed25519PrivateKey,
|
||||||
"""
|
"""
|
||||||
|
if not bool(password):
|
||||||
|
password = None
|
||||||
if isinstance(text, str):
|
if isinstance(text, str):
|
||||||
try:
|
try:
|
||||||
text = text.encode("utf-8")
|
text = text.encode("utf-8")
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:2dd0610d610c2660f35d50dc2871ac08cc09080d2503e1080a57d97c47fea471
|
oid sha256:591b458d6f8ea8d125bd584ca57768cd5aa5a7103b42e345eaadac744a73d475
|
||||||
size 114418
|
size 114412
|
||||||
|
|||||||
@@ -1060,7 +1060,7 @@ msgstr "Web"
|
|||||||
|
|
||||||
#: assets/const/category.py:15
|
#: assets/const/category.py:15
|
||||||
msgid "Custom type"
|
msgid "Custom type"
|
||||||
msgstr "自定义类型"
|
msgstr "自定义"
|
||||||
|
|
||||||
#: assets/const/cloud.py:7
|
#: assets/const/cloud.py:7
|
||||||
msgid "Public cloud"
|
msgid "Public cloud"
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ def on_org_create_or_update(sender, instance, **kwargs):
|
|||||||
|
|
||||||
|
|
||||||
@receiver(pre_delete, sender=Organization)
|
@receiver(pre_delete, sender=Organization)
|
||||||
def on_org_delete(sender, instance, **kwargs):
|
def delete_org_root_node_on_org_delete(sender, instance, **kwargs):
|
||||||
expire_orgs_mapping_for_memory(instance.id)
|
expire_orgs_mapping_for_memory(instance.id)
|
||||||
|
|
||||||
# 删除该组织下所有 节点
|
# 删除该组织下所有 节点
|
||||||
@@ -91,7 +91,7 @@ def on_org_delete(sender, instance, **kwargs):
|
|||||||
|
|
||||||
|
|
||||||
@receiver(post_delete, sender=Organization)
|
@receiver(post_delete, sender=Organization)
|
||||||
def on_org_delete(sender, instance, **kwargs):
|
def expire_user_orgs_on_org_delete(sender, instance, **kwargs):
|
||||||
expire_user_orgs()
|
expire_user_orgs()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ class AssetPermissionSerializer(BulkOrgResourceModelSerializer):
|
|||||||
for i in range(0, len(account_ids), slice_count):
|
for i in range(0, len(account_ids), slice_count):
|
||||||
push_accounts_to_assets_task.delay(account_ids[i:i + slice_count])
|
push_accounts_to_assets_task.delay(account_ids[i:i + slice_count])
|
||||||
|
|
||||||
def validate_accounts(self, usernames: list[str]):
|
def validate_accounts(self, usernames):
|
||||||
template_ids = []
|
template_ids = []
|
||||||
account_usernames = []
|
account_usernames = []
|
||||||
for username in usernames:
|
for username in usernames:
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ class Applet(JMSBaseModel):
|
|||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(d, 'platform.yml')) as f:
|
with open(os.path.join(d, 'platform.yml')) as f:
|
||||||
data = yaml.safe_load(f)
|
data = yaml_load_with_i18n(f)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise ValidationError({'error': _('Load platform.yml failed: {}').format(e)})
|
raise ValidationError({'error': _('Load platform.yml failed: {}').format(e)})
|
||||||
|
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ class ComponentsPrometheusMetricsUtil(TypedComponentsStatusMetricsUtil):
|
|||||||
for component in self.components:
|
for component in self.components:
|
||||||
if not component.is_alive:
|
if not component.is_alive:
|
||||||
continue
|
continue
|
||||||
component_stat = component.latest_stat
|
component_stat = component.last_stat
|
||||||
if not component_stat:
|
if not component_stat:
|
||||||
continue
|
continue
|
||||||
metric_text = state_metric_text % (
|
metric_text = state_metric_text % (
|
||||||
|
|||||||
Reference in New Issue
Block a user