From 5447ee6c395dd82d89310db38bcbdcdb4a08d5fb Mon Sep 17 00:00:00 2001 From: "Jiangjie.Bai" Date: Fri, 4 Nov 2022 18:46:49 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E4=BF=AE=E6=94=B9=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E7=94=A8=E6=88=B7-=E8=B5=84=E4=BA=A7=E6=8E=88?= =?UTF-8?q?=E6=9D=83=E7=9A=84=E8=B4=A6=E5=8F=B7=E5=88=97=E8=A1=A8=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E7=BB=93=E6=9E=84;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/perms/api/user_permission/__init__.py | 1 - apps/perms/api/user_permission/accounts.py | 82 +++++++++++++++++++-- apps/perms/api/user_permission/common.py | 84 ---------------------- apps/perms/utils/account.py | 4 +- apps/perms/utils/permission.py | 2 +- 5 files changed, 81 insertions(+), 92 deletions(-) delete mode 100644 apps/perms/api/user_permission/common.py diff --git a/apps/perms/api/user_permission/__init__.py b/apps/perms/api/user_permission/__init__.py index b0db20ee0..55bc108b4 100644 --- a/apps/perms/api/user_permission/__init__.py +++ b/apps/perms/api/user_permission/__init__.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- # -from .common import * from .nodes import * from .assets import * from .nodes_with_assets import * diff --git a/apps/perms/api/user_permission/accounts.py b/apps/perms/api/user_permission/accounts.py index d504ac8f9..70973d988 100644 --- a/apps/perms/api/user_permission/accounts.py +++ b/apps/perms/api/user_permission/accounts.py @@ -1,13 +1,29 @@ -from rest_framework import generics +from django.shortcuts import get_object_or_404 +from rest_framework.generics import ListAPIView, get_object_or_404 + +from common.permissions import IsValidUser +from common.utils import get_logger, lazyproperty from assets.serializers import AccountSerializer -from perms.utils.account import PermAccountUtil +from perms.hands import User, Asset, Account +from perms import serializers +from perms.models import Action +from perms.utils import PermAccountUtil from .mixin import RoleAdminMixin, RoleUserMixin - -__all__ = ['UserAllGrantedAccountsApi', 'MyAllGrantedAccountsApi'] +logger = get_logger(__name__) -class UserAllGrantedAccountsApi(RoleAdminMixin, generics.ListAPIView): +__all__ = [ + 'UserAllGrantedAccountsApi', + 'MyAllGrantedAccountsApi', + 'UserGrantedAssetAccountsApi', + 'MyGrantedAssetAccountsApi', + 'UserGrantedAssetSpecialAccountsApi', + 'MyGrantedAssetSpecialAccountsApi', +] + + +class UserAllGrantedAccountsApi(RoleAdminMixin, ListAPIView): """ 授权给用户的所有账号列表 """ serializer_class = AccountSerializer filterset_fields = ("name", "username", "privileged", "version") @@ -22,3 +38,59 @@ class UserAllGrantedAccountsApi(RoleAdminMixin, generics.ListAPIView): class MyAllGrantedAccountsApi(RoleUserMixin, UserAllGrantedAccountsApi): """ 授权给我的所有账号列表 """ pass + + +class UserGrantedAssetAccountsApi(ListAPIView): + serializer_class = serializers.AccountsGrantedSerializer + + @lazyproperty + def user(self) -> User: + user_id = self.kwargs.get('pk') + return User.objects.get(id=user_id) + + @lazyproperty + def asset(self): + asset_id = self.kwargs.get('asset_id') + kwargs = {'id': asset_id, 'is_active': True} + asset = get_object_or_404(Asset, **kwargs) + return asset + + def get_queryset(self): + accounts = PermAccountUtil().get_perm_accounts_for_user_asset( + self.user, self.asset, with_actions=True + ) + return accounts + + +class MyGrantedAssetAccountsApi(UserGrantedAssetAccountsApi): + permission_classes = (IsValidUser,) + + @lazyproperty + def user(self): + return self.request.user + + +class UserGrantedAssetSpecialAccountsApi(ListAPIView): + serializer_class = serializers.AccountsGrantedSerializer + + @lazyproperty + def user(self): + return self.request.user + + def get_queryset(self): + # 构造默认包含的账号,如: @INPUT @USER + accounts = [ + Account.get_input_account(), + Account.get_user_account(self.user.username) + ] + for account in accounts: + account.actions = Action.ALL + return accounts + + +class MyGrantedAssetSpecialAccountsApi(UserGrantedAssetSpecialAccountsApi): + permission_classes = (IsValidUser,) + + @lazyproperty + def user(self): + return self.request.user diff --git a/apps/perms/api/user_permission/common.py b/apps/perms/api/user_permission/common.py deleted file mode 100644 index 927ec7443..000000000 --- a/apps/perms/api/user_permission/common.py +++ /dev/null @@ -1,84 +0,0 @@ -# -*- coding: utf-8 -*- -# -from django.shortcuts import get_object_or_404 -from rest_framework.generics import ( - ListAPIView, get_object_or_404 -) -from common.permissions import IsValidUser -from common.utils import get_logger, lazyproperty - -from perms.hands import User, Asset, Account -from perms import serializers -from perms.models import Action -from perms.utils import PermAccountUtil - -logger = get_logger(__name__) - -__all__ = [ - 'UserGrantedAssetAccountsApi', - 'MyGrantedAssetAccountsApi', - 'UserGrantedAssetSpecialAccountsApi', - 'MyGrantedAssetSpecialAccountsApi', -] - - -class UserGrantedAssetAccountsApi(ListAPIView): - serializer_class = serializers.AccountsGrantedSerializer - rbac_perms = { - 'list': 'perms.view_userassets' - } - - @lazyproperty - def user(self) -> User: - user_id = self.kwargs.get('pk') - return User.objects.get(id=user_id) - - @lazyproperty - def asset(self): - asset_id = self.kwargs.get('asset_id') - kwargs = {'id': asset_id, 'is_active': True} - asset = get_object_or_404(Asset, **kwargs) - return asset - - def get_queryset(self): - accounts = PermAccountUtil().get_perm_accounts_for_user_asset( - self.user, self.asset, with_actions=True - ) - return accounts - - -class MyGrantedAssetAccountsApi(UserGrantedAssetAccountsApi): - permission_classes = (IsValidUser,) - - @lazyproperty - def user(self): - return self.request.user - - -class UserGrantedAssetSpecialAccountsApi(ListAPIView): - serializer_class = serializers.AccountsGrantedSerializer - rbac_perms = { - 'list': 'perms.view_userassets' - } - - @lazyproperty - def user(self): - return self.request.user - - def get_queryset(self): - # 构造默认包含的账号,如: @INPUT @USER - accounts = [ - Account.get_input_account(), - Account.get_user_account(self.user.username) - ] - for account in accounts: - account.actions = Action.ALL - return accounts - - -class MyGrantedAssetSpecialAccountsApi(UserGrantedAssetSpecialAccountsApi): - permission_classes = (IsValidUser,) - - @lazyproperty - def user(self): - return self.request.user diff --git a/apps/perms/utils/account.py b/apps/perms/utils/account.py index 63bfcc723..3963e113c 100644 --- a/apps/perms/utils/account.py +++ b/apps/perms/utils/account.py @@ -39,7 +39,9 @@ class PermAccountUtil(AssetPermissionUtil): for aid in account_ids: aid_actions_map[str(aid)] |= actions account_ids = list(aid_actions_map.keys()) - accounts = Account.objects.filter(id__in=account_ids) + accounts = Account.objects.filter(id__in=account_ids).order_by( + 'asset__name', 'name', 'username' + ) if with_actions: for account in accounts: account.actions = aid_actions_map.get(str(account.id)) diff --git a/apps/perms/utils/permission.py b/apps/perms/utils/permission.py index e7d88e06d..fd0ea593b 100644 --- a/apps/perms/utils/permission.py +++ b/apps/perms/utils/permission.py @@ -52,7 +52,7 @@ class AssetPermissionUtil(object): .values_list('assetpermission_id', flat=True).distinct() perm_ids.update(asset_perm_ids) if with_node: - nodes = asset.get_all_nodes(flat=True) + nodes = asset.get_all_nodes() node_perm_ids = self.get_permissions_for_nodes(nodes, flat=True) perm_ids.update(node_perm_ids) if flat: From dca92a1e04a2780a8a3e0e9e5787738984228361 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Fri, 4 Nov 2022 19:18:15 +0800 Subject: [PATCH 2/2] perf: push account (#9020) Co-authored-by: feng <1304903146@qq.com> --- apps/assets/automations/base/manager.py | 12 ++++++++---- .../automations/push_account/host/posix/main.yml | 4 ++-- apps/assets/automations/push_account/manager.py | 2 +- apps/assets/automations/verify_account/manager.py | 2 +- apps/assets/models/automations/push_account.py | 2 +- apps/assets/serializers/asset/common.py | 4 ++-- apps/assets/tasks/push_account.py | 4 ++-- apps/assets/tasks/verify_account.py | 4 ++-- 8 files changed, 19 insertions(+), 15 deletions(-) diff --git a/apps/assets/automations/base/manager.py b/apps/assets/automations/base/manager.py index 758dea52c..c5f334167 100644 --- a/apps/assets/automations/base/manager.py +++ b/apps/assets/automations/base/manager.py @@ -23,6 +23,7 @@ class PushOrVerifyHostCallbackMixin: execution: callable host_account_mapper: dict ignore_account: bool + need_privilege_account: bool generate_public_key: callable generate_private_key_path: callable @@ -32,7 +33,7 @@ class PushOrVerifyHostCallbackMixin: return host accounts = asset.accounts.all() - if self.ignore_account and account: + if self.need_privilege_account and accounts.count() > 1 and account: accounts = accounts.exclude(id=account.id) if '*' not in self.execution.snapshot['accounts']: @@ -114,9 +115,9 @@ class BasePlaybookManager: method_attr = '{}_method'.format(self.__class__.method_type()) method_enabled = automation and \ - getattr(automation, enabled_attr) and \ - getattr(automation, method_attr) and \ - getattr(automation, method_attr) in self.method_id_meta_mapper + getattr(automation, enabled_attr) and \ + getattr(automation, method_attr) and \ + getattr(automation, method_attr) in self.method_id_meta_mapper if not method_enabled: host['error'] = _('{} disabled'.format(self.__class__.method_type())) @@ -198,6 +199,9 @@ class BasePlaybookManager: result = cb.host_results.get(host) if state == 'ok': self.on_host_success(host, result) + elif state == 'skipped': + # TODO + print('skipped: ', hosts) else: error = hosts.get(host) self.on_host_error(host, error, result) diff --git a/apps/assets/automations/push_account/host/posix/main.yml b/apps/assets/automations/push_account/host/posix/main.yml index afe13b226..e78c57152 100644 --- a/apps/assets/automations/push_account/host/posix/main.yml +++ b/apps/assets/automations/push_account/host/posix/main.yml @@ -2,8 +2,8 @@ gather_facts: no tasks: - name: Add user account.username - ansible.builtin.user: - name: "{{ account.username }}" + ansible.builtin.user: + name: "{{ account.username }}" - name: Set account.username password ansible.builtin.user: diff --git a/apps/assets/automations/push_account/manager.py b/apps/assets/automations/push_account/manager.py index ea5e2193f..f849f3e6e 100644 --- a/apps/assets/automations/push_account/manager.py +++ b/apps/assets/automations/push_account/manager.py @@ -6,7 +6,7 @@ logger = get_logger(__name__) class PushAccountManager(PushOrVerifyHostCallbackMixin, BasePlaybookManager): - ignore_account = True + need_privilege_account = True def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/apps/assets/automations/verify_account/manager.py b/apps/assets/automations/verify_account/manager.py index 5445511ba..fe46bc0ff 100644 --- a/apps/assets/automations/verify_account/manager.py +++ b/apps/assets/automations/verify_account/manager.py @@ -6,7 +6,7 @@ logger = get_logger(__name__) class VerifyAccountManager(PushOrVerifyHostCallbackMixin, BasePlaybookManager): - ignore_account = False + need_privilege_account = False def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/apps/assets/models/automations/push_account.py b/apps/assets/models/automations/push_account.py index b1da1966f..8439041cb 100644 --- a/apps/assets/models/automations/push_account.py +++ b/apps/assets/models/automations/push_account.py @@ -9,7 +9,7 @@ __all__ = ['PushAccountAutomation'] class PushAccountAutomation(BaseAutomation): def save(self, *args, **kwargs): - self.type = AutomationTypes.verify_account + self.type = AutomationTypes.push_account super().save(*args, **kwargs) class Meta: diff --git a/apps/assets/serializers/asset/common.py b/apps/assets/serializers/asset/common.py index d7f25111c..c44be52ce 100644 --- a/apps/assets/serializers/asset/common.py +++ b/apps/assets/serializers/asset/common.py @@ -65,8 +65,8 @@ class AssetSerializer(OrgResourceSerializerMixin, WritableNestedModelSerializer) platform = ObjectRelatedField(required=False, queryset=Platform.objects, label=_('Platform')) nodes = ObjectRelatedField(many=True, required=False, queryset=Node.objects, label=_('Nodes')) labels = AssetLabelSerializer(many=True, required=False, label=_('Labels')) - accounts = AssetAccountSerializer(many=True, required=False, label=_('Accounts')) protocols = AssetProtocolsSerializer(many=True, required=False, label=_('Protocols')) + accounts = AssetAccountSerializer(many=True, required=False, label=_('Accounts')) class Meta: model = Asset @@ -74,7 +74,7 @@ class AssetSerializer(OrgResourceSerializerMixin, WritableNestedModelSerializer) fields_small = fields_mini + ['is_active', 'comment'] fields_fk = ['domain', 'platform', 'platform'] fields_m2m = [ - 'nodes', 'labels', 'accounts', 'protocols', 'nodes_display', + 'nodes', 'labels', 'protocols', 'accounts', 'nodes_display', ] read_only_fields = [ 'category', 'type', 'specific', diff --git a/apps/assets/tasks/push_account.py b/apps/assets/tasks/push_account.py index 8af71cd3f..cd5de975a 100644 --- a/apps/assets/tasks/push_account.py +++ b/apps/assets/tasks/push_account.py @@ -31,7 +31,7 @@ def push_accounts_to_assets_util(accounts, assets): def push_accounts_to_assets(account_ids, asset_ids): from assets.models import Asset, Account with tmp_to_root_org(): - assets = Asset.objects.get(id=asset_ids) - accounts = Account.objects.get(id=account_ids) + assets = Asset.objects.filter(id__in=asset_ids) + accounts = Account.objects.filter(id__in=account_ids) return push_accounts_to_assets_util(accounts, assets) diff --git a/apps/assets/tasks/verify_account.py b/apps/assets/tasks/verify_account.py index afb98a4a3..2874113d8 100644 --- a/apps/assets/tasks/verify_account.py +++ b/apps/assets/tasks/verify_account.py @@ -30,8 +30,8 @@ def verify_accounts_connectivity_util(accounts, assets, task_name): def verify_accounts_connectivity(account_ids, asset_ids): from assets.models import Asset, Account with tmp_to_root_org(): - assets = Asset.objects.get(id=asset_ids) - accounts = Account.objects.get(id=account_ids) + assets = Asset.objects.filter(id__in=asset_ids) + accounts = Account.objects.filter(id__in=account_ids) task_name = gettext_noop("Verify accounts connectivity") return verify_accounts_connectivity_util(accounts, assets, task_name)