mirror of https://github.com/jumpserver/jumpserver
Merge branch 'v3' of github.com:jumpserver/jumpserver into v3
commit
ef04e6ffcc
|
@ -1 +1,2 @@
|
||||||
|
from .endpoint import ExecutionManager
|
||||||
from .methods import platform_automation_methods, filter_platform_methods
|
from .methods import platform_automation_methods, filter_platform_methods
|
||||||
|
|
|
@ -148,7 +148,7 @@ class BasePlaybookManager:
|
||||||
print(" inventory: {}".format(runner.inventory))
|
print(" inventory: {}".format(runner.inventory))
|
||||||
print(" playbook: {}".format(runner.playbook))
|
print(" playbook: {}".format(runner.playbook))
|
||||||
|
|
||||||
def run(self, **kwargs):
|
def run(self, *args, **kwargs):
|
||||||
runners = self.get_runners()
|
runners = self.get_runners()
|
||||||
if len(runners) > 1:
|
if len(runners) > 1:
|
||||||
print("### 分批次执行开始任务, 总共 {}\n".format(len(runners)))
|
print("### 分批次执行开始任务, 总共 {}\n".format(len(runners)))
|
||||||
|
|
|
@ -6,30 +6,26 @@ from collections import defaultdict
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from common.utils import lazyproperty, gen_key_pair
|
from common.utils import lazyproperty, gen_key_pair
|
||||||
from assets.models import ChangeSecretRecord, SecretStrategy
|
from assets.models import ChangeSecretRecord
|
||||||
|
from assets.const import (
|
||||||
|
AutomationTypes, SecretType, SecretStrategy, DEFAULT_PASSWORD_RULES
|
||||||
|
)
|
||||||
from ..base.manager import BasePlaybookManager
|
from ..base.manager import BasePlaybookManager
|
||||||
|
|
||||||
string_punctuation = '!#$%&()*+,-.:;<=>?@[]^_~'
|
|
||||||
DEFAULT_PASSWORD_LENGTH = 30
|
|
||||||
DEFAULT_PASSWORD_RULES = {
|
|
||||||
'length': DEFAULT_PASSWORD_LENGTH,
|
|
||||||
'symbol_set': string_punctuation
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class ChangeSecretManager(BasePlaybookManager):
|
class ChangeSecretManager(BasePlaybookManager):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.method_hosts_mapper = defaultdict(list)
|
self.method_hosts_mapper = defaultdict(list)
|
||||||
self.password_strategy = self.execution.automation.password_strategy
|
self.secret_strategy = self.execution.plan_snapshot['secret_strategy']
|
||||||
self.ssh_key_strategy = self.execution.automation.ssh_key_strategy
|
self.ssh_key_change_strategy = self.execution.plan_snapshot['ssh_key_change_strategy']
|
||||||
self._password_generated = None
|
self._password_generated = None
|
||||||
self._ssh_key_generated = None
|
self._ssh_key_generated = None
|
||||||
self.name_recorder_mapper = {} # 做个映射,方便后面处理
|
self.name_recorder_mapper = {} # 做个映射,方便后面处理
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def method_type(cls):
|
def method_type(cls):
|
||||||
return 'change_secret'
|
return AutomationTypes.change_secret
|
||||||
|
|
||||||
@lazyproperty
|
@lazyproperty
|
||||||
def related_accounts(self):
|
def related_accounts(self):
|
||||||
|
@ -41,43 +37,52 @@ class ChangeSecretManager(BasePlaybookManager):
|
||||||
return private_key
|
return private_key
|
||||||
|
|
||||||
def generate_password(self):
|
def generate_password(self):
|
||||||
kwargs = self.automation.password_rules or {}
|
kwargs = self.automation.plan_snapshot['password_rules'] or {}
|
||||||
length = int(kwargs.get('length', DEFAULT_PASSWORD_RULES['length']))
|
length = int(kwargs.get('length', DEFAULT_PASSWORD_RULES['length']))
|
||||||
symbol_set = kwargs.get('symbol_set')
|
symbol_set = kwargs.get('symbol_set')
|
||||||
if symbol_set is None:
|
if symbol_set is None:
|
||||||
symbol_set = DEFAULT_PASSWORD_RULES['symbol_set']
|
symbol_set = DEFAULT_PASSWORD_RULES['symbol_set']
|
||||||
chars = string.ascii_letters + string.digits + symbol_set
|
|
||||||
password = ''.join([random.choice(chars) for _ in range(length)])
|
no_special_chars = string.ascii_letters + string.digits
|
||||||
|
chars = no_special_chars + symbol_set
|
||||||
|
|
||||||
|
first_char = random.choice(no_special_chars)
|
||||||
|
password = ''.join([random.choice(chars) for _ in range(length - 1)])
|
||||||
|
password = first_char + password
|
||||||
return password
|
return password
|
||||||
|
|
||||||
def get_ssh_key(self):
|
def get_ssh_key(self):
|
||||||
if self.ssh_key_strategy == SecretStrategy.custom:
|
if self.secret_strategy == SecretStrategy.custom:
|
||||||
return self.automation.ssh_key
|
ssh_key = self.automation.plan_snapshot['ssh_key']
|
||||||
elif self.ssh_key_strategy == SecretStrategy.random_one:
|
if not ssh_key:
|
||||||
|
raise ValueError("Automation SSH key must be set")
|
||||||
|
return ssh_key
|
||||||
|
elif self.secret_strategy == SecretStrategy.random_one:
|
||||||
if not self._ssh_key_generated:
|
if not self._ssh_key_generated:
|
||||||
self._ssh_key_generated = self.generate_ssh_key()
|
self._ssh_key_generated = self.generate_ssh_key()
|
||||||
return self._ssh_key_generated
|
return self._ssh_key_generated
|
||||||
else:
|
else:
|
||||||
self.generate_ssh_key()
|
return self.generate_ssh_key()
|
||||||
|
|
||||||
def get_password(self):
|
def get_password(self):
|
||||||
if self.password_strategy == SecretStrategy.custom:
|
if self.secret_strategy == SecretStrategy.custom:
|
||||||
if not self.automation.password:
|
password = self.automation.plan_snapshot['password']
|
||||||
|
if not password:
|
||||||
raise ValueError("Automation Password must be set")
|
raise ValueError("Automation Password must be set")
|
||||||
return self.automation.password
|
return password
|
||||||
elif self.password_strategy == SecretStrategy.random_one:
|
elif self.secret_strategy == SecretStrategy.random_one:
|
||||||
if not self._password_generated:
|
if not self._password_generated:
|
||||||
self._password_generated = self.generate_password()
|
self._password_generated = self.generate_password()
|
||||||
return self._password_generated
|
return self._password_generated
|
||||||
else:
|
else:
|
||||||
self.generate_password()
|
return self.generate_password()
|
||||||
|
|
||||||
def get_secret(self, account):
|
def get_secret(self, account):
|
||||||
if account.secret_type == 'ssh-key':
|
if account.secret_type == SecretType.ssh_key:
|
||||||
secret = self.get_ssh_key()
|
secret = self.get_ssh_key()
|
||||||
else:
|
elif account.secret_type == SecretType.password:
|
||||||
secret = self.get_password()
|
secret = self.get_password()
|
||||||
if not secret:
|
else:
|
||||||
raise ValueError("Secret must be set")
|
raise ValueError("Secret must be set")
|
||||||
return secret
|
return secret
|
||||||
|
|
||||||
|
@ -145,5 +150,3 @@ class ChangeSecretManager(BasePlaybookManager):
|
||||||
|
|
||||||
def on_runner_failed(self, runner, e):
|
def on_runner_failed(self, runner, e):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,18 +3,19 @@
|
||||||
#
|
#
|
||||||
from .change_secret.manager import ChangeSecretManager
|
from .change_secret.manager import ChangeSecretManager
|
||||||
from .gather_facts.manager import GatherFactsManager
|
from .gather_facts.manager import GatherFactsManager
|
||||||
|
from ..const import AutomationTypes
|
||||||
|
|
||||||
|
|
||||||
class ExecutionManager:
|
class ExecutionManager:
|
||||||
manager_type_mapper = {
|
manager_type_mapper = {
|
||||||
'change_secret': ChangeSecretManager,
|
AutomationTypes.change_secret: ChangeSecretManager,
|
||||||
'gather_facts': GatherFactsManager,
|
AutomationTypes.gather_facts: GatherFactsManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, execution):
|
def __init__(self, execution):
|
||||||
self.execution = execution
|
self.execution = execution
|
||||||
self._runner = self.manager_type_mapper[execution.automation.type](execution)
|
self._runner = self.manager_type_mapper[execution.manager_type](execution)
|
||||||
|
|
||||||
def run(self, **kwargs):
|
def run(self, *args, **kwargs):
|
||||||
return self._runner.run(**kwargs)
|
return self._runner.run(*args, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from .types import *
|
||||||
|
from .account import *
|
||||||
from .protocol import *
|
from .protocol import *
|
||||||
from .category import *
|
from .category import *
|
||||||
from .types import *
|
from .automation import *
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
from django.db.models import TextChoices
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
class Connectivity(TextChoices):
|
||||||
|
unknown = 'unknown', _('Unknown')
|
||||||
|
ok = 'ok', _('Ok')
|
||||||
|
failed = 'failed', _('Failed')
|
||||||
|
|
||||||
|
|
||||||
|
class SecretType(TextChoices):
|
||||||
|
password = 'password', _('Password')
|
||||||
|
ssh_key = 'ssh_key', _('SSH key')
|
||||||
|
access_key = 'access_key', _('Access key')
|
||||||
|
token = 'token', _('Token')
|
|
@ -0,0 +1,30 @@
|
||||||
|
from django.db.models import TextChoices
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
string_punctuation = '!#$%&()*+,-.:;<=>?@[]^_~'
|
||||||
|
DEFAULT_PASSWORD_LENGTH = 30
|
||||||
|
DEFAULT_PASSWORD_RULES = {
|
||||||
|
'length': DEFAULT_PASSWORD_LENGTH,
|
||||||
|
'symbol_set': string_punctuation
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class AutomationTypes(TextChoices):
|
||||||
|
ping = 'ping', _('Ping')
|
||||||
|
gather_facts = 'gather_facts', _('Gather facts')
|
||||||
|
push_account = 'push_account', _('Create account')
|
||||||
|
change_secret = 'change_secret', _('Change secret')
|
||||||
|
verify_account = 'verify_account', _('Verify account')
|
||||||
|
gather_account = 'gather_account', _('Gather account')
|
||||||
|
|
||||||
|
|
||||||
|
class SecretStrategy(TextChoices):
|
||||||
|
custom = 'specific', _('Specific')
|
||||||
|
random_one = 'random_one', _('All assets use the same random password')
|
||||||
|
random_all = 'random_all', _('All assets use different random password')
|
||||||
|
|
||||||
|
|
||||||
|
class SSHKeyStrategy(TextChoices):
|
||||||
|
add = 'add', _('Append SSH KEY')
|
||||||
|
set = 'set', _('Empty and append SSH KEY')
|
||||||
|
set_jms = 'set_jms', _('Replace (The key generated by JumpServer) ')
|
|
@ -0,0 +1,75 @@
|
||||||
|
# Generated by Django 3.2.14 on 2022-10-19 09:06
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assets', '0107_auto_20221019_1115'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='automationexecution',
|
||||||
|
options={'verbose_name': 'Automation task execution'},
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='baseautomation',
|
||||||
|
options={'verbose_name': 'Automation task'},
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='changesecretrecord',
|
||||||
|
options={'verbose_name': 'Change secret record'},
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='verifyaccountautomation',
|
||||||
|
options={'verbose_name': 'Verify account automation'},
|
||||||
|
),
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='changesecretautomation',
|
||||||
|
old_name='password',
|
||||||
|
new_name='secret',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='baseautomation',
|
||||||
|
name='updated_by',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='changesecretautomation',
|
||||||
|
name='password_strategy',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='changesecretautomation',
|
||||||
|
name='secret_types',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='changesecretautomation',
|
||||||
|
name='ssh_key',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='changesecretautomation',
|
||||||
|
name='ssh_key_strategy',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='changesecretautomation',
|
||||||
|
name='secret_strategy',
|
||||||
|
field=models.CharField(choices=[('specific', 'Specific'), ('random_one', 'All assets use the same random password'), ('random_all', 'All assets use different random password')], default='random_one', max_length=16, verbose_name='Secret strategy'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='changesecretautomation',
|
||||||
|
name='secret_type',
|
||||||
|
field=models.CharField(choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'), ('token', 'Token')], default='password', max_length=16, verbose_name='Secret type'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='automationexecution',
|
||||||
|
name='automation',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='executions', to='assets.baseautomation', verbose_name='Automation task'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='changesecretautomation',
|
||||||
|
name='ssh_key_change_strategy',
|
||||||
|
field=models.CharField(choices=[('add', 'Append SSH KEY'), ('set', 'Empty and append SSH KEY'), ('set_jms', 'Replace (The key generated by JumpServer) ')], default='add', max_length=16, verbose_name='SSH key change strategy'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,5 +1,4 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from simple_history.models import HistoricalRecords
|
from simple_history.models import HistoricalRecords
|
||||||
|
|
||||||
|
|
|
@ -4,23 +4,14 @@ from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from common.const.choices import Trigger
|
from common.const.choices import Trigger
|
||||||
|
from common.mixins.models import CommonModelMixin
|
||||||
from common.db.fields import EncryptJsonDictTextField
|
from common.db.fields import EncryptJsonDictTextField
|
||||||
from orgs.mixins.models import OrgModelMixin, JMSOrgBaseModel
|
from orgs.mixins.models import OrgModelMixin
|
||||||
from ops.mixin import PeriodTaskModelMixin
|
from ops.mixin import PeriodTaskModelMixin
|
||||||
from ops.tasks import execute_automation_strategy
|
|
||||||
from assets.models import Node, Asset
|
from assets.models import Node, Asset
|
||||||
|
|
||||||
|
|
||||||
class AutomationTypes(models.TextChoices):
|
class BaseAutomation(CommonModelMixin, PeriodTaskModelMixin, OrgModelMixin):
|
||||||
ping = 'ping', _('Ping')
|
|
||||||
gather_facts = 'gather_facts', _('Gather facts')
|
|
||||||
push_account = 'push_account', _('Create account')
|
|
||||||
change_secret = 'change_secret', _('Change secret')
|
|
||||||
verify_account = 'verify_account', _('Verify account')
|
|
||||||
gather_account = 'gather_account', _('Gather account')
|
|
||||||
|
|
||||||
|
|
||||||
class BaseAutomation(JMSOrgBaseModel, PeriodTaskModelMixin):
|
|
||||||
accounts = models.JSONField(default=list, verbose_name=_("Accounts"))
|
accounts = models.JSONField(default=list, verbose_name=_("Accounts"))
|
||||||
nodes = models.ManyToManyField(
|
nodes = models.ManyToManyField(
|
||||||
'assets.Node', blank=True, verbose_name=_("Nodes")
|
'assets.Node', blank=True, verbose_name=_("Nodes")
|
||||||
|
@ -47,18 +38,17 @@ class BaseAutomation(JMSOrgBaseModel, PeriodTaskModelMixin):
|
||||||
return assets.group_by_platform()
|
return assets.group_by_platform()
|
||||||
|
|
||||||
def get_register_task(self):
|
def get_register_task(self):
|
||||||
name = "automation_strategy_period_{}".format(str(self.id)[:8])
|
raise NotImplementedError
|
||||||
task = execute_automation_strategy.name
|
|
||||||
args = (str(self.id), Trigger.timing)
|
|
||||||
kwargs = {}
|
|
||||||
return name, task, args, kwargs
|
|
||||||
|
|
||||||
def to_attr_json(self):
|
def to_attr_json(self):
|
||||||
return {
|
return {
|
||||||
'name': self.name,
|
'name': self.name,
|
||||||
|
'type': self.type,
|
||||||
|
'org_id': self.org_id,
|
||||||
|
'comment': self.comment,
|
||||||
'accounts': self.accounts,
|
'accounts': self.accounts,
|
||||||
|
'nodes': list(self.nodes.all().values_list('id', flat=True)),
|
||||||
'assets': list(self.assets.all().values_list('id', flat=True)),
|
'assets': list(self.assets.all().values_list('id', flat=True)),
|
||||||
'nodes': list(self.assets.all().values_list('id', flat=True)),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def execute(self, trigger=Trigger.manual):
|
def execute(self, trigger=Trigger.manual):
|
||||||
|
@ -67,8 +57,9 @@ class BaseAutomation(JMSOrgBaseModel, PeriodTaskModelMixin):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
eid = str(uuid.uuid4())
|
eid = str(uuid.uuid4())
|
||||||
|
|
||||||
execution = self.executions.create(
|
execution = self.executions.model.objects.create(
|
||||||
id=eid, trigger=trigger,
|
id=eid, trigger=trigger, automation=self,
|
||||||
|
plan_snapshot=self.to_attr_json(),
|
||||||
)
|
)
|
||||||
return execution.start()
|
return execution.start()
|
||||||
|
|
||||||
|
|
|
@ -2,45 +2,61 @@ from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from common.db import fields
|
from common.db import fields
|
||||||
|
from common.const.choices import Trigger
|
||||||
from common.db.models import JMSBaseModel
|
from common.db.models import JMSBaseModel
|
||||||
|
from assets.tasks import execute_change_secret_automation
|
||||||
|
from assets.const import AutomationTypes, SecretType, SecretStrategy, SSHKeyStrategy
|
||||||
from .base import BaseAutomation
|
from .base import BaseAutomation
|
||||||
|
|
||||||
|
__all__ = ['ChangeSecretAutomation', 'ChangeSecretRecord']
|
||||||
__all__ = ['ChangeSecretAutomation', 'ChangeSecretRecord', 'SecretStrategy']
|
|
||||||
|
|
||||||
|
|
||||||
class SecretStrategy(models.TextChoices):
|
|
||||||
custom = 'specific', _('Specific')
|
|
||||||
random_one = 'random_one', _('All assets use the same random password')
|
|
||||||
random_all = 'random_all', _('All assets use different random password')
|
|
||||||
|
|
||||||
|
|
||||||
class SSHKeyStrategy(models.TextChoices):
|
|
||||||
add = 'add', _('Append SSH KEY')
|
|
||||||
set = 'set', _('Empty and append SSH KEY')
|
|
||||||
set_jms = 'set_jms', _('Replace (The key generated by JumpServer) ')
|
|
||||||
|
|
||||||
|
|
||||||
class ChangeSecretAutomation(BaseAutomation):
|
class ChangeSecretAutomation(BaseAutomation):
|
||||||
secret_types = models.JSONField(default=list, verbose_name=_('Secret types'))
|
secret_type = models.CharField(
|
||||||
password_strategy = models.CharField(choices=SecretStrategy.choices, max_length=16,
|
choices=SecretType.choices, max_length=16,
|
||||||
default=SecretStrategy.random_one, verbose_name=_('Password strategy'))
|
default=SecretType.password, verbose_name=_('Secret type')
|
||||||
password = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Secret'))
|
)
|
||||||
|
secret_strategy = models.CharField(
|
||||||
|
choices=SecretStrategy.choices, max_length=16,
|
||||||
|
default=SecretStrategy.random_one, verbose_name=_('Secret strategy')
|
||||||
|
)
|
||||||
|
secret = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Secret'))
|
||||||
password_rules = models.JSONField(default=dict, verbose_name=_('Password rules'))
|
password_rules = models.JSONField(default=dict, verbose_name=_('Password rules'))
|
||||||
|
ssh_key_change_strategy = models.CharField(
|
||||||
ssh_key_strategy = models.CharField(choices=SecretStrategy.choices, default=SecretStrategy.random_one, max_length=16)
|
choices=SSHKeyStrategy.choices, max_length=16,
|
||||||
ssh_key = fields.EncryptTextField(blank=True, null=True, verbose_name=_('SSH key'))
|
default=SSHKeyStrategy.add, verbose_name=_('SSH key change strategy')
|
||||||
ssh_key_change_strategy = models.CharField(choices=SSHKeyStrategy.choices, max_length=16,
|
)
|
||||||
default=SSHKeyStrategy.add, verbose_name=_('SSH key strategy'))
|
|
||||||
recipients = models.ManyToManyField('users.User', blank=True, verbose_name=_("Recipient"))
|
recipients = models.ManyToManyField('users.User', blank=True, verbose_name=_("Recipient"))
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
self.type = 'change_secret'
|
self.type = AutomationTypes.change_secret
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Change secret automation")
|
verbose_name = _("Change secret automation")
|
||||||
|
|
||||||
|
def get_register_task(self):
|
||||||
|
name = "automation_change_secret_strategy_period_{}".format(str(self.id)[:8])
|
||||||
|
task = execute_change_secret_automation.name
|
||||||
|
args = (str(self.id), Trigger.timing)
|
||||||
|
kwargs = {}
|
||||||
|
return name, task, args, kwargs
|
||||||
|
|
||||||
|
def to_attr_json(self):
|
||||||
|
attr_json = super().to_attr_json()
|
||||||
|
attr_json.update({
|
||||||
|
'secret': self.secret,
|
||||||
|
'secret_type': self.secret_type,
|
||||||
|
'secret_strategy': self.secret_strategy,
|
||||||
|
'password_rules': self.password_rules,
|
||||||
|
'ssh_key_change_strategy': self.ssh_key_change_strategy,
|
||||||
|
'recipients': {
|
||||||
|
str(recipient.id): (str(recipient), bool(recipient.secret_key))
|
||||||
|
for recipient in self.recipients.all()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return attr_json
|
||||||
|
|
||||||
|
|
||||||
class ChangeSecretRecord(JMSBaseModel):
|
class ChangeSecretRecord(JMSBaseModel):
|
||||||
execution = models.ForeignKey('assets.AutomationExecution', on_delete=models.CASCADE)
|
execution = models.ForeignKey('assets.AutomationExecution', on_delete=models.CASCADE)
|
||||||
|
@ -53,7 +69,7 @@ class ChangeSecretRecord(JMSBaseModel):
|
||||||
error = models.TextField(blank=True, null=True, verbose_name=_('Error'))
|
error = models.TextField(blank=True, null=True, verbose_name=_('Error'))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Change secret")
|
verbose_name = _("Change secret record")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.account.__str__()
|
return self.account.__str__()
|
||||||
|
|
|
@ -18,18 +18,12 @@ from common.utils import (
|
||||||
random_string, ssh_pubkey_gen,
|
random_string, ssh_pubkey_gen,
|
||||||
)
|
)
|
||||||
from common.db import fields
|
from common.db import fields
|
||||||
|
from assets.const import Connectivity
|
||||||
from orgs.mixins.models import OrgModelMixin
|
from orgs.mixins.models import OrgModelMixin
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
|
||||||
|
|
||||||
class Connectivity(models.TextChoices):
|
|
||||||
unknown = 'unknown', _('Unknown')
|
|
||||||
ok = 'ok', _('Ok')
|
|
||||||
failed = 'failed', _('Failed')
|
|
||||||
|
|
||||||
|
|
||||||
class AbsConnectivity(models.Model):
|
class AbsConnectivity(models.Model):
|
||||||
connectivity = models.CharField(
|
connectivity = models.CharField(
|
||||||
choices=Connectivity.choices, default=Connectivity.unknown,
|
choices=Connectivity.choices, default=Connectivity.unknown,
|
||||||
|
@ -64,7 +58,9 @@ class BaseAccount(OrgModelMixin):
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
name = models.CharField(max_length=128, verbose_name=_("Name"))
|
name = models.CharField(max_length=128, verbose_name=_("Name"))
|
||||||
username = models.CharField(max_length=128, blank=True, verbose_name=_('Username'), db_index=True)
|
username = models.CharField(max_length=128, blank=True, verbose_name=_('Username'), db_index=True)
|
||||||
secret_type = models.CharField(max_length=16, choices=SecretType.choices, default='password', verbose_name=_('Secret type'))
|
secret_type = models.CharField(
|
||||||
|
max_length=16, choices=SecretType.choices, default=SecretType.password, verbose_name=_('Secret type')
|
||||||
|
)
|
||||||
secret = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Secret'))
|
secret = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Secret'))
|
||||||
privileged = models.BooleanField(verbose_name=_("Privileged"), default=False)
|
privileged = models.BooleanField(verbose_name=_("Privileged"), default=False)
|
||||||
comment = models.TextField(blank=True, verbose_name=_('Comment'))
|
comment = models.TextField(blank=True, verbose_name=_('Comment'))
|
||||||
|
@ -165,10 +161,7 @@ class BaseAccount(OrgModelMixin):
|
||||||
'username': self.username,
|
'username': self.username,
|
||||||
'password': self.password,
|
'password': self.password,
|
||||||
'public_key': self.public_key,
|
'public_key': self.public_key,
|
||||||
'private_key': self.private_key_file,
|
|
||||||
'token': self.token
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
|
|
||||||
from .utils import *
|
from .utils import *
|
||||||
from .common import *
|
from .common import *
|
||||||
|
from .backup import *
|
||||||
|
from .automation import *
|
||||||
|
from .nodes_amount import *
|
||||||
|
from .gather_asset_users import *
|
||||||
from .asset_connectivity import *
|
from .asset_connectivity import *
|
||||||
from .account_connectivity import *
|
from .account_connectivity import *
|
||||||
from .gather_asset_users import *
|
|
||||||
from .gather_asset_hardware_info import *
|
from .gather_asset_hardware_info import *
|
||||||
from .nodes_amount import *
|
|
||||||
from .backup import *
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
from celery import shared_task
|
||||||
|
|
||||||
|
from orgs.utils import tmp_to_root_org, tmp_to_org
|
||||||
|
from common.utils import get_logger, get_object_or_none
|
||||||
|
|
||||||
|
logger = get_logger(__file__)
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task
|
||||||
|
def execute_change_secret_automation(pid, trigger):
|
||||||
|
from assets.models import ChangeSecretAutomation
|
||||||
|
with tmp_to_root_org():
|
||||||
|
instance = get_object_or_none(ChangeSecretAutomation, pk=pid)
|
||||||
|
if not instance:
|
||||||
|
logger.error("No automation plan found: {}".format(pid))
|
||||||
|
return
|
||||||
|
with tmp_to_org(instance.org):
|
||||||
|
instance.execute(trigger)
|
|
@ -126,8 +126,8 @@ class NodeAssetsUtil:
|
||||||
from assets.models import Node, Asset
|
from assets.models import Node, Asset
|
||||||
|
|
||||||
nodes = list(Node.objects.all())
|
nodes = list(Node.objects.all())
|
||||||
nodes_assets = Asset.nodes.through.objects.all()\
|
nodes_assets = Asset.nodes.through.objects.all() \
|
||||||
.annotate(aid=output_as_string('asset_id'))\
|
.annotate(aid=output_as_string('asset_id')) \
|
||||||
.values_list('node__key', 'aid')
|
.values_list('node__key', 'aid')
|
||||||
|
|
||||||
mapping = defaultdict(set)
|
mapping = defaultdict(set)
|
||||||
|
|
|
@ -71,7 +71,7 @@ class PeriodTaskModelMixin(models.Model):
|
||||||
}
|
}
|
||||||
create_or_update_celery_periodic_tasks(tasks)
|
create_or_update_celery_periodic_tasks(tasks)
|
||||||
|
|
||||||
def save(self, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
instance = super().save(**kwargs)
|
instance = super().save(**kwargs)
|
||||||
self.set_period_schedule()
|
self.set_period_schedule()
|
||||||
return instance
|
return instance
|
||||||
|
|
Loading…
Reference in New Issue