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