mirror of https://github.com/jumpserver/jumpserver
[Bugfix] 修复ops一些功能的bug
parent
3f89701b84
commit
5a92972120
|
@ -1,15 +1,16 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
PUSH_SYSTEM_USER_PERIOD_LOCK_KEY = "PUSH_SYSTEM_USER_PERIOD_KEY"
|
||||
PUSH_SYSTEM_USER_PERIOD_TASK_NAME = "PUSH-SYSTEM-USER-PERIOD"
|
||||
PUSH_SYSTEM_USER_TASK_NAME = "PUSH-SYSTEM-USER-TO-CLUSTER-{}"
|
||||
PUSH_SYSTEM_USER_PERIOD_TASK_NAME = _("PUSH SYSTEM USER TO CLUSTER PERIOD TASK")
|
||||
PUSH_SYSTEM_USER_TASK_NAME = _("PUSH SYSTEM USER TO CLUSTER: {}")
|
||||
PUSH_SYSTEM_USER_LOCK_KEY = "PUSH_SYSTEM_USER_TO_CLUSTER_LOCK_{}"
|
||||
|
||||
|
||||
UPDATE_ASSETS_HARDWARE_TASK_NAME = 'UPDATE-ASSETS-HARDWARE-INFO'
|
||||
UPDATE_ASSETS_HARDWARE_TASK_NAME = _('UPDATE ASSETS HARDWARE INFO')
|
||||
UPDATE_ASSETS_HARDWARE_PERIOD_LOCK_KEY = "UPDATE_ASSETS_HARDWARE_PERIOD_LOCK_KEY"
|
||||
UPDATE_ASSETS_HARDWARE_PERIOD_TASK_NAME = 'UPDATE-ASSETS-HARDWARE-INFO-PERIOD'
|
||||
UPDATE_ASSETS_HARDWARE_PERIOD_TASK_NAME = _('UPDATE ASSETS HARDWARE INFO PERIOD')
|
||||
UPDATE_ASSETS_HARDWARE_TASKS = [
|
||||
{
|
||||
'name': UPDATE_ASSETS_HARDWARE_TASK_NAME,
|
||||
|
@ -20,8 +21,8 @@ UPDATE_ASSETS_HARDWARE_TASKS = [
|
|||
]
|
||||
|
||||
TEST_ADMIN_USER_CONN_PERIOD_LOCK_KEY = "TEST_ADMIN_USER_CONN_PERIOD_KEY"
|
||||
TEST_ADMIN_USER_CONN_PERIOD_TASK_NAME = "TEST_ADMIN_USER_CONN_PERIOD_TASK"
|
||||
TEST_ADMIN_USER_CONN_TASK_NAME = "TEST-ADMIN-USER-CONN-{}"
|
||||
TEST_ADMIN_USER_CONN_PERIOD_TASK_NAME = _("TEST ADMIN USER CONN PERIOD TASK")
|
||||
TEST_ADMIN_USER_CONN_TASK_NAME = _("TEST ADMIN USER CONN: {}")
|
||||
TEST_ADMIN_USER_CONN_LOCK_KEY = TEST_ADMIN_USER_CONN_TASK_NAME
|
||||
ADMIN_USER_CONN_CACHE_KEY = "ADMIN_USER_CONN_{}"
|
||||
TEST_ADMIN_USER_CONN_TASKS = [
|
||||
|
@ -34,12 +35,12 @@ TEST_ADMIN_USER_CONN_TASKS = [
|
|||
]
|
||||
|
||||
ASSET_ADMIN_CONN_CACHE_KEY = "ASSET_ADMIN_USER_CONN_{}"
|
||||
TEST_ASSET_CONN_TASK_NAME = "ASSET_CONN_TEST_MANUAL"
|
||||
TEST_ASSET_CONN_TASK_NAME = _("ASSET CONN TEST MANUAL")
|
||||
|
||||
TEST_SYSTEM_USER_CONN_PERIOD_LOCK_KEY = "TEST_SYSTEM_USER_CONN_PERIOD_KEY"
|
||||
TEST_SYSTEM_USER_CONN_PERIOD_TASK_NAME = "TEST-SYSTEM-USER-CONN-PERIOD-TASK"
|
||||
TEST_SYSTEM_USER_CONN_PERIOD_TASK_NAME = _("TEST SYSTEM USER CONN PERIOD TASK")
|
||||
TEST_SYSTEM_USER_CONN_CACHE_KEY_PREFIX = "SYSTEM_USER_CONN_"
|
||||
TEST_SYSTEM_USER_CONN_TASK_NAME = "TEST-SYSTEM-USER-CONN-{}"
|
||||
TEST_SYSTEM_USER_CONN_TASK_NAME = _("TEST SYSTEM USER CONN: {}")
|
||||
TEST_SYSTEM_USER_CONN_LOCK_KEY = "TEST_SYSTEM_USER_CONN_{}"
|
||||
SYSTEM_USER_CONN_CACHE_KEY = "SYSTEM_USER_CONN_{}"
|
||||
TEST_SYSTEM_USER_CONN_TASKS = [
|
||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -35,8 +35,13 @@ class AdHocRunHistorySet(viewsets.ModelViewSet):
|
|||
|
||||
def get_queryset(self):
|
||||
task_id = self.request.query_params.get('task')
|
||||
adhoc_id = self.request.query_params.get('adhoc')
|
||||
if task_id:
|
||||
task = get_object_or_404(Task, id=task_id)
|
||||
adhocs = task.adhoc.all()
|
||||
self.queryset = self.queryset.filter(adhoc__in=adhocs)
|
||||
|
||||
if adhoc_id:
|
||||
adhoc = get_object_or_404(AdHoc, id=adhoc_id)
|
||||
self.queryset = self.queryset.filter(adhoc=adhoc)
|
||||
return self.queryset
|
||||
|
|
|
@ -222,6 +222,14 @@ class AdHocRunHistory(models.Model):
|
|||
def summary(self, item):
|
||||
self._summary = json.dumps(item)
|
||||
|
||||
@property
|
||||
def success_hosts(self):
|
||||
return self.summary.get('contacted', [])
|
||||
|
||||
@property
|
||||
def failed_hosts(self):
|
||||
return self.summary.get('dark', {})
|
||||
|
||||
def __str__(self):
|
||||
return self.short_id
|
||||
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
||||
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="panel-options">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active">
|
||||
<a href="{% url 'ops:adhoc-detail' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Version detail' %} </a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'ops:adhoc-history' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Version run history' %} </a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="col-sm-7" style="padding-left: 0">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label"><b>{{ object.task.name }}: {{ object.short_id }}</b></span>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
</a>
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<i class="fa fa-wrench"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-user">
|
||||
</ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr class="no-borders-tr">
|
||||
<td width="20%">{% trans 'ID' %}:</td>
|
||||
<td><b>{{ object.id }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%">{% trans 'Hosts' %}:</td>
|
||||
<td><b>{{ object.hosts | length }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%">{% trans 'Pattern' %}:</td>
|
||||
<td><b>{{ object.pattern }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Options' %}</td>
|
||||
<td>
|
||||
<b>
|
||||
{% for k, v in object.options.items %}
|
||||
{{ k }} = {{ v }} <br/>
|
||||
{% endfor %}
|
||||
</b>
|
||||
</td>
|
||||
</tr>
|
||||
{% if object.run_as_admin %}
|
||||
<tr>
|
||||
<td>{% trans 'Run as' %}</td>
|
||||
<td><b> Admin </b></td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td>{% trans 'Run as' %}:</td>
|
||||
<td><b>{{ object.get_latest_history.date_start }}</b></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td>{% trans 'Become' %}</td>
|
||||
<td><b>{{ object.become.user }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Created by' %}</td>
|
||||
<td><b>{{ object.created_by }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date created' %}:</td>
|
||||
<td><b>{{ object.date_created }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Run times' %}:</td>
|
||||
<td><b>{{ object.history.all | length }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Last run' %}:</td>
|
||||
<td><b>{{ object.latest_history.short_id }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Time delta' %}:</td>
|
||||
<td><b>{{ object.latest_history.timedelta|floatformat}} s</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Is finished' %}:</td>
|
||||
<td><b>{{ object.latest_history.is_finished|yesno:"Yes,No,Unkown" }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Is success ' %}:</td>
|
||||
<td><b>{{ object.latest_history.is_success|yesno:"Yes,No,Unkown" }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Tasks' %}:</td>
|
||||
<td>
|
||||
<b>
|
||||
{% for task in object.tasks %}
|
||||
{{ forloop.counter }}. {{ task.name }} ::: {{ task.action.module }} <br/>
|
||||
{% endfor %}
|
||||
</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Last run failed hosts' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
{% for host, task in object.latest_history.failed_hosts.items %}
|
||||
{% if forloop.first %}
|
||||
<tr class="no-borders-tr">
|
||||
{% else %}
|
||||
<tr>
|
||||
{% endif %}
|
||||
<td>{{ host }}: </td>
|
||||
<td>
|
||||
{% for name, result in task.items %}
|
||||
<b>{{ name }}</b> => {{ result.msg }}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr class="no-borders-tr">
|
||||
<td>{% trans 'No hosts' %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Last run success hosts' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
{% for host in object.latest_history.success_hosts %}
|
||||
{% if forloop.first %}
|
||||
<tr class="no-borders-tr">
|
||||
{% else %}
|
||||
<tr>
|
||||
{% endif %}
|
||||
<td>{{ host }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr class="no-borders-tr">
|
||||
<td>{% trans 'No hosts' %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'users/_user_update_pk_modal.html' %}
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
||||
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="panel-options">
|
||||
<ul class="nav nav-tabs">
|
||||
<li>
|
||||
<a href="{% url 'ops:adhoc-detail' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Version detail' %} </a>
|
||||
</li>
|
||||
<li class="active">
|
||||
<a href="{% url 'ops:adhoc-history' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Version run history' %} </a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="col-sm-12" style="padding-left: 0">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span style="float: left">{% trans 'History of ' %} <b>{{ object.task.name }}:{{ object.short_id }}</b></span>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
</a>
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<i class="fa fa-wrench"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-user">
|
||||
</ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<table class="table table-hover " id="task-history-list-table" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">
|
||||
<input type="checkbox" id="check_all" class="ipt_check_all" >
|
||||
</th>
|
||||
<th>{% trans 'Date start' %}</th>
|
||||
<th>{% trans 'F/S/T' %}</th>
|
||||
<th>{% trans 'Ratio' %}</th>
|
||||
<th>{% trans 'Is finished' %}</th>
|
||||
<th>{% trans 'Is success' %}</th>
|
||||
<th>{% trans 'Time' %}</th>
|
||||
<th>{% trans 'Version' %}</th>
|
||||
<th>{% trans 'Action' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
function initTable() {
|
||||
var options = {
|
||||
ele: $('#task-history-list-table'),
|
||||
buttons: [],
|
||||
order: [],
|
||||
select: [],
|
||||
columnDefs: [
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
$(td).html(cellData);
|
||||
}},
|
||||
{targets: 2, createdCell: function (td, cellData) {
|
||||
var total = "<span>" + cellData.total + "</span>";
|
||||
var success = "<span class='text-navy'>" + cellData.success + "</span>";
|
||||
var failed = "<span class='text-danger'>" + cellData.failed + "</span>";
|
||||
$(td).html(failed + '/' + success + '/' + total );
|
||||
}},
|
||||
{targets: 3, createdCell: function (td, cellData) {
|
||||
var val = 0;
|
||||
var innerHtml = "";
|
||||
if (cellData.total !== 0) {
|
||||
val = cellData.success/cellData.total * 100;
|
||||
}
|
||||
|
||||
if (val === 100) {
|
||||
innerHtml = "<span class='text-navy'>" + val + "% </span>";
|
||||
} else {
|
||||
innerHtml = "<span class='text-danger'>" + val + "% </span>";
|
||||
}
|
||||
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>');
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||
}
|
||||
}},
|
||||
{targets: 5, createdCell: function (td, cellData) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||
}
|
||||
}},
|
||||
{targets: 6, createdCell: function (td, cellData) {
|
||||
if (cellData) {
|
||||
$(td).html(cellData.toFixed(2) + ' s')
|
||||
} else {
|
||||
$(td).html("0" + ' s')
|
||||
}
|
||||
}},
|
||||
{targets: 8, createdCell: function (td, cellData) {
|
||||
var run_btn = '<a class="btn btn-xs btn-primary m-l-xs btn-run" href="{% url 'ops:adhoc-history-detail' pk=DEFAULT_PK %}">{% trans "Detail" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
|
||||
if (cellData) {
|
||||
$(td).html(run_btn);
|
||||
}
|
||||
}}
|
||||
],
|
||||
ajax_url: '{% url "api-ops:history-list" %}?adhoc={{ object.pk }}',
|
||||
columns: [{data: function(){return ""}}, {data: "date_start"}, {data: "stat"}, {data: "stat"}, {data: "is_finished"},
|
||||
{data: "is_success"}, {data: "timedelta"}, {data: 'adhoc_short_id'}, {data: "id"}]
|
||||
};
|
||||
jumpserver.initDataTable(options);
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
initTable();
|
||||
})
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -0,0 +1,141 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
||||
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="panel-options">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active">
|
||||
<a href="{% url 'ops:adhoc-history-detail' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Run history detail' %} </a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="col-sm-7" style="padding-left: 0">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label"><b>{% trans 'History detail of' %} {{ object.task.name }}: {{ object.adhoc.short_id }} </b></span>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
</a>
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<i class="fa fa-wrench"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-user">
|
||||
</ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr class="no-borders-tr">
|
||||
<td width="20%">{% trans 'ID' %}:</td>
|
||||
<td><b>{{ object.id }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%">{% trans 'Task name' %}:</td>
|
||||
<td><b>{{ object.task.name }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Version' %}:</td>
|
||||
<td><b>{{ object.adhoc.short_id }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date start' %}:</td>
|
||||
<td><b>{{ object.date_start }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Time delta' %}:</td>
|
||||
<td><b>{{ object.timedelta|floatformat}} s</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Is finished' %}:</td>
|
||||
<td><b>{{ object.is_finished|yesno:"Yes,No,Unkown" }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Is success ' %}:</td>
|
||||
<td><b>{{ object.is_success|yesno:"Yes,No,Unkown" }}</b></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Failed assets' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
{% for host, task in object.failed_hosts.items %}
|
||||
{% if forloop.first %}
|
||||
<tr class="no-borders-tr">
|
||||
{% else %}
|
||||
<tr>
|
||||
{% endif %}
|
||||
<td>{{ host }}: </td>
|
||||
<td>
|
||||
{% for name, result in task.items %}
|
||||
<b>{{ name }}</b> => {{ result.msg }}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr class="no-borders-tr">
|
||||
<td>{% trans 'No assets' %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Success assets' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
{% for host in object.success_hosts %}
|
||||
{% if forloop.first %}
|
||||
<tr class="no-borders-tr">
|
||||
{% else %}
|
||||
<tr>
|
||||
{% endif %}
|
||||
<td>{{ host }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr class="no-borders-tr">
|
||||
<td>{% trans 'No assets' %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'users/_user_update_pk_modal.html' %}
|
||||
{% endblock %}
|
||||
|
|
@ -106,7 +106,7 @@
|
|||
}
|
||||
}},
|
||||
{targets: 7, createdCell: function (td, cellData, rowData) {
|
||||
var detail_btn = '<a class="btn btn-xs btn-primary m-l-xs btn-run" data-uid="{{ DEFAULT_PK }}">{% trans "Detail" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
|
||||
var detail_btn = '<a class="btn btn-xs btn-primary m-l-xs btn-run" href="{% url 'ops:adhoc-detail' pk=DEFAULT_PK %}">{% trans "Detail" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
|
||||
if (cellData) {
|
||||
$(td).html(detail_btn);
|
||||
}
|
||||
|
|
|
@ -66,30 +66,30 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Latest version' %}</td>
|
||||
<td><b>{{ object.get_latest_adhoc.short_id }}</b></td>
|
||||
<td><b><a href="{% url 'ops:adhoc-detail' pk=object.latest_adhoc.id %}">{{ object.latest_adhoc.short_id }}</a></b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Latest run' %}:</td>
|
||||
<td><b>{{ object.get_latest_history.date_start }}</b></td>
|
||||
<td><b>{{ object.latest_history.date_start }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Time delta' %}:</td>
|
||||
<td><b>{{ object.get_latest_history.timedelta|floatformat}} s</b></td>
|
||||
<td><b>{{ object.latest_history.timedelta|floatformat}} s</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Is finished' %}:</td>
|
||||
<td><b>{{ object.get_latest_history.is_finished|yesno:"Yes,No,Unkown" }}</b></td>
|
||||
<td><b>{{ object.latest_history.is_finished|yesno:"Yes,No,Unkown" }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Is success ' %}:</td>
|
||||
<td><b>{{ object.get_latest_history.is_success|yesno:"Yes,No,Unkown" }}</b></td>
|
||||
<td><b>{{ object.latest_history.is_success|yesno:"Yes,No,Unkown" }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Contents' %}:</td>
|
||||
<td>
|
||||
<b>
|
||||
{% for task in object.get_latest_adhoc.tasks %}
|
||||
{{ task.name }} : {{ task.action.module }} <br/>
|
||||
{% for task in object.latest_adhoc.tasks %}
|
||||
{{ forloop.counter }}. {{ task.name }} : {{ task.action.module }} <br/>
|
||||
{% endfor %}
|
||||
</b>
|
||||
</td>
|
||||
|
@ -102,23 +102,27 @@
|
|||
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Failed assets' %}
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Last run failed hosts' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
{% for host, msg in results.failed %}
|
||||
{% for host, task in object.latest_history.failed_hosts.items %}
|
||||
{% if forloop.first %}
|
||||
<tr class="no-borders-tr">
|
||||
{% else %}
|
||||
<tr>
|
||||
{% endif %}
|
||||
<td>{{ host }}: </td>
|
||||
<td>{{ msg }}</td>
|
||||
<td>
|
||||
{% for name, result in task.items %}
|
||||
<b>{{ name }}</b> => {{ result.msg }}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr class="no-borders-tr">
|
||||
<td>{% trans 'No assets' %}</td>
|
||||
<td>{% trans 'No hosts' %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
@ -128,12 +132,12 @@
|
|||
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Success assets' %}
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Last run success hosts' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
{% for host in object.get_latest_history.summary.contacted %}
|
||||
{% for host in object.latest_history.success_hosts %}
|
||||
{% if forloop.first %}
|
||||
<tr class="no-borders-tr">
|
||||
{% else %}
|
||||
|
@ -143,7 +147,7 @@
|
|||
</tr>
|
||||
{% empty %}
|
||||
<tr class="no-borders-tr">
|
||||
<td>{% trans 'No assets' %}</td>
|
||||
<td>{% trans 'No hosts' %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
<div class="col-sm-12" style="padding-left: 0">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span style="float: left">{% trans 'History of ' %} <b>{{ object.name }}</b></span>
|
||||
<span style="float: left">{% trans 'History of ' %} <b>{{ object.task.name }}:{{ object.short_id }}</b></span>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
|
@ -54,6 +54,7 @@
|
|||
</th>
|
||||
<th>{% trans 'Date start' %}</th>
|
||||
<th>{% trans 'F/S/T' %}</th>
|
||||
<th>{% trans 'Ratio' %}</th>
|
||||
<th>{% trans 'Is finished' %}</th>
|
||||
<th>{% trans 'Is success' %}</th>
|
||||
<th>{% trans 'Time' %}</th>
|
||||
|
@ -75,57 +76,75 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
var options = {
|
||||
ele: $('#task-history-list-table'),
|
||||
buttons: [],
|
||||
order: [],
|
||||
select: [],
|
||||
columnDefs: [
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
{# var detail_btn = '<a href="' + cellData + '</a>';#}
|
||||
$(td).html(cellData);
|
||||
}},
|
||||
{targets: 2, createdCell: function (td, cellData) {
|
||||
var total = "<span>" + cellData.total + "</span>";
|
||||
var success = "<span class='text-navy'>" + cellData.success + "</span>";
|
||||
var failed = "<span class='text-danger'>" + cellData.failed + "</span>";
|
||||
$(td).html(failed + '/' + success + '/' + total );
|
||||
}},
|
||||
{targets: 3, createdCell: function (td, cellData) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||
}
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||
}
|
||||
}},
|
||||
{targets: 5, createdCell: function (td, cellData) {
|
||||
if (cellData) {
|
||||
$(td).html(cellData.toFixed(2) + ' s')
|
||||
} else {
|
||||
$(td).html("0" + ' s')
|
||||
}
|
||||
}},
|
||||
{targets: 7, createdCell: function (td, cellData) {
|
||||
var run_btn = '<a class="btn btn-xs btn-primary m-l-xs btn-run" data-uid="{{ DEFAULT_PK }}">{% trans "Detail" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
|
||||
if (cellData) {
|
||||
$(td).html(run_btn);
|
||||
}
|
||||
}}
|
||||
],
|
||||
ajax_url: '{% url "api-ops:history-list" %}?task={{ object.pk }}',
|
||||
columns: [{data: function(){return ""}}, {data: "date_start"}, {data: "stat"}, {data: "adhoc_short_id"},
|
||||
{data: "adhoc_short_id"}, {data: "timedelta"}, {data: 'adhoc_short_id'}, {data: "id"}]
|
||||
};
|
||||
jumpserver.initDataTable(options);
|
||||
})
|
||||
</script>
|
||||
<script>
|
||||
function initTable() {
|
||||
var options = {
|
||||
ele: $('#task-history-list-table'),
|
||||
buttons: [],
|
||||
order: [],
|
||||
select: [],
|
||||
columnDefs: [
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
$(td).html(cellData);
|
||||
}},
|
||||
{targets: 2, createdCell: function (td, cellData) {
|
||||
var total = "<span>" + cellData.total + "</span>";
|
||||
var success = "<span class='text-navy'>" + cellData.success + "</span>";
|
||||
var failed = "<span class='text-danger'>" + cellData.failed + "</span>";
|
||||
$(td).html(failed + '/' + success + '/' + total );
|
||||
}},
|
||||
{targets: 3, createdCell: function (td, cellData) {
|
||||
var val = 0;
|
||||
var innerHtml = "";
|
||||
if (cellData.total !== 0) {
|
||||
val = cellData.success/cellData.total * 100;
|
||||
}
|
||||
|
||||
if (val === 100) {
|
||||
innerHtml = "<span class='text-navy'>" + val + "% </span>";
|
||||
} else {
|
||||
innerHtml = "<span class='text-danger'>" + val + "% </span>";
|
||||
}
|
||||
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>');
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||
}
|
||||
}},
|
||||
{targets: 5, createdCell: function (td, cellData) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||
}
|
||||
}},
|
||||
{targets: 6, createdCell: function (td, cellData) {
|
||||
if (cellData) {
|
||||
$(td).html(cellData.toFixed(2) + ' s')
|
||||
} else {
|
||||
$(td).html("0" + ' s')
|
||||
}
|
||||
}},
|
||||
{targets: 8, createdCell: function (td, cellData) {
|
||||
var run_btn = '<a class="btn btn-xs btn-primary m-l-xs btn-run" href="{% url 'ops:adhoc-history-detail' pk=DEFAULT_PK %}">{% trans "Detail" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
|
||||
if (cellData) {
|
||||
$(td).html(run_btn);
|
||||
}
|
||||
}}
|
||||
],
|
||||
ajax_url: '{% url "api-ops:history-list" %}?task={{ object.pk }}',
|
||||
columns: [{data: function(){return ""}}, {data: "date_start"}, {data: "stat"}, {data: "stat"}, {data: "is_finished"},
|
||||
{data: "is_success"}, {data: "timedelta"}, {data: 'adhoc_short_id'}, {data: "id"}]
|
||||
};
|
||||
jumpserver.initDataTable(options);
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
initTable();
|
||||
})
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control input-sm" name="keyword" placeholder="Search" value="{{ keyword }}">
|
||||
<input type="text" class="form-control input-sm" name="keyword" placeholder="{% trans "Search" %}" value="{{ keyword }}">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<div class="input-group-btn">
|
||||
|
@ -50,7 +50,7 @@
|
|||
{% for object in task_list %}
|
||||
<tr class="gradeX">
|
||||
<td class="text-center"><input type="checkbox" class="cbx-term"> </td>
|
||||
<td class="text-center"><a href="{% url 'ops:task-detail' pk=object.id %}">{{ object.name }}</a></td>
|
||||
<td class="text-left"><a href="{% url 'ops:task-detail' pk=object.id %}">{{ object.name }}</a></td>
|
||||
<td class="text-center">
|
||||
<span class="text-danger">{{ object.history_summary.failed }}</span>/<span class="text-navy">{{ object.history_summary.success}}</span>/{{ object.history_summary.total}}
|
||||
</td>
|
||||
|
@ -67,38 +67,37 @@
|
|||
<td class="text-center">{{ object.latest_history.timedelta|floatformat }} s</td>
|
||||
<td class="text-center">
|
||||
<a href="{% url 'ops:task-run' pk=object.id %}" class="btn btn-xs btn-info">{% trans "Run" %}</a>
|
||||
<a data-uid="{{ object.uuid }}" class="btn btn-xs btn-danger btn-del">{% trans "Delete" %}</a>
|
||||
<a data-uid="{{ object.id }}" class="btn btn-xs btn-danger btn-del">{% trans "Delete" %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{# comment #}
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('table').DataTable({
|
||||
"searching": false,
|
||||
"paging": false,
|
||||
"bInfo" : false,
|
||||
"order": []
|
||||
});
|
||||
$('.select2').select2();
|
||||
$('#date .input-daterange').datepicker({
|
||||
dateFormat: 'mm/dd/yy',
|
||||
keyboardNavigation: false,
|
||||
forceParse: false,
|
||||
autoclose: true
|
||||
});
|
||||
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('table').DataTable({
|
||||
"searching": false,
|
||||
"paging": false,
|
||||
"bInfo" : false,
|
||||
"order": []
|
||||
});
|
||||
$('.select2').select2();
|
||||
$('#date .input-daterange').datepicker({
|
||||
dateFormat: 'mm/dd/yy',
|
||||
keyboardNavigation: false,
|
||||
forceParse: false,
|
||||
autoclose: true
|
||||
});
|
||||
|
||||
}).on('click', '.btn-del', function () {
|
||||
var $this = $(this);
|
||||
var name = $(this).closest("tr").find(":nth-child(2)").children('a').html();
|
||||
var uid = $this.data('uid');
|
||||
var the_url = '{% url "api-ops:task-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
|
||||
objectDelete($this, name, the_url);
|
||||
})
|
||||
</script>
|
||||
}).on('click', '.btn-del', function () {
|
||||
var $this = $(this);
|
||||
var name = $(this).closest("tr").find(":nth-child(2)").children('a').html();
|
||||
var uid = $this.data('uid');
|
||||
var the_url = '{% url "api-ops:task-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
|
||||
objectDelete($this, name, the_url);
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -16,4 +16,7 @@ urlpatterns = [
|
|||
url(r'^task/(?P<pk>[0-9a-zA-Z\-]{36})/adhoc/$', views.TaskAdhocView.as_view(), name='task-adhoc'),
|
||||
url(r'^task/(?P<pk>[0-9a-zA-Z\-]{36})/history/$', views.TaskHistoryView.as_view(), name='task-history'),
|
||||
url(r'^task/(?P<pk>[0-9a-zA-Z\-]{36})/run/$', views.TaskRunView.as_view(), name='task-run'),
|
||||
]
|
||||
url(r'^adhoc/(?P<pk>[0-9a-zA-Z\-]{36})/$', views.AdHocDetailView.as_view(), name='adhoc-detail'),
|
||||
url(r'^adhoc/(?P<pk>[0-9a-zA-Z\-]{36})/history/$', views.AdHocHistoryView.as_view(), name='adhoc-history'),
|
||||
url(r'^adhoc/history/(?P<pk>[0-9a-zA-Z\-]{36})/$', views.AdHocHistoryDetailView.as_view(), name='adhoc-history-detail'),
|
||||
]
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
from __future__ import unicode_literals
|
||||
import time
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.conf import settings
|
||||
from django.views.generic import ListView, DetailView, View
|
||||
from django.utils import timezone
|
||||
|
@ -53,7 +53,7 @@ class TaskListView(ListView):
|
|||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': 'Ops',
|
||||
'action': 'Playbook record list',
|
||||
'action': _('Task list'),
|
||||
'date_from': self.date_from_s,
|
||||
'date_to': self.date_to_s,
|
||||
'keyword': self.keyword,
|
||||
|
@ -109,3 +109,42 @@ class TaskRunView(View):
|
|||
rerun_task.delay(pk)
|
||||
time.sleep(0.5)
|
||||
return redirect(reverse('ops:task-detail', kwargs={'pk': pk}))
|
||||
|
||||
|
||||
class AdHocDetailView(DetailView):
|
||||
model = AdHoc
|
||||
template_name = 'ops/adhoc_detail.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': 'Ops',
|
||||
'action': 'Task version detail',
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AdHocHistoryView(DetailView):
|
||||
model = AdHoc
|
||||
template_name = 'ops/adhoc_history.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': 'Ops',
|
||||
'action': 'Version run history',
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AdHocHistoryDetailView(DetailView):
|
||||
model = AdHocRunHistory
|
||||
template_name = 'ops/adhoc_history_detail.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': 'Ops',
|
||||
'action': 'Run history detail',
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super().get_context_data(**kwargs)
|
|
@ -65,5 +65,5 @@ class AssetPermission(models.Model):
|
|||
for system_user in self.system_users.all():
|
||||
cluster_remain = clusters - set(system_user.cluster.all())
|
||||
if cluster_remain:
|
||||
errors[system_user.name] = cluster_remain
|
||||
errors[system_user] = cluster_remain
|
||||
return errors
|
||||
|
|
|
@ -50,10 +50,11 @@ class MessageMixin:
|
|||
|
||||
@staticmethod
|
||||
def get_warning_messages(errors):
|
||||
message = "System user should in behind clusters, so that " \
|
||||
"system user auto push to cluster assets <br>"
|
||||
for system_user, clusters in errors:
|
||||
message += "{}: {} ".format(system_user.name, ", ".join(list(clusters)))
|
||||
message = "<b><i class='fa fa-warning'></i>WARNING: System user " \
|
||||
"should in behind clusters, so that " \
|
||||
"system user cat auto push to the cluster assets:</b> <br>"
|
||||
for system_user, clusters in errors.items():
|
||||
message += " >>> {}: {} ".format(system_user.name, ", ".join((cluster.name for cluster in clusters)))
|
||||
return message
|
||||
|
||||
def get_success_message(self, cleaned_data):
|
||||
|
|
Loading…
Reference in New Issue