perf: 修改改密

pull/8970/head
ibuler 2022-10-09 20:54:11 +08:00 committed by 老广
parent f921f12171
commit 4e5a7a0a25
83 changed files with 413 additions and 652 deletions

View File

@ -0,0 +1 @@
from .methods import platform_automation_methods

View File

@ -0,0 +1,14 @@
## all connection vars
hostname asset_name=name asset_type=type asset_primary_protocol=ssh asset_primary_port=22 asset_protocols=[]
## local connection
hostname ansible_connection=local
## local connection with gateway
hostname ansible_connection=ssh ansible_user=gateway.username ansible_port=gateway.port ansible_host=gateway.host ansible_ssh_private_key_file=gateway.key
## ssh connection for windows
hostname ansible_connection=ssh ansible_shell_type=powershell/cmd ansible_user=windows.username ansible_port=windows.port ansible_host=windows.host ansible_ssh_private_key_file=windows.key
## ssh connection
hostname ansible_user=user ansible_password=pass ansible_host=host ansible_port=port ansible_ssh_private_key_file=key ssh_args="-o StrictHostKeyChecking=no"

View File

@ -0,0 +1,70 @@
import os
from django.conf import settings
from django.utils import timezone
from ops.ansible import JMSInventory
class BasePlaybookManager:
ansible_account_policy = 'privileged_first'
def __init__(self, execution):
self.execution = execution
self.automation = execution.automation
def get_grouped_assets(self):
return self.automation.all_assets_group_by_platform()
@property
def playbook_dir_path(self):
ansible_dir = settings.ANSIBLE_DIR
path = os.path.join(
ansible_dir, self.automation.type, self.automation.name,
timezone.now().strftime('%Y%m%d_%H%M%S')
)
return path
@property
def inventory_path(self):
return os.path.join(self.playbook_dir_path, 'inventory', 'hosts.json')
@property
def playbook_path(self):
return os.path.join(self.playbook_dir_path, 'project', 'main.yml')
def generate(self):
self.prepare_playbook_dir()
self.generate_inventory()
self.generate_playbook()
def prepare_playbook_dir(self):
inventory_dir = os.path.dirname(self.inventory_path)
playbook_dir = os.path.dirname(self.playbook_path)
for d in [inventory_dir, playbook_dir]:
if not os.path.exists(d):
os.makedirs(d, exist_ok=True, mode=0o755)
def inventory_kwargs(self):
raise NotImplemented
def generate_inventory(self):
inventory = JMSInventory(
assets=self.automation.get_all_assets(),
account_policy=self.ansible_account_policy,
**self.inventory_kwargs()
)
inventory.write_to_file(self.inventory_path)
print("Generate inventory done: {}".format(self.inventory_path))
def generate_playbook(self):
raise NotImplemented
def get_runner(self):
raise NotImplemented
def run(self, **kwargs):
self.generate()
runner = self.get_runner()
return runner.run(**kwargs)

View File

@ -0,0 +1,29 @@
- hosts: demo
tasks:
- name: ping
ping:
#- name: print variables
# debug:
# msg: "Username: {{ account.username }}, Password: {{ account.password }}"
- name: Change password
user:
name: "{{ account.username }}"
password: "{{ account.password | password_hash('des') }}"
update_password: always
when: account.password
- name: Change public key
authorized_key:
user: "{{ account.username }}"
key: "{{ account.public_key }}"
state: present
when: account.public_key
- name: Verify password
ping:
vars:
ansible_user: "{{ account.username }}"
ansible_pass: "{{ account.password }}"
ansible_ssh_connection: paramiko

View File

@ -0,0 +1,29 @@
- hosts: demo
tasks:
- name: ping
ping:
#- name: print variables
# debug:
# msg: "Username: {{ account.username }}, Password: {{ account.password }}"
- name: Change password
user:
name: "{{ account.username }}"
password: "{{ account.password | password_hash('des') }}"
update_password: always
when: account.password
- name: Change public key
authorized_key:
user: "{{ account.username }}"
key: "{{ account.public_key }}"
state: present
when: account.public_key
- name: Verify password
ping:
vars:
ansible_user: "{{ account.username }}"
ansible_pass: "{{ account.password }}"
ansible_ssh_connection: paramiko

View File

@ -0,0 +1,2 @@
# all base inventory in base/base_inventory.txt
asset_name(ip)_account_username account={"username": "", "password": "xxx"} ...base_inventory_vars

View File

