mirror of https://github.com/jumpserver/jumpserver
merge: v3
commit
0328fd1bb0
|
@ -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),
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -40,7 +40,6 @@ class DeviceTypes(BaseType):
|
|||
'gather_accounts_enabled': False,
|
||||
'verify_account_enabled': False,
|
||||
'change_secret_enabled': False,
|
||||
'push_account_enabled': False,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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': {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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": "启用账号收集"},
|
||||
|
|
|
@ -8,6 +8,7 @@ class DefaultCallback:
|
|||
'failed': 'failed',
|
||||
'running': 'running',
|
||||
'pending': 'pending',
|
||||
'timeout': 'timeout',
|
||||
'unknown': 'unknown'
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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)'),
|
||||
),
|
||||
]
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue