merge: v3

pull/9248/head
Bai 2022-12-27 17:13:29 +08:00
commit 0328fd1bb0
13 changed files with 83 additions and 47 deletions

View File

@ -60,6 +60,7 @@ class AssetViewSet(SuggestionMixin, NodeFilterMixin, OrgBulkModelViewSet):
ordering = ("name",)
serializer_classes = (
("default", serializers.AssetSerializer),
("retrieve", serializers.AssetDetailSerializer),
("suggestion", serializers.MiniAssetSerializer),
("platform", serializers.PlatformSerializer),
("gateways", serializers.GatewaySerializer),

View File

@ -25,7 +25,6 @@ class CloudTypes(BaseType):
'gather_facts_enabled': False,
'verify_account_enabled': False,
'change_secret_enabled': False,
'push_account_enabled': False,
'gather_accounts_enabled': False,
}
}

View File

@ -33,7 +33,6 @@ class DatabaseTypes(BaseType):
'gather_accounts_enabled': True,
'verify_account_enabled': True,
'change_secret_enabled': True,
'push_account_enabled': True,
}
}
return constrains

View File

@ -40,7 +40,6 @@ class DeviceTypes(BaseType):
'gather_accounts_enabled': False,
'verify_account_enabled': False,
'change_secret_enabled': False,
'push_account_enabled': False,
}
}

View File

