Commit 91587313 authored by ibuler's avatar ibuler

[Fixture] 添加runner run record

parent a822f667
......@@ -23,19 +23,16 @@ class AssetCreateForm(forms.ModelForm):
self.instance.tags.clear()
self.instance.tags.add(*tuple(tags))
# def clean(self):
# clean_data = super(AssetCreateForm, self).clean()
# ip = clean_data.get('ip')
# port = clean_data.get('port')
# query = Asset.objects.filter(ip=ip, port=port)
# if query:
# raise forms.ValidationError('this asset has exists.')
def clean_admin_user(self):
if not self.cleaned_data['admin_user']:
raise forms.ValidationError(_('Select admin user'))
return self.cleaned_data['admin_user']
class Meta:
model = Asset
tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all())
fields = [
'hostname', 'ip', 'port', 'type', 'comment', 'admin_user', 'system_users', 'idc', 'groups',
'hostname', 'ip', 'port', 'type', 'comment', 'admin_user', 'idc', 'groups',
'other_ip', 'remote_card_ip', 'mac_address', 'brand', 'cpu', 'memory', 'disk', 'os', 'cabinet_no',
'cabinet_pos', 'number', 'status', 'env', 'sn', 'tags',
]
......@@ -44,8 +41,6 @@ class AssetCreateForm(forms.ModelForm):
'data-placeholder': _('Select asset groups')}),
'tags': forms.SelectMultiple(attrs={'class': 'select2',
'data-placeholder': _('Select asset tags')}),
'system_users': forms.SelectMultiple(attrs={'class': 'select2',
'data-placeholder': _('Select asset system users')}),
'admin_user': forms.Select(attrs={'class': 'select2', 'data-placeholder': _('Select asset admin user')}),
}
help_texts = {
......
......@@ -94,9 +94,9 @@ class Asset(models.Model):
'ip': self.ip,
'port': self.port,
'groups': [group.name for group in self.groups.all()],
'username': self.admin_user.username,
'password': self.admin_user.password,
'private_key': self.admin_user.private_key,
'username': self.admin_user.username if self.admin_user else '',
'password': self.admin_user.password if self.admin_user else '',
'private_key': self.admin_user.private_key if self.admin_user else None,
}
class Meta:
......
......@@ -20,7 +20,6 @@
<div class="hr-line-dashed"></div>
<h3>{% trans 'Asset user' %}</h3>
{{ form.admin_user|bootstrap_horizontal }}
{{ form.system_users|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
<h3>{% trans 'Other' %}</h3>
......
......@@ -25,7 +25,6 @@
<div class="hr-line-dashed"></div>
<h3>{% trans 'Asset user' %}</h3>
{{ form.admin_user|bootstrap_horizontal }}
{{ form.system_users|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
<h3>{% trans 'Hardware' %}</h3>
......
......@@ -2,6 +2,8 @@
from __future__ import unicode_literals, absolute_import
import logging
from collections import OrderedDict
import json
from django.db import models
from django.utils.translation import ugettext_lazy as _
......@@ -17,10 +19,14 @@ class TaskRecord(models.Model):
name = models.CharField(max_length=128, blank=True, verbose_name=_('Name'))
date_start = models.DateTimeField(auto_now_add=True, verbose_name=_('Start time'))
date_finished = models.DateTimeField(blank=True, null=True, verbose_name=_('End time'))
timedelta = models.FloatField(default=0.0, verbose_name=_('Time'), null=True)
is_finished = models.BooleanField(default=False, verbose_name=_('Is finished'))
is_success = models.BooleanField(default=False, verbose_name=_('Is success'))
assets = models.TextField(blank=True, null=True, verbose_name=_('Assets'))
result = models.TextField(blank=True, null=True, verbose_name=_('Task result'))
assets = models.TextField(blank=True, null=True, verbose_name=_('Assets for hostname')) # Asset inventory may be change
_modules_args = models.TextField(blank=True, null=True, verbose_name=_('Task module and args json format'))
pattern = models.CharField(max_length=64, default='all', verbose_name=_('Task run pattern'))
result = models.TextField(blank=True, null=True, verbose_name=_('Task raw result'))
summary = models.TextField(blank=True, null=True, verbose_name=_('Task summary'))
def __unicode__(self):
return "%s" % self.uuid
......@@ -29,3 +35,25 @@ class TaskRecord(models.Model):
def total_assets(self):
return self.assets.split(',')
@property
def assets_json(self):
from assets.models import Asset
return [Asset.objects.get(hostname=hostname)._to_secret_json()
for hostname in self.total_assets
if Asset.objects.exists(hostname=hostname)]
@property
def module_args(self):
task_tuple = []
for module, args in json.loads(self._modules_args, object_pairs_hook=OrderedDict).items():
task_tuple.append((module, args))
return task_tuple
@module_args.setter
def module_args(self, task_tuple):
module_args_ = OrderedDict({})
for module, args in task_tuple:
module_args_[module] = args
self._modules_args = json.dumps(module_args_)
# coding: utf-8
from __future__ import absolute_import, unicode_literals
import json
import time
......@@ -33,13 +34,50 @@ def asset_test_ping_check(assets):
return result['contacted'].keys(), result['dark'].keys()
@shared_task(bind=True)
def run_AdHoc(self, task_tuple, assets,
task_name='Ansible AdHoc runner', pattern='all', record=True):
runner = AdHocRunner(assets)
if record:
from .models import TaskRecord
if not TaskRecord.objects.filter(uuid=self.request.id):
record = TaskRecord(uuid=self.request.id,
name=task_name,
assets=','.join(asset['hostname'] for asset in assets),
module_args=task_tuple,
pattern=pattern)
record.save()
else:
record = TaskRecord.objects.get(uuid=self.request.id)
record.date_start = timezone.now()
ts_start = time.time()
logger.warn('Start runner {}'.format(task_name))
result = runner.run(task_tuple, pattern=pattern, task_name=task_name)
timedelta = round(time.time() - ts_start, 2)
summary = runner.clean_result()
if record:
record.date_finished = timezone.now()
record.is_finished = True
record.result = json.dumps(result)
record.summary = json.dumps(summary)
record.timedelta = timedelta
if len(summary['failed']) == 0:
record.is_success = True
else:
record.is_success = False
record.save()
return summary
@shared_task(bind=True)
def push_users(self, assets, users):
"""
user: {
username: xxx,
shell: /bin/bash,
password: 'staf',
name: 'web',
username: 'web',
shell: '/bin/bash',
password: '123123123',
public_key: 'string',
sudo: '/bin/whoami,/sbin/ifconfig'
}
......@@ -49,8 +87,8 @@ def push_users(self, assets, users):
if isinstance(assets, dict):
assets = [assets]
task_tuple = []
for user in users:
logger.debug('Push user: {}'.format(user))
# 添加用户, 设置公钥, 设置sudo
task_tuple.extend([
('user', 'name={} shell={} state=present password={}'.format(
......@@ -65,16 +103,19 @@ def push_users(self, assets, users):
user['username'], user.get('sudo', '/bin/whoami')
))
])
record = TaskRecord(name='Push user',
task_name = 'Push user {}'.format(','.join([user['name'] for user in users]))
record = TaskRecord(name=task_name,
uuid=self.request.id,
date_start=timezone.now(),
assets=','.join(asset['hostname'] for asset in assets))
record.save()
logger.info('Runner start {0}'.format(timezone.now()))
logger.info('Runner {0} start {1}'.format(task_name, timezone.now()))
hoc = AdHocRunner(assets)
ts_start = time.time()
_ = hoc.run(task_tuple)
logger.info('Runner complete {0}'.format(timezone.now()))
logger.info('Runner {0} complete {1}'.format(task_name, timezone.now()))
result_clean = hoc.clean_result()
record.time = int(time.time() - ts_start)
record.date_finished = timezone.now()
record.is_finished = True
......@@ -82,6 +123,6 @@ def push_users(self, assets, users):
record.is_success = True
else:
record.is_success = False
record.result = result_clean
record.result = json.dumps(result_clean)
record.save()
return result_clean
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% load bootstrap %}
{% block custom_head_css_js %}
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
<link href="{% static "css/plugins/datepicker/datepicker3.css" %}" rel="stylesheet">
{% 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="ibox-title">
<h5>{% block user_template_title %}{% trans 'Create user' %}{% endblock %}</h5>
<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>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
{% csrf_token %}
<h3>{% trans 'Account' %}</h3>
{% block username %} {% endblock %}
{{ form.email|bootstrap_horizontal }}
{{ form.name|bootstrap_horizontal }}
{{ form.groups|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
{% block password %} {% endblock %}
<div class="hr-line-dashed"></div>
<h3>{% trans 'Security and Role' %}</h3>
{{ form.role|bootstrap_horizontal }}
<div class="form-group {% if form.date_expired.errors %} has-error {% endif %}" id="date_5">
<label for="{{ form.date_expired.id_for_label }}" class="col-sm-2 control-label">{{ form.date_expired.label }}</label>
<div class="col-sm-9">
<div class="input-group date">
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
<input id="{{ form.date_expired.id_for_label }}" name="{{ form.date_expired.html_name }}" type="text" class="form-control" value="{{ form.date_expired.value|date:'Y-m-d' }}">
</div>
<span class="help-block ">{{ form.date_expired.errors }}</span>
</div>
</div>
{# {{ form.date_expired|bootstrap_horizontal }}#}
<div class="form-group">
<label for="{{ form.enable_otp.id_for_label }}" class="col-sm-2 control-label">{% trans 'Enable OTP' %}</label>
<div class="col-sm-8">
{{ form.enable_otp }}
</div>
</div>
<div class="hr-line-dashed"></div>
<h3>{% trans 'Profile' %}</h3>
{{ form.phone|bootstrap_horizontal }}
{{ form.wechat|bootstrap_horizontal }}
{{ form.comment|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="reset">{% trans 'Reset' %}</button>
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/plugins/datapicker/bootstrap-datepicker.js' %}"></script>
<script>
$(document).ready(function () {
$('.select2').select2();
$('.input-group.date').datepicker({
format: "yyyy-mm-dd",
todayBtn: "linked",
keyboardNavigation: false,
forceParse: false,
calendarWeeks: true,
autoclose: true
});
})
</script>
{% endblock %}
{% extends 'cron/_cron.html' %}
{% load i18n %}
{% load bootstrap %}
{% block user_template_title %}{% trans "Create user" %}{% endblock %}
{% block username %}
{{ form.username|bootstrap_horizontal }}
{% endblock %}
{% block password %}
<h3>{% trans 'Password' %}</h3>
<div class="form-group">
<label class="col-sm-2 control-label">{% trans 'Password' %}</label>
<div class="col-sm-8 controls" >
{% trans 'Reset link will be generated and sent to the user. ' %}
</div>
</div>
{% endblock %}
\ No newline at end of file
This diff is collapsed.
{% extends '_base_list.html' %}
{% load i18n static %}
{% block table_search %}
{% endblock %}
{% block table_container %}
<div class="uc pull-left m-l-5 m-r-5"><a href="{% url "users:user-create" %}" class="btn btn-sm btn-primary"> {% trans "Create cron" %} </a></div>
{#<div class="uc pull-left"><a href="javascript:void(0);" class="btn btn-sm btn-primary" data-toggle="modal" data-target="#user_import_modal"> {% trans "Import user" %} </a></div>#}
<table class="table table-striped table-bordered table-hover " id="cron_list_table">
<thead>
<tr>
<th class="text-center">
{# <div><input id="" type="checkbox" class="ipt_check_all"><label></label></div>#}
<input id="" type="checkbox" class="ipt_check_all">
</th>
<th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'Time(minute-hour-day-month-weekday)' %}</th>
<th class="text-center">{% trans 'Job' %}</th>
<th class="text-center">{% trans 'User' %}</th>
<th class="text-center">{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div id="actions" class="hide">
<div class="input-group">
<select class="form-control m-b" style="width: auto" id="slct_bulk_update">
<option value="delete">{% trans 'Delete selected' %}</option>
<option value="update">{% trans 'Update selected' %}</option>
<option value="deactive">{% trans 'Deactive selected' %}</option>
</select>
<div class="input-group-btn pull-left" style="padding-left: 5px;">
<button id='btn_bulk_update' style="height: 32px;" class="btn btn-sm btn-primary">
{% trans 'Submit' %}
</button>
</div>
</div>
</div>
{% include "users/_user_bulk_update_modal.html" %}
{#{% include "users/_user_import_modal.html" %}#}
{% endblock %}
{% block content_bottom_left %}{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/jquery.form.min.js' %}"></script>
<script>
$(document).ready(function(){
var options = {
ele: $('#cron_list_table'),
columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) {
var detail_btn = '<a href="{% url "ops:page-cron-detail" pk=99991937 %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('99991937', rowData.id));
}},
{targets: 2, createdCell: function (td, cellData, rowData) {
var cron_time_tmp = "{0}-{1}-{2}-{3}-{4}";
var cron_time = cron_time_tmp.format(rowData.minute, rowData.hour, rowData.day, rowData.month, rowData.weekday);
var innerHtml = '<span>' + cron_time + '</span>';
$(td).html(innerHtml.replace('99991937', rowData.id));
}},
{targets: 5, createdCell: function (td, cellData, rowData) {
var job_btn = '<a href="{% url "users:user-update" pk=99991937 %}" class="btn btn-xs btn-primary m-l-xs">{% trans "Job" %}</a>'.replace('99991937', cellData);
var update_btn = '<a href="{% url "users:user-update" pk=99991937 %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('99991937', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_user_delete" data-uid="99991937">{% trans "Delete" %}</a>'.replace('99991937', cellData);
if (rowData.id === 1 || rowData.username == "admin") {
$(td).html(update_btn)
} else {
$(td).html(job_btn + update_btn + del_btn)
}
}}],
ajax_url: '{% url "api-ops:crontable-list" %}',
columns: [{data: "id"}, {data: "name" }, {data: "month" }, {data: "job" }, {data: "user" }, {data: "id" }],
op_html: $('#actions').html()
};
var table = jumpserver.initDataTable(options);
$('.buttons-pdf').click(function () {
var users = [];
var rows = table.rows('.selected').data();
$.each(rows, function (index, obj) {
users.push(obj.id)
})
});
}).on('click', '#btn_bulk_update', function(){
var action = $('#slct_bulk_update').val();
var $data_table = $('#cron_list_table').DataTable();
var id_list = [];
var plain_id_list = [];
$data_table.rows({selected: true}).every(function(){
id_list.push({id: this.data().id});
plain_id_list.push(this.data().id);
});
if (id_list === []) {
return false;
}
var the_url = "{% url 'api-users:user-list' %}";
function doDeactive() {
var body = $.each(id_list, function(index, user_object) {
user_object['is_active'] = false;
});
APIUpdateAttr({url: the_url, method: 'PATCH', body: JSON.stringify(body)});
$data_table.ajax.reload();
jumpserver.checked = false;
}
function doDelete() {
swal({
title: "{% trans 'Are you sure?' %}",
text: "{% trans 'This will delete the selected users !!!' %}",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "{% trans 'Confirm' %}",
closeOnConfirm: false
}, function() {
var success = function() {
var msg = "{% trans 'User Deleted.' %}";
swal("{% trans 'User Delete' %}", msg, "success");
$('#cron_list_table').DataTable().ajax.reload();
};
var fail = function() {
var msg = "{% trans 'User Deleting failed.' %}";
swal("{% trans 'User Delete' %}", msg, "error");
};
var url_delete = the_url + '?id__in=' + JSON.stringify(plain_id_list);
APIUpdateAttr({url: url_delete, method: 'DELETE', success: success, error: fail});
jumpserver.checked = false;
});
}
function doUpdate() {
$('#user_bulk_update_modal').modal('show');
}
switch(action) {
case 'deactive':
doDeactive();
break;
case 'delete':
doDelete();
break;
case 'update':
doUpdate();
break;
default:
break;
}
}).on('click', '.btn_user_delete', function(){
var $this = $(this);
function doDelete() {
var uid = $this.data('uid');
var the_url = '{% url "api-users:user-detail" pk=99991937 %}'.replace('99991937', uid);
var body = {};
var success = function() {
var msg = "{% trans 'User Deleted.' %}";
swal("{% trans 'User Delete' %}", msg, "success");
$('#cron_list_table').DataTable().ajax.reload();
};
var fail = function() {
var msg = "{% trans 'User Deleting failed.' %}";
swal("{% trans 'User Delete' %}", msg, "error");
};
APIUpdateAttr({
url: the_url,
body: JSON.stringify(body),
method: 'DELETE',
success: success,
error: fail
});
}
swal({
title: "{% trans 'Are you sure?' %}",
text: "{% trans 'This will delete the selected user.' %}",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "{% trans 'Confirm' %}",
closeOnConfirm: false
}, function() {
doDelete();
});
}).on('click', '#btn_user_bulk_update', function(){
var json_data = $('#fm_user_bulk_update').serializeObject();
var body = {};
body.enable_otp = (json_data.enable_otp === 'on')? true: false;
if (json_data.role != '') {
body.role = json_data.role;
}
if (json_data.groups != undefined) {
body.groups = json_data.groups;
}
if (typeof body.groups === 'string') {
body.groups = [parseInt(body.groups)]
} else if(typeof body.groups === 'array') {
new_groups = body.groups.map(Number);
body.groups = new_groups;
}
var $data_table = $('#cron_list_table').DataTable()
var post_list = [];
$data_table.rows({selected: true}).every(function(){
var content = Object.assign({id: this.data().id}, body);
post_list.push(content);
});
if (post_list === []) {
return false
}
var the_url = "{% url 'api-users:user-list' %}";
var success = function() {
var msg = "{% trans 'The selected users has been updated successfully.' %}";
swal("{% trans 'User Updated' %}", msg, "success");
$('#cron_list_table').DataTable().ajax.reload();
jumpserver.checked = false;
};
APIUpdateAttr({url: the_url, method: 'PATCH', body: JSON.stringify(post_list), success: success});
$('#user_bulk_update_modal').modal('hide');
}).on('click', '#btn_user_import', function() {
var $form = $('#fm_user_import');
$form.find('.help-block').remove();
function success (data) {
if (data.success === false) {
var $help = $form.find('.help-block');
$('<span />', {class: 'help-block text-danger'}).html(data.msg).insertAfter($('#id_excel'));
} else {
$('#user_import_modal').modal('hide');
var $data_table = $('#cron_list_table').DataTable();
toastr.success("{% trans 'Import User Success.' %}");
$data_table.ajax.reload();
}
}
$form.ajaxSubmit({success: success});
})
</script>
{% endblock %}
{% extends 'cron/_cron.html' %}
{% load i18n %}
{% block user_template_title %}{% trans "Update user" %}{% endblock %}
{% block username %}
<div class="form-group">
<label for="{{ form.username.id_for_label }}" class="col-sm-2 control-label">{% trans 'Username' %}</label>
<div class="col-sm-9 controls" >
<input id="{{ form.username.id_for_label }}" name="{{ form.username.html_name }}" type="text" value="{{ user_object.username }}" readonly class="form-control">
</div>
</div>
{% endblock %}
{% block password %}
<h3>{% trans 'Password' %}</h3>
<div class="form-group">
<label for="password" class="col-sm-2 control-label">{% trans 'Password' %}</label>
<div class="col-sm-9 controls" >
<input id="password" name="password" type="password" class="form-control">
</div>
</div>
{% endblock %}
{% extends '_base_list.html' %}
{% load i18n %}
{% load static %}
{% block content_left_head %}
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
<style>
#search_btn {
margin-bottom: 0;
}
</style>
{% endblock %}
{% block table_search %}
<form id="search_form" method="get" action="" class="pull-right form-inline">
<div class="form-group" id="date">
<div class="input-daterange input-group" id="datepicker">
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_from" value="{{ date_from }}">
<span class="input-group-addon">to</span>
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_to" value="{{ date_to }}">
</div>
</div>
<div class="input-group">
<input type="text" class="form-control input-sm" name="keyword" placeholder="Keyword" value="{{ keyword }}">
</div>
<div class="input-group">
<div class="input-group-btn">
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
搜索
</button>
</div>
</div>
</form>
{% endblock %}
{% block table_head %}
<th></th>
<th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'Asset' %}</th>
<th class="text-center">{% trans 'Success' %}</th>
<th class="text-center">{% trans 'Finished' %}</th>
<th class="text-center">{% trans 'Date start' %}</th>
<th class="text-center">{% trans 'Time' %}</th>
<th class="text-center">{% trans 'Action' %}</th>
{% endblock %}
{% block table_body %}
{% for object in task_record_list %}
<tr class="gradeX">
<td class="text-center"><input type="checkbox" class="cbx-term"> </td>
<td class="text-center"><a href="{% url 'ops:task-record-detail' pk=object.uuid %}">{{ object.name }}</a></td>
<td class="text-center">{{ object.total_assets|length }}</td>
<td class="text-center">
{% if object.is_success %}
<i class="fa fa-check text-navy"></i>
{% else %}
<i class="fa fa-times text-danger"></i>
{% endif %}
</td>
<td class="text-center">
{% if object.is_finished %}
<i class="fa fa-check text-navy"></i>
{% else %}
<i class="fa fa-times text-danger"></i>
{% endif %}
</td>
<td class="text-center">{{ object.date_start }}</td>
<td class="text-center">{{ object.timedelta }} s</td>
<td class="text-center">
<a href="" class="btn btn-xs btn-info">{% trans "Repush" %}</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>
{# function terminateConnection(data) {#}
{# function success() {#}
{# window.setTimeout(function () {#}
{# window.location.reload()#}
{# }, 300)#}
{# }#}
{# var the_url = "{% url 'api-applications:terminate-connection' %}";#}
{# APIUpdateAttr({url: the_url, method: 'POST', body: JSON.stringify(data), success: success, success_message: 'Terminate success'});#}
{# }#}
{# $(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-term', function () {#}
{# var $this = $(this);#}
{# var proxy_log_id = $this.attr('value');#}
{# var data = {#}
{# proxy_log_id: proxy_log_id#}
{# };#}
{# terminateConnection(data)#}
{# }).on('click', '#btn_bulk_update', function () {#}
{# var data = [];#}
{# $('.cbx-term:checked').each(function () {#}
{# data.push({proxy_log_id: $(this).attr('value')})#}
{# });#}
{# terminateConnection(data)#}
{# })#}
{# </script>#}
{% endblock %}
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% load bootstrap %}
{% block custom_head_css_js %}
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
<link href="{% static "css/plugins/datepicker/datepicker3.css" %}" rel="stylesheet">
{% 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="ibox-title">
<h5>{% block user_template_title %}{% trans 'Create user' %}{% endblock %}</h5>
<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>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
{% csrf_token %}
<h3>{% trans 'Account' %}</h3>
{% block username %} {% endblock %}
{{ form.email|bootstrap_horizontal }}
{{ form.name|bootstrap_horizontal }}
{{ form.groups|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
{% block password %} {% endblock %}
<div class="hr-line-dashed"></div>
<h3>{% trans 'Security and Role' %}</h3>
{{ form.role|bootstrap_horizontal }}
<div class="form-group {% if form.date_expired.errors %} has-error {% endif %}" id="date_5">
<label for="{{ form.date_expired.id_for_label }}" class="col-sm-2 control-label">{{ form.date_expired.label }}</label>
<div class="col-sm-9">
<div class="input-group date">
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
<input id="{{ form.date_expired.id_for_label }}" name="{{ form.date_expired.html_name }}" type="text" class="form-control" value="{{ form.date_expired.value|date:'Y-m-d' }}">
</div>
<span class="help-block ">{{ form.date_expired.errors }}</span>
</div>
</div>
{# {{ form.date_expired|bootstrap_horizontal }}#}
<div class="form-group">
<label for="{{ form.enable_otp.id_for_label }}" class="col-sm-2 control-label">{% trans 'Enable OTP' %}</label>
<div class="col-sm-8">
{{ form.enable_otp }}
</div>
</div>
<div class="hr-line-dashed"></div>
<h3>{% trans 'Profile' %}</h3>
{{ form.phone|bootstrap_horizontal }}
{{ form.wechat|bootstrap_horizontal }}
{{ form.comment|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="reset">{% trans 'Reset' %}</button>
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/plugins/datapicker/bootstrap-datepicker.js' %}"></script>
<script>
$(document).ready(function () {
$('.select2').select2();
$('.input-group.date').datepicker({
format: "yyyy-mm-dd",
todayBtn: "linked",
keyboardNavigation: false,
forceParse: false,
calendarWeeks: true,
autoclose: true
});
})
</script>
{% endblock %}
{% extends 'sudo/_sudo.html' %}
{% load i18n %}
{% load bootstrap %}
{% block user_template_title %}{% trans "Create user" %}{% endblock %}
{% block username %}
{{ form.username|bootstrap_horizontal }}
{% endblock %}
{% block password %}
<h3>{% trans 'Password' %}</h3>
<div class="form-group">
<label class="col-sm-2 control-label">{% trans 'Password' %}</label>
<div class="col-sm-8 controls" >
{% trans 'Reset link will be generated and sent to the user. ' %}
</div>
</div>
{% endblock %}
\ No newline at end of file
This diff is collapsed.
{% extends '_base_list.html' %}
{% load i18n static %}
{% block table_search %}
{% endblock %}
{% block table_container %}
<div class="uc pull-left m-l-5 m-r-5"><a href="{% url "users:user-create" %}" class="btn btn-sm btn-primary"> {% trans "Create sudo" %} </a></div>
{#<div class="uc pull-left"><a href="javascript:void(0);" class="btn btnbtn-sm btn-primary" data-toggle="modal" data-target="#user_import_modal"> {% trans "Import user" %} </a></div>#}
<table class="table table-striped table-bordered table-hover " id="sudo_list_table">
<thead>
<tr>
<th class="text-center">
<input id="" type="checkbox" class="ipt_check_all">
</th>
<th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'Privileges' %}</th>
<th class="text-center">{% trans 'Extra Lines' %}</th>
<th class="text-center">{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div id="actions" class="hide">
<div class="input-group">
<select class="form-control m-b" style="width: auto" id="slct_bulk_update">
<option value="delete">{% trans 'Delete selected' %}</option>
<option value="update">{% trans 'Update selected' %}</option>
<option value="deactive">{% trans 'Deactive selected' %}</option>
</select>
<div class="input-group-btn pull-left" style="padding-left: 5px;">
<button id='btn_bulk_update' style="height: 32px;" class="btn btn-sm btn-primary">
{% trans 'Submit' %}
</button>
</div>
</div>
</div>
{#{% include "users/_user_bulk_update_modal.html" %}#}
{#{% include "users/_user_import_modal.html" %}#}
{% endblock %}
{% block content_bottom_left %}{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/jquery.form.min.js' %}"></script>
<script>
$(document).ready(function(){
var options = {
ele: $('#sudo_list_table'),
columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) {
var detail_btn = '<a href="{% url "ops:page-sudo-detail" pk=99991937 %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('99991937', rowData.id));
}},
{targets: 4, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "users:user-update" pk=99991937 %}" class="btn btn-xs btn-info m-l-xs">{% trans "Update" %}</a>'.replace('99991937', cellData);
var preview_btn = '<a href="{% url "users:user-update" pk=99991937 %}" class="btn btn-xs btn-info m-l-xs">{% trans "Preview" %}</a>'.replace('99991937', cellData);
var job_btn = '<a href="{% url "users:user-update" pk=99991937 %}" class="btn btn-xs btn-primary m-l-xs">{% trans "Job" %}</a>'.replace('99991937', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_user_delete" data-uid="99991937">{% trans "Delete" %}</a>'.replace('99991937', cellData);
if (rowData.id === 1 || rowData.username == "admin") {
$(td).html(update_btn)
} else {
$(td).html(preview_btn + job_btn + update_btn + del_btn)
}
}}],
ajax_url: '{% url "api-ops:sudo-list" %}',
columns: [{data: "id"}, {data: "name" }, {data: "privilege_items" }, {data: "extra_lines" }, {data: "id" }],
op_html: $('#actions').html()
};
var table = jumpserver.initDataTable(options);
$('.buttons-pdf').click(function () {
var users = [];
var rows = table.rows('.selected').data();
$.each(rows, function (index, obj) {
users.push(obj.id)
})
});
}).on('click', '#btn_bulk_update', function(){
var action = $('#slct_bulk_update').val();
var $data_table = $('#sudo_list_table').DataTable();
var id_list = [];
var plain_id_list = [];
$data_table.rows({selected: true}).every(function(){
id_list.push({id: this.data().id});
plain_id_list.push(this.data().id);
});
if (id_list === []) {
return false;
}
var the_url = "{% url 'api-users:user-list' %}";
function doDeactive() {
var body = $.each(id_list, function(index, user_object) {
user_object['is_active'] = false;
});
APIUpdateAttr({url: the_url, method: 'PATCH', body: JSON.stringify(body)});
$data_table.ajax.reload();
jumpserver.checked = false;
}
function doDelete() {
swal({
title: "{% trans 'Are you sure?' %}",
text: "{% trans 'This will delete the selected users !!!' %}",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "{% trans 'Confirm' %}",
closeOnConfirm: false
}, function() {
var success = function() {
var msg = "{% trans 'User Deleted.' %}";
swal("{% trans 'User Delete' %}", msg, "success");
$('#sudo_list_table').DataTable().ajax.reload();
};
var fail = function() {
var msg = "{% trans 'User Deleting failed.' %}";
swal("{% trans 'User Delete' %}", msg, "error");
};
var url_delete = the_url + '?id__in=' + JSON.stringify(plain_id_list);
APIUpdateAttr({url: url_delete, method: 'DELETE', success: success, error: fail});
jumpserver.checked = false;
});
}
function doUpdate() {
$('#user_bulk_update_modal').modal('show');
}
switch(action) {
case 'deactive':
doDeactive();
break;
case 'delete':
doDelete();
break;
case 'update':
doUpdate();
break;
default:
break;
}
}).on('click', '.btn_user_delete', function(){
var $this = $(this);
function doDelete() {
var uid = $this.data('uid');
var the_url = '{% url "api-users:user-detail" pk=99991937 %}'.replace('99991937', uid);
var body = {};
var success = function() {
var msg = "{% trans 'User Deleted.' %}";
swal("{% trans 'User Delete' %}", msg, "success");
$('#sudo_list_table').DataTable().ajax.reload();
};
var fail = function() {
var msg = "{% trans 'User Deleting failed.' %}";
swal("{% trans 'User Delete' %}", msg, "error");
};
APIUpdateAttr({
url: the_url,
body: JSON.stringify(body),
method: 'DELETE',
success: success,
error: fail
});
}
swal({
title: "{% trans 'Are you sure?' %}",
text: "{% trans 'This will delete the selected user.' %}",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "{% trans 'Confirm' %}",
closeOnConfirm: false
}, function() {
doDelete();
});
}).on('click', '#btn_user_bulk_update', function(){
var json_data = $('#fm_user_bulk_update').serializeObject();
var body = {};
body.enable_otp = (json_data.enable_otp === 'on')? true: false;
if (json_data.role != '') {
body.role = json_data.role;
}
if (json_data.groups != undefined) {
body.groups = json_data.groups;
}
if (typeof body.groups === 'string') {
body.groups = [parseInt(body.groups)]
} else if(typeof body.groups === 'array') {
new_groups = body.groups.map(Number);
body.groups = new_groups;
}
var $data_table = $('#sudo_list_table').DataTable()
var post_list = [];
$data_table.rows({selected: true}).every(function(){
var content = Object.assign({id: this.data().id}, body);
post_list.push(content);
});
if (post_list === []) {
return false
}
var the_url = "{% url 'api-users:user-list' %}";
var success = function() {
var msg = "{% trans 'The selected users has been updated successfully.' %}";
swal("{% trans 'User Updated' %}", msg, "success");
$('#sudo_list_table').DataTable().ajax.reload();
jumpserver.checked = false;
};
APIUpdateAttr({url: the_url, method: 'PATCH', body: JSON.stringify(post_list), success: success});
$('#user_bulk_update_modal').modal('hide');
}).on('click', '#btn_user_import', function() {
var $form = $('#fm_user_import');
$form.find('.help-block').remove();
function success (data) {
if (data.success === false) {
var $help = $form.find('.help-block');
$('<span />', {class: 'help-block text-danger'}).html(data.msg).insertAfter($('#id_excel'));
} else {
$('#user_import_modal').modal('hide');
var $data_table = $('#sudo_list_table').DataTable();
toastr.success("{% trans 'Import User Success.' %}");
$data_table.ajax.reload();
}
}
$form.ajaxSubmit({success: success});
})
</script>
{% endblock %}
{% extends 'sudo/_sudo.html' %}
{% load i18n %}
{% block user_template_title %}{% trans "Update user" %}{% endblock %}
{% block username %}
<div class="form-group">
<label for="{{ form.username.id_for_label }}" class="col-sm-2 control-label">{% trans 'Username' %}</label>
<div class="col-sm-9 controls" >
<input id="{{ form.username.id_for_label }}" name="{{ form.username.html_name }}" type="text" value="{{ user_object.username }}" readonly class="form-control">
</div>
</div>
{% endblock %}
{% block password %}
<h3>{% trans 'Password' %}</h3>
<div class="form-group">
<label for="password" class="col-sm-2 control-label">{% trans 'Password' %}</label>
<div class="col-sm-9 controls" >
<input id="password" name="password" type="password" class="form-control">
</div>
</div>
{% endblock %}
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% load bootstrap %}
{% block custom_head_css_js %}
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
<link href="{% static "css/plugins/datepicker/datepicker3.css" %}" rel="stylesheet">
{% 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="ibox-title">
<h5>{% block user_template_title %}{% trans 'Create user' %}{% endblock %}</h5>
<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>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
{% csrf_token %}
<h3>{% trans 'Account' %}</h3>
{% block username %} {% endblock %}
{{ form.email|bootstrap_horizontal }}
{{ form.name|bootstrap_horizontal }}
{{ form.groups|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
{% block password %} {% endblock %}
<div class="hr-line-dashed"></div>
<h3>{% trans 'Security and Role' %}</h3>
{{ form.role|bootstrap_horizontal }}
<div class="form-group {% if form.date_expired.errors %} has-error {% endif %}" id="date_5">
<label for="{{ form.date_expired.id_for_label }}" class="col-sm-2 control-label">{{ form.date_expired.label }}</label>
<div class="col-sm-9">
<div class="input-group date">
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
<input id="{{ form.date_expired.id_for_label }}" name="{{ form.date_expired.html_name }}" type="text" class="form-control" value="{{ form.date_expired.value|date:'Y-m-d' }}">
</div>
<span class="help-block ">{{ form.date_expired.errors }}</span>
</div>
</div>
{# {{ form.date_expired|bootstrap_horizontal }}#}
<div class="form-group">
<label for="{{ form.enable_otp.id_for_label }}" class="col-sm-2 control-label">{% trans 'Enable OTP' %}</label>
<div class="col-sm-8">
{{ form.enable_otp }}
</div>
</div>
<div class="hr-line-dashed"></div>
<h3>{% trans 'Profile' %}</h3>
{{ form.phone|bootstrap_horizontal }}
{{ form.wechat|bootstrap_horizontal }}
{{ form.comment|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="reset">{% trans 'Reset' %}</button>
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/plugins/datapicker/bootstrap-datepicker.js' %}"></script>
<script>
$(document).ready(function () {
$('.select2').select2();
$('.input-group.date').datepicker({
format: "yyyy-mm-dd",
todayBtn: "linked",
keyboardNavigation: false,
forceParse: false,
calendarWeeks: true,
autoclose: true
});
})
</script>
{% endblock %}
{% extends 'sudo/_sudo.html' %}
{% load i18n %}
{% load bootstrap %}
{% block user_template_title %}{% trans "Create user" %}{% endblock %}
{% block username %}
{{ form.username|bootstrap_horizontal }}
{% endblock %}
{% block password %}
<h3>{% trans 'Password' %}</h3>
<div class="form-group">
<label class="col-sm-2 control-label">{% trans 'Password' %}</label>
<div class="col-sm-8 controls" >
{% trans 'Reset link will be generated and sent to the user. ' %}
</div>
</div>
{% endblock %}
\ No newline at end of file
{% extends '_base_list.html' %}
{% load i18n static %}
{% block table_search %}
{% endblock %}
{% block table_container %}
<div class="uc pull-left m-l-5 m-r-5"><a href="{% url "ops:page-task-create" %}" class="btn btn-sm btn-primary"> {% trans "Create task" %} </a></div>
{#<div class="uc pull-left"><a href="javascript:void(0);" class="btn btnbtn-sm btn-primary" data-toggle="modal" data-target="#user_import_modal"> {% trans "Import user" %} </a></div>#}
<table class="table table-striped table-bordered table-hover " id="sudo_list_table">
<thead>
<tr>
<th class="text-center">
<input id="" type="checkbox" class="ipt_check_all">
</th>
<th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'UUID' %}</th>
<th class="text-center">{% trans 'Start' %}</th>
<th class="text-center">{% trans 'Completed' %}</th>
<th class="text-center">{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div id="actions" class="hide">
<div class="input-group">
<select class="form-control m-b" style="width: auto" id="slct_bulk_update">
<option value="delete">{% trans 'Delete selected' %}</option>
<option value="update">{% trans 'Update selected' %}</option>
<option value="deactive">{% trans 'Deactive selected' %}</option>
</select>
<div class="input-group-btn pull-left" style="padding-left: 5px;">
<button id='btn_bulk_update' style="height: 32px;" class="btn btn-sm btn-primary">
{% trans 'Submit' %}
</button>
</div>
</div>
</div>
{% endblock %}
{% block content_bottom_left %}{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/jquery.form.min.js' %}"></script>
<script>
$(document).ready(function(){
var options = {
ele: $('#sudo_list_table'),
columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) {
var detail_btn = '<a href="{% url "ops:page-task-detail" pk=99991937 %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('99991937', rowData.id));
}},
{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) {
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_user_delete" data-uid="99991937">{% trans "Delete" %}</a>'.replace('99991937', cellData)
$(td).html(del_btn)
}}],
ajax_url: '{% url "api-ops:task-list" %}',
columns: [{data: "name"}, {data: "uuid" }, {data: "start" }, {data: "completed" }, {data: "id" }],
op_html: $('#actions').html()
};
var table = jumpserver.initDataTable(options);
$('.buttons-pdf').click(function () {
var users = [];
var rows = table.rows('.selected').data();
$.each(rows, function (index, obj) {
users.push(obj.id)
})
});
}).on('click', '#btn_bulk_update', function(){
var action = $('#slct_bulk_update').val();
var $data_table = $('#sudo_list_table').DataTable();
var id_list = [];
var plain_id_list = [];
$data_table.rows({selected: true}).every(function(){
id_list.push({id: this.data().id});
plain_id_list.push(this.data().id);
});
if (id_list === []) {
return false;
}
var the_url = "{% url 'api-users:user-list' %}";
function doDeactive() {
var body = $.each(id_list, function(index, user_object) {
user_object['is_active'] = false;
});
APIUpdateAttr({url: the_url, method: 'PATCH', body: JSON.stringify(body)});
$data_table.ajax.reload();
jumpserver.checked = false;
}
function doDelete() {
swal({
title: "{% trans 'Are you sure?' %}",
text: "{% trans 'This will delete the selected users !!!' %}",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "{% trans 'Confirm' %}",
closeOnConfirm: false
}, function() {
var success = function() {
var msg = "{% trans 'User Deleted.' %}";
swal("{% trans 'User Delete' %}", msg, "success");
$('#sudo_list_table').DataTable().ajax.reload();
};
var fail = function() {
var msg = "{% trans 'User Deleting failed.' %}";
swal("{% trans 'User Delete' %}", msg, "error");
};
var url_delete = the_url + '?id__in=' + JSON.stringify(plain_id_list);
APIUpdateAttr({url: url_delete, method: 'DELETE', success: success, error: fail});
jumpserver.checked = false;
});
}
function doUpdate() {
$('#user_bulk_update_modal').modal('show');
}
switch(action) {
case 'deactive':
doDeactive();
break;
case 'delete':
doDelete();
break;
case 'update':
doUpdate();
break;
default:
break;
}
}).on('click', '.btn_user_delete', function(){
var $this = $(this);
function doDelete() {
var uid = $this.data('uid');
var the_url = '{% url "api-users:user-detail" pk=99991937 %}'.replace('99991937', uid);
var body = {};
var success = function() {
var msg = "{% trans 'User Deleted.' %}";
swal("{% trans 'User Delete' %}", msg, "success");
$('#sudo_list_table').DataTable().ajax.reload();
};
var fail = function() {
var msg = "{% trans 'User Deleting failed.' %}";
swal("{% trans 'User Delete' %}", msg, "error");
};
APIUpdateAttr({
url: the_url,
body: JSON.stringify(body),
method: 'DELETE',
success: success,
error: fail
});
}
swal({
title: "{% trans 'Are you sure?' %}",
text: "{% trans 'This will delete the selected user.' %}",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "{% trans 'Confirm' %}",
closeOnConfirm: false
}, function() {
doDelete();
});
}).on('click', '#btn_user_bulk_update', function(){
var json_data = $('#fm_user_bulk_update').serializeObject();
var body = {};
body.enable_otp = (json_data.enable_otp === 'on')? true: false;
if (json_data.role != '') {
body.role = json_data.role;
}
if (json_data.groups != undefined) {
body.groups = json_data.groups;
}
if (typeof body.groups === 'string') {
body.groups = [parseInt(body.groups)]
} else if(typeof body.groups === 'array') {
new_groups = body.groups.map(Number);
body.groups = new_groups;
}
var $data_table = $('#sudo_list_table').DataTable()
var post_list = [];
$data_table.rows({selected: true}).every(function(){
var content = Object.assign({id: this.data().id}, body);
post_list.push(content);
});
if (post_list === []) {
return false
}
var the_url = "{% url 'api-users:user-list' %}";
var success = function() {
var msg = "{% trans 'The selected users has been updated successfully.' %}";
swal("{% trans 'User Updated' %}", msg, "success");
$('#sudo_list_table').DataTable().ajax.reload();
jumpserver.checked = false;
};
APIUpdateAttr({url: the_url, method: 'PATCH', body: JSON.stringify(post_list), success: success});
$('#user_bulk_update_modal').modal('hide');
}).on('click', '#btn_user_import', function() {
var $form = $('#fm_user_import');
$form.find('.help-block').remove();
function success (data) {
if (data.success === false) {
var $help = $form.find('.help-block');
$('<span />', {class: 'help-block text-danger'}).html(data.msg).insertAfter($('#id_excel'));
} else {
$('#user_import_modal').modal('hide');
var $data_table = $('#sudo_list_table').DataTable();
toastr.success("{% trans 'Import User Success.' %}");
$data_table.ajax.reload();
}
}
$form.ajaxSubmit({success: success});
})
</script>
{% endblock %}
{% extends 'sudo/_sudo.html' %}
{% load i18n %}
{% block user_template_title %}{% trans "Update user" %}{% endblock %}
{% block username %}
<div class="form-group">
<label for="{{ form.username.id_for_label }}" class="col-sm-2 control-label">{% trans 'Username' %}</label>
<div class="col-sm-9 controls" >
<input id="{{ form.username.id_for_label }}" name="{{ form.username.html_name }}" type="text" value="{{ user_object.username }}" readonly class="form-control">
</div>
</div>
{% endblock %}
{% block password %}
<h3>{% trans 'Password' %}</h3>
<div class="form-group">
<label for="password" class="col-sm-2 control-label">{% trans 'Password' %}</label>
<div class="col-sm-9 controls" >
<input id="password" name="password" type="password" class="form-control">
</div>
</div>
{% endblock %}
......@@ -3,11 +3,12 @@ from __future__ import unicode_literals
from django.conf.urls import url
from ops import views as page_view
from .. import views
__all__ = ["urlpatterns"]
urlpatterns = [
# TResource Task url
url(r'^task/list$', page_view.TaskListView.as_view(), name='page-task-list'),
url(r'^task-record/$', views.TaskRecordListView.as_view(), name='task-record-list'),
url(r'^task-record/(?P<pk>[0-9a-zA-Z-]+)/$', views.TaskRecordDetailView.as_view(), name='task-record-detail'),
]
\ No newline at end of file
# ~*~ coding: utf-8 ~*~
from collections import defaultdict
from ansible.plugins.callback import CallbackBase
class CommandResultCallback(CallbackBase):
def __init__(self, display=None):
self.result_q = dict(contacted={}, dark={})
super(CommandResultCallback, self).__init__(display)
def gather_result(self, n, res):
self.result_q[n][res._host.name] = {}
self.result_q[n][res._host.name]['cmd'] = res._result.get('cmd')
self.result_q[n][res._host.name]['stderr'] = res._result.get('stderr')
self.result_q[n][res._host.name]['stdout'] = res._result.get('stdout')
self.result_q[n][res._host.name]['rc'] = res._result.get('rc')
def v2_runner_on_ok(self, result):
self.gather_result("contacted", result)
def v2_runner_on_failed(self, result, ignore_errors=False):
self.gather_result("dark", result)
def v2_runner_on_unreachable(self, result):
self.gather_result("dark", result)
def v2_runner_on_skipped(self, result):
self.gather_result("dark", result)
class AdHocResultCallback(CallbackBase):
"""
Custom Callback
AdHoc result Callback
"""
def __init__(self, display=None):
self.result_q = dict(contacted={}, dark={})
......
......@@ -14,7 +14,8 @@ from ansible.utils.vars import load_extra_vars
from ansible.utils.vars import load_options_vars
from .inventory import JMSInventory
from .callback import AdHocResultCallback, PlaybookResultCallBack
from .callback import AdHocResultCallback, PlaybookResultCallBack, \
CommandResultCallback
from common.utils import get_logger
......@@ -29,6 +30,7 @@ class AnsibleError(StandardError):
pass
# Jumpserver not use playbook
class PlayBookRunner(object):
"""
用于执行AnsiblePlaybook的接口.简化Playbook对象的使用.
......@@ -136,6 +138,8 @@ class AdHocRunner(object):
]
)
results_callback_class = AdHocResultCallback
def __init__(self,
hosts=C.DEFAULT_HOST_LIST,
forks=C.DEFAULT_FORKS, # 5
......@@ -156,7 +160,7 @@ class AdHocRunner(object):
self.variable_manager = VariableManager()
self.loader = DataLoader()
self.gather_facts = gather_facts
self.results_callback = AdHocResultCallback()
self.results_callback = AdHocRunner.results_callback_class()
self.options = self.Options(
connection=connection_type,
timeout=timeout,
......@@ -171,7 +175,8 @@ class AdHocRunner(object):
private_key_file=private_key_file,
)
self.variable_manager.extra_vars = load_extra_vars(self.loader, options=self.options)
self.variable_manager.extra_vars = load_extra_vars(self.loader,
options=self.options)
self.variable_manager.options_vars = load_options_vars(self.options)
self.passwords = passwords or {}
self.inventory = JMSInventory(hosts)
......@@ -252,7 +257,7 @@ class AdHocRunner(object):
"""
:return: {
"success": ['hostname',],
"failed": [{'hostname': 'msg'}, {}],
"failed": [('hostname', 'msg'), {}],
}
"""
result = {'success': [], 'failed': []}
......@@ -262,26 +267,30 @@ class AdHocRunner(object):
for host, msgs in self.results_callback.result_q['dark'].items():
msg = '\n'.join(['{}: {}'.format(msg.get('invocation', {}).get('module_name'),
msg.get('msg', '')) for msg in msgs])
result['failed'].append({host: msg})
result['failed'].append((host, msg))
return result
def test_run():
assets = [
{
"hostname": "192.168.152.129",
"ip": "192.168.152.129",
"hostname": "192.168.244.129",
"ip": "192.168.244.129",
"port": 22,
"username": "root",
"password": "redhat",
},
]
task_tuple = (('shell', 'ls'), ('ping', ''))
task_tuple = (('shell', 'ls'),)
hoc = AdHocRunner(hosts=assets)
hoc.results_callback = CommandResultCallback()
ret = hoc.run(task_tuple)
print(ret)
play = PlayBookRunner(assets, playbook_path='/tmp/some.yml')
#play = PlayBookRunner(assets, playbook_path='/tmp/some.yml')
"""
# /tmp/some.yml
---
......@@ -293,7 +302,7 @@ def test_run():
- name: exec uptime
shell: uptime
"""
play.run()
#play.run()
if __name__ == "__main__":
......
# ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals
import json
from django.conf import settings
from django.views.generic.list import ListView
from django.views.generic import ListView, DetailView
from users.utils import AdminUserRequiredMixin
from .models import TaskRecord
class TaskListView(AdminUserRequiredMixin, ListView):
class TaskRecordListView(ListView):
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
model = TaskRecord
context_object_name = 'tasks'
template_name = 'task/list.html'
ordering = ('-date_start',)
context_object_name = 'task_record_list'
template_name = 'ops/task_record_list.html'
def get_context_data(self, **kwargs):
context = {
'task': 'Assets',
'action': 'Create asset',
'app': 'Ops',
'action': 'Task record list',
}
kwargs.update(context)
return super(TaskListView, self).get_context_data(**kwargs)
return super(TaskRecordListView, self).get_context_data(**kwargs)
class TaskRecordDetailView(DetailView):
model = TaskRecord
template_name = 'ops/task_record_detail.html'
def get_context_data(self, **kwargs):
context = {
'app': 'Ops',
'action': 'Task record detail',
'results': json.loads(self.object.summary),
}
kwargs.update(context)
return super(TaskRecordDetailView, self).get_context_data(**kwargs)
......@@ -49,7 +49,7 @@
<i class="fa fa-coffee"></i> <span class="nav-label">{% trans 'Job Center' %}</span><span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level">
<li id="task"><a href="{% url 'ops:page-task-list' %}">{% trans 'Task' %}</a></li>
<li id="task"><a href="{% url 'ops:task-record-list' %}">{% trans 'Task Record' %}</a></li>
</ul>
</li>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment