feat: 增加跳过的主机统计, 增加每台主机执行情况api

pull/9169/head
Aaron3S 2022-12-07 20:13:26 +08:00
parent 66bdc375df
commit c14b97419d
5 changed files with 83 additions and 10 deletions

View File

@ -10,7 +10,7 @@ __all__ = ['JMSInventory']
class JMSInventory:
def __init__(self, assets, account_policy='privileged_first',
account_prefer='root,Administrator', host_callback=None):
account_prefer='root,Administrator', host_callback=None, unique_host_name=False):
"""
:param assets:
:param account_prefer: account username name if not set use account_policy
@ -20,6 +20,8 @@ class JMSInventory:
self.account_prefer = account_prefer
self.account_policy = account_policy
self.host_callback = host_callback
self.exclude_hosts = {}
self.unique_host_name = unique_host_name
@staticmethod
def clean_assets(assets):
@ -112,6 +114,9 @@ class JMSInventory:
'secret': account.secret, 'secret_type': account.secret_type
} if account else None
}
if self.unique_host_name:
host['name'] += '({})'.format(asset.id)
if host['jms_account'] and asset.platform.type == 'oracle':
host['jms_account']['mode'] = 'sysdba' if account.privileged else None
@ -194,7 +199,7 @@ class JMSInventory:
print(_("Skip hosts below:"))
for i, host in enumerate(exclude_hosts, start=1):
print("{}: [{}] \t{}".format(i, host['name'], host['error']))
self.exclude_hosts[host['name']] = host['error']
hosts = list(filter(lambda x: not x.get('error'), hosts))
data = {'all': {'hosts': {}}}
for host in hosts:

View File

@ -1,12 +1,12 @@
from rest_framework.views import APIView
from django.shortcuts import get_object_or_404
from rest_framework.response import Response
from ops.api.base import SelfBulkModelViewSet
from ops.models import Job, JobExecution
from ops.serializers.job import JobSerializer, JobExecutionSerializer
__all__ = ['JobViewSet', 'JobExecutionViewSet', 'JobRunVariableHelpAPIView']
__all__ = ['JobViewSet', 'JobExecutionViewSet', 'JobRunVariableHelpAPIView', 'JobAssetDetail']
from ops.tasks import run_ops_job_execution
from ops.variables import JMS_JOB_VARIABLE_HELP
@ -73,3 +73,14 @@ class JobRunVariableHelpAPIView(APIView):
def get(self, request, **kwargs):
return Response(data=JMS_JOB_VARIABLE_HELP)
class JobAssetDetail(APIView):
rbac_perms = ()
permission_classes = ()
def get(self, request, **kwargs):
execution_id = request.query_params.get('execution_id')
if execution_id:
execution = get_object_or_404(JobExecution, id=execution_id)
return Response(data=execution.assent_result_detail)

View File

@ -88,7 +88,7 @@ class Job(JMSBaseModel, PeriodTaskModelMixin):
@property
def inventory(self):
return JMSInventory(self.assets.all(), self.runas_policy, self.runas)
return JMSInventory(self.assets.all(), self.runas_policy, self.runas, unique_host_name=True)
def create_execution(self):
return self.executions.create()
@ -110,6 +110,55 @@ class JobExecution(JMSBaseModel):
date_start = models.DateTimeField(null=True, verbose_name=_('Date start'), db_index=True)
date_finished = models.DateTimeField(null=True, verbose_name=_("Date finished"))
@property
def count(self):
if self.is_finished and not self.summary.get('error', None):
return {
"ok": len(self.summary['ok']),
"failed": len(self.summary['failures']) + len(self.summary['dark']),
"excludes": len(self.summary['excludes']),
"total": self.job.assets.count()
}
@property
def assent_result_detail(self):
if self.is_finished and not self.summary.get('error', None):
result = {
"summary": self.count,
"detail": [],
}
for asset in self.job.assets.all():
asset_detail = {
"name": asset.name,
"status": "ok",
"tasks": [],
}
host_name = "{}({})".format(asset.name, asset.id)
if self.summary["excludes"].get(host_name, None):
asset_detail.update({"status": "excludes"})
result["detail"].append(asset_detail)
break
if self.result["dark"].get(host_name, None):
asset_detail.update({"status": "failed"})
for key, task in self.result["dark"][host_name].items():
task_detail = {"name": key,
"output": "{}{}".format(task.get("stdout", ""), task.get("stderr", ""))}
asset_detail["tasks"].append(task_detail)
if self.result["failures"].get(host_name, None):
asset_detail.update({"status": "failed"})
for key, task in self.result["failures"][host_name].items():
task_detail = {"name": key,
"output": "{}{}".format(task.get("stdout", ""), task.get("stderr", ""))}
asset_detail["tasks"].append(task_detail)
if self.result["ok"].get(host_name, None):
for key, task in self.result["ok"][host_name].items():
task_detail = {"name": key,
"output": "{}{}".format(task.get("stdout", ""), task.get("stderr", ""))}
asset_detail["tasks"].append(task_detail)
result["detail"].append(asset_detail)
return result
@property
def job_type(self):
return self.job.type
@ -124,6 +173,11 @@ class JobExecution(JMSBaseModel):
def get_runner(self):
inv = self.job.inventory
inv.write_to_file(self.inventory_path)
if len(inv.exclude_hosts) > 0:
self.summary['excludes'] = inv.exclude_hosts
self.result['excludes'] = inv.exclude_hosts
self.save()
if isinstance(self.parameters, str):
extra_vars = json.loads(self.parameters)
else:
@ -191,7 +245,7 @@ class JobExecution(JMSBaseModel):
def set_error(self, error):
this = self.__class__.objects.get(id=self.id) # 重新获取一次,避免数据库超时连接超时
this.status = 'failed'
this.summary['error'] = str(error)
this.summary.update({'error': str(error)})
this.finish_task()
def set_result(self, cb):
@ -200,8 +254,8 @@ class JobExecution(JMSBaseModel):
}
this = self.__class__.objects.get(id=self.id)
this.status = status_mapper.get(cb.status, cb.status)
this.summary = cb.summary
this.result = cb.result
this.summary.update(cb.summary)
this.result.update(cb.result)
this.finish_task()
def finish_task(self):

View File

@ -28,10 +28,13 @@ class JobSerializer(serializers.ModelSerializer, PeriodTaskSerializerMixin):
class JobExecutionSerializer(serializers.ModelSerializer):
creator = ReadableHiddenField(default=serializers.CurrentUserDefault())
job_type = serializers.ReadOnlyField(label=_("Job type"))
count = serializers.ReadOnlyField(label=_("Count"))
class Meta:
model = JobExecution
read_only_fields = ["id", "task_id", "timedelta", "time_cost", 'is_finished', 'date_start', 'date_created',
read_only_fields = ["id", "task_id", "timedelta", "count", "time_cost", 'is_finished', 'date_start',
'date_finished',
'date_created',
'is_success', 'task_id', 'short_id', 'job_type', 'creator']
fields = read_only_fields + [
"job", "parameters"

View File

@ -24,7 +24,7 @@ router.register(r'task-executions', api.CeleryTaskExecutionViewSet, 'task-execut
urlpatterns = [
path('variables/help/', api.JobRunVariableHelpAPIView.as_view(), name='variable-help'),
path('job-execution/asset-detail/', api.JobAssetDetail.as_view(), name='asset-detail'),
path('ansible/job-execution/<uuid:pk>/log/', api.AnsibleTaskLogApi.as_view(), name='job-execution-log'),
path('celery/task/<uuid:name>/task-execution/<uuid:pk>/log/', api.CeleryTaskExecutionLogApi.as_view(),