@ -0,0 +1,29 @@
- hosts: demo
tasks:
- name: ping
ping:
#- name: print variables
# debug:
# msg: "Username: {{ account.username }}, Password: {{ account.password }}"
- name: Change password
user:
name: "{{ account.username }}"
password: "{{ account.password | password_hash('des') }}"
update_password: always
when: account.password
- name: Change public key
authorized_key:
user: "{{ account.username }}"
key: "{{ account.public_key }}"
state: present
when: account.public_key
- name: Verify password
ping:
vars:
ansible_user: "{{ account.username }}"
ansible_pass: "{{ account.password }}"
ansible_ssh_connection: paramiko

View File

@ -0,0 +1,29 @@
- hosts: demo
tasks:
- name: Test privileged account
ping:
#- name: print variables
# debug:
# msg: "Username: {{ account.username }}, Password: {{ account.password }}"
- name: Change password
user:
name: "{{ account.username }}"
password: "{{ account.password | password_hash('des') }}"
update_password: always
when: account.secret_type == 'password'
- name: Change public key
authorized_key:
user: "{{ account.username }}"
key: "{{ account.public_key }}"
state: present
when: account.public_key
- name: Verify password
ping:
vars:
ansible_user: "{{ account.username }}"
ansible_pass: "{{ account.password }}"
ansible_ssh_connection: paramiko

View File

@ -0,0 +1,29 @@
- hosts: demo
tasks:
- name: ping
ping:
#- name: print variables
# debug:
# msg: "Username: {{ account.username }}, Password: {{ account.password }}"
- name: Change password
user:
name: "{{ account.username }}"
password: "{{ account.password | password_hash('des') }}"
update_password: always
when: account.password
- name: Change public key
authorized_key:
user: "{{ account.username }}"
key: "{{ account.public_key }}"
state: present
when: account.public_key
- name: Verify password
ping:
vars:
ansible_user: "{{ account.username }}"
ansible_pass: "{{ account.password }}"
ansible_ssh_connection: paramiko

View File

@ -0,0 +1,91 @@
import os
import shutil
from copy import deepcopy
from collections import defaultdict
import yaml
from django.utils.translation import gettext as _
from ops.ansible import PlaybookRunner, JMSInventory
from ..base.manager import BasePlaybookManager
from assets.automations.methods import platform_automation_methods
class ChangePasswordManager(BasePlaybookManager):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.id_method_mapper = {
method['id']: method
for method in platform_automation_methods
}
self.method_hosts_mapper = defaultdict(list)
def host_duplicator(self, host, asset=None, account=None, platform=None, **kwargs):
accounts = asset.accounts.all()
if account:
accounts = accounts.exclude(id=account.id)
if '*' not in self.automation.accounts:
accounts = accounts.filter(username__in=self.automation.accounts)
automation = platform.automation
change_password_enabled = automation and \
automation.change_password_enabled and \
automation.change_password_method and \
automation.change_password_method in self.id_method_mapper
if not change_password_enabled:
host.exclude = _('Change password disabled')
return [host]
hosts = []
for account in accounts:
h = deepcopy(host)
h['name'] += '_' + account.username
h['account'] = {
'name': account.name,
'username': account.username,
'secret_type': account.secret_type,
'secret': account.secret,
}
hosts.append(h)
self.method_hosts_mapper[automation.change_password_method].append(h['name'])
return hosts
def inventory_kwargs(self):
return {
'host_duplicator': self.host_duplicator
}
def generate_playbook(self):
playbook = []
for method_id, host_names in self.method_hosts_mapper.items():
method = self.id_method_mapper[method_id]
playbook_dir_path = method['dir']
playbook_dir_name = os.path.dirname(playbook_dir_path)
shutil.copytree(playbook_dir_path, self.playbook_dir_path)
sub_playbook_path = os.path.join(self.playbook_dir_path, playbook_dir_name, 'main.yml')
with open(sub_playbook_path, 'r') as f:
host_playbook_play = yaml.safe_load(f)
plays = []
for name in host_names:
play = deepcopy(host_playbook_play)
play['hosts'] = name
plays.append(play)
with open(sub_playbook_path, 'w') as f:
yaml.safe_dump(plays, f, default_flow_style=False)
playbook.append({
'name': method['name'],
'import_playbook': playbook_dir_name + '/' + 'main.yml'
})
with open(self.playbook_path, 'w') as f:
yaml.safe_dump(playbook, f, default_flow_style=False)
print("Generate playbook done: " + self.playbook_path)

View File

@ -0,0 +1,7 @@
# from .backup.manager import AccountBackupExecutionManager
#
#
class ExecutionManager:
manager_type = {
}

