mirror of https://github.com/jumpserver/jumpserver
merge: v3
commit
0328fd1bb0
|
@ -60,6 +60,7 @@ class AssetViewSet(SuggestionMixin, NodeFilterMixin, OrgBulkModelViewSet):
|
||||||
ordering = ("name",)
|
ordering = ("name",)
|
||||||
serializer_classes = (
|
serializer_classes = (
|
||||||
("default", serializers.AssetSerializer),
|
("default", serializers.AssetSerializer),
|
||||||
|
("retrieve", serializers.AssetDetailSerializer),
|
||||||
("suggestion", serializers.MiniAssetSerializer),
|
("suggestion", serializers.MiniAssetSerializer),
|
||||||
("platform", serializers.PlatformSerializer),
|
("platform", serializers.PlatformSerializer),
|
||||||
("gateways", serializers.GatewaySerializer),
|
("gateways", serializers.GatewaySerializer),
|
||||||
|
|
|
@ -25,7 +25,6 @@ class CloudTypes(BaseType):
|
||||||
'gather_facts_enabled': False,
|
'gather_facts_enabled': False,
|
||||||
'verify_account_enabled': False,
|
'verify_account_enabled': False,
|
||||||
'change_secret_enabled': False,
|
'change_secret_enabled': False,
|
||||||
'push_account_enabled': False,
|
|
||||||
'gather_accounts_enabled': False,
|
'gather_accounts_enabled': False,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ class DatabaseTypes(BaseType):
|
||||||
'gather_accounts_enabled': True,
|
'gather_accounts_enabled': True,
|
||||||
'verify_account_enabled': True,
|
'verify_account_enabled': True,
|
||||||
'change_secret_enabled': True,
|
'change_secret_enabled': True,
|
||||||
'push_account_enabled': True,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return constrains
|
return constrains
|
||||||
|
|
|
@ -40,7 +40,6 @@ class DeviceTypes(BaseType):
|
||||||
'gather_accounts_enabled': False,
|
'gather_accounts_enabled': False,
|
||||||
'verify_account_enabled': False,
|
'verify_account_enabled': False,
|
||||||
'change_secret_enabled': False,
|
'change_secret_enabled': False,
|
||||||
'push_account_enabled': False,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,6 @@ class HostTypes(BaseType):
|
||||||
'gather_accounts_enabled': True,
|
'gather_accounts_enabled': True,
|
||||||
'verify_account_enabled': True,
|
'verify_account_enabled': True,
|
||||||
'change_secret_enabled': True,
|
'change_secret_enabled': True,
|
||||||
'push_account_enabled': True,
|
|
||||||
},
|
},
|
||||||
cls.WINDOWS: {
|
cls.WINDOWS: {
|
||||||
'ansible_config': {
|
'ansible_config': {
|
||||||
|
|
|
@ -1,21 +1,22 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- 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.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.fields import LabeledChoiceField, ObjectRelatedField
|
||||||
|
from common.drf.serializers import WritableNestedModelSerializer
|
||||||
from orgs.mixins.serializers import BulkOrgResourceSerializerMixin
|
from orgs.mixins.serializers import BulkOrgResourceSerializerMixin
|
||||||
from ..account import AccountSerializer
|
from ..account import AccountSerializer
|
||||||
from ...models import Asset, Node, Platform, Label, Domain, Account, Protocol
|
|
||||||
from ...const import Category, AllTypes
|
from ...const import Category, AllTypes
|
||||||
|
from ...models import Asset, Node, Platform, Label, Domain, Account, Protocol
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'AssetSerializer', 'AssetSimpleSerializer', 'MiniAssetSerializer',
|
'AssetSerializer', 'AssetSimpleSerializer', 'MiniAssetSerializer',
|
||||||
'AssetTaskSerializer', 'AssetsTaskSerializer', 'AssetProtocolsSerializer',
|
'AssetTaskSerializer', 'AssetsTaskSerializer', 'AssetProtocolsSerializer',
|
||||||
|
'AssetDetailSerializer',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -71,16 +72,16 @@ class AssetSerializer(BulkOrgResourceSerializerMixin, WritableNestedModelSeriali
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Asset
|
model = Asset
|
||||||
fields_mini = ['id', 'name', 'address', 'enabled_info']
|
fields_mini = ['id', 'name', 'address']
|
||||||
fields_small = fields_mini + ['is_active', 'comment']
|
fields_small = fields_mini + ['is_active', 'comment']
|
||||||
fields_fk = ['domain', 'platform', 'platform']
|
fields_fk = ['domain', 'platform', 'platform']
|
||||||
fields_m2m = [
|
fields_m2m = [
|
||||||
'nodes', 'labels', 'protocols', 'accounts', 'nodes_display',
|
'nodes', 'labels', 'protocols', 'accounts', 'nodes_display',
|
||||||
]
|
]
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
'category', 'type', 'specific', 'info',
|
'category', 'type', 'info',
|
||||||
'connectivity', 'date_verified', 'created_by',
|
'connectivity', 'date_verified',
|
||||||
'date_created'
|
'created_by', 'date_created'
|
||||||
]
|
]
|
||||||
fields = fields_small + fields_fk + fields_m2m + read_only_fields
|
fields = fields_small + fields_fk + fields_m2m + read_only_fields
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
|
@ -89,36 +90,13 @@ class AssetSerializer(BulkOrgResourceSerializerMixin, WritableNestedModelSeriali
|
||||||
'nodes_display': {'label': _('Node path')},
|
'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
|
@classmethod
|
||||||
def setup_eager_loading(cls, queryset):
|
def setup_eager_loading(cls, queryset):
|
||||||
""" Perform necessary eager loading of data. """
|
""" Perform necessary eager loading of data. """
|
||||||
queryset = queryset.prefetch_related('domain', 'platform', 'protocols') \
|
queryset = queryset.prefetch_related('domain', 'platform', 'protocols') \
|
||||||
.annotate(category=F("platform__category")) \
|
.annotate(category=F("platform__category")) \
|
||||||
.annotate(type=F("platform__type"))
|
.annotate(type=F("platform__type"))
|
||||||
queryset = queryset.prefetch_related('nodes', 'labels')
|
queryset = queryset.prefetch_related('nodes', 'labels', 'accounts')
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def perform_nodes_display_create(self, instance, nodes_display):
|
def perform_nodes_display_create(self, instance, nodes_display):
|
||||||
|
@ -189,6 +167,30 @@ class AssetSerializer(BulkOrgResourceSerializerMixin, WritableNestedModelSeriali
|
||||||
return instance
|
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 MiniAssetSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Asset
|
model = Asset
|
||||||
|
|
|
@ -56,8 +56,6 @@ class PlatformAutomationSerializer(serializers.ModelSerializer):
|
||||||
"gather_facts_method": {"label": "收集信息方式"},
|
"gather_facts_method": {"label": "收集信息方式"},
|
||||||
"verify_account_enabled": {"label": "启用校验账号"},
|
"verify_account_enabled": {"label": "启用校验账号"},
|
||||||
"verify_account_method": {"label": "校验账号方式"},
|
"verify_account_method": {"label": "校验账号方式"},
|
||||||
"push_account_enabled": {"label": "启用推送账号"},
|
|
||||||
"push_account_method": {"label": "推送账号方式"},
|
|
||||||
"change_secret_enabled": {"label": "启用账号改密"},
|
"change_secret_enabled": {"label": "启用账号改密"},
|
||||||
"change_secret_method": {"label": "账号改密方式"},
|
"change_secret_method": {"label": "账号改密方式"},
|
||||||
"gather_accounts_enabled": {"label": "启用账号收集"},
|
"gather_accounts_enabled": {"label": "启用账号收集"},
|
||||||
|
|
|
@ -8,6 +8,7 @@ class DefaultCallback:
|
||||||
'failed': 'failed',
|
'failed': 'failed',
|
||||||
'running': 'running',
|
'running': 'running',
|
||||||
'pending': 'pending',
|
'pending': 'pending',
|
||||||
|
'timeout': 'timeout',
|
||||||
'unknown': 'unknown'
|
'unknown': 'unknown'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ class AdHocRunner:
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, inventory, module, module_args='', pattern='*', project_dir='/tmp/', extra_vars={},
|
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.id = uuid.uuid4()
|
||||||
self.inventory = inventory
|
self.inventory = inventory
|
||||||
self.pattern = pattern
|
self.pattern = pattern
|
||||||
|
@ -25,6 +25,7 @@ class AdHocRunner:
|
||||||
self.runner = None
|
self.runner = None
|
||||||
self.extra_vars = extra_vars
|
self.extra_vars = extra_vars
|
||||||
self.dry_run = dry_run
|
self.dry_run = dry_run
|
||||||
|
self.timeout = timeout
|
||||||
|
|
||||||
def check_module(self):
|
def check_module(self):
|
||||||
if self.module not in self.cmd_modules_choices:
|
if self.module not in self.cmd_modules_choices:
|
||||||
|
@ -41,6 +42,7 @@ class AdHocRunner:
|
||||||
os.mkdir(self.project_dir, 0o755)
|
os.mkdir(self.project_dir, 0o755)
|
||||||
|
|
||||||
ansible_runner.run(
|
ansible_runner.run(
|
||||||
|
timeout=self.timeout if self.timeout > 0 else None,
|
||||||
extravars=self.extra_vars,
|
extravars=self.extra_vars,
|
||||||
host_pattern=self.pattern,
|
host_pattern=self.pattern,
|
||||||
private_data_dir=self.project_dir,
|
private_data_dir=self.project_dir,
|
||||||
|
|
|
@ -7,7 +7,7 @@ from ops.models import Job, JobExecution
|
||||||
from ops.serializers.job import JobSerializer, JobExecutionSerializer
|
from ops.serializers.job import JobSerializer, JobExecutionSerializer
|
||||||
|
|
||||||
__all__ = ['JobViewSet', 'JobExecutionViewSet', 'JobRunVariableHelpAPIView',
|
__all__ = ['JobViewSet', 'JobExecutionViewSet', 'JobRunVariableHelpAPIView',
|
||||||
'JobAssetDetail', 'JobExecutionTaskDetail','FrequentUsernames']
|
'JobAssetDetail', 'JobExecutionTaskDetail', 'FrequentUsernames']
|
||||||
|
|
||||||
from ops.tasks import run_ops_job_execution
|
from ops.tasks import run_ops_job_execution
|
||||||
from ops.variables import JMS_JOB_VARIABLE_HELP
|
from ops.variables import JMS_JOB_VARIABLE_HELP
|
||||||
|
@ -110,6 +110,7 @@ class JobExecutionTaskDetail(APIView):
|
||||||
with tmp_to_org(org):
|
with tmp_to_org(org):
|
||||||
execution = get_object_or_404(JobExecution, task_id=task_id)
|
execution = get_object_or_404(JobExecution, task_id=task_id)
|
||||||
return Response(data={
|
return Response(data={
|
||||||
|
'status': execution.status,
|
||||||
'is_finished': execution.is_finished,
|
'is_finished': execution.is_finished,
|
||||||
'is_success': execution.is_success,
|
'is_success': execution.is_success,
|
||||||
'time_cost': execution.time_cost,
|
'time_cost': execution.time_cost,
|
||||||
|
|
|
@ -43,9 +43,11 @@ class RunasPolicies(models.TextChoices):
|
||||||
class Modules(models.TextChoices):
|
class Modules(models.TextChoices):
|
||||||
shell = 'shell', _('Shell')
|
shell = 'shell', _('Shell')
|
||||||
winshell = 'win_shell', _('Powershell')
|
winshell = 'win_shell', _('Powershell')
|
||||||
|
python = 'python', _('Python')
|
||||||
|
|
||||||
|
|
||||||
class JobStatus(models.TextChoices):
|
class JobStatus(models.TextChoices):
|
||||||
running = 'running', _('Running')
|
running = 'running', _('Running')
|
||||||
success = 'success', _('Success')
|
success = 'success', _('Success')
|
||||||
|
timeout = 'timeout', _('Timeout')
|
||||||
failed = 'failed', _('Failed')
|
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,
|
module = models.CharField(max_length=128, choices=Modules.choices, default=Modules.shell,
|
||||||
verbose_name=_('Module'), null=True)
|
verbose_name=_('Module'), null=True)
|
||||||
chdir = models.CharField(default="", max_length=1024, verbose_name=_('Chdir'), null=True, blank=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)
|
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"))
|
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)
|
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':
|
if self.current_job.type != 'adhoc':
|
||||||
return
|
return
|
||||||
result = self.current_job.args
|
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']:
|
if self.current_job.module in ['python']:
|
||||||
result += " executable={}".format(self.current_job.module)
|
result += " executable={}".format(self.current_job.module)
|
||||||
print(result)
|
return result
|
||||||
return self.job.args
|
|
||||||
|
|
||||||
def get_runner(self):
|
def get_runner(self):
|
||||||
inv = self.current_job.inventory
|
inv = self.current_job.inventory
|
||||||
|
@ -198,6 +197,7 @@ class JobExecution(JMSOrgBaseModel):
|
||||||
runner = AdHocRunner(
|
runner = AdHocRunner(
|
||||||
self.inventory_path,
|
self.inventory_path,
|
||||||
module,
|
module,
|
||||||
|
timeout=self.current_job.timeout,
|
||||||
module_args=args,
|
module_args=args,
|
||||||
pattern="all",
|
pattern="all",
|
||||||
project_dir=self.private_dir,
|
project_dir=self.private_dir,
|
||||||
|
@ -238,7 +238,7 @@ class JobExecution(JMSOrgBaseModel):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_finished(self):
|
def is_finished(self):
|
||||||
return self.status in [JobStatus.success, JobStatus.failed]
|
return self.status in [JobStatus.success, JobStatus.failed, JobStatus.timeout]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_success(self):
|
def is_success(self):
|
||||||
|
|
Loading…
Reference in New Issue