perf: 解决冲突

pull/9671/head
jiangweidong 2023-02-22 11:44:46 +08:00
commit cde59f7ae8
26 changed files with 76 additions and 93 deletions

View File

@ -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)

View File

@ -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', {})

View File

@ -86,6 +86,10 @@ class ChangeSecretManager(AccountBasePlaybookManager):
accounts = accounts.filter(username__in=self.snapshot_account_usernames)
accounts = accounts.filter(secret_type=self.secret_type)
if not accounts:
print('没有发现待改密账号: %s 用户名: %s 类型: %s' % (asset.name, account.username, self.secret_type))
return []
method_attr = getattr(automation, self.method_type() + '_method')
method_hosts = self.method_hosts_mapper[method_attr]
method_hosts = [h for h in method_hosts if h != host['name']]
@ -137,8 +141,10 @@ class ChangeSecretManager(AccountBasePlaybookManager):
recorder.status = 'success'
recorder.date_finished = timezone.now()
recorder.save()
print('recorder.new_secret', recorder.new_secret)
account = recorder.account
if not account:
print("Account not found, deleted ?", recorder)
return
account.secret = recorder.new_secret
account.save(update_fields=['secret'])

View File

@ -36,7 +36,7 @@ class PushAccountManager(ChangeSecretManager, AccountBasePlaybookManager):
def get_accounts(self, privilege_account, accounts: QuerySet):
if not privilege_account:
logger.debug(f'not privilege account')
print(f'not privilege account')
return []
snapshot_account_usernames = self.execution.snapshot['accounts']
if '*' in snapshot_account_usernames:

View File

@ -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 }}"

View File

@ -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 }}"

View File

@ -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 }}'

View File

@ -1,17 +0,0 @@
# 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

@ -68,6 +68,9 @@ class Account(AbsConnectivity, BaseAccount):
('push_account', _('Can push account')),
]
def __str__(self):
return '{}'.format(self.username)
@lazyproperty
def platform(self):
return self.asset.platform
@ -78,9 +81,6 @@ class Account(AbsConnectivity, BaseAccount):
return self.username
return self.name
def __str__(self):
return '{}'.format(self.username)
@lazyproperty
def has_secret(self):
return bool(self.secret)
@ -99,14 +99,6 @@ class Account(AbsConnectivity, BaseAccount):
""" 排除自己和以自己为 su-from 的账号 """
return self.asset.accounts.exclude(id=self.id).exclude(su_from=self)
def secret_changed(self):
history = self.history.first()
if not history:
return True
if history.secret != self.secret or history.secret_type != self.secret_type:
return True
return False
class AccountTemplate(BaseAccount):
class Meta:

View File

@ -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

View File

@ -43,7 +43,7 @@ class AccountSerializerCreateValidateMixin:
def push_account(instance, push_now):
if not push_now:
return
push_accounts_to_assets_task.delay([instance.id], [instance.asset_id])
push_accounts_to_assets_task.delay([instance.id])
def create(self, validated_data):
push_now = validated_data.pop('push_now', None)
@ -102,7 +102,7 @@ class AccountSerializer(AccountSerializerCreateMixin, BaseAccountSerializer):
class Meta(BaseAccountSerializer.Meta):
model = Account
fields = BaseAccountSerializer.Meta.fields \
+ ['su_from', 'version', 'asset'] \
+ ['su_from', 'asset'] \
+ ['template', 'push_now', 'source']
extra_kwargs = {
**BaseAccountSerializer.Meta.extra_kwargs,

View File

@ -38,6 +38,8 @@ class BaseAutomationSerializer(PeriodTaskSerializerMixin, BulkOrgResourceModelSe
}
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

View File

@ -1,17 +1,3 @@
from django.db.models.signals import pre_save
from django.dispatch import receiver
from common.utils import get_logger
from .models import Account
logger = get_logger(__name__)
@receiver(pre_save, sender=Account)
def on_account_pre_create(sender, instance, update_fields=(), **kwargs):
# 这是创建时
if instance.version == 0 or instance.secret_changed():
instance.version += 1
# 即使在 root 组织也不怕
instance.org_id = instance.asset.org_id

View File

@ -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
@ -205,9 +207,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_task.delay(account_ids, asset_ids)
task = push_accounts_to_assets_task.delay(account_ids)
elif action == "test_account":
task = verify_accounts_connectivity_task.delay(account_ids, asset_ids)
task = verify_accounts_connectivity_task.delay(account_ids)
else:
task = None
return task

View File

@ -67,7 +67,7 @@ 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))
print(f'Ansible runtime dir: {path}')
return path
@staticmethod
@ -156,10 +156,9 @@ class BasePlaybookManager:
return sub_playbook_path
def get_runners(self):
# TODO 临时打印一下 找一下打印不出日志的原因
print('ansible runner: 任务开始执行')
assets_group_by_platform = self.get_assets_group_by_platform()
print('ansible runner: 获取资产分组', assets_group_by_platform)
if settings.DEBUG_DEV:
print("assets_group_by_platform: {}".format(assets_group_by_platform))
runners = []
for platform, assets in assets_group_by_platform.items():
assets_bulked = [assets[i:i + self.bulk_size] for i in range(0, len(assets), self.bulk_size)]
@ -213,6 +212,7 @@ class BasePlaybookManager:
def file_to_json(path):
with open(path, 'r') as f:
d = json.load(f)
return d
@staticmethod

View File

@ -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")

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'), ('change_assettonode', 'Can change asset nodes')], 'verbose_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

@ -1,17 +0,0 @@
# 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'), ('match_asset', 'Can match asset'), ('change_assetnodes', 'Can change asset nodes')], 'verbose_name': 'Asset'},
),
]

View File

@ -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)

View File

@ -530,7 +530,7 @@ class Config(dict):
'PERIOD_TASK_ENABLED': True,
# 导航栏 帮助
'HELP_DOCUMENT_URL': 'http://docs.jumpserver.org',
'HELP_DOCUMENT_URL': 'https://docs.jumpserver.org/zh/v3/',
'HELP_SUPPORT_URL': 'http://www.jumpserver.org/support/',
'FORGOT_PASSWORD_URL': '',

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:331188bb5169bb463da018a635589e12a2136d476db264ac7e5d6e5d63ca474a
size 135916
oid sha256:af57d16430705feb02ebbb99fc3a2f5fc3bab69209f558aa4d69b1e8055a6f5f
size 136036

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-02-21 18:29+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"
@ -908,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 ""
"資産を直接作成することはできません。ホストまたはその他を作成する必要がありま"
@ -1051,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秘密鍵"

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2cdc2b875c98f41bd698833a989195d8cc4245f39f52b7eab41ad4d95075cb17
size 111666
oid sha256:3b6ee4a378810f2515be5020e3fa0b1297e1c207260ca60bb14dc5407ca19c43
size 111750

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-21 18:29+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"
@ -902,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 "不能直接创建资产, 你应该创建主机或其他资产"
@ -1043,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密钥"

View File

@ -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

View File

@ -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