View File

@ -1,5 +1,6 @@
import os
import yaml
import json
from functools import partial
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
@ -62,4 +63,4 @@ platform_automation_methods = get_platform_automation_methods()
if __name__ == '__main__':
print(get_platform_automation_methods())
print(json.dumps(platform_automation_methods, indent=4))

View File

@ -38,7 +38,7 @@ class AllTypes(ChoicesMixin):
@classmethod
def set_automation_methods(cls, category, tp, constraints):
from assets.playbooks import filter_platform_methods
from assets.automations import filter_platform_methods
automation = constraints.get('automation', {})
automation_methods = {}
for item, enabled in automation.items():

View File

@ -10,6 +10,7 @@ from .gathered_user import *
from .favorite_asset import *
from .account import *
from .backup import *
from .automations import *
from ._user import *
# 废弃以下
# from ._authbook import *

View File

@ -4,6 +4,7 @@
import logging
import uuid
from collections import defaultdict
from django.db import models
from django.db.models import Q
@ -41,6 +42,12 @@ class AssetQuerySet(models.QuerySet):
def has_protocol(self, name):
return self.filter(protocols__contains=name)
def group_by_platform(self) -> dict:
groups = defaultdict(list)
for asset in self.all():
groups[asset.platform].append(asset)
return groups
class NodesRelationMixin:
NODES_CACHE_KEY = 'ASSET_NODES_{}'
@ -126,6 +133,22 @@ class Asset(AbsConnectivity, NodesRelationMixin, JMSOrgBaseModel):
names.append(n.name + ':' + n.value)
return names
@lazyproperty
def primary_protocol(self):
return self.protocols.first()
@lazyproperty
def protocol(self):
if not self.primary_protocol:
return 'none'
return self.primary_protocol.name
@lazyproperty
def port(self):
if not self.primary_protocol:
return 0
return self.primary_protocol.port
@property
def protocols_as_list(self):
return [{'name': p.name, 'port': p.port} for p in self.protocols.all()]

View File

@ -1,6 +1,7 @@
from django.utils.translation import ugettext_lazy as _
from ops.const import StrategyChoice
from ops.ansible.runner import PlaybookRunner
from .base import BaseAutomation

View File