@ -54,7 +54,6 @@ class HostTypes(BaseType):
'gather_accounts_enabled': True,
'verify_account_enabled': True,
'change_secret_enabled': True,
'push_account_enabled': True,
},
cls.WINDOWS: {
'ansible_config': {

View File

@ -1,21 +1,22 @@
# -*- coding: utf-8 -*-
#
from rest_framework import serializers
from django.utils.translation import ugettext_lazy as _
from django.db.transaction import atomic
from django.db.models import F
from django.db.transaction import atomic
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from common.drf.serializers import WritableNestedModelSerializer
from common.drf.fields import LabeledChoiceField, ObjectRelatedField
from common.drf.serializers import WritableNestedModelSerializer
from orgs.mixins.serializers import BulkOrgResourceSerializerMixin
from ..account import AccountSerializer
from ...models import Asset, Node, Platform, Label, Domain, Account, Protocol
from ...const import Category, AllTypes
from ...models import Asset, Node, Platform, Label, Domain, Account, Protocol
__all__ = [
'AssetSerializer', 'AssetSimpleSerializer', 'MiniAssetSerializer',
'AssetTaskSerializer', 'AssetsTaskSerializer', 'AssetProtocolsSerializer',
'AssetDetailSerializer',
]
@ -71,16 +72,16 @@ class AssetSerializer(BulkOrgResourceSerializerMixin, WritableNestedModelSeriali
class Meta:
model = Asset
fields_mini = ['id', 'name', 'address', 'enabled_info']
fields_mini = ['id', 'name', 'address']
fields_small = fields_mini + ['is_active', 'comment']
fields_fk = ['domain', 'platform', 'platform']
fields_m2m = [
'nodes', 'labels', 'protocols', 'accounts', 'nodes_display',
]
read_only_fields = [
'category', 'type', 'specific', 'info',
'connectivity', 'date_verified', 'created_by',
'date_created'
'category', 'type', 'info',
'connectivity', 'date_verified',
'created_by', 'date_created'
]
fields = fields_small + fields_fk + fields_m2m + read_only_fields
extra_kwargs = {
@ -89,36 +90,13 @@ class AssetSerializer(BulkOrgResourceSerializerMixin, WritableNestedModelSeriali
'nodes_display': {'label': _('Node path')},
}
def get_field_names(self, declared_fields, info):
names = super().get_field_names(declared_fields, info)
if self.__class__.__name__ != 'AssetSerializer':
names.remove('specific')
return names
@staticmethod
def get_enabled_info(obj):
platform = obj.platform
automation = platform.automation
return {
'su_enabled': platform.su_enabled,
'ping_enabled': automation.ping_enabled,
'domain_enabled': platform.domain_enabled,
'ansible_enabled': automation.ansible_enabled,
'protocols_enabled': platform.protocols_enabled,
'gather_facts_enabled': automation.gather_facts_enabled,
'push_account_enabled': automation.push_account_enabled,
'change_secret_enabled': automation.change_secret_enabled,
'verify_account_enabled': automation.verify_account_enabled,
'gather_accounts_enabled': automation.gather_accounts_enabled,
}
@classmethod
def setup_eager_loading(cls, queryset):
""" Perform necessary eager loading of data. """
queryset = queryset.prefetch_related('domain', 'platform', 'protocols') \
.annotate(category=F("platform__category")) \
.annotate(type=F("platform__type"))
queryset = queryset.prefetch_related('nodes', 'labels')
queryset = queryset.prefetch_related('nodes', 'labels', 'accounts')
return queryset
def perform_nodes_display_create(self, instance, nodes_display):
@ -189,6 +167,30 @@ class AssetSerializer(BulkOrgResourceSerializerMixin, WritableNestedModelSeriali
return instance
class AssetDetailSerializer(AssetSerializer):
accounts = AssetAccountSerializer(many=True, required=False, label=_('Accounts'))
enabled_info = serializers.SerializerMethodField()
class Meta(AssetSerializer.Meta):
fields = AssetSerializer.Meta.fields + ['accounts', 'enabled_info', 'info', 'specific']
@staticmethod
def get_enabled_info(obj):
platform = obj.platform
automation = platform.automation
return {
'su_enabled': platform.su_enabled,
'ping_enabled': automation.ping_enabled,
'domain_enabled': platform.domain_enabled,
'ansible_enabled': automation.ansible_enabled,
'protocols_enabled': platform.protocols_enabled,
'gather_facts_enabled': automation.gather_facts_enabled,
'change_secret_enabled': automation.change_secret_enabled,
'verify_account_enabled': automation.verify_account_enabled,
'gather_accounts_enabled': automation.gather_accounts_enabled,
}
class MiniAssetSerializer(serializers.ModelSerializer):
class Meta:
model = Asset

View File

@ -56,8 +56,6 @@ class PlatformAutomationSerializer(serializers.ModelSerializer):
"gather_facts_method": {"label": "收集信息方式"},
"verify_account_enabled": {"label": "启用校验账号"},
"verify_account_method": {"label": "校验账号方式"},
"push_account_enabled": {"label": "启用推送账号"},
"push_account_method": {"label": "推送账号方式"},
"change_secret_enabled": {"label": "启用账号改密"},
"change_secret_method": {"label": "账号改密方式"},
"gather_accounts_enabled": {"label": "启用账号收集"},

View File

@ -8,6 +8,7 @@ class DefaultCallback:
'failed': 'failed',
'running': 'running',
'pending': 'pending',
'timeout': 'timeout',
'unknown': 'unknown'
}

View File

@ -14,7 +14,7 @@ class AdHocRunner:
]
def __init__(self, inventory, module, module_args='', pattern='*', project_dir='/tmp/', extra_vars={},
dry_run=False):
dry_run=False, timeout=-1):
self.id = uuid.uuid4()
self.inventory = inventory
self.pattern = pattern
@ -25,6 +25,7 @@ class AdHocRunner:
self.runner = None
self.extra_vars = extra_vars
self.dry_run = dry_run
self.timeout = timeout
def check_module(self):
if self.module not in self.cmd_modules_choices:
@ -41,6 +42,7 @@ class AdHocRunner:
os.mkdir(self.project_dir, 0o755)
ansible_runner.run(
timeout=self.timeout if self.timeout > 0 else None,
extravars=self.extra_vars,
host_pattern=self.pattern,
private_data_dir=self.project_dir,

View File

@ -7,7 +7,7 @@ from ops.models import Job, JobExecution
from ops.serializers.job import JobSerializer, JobExecutionSerializer
__all__ = ['JobViewSet', 'JobExecutionViewSet', 'JobRunVariableHelpAPIView',
'JobAssetDetail', 'JobExecutionTaskDetail','FrequentUsernames']
'JobAssetDetail', 'JobExecutionTaskDetail', 'FrequentUsernames']
from ops.tasks import run_ops_job_execution
from ops.variables import JMS_JOB_VARIABLE_HELP
@ -110,6 +110,7 @@ class JobExecutionTaskDetail(APIView):
with tmp_to_org(org):
execution = get_object_or_404(JobExecution, task_id=task_id)
return Response(data={
'status': execution.status,
'is_finished': execution.is_finished,
'is_success': execution.is_success,
'time_cost': execution.time_cost,

View File

@ -43,9 +43,11 @@ class RunasPolicies(models.TextChoices):
class Modules(models.TextChoices):
shell = 'shell', _('Shell')
winshell = 'win_shell', _('Powershell')
python = 'python', _('Python')
class JobStatus(models.TextChoices):
running = 'running', _('Running')
success = 'success', _('Success')
timeout = 'timeout', _('Timeout')
failed = 'failed', _('Failed')

View File

@ -0,0 +1,33 @@
# Generated by Django 3.2.14 on 2022-12-27 07:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ops', '0034_alter_celerytask_options'),
]
operations = [
migrations.AlterField(
model_name='historicaljob',
name='module',
field=models.CharField(choices=[('shell', 'Shell'), ('win_shell', 'Powershell'), ('python', 'Python')], default='shell', max_length=128, null=True, verbose_name='Module'),
),
migrations.AlterField(
model_name='historicaljob',
name='timeout',
field=models.IntegerField(default=-1, verbose_name='Timeout (Seconds)'),
),
migrations.AlterField(
model_name='job',
name='module',
field=models.CharField(choices=[('shell', 'Shell'), ('win_shell', 'Powershell'), ('python', 'Python')], default='shell', max_length=128, null=True, verbose_name='Module'),
),
migrations.AlterField(
model_name='job',
name='timeout',
field=models.IntegerField(default=-1, verbose_name='Timeout (Seconds)'),
),
]

View File

@ -27,7 +27,7 @@ class Job(JMSOrgBaseModel, PeriodTaskModelMixin):
module = models.CharField(max_length=128, choices=Modules.choices, default=Modules.shell,
verbose_name=_('Module'), null=True)
chdir = models.CharField(default="", max_length=1024, verbose_name=_('Chdir'), null=True, blank=True)
timeout = models.IntegerField(default=60, verbose_name=_('Timeout (Seconds)'))
timeout = models.IntegerField(default=-1, verbose_name=_('Timeout (Seconds)'))
playbook = models.ForeignKey('ops.Playbook', verbose_name=_("Playbook"), null=True, on_delete=models.SET_NULL)
type = models.CharField(max_length=128, choices=Types.choices, default=Types.adhoc, verbose_name=_("Type"))
creator = models.ForeignKey('users.User', verbose_name=_("Creator"), on_delete=models.SET_NULL, null=True)
@ -165,12 +165,11 @@ class JobExecution(JMSOrgBaseModel):
if self.current_job.type != 'adhoc':
return
result = self.current_job.args
result += " chdir={}".format(self.current_job.chdir)
if self.current_job.chdir:
result += " chdir={}".format(self.current_job.chdir)
if self.current_job.module in ['python']:
result += " executable={}".format(self.current_job.module)
print(result)
return self.job.args
return result
def get_runner(self):
inv = self.current_job.inventory
@ -198,6 +197,7 @@ class JobExecution(JMSOrgBaseModel):
runner = AdHocRunner(
self.inventory_path,
module,
timeout=self.current_job.timeout,
module_args=args,
pattern="all",
project_dir=self.private_dir,
@ -238,7 +238,7 @@ class JobExecution(JMSOrgBaseModel):
@property
def is_finished(self):
return self.status in [JobStatus.success, JobStatus.failed]
return self.status in [JobStatus.success, JobStatus.failed, JobStatus.timeout]
@property
def is_success(self):