mirror of https://github.com/jumpserver/jumpserver
merge: with dev
commit
0996b1fbf5
|
@ -45,6 +45,7 @@ class AccountViewSet(OrgBulkModelViewSet):
|
||||||
accounts = asset.accounts.all()
|
accounts = asset.accounts.all()
|
||||||
else:
|
else:
|
||||||
accounts = []
|
accounts = []
|
||||||
|
accounts = self.filter_queryset(accounts)
|
||||||
serializer = serializers.AccountSerializer(accounts, many=True)
|
serializer = serializers.AccountSerializer(accounts, many=True)
|
||||||
return Response(data=serializer.data)
|
return Response(data=serializer.data)
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ from rest_framework.response import Response
|
||||||
|
|
||||||
from accounts import serializers
|
from accounts import serializers
|
||||||
from accounts.tasks import verify_accounts_connectivity_task, push_accounts_to_assets_task
|
from accounts.tasks import verify_accounts_connectivity_task, push_accounts_to_assets_task
|
||||||
|
from assets.exceptions import NotSupportedTemporarilyError
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'AccountsTaskCreateAPI',
|
'AccountsTaskCreateAPI',
|
||||||
|
@ -28,6 +29,11 @@ class AccountsTaskCreateAPI(CreateAPIView):
|
||||||
if data['action'] == 'push':
|
if data['action'] == 'push':
|
||||||
task = push_accounts_to_assets_task.delay(account_ids)
|
task = push_accounts_to_assets_task.delay(account_ids)
|
||||||
else:
|
else:
|
||||||
|
account = accounts[0]
|
||||||
|
asset = account.asset
|
||||||
|
if not asset.auto_info['ansible_enabled'] or \
|
||||||
|
not asset.auto_info['ping_enabled']:
|
||||||
|
raise NotSupportedTemporarilyError()
|
||||||
task = verify_accounts_connectivity_task.delay(account_ids)
|
task = verify_accounts_connectivity_task.delay(account_ids)
|
||||||
|
|
||||||
data = getattr(serializer, '_data', {})
|
data = getattr(serializer, '_data', {})
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from orgs.utils import tmp_to_org
|
from accounts.const import AutomationTypes
|
||||||
from common.utils import get_logger
|
|
||||||
from accounts.models import GatheredAccount
|
from accounts.models import GatheredAccount
|
||||||
from accounts.const import AutomationTypes, Source
|
from common.utils import get_logger
|
||||||
|
from orgs.utils import tmp_to_org
|
||||||
from .filter import GatherAccountsFilter
|
from .filter import GatherAccountsFilter
|
||||||
from ..base.manager import AccountBasePlaybookManager
|
from ..base.manager import AccountBasePlaybookManager
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
tasks:
|
tasks:
|
||||||
- name: Verify account
|
- name: Verify account
|
||||||
mongodb_ping:
|
mongodb_ping:
|
||||||
login_user: "{{ jms_account.username }}"
|
login_user: "{{ account.username }}"
|
||||||
login_password: "{{ jms_account.secret }}"
|
login_password: "{{ account.secret }}"
|
||||||
login_host: "{{ jms_asset.address }}"
|
login_host: "{{ jms_asset.address }}"
|
||||||
login_port: "{{ jms_asset.port }}"
|
login_port: "{{ jms_asset.port }}"
|
||||||
login_database: "{{ jms_asset.spec_info.db_name }}"
|
login_database: "{{ jms_asset.spec_info.db_name }}"
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
tasks:
|
tasks:
|
||||||
- name: Verify account
|
- name: Verify account
|
||||||
oracle_ping:
|
oracle_ping:
|
||||||
login_user: "{{ jms_account.username }}"
|
login_user: "{{ account.username }}"
|
||||||
login_password: "{{ jms_account.secret }}"
|
login_password: "{{ account.secret }}"
|
||||||
login_host: "{{ jms_asset.address }}"
|
login_host: "{{ jms_asset.address }}"
|
||||||
login_port: "{{ jms_asset.port }}"
|
login_port: "{{ jms_asset.port }}"
|
||||||
login_database: "{{ jms_asset.spec_info.db_name }}"
|
login_database: "{{ jms_asset.spec_info.db_name }}"
|
||||||
mode: "{{ jms_account.mode }}"
|
mode: "{{ account.mode }}"
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
tasks:
|
tasks:
|
||||||
- name: Verify account
|
- name: Verify account
|
||||||
community.general.mssql_script:
|
community.general.mssql_script:
|
||||||
login_user: "{{ jms_account.username }}"
|
login_user: "{{ account.username }}"
|
||||||
login_password: "{{ jms_account.secret }}"
|
login_password: "{{ account.secret }}"
|
||||||
login_host: "{{ jms_asset.address }}"
|
login_host: "{{ jms_asset.address }}"
|
||||||
login_port: "{{ jms_asset.port }}"
|
login_port: "{{ jms_asset.port }}"
|
||||||
name: '{{ jms_asset.spec_info.db_name }}'
|
name: '{{ jms_asset.spec_info.db_name }}'
|
||||||
|
|
|
@ -109,7 +109,7 @@ class BaseAccount(JMSOrgBaseModel):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def private_key_path(self):
|
def private_key_path(self):
|
||||||
if not self.secret_type != SecretType.SSH_KEY \
|
if self.secret_type != SecretType.SSH_KEY \
|
||||||
or not self.secret \
|
or not self.secret \
|
||||||
or not self.private_key:
|
or not self.private_key:
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from ops.mixin import PeriodTaskSerializerMixin
|
from accounts.models import AutomationExecution
|
||||||
from assets.const import AutomationTypes
|
from assets.const import AutomationTypes
|
||||||
from assets.models import Asset, Node, BaseAutomation
|
from assets.models import Asset, Node, BaseAutomation
|
||||||
from accounts.models import AutomationExecution
|
|
||||||
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
|
||||||
from common.utils import get_logger
|
|
||||||
from common.const.choices import Trigger
|
from common.const.choices import Trigger
|
||||||
from common.serializers.fields import ObjectRelatedField, LabeledChoiceField
|
from common.serializers.fields import ObjectRelatedField, LabeledChoiceField
|
||||||
|
from common.utils import get_logger
|
||||||
|
from ops.mixin import PeriodTaskSerializerMixin
|
||||||
|
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
|
||||||
|
@ -37,6 +37,17 @@ class BaseAutomationSerializer(PeriodTaskSerializerMixin, BulkOrgResourceModelSe
|
||||||
'executed_amount': {'label': _('Executed amount')},
|
'executed_amount': {'label': _('Executed amount')},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def validate_name(self, name):
|
||||||
|
if self.instance:
|
||||||
|
return name
|
||||||
|
if BaseAutomation.objects.filter(name=name, type=self.model_type).exists():
|
||||||
|
raise serializers.ValidationError(_('Name already exists'))
|
||||||
|
return name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def model_type(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
class AutomationExecutionSerializer(serializers.ModelSerializer):
|
class AutomationExecutionSerializer(serializers.ModelSerializer):
|
||||||
snapshot = serializers.SerializerMethodField(label=_('Automation snapshot'))
|
snapshot = serializers.SerializerMethodField(label=_('Automation snapshot'))
|
||||||
|
|
|
@ -4,13 +4,13 @@ from django.utils.translation import ugettext as _
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from accounts.const import (
|
from accounts.const import (
|
||||||
DEFAULT_PASSWORD_RULES, SecretType, SecretStrategy, SSHKeyStrategy
|
AutomationTypes, DEFAULT_PASSWORD_RULES,
|
||||||
|
SecretType, SecretStrategy, SSHKeyStrategy
|
||||||
)
|
)
|
||||||
from accounts.models import (
|
from accounts.models import (
|
||||||
Account, ChangeSecretAutomation,
|
Account, ChangeSecretAutomation,
|
||||||
ChangeSecretRecord
|
ChangeSecretRecord, AutomationExecution
|
||||||
)
|
)
|
||||||
from accounts.models import AutomationExecution
|
|
||||||
from accounts.serializers import AuthValidateMixin
|
from accounts.serializers import AuthValidateMixin
|
||||||
from assets.models import Asset
|
from assets.models import Asset
|
||||||
from common.serializers.fields import LabeledChoiceField, ObjectRelatedField
|
from common.serializers.fields import LabeledChoiceField, ObjectRelatedField
|
||||||
|
@ -53,10 +53,14 @@ class ChangeSecretAutomationSerializer(AuthValidateMixin, BaseAutomationSerializ
|
||||||
'ssh_key_change_strategy', 'passphrase', 'recipients',
|
'ssh_key_change_strategy', 'passphrase', 'recipients',
|
||||||
]
|
]
|
||||||
extra_kwargs = {**BaseAutomationSerializer.Meta.extra_kwargs, **{
|
extra_kwargs = {**BaseAutomationSerializer.Meta.extra_kwargs, **{
|
||||||
|
'accounts': {'required': True},
|
||||||
'recipients': {'label': _('Recipient'), 'help_text': _(
|
'recipients': {'label': _('Recipient'), 'help_text': _(
|
||||||
"Currently only mail sending is supported"
|
"Currently only mail sending is supported"
|
||||||
)},
|
)},
|
||||||
}}
|
}}
|
||||||
|
@property
|
||||||
|
def model_type(self):
|
||||||
|
return AutomationTypes.change_secret
|
||||||
|
|
||||||
def validate_password_rules(self, password_rules):
|
def validate_password_rules(self, password_rules):
|
||||||
secret_type = self.initial_data['secret_type']
|
secret_type = self.initial_data['secret_type']
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from accounts.const import AutomationTypes
|
||||||
from accounts.models import GatherAccountsAutomation
|
from accounts.models import GatherAccountsAutomation
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
|
|
||||||
|
@ -20,3 +20,7 @@ class GatherAccountAutomationSerializer(BaseAutomationSerializer):
|
||||||
fields = BaseAutomationSerializer.Meta.fields + read_only_fields
|
fields = BaseAutomationSerializer.Meta.fields + read_only_fields
|
||||||
|
|
||||||
extra_kwargs = BaseAutomationSerializer.Meta.extra_kwargs
|
extra_kwargs = BaseAutomationSerializer.Meta.extra_kwargs
|
||||||
|
|
||||||
|
@property
|
||||||
|
def model_type(self):
|
||||||
|
return AutomationTypes.gather_accounts
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import copy
|
from accounts.const import AutomationTypes
|
||||||
from accounts.models import PushAccountAutomation
|
from accounts.models import PushAccountAutomation
|
||||||
from .change_secret import (
|
from .change_secret import (
|
||||||
ChangeSecretAutomationSerializer, ChangeSecretUpdateAssetSerializer,
|
ChangeSecretAutomationSerializer, ChangeSecretUpdateAssetSerializer,
|
||||||
|
@ -14,6 +14,10 @@ class PushAccountAutomationSerializer(ChangeSecretAutomationSerializer):
|
||||||
if n not in ['recipients']
|
if n not in ['recipients']
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def model_type(self):
|
||||||
|
return AutomationTypes.push_account
|
||||||
|
|
||||||
|
|
||||||
class PushAccountUpdateAssetSerializer(ChangeSecretUpdateAssetSerializer):
|
class PushAccountUpdateAssetSerializer(ChangeSecretUpdateAssetSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -8,12 +8,10 @@ from rest_framework.response import Response
|
||||||
|
|
||||||
from accounts.tasks import push_accounts_to_assets_task, verify_accounts_connectivity_task
|
from accounts.tasks import push_accounts_to_assets_task, verify_accounts_connectivity_task
|
||||||
from assets import serializers
|
from assets import serializers
|
||||||
|
from assets.exceptions import NotSupportedTemporarilyError
|
||||||
from assets.filters import IpInFilterBackend, LabelFilterBackend, NodeFilterBackend
|
from assets.filters import IpInFilterBackend, LabelFilterBackend, NodeFilterBackend
|
||||||
from assets.models import Asset, Gateway
|
from assets.models import Asset, Gateway
|
||||||
from assets.tasks import (
|
from assets.tasks import test_assets_connectivity_manual, update_assets_hardware_info_manual
|
||||||
test_assets_connectivity_manual,
|
|
||||||
update_assets_hardware_info_manual
|
|
||||||
)
|
|
||||||
from common.api import SuggestionMixin
|
from common.api import SuggestionMixin
|
||||||
from common.drf.filters import BaseFilterSet
|
from common.drf.filters import BaseFilterSet
|
||||||
from common.utils import get_logger, is_uuid
|
from common.utils import get_logger, is_uuid
|
||||||
|
@ -154,6 +152,10 @@ class AssetsTaskMixin:
|
||||||
if data["action"] == "refresh":
|
if data["action"] == "refresh":
|
||||||
task = update_assets_hardware_info_manual(assets)
|
task = update_assets_hardware_info_manual(assets)
|
||||||
else:
|
else:
|
||||||
|
asset = assets[0]
|
||||||
|
if not asset.auto_info['ansible_enabled'] or \
|
||||||
|
not asset.auto_info['ping_enabled']:
|
||||||
|
raise NotSupportedTemporarilyError()
|
||||||
task = test_assets_connectivity_manual(assets)
|
task = test_assets_connectivity_manual(assets)
|
||||||
return task
|
return task
|
||||||
|
|
||||||
|
|
|
@ -173,6 +173,12 @@ class BasePlaybookManager:
|
||||||
self.runtime_dir,
|
self.runtime_dir,
|
||||||
callback=PlaybookCallback(),
|
callback=PlaybookCallback(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
with open(inventory_path, 'r') as f:
|
||||||
|
inventory_data = json.load(f)
|
||||||
|
if not inventory_data['all'].get('hosts'):
|
||||||
|
continue
|
||||||
|
|
||||||
runners.append(runer)
|
runners.append(runer)
|
||||||
return runners
|
return runners
|
||||||
|
|
||||||
|
@ -236,7 +242,6 @@ class BasePlaybookManager:
|
||||||
print(">>> 开始执行任务\n")
|
print(">>> 开始执行任务\n")
|
||||||
else:
|
else:
|
||||||
print("### 没有需要执行的任务\n")
|
print("### 没有需要执行的任务\n")
|
||||||
return
|
|
||||||
|
|
||||||
self.execution.date_start = timezone.now()
|
self.execution.date_start = timezone.now()
|
||||||
for i, runner in enumerate(runners, start=1):
|
for i, runner in enumerate(runners, start=1):
|
||||||
|
@ -245,11 +250,12 @@ class BasePlaybookManager:
|
||||||
self.before_runner_start(runner)
|
self.before_runner_start(runner)
|
||||||
try:
|
try:
|
||||||
cb = runner.run(**kwargs)
|
cb = runner.run(**kwargs)
|
||||||
self.delete_sensitive_data(runner.inventory)
|
|
||||||
self.on_runner_success(runner, cb)
|
self.on_runner_success(runner, cb)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.on_runner_failed(runner, e)
|
self.on_runner_failed(runner, e)
|
||||||
print('\n')
|
finally:
|
||||||
|
self.delete_sensitive_data(runner.inventory)
|
||||||
|
print('\n')
|
||||||
self.execution.status = 'success'
|
self.execution.status = 'success'
|
||||||
self.execution.date_finished = timezone.now()
|
self.execution.date_finished = timezone.now()
|
||||||
self.execution.save()
|
self.execution.save()
|
||||||
|
|
|
@ -38,9 +38,21 @@ class DatabaseTypes(BaseType):
|
||||||
},
|
},
|
||||||
cls.REDIS: {
|
cls.REDIS: {
|
||||||
'ansible_enabled': False,
|
'ansible_enabled': False,
|
||||||
|
'ping_enabled': False,
|
||||||
|
'gather_facts_enabled': False,
|
||||||
|
'gather_accounts_enabled': False,
|
||||||
|
'verify_account_enabled': False,
|
||||||
|
'change_secret_enabled': False,
|
||||||
|
'push_account_enabled': False,
|
||||||
},
|
},
|
||||||
cls.CLICKHOUSE: {
|
cls.CLICKHOUSE: {
|
||||||
'ansible_enabled': False,
|
'ansible_enabled': False,
|
||||||
|
'ping_enabled': False,
|
||||||
|
'gather_facts_enabled': False,
|
||||||
|
'gather_accounts_enabled': False,
|
||||||
|
'verify_account_enabled': False,
|
||||||
|
'change_secret_enabled': False,
|
||||||
|
'push_account_enabled': False,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return constrains
|
return constrains
|
||||||
|
|
|
@ -63,7 +63,13 @@ class HostTypes(BaseType):
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
cls.OTHER_HOST: {
|
cls.OTHER_HOST: {
|
||||||
'ansible_enabled': False
|
'ansible_enabled': False,
|
||||||
|
'ping_enabled': False,
|
||||||
|
'gather_facts_enabled': False,
|
||||||
|
'gather_accounts_enabled': False,
|
||||||
|
'verify_account_enabled': False,
|
||||||
|
'change_secret_enabled': False,
|
||||||
|
'push_account_enabled': False
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -253,17 +253,20 @@ class AllTypes(ChoicesMixin):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_or_update_by_platform_data(cls, name, platform_data):
|
def create_or_update_by_platform_data(cls, name, platform_data, platform_cls=None):
|
||||||
from assets.models import Platform, PlatformAutomation, PlatformProtocol
|
# 不直接用 Platform 是因为可能在 migrations 中使用
|
||||||
|
from assets.models import Platform
|
||||||
|
if platform_cls is None:
|
||||||
|
platform_cls = Platform
|
||||||
|
|
||||||
automation_data = platform_data.pop('automation', {})
|
automation_data = platform_data.pop('automation', {})
|
||||||
protocols_data = platform_data.pop('protocols', [])
|
protocols_data = platform_data.pop('protocols', [])
|
||||||
|
|
||||||
platform, created = Platform.objects.update_or_create(
|
platform, created = platform_cls.objects.update_or_create(
|
||||||
defaults=platform_data, name=name
|
defaults=platform_data, name=name
|
||||||
)
|
)
|
||||||
if not platform.automation:
|
if not platform.automation:
|
||||||
automation = PlatformAutomation.objects.create()
|
automation = platform_cls.automation.field.related_model.objects.create()
|
||||||
platform.automation = automation
|
platform.automation = automation
|
||||||
platform.save()
|
platform.save()
|
||||||
else:
|
else:
|
||||||
|
@ -275,10 +278,13 @@ class AllTypes(ChoicesMixin):
|
||||||
platform.protocols.all().delete()
|
platform.protocols.all().delete()
|
||||||
for p in protocols_data:
|
for p in protocols_data:
|
||||||
p.pop('primary', None)
|
p.pop('primary', None)
|
||||||
PlatformProtocol.objects.create(**p, platform=platform)
|
platform.protocols.create(**p)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_or_update_internal_platforms(cls):
|
def create_or_update_internal_platforms(cls, platform_cls=None):
|
||||||
|
if platform_cls is None:
|
||||||
|
platform_cls = cls
|
||||||
|
|
||||||
print("\n\tCreate internal platforms")
|
print("\n\tCreate internal platforms")
|
||||||
for category, type_cls in cls.category_types():
|
for category, type_cls in cls.category_types():
|
||||||
print("\t## Category: {}".format(category.label))
|
print("\t## Category: {}".format(category.label))
|
||||||
|
@ -311,7 +317,7 @@ class AllTypes(ChoicesMixin):
|
||||||
'automation': {**default_automation, **_automation},
|
'automation': {**default_automation, **_automation},
|
||||||
'protocols': protocols_data
|
'protocols': protocols_data
|
||||||
}
|
}
|
||||||
cls.create_or_update_by_platform_data(name, platform_data)
|
cls.create_or_update_by_platform_data(name, platform_data, platform_cls=platform_cls)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def update_user_create_platforms(cls, platform_cls):
|
def update_user_create_platforms(cls, platform_cls):
|
||||||
|
@ -328,4 +334,4 @@ class AllTypes(ChoicesMixin):
|
||||||
for platform in user_platforms:
|
for platform in user_platforms:
|
||||||
print("\t- Update platform: {}".format(platform.name))
|
print("\t- Update platform: {}".format(platform.name))
|
||||||
platform_data = cls.get_type_default_platform(platform.category, platform.type)
|
platform_data = cls.get_type_default_platform(platform.category, platform.type)
|
||||||
cls.create_or_update_by_platform_data(platform.name, platform_data)
|
cls.create_or_update_by_platform_data(platform.name, platform_data, platform_cls=platform_cls)
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
|
|
||||||
from common.exceptions import JMSException
|
from common.exceptions import JMSException
|
||||||
|
|
||||||
|
|
||||||
class NodeIsBeingUpdatedByOthers(JMSException):
|
class NodeIsBeingUpdatedByOthers(JMSException):
|
||||||
status_code = status.HTTP_409_CONFLICT
|
status_code = status.HTTP_409_CONFLICT
|
||||||
|
|
||||||
|
|
||||||
|
class NotSupportedTemporarilyError(JMSException):
|
||||||
|
default_detail = _("This function is not supported temporarily")
|
||||||
|
|
|
@ -5,7 +5,8 @@ from assets.const import AllTypes
|
||||||
|
|
||||||
|
|
||||||
def create_internal_platforms(apps, *args):
|
def create_internal_platforms(apps, *args):
|
||||||
AllTypes.create_or_update_internal_platforms()
|
platform_cls = apps.get_model('assets', 'Platform')
|
||||||
|
AllTypes.create_or_update_internal_platforms(platform_cls)
|
||||||
|
|
||||||
|
|
||||||
def update_user_platforms(apps, *args):
|
def update_user_platforms(apps, *args):
|
||||||
|
|
|
@ -277,6 +277,8 @@ class AssetSerializer(BulkOrgResourceModelSerializer, WritableNestedModelSeriali
|
||||||
|
|
||||||
@atomic
|
@atomic
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
|
if not validated_data.get('accounts'):
|
||||||
|
validated_data.pop('accounts', None)
|
||||||
nodes_display = validated_data.pop('nodes_display', '')
|
nodes_display = validated_data.pop('nodes_display', '')
|
||||||
instance = super().update(instance, validated_data)
|
instance = super().update(instance, validated_data)
|
||||||
self.perform_nodes_display_create(instance, nodes_display)
|
self.perform_nodes_display_create(instance, nodes_display)
|
||||||
|
|
|
@ -10,7 +10,7 @@ from rest_framework.permissions import IsAuthenticated
|
||||||
from common.drf.filters import DatetimeRangeFilter
|
from common.drf.filters import DatetimeRangeFilter
|
||||||
from common.plugins.es import QuerySet as ESQuerySet
|
from common.plugins.es import QuerySet as ESQuerySet
|
||||||
from common.utils import is_uuid
|
from common.utils import is_uuid
|
||||||
from orgs.mixins.api import OrgReadonlyModelViewSet
|
from orgs.mixins.api import OrgReadonlyModelViewSet, OrgModelViewSet
|
||||||
from orgs.utils import current_org, tmp_to_root_org
|
from orgs.utils import current_org, tmp_to_root_org
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from .backends import TYPE_ENGINE_MAPPING
|
from .backends import TYPE_ENGINE_MAPPING
|
||||||
|
@ -35,7 +35,7 @@ class JobAuditViewSet(OrgReadonlyModelViewSet):
|
||||||
ordering = ['-date_start']
|
ordering = ['-date_start']
|
||||||
|
|
||||||
|
|
||||||
class FTPLogViewSet(OrgReadonlyModelViewSet):
|
class FTPLogViewSet(OrgModelViewSet):
|
||||||
model = FTPLog
|
model = FTPLog
|
||||||
serializer_class = FTPLogSerializer
|
serializer_class = FTPLogSerializer
|
||||||
extra_filter_backends = [DatetimeRangeFilter]
|
extra_filter_backends = [DatetimeRangeFilter]
|
||||||
|
@ -45,6 +45,7 @@ class FTPLogViewSet(OrgReadonlyModelViewSet):
|
||||||
filterset_fields = ['user', 'asset', 'account', 'filename']
|
filterset_fields = ['user', 'asset', 'account', 'filename']
|
||||||
search_fields = filterset_fields
|
search_fields = filterset_fields
|
||||||
ordering = ['-date_start']
|
ordering = ['-date_start']
|
||||||
|
http_method_names = ['post', 'get', 'head', 'options']
|
||||||
|
|
||||||
|
|
||||||
class UserLoginCommonMixin:
|
class UserLoginCommonMixin:
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:014483808a830a01f5432fdc44bc34f7f392e53a160ffa97eb377dbb49e0ec9a
|
oid sha256:af57d16430705feb02ebbb99fc3a2f5fc3bab69209f558aa4d69b1e8055a6f5f
|
||||||
size 135547
|
size 136036
|
||||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-02-21 13:46+0800\n"
|
"POT-Creation-Date: 2023-02-21 22:44+0800\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -162,8 +162,8 @@ msgstr "作成のみ"
|
||||||
#: accounts/models/automations/gather_account.py:16
|
#: accounts/models/automations/gather_account.py:16
|
||||||
#: accounts/serializers/account/account.py:95
|
#: accounts/serializers/account/account.py:95
|
||||||
#: accounts/serializers/account/gathered_account.py:10
|
#: accounts/serializers/account/gathered_account.py:10
|
||||||
#: accounts/serializers/automations/change_secret.py:107
|
#: accounts/serializers/automations/change_secret.py:111
|
||||||
#: accounts/serializers/automations/change_secret.py:127
|
#: accounts/serializers/automations/change_secret.py:131
|
||||||
#: acls/models/base.py:100 acls/serializers/base.py:56
|
#: acls/models/base.py:100 acls/serializers/base.py:56
|
||||||
#: assets/models/asset/common.py:92 assets/models/asset/common.py:279
|
#: assets/models/asset/common.py:92 assets/models/asset/common.py:279
|
||||||
#: assets/models/cmd_filter.py:36 assets/serializers/domain.py:19
|
#: assets/models/cmd_filter.py:36 assets/serializers/domain.py:19
|
||||||
|
@ -192,8 +192,8 @@ msgid "Source"
|
||||||
msgstr "ソース"
|
msgstr "ソース"
|
||||||
|
|
||||||
#: accounts/models/account.py:58
|
#: accounts/models/account.py:58
|
||||||
#: accounts/serializers/automations/change_secret.py:108
|
#: accounts/serializers/automations/change_secret.py:112
|
||||||
#: accounts/serializers/automations/change_secret.py:128
|
#: accounts/serializers/automations/change_secret.py:132
|
||||||
#: acls/models/base.py:102 acls/serializers/base.py:57
|
#: acls/models/base.py:102 acls/serializers/base.py:57
|
||||||
#: assets/serializers/asset/common.py:125 assets/serializers/gateway.py:28
|
#: assets/serializers/asset/common.py:125 assets/serializers/gateway.py:28
|
||||||
#: audits/models.py:49 ops/models/base.py:18
|
#: audits/models.py:49 ops/models/base.py:18
|
||||||
|
@ -238,7 +238,7 @@ msgstr "アセット アカウント テンプレートのパスワードを変
|
||||||
#: accounts/models/automations/backup_account.py:27
|
#: accounts/models/automations/backup_account.py:27
|
||||||
#: accounts/models/automations/change_secret.py:47
|
#: accounts/models/automations/change_secret.py:47
|
||||||
#: accounts/serializers/account/backup.py:34
|
#: accounts/serializers/account/backup.py:34
|
||||||
#: accounts/serializers/automations/change_secret.py:56
|
#: accounts/serializers/automations/change_secret.py:57
|
||||||
msgid "Recipient"
|
msgid "Recipient"
|
||||||
msgstr "受信者"
|
msgstr "受信者"
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ msgstr "アカウントのバックアップスナップショット"
|
||||||
|
|
||||||
#: accounts/models/automations/backup_account.py:94
|
#: accounts/models/automations/backup_account.py:94
|
||||||
#: accounts/serializers/account/backup.py:42
|
#: accounts/serializers/account/backup.py:42
|
||||||
#: accounts/serializers/automations/base.py:44
|
#: accounts/serializers/automations/base.py:53
|
||||||
#: assets/models/automations/base.py:121
|
#: assets/models/automations/base.py:121
|
||||||
#: assets/serializers/automations/base.py:40
|
#: assets/serializers/automations/base.py:40
|
||||||
msgid "Trigger mode"
|
msgid "Trigger mode"
|
||||||
|
@ -281,8 +281,8 @@ msgid "Reason"
|
||||||
msgstr "理由"
|
msgstr "理由"
|
||||||
|
|
||||||
#: accounts/models/automations/backup_account.py:99
|
#: accounts/models/automations/backup_account.py:99
|
||||||
#: accounts/serializers/automations/change_secret.py:106
|
#: accounts/serializers/automations/change_secret.py:110
|
||||||
#: accounts/serializers/automations/change_secret.py:129
|
#: accounts/serializers/automations/change_secret.py:133
|
||||||
#: ops/serializers/job.py:64 terminal/serializers/session.py:45
|
#: ops/serializers/job.py:64 terminal/serializers/session.py:45
|
||||||
msgid "Is success"
|
msgid "Is success"
|
||||||
msgstr "成功は"
|
msgstr "成功は"
|
||||||
|
@ -540,7 +540,7 @@ msgid "Category"
|
||||||
msgstr "カテゴリ"
|
msgstr "カテゴリ"
|
||||||
|
|
||||||
#: accounts/serializers/account/account.py:76
|
#: accounts/serializers/account/account.py:76
|
||||||
#: accounts/serializers/automations/base.py:43 acls/models/command_acl.py:24
|
#: accounts/serializers/automations/base.py:52 acls/models/command_acl.py:24
|
||||||
#: acls/serializers/command_acl.py:18 applications/models.py:14
|
#: acls/serializers/command_acl.py:18 applications/models.py:14
|
||||||
#: assets/models/_user.py:50 assets/models/automations/base.py:20
|
#: assets/models/_user.py:50 assets/models/automations/base.py:20
|
||||||
#: assets/models/cmd_filter.py:74 assets/models/platform.py:78
|
#: assets/models/cmd_filter.py:74 assets/models/platform.py:78
|
||||||
|
@ -575,7 +575,7 @@ msgid "Executed amount"
|
||||||
msgstr "実行回数"
|
msgstr "実行回数"
|
||||||
|
|
||||||
#: accounts/serializers/account/backup.py:35
|
#: accounts/serializers/account/backup.py:35
|
||||||
#: accounts/serializers/automations/change_secret.py:57
|
#: accounts/serializers/automations/change_secret.py:58
|
||||||
msgid "Currently only mail sending is supported"
|
msgid "Currently only mail sending is supported"
|
||||||
msgstr "現在、メール送信のみがサポートされています"
|
msgstr "現在、メール送信のみがサポートされています"
|
||||||
|
|
||||||
|
@ -612,6 +612,10 @@ msgid "Nodes"
|
||||||
msgstr "ノード"
|
msgstr "ノード"
|
||||||
|
|
||||||
#: accounts/serializers/automations/base.py:42
|
#: accounts/serializers/automations/base.py:42
|
||||||
|
msgid "Name already exists"
|
||||||
|
msgstr "名前は既に存在します。"
|
||||||
|
|
||||||
|
#: accounts/serializers/automations/base.py:51
|
||||||
#: assets/models/automations/base.py:117
|
#: assets/models/automations/base.py:117
|
||||||
#: assets/serializers/automations/base.py:39
|
#: assets/serializers/automations/base.py:39
|
||||||
msgid "Automation snapshot"
|
msgid "Automation snapshot"
|
||||||
|
@ -621,20 +625,20 @@ msgstr "自動スナップショット"
|
||||||
msgid "SSH Key strategy"
|
msgid "SSH Key strategy"
|
||||||
msgstr "SSHキー戦略"
|
msgstr "SSHキー戦略"
|
||||||
|
|
||||||
#: accounts/serializers/automations/change_secret.py:76
|
#: accounts/serializers/automations/change_secret.py:80
|
||||||
msgid "* Please enter the correct password length"
|
msgid "* Please enter the correct password length"
|
||||||
msgstr "* 正しいパスワードの長さを入力してください"
|
msgstr "* 正しいパスワードの長さを入力してください"
|
||||||
|
|
||||||
#: accounts/serializers/automations/change_secret.py:80
|
#: accounts/serializers/automations/change_secret.py:84
|
||||||
msgid "* Password length range 6-30 bits"
|
msgid "* Password length range 6-30 bits"
|
||||||
msgstr "* パスワードの長さの範囲6-30ビット"
|
msgstr "* パスワードの長さの範囲6-30ビット"
|
||||||
|
|
||||||
#: accounts/serializers/automations/change_secret.py:110
|
#: accounts/serializers/automations/change_secret.py:114
|
||||||
#: assets/models/automations/base.py:126
|
#: assets/models/automations/base.py:126
|
||||||
msgid "Automation task execution"
|
msgid "Automation task execution"
|
||||||
msgstr "自動タスク実行履歴"
|
msgstr "自動タスク実行履歴"
|
||||||
|
|
||||||
#: accounts/serializers/automations/change_secret.py:150 audits/const.py:52
|
#: accounts/serializers/automations/change_secret.py:154 audits/const.py:52
|
||||||
#: audits/models.py:54 audits/signal_handlers/activity_log.py:33
|
#: audits/models.py:54 audits/signal_handlers/activity_log.py:33
|
||||||
#: common/const/choices.py:18 ops/const.py:56 ops/serializers/celery.py:39
|
#: common/const/choices.py:18 ops/const.py:56 ops/serializers/celery.py:39
|
||||||
#: terminal/const.py:59 terminal/models/session/sharing.py:103
|
#: terminal/const.py:59 terminal/models/session/sharing.py:103
|
||||||
|
@ -642,7 +646,7 @@ msgstr "自動タスク実行履歴"
|
||||||
msgid "Success"
|
msgid "Success"
|
||||||
msgstr "成功"
|
msgstr "成功"
|
||||||
|
|
||||||
#: accounts/serializers/automations/change_secret.py:151 audits/const.py:53
|
#: accounts/serializers/automations/change_secret.py:155 audits/const.py:53
|
||||||
#: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19
|
#: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19
|
||||||
#: ops/const.py:58 terminal/const.py:60 xpack/plugins/cloud/const.py:41
|
#: ops/const.py:58 terminal/const.py:60 xpack/plugins/cloud/const.py:41
|
||||||
msgid "Failed"
|
msgid "Failed"
|
||||||
|
@ -904,7 +908,7 @@ msgstr "アプリケーション"
|
||||||
msgid "Can match application"
|
msgid "Can match application"
|
||||||
msgstr "アプリケーションを一致させることができます"
|
msgstr "アプリケーションを一致させることができます"
|
||||||
|
|
||||||
#: assets/api/asset/asset.py:144
|
#: assets/api/asset/asset.py:142
|
||||||
msgid "Cannot create asset directly, you should create a host or other"
|
msgid "Cannot create asset directly, you should create a host or other"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"資産を直接作成することはできません。ホストまたはその他を作成する必要がありま"
|
"資産を直接作成することはできません。ホストまたはその他を作成する必要がありま"
|
||||||
|
@ -1047,6 +1051,10 @@ msgstr "基本"
|
||||||
msgid "Script"
|
msgid "Script"
|
||||||
msgstr "脚本"
|
msgstr "脚本"
|
||||||
|
|
||||||
|
#: assets/exceptions.py:12
|
||||||
|
msgid "This function is not supported temporarily"
|
||||||
|
msgstr "この機能は一時的にサポートされていません"
|
||||||
|
|
||||||
#: assets/models/_user.py:25
|
#: assets/models/_user.py:25
|
||||||
msgid "SSH private key"
|
msgid "SSH private key"
|
||||||
msgstr "SSH秘密鍵"
|
msgstr "SSH秘密鍵"
|
||||||
|
@ -7286,6 +7294,14 @@ msgstr "実行回数"
|
||||||
msgid "Instance count"
|
msgid "Instance count"
|
||||||
msgstr "インスタンス数"
|
msgstr "インスタンス数"
|
||||||
|
|
||||||
|
#: xpack/plugins/cloud/tasks.py:27
|
||||||
|
msgid "Run sync instance task"
|
||||||
|
msgstr "同期インスタンス タスクを実行する"
|
||||||
|
|
||||||
|
#: xpack/plugins/cloud/tasks.py:41
|
||||||
|
msgid "Period clean sync instance task execution"
|
||||||
|
msgstr "同期インスタンス タスクの実行記録を定期的にクリアする"
|
||||||
|
|
||||||
#: xpack/plugins/cloud/utils.py:69
|
#: xpack/plugins/cloud/utils.py:69
|
||||||
msgid "Account unavailable"
|
msgid "Account unavailable"
|
||||||
msgstr "利用できないアカウント"
|
msgstr "利用できないアカウント"
|
||||||
|
@ -7365,9 +7381,3 @@ msgstr "コミュニティ版"
|
||||||
|
|
||||||
#~ msgid "Remove asset from node"
|
#~ msgid "Remove asset from node"
|
||||||
#~ msgstr "ノードからアセットを削除"
|
#~ msgstr "ノードからアセットを削除"
|
||||||
|
|
||||||
#~ msgid "Run sync instance task"
|
|
||||||
#~ msgstr "同期インスタンス タスクを実行する"
|
|
||||||
|
|
||||||
#~ msgid "Period clean sync instance task execution"
|
|
||||||
#~ msgstr "同期インスタンス タスクの実行記録を定期的にクリアする"
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:1c1524b6173a2613845d9450d84ef8ca9cf1be6d0f7cdae2a89f6131d6abc1f1
|
oid sha256:3b6ee4a378810f2515be5020e3fa0b1297e1c207260ca60bb14dc5407ca19c43
|
||||||
size 111449
|
size 111750
|
||||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: JumpServer 0.3.3\n"
|
"Project-Id-Version: JumpServer 0.3.3\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-02-21 13:46+0800\n"
|
"POT-Creation-Date: 2023-02-21 22:44+0800\n"
|
||||||
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
|
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
|
||||||
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
||||||
"Language-Team: JumpServer team<ibuler@qq.com>\n"
|
"Language-Team: JumpServer team<ibuler@qq.com>\n"
|
||||||
|
@ -161,8 +161,8 @@ msgstr "仅创建"
|
||||||
#: accounts/models/automations/gather_account.py:16
|
#: accounts/models/automations/gather_account.py:16
|
||||||
#: accounts/serializers/account/account.py:95
|
#: accounts/serializers/account/account.py:95
|
||||||
#: accounts/serializers/account/gathered_account.py:10
|
#: accounts/serializers/account/gathered_account.py:10
|
||||||
#: accounts/serializers/automations/change_secret.py:107
|
#: accounts/serializers/automations/change_secret.py:111
|
||||||
#: accounts/serializers/automations/change_secret.py:127
|
#: accounts/serializers/automations/change_secret.py:131
|
||||||
#: acls/models/base.py:100 acls/serializers/base.py:56
|
#: acls/models/base.py:100 acls/serializers/base.py:56
|
||||||
#: assets/models/asset/common.py:92 assets/models/asset/common.py:279
|
#: assets/models/asset/common.py:92 assets/models/asset/common.py:279
|
||||||
#: assets/models/cmd_filter.py:36 assets/serializers/domain.py:19
|
#: assets/models/cmd_filter.py:36 assets/serializers/domain.py:19
|
||||||
|
@ -191,8 +191,8 @@ msgid "Source"
|
||||||
msgstr "来源"
|
msgstr "来源"
|
||||||
|
|
||||||
#: accounts/models/account.py:58
|
#: accounts/models/account.py:58
|
||||||
#: accounts/serializers/automations/change_secret.py:108
|
#: accounts/serializers/automations/change_secret.py:112
|
||||||
#: accounts/serializers/automations/change_secret.py:128
|
#: accounts/serializers/automations/change_secret.py:132
|
||||||
#: acls/models/base.py:102 acls/serializers/base.py:57
|
#: acls/models/base.py:102 acls/serializers/base.py:57
|
||||||
#: assets/serializers/asset/common.py:125 assets/serializers/gateway.py:28
|
#: assets/serializers/asset/common.py:125 assets/serializers/gateway.py:28
|
||||||
#: audits/models.py:49 ops/models/base.py:18
|
#: audits/models.py:49 ops/models/base.py:18
|
||||||
|
@ -237,7 +237,7 @@ msgstr "可以更改资产账号模版密码"
|
||||||
#: accounts/models/automations/backup_account.py:27
|
#: accounts/models/automations/backup_account.py:27
|
||||||
#: accounts/models/automations/change_secret.py:47
|
#: accounts/models/automations/change_secret.py:47
|
||||||
#: accounts/serializers/account/backup.py:34
|
#: accounts/serializers/account/backup.py:34
|
||||||
#: accounts/serializers/automations/change_secret.py:56
|
#: accounts/serializers/automations/change_secret.py:57
|
||||||
msgid "Recipient"
|
msgid "Recipient"
|
||||||
msgstr "收件人"
|
msgstr "收件人"
|
||||||
|
|
||||||
|
@ -268,7 +268,7 @@ msgstr "账号备份快照"
|
||||||
|
|
||||||
#: accounts/models/automations/backup_account.py:94
|
#: accounts/models/automations/backup_account.py:94
|
||||||
#: accounts/serializers/account/backup.py:42
|
#: accounts/serializers/account/backup.py:42
|
||||||
#: accounts/serializers/automations/base.py:44
|
#: accounts/serializers/automations/base.py:53
|
||||||
#: assets/models/automations/base.py:121
|
#: assets/models/automations/base.py:121
|
||||||
#: assets/serializers/automations/base.py:40
|
#: assets/serializers/automations/base.py:40
|
||||||
msgid "Trigger mode"
|
msgid "Trigger mode"
|
||||||
|
@ -280,8 +280,8 @@ msgid "Reason"
|
||||||
msgstr "原因"
|
msgstr "原因"
|
||||||
|
|
||||||
#: accounts/models/automations/backup_account.py:99
|
#: accounts/models/automations/backup_account.py:99
|
||||||
#: accounts/serializers/automations/change_secret.py:106
|
#: accounts/serializers/automations/change_secret.py:110
|
||||||
#: accounts/serializers/automations/change_secret.py:129
|
#: accounts/serializers/automations/change_secret.py:133
|
||||||
#: ops/serializers/job.py:64 terminal/serializers/session.py:45
|
#: ops/serializers/job.py:64 terminal/serializers/session.py:45
|
||||||
msgid "Is success"
|
msgid "Is success"
|
||||||
msgstr "是否成功"
|
msgstr "是否成功"
|
||||||
|
@ -536,7 +536,7 @@ msgid "Category"
|
||||||
msgstr "类别"
|
msgstr "类别"
|
||||||
|
|
||||||
#: accounts/serializers/account/account.py:76
|
#: accounts/serializers/account/account.py:76
|
||||||
#: accounts/serializers/automations/base.py:43 acls/models/command_acl.py:24
|
#: accounts/serializers/automations/base.py:52 acls/models/command_acl.py:24
|
||||||
#: acls/serializers/command_acl.py:18 applications/models.py:14
|
#: acls/serializers/command_acl.py:18 applications/models.py:14
|
||||||
#: assets/models/_user.py:50 assets/models/automations/base.py:20
|
#: assets/models/_user.py:50 assets/models/automations/base.py:20
|
||||||
#: assets/models/cmd_filter.py:74 assets/models/platform.py:78
|
#: assets/models/cmd_filter.py:74 assets/models/platform.py:78
|
||||||
|
@ -571,7 +571,7 @@ msgid "Executed amount"
|
||||||
msgstr "执行次数"
|
msgstr "执行次数"
|
||||||
|
|
||||||
#: accounts/serializers/account/backup.py:35
|
#: accounts/serializers/account/backup.py:35
|
||||||
#: accounts/serializers/automations/change_secret.py:57
|
#: accounts/serializers/automations/change_secret.py:58
|
||||||
msgid "Currently only mail sending is supported"
|
msgid "Currently only mail sending is supported"
|
||||||
msgstr "当前只支持邮件发送"
|
msgstr "当前只支持邮件发送"
|
||||||
|
|
||||||
|
@ -608,6 +608,10 @@ msgid "Nodes"
|
||||||
msgstr "节点"
|
msgstr "节点"
|
||||||
|
|
||||||
#: accounts/serializers/automations/base.py:42
|
#: accounts/serializers/automations/base.py:42
|
||||||
|
msgid "Name already exists"
|
||||||
|
msgstr "名称已存在"
|
||||||
|
|
||||||
|
#: accounts/serializers/automations/base.py:51
|
||||||
#: assets/models/automations/base.py:117
|
#: assets/models/automations/base.py:117
|
||||||
#: assets/serializers/automations/base.py:39
|
#: assets/serializers/automations/base.py:39
|
||||||
msgid "Automation snapshot"
|
msgid "Automation snapshot"
|
||||||
|
@ -617,20 +621,20 @@ msgstr "自动化快照"
|
||||||
msgid "SSH Key strategy"
|
msgid "SSH Key strategy"
|
||||||
msgstr "SSH 密钥更改方式"
|
msgstr "SSH 密钥更改方式"
|
||||||
|
|
||||||
#: accounts/serializers/automations/change_secret.py:76
|
#: accounts/serializers/automations/change_secret.py:80
|
||||||
msgid "* Please enter the correct password length"
|
msgid "* Please enter the correct password length"
|
||||||
msgstr "* 请输入正确的密码长度"
|
msgstr "* 请输入正确的密码长度"
|
||||||
|
|
||||||
#: accounts/serializers/automations/change_secret.py:80
|
#: accounts/serializers/automations/change_secret.py:84
|
||||||
msgid "* Password length range 6-30 bits"
|
msgid "* Password length range 6-30 bits"
|
||||||
msgstr "* 密码长度范围 6-30 位"
|
msgstr "* 密码长度范围 6-30 位"
|
||||||
|
|
||||||
#: accounts/serializers/automations/change_secret.py:110
|
#: accounts/serializers/automations/change_secret.py:114
|
||||||
#: assets/models/automations/base.py:126
|
#: assets/models/automations/base.py:126
|
||||||
msgid "Automation task execution"
|
msgid "Automation task execution"
|
||||||
msgstr "自动化任务执行历史"
|
msgstr "自动化任务执行历史"
|
||||||
|
|
||||||
#: accounts/serializers/automations/change_secret.py:150 audits/const.py:52
|
#: accounts/serializers/automations/change_secret.py:154 audits/const.py:52
|
||||||
#: audits/models.py:54 audits/signal_handlers/activity_log.py:33
|
#: audits/models.py:54 audits/signal_handlers/activity_log.py:33
|
||||||
#: common/const/choices.py:18 ops/const.py:56 ops/serializers/celery.py:39
|
#: common/const/choices.py:18 ops/const.py:56 ops/serializers/celery.py:39
|
||||||
#: terminal/const.py:59 terminal/models/session/sharing.py:103
|
#: terminal/const.py:59 terminal/models/session/sharing.py:103
|
||||||
|
@ -638,7 +642,7 @@ msgstr "自动化任务执行历史"
|
||||||
msgid "Success"
|
msgid "Success"
|
||||||
msgstr "成功"
|
msgstr "成功"
|
||||||
|
|
||||||
#: accounts/serializers/automations/change_secret.py:151 audits/const.py:53
|
#: accounts/serializers/automations/change_secret.py:155 audits/const.py:53
|
||||||
#: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19
|
#: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19
|
||||||
#: ops/const.py:58 terminal/const.py:60 xpack/plugins/cloud/const.py:41
|
#: ops/const.py:58 terminal/const.py:60 xpack/plugins/cloud/const.py:41
|
||||||
msgid "Failed"
|
msgid "Failed"
|
||||||
|
@ -898,7 +902,7 @@ msgstr "应用程序"
|
||||||
msgid "Can match application"
|
msgid "Can match application"
|
||||||
msgstr "匹配应用"
|
msgstr "匹配应用"
|
||||||
|
|
||||||
#: assets/api/asset/asset.py:144
|
#: assets/api/asset/asset.py:142
|
||||||
msgid "Cannot create asset directly, you should create a host or other"
|
msgid "Cannot create asset directly, you should create a host or other"
|
||||||
msgstr "不能直接创建资产, 你应该创建主机或其他资产"
|
msgstr "不能直接创建资产, 你应该创建主机或其他资产"
|
||||||
|
|
||||||
|
@ -1039,6 +1043,10 @@ msgstr "基本"
|
||||||
msgid "Script"
|
msgid "Script"
|
||||||
msgstr "脚本"
|
msgstr "脚本"
|
||||||
|
|
||||||
|
#: assets/exceptions.py:12
|
||||||
|
msgid "This function is not supported temporarily"
|
||||||
|
msgstr "暂时不支持此功能"
|
||||||
|
|
||||||
#: assets/models/_user.py:25
|
#: assets/models/_user.py:25
|
||||||
msgid "SSH private key"
|
msgid "SSH private key"
|
||||||
msgstr "SSH密钥"
|
msgstr "SSH密钥"
|
||||||
|
@ -5613,7 +5621,7 @@ msgstr "图标"
|
||||||
|
|
||||||
#: terminal/serializers/applet_host.py:24
|
#: terminal/serializers/applet_host.py:24
|
||||||
msgid "Per Session"
|
msgid "Per Session"
|
||||||
msgstr "每会话"
|
msgstr "每用户"
|
||||||
|
|
||||||
#: terminal/serializers/applet_host.py:25
|
#: terminal/serializers/applet_host.py:25
|
||||||
msgid "Per Device"
|
msgid "Per Device"
|
||||||
|
@ -7191,6 +7199,14 @@ msgstr "执行次数"
|
||||||
msgid "Instance count"
|
msgid "Instance count"
|
||||||
msgstr "实例个数"
|
msgstr "实例个数"
|
||||||
|
|
||||||
|
#: xpack/plugins/cloud/tasks.py:27
|
||||||
|
msgid "Run sync instance task"
|
||||||
|
msgstr "执行同步实例任务"
|
||||||
|
|
||||||
|
#: xpack/plugins/cloud/tasks.py:41
|
||||||
|
msgid "Period clean sync instance task execution"
|
||||||
|
msgstr "定期清除同步实例任务执行记录"
|
||||||
|
|
||||||
#: xpack/plugins/cloud/utils.py:69
|
#: xpack/plugins/cloud/utils.py:69
|
||||||
msgid "Account unavailable"
|
msgid "Account unavailable"
|
||||||
msgstr "账号无效"
|
msgstr "账号无效"
|
||||||
|
@ -7271,12 +7287,6 @@ msgstr "社区版"
|
||||||
#~ msgid "Remove asset from node"
|
#~ msgid "Remove asset from node"
|
||||||
#~ msgstr "从节点移除资产"
|
#~ msgstr "从节点移除资产"
|
||||||
|
|
||||||
#~ msgid "Run sync instance task"
|
|
||||||
#~ msgstr "执行同步实例任务"
|
|
||||||
|
|
||||||
#~ msgid "Period clean sync instance task execution"
|
|
||||||
#~ msgstr "定期清除同步实例任务执行记录"
|
|
||||||
|
|
||||||
#~ msgid "Clean audits log"
|
#~ msgid "Clean audits log"
|
||||||
#~ msgstr "清理审计日志"
|
#~ msgstr "清理审计日志"
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ from django.conf import settings
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
|
|
||||||
|
from common.exceptions import JMSException
|
||||||
from orgs.mixins.api import OrgBulkModelViewSet
|
from orgs.mixins.api import OrgBulkModelViewSet
|
||||||
from ..exception import PlaybookNoValidEntry
|
from ..exception import PlaybookNoValidEntry
|
||||||
from ..models import Playbook
|
from ..models import Playbook
|
||||||
|
@ -39,7 +40,11 @@ class PlaybookViewSet(OrgBulkModelViewSet):
|
||||||
if 'multipart/form-data' in self.request.headers['Content-Type']:
|
if 'multipart/form-data' in self.request.headers['Content-Type']:
|
||||||
src_path = os.path.join(settings.MEDIA_ROOT, instance.path.name)
|
src_path = os.path.join(settings.MEDIA_ROOT, instance.path.name)
|
||||||
dest_path = os.path.join(settings.DATA_DIR, "ops", "playbook", instance.id.__str__())
|
dest_path = os.path.join(settings.DATA_DIR, "ops", "playbook", instance.id.__str__())
|
||||||
unzip_playbook(src_path, dest_path)
|
try:
|
||||||
|
unzip_playbook(src_path, dest_path)
|
||||||
|
except RuntimeError as e:
|
||||||
|
raise JMSException(code='invalid_playbook_file', detail={"msg": "Unzip failed"})
|
||||||
|
|
||||||
if 'main.yml' not in os.listdir(dest_path):
|
if 'main.yml' not in os.listdir(dest_path):
|
||||||
raise PlaybookNoValidEntry
|
raise PlaybookNoValidEntry
|
||||||
|
|
||||||
|
@ -145,16 +150,17 @@ class PlaybookFileBrowserAPIView(APIView):
|
||||||
return Response(status=status.HTTP_400_BAD_REQUEST)
|
return Response(status=status.HTTP_400_BAD_REQUEST)
|
||||||
file_path = os.path.join(work_path, file_key)
|
file_path = os.path.join(work_path, file_key)
|
||||||
|
|
||||||
|
# rename
|
||||||
if new_name:
|
if new_name:
|
||||||
new_file_path = os.path.join(os.path.dirname(file_path), new_name)
|
new_file_path = os.path.join(os.path.dirname(file_path), new_name)
|
||||||
if os.path.exists(new_file_path):
|
if os.path.exists(new_file_path):
|
||||||
return Response({'msg': '{} already exists'.format(new_name)}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({'msg': '{} already exists'.format(new_name)}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
os.rename(file_path, new_file_path)
|
os.rename(file_path, new_file_path)
|
||||||
file_path = new_file_path
|
# edit content
|
||||||
|
else:
|
||||||
if not is_directory and content:
|
if not is_directory:
|
||||||
with open(file_path, 'w') as f:
|
with open(file_path, 'w') as f:
|
||||||
f.write(content)
|
f.write(content)
|
||||||
return Response({'msg': 'ok'})
|
return Response({'msg': 'ok'})
|
||||||
|
|
||||||
def delete(self, request, **kwargs):
|
def delete(self, request, **kwargs):
|
||||||
|
|
|
@ -36,8 +36,7 @@ class ActionChoices(BitChoices):
|
||||||
return cls.copy | cls.paste
|
return cls.copy | cls.paste
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def contains(cls, total, action):
|
def contains(cls, total, action_value):
|
||||||
action_value = getattr(cls, action)
|
|
||||||
return action_value & total == action_value
|
return action_value & total == action_value
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -111,7 +111,8 @@ class Applet(JMSBaseModel):
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
def select_host_account(self):
|
def select_host_account(self):
|
||||||
hosts = list(self.hosts.all())
|
# 选择激活的发布机
|
||||||
|
hosts = list(self.hosts.filter(is_active=True).all())
|
||||||
if not hosts:
|
if not hosts:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ class DeployOptionsSerializer(serializers.Serializer):
|
||||||
CORE_HOST = serializers.CharField(default=settings.SITE_URL, label=_('API Server'), max_length=1024)
|
CORE_HOST = serializers.CharField(default=settings.SITE_URL, label=_('API Server'), max_length=1024)
|
||||||
RDS_Licensing = serializers.BooleanField(default=False, label=_("RDS Licensing"))
|
RDS_Licensing = serializers.BooleanField(default=False, label=_("RDS Licensing"))
|
||||||
RDS_LicenseServer = serializers.CharField(default='127.0.0.1', label=_('RDS License Server'), max_length=1024)
|
RDS_LicenseServer = serializers.CharField(default='127.0.0.1', label=_('RDS License Server'), max_length=1024)
|
||||||
RDS_LicensingMode = serializers.ChoiceField(choices=LICENSE_MODE_CHOICES, default=4, label=_('RDS Licensing Mode'))
|
RDS_LicensingMode = serializers.ChoiceField(choices=LICENSE_MODE_CHOICES, default=2, label=_('RDS Licensing Mode'))
|
||||||
RDS_fSingleSessionPerUser = serializers.ChoiceField(choices=SESSION_PER_USER, default=1,
|
RDS_fSingleSessionPerUser = serializers.ChoiceField(choices=SESSION_PER_USER, default=1,
|
||||||
label=_("RDS Single Session Per User"))
|
label=_("RDS Single Session Per User"))
|
||||||
RDS_MaxDisconnectionTime = serializers.IntegerField(default=60000, label=_("RDS Max Disconnection Time"))
|
RDS_MaxDisconnectionTime = serializers.IntegerField(default=60000, label=_("RDS Max Disconnection Time"))
|
||||||
|
|
Loading…
Reference in New Issue