From eca50874f0e31b598a24e81f5219411eab778ea3 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Wed, 6 Dec 2023 18:48:35 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=90=8C=E6=AD=A5=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E8=BF=9C=E7=A8=8B=E6=9C=BA=E5=99=A8=E8=B4=A6=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/accounts/api/account/task.py | 35 +++++----- apps/accounts/automations/endpoint.py | 8 ++- .../automations/remove_account/__init__.py | 0 .../remove_account/database/mongodb/main.yml | 21 ++++++ .../database/mongodb/manifest.yml | 12 ++++ .../remove_account/database/mysql/main.yml | 18 +++++ .../database/mysql/manifest.yml | 14 ++++ .../remove_account/database/oracle/main.yml | 16 +++++ .../database/oracle/manifest.yml | 12 ++++ .../database/postgresql/main.yml | 15 +++++ .../database/postgresql/manifest.yml | 12 ++++ .../database/sqlserver/main.yml | 14 ++++ .../database/sqlserver/manifest.yml | 12 ++++ .../remove_account/host/posix/main.yml | 25 +++++++ .../remove_account/host/posix/manifest.yml | 13 ++++ .../remove_account/host/windows/main.yml | 9 +++ .../remove_account/host/windows/manifest.yml | 13 ++++ .../automations/remove_account/manager.py | 67 +++++++++++++++++++ .../verify_account/database/mongodb/main.yml | 2 +- apps/accounts/const/automation.py | 1 + .../migrations/0007_alter_account_options.py | 10 ++- apps/accounts/models/account.py | 1 + apps/accounts/permissions.py | 19 ++++++ apps/accounts/serializers/account/account.py | 6 +- apps/accounts/tasks/__init__.py | 1 + apps/accounts/tasks/remove_account.py | 31 +++++++++ .../0126_automation_remove_account.py | 55 +++++++++++++++ apps/assets/models/platform.py | 6 ++ 28 files changed, 424 insertions(+), 24 deletions(-) create mode 100644 apps/accounts/automations/remove_account/__init__.py create mode 100644 apps/accounts/automations/remove_account/database/mongodb/main.yml create mode 100644 apps/accounts/automations/remove_account/database/mongodb/manifest.yml create mode 100644 apps/accounts/automations/remove_account/database/mysql/main.yml create mode 100644 apps/accounts/automations/remove_account/database/mysql/manifest.yml create mode 100644 apps/accounts/automations/remove_account/database/oracle/main.yml create mode 100644 apps/accounts/automations/remove_account/database/oracle/manifest.yml create mode 100644 apps/accounts/automations/remove_account/database/postgresql/main.yml create mode 100644 apps/accounts/automations/remove_account/database/postgresql/manifest.yml create mode 100644 apps/accounts/automations/remove_account/database/sqlserver/main.yml create mode 100644 apps/accounts/automations/remove_account/database/sqlserver/manifest.yml create mode 100644 apps/accounts/automations/remove_account/host/posix/main.yml create mode 100644 apps/accounts/automations/remove_account/host/posix/manifest.yml create mode 100644 apps/accounts/automations/remove_account/host/windows/main.yml create mode 100644 apps/accounts/automations/remove_account/host/windows/manifest.yml create mode 100644 apps/accounts/automations/remove_account/manager.py create mode 100644 apps/accounts/permissions.py create mode 100644 apps/accounts/tasks/remove_account.py create mode 100644 apps/assets/migrations/0126_automation_remove_account.py diff --git a/apps/accounts/api/account/task.py b/apps/accounts/api/account/task.py index 16ea84eae..c4f6ebd9f 100644 --- a/apps/accounts/api/account/task.py +++ b/apps/accounts/api/account/task.py @@ -1,9 +1,12 @@ 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 +from accounts.permissions import AccountTaskActionPermission +from accounts.tasks import ( + remove_accounts_task, verify_accounts_connectivity_task, push_accounts_to_assets_task +) from assets.exceptions import NotSupportedTemporarilyError +from authentication.permissions import UserConfirmation, ConfirmType __all__ = [ 'AccountsTaskCreateAPI', @@ -12,16 +15,16 @@ __all__ = [ class AccountsTaskCreateAPI(CreateAPIView): serializer_class = serializers.AccountTaskSerializer + permission_classes = (AccountTaskActionPermission,) - def check_permissions(self, request): - act = request.data.get('action') - if act == 'push': - code = 'accounts.push_account' - else: - code = 'accounts.verify_account' - has = request.user.has_perm(code) - if not has: - self.permission_denied(request) + def get_permissions(self): + act = self.request.data.get('action') + if act == 'remove': + self.permission_classes = [ + AccountTaskActionPermission, + UserConfirmation.require(ConfirmType.PASSWORD) + ] + return super().get_permissions() def perform_create(self, serializer): data = serializer.validated_data @@ -31,6 +34,10 @@ class AccountsTaskCreateAPI(CreateAPIView): if data['action'] == 'push': task = push_accounts_to_assets_task.delay(account_ids, params) + elif data['action'] == 'remove': + gather_accounts = data.get('gather_accounts', []) + gather_account_ids = [str(a.id) for a in gather_accounts] + task = remove_accounts_task.delay(gather_account_ids) else: account = accounts[0] asset = account.asset @@ -43,9 +50,3 @@ class AccountsTaskCreateAPI(CreateAPIView): 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=401) - - return handler diff --git a/apps/accounts/automations/endpoint.py b/apps/accounts/automations/endpoint.py index c1a19c968..f045858a7 100644 --- a/apps/accounts/automations/endpoint.py +++ b/apps/accounts/automations/endpoint.py @@ -1,8 +1,9 @@ -from .push_account.manager import PushAccountManager -from .change_secret.manager import ChangeSecretManager -from .verify_account.manager import VerifyAccountManager from .backup_account.manager import AccountBackupManager +from .change_secret.manager import ChangeSecretManager from .gather_accounts.manager import GatherAccountsManager +from .push_account.manager import PushAccountManager +from .remove_account.manager import RemoveAccountManager +from .verify_account.manager import VerifyAccountManager from .verify_gateway_account.manager import VerifyGatewayAccountManager from ..const import AutomationTypes @@ -12,6 +13,7 @@ class ExecutionManager: AutomationTypes.push_account: PushAccountManager, AutomationTypes.change_secret: ChangeSecretManager, AutomationTypes.verify_account: VerifyAccountManager, + AutomationTypes.remove_account: RemoveAccountManager, AutomationTypes.gather_accounts: GatherAccountsManager, AutomationTypes.verify_gateway_account: VerifyGatewayAccountManager, # TODO 后期迁移到自动化策略中 diff --git a/apps/accounts/automations/remove_account/__init__.py b/apps/accounts/automations/remove_account/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/accounts/automations/remove_account/database/mongodb/main.yml b/apps/accounts/automations/remove_account/database/mongodb/main.yml new file mode 100644 index 000000000..3ec800981 --- /dev/null +++ b/apps/accounts/automations/remove_account/database/mongodb/main.yml @@ -0,0 +1,21 @@ +- hosts: mongodb + gather_facts: no + vars: + ansible_python_interpreter: /opt/py3/bin/python + + tasks: + - name: "Remove account" + mongodb_user: + login_user: "{{ jms_account.username }}" + login_password: "{{ jms_account.secret }}" + login_host: "{{ jms_asset.address }}" + login_port: "{{ jms_asset.port }}" + login_database: "{{ jms_asset.spec_info.db_name }}" + ssl: "{{ jms_asset.spec_info.use_ssl }}" + ssl_ca_certs: "{{ jms_asset.secret_info.ca_cert | default('') }}" + ssl_certfile: "{{ jms_asset.secret_info.client_key | default('') }}" + connection_options: + - tlsAllowInvalidHostnames: "{{ jms_asset.spec_info.allow_invalid_cert}}" + db: "{{ jms_asset.spec_info.db_name }}" + name: "{{ account.username }}" + state: absent \ No newline at end of file diff --git a/apps/accounts/automations/remove_account/database/mongodb/manifest.yml b/apps/accounts/automations/remove_account/database/mongodb/manifest.yml new file mode 100644 index 000000000..681a6a521 --- /dev/null +++ b/apps/accounts/automations/remove_account/database/mongodb/manifest.yml @@ -0,0 +1,12 @@ +id: remove_account_mongodb +name: "{{ 'MongoDB account remove' | trans }}" +category: database +type: + - mongodb +method: remove_account + +i18n: + MongoDB account remove: + zh: 使用 Ansible 模块 mongodb 删除账号 + ja: Ansible モジュール mongodb を使用してアカウントを削除する + en: Delete account using Ansible module mongodb diff --git a/apps/accounts/automations/remove_account/database/mysql/main.yml b/apps/accounts/automations/remove_account/database/mysql/main.yml new file mode 100644 index 000000000..563a7d74b --- /dev/null +++ b/apps/accounts/automations/remove_account/database/mysql/main.yml @@ -0,0 +1,18 @@ +- hosts: mysql + gather_facts: no + vars: + ansible_python_interpreter: /opt/py3/bin/python + + tasks: + - name: "Remove account" + community.mysql.mysql_user: + login_user: "{{ jms_account.username }}" + login_password: "{{ jms_account.secret }}" + login_host: "{{ jms_asset.address }}" + login_port: "{{ jms_asset.port }}" + check_hostname: "{{ check_ssl if check_ssl else omit }}" + ca_cert: "{{ jms_asset.secret_info.ca_cert | default(omit) if check_ssl else omit }}" + client_cert: "{{ jms_asset.secret_info.client_cert | default(omit) if check_ssl else omit }}" + client_key: "{{ jms_asset.secret_info.client_key | default(omit) if check_ssl else omit }}" + name: "{{ account.username }}" + state: absent diff --git a/apps/accounts/automations/remove_account/database/mysql/manifest.yml b/apps/accounts/automations/remove_account/database/mysql/manifest.yml new file mode 100644 index 000000000..ff8845a6d --- /dev/null +++ b/apps/accounts/automations/remove_account/database/mysql/manifest.yml @@ -0,0 +1,14 @@ +id: remove_account_mysql +name: "{{ 'MySQL account remove' | trans }}" +category: database +type: + - mysql + - mariadb +method: remove_account + +i18n: + MySQL account remove: + zh: 使用 Ansible 模块 mysql_user 删除账号 + ja: Ansible モジュール mysql_user を使用してアカウントを削除します + en: Use the Ansible module mysql_user to delete the account + diff --git a/apps/accounts/automations/remove_account/database/oracle/main.yml b/apps/accounts/automations/remove_account/database/oracle/main.yml new file mode 100644 index 000000000..ffd846d47 --- /dev/null +++ b/apps/accounts/automations/remove_account/database/oracle/main.yml @@ -0,0 +1,16 @@ +- hosts: oracle + gather_facts: no + vars: + ansible_python_interpreter: /opt/py3/bin/python + + tasks: + - name: "Remove account" + oracle_user: + login_user: "{{ jms_account.username }}" + login_password: "{{ jms_account.secret }}" + login_host: "{{ jms_asset.address }}" + login_port: "{{ jms_asset.port }}" + login_database: "{{ jms_asset.spec_info.db_name }}" + mode: "{{ jms_account.mode }}" + name: "{{ account.username }}" + state: absent diff --git a/apps/accounts/automations/remove_account/database/oracle/manifest.yml b/apps/accounts/automations/remove_account/database/oracle/manifest.yml new file mode 100644 index 000000000..173053673 --- /dev/null +++ b/apps/accounts/automations/remove_account/database/oracle/manifest.yml @@ -0,0 +1,12 @@ +id: remove_account_oracle +name: "{{ 'Oracle account remove' | trans }}" +category: database +type: + - oracle +method: remove_account + +i18n: + Oracle account remove: + zh: 使用 Python 模块 oracledb 删除账号 + ja: Python モジュール oracledb を使用してアカウントを検証する + en: Using Python module oracledb to verify account diff --git a/apps/accounts/automations/remove_account/database/postgresql/main.yml b/apps/accounts/automations/remove_account/database/postgresql/main.yml new file mode 100644 index 000000000..7004dc945 --- /dev/null +++ b/apps/accounts/automations/remove_account/database/postgresql/main.yml @@ -0,0 +1,15 @@ +- hosts: postgresql + gather_facts: no + vars: + ansible_python_interpreter: /opt/py3/bin/python + + tasks: + - name: "Remove account" + community.postgresql.postgresql_user: + login_user: "{{ jms_account.username }}" + login_password: "{{ jms_account.secret }}" + login_host: "{{ jms_asset.address }}" + login_port: "{{ jms_asset.port }}" + db: "{{ jms_asset.spec_info.db_name }}" + name: "{{ account.username }}" + state: absent diff --git a/apps/accounts/automations/remove_account/database/postgresql/manifest.yml b/apps/accounts/automations/remove_account/database/postgresql/manifest.yml new file mode 100644 index 000000000..c6c143e94 --- /dev/null +++ b/apps/accounts/automations/remove_account/database/postgresql/manifest.yml @@ -0,0 +1,12 @@ +id: remove_account_postgresql +name: "{{ 'PostgreSQL account remove' | trans }}" +category: database +type: + - postgresql +method: remove_account + +i18n: + PostgreSQL account remove: + zh: 使用 Ansible 模块 postgresql_user 删除账号 + ja: Ansible モジュール postgresql_user を使用してアカウントを削除します + en: Use the Ansible module postgresql_user to delete the account diff --git a/apps/accounts/automations/remove_account/database/sqlserver/main.yml b/apps/accounts/automations/remove_account/database/sqlserver/main.yml new file mode 100644 index 000000000..597e12906 --- /dev/null +++ b/apps/accounts/automations/remove_account/database/sqlserver/main.yml @@ -0,0 +1,14 @@ +- hosts: sqlserver + gather_facts: no + vars: + ansible_python_interpreter: /opt/py3/bin/python + + tasks: + - name: "Remove account" + community.general.mssql_script: + login_user: "{{ jms_account.username }}" + login_password: "{{ jms_account.secret }}" + login_host: "{{ jms_asset.address }}" + login_port: "{{ jms_asset.port }}" + name: "{{ jms_asset.spec_info.db_name }}" + script: "DROP USER {{ account.username }}" diff --git a/apps/accounts/automations/remove_account/database/sqlserver/manifest.yml b/apps/accounts/automations/remove_account/database/sqlserver/manifest.yml new file mode 100644 index 000000000..33c4895e2 --- /dev/null +++ b/apps/accounts/automations/remove_account/database/sqlserver/manifest.yml @@ -0,0 +1,12 @@ +id: remove_account_sqlserver +name: "{{ 'SQLServer account remove' | trans }}" +category: database +type: + - sqlserver +method: remove_account + +i18n: + SQLServer account remove: + zh: 使用 Ansible 模块 mssql 删除账号 + ja: Ansible モジュール mssql を使用してアカウントを削除する + en: Use Ansible module mssql to delete account diff --git a/apps/accounts/automations/remove_account/host/posix/main.yml b/apps/accounts/automations/remove_account/host/posix/main.yml new file mode 100644 index 000000000..de91b8552 --- /dev/null +++ b/apps/accounts/automations/remove_account/host/posix/main.yml @@ -0,0 +1,25 @@ +- hosts: demo + gather_facts: no + tasks: + - name: "Get user home directory path" + ansible.builtin.shell: + cmd: "getent passwd {{ account.username }} | cut -d: -f6" + register: user_home_dir + ignore_errors: yes + + - name: "Check if user home directory exists" + ansible.builtin.stat: + path: "{{ user_home_dir.stdout }}" + register: home_dir + when: user_home_dir.stdout != "" + + - name: "Rename user home directory if it exists" + ansible.builtin.command: + cmd: "mv {{ user_home_dir.stdout }} {{ user_home_dir.stdout }}.bak" + when: home_dir.stat.exists and user_home_dir.stdout != "" + + - name: "Remove account" + ansible.builtin.user: + name: "{{ account.username }}" + state: absent + remove: "{{ home_dir.stat.exists }}" diff --git a/apps/accounts/automations/remove_account/host/posix/manifest.yml b/apps/accounts/automations/remove_account/host/posix/manifest.yml new file mode 100644 index 000000000..753c63574 --- /dev/null +++ b/apps/accounts/automations/remove_account/host/posix/manifest.yml @@ -0,0 +1,13 @@ +id: remove_account_posix +name: "{{ 'Posix account remove' | trans }}" +category: host +type: + - linux + - unix +method: remove_account + +i18n: + Posix account remove: + zh: 使用 Ansible 模块 user 删除账号 + ja: Ansible モジュール ユーザーを使用してアカウントを削除します + en: Use the Ansible module user to delete the account diff --git a/apps/accounts/automations/remove_account/host/windows/main.yml b/apps/accounts/automations/remove_account/host/windows/main.yml new file mode 100644 index 000000000..7be9940b3 --- /dev/null +++ b/apps/accounts/automations/remove_account/host/windows/main.yml @@ -0,0 +1,9 @@ +- hosts: windows + gather_facts: no + tasks: + - name: "Remove account" + ansible.windows.win_user: + name: "{{ account.username }}" + state: absent + purge: yes + force: yes \ No newline at end of file diff --git a/apps/accounts/automations/remove_account/host/windows/manifest.yml b/apps/accounts/automations/remove_account/host/windows/manifest.yml new file mode 100644 index 000000000..588d7efea --- /dev/null +++ b/apps/accounts/automations/remove_account/host/windows/manifest.yml @@ -0,0 +1,13 @@ +id: remove_account_windows +name: "{{ 'Windows account remove' | trans }}" +version: 1 +method: remove_account +category: host +type: + - windows + +i18n: + Windows account remove: + zh: 使用 Ansible 模块 win_user 删除账号 + ja: Ansible モジュール win_user を使用してアカウントを削除する + en: Use the Ansible module win_user to delete an account diff --git a/apps/accounts/automations/remove_account/manager.py b/apps/accounts/automations/remove_account/manager.py new file mode 100644 index 000000000..37dd28f2d --- /dev/null +++ b/apps/accounts/automations/remove_account/manager.py @@ -0,0 +1,67 @@ +import os +from copy import deepcopy + +from django.db.models import QuerySet + +from accounts.const import AutomationTypes +from accounts.models import Account +from common.utils import get_logger +from ..base.manager import AccountBasePlaybookManager + +logger = get_logger(__name__) + + +class RemoveAccountManager(AccountBasePlaybookManager): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.host_account_mapper = {} + + def prepare_runtime_dir(self): + path = super().prepare_runtime_dir() + ansible_config_path = os.path.join(path, 'ansible.cfg') + + with open(ansible_config_path, 'w') as f: + f.write('[ssh_connection]\n') + f.write('ssh_args = -o ControlMaster=no -o ControlPersist=no\n') + return path + + @classmethod + def method_type(cls): + return AutomationTypes.remove_account + + def get_gather_accounts(self, privilege_account, gather_accounts: QuerySet): + gather_account_ids = self.execution.snapshot['gather_accounts'] + gather_accounts = gather_accounts.filter(id__in=gather_account_ids) + gather_accounts = gather_accounts.exclude( + username__in=[privilege_account.username, 'root', 'Administrator'] + ) + return gather_accounts + + def host_callback(self, host, asset=None, account=None, automation=None, path_dir=None, **kwargs): + if host.get('error'): + return host + + gather_accounts = asset.gatheredaccount_set.all() + gather_accounts = self.get_gather_accounts(account, gather_accounts) + + inventory_hosts = [] + + for gather_account in gather_accounts: + h = deepcopy(host) + h['name'] += '(' + gather_account.username + ')' + self.host_account_mapper[h['name']] = (asset, gather_account) + h['account'] = {'username': gather_account.username} + inventory_hosts.append(h) + return inventory_hosts + + def on_host_success(self, host, result): + tuple_asset_gather_account = self.host_account_mapper.get(host) + if not tuple_asset_gather_account: + return + asset, gather_account = tuple_asset_gather_account + Account.objects.filter( + asset_id=asset.id, + username=gather_account.username + ).delete() + gather_account.delete() diff --git a/apps/accounts/automations/verify_account/database/mongodb/main.yml b/apps/accounts/automations/verify_account/database/mongodb/main.yml index 2770e6eb4..13ecccb61 100644 --- a/apps/accounts/automations/verify_account/database/mongodb/main.yml +++ b/apps/accounts/automations/verify_account/database/mongodb/main.yml @@ -1,4 +1,4 @@ -- hosts: mongdb +- hosts: mongodb gather_facts: no vars: ansible_python_interpreter: /opt/py3/bin/python diff --git a/apps/accounts/const/automation.py b/apps/accounts/const/automation.py index 0a67de5c8..cde7fe982 100644 --- a/apps/accounts/const/automation.py +++ b/apps/accounts/const/automation.py @@ -24,6 +24,7 @@ class AutomationTypes(models.TextChoices): push_account = 'push_account', _('Push account') change_secret = 'change_secret', _('Change secret') verify_account = 'verify_account', _('Verify account') + remove_account = 'remove_account', _('Remove account') gather_accounts = 'gather_accounts', _('Gather accounts') verify_gateway_account = 'verify_gateway_account', _('Verify gateway account') diff --git a/apps/accounts/migrations/0007_alter_account_options.py b/apps/accounts/migrations/0007_alter_account_options.py index 4ec798a21..6def6de6e 100644 --- a/apps/accounts/migrations/0007_alter_account_options.py +++ b/apps/accounts/migrations/0007_alter_account_options.py @@ -4,7 +4,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ ('accounts', '0006_gatheredaccount'), ] @@ -12,6 +11,13 @@ 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'), ('verify_account', 'Can verify account'), ('push_account', 'Can push account')], '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'), + ('remove_account', 'Can remove account'), + ], 'verbose_name': 'Account'}, ), ] diff --git a/apps/accounts/models/account.py b/apps/accounts/models/account.py index c3c052b1b..1defa3642 100644 --- a/apps/accounts/models/account.py +++ b/apps/accounts/models/account.py @@ -69,6 +69,7 @@ class Account(AbsConnectivity, LabeledMixin, BaseAccount): ('view_historyaccountsecret', _('Can view asset history account secret')), ('verify_account', _('Can verify account')), ('push_account', _('Can push account')), + ('remove_account', _('Can remove account')), ] def __str__(self): diff --git a/apps/accounts/permissions.py b/apps/accounts/permissions.py new file mode 100644 index 000000000..6d3b94260 --- /dev/null +++ b/apps/accounts/permissions.py @@ -0,0 +1,19 @@ +from rest_framework import permissions + + +def check_permissions(request): + act = request.data.get('action') + if act == 'push': + code = 'accounts.push_account' + elif act == 'remove': + code = 'accounts.remove_account' + else: + code = 'accounts.verify_account' + return request.user.has_perm(code) + + +class AccountTaskActionPermission(permissions.IsAuthenticated): + + def has_permission(self, request, view): + return super().has_permission(request, view) \ + and check_permissions(request) diff --git a/apps/accounts/serializers/account/account.py b/apps/accounts/serializers/account/account.py index c1098a6d1..197c64c7d 100644 --- a/apps/accounts/serializers/account/account.py +++ b/apps/accounts/serializers/account/account.py @@ -10,7 +10,7 @@ from rest_framework.generics import get_object_or_404 from rest_framework.validators import UniqueTogetherValidator from accounts.const import SecretType, Source, AccountInvalidPolicy -from accounts.models import Account, AccountTemplate +from accounts.models import Account, AccountTemplate, GatheredAccount from accounts.tasks import push_accounts_to_assets_task from assets.const import Category, AllTypes from assets.models import Asset @@ -458,11 +458,15 @@ class AccountTaskSerializer(serializers.Serializer): ('test', 'test'), ('verify', 'verify'), ('push', 'push'), + ('remove', 'remove'), ) action = serializers.ChoiceField(choices=ACTION_CHOICES, write_only=True) accounts = serializers.PrimaryKeyRelatedField( queryset=Account.objects, required=False, allow_empty=True, many=True ) + gather_accounts = serializers.PrimaryKeyRelatedField( + queryset=GatheredAccount.objects, required=False, allow_empty=True, many=True + ) task = serializers.CharField(read_only=True) params = serializers.JSONField( decoder=None, encoder=None, required=False, diff --git a/apps/accounts/tasks/__init__.py b/apps/accounts/tasks/__init__.py index 8a79c1aa4..a20eba291 100644 --- a/apps/accounts/tasks/__init__.py +++ b/apps/accounts/tasks/__init__.py @@ -2,5 +2,6 @@ from .automation import * from .backup_account import * from .gather_accounts import * from .push_account import * +from .remove_account import * from .template import * from .verify_account import * diff --git a/apps/accounts/tasks/remove_account.py b/apps/accounts/tasks/remove_account.py new file mode 100644 index 000000000..62a9375a1 --- /dev/null +++ b/apps/accounts/tasks/remove_account.py @@ -0,0 +1,31 @@ +from celery import shared_task +from django.utils.translation import gettext_noop, gettext_lazy as _ + +from accounts.const import AutomationTypes +from accounts.tasks.common import quickstart_automation_by_snapshot +from common.utils import get_logger + +logger = get_logger(__file__) + +__all__ = ['remove_accounts_task'] + + +@shared_task( + queue="ansible", verbose_name=_('Remove accounts'), + activity_callback=lambda self, gather_account_ids, *args, **kwargs: (gather_account_ids, None) +) +def remove_accounts_task(gather_account_ids): + from accounts.models import GatheredAccount + + gather_accounts = GatheredAccount.objects.filter( + id__in=gather_account_ids + ) + task_name = gettext_noop("Remove accounts") + + task_snapshot = { + 'assets': [str(i.asset_id) for i in gather_accounts], + 'gather_accounts': [str(i.id) for i in gather_accounts], + } + + tp = AutomationTypes.remove_account + quickstart_automation_by_snapshot(task_name, tp, task_snapshot) diff --git a/apps/assets/migrations/0126_automation_remove_account.py b/apps/assets/migrations/0126_automation_remove_account.py new file mode 100644 index 000000000..6ac63ab3d --- /dev/null +++ b/apps/assets/migrations/0126_automation_remove_account.py @@ -0,0 +1,55 @@ +# Generated by Django 4.1.10 on 2023-12-05 10:03 +from functools import reduce + +from django.db import migrations, models +from django.db.models import F + + +def migrate_automation_ansible_remove_account(apps, *args): + automation_model = apps.get_model('assets', 'PlatformAutomation') + automation_map = { + ('oracle',): 'remove_account_oracle', + ('windows',): 'remove_account_windows', + ('mongodb',): 'remove_account_mongodb', + ('linux', 'unix'): 'remove_account_posix', + ('sqlserver',): 'remove_account_sqlserver', + ('mysql', 'mariadb'): 'remove_account_mysql', + ('postgresql',): 'remove_account_postgresql', + } + + update_objs = [] + types = list(reduce(lambda x, y: x + y, automation_map.keys())) + qs = automation_model.objects.filter(platform__type__in=types).annotate(tp=F('platform__type')) + for automation in qs: + for types, method in automation_map.items(): + if automation.tp in types: + automation.remove_account_enabled = True + automation.remove_account_method = method + break + update_objs.append(automation) + automation_model.objects.bulk_update(update_objs, ['remove_account_enabled', 'remove_account_method']) + + +class Migration(migrations.Migration): + dependencies = [ + ('assets', '0125_auto_20231011_1053'), + ] + + operations = [ + migrations.AddField( + model_name='platformautomation', + name='remove_account_enabled', + field=models.BooleanField(default=False, verbose_name='Remove account enabled'), + ), + migrations.AddField( + model_name='platformautomation', + name='remove_account_method', + field=models.TextField(blank=True, max_length=32, null=True, verbose_name='Remove account method'), + ), + migrations.AddField( + model_name='platformautomation', + name='remove_account_params', + field=models.JSONField(default=dict, verbose_name='Remove account params'), + ), + migrations.RunPython(migrate_automation_ansible_remove_account) + ] diff --git a/apps/assets/models/platform.py b/apps/assets/models/platform.py index 74fcb9cfb..a93a96863 100644 --- a/apps/assets/models/platform.py +++ b/apps/assets/models/platform.py @@ -72,6 +72,12 @@ class PlatformAutomation(models.Model): max_length=32, blank=True, null=True, verbose_name=_("Gather facts method") ) gather_accounts_params = models.JSONField(default=dict, verbose_name=_("Gather facts params")) + + remove_account_enabled = models.BooleanField(default=False, verbose_name=_("Remove account enabled")) + remove_account_method = models.TextField( + max_length=32, blank=True, null=True, verbose_name=_("Remove account method") + ) + remove_account_params = models.JSONField(default=dict, verbose_name=_("Remove account params")) platform = models.OneToOneField('Platform', on_delete=models.CASCADE, related_name='automation', null=True)