@ -8,16 +8,17 @@ from common.db.fields import EncryptJsonDictTextField
from orgs.mixins.models import OrgModelMixin, JMSOrgBaseModel
from ops.mixin import PeriodTaskModelMixin
from ops.tasks import execute_automation_strategy
from ops.task_handlers import ExecutionManager
from assets.models import Node, Asset
from assets.automations.endpoint import ExecutionManager
class BaseAutomation(JMSOrgBaseModel, PeriodTaskModelMixin):
accounts = models.JSONField(default=list, verbose_name=_("Accounts"))
nodes = models.ManyToManyField(
'assets.Node', related_name='automation_strategy', blank=True, verbose_name=_("Nodes")
'assets.Node', blank=True, verbose_name=_("Nodes")
)
assets = models.ManyToManyField(
'assets.Asset', related_name='automation_strategy', blank=True, verbose_name=_("Assets")
'assets.Asset', blank=True, verbose_name=_("Assets")
)
type = models.CharField(max_length=16, verbose_name=_('Type'))
comment = models.TextField(blank=True, verbose_name=_('Comment'))
@ -25,6 +26,17 @@ class BaseAutomation(JMSOrgBaseModel, PeriodTaskModelMixin):
def __str__(self):
return self.name + '@' + str(self.created_by)
def get_all_assets(self):
nodes = self.nodes.all()
node_asset_ids = Node.get_nodes_all_assets(*nodes).values_list('id', flat=True)
direct_asset_ids = self.assets.all().values_list('id', flat=True)
asset_ids = set(list(direct_asset_ids) + list(node_asset_ids))
return Asset.objects.filter(id__in=asset_ids)
def all_assets_group_by_platform(self):
assets = self.get_all_assets().prefetch_related('platform')
return assets.group_by_platform()
def get_register_task(self):
name = "automation_strategy_period_{}".format(str(self.id)[:8])
task = execute_automation_strategy.name
@ -40,13 +52,15 @@ class BaseAutomation(JMSOrgBaseModel, PeriodTaskModelMixin):
'nodes': list(self.assets.all().values_list('id', flat=True)),
}
def execute(self, trigger):
def execute(self, trigger=Trigger.manual):
try:
eid = current_task.request.id
except AttributeError:
eid = str(uuid.uuid4())
execution = AutomationStrategyExecution.objects.create(
id=eid, strategy=self, snapshot=self.to_attr_json(), trigger=trigger
execution = AutomationExecution.objects.create(
id=eid, strategy=self, trigger=trigger,
snapshot=self.to_attr_json(),
)
return execution.start()
@ -55,22 +69,22 @@ class BaseAutomation(JMSOrgBaseModel, PeriodTaskModelMixin):
verbose_name = _("Automation plan")
class AutomationStrategyExecution(OrgModelMixin):
class AutomationExecution(OrgModelMixin):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
date_created = models.DateTimeField(auto_now_add=True)
timedelta = models.FloatField(default=0.0, verbose_name=_('Time'), null=True)
date_start = models.DateTimeField(auto_now_add=True, verbose_name=_('Date start'))
automation = models.ForeignKey(
'BaseAutomation', related_name='executions', on_delete=models.CASCADE,
verbose_name=_('Automation strategy')
)
status = models.CharField(max_length=16, default='pending')
date_created = models.DateTimeField(auto_now_add=True, verbose_name=_('Date created'))
date_start = models.DateTimeField(null=True, verbose_name=_('Date start'), db_index=True)
date_finished = models.DateTimeField(null=True, verbose_name=_("Date finished"))
snapshot = EncryptJsonDictTextField(
default=dict, blank=True, null=True, verbose_name=_('Automation snapshot')
)
strategy = models.ForeignKey(
'BaseAutomation', related_name='execution', on_delete=models.CASCADE,
verbose_name=_('Automation strategy')
)
trigger = models.CharField(
max_length=128, default=Trigger.manual, choices=Trigger.choices, verbose_name=_('Trigger mode')
max_length=128, default=Trigger.manual, choices=Trigger.choices,
verbose_name=_('Trigger mode')
)
class Meta:
@ -83,28 +97,3 @@ class AutomationStrategyExecution(OrgModelMixin):
def start(self):
manager = ExecutionManager(execution=self)
return manager.run()
class AutomationStrategyTask(OrgModelMixin):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
asset = models.ForeignKey(
'assets.Asset', on_delete=models.CASCADE, verbose_name=_('Asset')
)
account = models.ForeignKey(
'assets.Account', on_delete=models.CASCADE, verbose_name=_('Account')
)
is_success = models.BooleanField(default=False, verbose_name=_('Is success'))
timedelta = models.FloatField(default=0.0, null=True, verbose_name=_('Time'))
date_start = models.DateTimeField(auto_now_add=True, verbose_name=_('Date start'))
reason = models.CharField(max_length=1024, blank=True, null=True, verbose_name=_('Reason'))
execution = models.ForeignKey(
'AutomationStrategyExecution', related_name='task', on_delete=models.CASCADE,
verbose_name=_('Automation strategy execution')
)
class Meta:
verbose_name = _('Automation strategy task')
@property
def handler_type(self):
return self.execution.snapshot['type']

View File

@ -2,7 +2,7 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _
from common.db import fields
from ops.const import SSHKeyStrategy, PasswordStrategy, StrategyChoice
from ops.const import PasswordStrategy, StrategyChoice
from ops.utils import generate_random_password
from .base import BaseAutomation

View File

@ -1,33 +0,0 @@
import os
import time
import shutil
from typing import List
from django.conf import settings
from assets.models import Asset
class BaseRunner:
src_filepath: str
def __init__(self, assets: List[Asset], strategy):
self.assets = assets
self.strategy = strategy
self.temp_folder = self.temp_folder_path()
@staticmethod
def temp_folder_path():
project_dir = settings.PROJECT_DIR
tmp_dir = os.path.join(project_dir, 'tmp')
filepath = os.path.join(tmp_dir, str(time.time()))
return filepath
def del_temp_folder(self):
shutil.rmtree(self.temp_folder)
def generate_temp_playbook(self):
src = self.src_filepath
dst = os.path.join(self.temp_folder, self.strategy)
shutil.copytree(src, dst)
return dst

View File

@ -1,47 +0,0 @@
import os
import tempfile
import shutil
from typing import List
from django.conf import settings
from assets.models import Asset
class BasePlaybookGenerator:
def __init__(self, assets: list[Asset], strategy, ansible_connection='ssh'):
self.assets = assets
self.strategy = strategy
self.playbook_dir = self.temp_folder_path()
def generate(self):
self.prepare_playbook_dir()
self.generate_inventory()
self.generate_playbook()
def prepare_playbook_dir(self):
pass
def generate_inventory(self):
pass
def generate_playbook(self):
pass
@property
def base_dir(self):
tmp_dir = os.path.join(settings.PROJECT_DIR, 'tmp')
path = os.path.join(tmp_dir, self.strategy)
return path
def temp_folder_path(self):
return tempfile.mkdtemp(dir=self.base_dir)
def del_temp_folder(self):
shutil.rmtree(self.playbook_dir)
def generate_temp_playbook(self):
src = self.src_filepath
dst = os.path.join(self.temp_folder, self.strategy)
shutil.copytree(src, dst)
return dst

View File

@ -1,10 +0,0 @@
{% for account in accounts %}
- hosts: {{ account.asset.name }}
vars:
account:
username: {{ account.username }}
password: {{ account.password }}
public_key: {{ account.public_key }}
roles:
- change_password
{% endfor %}

View File

@ -1,27 +0,0 @@
- name: ping
ping:
#- name: print variables
# debug:
# msg: "Username: {{ account.username }}, Password: {{ account.password }}"
- name: Change password
user:
name: "{{ account.username }}"
password: "{{ account.password | password_hash('des') }}"
update_password: always
when: account.password
- name: Change public key
authorized_key:
user: "{{ account.username }}"
key: "{{ account.public_key }}"
state: present
when: account.public_key
- name: Verify password
ping:
vars:
ansible_user: "{{ account.username }}"
ansible_pass: "{{ account.password }}"
ansible_ssh_connection: paramiko

View File

@ -1,10 +0,0 @@
{% for account in accounts %}
- hosts: {{ account.asset.name }}
vars:
account:
username: {{ account.username }}
password: {{ account.password }}
public_key: {{ account.public_key }}
roles:
- change_password
{% endfor %}

View File

@ -1,27 +0,0 @@
- name: ping
ping:
#- name: print variables
# debug:
# msg: "Username: {{ account.username }}, Password: {{ account.password }}"
- name: Change password
user:
name: "{{ account.username }}"
password: "{{ account.password | password_hash('des') }}"
update_password: always
when: account.password
- name: Change public key
authorized_key:
user: "{{ account.username }}"
key: "{{ account.public_key }}"
state: present
when: account.public_key
- name: Verify password
ping:
vars:
ansible_user: "{{ account.username }}"
ansible_pass: "{{ account.password }}"
ansible_ssh_connection: paramiko

View File

@ -1,10 +0,0 @@
{% for account in accounts %}
- hosts: {{ account.asset.name }}
vars:
account:
username: {{ account.username }}
password: {{ account.password }}
public_key: {{ account.public_key }}
roles:
- change_password
{% endfor %}

View File

@ -1,27 +0,0 @@
- name: ping
ping:
#- name: print variables
# debug:
# msg: "Username: {{ account.username }}, Password: {{ account.password }}"
- name: Change password
user:
name: "{{ account.username }}"
password: "{{ account.password | password_hash('des') }}"
update_password: always
when: account.password
- name: Change public key
authorized_key:
user: "{{ account.username }}"
key: "{{ account.public_key }}"
state: present
when: account.public_key
- name: Verify password
ping:
vars:
ansible_user: "{{ account.username }}"
ansible_pass: "{{ account.password }}"
ansible_ssh_connection: paramiko

View File

@ -1,8 +0,0 @@
- hosts: all
vars:
account:
username: {{ account.username }}
password: {{ account.password }}
public_key: {{ account.public_key }}
roles:
- change_password

View File

@ -1,23 +0,0 @@
- name: Check connection
ping:
- name: Change password
user:
name: "{{ account.username }}"
password: "{{ account.password | password_hash('sha512') }}"
update_password: always
when: account.password
- name: Change public key
authorized_key:
user: "{{ account.username }}"
key: "{{ account.public_key }}"
state: present
when: account.public_key
- name: Verify password
ping:
vars:
ansible_user: "{{ account.username }}"
ansible_pass: "{{ account.password }}"
ansible_ssh_connection: paramiko

View File

@ -1,10 +0,0 @@
{% for account in accounts %}
- hosts: {{ account.asset.name }}
vars:
account:
username: {{ account.username }}
password: {{ account.password }}
public_key: {{ account.public_key }}
roles:
- change_password
{% endfor %}

View File

@ -1,27 +0,0 @@
- name: ping
ping:
#- name: print variables
# debug:
# msg: "Username: {{ account.username }}, Password: {{ account.password }}"
- name: Change password
user:
name: "{{ account.username }}"
password: "{{ account.password | password_hash('des') }}"
update_password: always
when: account.password
- name: Change public key
authorized_key:
user: "{{ account.username }}"
key: "{{ account.public_key }}"
state: present
when: account.public_key
- name: Verify password
ping:
vars:
ansible_user: "{{ account.username }}"
ansible_pass: "{{ account.password }}"
ansible_ssh_connection: paramiko

View File

@ -1,13 +0,0 @@
- hosts: centos
gather_facts: no
vars:
account:
username: web
password: test123
tasks:
- name: Verify password
ping:
vars:
ansible_user: "{{ account.username }}"
ansible_pass: "{{ account.password }}"

View File

@ -1,10 +0,0 @@
id: ansible_posix_ping
name: Ansible posix ping
description: Ansible ping
category: host
type:
- linux
- unix
- macos
- bsd
method: verify_account

View File

@ -1,13 +0,0 @@
- hosts: centos
gather_facts: no
vars:
account:
username: web
password: test123
tasks:
- name: Verify password
win_ping:
vars:
ansible_user: "{{ account.username }}"
ansible_pass: "{{ account.password }}"

View File

@ -1,6 +0,0 @@
id: ansible_win_ping
name: Ansible win ping
category: host
type:
- windows
method: verify_account

View File

@ -1,12 +0,0 @@
- hosts: all
vars:
connection_type: ssh
password:
value: {{ password }}
public_key:
value: {{ jms_key }}
exclusive: {{ exclusive }}
key_strategy: {{ key_strategy }}
private_key_file: {{ private_key_file }}
roles:
- linux

View File

@ -1,36 +0,0 @@
- name: Check connection
ping:
- name: Change password
user:
name: "{{ item }}"
password: "{{ password.value | password_hash('sha512') }}"
update_password: always
with_items: "{{ usernames }}"
when: "{{ password.value }}"
- name: Change public key
authorized_key:
user: "{{ item }}"
key: "{{ lookup('file', id_rsa.pub) }}"
state: present
exclusive: "{{ public_key.exclusive }}"
with_items: "{{ usernames }}"
when: "{{ public_key.value and key_strategy != 'set_jms' }}"
- name: Change public key
lineinfile:
user: "{{ item }}"
dest: /home/{{ item }}/.ssh/authorized_keys regexp='.*{{ public_key.value }}$
state: absent
with_items: "{{ usernames }}"
when: "{{ public_key.value and key_strategy == 'set_jms' }}"
- name: Verify user
ping:
vars:
ansible_user: "{{ item }}"
ansible_pass: "{{ password.value }}"
ansible_ssh_private_key_file: "{{ private_key_file }}"
ansible_connection: "{{ connection_type | default('ssh') }}"
with_items: "{{ usernames }}"

View File

@ -1,5 +0,0 @@
- hosts: all
vars:
connection_type: ssh
roles:
- linux

View File

@ -1,8 +0,0 @@
- name: Verify user
ping:
vars:
ansible_user: "{{ item.username }}"
ansible_pass: "{{ item.username }}"
ansible_connection: "{{ connection_type | default('ssh') }}"
ansible_ssh_private_key_file: "{{ item.private_key_file }}"
with_items: "{{ account_info }}"

View File

@ -1 +0,0 @@
from .endpoint import *

View File

@ -1,10 +0,0 @@
from .backup.manager import AccountBackupExecutionManager
class ExecutionManager:
manager_type = {
'backup': AccountBackupExecutionManager
}
def __new__(cls, execution):
return AccountBackupExecutionManager(execution)

View File

@ -71,7 +71,7 @@ class DefaultCallback:
def runner_on_start(self, event_data, **kwargs):
pass
def runer_retry(self, event_data, **kwargs):
def runner_retry(self, event_data, **kwargs):
pass
def runner_on_file_diff(self, event_data, **kwargs):

View File

@ -1,7 +1,7 @@
# ~*~ coding: utf-8 ~*~
from collections import defaultdict
import json
import os
from collections import defaultdict
from django.utils.translation import gettext as _
@ -10,7 +10,7 @@ __all__ = ['JMSInventory']
class JMSInventory:
def __init__(self, assets, account='', account_policy='smart', host_var_callback=None):
def __init__(self, assets, account='', account_policy='smart', host_var_callback=None, host_duplicator=None):
"""
:param assets:
:param account: account username name if not set use account_policy
@ -21,6 +21,7 @@ class JMSInventory:
self.account_username = account
self.account_policy = account_policy
self.host_var_callback = host_var_callback
self.host_duplicator = host_duplicator
@staticmethod
def clean_assets(assets):
@ -59,11 +60,16 @@ class JMSInventory:
return {"ansible_ssh_common_args": proxy_command}
def asset_to_host(self, asset, account, automation, protocols):
host = {'name': asset.name, 'vars': {
'asset_id': str(asset.id), 'asset_name': asset.name,
'asset_type': asset.type, 'asset_category': asset.category,
host = {
'name': asset.name,
'asset': {
'id': asset.id, 'name': asset.name, 'ip': asset.ip,
'type': asset.type, 'category': asset.category,
'protocol': asset.protocol, 'port': asset.port,
'protocols': [{'name': p.name, 'port': p.port} for p in protocols],
},
'exclude': ''
}}
}
ansible_connection = automation.ansible_config.get('ansible_connection', 'ssh')
gateway = None
if asset.domain:
@ -91,15 +97,15 @@ class JMSInventory:
elif account.secret_type == 'private_key' and account.secret:
host['ssh_private_key'] = account.private_key_file
else:
host['vars']['exclude'] = _("No account found")
host['exclude'] = _("No account found")
if gateway:
host['vars'].update(self.make_proxy_command(gateway))
host.update(self.make_proxy_command(gateway))
if self.host_var_callback:
callback_var = self.host_var_callback(asset)
if isinstance(callback_var, dict):
host['vars'].update(callback_var)
host.update(callback_var)
return host
def select_account(self, asset):
@ -137,8 +143,11 @@ class JMSInventory:
account = self.select_account(asset)
host = self.asset_to_host(asset, account, automation, protocols)
if not automation.ansible_enabled:
host['vars']['exclude'] = _('Ansible disabled')
hosts.append(host)
host['exclude'] = _('Ansible disabled')
if self.host_duplicator:
hosts.extend(self.host_duplicator(host, asset=asset, account=account, platform=platform))
else:
hosts.append(host)
exclude_hosts = list(filter(lambda x: x.get('exclude'), hosts))
if exclude_hosts:
@ -150,8 +159,6 @@ class JMSInventory:
data = {'all': {'hosts': {}}}
for host in hosts:
name = host.pop('name')
var = host.pop('vars', {})
host.update(var)
data['all']['hosts'][name] = host
return data

View File

@ -52,7 +52,7 @@ class BaseAnsibleExecution(models.Model):
creator = models.ForeignKey('users.User', verbose_name=_("Creator"), on_delete=models.SET_NULL, null=True)
date_created = models.DateTimeField(auto_now_add=True, verbose_name=_('Date created'))
date_start = models.DateTimeField(null=True, verbose_name=_('Date start'), db_index=True)
date_finished = models.DateTimeField(null=True)
date_finished = models.DateTimeField(null=True, verbose_name=_("Date finished"))
class Meta:
abstract = True

View File

@ -1 +0,0 @@
from .endpoint import *

View File

@ -1,2 +0,0 @@
from .manager import *
from .handlers import *

View File

@ -1,16 +0,0 @@
"""
执行改密计划的基类
"""
from common.utils import get_logger
logger = get_logger(__file__)
class BaseHandler:
def __init__(self, task, show_step_info=True):
self.task = task
self.conn = None
self.retry_times = 3
self.current_step = 0
self.is_frozen = False # 任务状态冻结标志
self.show_step_info = show_step_info

View File

@ -1,78 +0,0 @@
# -*- coding: utf-8 -*-
#
import time
from openpyxl import Workbook
from django.utils import timezone
from common.utils import get_logger
from common.utils.timezone import local_now_display
logger = get_logger(__file__)
class BaseExecutionManager:
task_back_up_serializer: None
def __init__(self, execution):
self.execution = execution
self.date_start = timezone.now()
self.time_start = time.time()
self.date_end = None
self.time_end = None
self.timedelta = 0
self.total_tasks = []
def on_tasks_pre_run(self, tasks):
raise NotImplementedError
def on_per_task_pre_run(self, task, total, index):
raise NotImplementedError
def create_csv_file(self, tasks, file_name):
raise NotImplementedError
def get_handler_cls(self):
raise NotImplemented
def do_run(self):
tasks = self.total_tasks = self.execution.create_plan_tasks()
self.on_tasks_pre_run(tasks)
total = len(tasks)
for index, task in enumerate(tasks, start=1):
self.on_per_task_pre_run(task, total, index)
task.start(show_step_info=False)
def pre_run(self):
self.execution.date_start = self.date_start
self.execution.save()
self.show_execution_steps()
def show_execution_steps(self):
pass
def show_summary(self):
split_line = '#' * 40
summary = self.execution.result_summary
logger.info(f'\n{split_line} 改密计划执行结果汇总 {split_line}')
logger.info(
'\n成功: {succeed}, 失败: {failed}, 总数: {total}\n'
''.format(**summary)
)
def post_run(self):
self.time_end = time.time()
self.date_end = timezone.now()
logger.info('\n\n' + '-' * 80)
logger.info('任务执行结束 {}\n'.format(local_now_display()))
self.timedelta = int(self.time_end - self.time_start)
logger.info('用时: {}s'.format(self.timedelta))
self.execution.timedelta = self.timedelta
self.execution.save()
self.show_summary()
def run(self):
self.pre_run()
self.do_run()
self.post_run()

View File

@ -1,2 +0,0 @@
from .manager import *
from .handlers import *

View File

@ -1,10 +0,0 @@
# -*- coding: utf-8 -*-
#
from common.utils import get_logger
from ..base import BaseHandler
logger = get_logger(__name__)
class ChangeAuthHandler(BaseHandler):
pass

View File

@ -1,12 +0,0 @@
# -*- coding: utf-8 -*-
#
from common.utils import get_logger
from ..base import BaseExecutionManager
from .handlers import ChangeAuthHandler
logger = get_logger(__name__)
class ChangeAuthExecutionManager(BaseExecutionManager):
def get_handler_cls(self):
return ChangeAuthHandler

View File

@ -1,2 +0,0 @@
from .manager import *
from .handlers import *

View File

@ -1,10 +0,0 @@
# -*- coding: utf-8 -*-
#
from common.utils import get_logger
from ..base import BaseHandler
logger = get_logger(__name__)
class CollectHandler(BaseHandler):
pass

View File

@ -1,10 +0,0 @@
# -*- coding: utf-8 -*-
#
from common.utils import get_logger
from ..base import BaseExecutionManager
logger = get_logger(__name__)
class CollectExecutionManager(object):
pass

View File

@ -1,31 +0,0 @@
from ops.const import StrategyChoice
from .push import PushExecutionManager, PushHandler
from .verify import VerifyExecutionManager, VerifyHandler
from .collect import CollectExecutionManager, CollectHandler
from .change_auth import ChangeAuthExecutionManager, ChangeAuthHandler
class ExecutionManager:
manager_type = {
StrategyChoice.push: PushExecutionManager,
StrategyChoice.verify: VerifyExecutionManager,
StrategyChoice.collect: CollectExecutionManager,
StrategyChoice.change_password: ChangeAuthExecutionManager,
}
def __new__(cls, execution):
manager = cls.manager_type[execution.manager_type]
return manager(execution)
class TaskHandler:
handler_type = {
StrategyChoice.push: PushHandler,
StrategyChoice.verify: VerifyHandler,
StrategyChoice.collect: CollectHandler,
StrategyChoice.change_password: ChangeAuthHandler,
}
def __new__(cls, task, show_step_info):
handler = cls.handler_type[task.handler_type]
return handler(task, show_step_info)

View File

@ -1,2 +0,0 @@
from .manager import *
from .handlers import *

View File

@ -1,10 +0,0 @@
# -*- coding: utf-8 -*-
#
from common.utils import get_logger
from ..base import BaseHandler
logger = get_logger(__name__)
class PushHandler(BaseHandler):
pass

View File

@ -1,10 +0,0 @@
# -*- coding: utf-8 -*-
#
from common.utils import get_logger
from ..base import BaseExecutionManager
logger = get_logger(__name__)
class PushExecutionManager(BaseExecutionManager):
pass

View File

@ -1,2 +0,0 @@
from .manager import *
from .handlers import *

View File

@ -1,10 +0,0 @@
# -*- coding: utf-8 -*-
#
from common.utils import get_logger
from ..base import BaseHandler
logger = get_logger(__name__)
class VerifyHandler(BaseHandler):
pass

View File

@ -1,10 +0,0 @@
# -*- coding: utf-8 -*-
#
from common.utils import get_logger
from ..base import BaseExecutionManager
logger = get_logger(__name__)
class VerifyExecutionManager(BaseExecutionManager):
pass

View File

@ -8,7 +8,7 @@ from common.utils import get_logger, get_object_or_none
from orgs.utils import org_aware_func
from jumpserver.const import PROJECT_DIR
from .models import Task, AdHoc
from .models import AdHoc
from .const import DEFAULT_PASSWORD_RULES
logger = get_logger(__file__)