From 121ba1df072baa4790932b0b79760b0b4e0ad3d9 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Fri, 28 Oct 2022 18:28:41 +0800 Subject: [PATCH] perf: automations push ping verify --- apps/assets/automations/base/manager.py | 76 +++++++++++++++++-- .../database/postgresql/main.yml | 6 +- .../change_secret/host/aix/main.yml | 58 -------------- .../change_secret/host/aix/manifest.yml | 6 -- .../automations/change_secret/manager.py | 18 +---- apps/assets/automations/endpoint.py | 4 + .../gather_accounts/database/mysql/main.yml | 4 +- .../database/postgresql/main.yml | 2 +- .../gather_accounts/host/posix/main.yml | 6 +- .../gather_accounts/host/windows/main.yml | 26 +++---- .../automations/gather_accounts/manager.py | 4 +- .../gather_facts/database/postgresql/main.yml | 2 +- .../automations/gather_facts/manager.py | 2 +- .../automations/ping/database/mysql/main.yml | 7 -- .../ping/database/postgresql/main.yml | 12 +-- .../automations/ping/host/windows/main.yml | 2 +- apps/assets/automations/ping/manager.py | 13 +++- .../README.md => push_account/__init__.py} | 0 .../push_account/database/mysql/main.yml | 15 ++++ .../push_account/database/mysql/manifest.yml | 6 ++ .../push_account/database/postgresql/main.yml | 16 ++++ .../database/postgresql/manifest.yml | 6 ++ .../push_account/host/posix/main.yml | 19 +++++ .../push_account/host/posix/manifest.yml | 7 ++ .../push_account/host/windows/main.yml | 13 ++++ .../push_account/host/windows/manifest.yml | 7 ++ .../automations/push_account/manager.py | 17 +++++ .../automations/verify_account/__init__.py | 0 .../verify_account/database/mysql/main.yml | 13 ++++ .../database/mysql/manifest.yml | 6 ++ .../database/postgresql/main.yml | 13 ++++ .../database/postgresql/manifest.yml | 6 ++ .../verify_account/host/posix/main.yml | 11 +++ .../verify_account/host/posix/manifest.yml | 7 ++ .../verify_account/host/windows/main.yml | 8 ++ .../verify_account/host/windows/manifest.yml | 7 ++ .../automations/verify_account/manager.py | 25 ++++++ apps/assets/models/automations/__init__.py | 2 +- .../models/automations/change_secret.py | 1 - .../assets/models/automations/push_account.py | 17 +++-- .../{verify_secret.py => verify_account.py} | 11 ++- apps/ops/ansible/callback.py | 2 +- apps/ops/ansible/inventory.py | 13 ++-- 43 files changed, 339 insertions(+), 157 deletions(-) delete mode 100644 apps/assets/automations/change_secret/host/aix/main.yml delete mode 100644 apps/assets/automations/change_secret/host/aix/manifest.yml rename apps/assets/automations/{gather_facts/README.md => push_account/__init__.py} (100%) create mode 100644 apps/assets/automations/push_account/database/mysql/main.yml create mode 100644 apps/assets/automations/push_account/database/mysql/manifest.yml create mode 100644 apps/assets/automations/push_account/database/postgresql/main.yml create mode 100644 apps/assets/automations/push_account/database/postgresql/manifest.yml create mode 100644 apps/assets/automations/push_account/host/posix/main.yml create mode 100644 apps/assets/automations/push_account/host/posix/manifest.yml create mode 100644 apps/assets/automations/push_account/host/windows/main.yml create mode 100644 apps/assets/automations/push_account/host/windows/manifest.yml create mode 100644 apps/assets/automations/push_account/manager.py create mode 100644 apps/assets/automations/verify_account/__init__.py create mode 100644 apps/assets/automations/verify_account/database/mysql/main.yml create mode 100644 apps/assets/automations/verify_account/database/mysql/manifest.yml create mode 100644 apps/assets/automations/verify_account/database/postgresql/main.yml create mode 100644 apps/assets/automations/verify_account/database/postgresql/manifest.yml create mode 100644 apps/assets/automations/verify_account/host/posix/main.yml create mode 100644 apps/assets/automations/verify_account/host/posix/manifest.yml create mode 100644 apps/assets/automations/verify_account/host/windows/main.yml create mode 100644 apps/assets/automations/verify_account/host/windows/manifest.yml create mode 100644 apps/assets/automations/verify_account/manager.py rename apps/assets/models/automations/{verify_secret.py => verify_account.py} (56%) diff --git a/apps/assets/automations/base/manager.py b/apps/assets/automations/base/manager.py index e2faecd64..2339867c1 100644 --- a/apps/assets/automations/base/manager.py +++ b/apps/assets/automations/base/manager.py @@ -1,19 +1,68 @@ import os -import shutil import yaml +import shutil +from hashlib import md5 +from copy import deepcopy +from socket import gethostname from collections import defaultdict from django.conf import settings from django.utils import timezone +from django.db.models import Model from django.utils.translation import gettext as _ from common.utils import get_logger +from common.utils import ssh_pubkey_gen, ssh_key_string_to_obj +from assets.const import SecretType from assets.automations.methods import platform_automation_methods from ops.ansible import JMSInventory, PlaybookRunner, DefaultCallback logger = get_logger(__name__) +class PushOrVerifyHostCallbackMixin: + execution: Model() + host_account_mapper: dict + ignore_account: bool + generate_public_key: callable + generate_private_key_path: callable + + 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, **kwargs) + if host.get('error'): + return host + + accounts = asset.accounts.all() + if self.ignore_account and account: + accounts = accounts.exclude(id=account.id) + + if '*' not in self.execution.snapshot['accounts']: + accounts = accounts.filter(username__in=self.execution.snapshot['accounts']) + + inventory_hosts = [] + for account in accounts: + h = deepcopy(host) + h['name'] += '_' + account.username + self.host_account_mapper[h['name']] = account + secret = account.secret + + private_key_path = None + if account.secret_type == SecretType.ssh_key: + private_key_path = self.generate_private_key_path(secret, path_dir) + secret = self.generate_public_key(secret) + + h['secret_type'] = account.secret_type + h['account'] = { + 'name': account.name, + 'username': account.username, + 'secret_type': account.secret_type, + 'secret': secret, + 'private_key_path': private_key_path + } + inventory_hosts.append(h) + return inventory_hosts + + class PlaybookCallback(DefaultCallback): def playbook_on_stats(self, event_data, **kwargs): super().playbook_on_stats(event_data, **kwargs) @@ -66,20 +115,33 @@ 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())) return host return host + @staticmethod + def generate_public_key(private_key): + return ssh_pubkey_gen(private_key=private_key, hostname=gethostname()) + + @staticmethod + def generate_private_key_path(secret, path_dir): + key_name = '.' + md5(secret.encode('utf-8')).hexdigest() + key_path = os.path.join(path_dir, key_name) + if not os.path.exists(key_path): + ssh_key_string_to_obj(secret, password=None).write_private_key_file(key_path) + os.chmod(key_path, 0o400) + return key_path + def generate_inventory(self, platformed_assets, inventory_path): inventory = JMSInventory( - manager=self, assets=platformed_assets, account_policy=self.ansible_account_policy, + host_callback=self.host_callback, ) inventory.write_to_file(inventory_path) @@ -105,7 +167,7 @@ class BasePlaybookManager: def get_runners(self): runners = [] for platform, assets in self.get_assets_group_by_platform().items(): - assets_bulked = [assets[i:i+self.bulk_size] for i in range(0, len(assets), self.bulk_size)] + assets_bulked = [assets[i:i + self.bulk_size] for i in range(0, len(assets), self.bulk_size)] for i, _assets in enumerate(assets_bulked, start=1): sub_dir = '{}_{}'.format(platform.name, i) @@ -148,7 +210,7 @@ class BasePlaybookManager: print(" inventory: {}".format(runner.inventory)) print(" playbook: {}".format(runner.playbook)) - def run(self, *args, **kwargs): + def run(self, *args, **kwargs): runners = self.get_runners() if len(runners) > 1: print("### 分批次执行开始任务, 总共 {}\n".format(len(runners))) diff --git a/apps/assets/automations/change_secret/database/postgresql/main.yml b/apps/assets/automations/change_secret/database/postgresql/main.yml index 40c326704..4ef9d65ab 100644 --- a/apps/assets/automations/change_secret/database/postgresql/main.yml +++ b/apps/assets/automations/change_secret/database/postgresql/main.yml @@ -10,7 +10,7 @@ login_password: "{{ jms_account.secret }}" login_host: "{{ jms_asset.address }}" login_port: "{{ jms_asset.port }}" - login_db: "{{ jms_asset.database }}" + login_db: "{{ jms_asset.category_property.db_name }}" register: db_info - name: Display PostgreSQL version @@ -24,7 +24,7 @@ login_password: "{{ jms_account.secret }}" login_host: "{{ jms_asset.address }}" login_port: "{{ jms_asset.port }}" - db: "{{ jms_asset.database }}" + db: "{{ jms_asset.category_property.db_name }}" name: "{{ account.username }}" password: "{{ account.secret }}" when: db_info is succeeded @@ -36,7 +36,7 @@ login_password: "{{ account.secret }}" login_host: "{{ jms_asset.address }}" login_port: "{{ jms_asset.port }}" - db: "{{ jms_asset.database }}" + db: "{{ jms_asset.category_property.db_name }}" when: - db_info is succeeded - change_info is succeeded diff --git a/apps/assets/automations/change_secret/host/aix/main.yml b/apps/assets/automations/change_secret/host/aix/main.yml deleted file mode 100644 index 1a4e6a6a4..000000000 --- a/apps/assets/automations/change_secret/host/aix/main.yml +++ /dev/null @@ -1,58 +0,0 @@ -- hosts: demo - gather_facts: no - 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: - name: "{{ account.username }}" - password: "{{ account.secret | password_hash('sha512') }}" - update_password: always - when: secret_type == "password" - - - name: create user If it already exists, no operation will be performed - ansible.builtin.user: - name: "{{ account.username }}" - when: secret_type == "ssh_key" - - - name: remove jumpserver ssh key - ansible.builtin.lineinfile: - dest: "{{ kwargs.dest }}" - regexp: "{{ kwargs.regexp }}" - state: absent - when: - - secret_type == "ssh_key" - - kwargs.strategy == "set_jms" - - - name: Change SSH key - ansible.builtin.authorized_key: - user: "{{ account.username }}" - key: "{{ account.secret }}" - exclusive: "{{ kwargs.exclusive }}" - when: secret_type == "ssh_key" - - - name: Refresh connection - ansible.builtin.meta: reset_connection - - - name: Verify password - ansible.builtin.ping: - become: no - vars: - ansible_user: "{{ account.username }}" - ansible_password: "{{ account.secret }}" - ansible_become: no - when: secret_type == "password" - - - name: Verify SSH key - ansible.builtin.ping: - become: no - vars: - ansible_user: "{{ account.username }}" - ansible_ssh_private_key_file: "{{ account.private_key_path }}" - ansible_become: no - when: secret_type == "ssh_key" diff --git a/apps/assets/automations/change_secret/host/aix/manifest.yml b/apps/assets/automations/change_secret/host/aix/manifest.yml deleted file mode 100644 index 94d93f3af..000000000 --- a/apps/assets/automations/change_secret/host/aix/manifest.yml +++ /dev/null @@ -1,6 +0,0 @@ -id: change_secret_aix -name: Change password for AIX -category: host -type: - - aix -method: change_secret diff --git a/apps/assets/automations/change_secret/manager.py b/apps/assets/automations/change_secret/manager.py index 4ac49676b..b8868acd1 100644 --- a/apps/assets/automations/change_secret/manager.py +++ b/apps/assets/automations/change_secret/manager.py @@ -1,14 +1,11 @@ -import os import random import string -from hashlib import md5 from copy import deepcopy -from socket import gethostname from collections import defaultdict from django.utils import timezone -from common.utils import lazyproperty, gen_key_pair, ssh_pubkey_gen, ssh_key_string_to_obj +from common.utils import lazyproperty, gen_key_pair from assets.models import ChangeSecretRecord from assets.const import ( AutomationTypes, SecretType, SecretStrategy, SSHKeyStrategy, DEFAULT_PASSWORD_RULES @@ -39,19 +36,6 @@ class ChangeSecretManager(BasePlaybookManager): private_key, public_key = gen_key_pair() return private_key - @staticmethod - def generate_public_key(private_key): - return ssh_pubkey_gen(private_key=private_key, hostname=gethostname()) - - @staticmethod - def generate_private_key_path(secret, path_dir): - key_name = '.' + md5(secret.encode('utf-8')).hexdigest() - key_path = os.path.join(path_dir, key_name) - if not os.path.exists(key_path): - ssh_key_string_to_obj(secret, password=None).write_private_key_file(key_path) - os.chmod(key_path, 0o400) - return key_path - def generate_password(self): kwargs = self.execution.snapshot['password_rules'] or {} length = int(kwargs.get('length', DEFAULT_PASSWORD_RULES['length'])) diff --git a/apps/assets/automations/endpoint.py b/apps/assets/automations/endpoint.py index 11330370a..c6eb04593 100644 --- a/apps/assets/automations/endpoint.py +++ b/apps/assets/automations/endpoint.py @@ -1,6 +1,8 @@ from .change_secret.manager import ChangeSecretManager from .gather_facts.manager import GatherFactsManager from .gather_accounts.manager import GatherAccountsManager +from .verify_account.manager import VerifyAccountManager +from .push_account.manager import PushAccountManager from ..const import AutomationTypes @@ -9,6 +11,8 @@ class ExecutionManager: AutomationTypes.change_secret: ChangeSecretManager, AutomationTypes.gather_facts: GatherFactsManager, AutomationTypes.gather_accounts: GatherAccountsManager, + AutomationTypes.verify_account: VerifyAccountManager, + AutomationTypes.push_account: PushAccountManager, } def __init__(self, execution): diff --git a/apps/assets/automations/gather_accounts/database/mysql/main.yml b/apps/assets/automations/gather_accounts/database/mysql/main.yml index cc934f20f..4b166322a 100644 --- a/apps/assets/automations/gather_accounts/database/mysql/main.yml +++ b/apps/assets/automations/gather_accounts/database/mysql/main.yml @@ -1,7 +1,7 @@ - hosts: mysql gather_facts: no vars: - ansible_python_interpreter: /usr/local/bin/python + ansible_python_interpreter: /Users/xiaofeng/Desktop/jumpserver/venv/bin/python tasks: - name: Get info @@ -9,7 +9,7 @@ login_user: "{{ jms_account.username }}" login_password: "{{ jms_account.secret }}" login_host: "{{ jms_asset.address }}" - login_port: "{{ jms_asset.port }}" + login_port: 1234 filter: users register: db_info diff --git a/apps/assets/automations/gather_accounts/database/postgresql/main.yml b/apps/assets/automations/gather_accounts/database/postgresql/main.yml index 2e12f51e5..cf0320627 100644 --- a/apps/assets/automations/gather_accounts/database/postgresql/main.yml +++ b/apps/assets/automations/gather_accounts/database/postgresql/main.yml @@ -10,7 +10,7 @@ login_password: "{{ jms_account.secret }}" login_host: "{{ jms_asset.address }}" login_port: "{{ jms_asset.port }}" - login_db: "{{ jms_asset.database }}" + login_db: "{{ jms_asset.category_property.db_name }}" filter: "roles" register: db_info diff --git a/apps/assets/automations/gather_accounts/host/posix/main.yml b/apps/assets/automations/gather_accounts/host/posix/main.yml index 97326431d..a64323f9d 100644 --- a/apps/assets/automations/gather_accounts/host/posix/main.yml +++ b/apps/assets/automations/gather_accounts/host/posix/main.yml @@ -2,8 +2,10 @@ gather_facts: no tasks: - name: Gather posix account - ansible.builtin.win_shell: - cmd: net user + ansible.builtin.shell: + cmd: > + users=$(getent passwd | grep -v nologin | grep -v shutdown | awk -F":" '{ print $1 }');for i in $users; + do last -w -F $i -1 | head -1 | grep -v ^$ | awk '{ print $1"@"$3"@"$5,$6,$7,$8 }';done register: result - name: Define info by set_fact diff --git a/apps/assets/automations/gather_accounts/host/windows/main.yml b/apps/assets/automations/gather_accounts/host/windows/main.yml index 377ffd10a..97326431d 100644 --- a/apps/assets/automations/gather_accounts/host/windows/main.yml +++ b/apps/assets/automations/gather_accounts/host/windows/main.yml @@ -1,18 +1,14 @@ -- hosts: windows - gather_facts: yes +- hosts: demo + gather_facts: no tasks: - - name: Get info - set_fact: - info: - arch: "{{ ansible_architecture2 }}" - distribution: "{{ ansible_distribution }}" - distribution_version: "{{ ansible_distribution_version }}" - kernel: "{{ ansible_kernel }}" - vendor: "{{ ansible_system_vendor }}" - model: "{{ ansible_product_name }}" - sn: "{{ ansible_product_serial }}" - cpu_vcpus: "{{ ansible_processor_vcpus }}" - memory: "{{ ansible_memtotal_mb }}" + - name: Gather posix account + ansible.builtin.win_shell: + cmd: net user + register: result + + - name: Define info by set_fact + ansible.builtin.set_fact: + info: "{{ result.stdout_lines }}" - debug: - var: info + var: info \ No newline at end of file diff --git a/apps/assets/automations/gather_accounts/manager.py b/apps/assets/automations/gather_accounts/manager.py index d6881f96c..40253be82 100644 --- a/apps/assets/automations/gather_accounts/manager.py +++ b/apps/assets/automations/gather_accounts/manager.py @@ -2,7 +2,7 @@ from common.utils import get_logger from assets.const import AutomationTypes from orgs.utils import tmp_to_org from .filter import GatherAccountsFilter -from ...models import Account, GatheredUser +from ...models import GatheredUser from ..base.manager import BasePlaybookManager logger = get_logger(__name__) @@ -42,4 +42,4 @@ class GatherAccountsManager(BasePlaybookManager): defaults['ip_last_login'] = data['address'][:32] GatheredUser.objects.update_or_create(defaults=defaults, asset=asset, username=username) else: - logger.error("Not found info, task name must be 'Get info': {}".format(host)) + logger.error("Not found info".format(host)) diff --git a/apps/assets/automations/gather_facts/database/postgresql/main.yml b/apps/assets/automations/gather_facts/database/postgresql/main.yml index 82adcdc16..98183e94c 100644 --- a/apps/assets/automations/gather_facts/database/postgresql/main.yml +++ b/apps/assets/automations/gather_facts/database/postgresql/main.yml @@ -10,7 +10,7 @@ login_password: "{{ jms_account.secret }}" login_host: "{{ jms_asset.address }}" login_port: "{{ jms_asset.port }}" - login_db: "{{ jms_asset.database }}" + login_db: "{{ jms_asset.category_property.db_name }}" register: db_info - name: Define info by set_fact diff --git a/apps/assets/automations/gather_facts/manager.py b/apps/assets/automations/gather_facts/manager.py index bbc3f9add..90fae1d75 100644 --- a/apps/assets/automations/gather_facts/manager.py +++ b/apps/assets/automations/gather_facts/manager.py @@ -26,4 +26,4 @@ class GatherFactsManager(BasePlaybookManager): asset.info = info asset.save() else: - logger.error("Not found info, task name must be 'Get info': {}".format(host)) + logger.error("Not found info: {}".format(host)) diff --git a/apps/assets/automations/ping/database/mysql/main.yml b/apps/assets/automations/ping/database/mysql/main.yml index fab498c76..ec7ca9432 100644 --- a/apps/assets/automations/ping/database/mysql/main.yml +++ b/apps/assets/automations/ping/database/mysql/main.yml @@ -2,12 +2,6 @@ gather_facts: no vars: ansible_python_interpreter: /usr/local/bin/python - jms_account: - username: root - password: redhat - jms_asset: - address: 127.0.0.1 - port: 3306 tasks: - name: Test MySQL connection @@ -17,4 +11,3 @@ login_host: "{{ jms_asset.address }}" login_port: "{{ jms_asset.port }}" filter: version - register: db_info diff --git a/apps/assets/automations/ping/database/postgresql/main.yml b/apps/assets/automations/ping/database/postgresql/main.yml index 3bc2f7957..d76ba3ae3 100644 --- a/apps/assets/automations/ping/database/postgresql/main.yml +++ b/apps/assets/automations/ping/database/postgresql/main.yml @@ -2,16 +2,6 @@ gather_facts: no vars: ansible_python_interpreter: /usr/local/bin/python - jms_account: - username: postgre - secret: postgre - jms_asset: - address: 127.0.0.1 - port: 5432 - database: testdb - account: - username: test - secret: jumpserver tasks: - name: Test PostgreSQL connection @@ -20,4 +10,4 @@ login_password: "{{ jms_account.secret }}" login_host: "{{ jms_asset.address }}" login_port: "{{ jms_asset.port }}" - login_db: "{{ jms_asset.database }}" + login_db: "{{ jms_asset.category_property.db_name }}" diff --git a/apps/assets/automations/ping/host/windows/main.yml b/apps/assets/automations/ping/host/windows/main.yml index 495b82a3d..d5af857a4 100644 --- a/apps/assets/automations/ping/host/windows/main.yml +++ b/apps/assets/automations/ping/host/windows/main.yml @@ -2,4 +2,4 @@ gather_facts: no tasks: - name: Windows ping - win_ping: + ansible.builtin.win_ping: diff --git a/apps/assets/automations/ping/manager.py b/apps/assets/automations/ping/manager.py index 84712fb44..791009e36 100644 --- a/apps/assets/automations/ping/manager.py +++ b/apps/assets/automations/ping/manager.py @@ -6,4 +6,15 @@ logger = get_logger(__name__) class PingManager(BasePlaybookManager): - pass + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.host_asset_mapper = {} + + @classmethod + def method_type(cls): + return AutomationTypes.ping + + def host_callback(self, host, asset=None, **kwargs): + super().host_callback(host, asset=asset, **kwargs) + self.host_asset_mapper[host['name']] = asset + return host diff --git a/apps/assets/automations/gather_facts/README.md b/apps/assets/automations/push_account/__init__.py similarity index 100% rename from apps/assets/automations/gather_facts/README.md rename to apps/assets/automations/push_account/__init__.py diff --git a/apps/assets/automations/push_account/database/mysql/main.yml b/apps/assets/automations/push_account/database/mysql/main.yml new file mode 100644 index 000000000..bf10c95af --- /dev/null +++ b/apps/assets/automations/push_account/database/mysql/main.yml @@ -0,0 +1,15 @@ +- hosts: mysql + gather_facts: no + vars: + ansible_python_interpreter: /usr/local/bin/python + + tasks: + - name: Add user account.username + community.mysql.mysql_user: + login_user: "{{ jms_account.username }}" + login_password: "{{ jms_account.secret }}" + login_host: "{{ jms_asset.address }}" + login_port: "{{ jms_asset.port }}" + name: "{{ account.username }}" + password: "{{ account.secret }}" + host: "%" diff --git a/apps/assets/automations/push_account/database/mysql/manifest.yml b/apps/assets/automations/push_account/database/mysql/manifest.yml new file mode 100644 index 000000000..d954cb1d8 --- /dev/null +++ b/apps/assets/automations/push_account/database/mysql/manifest.yml @@ -0,0 +1,6 @@ +id: push_account_mysql +name: Push account from MySQL +category: database +type: + - mysql +method: push_account diff --git a/apps/assets/automations/push_account/database/postgresql/main.yml b/apps/assets/automations/push_account/database/postgresql/main.yml new file mode 100644 index 000000000..72fbc5e83 --- /dev/null +++ b/apps/assets/automations/push_account/database/postgresql/main.yml @@ -0,0 +1,16 @@ +- hosts: postgresql + gather_facts: no + vars: + ansible_python_interpreter: /usr/local/bin/python + + tasks: + - name: Add user account.username + 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.category_property.db_name }}" + name: "{{ account.username }}" + password: "{{ account.secret }}" + diff --git a/apps/assets/automations/push_account/database/postgresql/manifest.yml b/apps/assets/automations/push_account/database/postgresql/manifest.yml new file mode 100644 index 000000000..6488ddd5a --- /dev/null +++ b/apps/assets/automations/push_account/database/postgresql/manifest.yml @@ -0,0 +1,6 @@ +id: push_account_postgresql +name: Push account for PostgreSQL +category: database +type: + - postgresql +method: push_account diff --git a/apps/assets/automations/push_account/host/posix/main.yml b/apps/assets/automations/push_account/host/posix/main.yml new file mode 100644 index 000000000..afe13b226 --- /dev/null +++ b/apps/assets/automations/push_account/host/posix/main.yml @@ -0,0 +1,19 @@ +- hosts: demo + gather_facts: no + tasks: + - name: Add user account.username + ansible.builtin.user: + name: "{{ account.username }}" + + - name: Set account.username password + ansible.builtin.user: + name: "{{ account.username }}" + password: "{{ account.secret | password_hash('sha512') }}" + update_password: always + when: secret_type == "password" + + - name: Set account.username SSH key + ansible.builtin.authorized_key: + user: "{{ account.username }}" + key: "{{ account.secret }}" + when: secret_type == "ssh_key" diff --git a/apps/assets/automations/push_account/host/posix/manifest.yml b/apps/assets/automations/push_account/host/posix/manifest.yml new file mode 100644 index 000000000..9a7cc5c8c --- /dev/null +++ b/apps/assets/automations/push_account/host/posix/manifest.yml @@ -0,0 +1,7 @@ +id: push_account_posix +name: Push posix account +category: host +type: + - linux + - unix +method: push_account diff --git a/apps/assets/automations/push_account/host/windows/main.yml b/apps/assets/automations/push_account/host/windows/main.yml new file mode 100644 index 000000000..bbe8219d0 --- /dev/null +++ b/apps/assets/automations/push_account/host/windows/main.yml @@ -0,0 +1,13 @@ +- hosts: windows + gather_facts: yes + tasks: + - name: Add user account.username + ansible.windows.win_user: + vars: + fullname: "{{ account.username }}" + name: "{{ account.username }}" + password: "{{ account.secret }}" + state: present + password_expired: no + update_password: always + password_never_expires: yes diff --git a/apps/assets/automations/push_account/host/windows/manifest.yml b/apps/assets/automations/push_account/host/windows/manifest.yml new file mode 100644 index 000000000..7e0256f44 --- /dev/null +++ b/apps/assets/automations/push_account/host/windows/manifest.yml @@ -0,0 +1,7 @@ +id: push_account_windows +name: Push account windows +version: 1 +method: push_account +category: host +type: + - windows diff --git a/apps/assets/automations/push_account/manager.py b/apps/assets/automations/push_account/manager.py new file mode 100644 index 000000000..ea5e2193f --- /dev/null +++ b/apps/assets/automations/push_account/manager.py @@ -0,0 +1,17 @@ +from common.utils import get_logger +from assets.const import AutomationTypes +from ..base.manager import BasePlaybookManager, PushOrVerifyHostCallbackMixin + +logger = get_logger(__name__) + + +class PushAccountManager(PushOrVerifyHostCallbackMixin, BasePlaybookManager): + ignore_account = True + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.host_account_mapper = {} + + @classmethod + def method_type(cls): + return AutomationTypes.push_account diff --git a/apps/assets/automations/verify_account/__init__.py b/apps/assets/automations/verify_account/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/assets/automations/verify_account/database/mysql/main.yml b/apps/assets/automations/verify_account/database/mysql/main.yml new file mode 100644 index 000000000..59c13d98a --- /dev/null +++ b/apps/assets/automations/verify_account/database/mysql/main.yml @@ -0,0 +1,13 @@ +- hosts: mysql + gather_facts: no + vars: + ansible_python_interpreter: /usr/local/bin/python + + tasks: + - name: Verify account + community.mysql.mysql_info: + login_user: "{{ account.username }}" + login_password: "{{ account.secret }}" + login_host: "{{ jms_asset.address }}" + login_port: "{{ jms_asset.port }}" + filter: version diff --git a/apps/assets/automations/verify_account/database/mysql/manifest.yml b/apps/assets/automations/verify_account/database/mysql/manifest.yml new file mode 100644 index 000000000..a20b5c7d7 --- /dev/null +++ b/apps/assets/automations/verify_account/database/mysql/manifest.yml @@ -0,0 +1,6 @@ +id: verify_account_mysql +name: Verify account from MySQL +category: database +type: + - mysql +method: verify_account diff --git a/apps/assets/automations/verify_account/database/postgresql/main.yml b/apps/assets/automations/verify_account/database/postgresql/main.yml new file mode 100644 index 000000000..c70364767 --- /dev/null +++ b/apps/assets/automations/verify_account/database/postgresql/main.yml @@ -0,0 +1,13 @@ +- hosts: postgresql + gather_facts: no + vars: + ansible_python_interpreter: /usr/local/bin/python + + tasks: + - name: Verify account + community.postgresql.postgresql_ping: + login_user: "{{ account.username }}" + login_password: "{{ account.secret }}" + login_host: "{{ jms_asset.address }}" + login_port: "{{ jms_asset.port }}" + db: "{{ jms_asset.category_property.db_name }}" diff --git a/apps/assets/automations/verify_account/database/postgresql/manifest.yml b/apps/assets/automations/verify_account/database/postgresql/manifest.yml new file mode 100644 index 000000000..4c9e2cbec --- /dev/null +++ b/apps/assets/automations/verify_account/database/postgresql/manifest.yml @@ -0,0 +1,6 @@ +id: verify_account_postgresql +name: Verify account for PostgreSQL +category: database +type: + - postgresql +method: verify_account diff --git a/apps/assets/automations/verify_account/host/posix/main.yml b/apps/assets/automations/verify_account/host/posix/main.yml new file mode 100644 index 000000000..41ae1768d --- /dev/null +++ b/apps/assets/automations/verify_account/host/posix/main.yml @@ -0,0 +1,11 @@ +- hosts: demo + gather_facts: no + tasks: + - name: Verify account + ansible.builtin.ping: + become: no + vars: + ansible_user: "{{ account.username }}" + ansible_password: "{{ account.secret }}" + ansible_ssh_private_key_file: "{{ account.private_key_path }}" + ansible_become: no diff --git a/apps/assets/automations/verify_account/host/posix/manifest.yml b/apps/assets/automations/verify_account/host/posix/manifest.yml new file mode 100644 index 000000000..5b9a1e51b --- /dev/null +++ b/apps/assets/automations/verify_account/host/posix/manifest.yml @@ -0,0 +1,7 @@ +id: verify_account_posix +name: Verify posix account +category: host +type: + - linux + - unix +method: verify_account diff --git a/apps/assets/automations/verify_account/host/windows/main.yml b/apps/assets/automations/verify_account/host/windows/main.yml new file mode 100644 index 000000000..da9d40a74 --- /dev/null +++ b/apps/assets/automations/verify_account/host/windows/main.yml @@ -0,0 +1,8 @@ +- hosts: windows + gather_facts: yes + tasks: + - name: Verify account + ansible.windows.win_ping: + vars: + ansible_user: "{{ account.username }}" + ansible_password: "{{ account.secret }}" diff --git a/apps/assets/automations/verify_account/host/windows/manifest.yml b/apps/assets/automations/verify_account/host/windows/manifest.yml new file mode 100644 index 000000000..69faf4217 --- /dev/null +++ b/apps/assets/automations/verify_account/host/windows/manifest.yml @@ -0,0 +1,7 @@ +id: verify_account_windows +name: Verify account windows +version: 1 +method: verify_account +category: host +type: + - windows diff --git a/apps/assets/automations/verify_account/manager.py b/apps/assets/automations/verify_account/manager.py new file mode 100644 index 000000000..5445511ba --- /dev/null +++ b/apps/assets/automations/verify_account/manager.py @@ -0,0 +1,25 @@ +from common.utils import get_logger +from assets.const import AutomationTypes, Connectivity +from ..base.manager import BasePlaybookManager, PushOrVerifyHostCallbackMixin + +logger = get_logger(__name__) + + +class VerifyAccountManager(PushOrVerifyHostCallbackMixin, BasePlaybookManager): + ignore_account = False + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.host_account_mapper = {} + + @classmethod + def method_type(cls): + return AutomationTypes.verify_account + + def on_host_success(self, host, result): + account = self.host_account_mapper.get(host) + account.set_connectivity(Connectivity.ok) + + def on_host_error(self, host, error, result): + account = self.host_account_mapper.get(host) + account.set_connectivity(Connectivity.failed) diff --git a/apps/assets/models/automations/__init__.py b/apps/assets/models/automations/__init__.py index 1c62bbddd..5c2a3e031 100644 --- a/apps/assets/models/automations/__init__.py +++ b/apps/assets/models/automations/__init__.py @@ -1,6 +1,6 @@ from .change_secret import * from .discovery_account import * from .push_account import * -from .verify_secret import * from .gather_facts import * from .gather_accounts import * +from .verify_account import * diff --git a/apps/assets/models/automations/change_secret.py b/apps/assets/models/automations/change_secret.py index ef20e27b0..53ca08aba 100644 --- a/apps/assets/models/automations/change_secret.py +++ b/apps/assets/models/automations/change_secret.py @@ -2,7 +2,6 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ from common.db import fields -from common.const.choices import Trigger from common.db.models import JMSBaseModel from assets.const import AutomationTypes, SecretType, SecretStrategy, SSHKeyStrategy from .base import BaseAutomation diff --git a/apps/assets/models/automations/push_account.py b/apps/assets/models/automations/push_account.py index c36d89b43..b1da1966f 100644 --- a/apps/assets/models/automations/push_account.py +++ b/apps/assets/models/automations/push_account.py @@ -1,15 +1,16 @@ from django.utils.translation import ugettext_lazy as _ +from assets.const import AutomationTypes from .base import BaseAutomation +__all__ = ['PushAccountAutomation'] + class PushAccountAutomation(BaseAutomation): - class Meta: - verbose_name = _("Push automation") - def to_attr_json(self): - attr_json = super().to_attr_json() - attr_json.update({ - 'type': 'push_account' - }) - return attr_json + def save(self, *args, **kwargs): + self.type = AutomationTypes.verify_account + super().save(*args, **kwargs) + + class Meta: + verbose_name = _("Push asset account") diff --git a/apps/assets/models/automations/verify_secret.py b/apps/assets/models/automations/verify_account.py similarity index 56% rename from apps/assets/models/automations/verify_secret.py rename to apps/assets/models/automations/verify_account.py index 62326c8bb..cf7004820 100644 --- a/apps/assets/models/automations/verify_secret.py +++ b/apps/assets/models/automations/verify_account.py @@ -1,12 +1,15 @@ from django.utils.translation import ugettext_lazy as _ +from assets.const import AutomationTypes from .base import BaseAutomation +__all__ = ['VerifyAccountAutomation'] + class VerifyAccountAutomation(BaseAutomation): - class Meta: - verbose_name = _("Verify account automation") - def save(self, *args, **kwargs): - self.type = 'verify_account' + self.type = AutomationTypes.verify_account super().save(*args, **kwargs) + + class Meta: + verbose_name = _("Verify asset account") diff --git a/apps/ops/ansible/callback.py b/apps/ops/ansible/callback.py index 344605a18..c613d5080 100644 --- a/apps/ops/ansible/callback.py +++ b/apps/ops/ansible/callback.py @@ -49,7 +49,7 @@ class DefaultCallback: } self.result['ok'][host][task] = detail - def runer_on_failed(self, event_data, host=None, task=None, res=None, **kwargs): + def runner_on_failed(self, event_data, host=None, task=None, res=None, **kwargs): detail = { 'action': event_data.get('task_action', ''), 'res': res, diff --git a/apps/ops/ansible/inventory.py b/apps/ops/ansible/inventory.py index 919b0948c..27988c3d0 100644 --- a/apps/ops/ansible/inventory.py +++ b/apps/ops/ansible/inventory.py @@ -9,8 +9,10 @@ __all__ = ['JMSInventory'] class JMSInventory: - def __init__(self, manager, assets=None, account_policy='smart', - account_prefer='root,administrator', host_callback=None): + def __init__( + self, assets=None, account_policy='smart', + account_prefer='root,administrator', host_callback=None + ): """ :param assets: :param account_prefer: account username name if not set use account_policy @@ -79,10 +81,7 @@ class JMSInventory: ssh_protocol_matched = list(filter(lambda x: x.name == 'ssh', protocols)) ssh_protocol = ssh_protocol_matched[0] if ssh_protocol_matched else None host['ansible_host'] = asset.address - if asset.port == 0: - host['ansible_port'] = ssh_protocol.port if ssh_protocol else 22 - else: - host['ansible_port'] = asset.port + host['ansible_port'] = ssh_protocol.port if ssh_protocol else 22 su_from = account.su_from if platform.su_enabled and su_from: @@ -166,9 +165,9 @@ class JMSInventory: platform_assets = self.group_by_platform(self.assets) for platform, assets in platform_assets.items(): automation = platform.automation - protocols = platform.protocols.all() for asset in assets: + protocols = asset.protocols.all() account = self.select_account(asset) host = self.asset_to_host(asset, account, automation, protocols, platform)