Merge pull request #9649 from jumpserver/pr@dev@perf_account_tasks

perf: 优化 tasks
pull/9660/head
老广 2023-02-21 14:14:37 +08:00 committed by GitHub
commit b91b9ef39e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 612 additions and 591 deletions

View File

@ -1,4 +1,3 @@
from .account import *
from .backup import *
from .task import *
from .template import *
from .gathered_account import *

View File

@ -1,12 +1,11 @@
from django.shortcuts import get_object_or_404
from rest_framework.decorators import action
from rest_framework.generics import CreateAPIView, ListAPIView
from rest_framework.generics import ListAPIView
from rest_framework.response import Response
from accounts import serializers
from accounts.filters import AccountFilterSet
from accounts.models import Account
from accounts.tasks import verify_accounts_connectivity
from assets.models import Asset
from authentication.const import ConfirmType
from common.permissions import UserConfirmation
@ -15,7 +14,7 @@ from orgs.mixins.api import OrgBulkModelViewSet
__all__ = [
'AccountViewSet', 'AccountSecretsViewSet',
'AccountTaskCreateAPI', 'AccountHistoriesSecretAPI'
'AccountHistoriesSecretAPI'
]
from rbac.permissions import RBACPermission
@ -29,7 +28,6 @@ class AccountViewSet(OrgBulkModelViewSet):
'default': serializers.AccountSerializer,
}
rbac_perms = {
'verify_account': 'accounts.test_account',
'partial_update': ['accounts.change_account'],
'su_from_accounts': 'accounts.view_account',
}
@ -38,6 +36,7 @@ class AccountViewSet(OrgBulkModelViewSet):
def su_from_accounts(self, request, *args, **kwargs):
account_id = request.query_params.get('account')
asset_id = request.query_params.get('asset')
if account_id:
account = get_object_or_404(Account, pk=account_id)
accounts = account.get_su_from_accounts()
@ -49,14 +48,6 @@ class AccountViewSet(OrgBulkModelViewSet):
serializer = serializers.AccountSerializer(accounts, many=True)
return Response(data=serializer.data)
@action(methods=['post'], detail=True, url_path='verify')
def verify_account(self, request, *args, **kwargs):
account = super().get_object()
account_ids = [account.id]
asset_ids = [account.asset_id]
task = verify_accounts_connectivity.delay(account_ids, asset_ids)
return Response(data={'task': task.id})
class AccountSecretsViewSet(RecordViewLogMixin, AccountViewSet):
"""
@ -84,33 +75,3 @@ class AccountHistoriesSecretAPI(RecordViewLogMixin, ListAPIView):
def get_queryset(self):
return self.model.objects.filter(id=self.kwargs.get('pk'))
class AccountTaskCreateAPI(CreateAPIView):
serializer_class = serializers.AccountTaskSerializer
search_fields = AccountViewSet.search_fields
filterset_class = AccountViewSet.filterset_class
def check_permissions(self, request):
return request.user.has_perm('assets.test_assetconnectivity')
def get_accounts(self):
queryset = Account.objects.all()
queryset = self.filter_queryset(queryset)
return queryset
def perform_create(self, serializer):
accounts = self.get_accounts()
account_ids = accounts.values_list('id', flat=True)
asset_ids = [account.asset_id for account in accounts]
task = verify_accounts_connectivity.delay(account_ids, asset_ids)
data = getattr(serializer, '_data', {})
data["task"] = task.id
setattr(serializer, '_data', data)
return task
def get_exception_handler(self):
def handler(e, context):
return Response({"error": str(e)}, status=400)
return handler

View File

@ -1,42 +0,0 @@
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.response import Response
from django.utils.translation import ugettext_lazy as _
from accounts import serializers
from accounts.const import Source
from accounts.models import GatheredAccount
from accounts.filters import GatheredAccountFilterSet
from orgs.mixins.api import OrgBulkModelViewSet
__all__ = [
'GatheredAccountViewSet',
]
class GatheredAccountViewSet(OrgBulkModelViewSet):
model = GatheredAccount
search_fields = ('username',)
filterset_class = GatheredAccountFilterSet
serializer_classes = {
'default': serializers.GatheredAccountSerializer,
}
rbac_perms = {
'sync_account': 'assets.add_gatheredaccount',
}
@action(methods=['post'], detail=True, url_path='sync')
def sync_account(self, request, *args, **kwargs):
gathered_account = super().get_object()
asset = gathered_account.asset
username = gathered_account.username
accounts = asset.accounts.filter(username=username)
if accounts.exists():
accounts.update(source=Source.COLLECTED)
else:
asset.accounts.model.objects.create(
asset=asset, username=username,
name=f'{username}-{_("Collected")}',
source=Source.COLLECTED
)
return Response(status=status.HTTP_201_CREATED)

View File

@ -0,0 +1,42 @@
from rest_framework.generics import CreateAPIView
from rest_framework.response import Response
from accounts import serializers
from accounts.tasks import verify_accounts_connectivity_task, push_accounts_to_assets_task
__all__ = [
'AccountsTaskCreateAPI',
]
class AccountsTaskCreateAPI(CreateAPIView):
serializer_class = serializers.AccountTaskSerializer
def check_permissions(self, request):
act = request.data.get('action')
if act == 'push':
code = 'accounts.push_account'
else:
code = 'accounts.verify_account'
return request.user.has_perm(code)
def perform_create(self, serializer):
data = serializer.validated_data
accounts = data.get('accounts', [])
account_ids = [a.id for a in accounts]
if data['action'] == 'push':
task = push_accounts_to_assets_task.delay(account_ids)
else:
task = verify_accounts_connectivity_task.delay(account_ids)
data = getattr(serializer, '_data', {})
data["task"] = task.id
setattr(serializer, '_data', data)
return task
def get_exception_handler(self):
def handler(e, context):
return Response({"error": str(e)}, status=400)
return handler

View File

@ -1,3 +1,4 @@
from .backup import *
from .base import *
from .change_secret import *
from .gather_accounts import *

View File

@ -7,7 +7,7 @@ from accounts import serializers
from accounts.models import (
AccountBackupAutomation, AccountBackupExecution
)
from accounts.tasks import execute_account_backup_plan
from accounts.tasks import execute_account_backup_task
from common.const.choices import Trigger
from orgs.mixins.api import OrgBulkModelViewSet
@ -38,5 +38,5 @@ class AccountBackupPlanExecutionViewSet(viewsets.ModelViewSet):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
pid = serializer.data.get('plan')
task = execute_account_backup_plan.delay(pid=str(pid), trigger=Trigger.manual)
task = execute_account_backup_task.delay(pid=str(pid), trigger=Trigger.manual)
return Response({'task': task.id}, status=status.HTTP_201_CREATED)

View File

@ -4,7 +4,7 @@ from rest_framework import status, mixins, viewsets
from rest_framework.response import Response
from accounts.models import AutomationExecution
from accounts.tasks import execute_automation
from accounts.tasks import execute_account_automation_task
from assets import serializers
from assets.models import BaseAutomation
from common.const.choices import Trigger
@ -109,7 +109,7 @@ class AutomationExecutionViewSet(
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
automation = serializer.validated_data.get('automation')
task = execute_automation.delay(
task = execute_account_automation_task.delay(
pid=str(automation.pk), trigger=Trigger.manual, tp=self.tp
)
return Response({'task': task.id}, status=status.HTTP_201_CREATED)

View File

@ -1,13 +1,22 @@
# -*- coding: utf-8 -*-
#
from django.utils.translation import ugettext_lazy as _
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.response import Response
from accounts import serializers
from accounts.const import AutomationTypes
from accounts.const import Source
from accounts.filters import GatheredAccountFilterSet
from accounts.models import GatherAccountsAutomation
from accounts.models import GatheredAccount
from orgs.mixins.api import OrgBulkModelViewSet
from .base import AutomationExecutionViewSet
__all__ = [
'GatherAccountsAutomationViewSet', 'GatherAccountsExecutionViewSet'
'GatherAccountsAutomationViewSet', 'GatherAccountsExecutionViewSet',
'GatheredAccountViewSet'
]
@ -31,3 +40,32 @@ class GatherAccountsExecutionViewSet(AutomationExecutionViewSet):
queryset = super().get_queryset()
queryset = queryset.filter(automation__type=self.tp)
return queryset
class GatheredAccountViewSet(OrgBulkModelViewSet):
model = GatheredAccount
search_fields = ('username',)
filterset_class = GatheredAccountFilterSet
serializer_classes = {
'default': serializers.GatheredAccountSerializer,
}
rbac_perms = {
'sync_account': 'assets.add_gatheredaccount',
}
@action(methods=['post'], detail=True, url_path='sync')
def sync_account(self, request, *args, **kwargs):
gathered_account = super().get_object()
asset = gathered_account.asset
username = gathered_account.username
accounts = asset.accounts.filter(username=username)
if accounts.exists():
accounts.update(source=Source.COLLECTED)
else:
asset.accounts.model.objects.create(
asset=asset, username=username,
name=f'{username}-{_("Collected")}',
source=Source.COLLECTED
)
return Response(status=status.HTTP_201_CREATED)

View File

@ -17,19 +17,19 @@ class VerifyHostCallbackMixin:
def host_callback(self, host, asset=None, account=None, automation=None, path_dir=None, **kwargs):
host = super().host_callback(
host, asset=asset, account=account, automation=automation,
path_dir=path_dir, **kwargs
host, asset=asset, account=account,
automation=automation, path_dir=path_dir, **kwargs
)
if host.get('error'):
return host
accounts = asset.accounts.all()
accounts = self.get_accounts(account, accounts)
inventory_hosts = []
for account in accounts:
h = deepcopy(host)
h['name'] += '_' + account.username
h['name'] += '(' + account.username + ')'
self.host_account_mapper[h['name']] = account
secret = account.secret

View File

@ -3,10 +3,6 @@
tasks:
- name: Test privileged account
ansible.builtin.ping:
#
# - name: print variables
# debug:
# msg: "Username: {{ account.username }}, Secret: {{ account.secret }}, Secret type: {{ secret_type }}"
- name: Change password
ansible.builtin.user:
@ -26,8 +22,8 @@
regexp: "{{ kwargs.regexp }}"
state: absent
when:
- secret_type == "ssh_key"
- kwargs.strategy == "set_jms"
- secret_type == "ssh_key"
- kwargs.strategy == "set_jms"
- name: Change SSH key
ansible.builtin.authorized_key:

View File

@ -99,7 +99,7 @@ class ChangeSecretManager(AccountBasePlaybookManager):
for account in accounts:
h = deepcopy(host)
h['name'] += '_' + account.username
h['name'] += '(' + account.username + ')'
new_secret = self.get_secret()
recorder = ChangeSecretRecord(

View File

@ -68,7 +68,7 @@ class PushAccountManager(ChangeSecretManager, AccountBasePlaybookManager):
for account in accounts:
h = deepcopy(host)
h['name'] += '_' + account.username
h['name'] += '(' + account.username + ')'
new_secret = self.get_secret()
self.name_recorder_mapper[h['name']] = {

View File

@ -50,7 +50,6 @@ class Migration(migrations.Migration):
options={
'verbose_name': 'Account',
'permissions': [('view_accountsecret', 'Can view asset account secret'),
('change_accountsecret', 'Can change asset account secret'),
('view_historyaccount', 'Can view asset history account'),
('view_historyaccountsecret', 'Can view asset history account secret')],
'unique_together': {('username', 'asset', 'secret_type'), ('name', 'asset')},

View File

@ -12,6 +12,6 @@ class Migration(migrations.Migration):
operations = [
migrations.AlterModelOptions(
name='account',
options={'permissions': [('view_accountsecret', 'Can view asset account secret'), ('view_historyaccount', 'Can view asset history account'), ('view_historyaccountsecret', 'Can view asset history account secret')], 'verbose_name': 'Account'},
options={'permissions': [('view_accountsecret', 'Can view asset account secret'), ('view_historyaccount', 'Can view asset history account'), ('view_historyaccountsecret', 'Can view asset history account secret'), ('verify_account', 'Can verify account'), ('push_account', 'Can push account')], 'verbose_name': 'Account'},
),
]

View File

@ -0,0 +1,17 @@
# Generated by Django 3.2.14 on 2023-02-21 05:13
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('accounts', '0007_alter_account_options'),
]
operations = [
migrations.AlterModelOptions(
name='account',
options={'permissions': [('view_accountsecret', 'Can view asset account secret'), ('view_historyaccount', 'Can view asset history account'), ('view_historyaccountsecret', 'Can view asset history account secret'), ('verify_account', 'Can verify account'), ('push_account', 'Can push account')], 'verbose_name': 'Account'},
),
]

View File

@ -1,4 +1,3 @@
from .base import *
from .account import *
from .automations import *
from .gathered_account import *

View File

@ -64,6 +64,8 @@ class Account(AbsConnectivity, BaseAccount):
('view_accountsecret', _('Can view asset account secret')),
('view_historyaccount', _('Can view asset history account')),
('view_historyaccountsecret', _('Can view asset history account secret')),
('verify_account', _('Can verify account')),
('push_account', _('Can push account')),
]
@lazyproperty

View File

@ -7,11 +7,11 @@ from celery import current_task
from django.db import models
from django.db.models import F
from django.utils.translation import ugettext_lazy as _
from common.utils import lazyproperty
from common.const.choices import Trigger
from common.db.encoder import ModelJSONFieldEncoder
from common.utils import get_logger
from common.utils import lazyproperty
from ops.mixin import PeriodTaskModelMixin
from orgs.mixins.models import OrgModelMixin, JMSOrgBaseModel
@ -36,9 +36,9 @@ class AccountBackupAutomation(PeriodTaskModelMixin, JMSOrgBaseModel):
verbose_name = _('Account backup plan')
def get_register_task(self):
from ...tasks import execute_account_backup_plan
from ...tasks import execute_account_backup_task
name = "account_backup_plan_period_{}".format(str(self.id)[:8])
task = execute_account_backup_plan.name
task = execute_account_backup_task.name
args = (str(self.id), Trigger.timing)
kwargs = {}
return name, task, args, kwargs

View File

@ -1,6 +1,6 @@
from django.utils.translation import gettext_lazy as _
from accounts.tasks import execute_automation
from accounts.tasks import execute_account_automation_task
from assets.models.automations import (
BaseAutomation as AssetBaseAutomation,
AutomationExecution as AssetAutomationExecution
@ -16,7 +16,7 @@ class AccountBaseAutomation(AssetBaseAutomation):
@property
def execute_task(self):
return execute_automation
return execute_account_automation_task
@property
def execution_model(self):

View File

@ -16,11 +16,11 @@ class ChangeSecretMixin(models.Model):
choices=SecretType.choices, max_length=16,
default=SecretType.PASSWORD, verbose_name=_('Secret type')
)
secret = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Secret'))
secret_strategy = models.CharField(
choices=SecretStrategy.choices, max_length=16,
default=SecretStrategy.custom, verbose_name=_('Secret strategy')
)
secret = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Secret'))
password_rules = models.JSONField(default=dict, verbose_name=_('Password rules'))
ssh_key_change_strategy = models.CharField(
choices=SSHKeyStrategy.choices, max_length=16,

View File

@ -1,9 +1,35 @@
from django.utils.translation import ugettext_lazy as _
from django.db import models
from django.utils.translation import ugettext_lazy as _
from orgs.mixins.models import JMSOrgBaseModel
from accounts.const import AutomationTypes
from .base import AccountBaseAutomation
__all__ = ['GatherAccountsAutomation']
__all__ = ['GatherAccountsAutomation', 'GatheredAccount']
class GatheredAccount(JMSOrgBaseModel):
present = models.BooleanField(default=True, verbose_name=_("Present"))
date_last_login = models.DateTimeField(null=True, verbose_name=_("Date last login"))
asset = models.ForeignKey('assets.Asset', on_delete=models.CASCADE, verbose_name=_("Asset"))
username = models.CharField(max_length=32, blank=True, db_index=True, verbose_name=_('Username'))
address_last_login = models.CharField(max_length=39, default='', verbose_name=_("Address last login"))
@property
def address(self):
return self.asset.address
class Meta:
verbose_name = _('Gather account')
unique_together = [
('username', 'asset'),
]
ordering = ['asset']
def __str__(self):
return '{}: {}'.format(self.asset, self.username)
class GatherAccountsAutomation(AccountBaseAutomation):

View File

@ -9,7 +9,6 @@ __all__ = ['PushAccountAutomation']
class PushAccountAutomation(ChangeSecretMixin, AccountBaseAutomation):
accounts = None
triggers = models.JSONField(max_length=16, default=list, verbose_name=_('Triggers'))
username = models.CharField(max_length=128, verbose_name=_('Username'))
action = models.CharField(max_length=16, verbose_name=_('Action'))

View File

@ -1,30 +0,0 @@
# -*- coding: utf-8 -*-
#
from django.db import models
from django.utils.translation import ugettext_lazy as _
from orgs.mixins.models import JMSOrgBaseModel
__all__ = ['GatheredAccount']
class GatheredAccount(JMSOrgBaseModel):
present = models.BooleanField(default=True, verbose_name=_("Present"))
date_last_login = models.DateTimeField(null=True, verbose_name=_("Date last login"))
asset = models.ForeignKey('assets.Asset', on_delete=models.CASCADE, verbose_name=_("Asset"))
username = models.CharField(max_length=32, blank=True, db_index=True, verbose_name=_('Username'))
address_last_login = models.CharField(max_length=39, default='', verbose_name=_("Address last login"))
@property
def address(self):
return self.asset.address
class Meta:
verbose_name = _('Gather account')
unique_together = [
('username', 'asset'),
]
ordering = ['asset']
def __str__(self):
return '{}: {}'.format(self.asset, self.username)

View File

@ -3,7 +3,7 @@ from rest_framework import serializers
from accounts.const import SecretType, Source
from accounts.models import Account, AccountTemplate
from accounts.tasks import push_accounts_to_assets
from accounts.tasks import push_accounts_to_assets_task
from assets.const import Category, AllTypes
from assets.models import Asset
from common.serializers import SecretReadableMixin, BulkModelSerializer
@ -43,7 +43,7 @@ class AccountSerializerCreateValidateMixin:
def push_account(instance, push_now):
if not push_now:
return
push_accounts_to_assets.delay([instance.id], [instance.asset_id])
push_accounts_to_assets_task.delay([instance.id], [instance.asset_id])
def create(self, validated_data):
push_now = validated_data.pop('push_now', None)
@ -140,6 +140,11 @@ class AccountHistorySerializer(serializers.ModelSerializer):
class AccountTaskSerializer(serializers.Serializer):
ACTION_CHOICES = (
('test', 'test'),
('verify', 'verify'),
('push', 'push'),
)
action = serializers.ChoiceField(choices=ACTION_CHOICES, write_only=True)
accounts = serializers.PrimaryKeyRelatedField(
queryset=Account.objects, required=False, allow_empty=True, many=True
)
task = serializers.CharField(read_only=True)

View File

@ -7,58 +7,12 @@ from .change_secret import (
class PushAccountAutomationSerializer(ChangeSecretAutomationSerializer):
# dynamic_username = serializers.BooleanField(label=_('Dynamic username'), default=False)
# triggers = TreeChoicesField(
# choice_cls=TriggerChoice, label=_('Triggers'),
# default=TriggerChoice.all(),
# )
# action = LabeledChoiceField(
# choices=PushAccountActionChoice.choices, label=_('Action'),
# default=PushAccountActionChoice.create_and_push
# )
class Meta(ChangeSecretAutomationSerializer.Meta):
model = PushAccountAutomation
fields = copy.copy(ChangeSecretAutomationSerializer.Meta.fields)
fields.remove('recipients')
# fields = ChangeSecretAutomationSerializer.Meta.fields + [
# 'dynamic_username', 'triggers', 'action'
# ]
# def validate_username(self, value):
# if self.initial_data.get('dynamic_username'):
# value = '@USER'
# queryset = self.Meta.model.objects.filter(username=value)
# if self.instance:
# queryset = queryset.exclude(id=self.instance.id)
# if queryset.exists():
# raise serializers.ValidationError(_('Username already exists'))
# return value
#
# def validate_dynamic_username(self, value):
# if not value:
# return value
# queryset = self.Meta.model.objects.filter(username='@USER')
# if self.instance:
# queryset = queryset.exclude(id=self.instance.id)
# if queryset.exists():
# raise serializers.ValidationError(_('Dynamic username already exists'))
# return value
#
# def validate_triggers(self, value):
# # Now triggers readonly, set all
# return TriggerChoice.all()
#
# def get_field_names(self, declared_fields, info):
# fields = super().get_field_names(declared_fields, info)
# excludes = [
# 'recipients', 'is_periodic', 'interval', 'crontab',
# 'periodic_display', 'assets', 'nodes'
# ]
# fields = [f for f in fields if f not in excludes]
# fields[fields.index('accounts')] = 'username'
# return fields
fields = [
n for n in ChangeSecretAutomationSerializer.Meta.fields
if n not in ['recipients']
]
class PushAccountUpdateAssetSerializer(ChangeSecretUpdateAssetSerializer):

View File

@ -24,7 +24,7 @@ def task_activity_callback(self, pid, trigger, tp):
queue='ansible', verbose_name=_('Account execute automation'),
activity_callback=task_activity_callback
)
def execute_automation(pid, trigger, tp):
def execute_account_automation_task(pid, trigger, tp):
model = AutomationTypes.get_type_model(tp)
with tmp_to_root_org():
instance = get_object_or_none(model, pk=pid)

View File

@ -10,6 +10,7 @@ logger = get_logger(__file__)
def task_activity_callback(self, pid, trigger):
from accounts.models import AccountBackupAutomation
with tmp_to_root_org():
plan = get_object_or_none(AccountBackupAutomation, pk=pid)
if not plan:
@ -22,7 +23,7 @@ def task_activity_callback(self, pid, trigger):
@shared_task(verbose_name=_('Execute account backup plan'), activity_callback=task_activity_callback)
def execute_account_backup_plan(pid, trigger):
def execute_account_backup_task(pid, trigger):
from accounts.models import AccountBackupAutomation
with tmp_to_root_org():
plan = get_object_or_none(AccountBackupAutomation, pk=pid)

View File

@ -4,17 +4,14 @@ from assets.tasks.common import generate_automation_execution_data
from common.const.choices import Trigger
def automation_execute_start(task_name, tp, task_snapshot=None):
def quickstart_automation_by_snapshot(task_name, tp, task_snapshot=None):
from accounts.models import AutomationExecution
data = generate_automation_execution_data(task_name, tp, task_snapshot)
while True:
try:
_id = data['id']
AutomationExecution.objects.get(id=_id)
data['id'] = str(uuid.uuid4())
except AutomationExecution.DoesNotExist:
break
pk = data['id']
if AutomationExecution.objects.filter(id=pk).exists():
data['id'] = str(uuid.uuid4())
execution = AutomationExecution.objects.create(
trigger=Trigger.manual, **data
)

View File

@ -4,12 +4,12 @@ from django.utils.translation import gettext_lazy as _
from django.utils.translation import gettext_noop
from accounts.const import AutomationTypes
from accounts.tasks.common import automation_execute_start
from accounts.tasks.common import quickstart_automation_by_snapshot
from assets.models import Node
from common.utils import get_logger
from orgs.utils import org_aware_func
__all__ = ['gather_asset_accounts']
__all__ = ['gather_asset_accounts_task']
logger = get_logger(__name__)
@ -22,14 +22,14 @@ def gather_asset_accounts_util(nodes, task_name):
'nodes': [str(node.id) for node in nodes],
}
tp = AutomationTypes.verify_account
automation_execute_start(task_name, tp, task_snapshot)
quickstart_automation_by_snapshot(task_name, tp, task_snapshot)
@shared_task(
queue="ansible", verbose_name=_('Gather asset accounts'),
activity_callback=lambda self, node_ids, task_name=None: (node_ids, None)
)
def gather_asset_accounts(node_ids, task_name=None):
def gather_asset_accounts_task(node_ids, task_name=None):
if task_name is None:
task_name = gettext_noop("Gather assets accounts")

View File

@ -2,45 +2,33 @@ from celery import shared_task
from django.utils.translation import gettext_noop, ugettext_lazy as _
from accounts.const import AutomationTypes
from accounts.tasks.common import automation_execute_start
from accounts.tasks.common import quickstart_automation_by_snapshot
from common.utils import get_logger
from orgs.utils import org_aware_func
logger = get_logger(__file__)
__all__ = [
'push_accounts_to_assets',
'push_accounts_to_assets_task',
]
def push_util(account, assets, task_name):
task_snapshot = {
'secret': account.secret,
'secret_type': account.secret_type,
'accounts': [account.username],
'assets': [str(asset.id) for asset in assets],
}
tp = AutomationTypes.push_account
automation_execute_start(task_name, tp, task_snapshot)
@org_aware_func("assets")
def push_accounts_to_assets_util(accounts, assets):
from accounts.models import PushAccountAutomation
task_name = gettext_noop("Push accounts to assets")
task_name = PushAccountAutomation.generate_unique_name(task_name)
for account in accounts:
push_util(account, assets, task_name)
@shared_task(
queue="ansible", verbose_name=_('Push accounts to assets'),
activity_callback=lambda self, account_ids, asset_ids: (account_ids, None)
)
def push_accounts_to_assets(account_ids, asset_ids):
from assets.models import Asset
def push_accounts_to_assets_task(account_ids):
from accounts.models import PushAccountAutomation
from accounts.models import Account
assets = Asset.objects.filter(id__in=asset_ids)
accounts = Account.objects.filter(id__in=account_ids)
return push_accounts_to_assets_util(accounts, assets)
task_name = gettext_noop("Push accounts to assets")
task_name = PushAccountAutomation.generate_unique_name(task_name)
for account in accounts:
task_snapshot = {
'secret': account.secret,
'secret_type': account.secret_type,
'accounts': [account.username],
'assets': [str(account.asset_id)],
}
tp = AutomationTypes.push_account
quickstart_automation_by_snapshot(task_name, tp, task_snapshot)

View File

@ -1,16 +1,16 @@
from celery import shared_task
from django.utils.translation import gettext_noop
from django.utils.translation import gettext_lazy as _
from django.utils.translation import gettext_noop
from accounts.const import AutomationTypes
from accounts.tasks.common import automation_execute_start
from accounts.tasks.common import quickstart_automation_by_snapshot
from assets.const import GATEWAY_NAME
from common.utils import get_logger
from orgs.utils import org_aware_func
logger = get_logger(__name__)
__all__ = [
'verify_accounts_connectivity'
'verify_accounts_connectivity_task'
]
@ -22,19 +22,26 @@ def verify_connectivity_util(assets, tp, accounts, task_name):
'accounts': account_usernames,
'assets': [str(asset.id) for asset in assets],
}
automation_execute_start(task_name, tp, task_snapshot)
quickstart_automation_by_snapshot(task_name, tp, task_snapshot)
@org_aware_func("assets")
def verify_accounts_connectivity_util(accounts, assets, task_name):
gateway_assets = assets.filter(platform__name=GATEWAY_NAME)
def verify_accounts_connectivity_util(accounts, task_name):
from assets.models import Asset
asset_ids = [a.asset_id for a in accounts]
assets = Asset.objects.filter(id__in=asset_ids)
gateways = assets.filter(platform__name=GATEWAY_NAME)
verify_connectivity_util(
gateway_assets, AutomationTypes.verify_gateway_account, accounts, task_name
gateways, AutomationTypes.verify_gateway_account,
accounts, task_name
)
non_gateway_assets = assets.exclude(platform__name=GATEWAY_NAME)
common_assets = assets.exclude(platform__name=GATEWAY_NAME)
verify_connectivity_util(
non_gateway_assets, AutomationTypes.verify_account, accounts, task_name
common_assets, AutomationTypes.verify_account,
accounts, task_name
)
@ -42,11 +49,9 @@ def verify_accounts_connectivity_util(accounts, assets, task_name):
queue="ansible", verbose_name=_('Verify asset account availability'),
activity_callback=lambda self, account_ids, asset_ids: (account_ids, None)
)
def verify_accounts_connectivity(account_ids, asset_ids):
from assets.models import Asset
def verify_accounts_connectivity_task(account_ids):
from accounts.models import Account, VerifyAccountAutomation
assets = Asset.objects.filter(id__in=asset_ids)
accounts = Account.objects.filter(id__in=account_ids)
task_name = gettext_noop("Verify accounts connectivity")
task_name = VerifyAccountAutomation.generate_unique_name(task_name)
return verify_accounts_connectivity_util(accounts, assets, task_name)
return verify_accounts_connectivity_util(accounts, task_name)

View File

@ -25,17 +25,22 @@ router.register(r'push-account-executions', api.PushAccountExecutionViewSet, 'pu
router.register(r'push-account-records', api.PushAccountRecordViewSet, 'push-account-record')
urlpatterns = [
path('accounts/tasks/', api.AccountTaskCreateAPI.as_view(), name='account-task-create'),
path('account-secrets/<uuid:pk>/histories/', api.AccountHistoriesSecretAPI.as_view(), name='account-secret-history'),
path('accounts/tasks/', api.AccountsTaskCreateAPI.as_view(), name='account-task-create'),
path('account-secrets/<uuid:pk>/histories/', api.AccountHistoriesSecretAPI.as_view(),
name='account-secret-history'),
path('change-secret/<uuid:pk>/asset/remove/', api.ChangSecretRemoveAssetApi.as_view(), name='change-secret-remove-asset'),
path('change-secret/<uuid:pk>/asset/remove/', api.ChangSecretRemoveAssetApi.as_view(),
name='change-secret-remove-asset'),
path('change-secret/<uuid:pk>/asset/add/', api.ChangSecretAddAssetApi.as_view(), name='change-secret-add-asset'),
path('change-secret/<uuid:pk>/nodes/', api.ChangSecretNodeAddRemoveApi.as_view(), name='change-secret-add-or-remove-node'),
path('change-secret/<uuid:pk>/nodes/', api.ChangSecretNodeAddRemoveApi.as_view(),
name='change-secret-add-or-remove-node'),
path('change-secret/<uuid:pk>/assets/', api.ChangSecretAssetsListApi.as_view(), name='change-secret-assets'),
path('push-account/<uuid:pk>/asset/remove/', api.PushAccountRemoveAssetApi.as_view(), name='push-account-remove-asset'),
path('push-account/<uuid:pk>/asset/remove/', api.PushAccountRemoveAssetApi.as_view(),
name='push-account-remove-asset'),
path('push-accountt/<uuid:pk>/asset/add/', api.PushAccountAddAssetApi.as_view(), name='push-account-add-asset'),
path('push-account/<uuid:pk>/nodes/', api.PushAccountNodeAddRemoveApi.as_view(), name='push-account-add-or-remove-node'),
path('push-account/<uuid:pk>/nodes/', api.PushAccountNodeAddRemoveApi.as_view(),
name='push-account-add-or-remove-node'),
path('push-account/<uuid:pk>/assets/', api.PushAccountAssetsListApi.as_view(), name='push-account-assets'),
]

View File

@ -6,7 +6,7 @@ from django.utils.translation import gettext as _
from rest_framework.decorators import action
from rest_framework.response import Response
from accounts.tasks import push_accounts_to_assets, verify_accounts_connectivity
from accounts.tasks import push_accounts_to_assets_task, verify_accounts_connectivity_task
from assets import serializers
from assets.filters import IpInFilterBackend, LabelFilterBackend, NodeFilterBackend
from assets.models import Asset, Gateway
@ -180,9 +180,9 @@ class AssetTaskCreateApi(AssetsTaskMixin, generics.CreateAPIView):
def check_permissions(self, request):
action_perm_require = {
"refresh": "assets.refresh_assethardwareinfo",
"push_account": "accounts.add_pushaccountexecution",
"push_account": "accounts.push_account",
"test": "assets.test_assetconnectivity",
"test_account": "assets.test_account",
"test_account": "accounts.verify_account",
}
_action = request.data.get("action")
perm_required = action_perm_require.get(_action)
@ -205,9 +205,9 @@ class AssetTaskCreateApi(AssetsTaskMixin, generics.CreateAPIView):
asset_ids = [asset.id]
account_ids = accounts.values_list("id", flat=True)
if action == "push_account":
task = push_accounts_to_assets.delay(account_ids, asset_ids)
task = push_accounts_to_assets_task.delay(account_ids, asset_ids)
elif action == "test_account":
task = verify_accounts_connectivity.delay(account_ids, asset_ids)
task = verify_accounts_connectivity_task.delay(account_ids, asset_ids)
else:
task = None
return task

View File

@ -103,7 +103,7 @@ class NodeAddAssetsApi(generics.UpdateAPIView):
instance = None
permission_classes = (RBACPermission,)
rbac_perms = {
'PUT': 'assets.add_assettonode',
'PUT': 'assets.change_assetnodes',
}
def perform_update(self, serializer):
@ -118,7 +118,7 @@ class NodeRemoveAssetsApi(generics.UpdateAPIView):
instance = None
permission_classes = (RBACPermission,)
rbac_perms = {
'PUT': 'assets.remove_assetfromnode',
'PUT': 'assets.change_assetnodes',
}
def perform_update(self, serializer):
@ -140,7 +140,7 @@ class MoveAssetsToNodeApi(generics.UpdateAPIView):
instance = None
permission_classes = (RBACPermission,)
rbac_perms = {
'PUT': 'assets.move_assettonode',
'PUT': 'assets.change_assetnodes',
}
def perform_update(self, serializer):

View File

@ -63,6 +63,8 @@ class BasePlaybookManager:
)
if not os.path.exists(path):
os.makedirs(path, exist_ok=True, mode=0o755)
if settings.DEBUG_DEV:
logger.debug('Ansible runtime dir: {}'.format(path))
return path
@staticmethod

View File

@ -33,7 +33,7 @@ class PingGatewayManager:
err = _('No account')
return False, err
print('Test account: {}'.format(account))
print('- ' + _('Asset, {}, using account {}').format(gateway, account))
try:
proxy.connect(
gateway.address,

View File

@ -15,4 +15,29 @@ class Migration(migrations.Migration):
name='charset',
field=models.CharField(choices=[('utf-8', 'UTF-8'), ('gbk', 'GBK')], default='utf-8', max_length=8, verbose_name='Charset'),
),
migrations.AddField(
model_name='platform',
name='created_by',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by'),
),
migrations.AddField(
model_name='platform',
name='date_created',
field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created'),
),
migrations.AddField(
model_name='platform',
name='date_updated',
field=models.DateTimeField(auto_now=True, verbose_name='Date updated'),
),
migrations.AddField(
model_name='platform',
name='updated_by',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by'),
),
migrations.AlterField(
model_name='platform',
name='comment',
field=models.TextField(blank=True, default='', verbose_name='Comment'),
),
]

View File

@ -12,6 +12,6 @@ class Migration(migrations.Migration):
operations = [
migrations.AlterModelOptions(
name='asset',
options={'ordering': ['name'], 'permissions': [('refresh_assethardwareinfo', 'Can refresh asset hardware info'), ('test_assetconnectivity', 'Can test asset connectivity'), ('push_assetaccount', 'Can push account to asset'), ('test_account', 'Can verify account'), ('match_asset', 'Can match asset'), ('add_assettonode', 'Add asset to node'), ('move_assettonode', 'Move asset to node'), ('remove_assetfromnode', 'Remove asset from node')], 'verbose_name': 'Asset'},
options={'ordering': ['name'], 'permissions': [('refresh_assethardwareinfo', 'Can refresh asset hardware info'), ('test_assetconnectivity', 'Can test asset connectivity'), ('push_assetaccount', 'Can push account to asset'), ('test_account', 'Can verify account'), ('match_asset', 'Can match asset'), ('change_assettonode', 'Can change asset nodes')], 'verbose_name': 'Asset'},
),
]

View File

@ -0,0 +1,17 @@
# Generated by Django 3.2.14 on 2023-02-21 05:11
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('assets', '0109_alter_asset_options'),
]
operations = [
migrations.AlterModelOptions(
name='asset',
options={'ordering': ['name'], 'permissions': [('refresh_assethardwareinfo', 'Can refresh asset hardware info'), ('test_assetconnectivity', 'Can test asset connectivity'), ('push_assetaccount', 'Can push account to asset'), ('test_account', 'Can verify account'), ('match_asset', 'Can match asset'), ('change_assetnodes', 'Can change asset nodes')], 'verbose_name': 'Asset'},
),
]

View File

@ -1,38 +0,0 @@
# Generated by Django 3.2.14 on 2023-02-20 02:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('assets', '0109_alter_asset_options'),
]
operations = [
migrations.AddField(
model_name='platform',
name='created_by',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by'),
),
migrations.AddField(
model_name='platform',
name='date_created',
field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created'),
),
migrations.AddField(
model_name='platform',
name='date_updated',
field=models.DateTimeField(auto_now=True, verbose_name='Date updated'),
),
migrations.AddField(
model_name='platform',
name='updated_by',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by'),
),
migrations.AlterField(
model_name='platform',
name='comment',
field=models.TextField(blank=True, default='', verbose_name='Comment'),
),
]

View File

@ -0,0 +1,17 @@
# Generated by Django 3.2.14 on 2023-02-21 05:22
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('assets', '0110_alter_asset_options'),
]
operations = [
migrations.AlterModelOptions(
name='asset',
options={'ordering': ['name'], 'permissions': [('refresh_assethardwareinfo', 'Can refresh asset hardware info'), ('test_assetconnectivity', 'Can test asset connectivity'), ('match_asset', 'Can match asset'), ('change_assetnodes', 'Can change asset nodes')], 'verbose_name': 'Asset'},
),
]

View File

@ -281,10 +281,6 @@ class Asset(NodesRelationMixin, AbsConnectivity, JMSOrgBaseModel):
permissions = [
('refresh_assethardwareinfo', _('Can refresh asset hardware info')),
('test_assetconnectivity', _('Can test asset connectivity')),
('push_assetaccount', _('Can push account to asset')),
('test_account', _('Can verify account')),
('match_asset', _('Can match asset')),
('add_assettonode', _('Add asset to node')),
('move_assettonode', _('Move asset to node')),
('remove_assetfromnode', _('Remove asset from node'))
('change_assetnodes', _('Can change asset nodes')),
]

View File

@ -6,7 +6,7 @@ from django.utils.translation import ugettext_lazy as _
from assets.models.asset import Asset
from assets.models.node import Node
from assets.tasks import execute_automation
from assets.tasks import execute_asset_automation_task
from common.const.choices import Trigger
from common.db.fields import EncryptJsonDictTextField
from ops.mixin import PeriodTaskModelMixin
@ -49,7 +49,7 @@ class BaseAutomation(PeriodTaskModelMixin, JMSOrgBaseModel):
@property
def execute_task(self):
return execute_automation
return execute_asset_automation_task
def get_register_task(self):
name = f"automation_{self.type}_strategy_period_{str(self.id)[:8]}"

View File

@ -30,11 +30,11 @@ class Domain(JMSOrgBaseModel):
def random_gateway(self):
gateways = [gw for gw in self.active_gateways if gw.is_connective]
if not gateways:
logger.warn(f'Gateway all bad. domain={self}, gateway_num={len(gateways)}.')
gateways = self.active_gateways
if not gateways:
logger.warn(f'Not active gateway. domain={self}')
logger.warn(f'Not active gateway, domain={self}, pass')
return None
return random.choice(gateways)

View File

@ -83,7 +83,7 @@ class AssetAccountSerializer(
def validate_push_now(self, value):
request = self.context['request']
if not request.user.has_perms('assets.push_assetaccount'):
if not request.user.has_perms('accounts.push_account'):
return False
return value

View File

@ -1,9 +1,9 @@
from celery import shared_task
from django.utils.translation import gettext_lazy as _
from orgs.utils import tmp_to_root_org, tmp_to_org
from common.utils import get_logger, get_object_or_none
from assets.const import AutomationTypes
from common.utils import get_logger, get_object_or_none
from orgs.utils import tmp_to_root_org, tmp_to_org
logger = get_logger(__file__)
@ -24,7 +24,7 @@ def task_activity_callback(self, pid, trigger, tp):
queue='ansible', verbose_name=_('Asset execute automation'),
activity_callback=task_activity_callback
)
def execute_automation(pid, trigger, tp):
def execute_asset_automation_task(pid, trigger, tp):
model = AutomationTypes.get_type_model(tp)
with tmp_to_root_org():
instance = get_object_or_none(model, pk=pid)

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8285be68ee7edb5423cf973c1c96a3659b75b40566c07a1557a17d59fcaf294d
size 136019
oid sha256:014483808a830a01f5432fdc44bc34f7f392e53a160ffa97eb377dbb49e0ec9a
size 135547

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-02-20 19:19+0800\n"
"POT-Creation-Date: 2023-02-21 13:46+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"
@ -158,7 +158,8 @@ msgstr "作成してプッシュ"
msgid "Only create"
msgstr "作成のみ"
#: accounts/models/account.py:47 accounts/models/gathered_account.py:14
#: accounts/models/account.py:47
#: 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
@ -181,7 +182,7 @@ msgid "Su from"
msgstr "から切り替え"
#: accounts/models/account.py:53 settings/serializers/auth/cas.py:20
#: terminal/models/applet/applet.py:28
#: terminal/models/applet/applet.py:29
msgid "Version"
msgstr "バージョン"
@ -214,15 +215,23 @@ msgstr "資産履歴アカウントを表示できます"
msgid "Can view asset history account secret"
msgstr "資産履歴アカウントパスワードを表示できます"
#: accounts/models/account.py:111
#: accounts/models/account.py:67
msgid "Can verify account"
msgstr "アカウントを確認できます"
#: accounts/models/account.py:68
msgid "Can push account"
msgstr "アカウントをプッシュできます"
#: accounts/models/account.py:113
msgid "Account template"
msgstr "アカウント テンプレート"
#: accounts/models/account.py:116
#: accounts/models/account.py:118
msgid "Can view asset account template secret"
msgstr "アセット アカウント テンプレートのパスワードを表示できます"
#: accounts/models/account.py:117
#: accounts/models/account.py:119
msgid "Can change asset account template secret"
msgstr "アセット アカウント テンプレートのパスワードを変更できます"
@ -241,7 +250,7 @@ msgstr "アカウントバックアップ計画"
#: accounts/models/automations/backup_account.py:83
#: assets/models/automations/base.py:114 audits/models.py:55
#: ops/models/base.py:55 ops/models/celery.py:63 ops/models/job.py:122
#: perms/models/asset_permission.py:72 terminal/models/applet/host.py:108
#: perms/models/asset_permission.py:72 terminal/models/applet/host.py:109
#: terminal/models/session/session.py:45
#: tickets/models/ticket/apply_application.py:30
#: tickets/models/ticket/apply_asset.py:19
@ -327,12 +336,7 @@ msgstr "プッシュ アカウントの作成の実行"
msgid "Secret type"
msgstr "鍵の種類"
#: accounts/models/automations/change_secret.py:21
#: accounts/serializers/automations/change_secret.py:40
msgid "Secret strategy"
msgstr "鍵ポリシー"
#: accounts/models/automations/change_secret.py:23
#: accounts/models/automations/change_secret.py:19
#: accounts/models/automations/change_secret.py:72 accounts/models/base.py:38
#: authentication/models/temp_token.py:10
#: authentication/templates/authentication/_access_key_modal.html:31
@ -340,6 +344,11 @@ msgstr "鍵ポリシー"
msgid "Secret"
msgstr "ひみつ"
#: accounts/models/automations/change_secret.py:22
#: accounts/serializers/automations/change_secret.py:40
msgid "Secret strategy"
msgstr "鍵ポリシー"
#: accounts/models/automations/change_secret.py:24
msgid "Password rules"
msgstr "パスワードルール"
@ -363,7 +372,7 @@ msgstr "開始日"
#: accounts/models/automations/change_secret.py:74
#: assets/models/automations/base.py:115 ops/models/base.py:56
#: ops/models/celery.py:64 ops/models/job.py:123
#: terminal/models/applet/host.py:109
#: terminal/models/applet/host.py:110
msgid "Date finished"
msgstr "終了日"
@ -376,20 +385,19 @@ msgstr "間違い"
msgid "Change secret record"
msgstr "パスワード レコードの変更"
#: accounts/models/automations/gather_account.py:14
msgid "Present"
msgstr "存在する"
#: accounts/models/automations/gather_account.py:15
#: accounts/tasks/gather_accounts.py:29
msgid "Gather asset accounts"
msgstr "アカウントのコレクション"
msgid "Date last login"
msgstr "最終ログイン日"
#: accounts/models/automations/push_account.py:13
msgid "Triggers"
msgstr "トリガー方式"
#: accounts/models/automations/push_account.py:14 accounts/models/base.py:34
#: accounts/models/gathered_account.py:15 acls/serializers/base.py:18
#: acls/serializers/base.py:49 assets/models/_user.py:23 audits/models.py:157
#: authentication/forms.py:25 authentication/forms.py:27
#: authentication/models/temp_token.py:9
#: accounts/models/automations/gather_account.py:17
#: accounts/models/automations/push_account.py:13 accounts/models/base.py:34
#: acls/serializers/base.py:18 acls/serializers/base.py:49
#: assets/models/_user.py:23 audits/models.py:157 authentication/forms.py:25
#: authentication/forms.py:27 authentication/models/temp_token.py:9
#: authentication/templates/authentication/_msg_different_city.html:9
#: authentication/templates/authentication/_msg_oauth_bind.html:9
#: users/forms/profile.py:32 users/forms/profile.py:112
@ -398,7 +406,24 @@ msgstr "トリガー方式"
msgid "Username"
msgstr "ユーザー名"
#: accounts/models/automations/push_account.py:15 acls/models/base.py:81
#: accounts/models/automations/gather_account.py:18
msgid "Address last login"
msgstr "最終ログインアドレス"
#: accounts/models/automations/gather_account.py:25 rbac/tree.py:50
msgid "Gather account"
msgstr "アカウントを集める"
#: accounts/models/automations/gather_account.py:41
#: accounts/tasks/gather_accounts.py:29
msgid "Gather asset accounts"
msgstr "アカウントのコレクション"
#: accounts/models/automations/push_account.py:12
msgid "Triggers"
msgstr "トリガー方式"
#: accounts/models/automations/push_account.py:14 acls/models/base.py:81
#: acls/serializers/base.py:81 acls/serializers/login_acl.py:25
#: assets/models/cmd_filter.py:81 audits/models.py:65 audits/serializers.py:82
#: authentication/serializers/connect_token_secret.py:109
@ -406,7 +431,7 @@ msgstr "ユーザー名"
msgid "Action"
msgstr "アクション"
#: accounts/models/automations/push_account.py:41
#: accounts/models/automations/push_account.py:40
msgid "Push asset account"
msgstr "アカウントプッシュ"
@ -422,13 +447,13 @@ msgstr "アカウントの確認"
#: assets/models/group.py:20 assets/models/label.py:18
#: assets/models/platform.py:21 assets/models/platform.py:76
#: assets/serializers/asset/common.py:68 assets/serializers/asset/common.py:142
#: assets/serializers/platform.py:132
#: assets/serializers/platform.py:91 assets/serializers/platform.py:136
#: authentication/serializers/connect_token_secret.py:103 ops/mixin.py:21
#: ops/models/adhoc.py:21 ops/models/celery.py:15 ops/models/celery.py:57
#: ops/models/job.py:26 ops/models/playbook.py:23 ops/serializers/job.py:19
#: orgs/models.py:69 perms/models/asset_permission.py:56 rbac/models/role.py:29
#: settings/models.py:33 settings/serializers/sms.py:6
#: terminal/models/applet/applet.py:26 terminal/models/component/endpoint.py:12
#: terminal/models/applet/applet.py:27 terminal/models/component/endpoint.py:12
#: terminal/models/component/endpoint.py:90
#: terminal/models/component/storage.py:26 terminal/models/component/task.py:15
#: terminal/models/component/terminal.py:79 users/forms/profile.py:33
@ -445,26 +470,10 @@ msgstr "特権アカウント"
#: assets/models/automations/base.py:21 assets/models/cmd_filter.py:39
#: assets/models/label.py:22
#: authentication/serializers/connect_token_secret.py:107
#: terminal/models/applet/applet.py:31 users/serializers/user.py:159
#: terminal/models/applet/applet.py:32 users/serializers/user.py:159
msgid "Is active"
msgstr "アクティブです。"
#: accounts/models/gathered_account.py:12
msgid "Present"
msgstr "存在する"
#: accounts/models/gathered_account.py:13
msgid "Date last login"
msgstr "最終ログイン日"
#: accounts/models/gathered_account.py:16
msgid "Address last login"
msgstr "最終ログインアドレス"
#: accounts/models/gathered_account.py:23 rbac/tree.py:50
msgid "Gather account"
msgstr "アカウントを集める"
#: accounts/notifications.py:8
msgid "Notification of account backup route task results"
msgstr "アカウントバックアップルートタスクの結果の通知"
@ -524,7 +533,7 @@ msgstr "エスクローされたパスワード"
#: accounts/serializers/account/account.py:75 applications/models.py:11
#: assets/models/label.py:21 assets/models/platform.py:77
#: assets/serializers/asset/common.py:121 assets/serializers/cagegory.py:8
#: assets/serializers/platform.py:93 assets/serializers/platform.py:133
#: assets/serializers/platform.py:97 assets/serializers/platform.py:137
#: perms/serializers/user_permission.py:25 settings/models.py:35
#: tickets/models/ticket/apply_application.py:13
msgid "Category"
@ -535,10 +544,10 @@ msgstr "カテゴリ"
#: 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
#: assets/serializers/asset/common.py:122 assets/serializers/platform.py:92
#: assets/serializers/asset/common.py:122 assets/serializers/platform.py:96
#: audits/serializers.py:48
#: authentication/serializers/connect_token_secret.py:116 ops/models/job.py:37
#: perms/serializers/user_permission.py:26 terminal/models/applet/applet.py:30
#: perms/serializers/user_permission.py:26 terminal/models/applet/applet.py:31
#: terminal/models/component/storage.py:57
#: terminal/models/component/storage.py:146 terminal/serializers/applet.py:28
#: terminal/serializers/session.py:22 terminal/serializers/storage.py:224
@ -643,7 +652,7 @@ msgstr "失敗しました"
msgid "Account execute automation"
msgstr "アカウント実行の自動化"
#: accounts/tasks/backup_account.py:24
#: accounts/tasks/backup_account.py:25
msgid "Execute account backup plan"
msgstr "アカウントのバックアップ計画を実施する"
@ -651,15 +660,15 @@ msgstr "アカウントのバックアップ計画を実施する"
msgid "Gather assets accounts"
msgstr "資産の口座番号を収集する"
#: accounts/tasks/push_account.py:30 accounts/tasks/push_account.py:37
#: accounts/tasks/push_account.py:15 accounts/tasks/push_account.py:23
msgid "Push accounts to assets"
msgstr "アカウントをアセットにプッシュ:"
#: accounts/tasks/verify_account.py:42
#: accounts/tasks/verify_account.py:49
msgid "Verify asset account availability"
msgstr "アセット アカウントの可用性を確認する"
#: accounts/tasks/verify_account.py:50
#: accounts/tasks/verify_account.py:55
msgid "Verify accounts connectivity"
msgstr "アカウント接続のテスト"
@ -921,7 +930,7 @@ msgstr "削除に失敗し、ノードにアセットが含まれています。
msgid "App assets"
msgstr "アプリ資産"
#: assets/automations/base/manager.py:105
#: assets/automations/base/manager.py:107
msgid "{} disabled"
msgstr "{} 無効"
@ -930,6 +939,12 @@ msgstr "{} 無効"
msgid "No account"
msgstr "アカウントなし"
#: assets/automations/ping_gateway/manager.py:36
#, fuzzy
#| msgid "Assets amount"
msgid "Asset, {}, using account {}"
msgstr "資産額"
#: assets/automations/ping_gateway/manager.py:55
#, python-brace-format
msgid "Unable to connect to port {port} on {address}"
@ -988,11 +1003,11 @@ msgid "Cloud service"
msgstr "クラウド サービス"
#: assets/const/category.py:15 assets/models/asset/web.py:16 audits/const.py:33
#: terminal/models/applet/applet.py:24
#: terminal/models/applet/applet.py:25
msgid "Web"
msgstr "Web"
#: assets/const/device.py:7 terminal/models/applet/applet.py:23
#: assets/const/device.py:7 terminal/models/applet/applet.py:24
#: tickets/const.py:8
msgid "General"
msgstr "一般"
@ -1028,7 +1043,7 @@ msgid "Basic"
msgstr "基本"
#: assets/const/web.py:61 assets/models/asset/web.py:13
#: assets/serializers/asset/common.py:117 assets/serializers/platform.py:39
#: assets/serializers/asset/common.py:117 assets/serializers/platform.py:40
msgid "Script"
msgstr "脚本"
@ -1044,8 +1059,8 @@ msgstr "SSHパブリックキー"
#: assets/models/cmd_filter.py:88 assets/models/group.py:23
#: common/db/models.py:37 ops/models/adhoc.py:27 ops/models/job.py:45
#: ops/models/playbook.py:26 rbac/models/role.py:37 settings/models.py:38
#: terminal/models/applet/applet.py:35 terminal/models/applet/applet.py:151
#: terminal/models/applet/host.py:110 terminal/models/component/endpoint.py:24
#: terminal/models/applet/applet.py:36 terminal/models/applet/applet.py:155
#: terminal/models/applet/host.py:111 terminal/models/component/endpoint.py:24
#: terminal/models/component/endpoint.py:100
#: terminal/models/session/session.py:47 tickets/models/comment.py:32
#: tickets/models/ticket/general.py:297 users/models/user.py:756
@ -1094,7 +1109,7 @@ msgstr "ユーザーと同じユーザー名"
#: assets/models/_user.py:52 authentication/models/connection_token.py:38
#: authentication/serializers/connect_token_secret.py:104
#: terminal/models/applet/applet.py:33 terminal/serializers/session.py:20
#: terminal/models/applet/applet.py:34 terminal/serializers/session.py:20
#: terminal/serializers/session.py:41 terminal/serializers/storage.py:68
msgid "Protocol"
msgstr "プロトコル"
@ -1183,28 +1198,12 @@ msgid "Can test asset connectivity"
msgstr "資産接続をテストできます"
#: assets/models/asset/common.py:284
msgid "Can push account to asset"
msgstr "アカウントをアセットにプッシュできます"
#: assets/models/asset/common.py:285
msgid "Can verify account"
msgstr "アカウントを確認できます"
#: assets/models/asset/common.py:286
msgid "Can match asset"
msgstr "アセットを一致させることができます"
#: assets/models/asset/common.py:287
msgid "Add asset to node"
msgstr "ノードにアセットを追加する"
#: assets/models/asset/common.py:288
msgid "Move asset to node"
msgstr "アセットをノードに移動する"
#: assets/models/asset/common.py:289
msgid "Remove asset from node"
msgstr "ノードからアセットを削除"
#: assets/models/asset/common.py:285
msgid "Can change asset nodes"
msgstr "資産ノードを変更できます"
#: assets/models/asset/database.py:10 assets/serializers/asset/common.py:110
#: settings/serializers/email.py:37
@ -1227,22 +1226,22 @@ msgstr "クライアントキー"
msgid "Allow invalid cert"
msgstr "証明書チェックを無視"
#: assets/models/asset/web.py:9 assets/serializers/platform.py:29
#: assets/models/asset/web.py:9 assets/serializers/platform.py:30
msgid "Autofill"
msgstr "自動充填"
#: assets/models/asset/web.py:10 assets/serializers/asset/common.py:114
#: assets/serializers/platform.py:31
#: assets/serializers/platform.py:32
msgid "Username selector"
msgstr "ユーザー名ピッカー"
#: assets/models/asset/web.py:11 assets/serializers/asset/common.py:115
#: assets/serializers/platform.py:34
#: assets/serializers/platform.py:35
msgid "Password selector"
msgstr "パスワードセレクター"
#: assets/models/asset/web.py:12 assets/serializers/asset/common.py:116
#: assets/serializers/platform.py:37
#: assets/serializers/platform.py:38
msgid "Submit selector"
msgstr "ボタンセレクターを確認する"
@ -1261,7 +1260,7 @@ msgstr "アセットの自動化タスク"
#: assets/models/automations/base.py:112 audits/models.py:177
#: audits/serializers.py:49 ops/models/base.py:49 ops/models/job.py:114
#: terminal/models/applet/applet.py:150 terminal/models/applet/host.py:107
#: terminal/models/applet/applet.py:154 terminal/models/applet/host.py:108
#: terminal/models/component/status.py:27 terminal/serializers/applet.py:17
#: terminal/serializers/applet_host.py:93 tickets/models/ticket/general.py:283
#: tickets/serializers/super_ticket.py:13
@ -1403,45 +1402,45 @@ msgstr "有効化"
msgid "Ansible config"
msgstr "Ansible 構成"
#: assets/models/platform.py:44 assets/serializers/platform.py:60
#: assets/models/platform.py:44 assets/serializers/platform.py:61
msgid "Ping enabled"
msgstr "アセット ディスカバリを有効にする"
#: assets/models/platform.py:45 assets/serializers/platform.py:61
#: assets/models/platform.py:45 assets/serializers/platform.py:62
msgid "Ping method"
msgstr "資産検出方法"
#: assets/models/platform.py:46 assets/models/platform.py:59
#: assets/serializers/platform.py:62
#: assets/serializers/platform.py:63
msgid "Gather facts enabled"
msgstr "資産情報の収集を有効にする"
#: assets/models/platform.py:47 assets/models/platform.py:61
#: assets/serializers/platform.py:63
#: assets/serializers/platform.py:64
msgid "Gather facts method"
msgstr "情報収集の方法"
#: assets/models/platform.py:48 assets/serializers/platform.py:66
#: assets/models/platform.py:48 assets/serializers/platform.py:67
msgid "Change secret enabled"
msgstr "パスワードの変更が有効"
#: assets/models/platform.py:50 assets/serializers/platform.py:67
#: assets/models/platform.py:50 assets/serializers/platform.py:68
msgid "Change secret method"
msgstr "パスワード変更モード"
#: assets/models/platform.py:52 assets/serializers/platform.py:68
#: assets/models/platform.py:52 assets/serializers/platform.py:69
msgid "Push account enabled"
msgstr "アカウントのプッシュを有効にする"
#: assets/models/platform.py:54 assets/serializers/platform.py:69
#: assets/models/platform.py:54 assets/serializers/platform.py:70
msgid "Push account method"
msgstr "アカウントプッシュ方式"
#: assets/models/platform.py:56 assets/serializers/platform.py:64
#: assets/models/platform.py:56 assets/serializers/platform.py:65
msgid "Verify account enabled"
msgstr "アカウントの確認をオンにする"
#: assets/models/platform.py:58 assets/serializers/platform.py:65
#: assets/models/platform.py:58 assets/serializers/platform.py:66
msgid "Verify account method"
msgstr "アカウント認証方法"
@ -1453,23 +1452,23 @@ msgstr "メタ"
msgid "Internal"
msgstr "ビルトイン"
#: assets/models/platform.py:83 assets/serializers/platform.py:90
#: assets/models/platform.py:83 assets/serializers/platform.py:94
msgid "Charset"
msgstr "シャーセット"
#: assets/models/platform.py:85 assets/serializers/platform.py:118
#: assets/models/platform.py:85 assets/serializers/platform.py:122
msgid "Domain enabled"
msgstr "ドメインを有効にする"
#: assets/models/platform.py:87 assets/serializers/platform.py:117
#: assets/models/platform.py:87 assets/serializers/platform.py:121
msgid "Su enabled"
msgstr "アカウントの切り替えを有効にする"
#: assets/models/platform.py:88 assets/serializers/platform.py:100
#: assets/models/platform.py:88 assets/serializers/platform.py:104
msgid "Su method"
msgstr "アカウントの切り替え方法"
#: assets/models/platform.py:90 assets/serializers/platform.py:97
#: assets/models/platform.py:90 assets/serializers/platform.py:101
msgid "Automation"
msgstr "オートメーション"
@ -1482,7 +1481,7 @@ msgstr "%(value)s は偶数ではありません"
msgid "Auto fill"
msgstr "自動充填"
#: assets/serializers/asset/common.py:124 assets/serializers/platform.py:95
#: assets/serializers/asset/common.py:124 assets/serializers/platform.py:99
#: authentication/serializers/connect_token_secret.py:28
#: authentication/serializers/connect_token_secret.py:66
#: perms/serializers/user_permission.py:24 xpack/plugins/cloud/models.py:99
@ -1594,31 +1593,31 @@ msgstr "含まれない:/"
msgid "The same level node name cannot be the same"
msgstr "同じレベルのノード名を同じにすることはできません。"
#: assets/serializers/platform.py:25
#: assets/serializers/platform.py:26
msgid "SFTP enabled"
msgstr "SFTP が有効"
#: assets/serializers/platform.py:26
#: assets/serializers/platform.py:27
msgid "SFTP home"
msgstr "SFTP ルート パス"
#: assets/serializers/platform.py:42
#: assets/serializers/platform.py:43
msgid "Auth with username"
msgstr "ユーザー名で認証する"
#: assets/serializers/platform.py:70
#: assets/serializers/platform.py:71
msgid "Gather accounts enabled"
msgstr "アカウント収集を有効にする"
#: assets/serializers/platform.py:71
#: assets/serializers/platform.py:72
msgid "Gather accounts method"
msgstr "アカウントの収集方法"
#: assets/serializers/platform.py:77
#: assets/serializers/platform.py:78
msgid "Primary"
msgstr "主要"
#: assets/serializers/platform.py:119
#: assets/serializers/platform.py:123
msgid "Default Domain"
msgstr "デフォルト ドメイン"
@ -1762,7 +1761,7 @@ msgid "Change password"
msgstr "パスワードを変更する"
#: audits/const.py:34 settings/serializers/terminal.py:6
#: terminal/models/applet/host.py:24 terminal/models/component/terminal.py:156
#: terminal/models/applet/host.py:25 terminal/models/component/terminal.py:156
#: terminal/serializers/session.py:48
msgid "Terminal"
msgstr "ターミナル"
@ -1779,7 +1778,7 @@ msgstr "セッションログ"
msgid "Login log"
msgstr "ログインログ"
#: audits/const.py:42 terminal/models/applet/host.py:111
#: audits/const.py:42 terminal/models/applet/host.py:112
#: terminal/models/component/task.py:24
msgid "Task"
msgstr "タスク"
@ -3587,7 +3586,7 @@ msgstr "組織"
msgid "Org name"
msgstr "組織名"
#: orgs/models.py:70 rbac/models/role.py:36 terminal/models/applet/applet.py:32
#: orgs/models.py:70 rbac/models/role.py:36 terminal/models/applet/applet.py:33
msgid "Builtin"
msgstr "ビルトイン"
@ -3832,7 +3831,7 @@ msgstr "パーマ"
msgid "Users amount"
msgstr "ユーザー数"
#: rbac/serializers/role.py:28 terminal/models/applet/applet.py:27
#: rbac/serializers/role.py:28 terminal/models/applet/applet.py:28
msgid "Display name"
msgstr "表示名"
@ -3896,8 +3895,8 @@ msgstr "タスクセンター"
msgid "My assets"
msgstr "私の資産"
#: rbac/tree.py:57 terminal/models/applet/applet.py:42
#: terminal/models/applet/applet.py:147 terminal/models/applet/host.py:27
#: rbac/tree.py:57 terminal/models/applet/applet.py:43
#: terminal/models/applet/applet.py:151 terminal/models/applet/host.py:28
msgid "Applet"
msgstr "リモートアプリケーション"
@ -5421,44 +5420,44 @@ msgstr "一括作成非サポート"
msgid "Storage is invalid"
msgstr "ストレージが無効です"
#: terminal/models/applet/applet.py:29
#: terminal/models/applet/applet.py:30
msgid "Author"
msgstr "著者"
#: terminal/models/applet/applet.py:34
#: terminal/models/applet/applet.py:35
msgid "Tags"
msgstr "ラベル"
#: terminal/models/applet/applet.py:38 terminal/serializers/storage.py:157
#: terminal/models/applet/applet.py:39 terminal/serializers/storage.py:157
msgid "Hosts"
msgstr "ホスト"
#: terminal/models/applet/applet.py:83
#: terminal/models/applet/applet.py:84
msgid "Applet pkg not valid, Missing file {}"
msgstr "無効なアプレット パッケージ、ファイル {} がありません"
#: terminal/models/applet/applet.py:149 terminal/models/applet/host.py:33
#: terminal/models/applet/host.py:105
#: terminal/models/applet/applet.py:153 terminal/models/applet/host.py:34
#: terminal/models/applet/host.py:106
msgid "Hosting"
msgstr "ホスト マシン"
#: terminal/models/applet/host.py:18 terminal/serializers/applet_host.py:43
#: terminal/models/applet/host.py:19 terminal/serializers/applet_host.py:43
msgid "Deploy options"
msgstr "展開パラメーター"
#: terminal/models/applet/host.py:19
#: terminal/models/applet/host.py:20
msgid "Inited"
msgstr "初期化された"
#: terminal/models/applet/host.py:20
#: terminal/models/applet/host.py:21
msgid "Date inited"
msgstr ""
#: terminal/models/applet/host.py:21
#: terminal/models/applet/host.py:22
msgid "Date synced"
msgstr "同期日"
#: terminal/models/applet/host.py:106
#: terminal/models/applet/host.py:107
msgid "Initial"
msgstr "初期化"
@ -7287,14 +7286,6 @@ 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 "利用できないアカウント"
@ -7362,3 +7353,21 @@ msgstr "究極のエディション"
#: xpack/plugins/license/models.py:85
msgid "Community edition"
msgstr "コミュニティ版"
#~ msgid "Can push account to asset"
#~ msgstr "アカウントをアセットにプッシュできます"
#~ msgid "Add asset to node"
#~ msgstr "ノードにアセットを追加する"
#~ msgid "Move asset to node"
#~ msgstr "アセットをノードに移動する"
#~ msgid "Remove asset from node"
#~ msgstr "ノードからアセットを削除"
#~ msgid "Run sync instance task"
#~ msgstr "同期インスタンス タスクを実行する"
#~ msgid "Period clean sync instance task execution"
#~ msgstr "同期インスタンス タスクの実行記録を定期的にクリアする"

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3a10e56f57d89f413c4aac8026e4339f630f70f6a66df8b9edee5b39bed88a75
size 111742
oid sha256:1c1524b6173a2613845d9450d84ef8ca9cf1be6d0f7cdae2a89f6131d6abc1f1
size 111449

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: JumpServer 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-02-20 19:19+0800\n"
"POT-Creation-Date: 2023-02-21 13:46+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"
@ -157,7 +157,8 @@ msgstr "创建并推送"
msgid "Only create"
msgstr "仅创建"
#: accounts/models/account.py:47 accounts/models/gathered_account.py:14
#: accounts/models/account.py:47
#: 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
@ -180,7 +181,7 @@ msgid "Su from"
msgstr "切换自"
#: accounts/models/account.py:53 settings/serializers/auth/cas.py:20
#: terminal/models/applet/applet.py:28
#: terminal/models/applet/applet.py:29
msgid "Version"
msgstr "版本"
@ -213,15 +214,23 @@ msgstr "可以查看资产历史账号"
msgid "Can view asset history account secret"
msgstr "可以查看资产历史账号密码"
#: accounts/models/account.py:111
#: accounts/models/account.py:67
msgid "Can verify account"
msgstr "可以验证账号"
#: accounts/models/account.py:68
msgid "Can push account"
msgstr "可以推送账号"
#: accounts/models/account.py:113
msgid "Account template"
msgstr "账号模版"
#: accounts/models/account.py:116
#: accounts/models/account.py:118
msgid "Can view asset account template secret"
msgstr "可以查看资产账号模版密码"
#: accounts/models/account.py:117
#: accounts/models/account.py:119
msgid "Can change asset account template secret"
msgstr "可以更改资产账号模版密码"
@ -240,7 +249,7 @@ msgstr "账号备份计划"
#: accounts/models/automations/backup_account.py:83
#: assets/models/automations/base.py:114 audits/models.py:55
#: ops/models/base.py:55 ops/models/celery.py:63 ops/models/job.py:122
#: perms/models/asset_permission.py:72 terminal/models/applet/host.py:108
#: perms/models/asset_permission.py:72 terminal/models/applet/host.py:109
#: terminal/models/session/session.py:45
#: tickets/models/ticket/apply_application.py:30
#: tickets/models/ticket/apply_asset.py:19
@ -326,12 +335,7 @@ msgstr "创建推送账号执行"
msgid "Secret type"
msgstr "密文类型"
#: accounts/models/automations/change_secret.py:21
#: accounts/serializers/automations/change_secret.py:40
msgid "Secret strategy"
msgstr "密文策略"
#: accounts/models/automations/change_secret.py:23
#: accounts/models/automations/change_secret.py:19
#: accounts/models/automations/change_secret.py:72 accounts/models/base.py:38
#: authentication/models/temp_token.py:10
#: authentication/templates/authentication/_access_key_modal.html:31
@ -339,6 +343,11 @@ msgstr "密文策略"
msgid "Secret"
msgstr "密钥"
#: accounts/models/automations/change_secret.py:22
#: accounts/serializers/automations/change_secret.py:40
msgid "Secret strategy"
msgstr "密文策略"
#: accounts/models/automations/change_secret.py:24
msgid "Password rules"
msgstr "密码规则"
@ -362,7 +371,7 @@ msgstr "开始日期"
#: accounts/models/automations/change_secret.py:74
#: assets/models/automations/base.py:115 ops/models/base.py:56
#: ops/models/celery.py:64 ops/models/job.py:123
#: terminal/models/applet/host.py:109
#: terminal/models/applet/host.py:110
msgid "Date finished"
msgstr "结束日期"
@ -375,20 +384,19 @@ msgstr "错误"
msgid "Change secret record"
msgstr "改密记录"
#: accounts/models/automations/gather_account.py:14
msgid "Present"
msgstr "存在"
#: accounts/models/automations/gather_account.py:15
#: accounts/tasks/gather_accounts.py:29
msgid "Gather asset accounts"
msgstr "收集账号"
msgid "Date last login"
msgstr "最后登录日期"
#: accounts/models/automations/push_account.py:13
msgid "Triggers"
msgstr "触发方式"
#: accounts/models/automations/push_account.py:14 accounts/models/base.py:34
#: accounts/models/gathered_account.py:15 acls/serializers/base.py:18
#: acls/serializers/base.py:49 assets/models/_user.py:23 audits/models.py:157
#: authentication/forms.py:25 authentication/forms.py:27
#: authentication/models/temp_token.py:9
#: accounts/models/automations/gather_account.py:17
#: accounts/models/automations/push_account.py:13 accounts/models/base.py:34
#: acls/serializers/base.py:18 acls/serializers/base.py:49
#: assets/models/_user.py:23 audits/models.py:157 authentication/forms.py:25
#: authentication/forms.py:27 authentication/models/temp_token.py:9
#: authentication/templates/authentication/_msg_different_city.html:9
#: authentication/templates/authentication/_msg_oauth_bind.html:9
#: users/forms/profile.py:32 users/forms/profile.py:112
@ -397,7 +405,24 @@ msgstr "触发方式"
msgid "Username"
msgstr "用户名"
#: accounts/models/automations/push_account.py:15 acls/models/base.py:81
#: accounts/models/automations/gather_account.py:18
msgid "Address last login"
msgstr "最后登录地址"
#: accounts/models/automations/gather_account.py:25 rbac/tree.py:50
msgid "Gather account"
msgstr "收集账号"
#: accounts/models/automations/gather_account.py:41
#: accounts/tasks/gather_accounts.py:29
msgid "Gather asset accounts"
msgstr "收集账号"
#: accounts/models/automations/push_account.py:12
msgid "Triggers"
msgstr "触发方式"
#: accounts/models/automations/push_account.py:14 acls/models/base.py:81
#: acls/serializers/base.py:81 acls/serializers/login_acl.py:25
#: assets/models/cmd_filter.py:81 audits/models.py:65 audits/serializers.py:82
#: authentication/serializers/connect_token_secret.py:109
@ -405,7 +430,7 @@ msgstr "用户名"
msgid "Action"
msgstr "动作"
#: accounts/models/automations/push_account.py:41
#: accounts/models/automations/push_account.py:40
msgid "Push asset account"
msgstr "账号推送"
@ -421,13 +446,13 @@ msgstr "账号验证"
#: assets/models/group.py:20 assets/models/label.py:18
#: assets/models/platform.py:21 assets/models/platform.py:76
#: assets/serializers/asset/common.py:68 assets/serializers/asset/common.py:142
#: assets/serializers/platform.py:132
#: assets/serializers/platform.py:91 assets/serializers/platform.py:136
#: authentication/serializers/connect_token_secret.py:103 ops/mixin.py:21
#: ops/models/adhoc.py:21 ops/models/celery.py:15 ops/models/celery.py:57
#: ops/models/job.py:26 ops/models/playbook.py:23 ops/serializers/job.py:19
#: orgs/models.py:69 perms/models/asset_permission.py:56 rbac/models/role.py:29
#: settings/models.py:33 settings/serializers/sms.py:6
#: terminal/models/applet/applet.py:26 terminal/models/component/endpoint.py:12
#: terminal/models/applet/applet.py:27 terminal/models/component/endpoint.py:12
#: terminal/models/component/endpoint.py:90
#: terminal/models/component/storage.py:26 terminal/models/component/task.py:15
#: terminal/models/component/terminal.py:79 users/forms/profile.py:33
@ -444,26 +469,10 @@ msgstr "特权账号"
#: assets/models/automations/base.py:21 assets/models/cmd_filter.py:39
#: assets/models/label.py:22
#: authentication/serializers/connect_token_secret.py:107
#: terminal/models/applet/applet.py:31 users/serializers/user.py:159
#: terminal/models/applet/applet.py:32 users/serializers/user.py:159
msgid "Is active"
msgstr "激活"
#: accounts/models/gathered_account.py:12
msgid "Present"
msgstr "存在"
#: accounts/models/gathered_account.py:13
msgid "Date last login"
msgstr "最后登录日期"
#: accounts/models/gathered_account.py:16
msgid "Address last login"
msgstr "最后登录地址"
#: accounts/models/gathered_account.py:23 rbac/tree.py:50
msgid "Gather account"
msgstr "收集账号"
#: accounts/notifications.py:8
msgid "Notification of account backup route task results"
msgstr "账号备份任务结果通知"
@ -520,7 +529,7 @@ msgstr "已托管密码"
#: accounts/serializers/account/account.py:75 applications/models.py:11
#: assets/models/label.py:21 assets/models/platform.py:77
#: assets/serializers/asset/common.py:121 assets/serializers/cagegory.py:8
#: assets/serializers/platform.py:93 assets/serializers/platform.py:133
#: assets/serializers/platform.py:97 assets/serializers/platform.py:137
#: perms/serializers/user_permission.py:25 settings/models.py:35
#: tickets/models/ticket/apply_application.py:13
msgid "Category"
@ -531,10 +540,10 @@ msgstr "类别"
#: 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
#: assets/serializers/asset/common.py:122 assets/serializers/platform.py:92
#: assets/serializers/asset/common.py:122 assets/serializers/platform.py:96
#: audits/serializers.py:48
#: authentication/serializers/connect_token_secret.py:116 ops/models/job.py:37
#: perms/serializers/user_permission.py:26 terminal/models/applet/applet.py:30
#: perms/serializers/user_permission.py:26 terminal/models/applet/applet.py:31
#: terminal/models/component/storage.py:57
#: terminal/models/component/storage.py:146 terminal/serializers/applet.py:28
#: terminal/serializers/session.py:22 terminal/serializers/storage.py:224
@ -639,7 +648,7 @@ msgstr "失败"
msgid "Account execute automation"
msgstr "账号执行自动化"
#: accounts/tasks/backup_account.py:24
#: accounts/tasks/backup_account.py:25
msgid "Execute account backup plan"
msgstr "执行账号备份计划"
@ -647,15 +656,15 @@ msgstr "执行账号备份计划"
msgid "Gather assets accounts"
msgstr "收集资产上的账号"
#: accounts/tasks/push_account.py:30 accounts/tasks/push_account.py:37
#: accounts/tasks/push_account.py:15 accounts/tasks/push_account.py:23
msgid "Push accounts to assets"
msgstr "推送账号到资产"
#: accounts/tasks/verify_account.py:42
#: accounts/tasks/verify_account.py:49
msgid "Verify asset account availability"
msgstr "验证资产账号可用性"
#: accounts/tasks/verify_account.py:50
#: accounts/tasks/verify_account.py:55
msgid "Verify accounts connectivity"
msgstr "测试账号可连接性"
@ -913,7 +922,7 @@ msgstr "删除失败,节点包含资产"
msgid "App assets"
msgstr "资产管理"
#: assets/automations/base/manager.py:105
#: assets/automations/base/manager.py:107
msgid "{} disabled"
msgstr "{} 已禁用"
@ -922,6 +931,12 @@ msgstr "{} 已禁用"
msgid "No account"
msgstr "没有账号"
#: assets/automations/ping_gateway/manager.py:36
#, fuzzy
#| msgid "Assets amount"
msgid "Asset, {}, using account {}"
msgstr "资产数量"
#: assets/automations/ping_gateway/manager.py:55
#, python-brace-format
msgid "Unable to connect to port {port} on {address}"
@ -980,11 +995,11 @@ msgid "Cloud service"
msgstr "云服务"
#: assets/const/category.py:15 assets/models/asset/web.py:16 audits/const.py:33
#: terminal/models/applet/applet.py:24
#: terminal/models/applet/applet.py:25
msgid "Web"
msgstr "Web"
#: assets/const/device.py:7 terminal/models/applet/applet.py:23
#: assets/const/device.py:7 terminal/models/applet/applet.py:24
#: tickets/const.py:8
msgid "General"
msgstr "一般"
@ -1020,7 +1035,7 @@ msgid "Basic"
msgstr "基本"
#: assets/const/web.py:61 assets/models/asset/web.py:13
#: assets/serializers/asset/common.py:117 assets/serializers/platform.py:39
#: assets/serializers/asset/common.py:117 assets/serializers/platform.py:40
msgid "Script"
msgstr "脚本"
@ -1036,8 +1051,8 @@ msgstr "SSH公钥"
#: assets/models/cmd_filter.py:88 assets/models/group.py:23
#: common/db/models.py:37 ops/models/adhoc.py:27 ops/models/job.py:45
#: ops/models/playbook.py:26 rbac/models/role.py:37 settings/models.py:38
#: terminal/models/applet/applet.py:35 terminal/models/applet/applet.py:151
#: terminal/models/applet/host.py:110 terminal/models/component/endpoint.py:24
#: terminal/models/applet/applet.py:36 terminal/models/applet/applet.py:155
#: terminal/models/applet/host.py:111 terminal/models/component/endpoint.py:24
#: terminal/models/component/endpoint.py:100
#: terminal/models/session/session.py:47 tickets/models/comment.py:32
#: tickets/models/ticket/general.py:297 users/models/user.py:756
@ -1086,7 +1101,7 @@ msgstr "用户名与用户相同"
#: assets/models/_user.py:52 authentication/models/connection_token.py:38
#: authentication/serializers/connect_token_secret.py:104
#: terminal/models/applet/applet.py:33 terminal/serializers/session.py:20
#: terminal/models/applet/applet.py:34 terminal/serializers/session.py:20
#: terminal/serializers/session.py:41 terminal/serializers/storage.py:68
msgid "Protocol"
msgstr "协议"
@ -1175,28 +1190,12 @@ msgid "Can test asset connectivity"
msgstr "可以测试资产连接性"
#: assets/models/asset/common.py:284
msgid "Can push account to asset"
msgstr "可以推送账号到资产"
#: assets/models/asset/common.py:285
msgid "Can verify account"
msgstr "可以验证账号"
#: assets/models/asset/common.py:286
msgid "Can match asset"
msgstr "可以匹配资产"
#: assets/models/asset/common.py:287
msgid "Add asset to node"
msgstr "添加资产到节点"
#: assets/models/asset/common.py:288
msgid "Move asset to node"
msgstr "移动资产到节点"
#: assets/models/asset/common.py:289
msgid "Remove asset from node"
msgstr "从节点移除资产"
#: assets/models/asset/common.py:285
msgid "Can change asset nodes"
msgstr "可以修改资产节点"
#: assets/models/asset/database.py:10 assets/serializers/asset/common.py:110
#: settings/serializers/email.py:37
@ -1219,22 +1218,22 @@ msgstr "客户端密钥"
msgid "Allow invalid cert"
msgstr "忽略证书校验"
#: assets/models/asset/web.py:9 assets/serializers/platform.py:29
#: assets/models/asset/web.py:9 assets/serializers/platform.py:30
msgid "Autofill"
msgstr "自动代填"
#: assets/models/asset/web.py:10 assets/serializers/asset/common.py:114
#: assets/serializers/platform.py:31
#: assets/serializers/platform.py:32
msgid "Username selector"
msgstr "用户名选择器"
#: assets/models/asset/web.py:11 assets/serializers/asset/common.py:115
#: assets/serializers/platform.py:34
#: assets/serializers/platform.py:35
msgid "Password selector"
msgstr "密码选择器"
#: assets/models/asset/web.py:12 assets/serializers/asset/common.py:116
#: assets/serializers/platform.py:37
#: assets/serializers/platform.py:38
msgid "Submit selector"
msgstr "确认按钮选择器"
@ -1253,7 +1252,7 @@ msgstr "资产自动化任务"
#: assets/models/automations/base.py:112 audits/models.py:177
#: audits/serializers.py:49 ops/models/base.py:49 ops/models/job.py:114
#: terminal/models/applet/applet.py:150 terminal/models/applet/host.py:107
#: terminal/models/applet/applet.py:154 terminal/models/applet/host.py:108
#: terminal/models/component/status.py:27 terminal/serializers/applet.py:17
#: terminal/serializers/applet_host.py:93 tickets/models/ticket/general.py:283
#: tickets/serializers/super_ticket.py:13
@ -1395,45 +1394,45 @@ msgstr "启用"
msgid "Ansible config"
msgstr "Ansible 配置"
#: assets/models/platform.py:44 assets/serializers/platform.py:60
#: assets/models/platform.py:44 assets/serializers/platform.py:61
msgid "Ping enabled"
msgstr "启用资产探活"
#: assets/models/platform.py:45 assets/serializers/platform.py:61
#: assets/models/platform.py:45 assets/serializers/platform.py:62
msgid "Ping method"
msgstr "资产探活方式"
#: assets/models/platform.py:46 assets/models/platform.py:59
#: assets/serializers/platform.py:62
#: assets/serializers/platform.py:63
msgid "Gather facts enabled"
msgstr "启用收集资产信息"
#: assets/models/platform.py:47 assets/models/platform.py:61
#: assets/serializers/platform.py:63
#: assets/serializers/platform.py:64
msgid "Gather facts method"
msgstr "收集信息方式"
#: assets/models/platform.py:48 assets/serializers/platform.py:66
#: assets/models/platform.py:48 assets/serializers/platform.py:67
msgid "Change secret enabled"
msgstr "启用改密"
#: assets/models/platform.py:50 assets/serializers/platform.py:67
#: assets/models/platform.py:50 assets/serializers/platform.py:68
msgid "Change secret method"
msgstr "改密方式"
#: assets/models/platform.py:52 assets/serializers/platform.py:68
#: assets/models/platform.py:52 assets/serializers/platform.py:69
msgid "Push account enabled"
msgstr "启用账号推送"
#: assets/models/platform.py:54 assets/serializers/platform.py:69
#: assets/models/platform.py:54 assets/serializers/platform.py:70
msgid "Push account method"
msgstr "账号推送方式"
#: assets/models/platform.py:56 assets/serializers/platform.py:64
#: assets/models/platform.py:56 assets/serializers/platform.py:65
msgid "Verify account enabled"
msgstr "开启账号验证"
#: assets/models/platform.py:58 assets/serializers/platform.py:65
#: assets/models/platform.py:58 assets/serializers/platform.py:66
msgid "Verify account method"
msgstr "账号验证方式"
@ -1445,23 +1444,23 @@ msgstr "元数据"
msgid "Internal"
msgstr "内置"
#: assets/models/platform.py:83 assets/serializers/platform.py:90
#: assets/models/platform.py:83 assets/serializers/platform.py:94
msgid "Charset"
msgstr "编码"
#: assets/models/platform.py:85 assets/serializers/platform.py:118
#: assets/models/platform.py:85 assets/serializers/platform.py:122
msgid "Domain enabled"
msgstr "启用网域"
#: assets/models/platform.py:87 assets/serializers/platform.py:117
#: assets/models/platform.py:87 assets/serializers/platform.py:121
msgid "Su enabled"
msgstr "启用账号切换"
#: assets/models/platform.py:88 assets/serializers/platform.py:100
#: assets/models/platform.py:88 assets/serializers/platform.py:104
msgid "Su method"
msgstr "账号切换方式"
#: assets/models/platform.py:90 assets/serializers/platform.py:97
#: assets/models/platform.py:90 assets/serializers/platform.py:101
msgid "Automation"
msgstr "自动化"
@ -1474,7 +1473,7 @@ msgstr "%(value)s is not an even number"
msgid "Auto fill"
msgstr "自动代填"
#: assets/serializers/asset/common.py:124 assets/serializers/platform.py:95
#: assets/serializers/asset/common.py:124 assets/serializers/platform.py:99
#: authentication/serializers/connect_token_secret.py:28
#: authentication/serializers/connect_token_secret.py:66
#: perms/serializers/user_permission.py:24 xpack/plugins/cloud/models.py:99
@ -1586,31 +1585,31 @@ msgstr "不能包含: /"
msgid "The same level node name cannot be the same"
msgstr "同级别节点名字不能重复"
#: assets/serializers/platform.py:25
#: assets/serializers/platform.py:26
msgid "SFTP enabled"
msgstr "SFTP 已启用"
#: assets/serializers/platform.py:26
#: assets/serializers/platform.py:27
msgid "SFTP home"
msgstr "SFTP 根路径"
#: assets/serializers/platform.py:42
#: assets/serializers/platform.py:43
msgid "Auth with username"
msgstr "使用用户名认证"
#: assets/serializers/platform.py:70
#: assets/serializers/platform.py:71
msgid "Gather accounts enabled"
msgstr "启用账号收集"
#: assets/serializers/platform.py:71
#: assets/serializers/platform.py:72
msgid "Gather accounts method"
msgstr "收集账号方式"
#: assets/serializers/platform.py:77
#: assets/serializers/platform.py:78
msgid "Primary"
msgstr "主要的"
#: assets/serializers/platform.py:119
#: assets/serializers/platform.py:123
msgid "Default Domain"
msgstr "默认网域"
@ -1752,7 +1751,7 @@ msgid "Change password"
msgstr "改密"
#: audits/const.py:34 settings/serializers/terminal.py:6
#: terminal/models/applet/host.py:24 terminal/models/component/terminal.py:156
#: terminal/models/applet/host.py:25 terminal/models/component/terminal.py:156
#: terminal/serializers/session.py:48
msgid "Terminal"
msgstr "终端"
@ -1769,7 +1768,7 @@ msgstr "会话日志"
msgid "Login log"
msgstr "登录日志"
#: audits/const.py:42 terminal/models/applet/host.py:111
#: audits/const.py:42 terminal/models/applet/host.py:112
#: terminal/models/component/task.py:24
msgid "Task"
msgstr "任务"
@ -3551,7 +3550,7 @@ msgstr "组织"
msgid "Org name"
msgstr "组织名称"
#: orgs/models.py:70 rbac/models/role.py:36 terminal/models/applet/applet.py:32
#: orgs/models.py:70 rbac/models/role.py:36 terminal/models/applet/applet.py:33
msgid "Builtin"
msgstr "内置的"
@ -3795,7 +3794,7 @@ msgstr "权限"
msgid "Users amount"
msgstr "用户数量"
#: rbac/serializers/role.py:28 terminal/models/applet/applet.py:27
#: rbac/serializers/role.py:28 terminal/models/applet/applet.py:28
msgid "Display name"
msgstr "显示名称"
@ -3859,8 +3858,8 @@ msgstr "任务中心"
msgid "My assets"
msgstr "我的资产"
#: rbac/tree.py:57 terminal/models/applet/applet.py:42
#: terminal/models/applet/applet.py:147 terminal/models/applet/host.py:27
#: rbac/tree.py:57 terminal/models/applet/applet.py:43
#: terminal/models/applet/applet.py:151 terminal/models/applet/host.py:28
msgid "Applet"
msgstr "远程应用"
@ -5349,44 +5348,44 @@ msgstr "不支持批量创建"
msgid "Storage is invalid"
msgstr "存储无效"
#: terminal/models/applet/applet.py:29
#: terminal/models/applet/applet.py:30
msgid "Author"
msgstr "作者"
#: terminal/models/applet/applet.py:34
#: terminal/models/applet/applet.py:35
msgid "Tags"
msgstr "标签"
#: terminal/models/applet/applet.py:38 terminal/serializers/storage.py:157
#: terminal/models/applet/applet.py:39 terminal/serializers/storage.py:157
msgid "Hosts"
msgstr "主机"
#: terminal/models/applet/applet.py:83
#: terminal/models/applet/applet.py:84
msgid "Applet pkg not valid, Missing file {}"
msgstr "Applet pkg 无效,缺少文件 {}"
#: terminal/models/applet/applet.py:149 terminal/models/applet/host.py:33
#: terminal/models/applet/host.py:105
#: terminal/models/applet/applet.py:153 terminal/models/applet/host.py:34
#: terminal/models/applet/host.py:106
msgid "Hosting"
msgstr "宿主机"
#: terminal/models/applet/host.py:18 terminal/serializers/applet_host.py:43
#: terminal/models/applet/host.py:19 terminal/serializers/applet_host.py:43
msgid "Deploy options"
msgstr "部署参数"
#: terminal/models/applet/host.py:19
#: terminal/models/applet/host.py:20
msgid "Inited"
msgstr "已初始化"
#: terminal/models/applet/host.py:20
#: terminal/models/applet/host.py:21
msgid "Date inited"
msgstr "初始化日期"
#: terminal/models/applet/host.py:21
#: terminal/models/applet/host.py:22
msgid "Date synced"
msgstr "同步日期"
#: terminal/models/applet/host.py:106
#: terminal/models/applet/host.py:107
msgid "Initial"
msgstr "初始化"
@ -7192,14 +7191,6 @@ 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 "账号无效"
@ -7268,6 +7259,24 @@ msgstr "旗舰版"
msgid "Community edition"
msgstr "社区版"
#~ msgid "Can push account to asset"
#~ msgstr "可以推送账号到资产"
#~ msgid "Add asset to node"
#~ msgstr "添加资产到节点"
#~ msgid "Move asset to node"
#~ 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 "清理审计日志"

View File

@ -101,7 +101,7 @@ class JMSInventory:
def asset_to_host(self, asset, account, automation, protocols, platform):
host = {
'name': '{}'.format(asset.name),
'name': '{}'.format(asset.name.replace(' ', '_')),
'jms_asset': {
'id': str(asset.id), 'name': asset.name, 'address': asset.address,
'type': asset.type, 'category': asset.category,

View File

@ -46,9 +46,25 @@ def sync_registered_tasks(*args, **kwargs):
@receiver(django_ready)
def check_registered_tasks(*args, **kwargs):
attrs = ['verbose_name', 'activity_callback']
ignores = [
'users.tasks.check_user_expired_periodic', 'ops.tasks.clean_celery_periodic_tasks',
'terminal.tasks.delete_terminal_status_period', 'ops.tasks.check_server_performance_period',
'settings.tasks.ldap.import_ldap_user', 'users.tasks.check_password_expired',
'assets.tasks.nodes_amount.check_node_assets_amount_task', 'notifications.notifications.publish_task',
'perms.tasks.check_asset_permission_will_expired',
'ops.tasks.create_or_update_registered_periodic_tasks', 'perms.tasks.check_asset_permission_expired',
'settings.tasks.ldap.import_ldap_user_periodic', 'users.tasks.check_password_expired_periodic',
'common.utils.verify_code.send_async', 'assets.tasks.nodes_amount.check_node_assets_amount_period_task',
'users.tasks.check_user_expired', 'orgs.tasks.refresh_org_cache_task',
'terminal.tasks.upload_session_replay_to_external_storage', 'terminal.tasks.clean_orphan_session',
'audits.tasks.clean_audits_log_period', 'authentication.tasks.clean_django_sessions'
]
for name, task in app.tasks.items():
if name.startswith('celery.'):
continue
if name in ignores:
continue
for attr in attrs:
if not hasattr(task, attr):
# print('>>> Task {} has no attribute {}'.format(name, attr))

View File

@ -49,6 +49,10 @@ exclude_permissions = (
('assets', 'gatherfactsautomation', '*', '*'),
('assets', 'commandfilter', '*', '*'),
('assets', 'commandfilterrule', '*', '*'),
('assets', 'asset', 'add,move', 'assettonode'),
('assets', 'asset', 'remove', 'assetfromnode'),
('assets', 'asset', 'test', 'account'),
('assets', 'asset', 'push', 'assetaccount'),
('accounts', 'historicalaccount', '*', '*'),
('accounts', 'accountbaseautomation', '*', '*'),

View File

@ -18,7 +18,8 @@ def migrate_remove_redundant_permission(apps, *args):
model.objects.filter(app_label='assets', model__in=[
'authbook', 'historicalauthbook', 'test_gateway',
'accountbackupplan', 'accountbackupplanexecution', 'gathereduser', 'systemuser'
'accountbackupplan', 'accountbackupplanexecution',
'gathereduser', 'systemuser'
]).delete()
model.objects.filter(app_label='perms', model__in=[
@ -27,7 +28,8 @@ def migrate_remove_redundant_permission(apps, *args):
perm_model = apps.get_model('auth', 'Permission')
perm_model.objects.filter(codename__in=[
'view_permusergroupasset', 'view_permuserasset', 'push_assetsystemuser', 'change_accountsecret'
'view_permusergroupasset', 'view_permuserasset', 'push_assetsystemuser',
'add_assettonode', 'move_assettonode', 'remove_assetfromnode',
]).delete()