Commit b60e5a7e authored by ibuler's avatar ibuler

[Change] 修改一些view

parent c940a4c0
......@@ -112,7 +112,12 @@ class Asset(models.Model):
'groups': [group.name for group in self.groups.all()],
'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,
'private_key': self.admin_user.private_key_file if self.admin_user else None,
'become': {
'method': self.admin_user.become_method,
'user': self.admin_user.become_user,
'pass': self.admin_user.become_pass,
} if self.admin_user.become else {},
}
class Meta:
......
......@@ -3,12 +3,14 @@
#
from __future__ import unicode_literals
import os
import logging
from hashlib import md5
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
from common.utils import signer, validate_ssh_private_key, ssh_key_string_to_obj
......@@ -38,7 +40,7 @@ class AdminUser(models.Model):
become = models.BooleanField(default=True)
become_method = models.CharField(choices=BECOME_METHOD_CHOICES, default='sudo', max_length=4)
become_user = models.CharField(default='root', max_length=64)
become_password = models.CharField(default='', max_length=128)
become_pass = models.CharField(default='', max_length=128)
_public_key = models.CharField(
max_length=4096, blank=True, verbose_name=_('SSH public key'))
comment = models.TextField(blank=True, verbose_name=_('Comment'))
......@@ -74,6 +76,18 @@ class AdminUser(models.Model):
def private_key(self, private_key_raw):
self._private_key = signer.sign(private_key_raw)
@property
def private_key_file(self):
if not self.private_key:
return None
project_dir = settings.PROJECT_DIR
tmp_dir = os.path.join(project_dir, 'tmp')
key_name = md5(self._private_key).hexdigest()
key_path = os.path.join(tmp_dir, key_name)
if not os.path.exists(key_path):
self.private_key.write_private_key_file(key_path)
return key_path
@property
def public_key(self):
return signer.unsign(self._public_key)
......
{% 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">
<select class="select2 form-control" name="username">
<option value="">{% trans 'User' %}</option>
{% for user in user_list %}
<option value="{{ user }}" {% if user == username %} selected {% endif %}>{{ user }}</option>
{% endfor %}
</select>
</div>
<div class="input-group">
<select class="select2 form-control" name="ip">
<option value="">{% trans 'Asset' %}</option>
{% for asset in asset_list %}
<option value="{{ asset }}" {% if asset == ip %} selected {% endif %}>{{ asset }}</option>
{% endfor %}
</select>
</div>
<div class="input-group">
<select class="select2 form-control" name="system_user">
<option value="">{% trans 'System user' %}</option>
{% for su in system_user_list %}
<option value="{{ su }}" {% if su == system_user %} selected {% endif %}>{{ su }}</option>
{% endfor %}
</select>
</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 class="text-center"></th>
<th class="text-center">{% trans 'ID' %}</th>
<th class="text-center">{% trans 'User' %}</th>
<th class="text-center">{% trans 'Asset' %}</th>
<th class="text-center">{% trans 'System user' %}</th>
<th class="text-center">{% trans 'Terminal' %}</th>
<th class="text-center">{% trans 'Command' %}</th>
<th class="text-center">{% trans 'Success' %}</th>
<th class="text-center">{% trans 'Finished' %}</th>
<th class="text-center">{% trans 'R/M' %}</th>
<th class="text-center">{% trans 'Date start' %}</th>
<th class="text-center">{% trans 'Time' %}</th>
{% endblock %}
{% block table_body %}
{% for proxy_log in proxy_log_list %}
<tr class="gradeX">
<td class="text-center"><input type="checkbox" class="cbx-term" value="{{ proxy_log.id }}"></td>
<td class="text-center">
<a href="{% url 'audits:proxy-log-detail' pk=proxy_log.id %}">{{ proxy_log.id }}</a>
</td>
<td class="text-center">{{ proxy_log.user }}</td>
<td class="text-center">{{ proxy_log.asset }}</td>
<td class="text-center">{{ proxy_log.system_user }}</td>
<td class="text-center">{{ proxy_log.terminal }}</td>
<td class="text-center">{{ proxy_log.commands.all|length}}</td>
<td class="text-center">
{% if proxy_log.is_failed %}
<i class="fa fa-times text-danger"></i>
{% else %}
<i class="fa fa-check text-navy"></i>
{% endif %}
</td>
{% if proxy_log.is_finished %}
<td class="text-center">
<i class="fa fa-check text-navy"></i>
</td>
<td class="text-center">
<a><span class="text-navy"><i class="fa fa-play-circle"></i></span></a>
</td>
{% else %}
<td class="text-center">
<a class="btn-term" value="{{ proxy_log.id }}"><i class="fa fa-times text-danger"></i></a>
</td>
<td class="text-center">
<a><span class="text-danger"><i class="fa fa-eye"></i></span></a>
</td>
{% endif %}
<td class="text-center">{{ proxy_log.date_start }}</td>
<td class="text-center">{{ proxy_log.date_finished|timeuntil:proxy_log.date_start }}</td>
</tr>
{% endfor %}
{% endblock %}
{% block content_bottom_left %}
<div id="actions">
<div class="input-group">
<select class="form-control m-b" style="width: auto" id="slct_bulk_update">
<option value="terminate">{% trans 'Terminate 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 custom_foot_js %}
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
<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 %}
......@@ -4,14 +4,16 @@ from .. import views
app_name = 'audits'
urlpatterns = [
url(r'^proxy-log$', views.ProxyLogListView.as_view(),
name='proxy-log-list'),
url(r'^proxy-log/(?P<pk>\d+)$', views.ProxyLogDetailView.as_view(),
url(r'^proxy-log-offline/$', views.ProxyLogOfflineListView.as_view(),
name='proxy-log-offline-list'),
url(r'^proxy-log-online/$', views.ProxyLogOnlineListView.as_view(),
name='proxy-log-online-list'),
url(r'^proxy-log/(?P<pk>\d+)/$', views.ProxyLogDetailView.as_view(),
name='proxy-log-detail'),
# url(r'^proxy-log/(?P<pk>\d+)/commands$', views.ProxyLogCommandsListView.as_view(), name='proxy-log-commands-list'),
url(r'^command-log$', views.CommandLogListView.as_view(),
url(r'^command-log/$', views.CommandLogListView.as_view(),
name='command-log-list'),
url(r'^login-log$', views.LoginLogListView.as_view(),
url(r'^login-log/$', views.LoginLogListView.as_view(),
name='login-log-list'),
]
......
......@@ -22,7 +22,7 @@ from audits.backends import CommandLogSerializer
class ProxyLogListView(AdminUserRequiredMixin, ListView):
model = ProxyLog
template_name = 'audits/proxy_log_list.html'
template_name = 'audits/proxy_log_online_list.html'
context_object_name = 'proxy_log_list'
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
keyword = user = asset = system_user = date_from_s = date_to_s = ''
......@@ -89,6 +89,38 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
return super(ProxyLogListView, self).get_context_data(**kwargs)
class ProxyLogOfflineListView(ProxyLogListView):
template_name = 'audits/proxy_log_online_list.html'
def get_queryset(self):
queryset = super(ProxyLogOfflineListView, self).get_queryset()
queryset = queryset.filter(is_finished=True)
return queryset
def get_context_data(self, **kwargs):
context = {
'action': _('Proxy log offline list'),
}
kwargs.update(context)
return super(ProxyLogOfflineListView, self).get_context_data(**kwargs)
class ProxyLogOnlineListView(ProxyLogListView):
template_name = 'audits/proxy_log_online_list.html'
def get_queryset(self):
queryset = super(ProxyLogOnlineListView, self).get_queryset()
queryset = queryset.filter(is_finished=False)
return queryset
def get_context_data(self, **kwargs):
context = {
'action': _('Proxy log online list'),
}
kwargs.update(context)
return super(ProxyLogOnlineListView, self).get_context_data(**kwargs)
class ProxyLogDetailView(AdminUserRequiredMixin,
SingleObjectMixin,
ListView):
......
......@@ -2,6 +2,7 @@
#
from __future__ import unicode_literals
from collections import OrderedDict
from six import string_types
import base64
import os
......@@ -53,6 +54,7 @@ def get_object_or_none(model, **kwargs):
class Signer(object):
"""用来加密,解密,和基于时间戳的方式验证token"""
def __init__(self, secret_key=SECRET_KEY):
self.secret_key = secret_key
......@@ -330,13 +332,13 @@ def encrypt_password(password):
return None
from collections import OrderedDict
def capacity_convert(size, expect='auto', rate=1000):
"""
:param cap: '100MB', '1G'
:param size: '100MB', '1G'
:param expect: 'K, M, G, T
:param rate: Default 1000, may be 1024
:return:
"""
rate_mapping = (
......
......@@ -21,16 +21,16 @@ class JMSHost(Host):
# 添加密码和秘钥
if asset.get('password'):
self.set_variable('ansible_ssh_pass', asset['password'])
if asset.get('key'):
if asset.get('private_key'):
self.set_variable('ansible_ssh_private_key_file', asset['private_key'])
# 添加become支持
become = asset.get("become", None)
if become is not None:
become = asset.get("become", False)
if become:
self.set_variable("ansible_become", True)
self.set_variable("ansible_become_method", become.get('method'))
self.set_variable("ansible_become_user", become.get('user'))
self.set_variable("ansible_become_pass", become.get('pass'))
self.set_variable("ansible_become_method", become.get('method', 'sudo'))
self.set_variable("ansible_become_user", become.get('user', 'root'))
self.set_variable("ansible_become_pass", become.get('pass', ''))
else:
self.set_variable("ansible_become", False)
......
......@@ -265,8 +265,10 @@ class AdHocRunner(object):
result['success'].append(host)
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])
msg = '\n'.join(['{} {}: {}'.format(
msg.get('module_stdout', ''),
msg.get('invocation', {}).get('module_name'),
msg.get('msg', '')) for msg in msgs])
result['failed'].append((host, msg))
return result
......
......@@ -68,7 +68,17 @@
</tr>
<tr>
<td>{% trans 'Is success ' %}:</td>
{% if object.is_finished %}
<td><b>{{ object.is_success|yesno:"Yes,No,Unkown" }}</b></td>
{% else %}
<td>
<div class="progress progress-striped active">
<div style="width: 50%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="75" role="progressbar" class="progress-bar progress-bar-danger">
<span class="sr-only">40% Complete (success)</span>
</div>
</div>
</td>
{% endif %}
</tr>
<tr>
<td>{% trans 'Assets ' %}:</td>
......@@ -84,6 +94,31 @@
</table>
</div>
</div>
<div class="ibox float-e-margins">
<div class="ibox-title">
<span><b>Result</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">
<pre>
{{ object.result }}
</pre>
</div>
</div>
</div>
</div>
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
<div class="panel panel-danger">
......
......@@ -18,7 +18,7 @@ logger = get_logger(__file__)
def run_AdHoc(task_tuple, assets,
task_name='Ansible AdHoc runner',
task_id=None, pattern='all',
record=True, verbose=False):
record=True, verbose=True):
"""
:param task_tuple: (('module_name', 'module_args'), ('module_name', 'module_args'))
:param assets: [asset1, asset2]
......@@ -51,6 +51,11 @@ def run_AdHoc(task_tuple, assets,
else:
record = Task.objects.get(uuid=task_id)
record.date_start = timezone.now()
record.date_finished = None
record.timedelta = None
record.is_finished = False
record.is_success = False
record.save()
ts_start = time.time()
if verbose:
logger.debug('Start runner {}'.format(task_name))
......@@ -61,7 +66,7 @@ def run_AdHoc(task_tuple, assets,
record.date_finished = timezone.now()
record.is_finished = True
if verbose:
record.result = json.dumps(result)
record.result = json.dumps(result, indent=4, sort_keys=True)
record.summary = json.dumps(summary)
record.timedelta = timedelta
if len(summary['failed']) == 0:
......
# ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals
import time
import json
from datetime import datetime
......@@ -81,4 +82,5 @@ class TaskRunView(View):
def get(self, request, *args, **kwargs):
pk = kwargs.get(self.pk_url_kwarg)
rerun_task.delay(pk)
time.sleep(0.5)
return redirect(reverse('ops:task-detail', kwargs={'pk': pk}))
......@@ -35,10 +35,10 @@ def push_users(self, assets, users):
('authorized_key', "user={} state=present key='{}'".format(
user['username'], user['public_key'])),
('lineinfile',
"name=/etc/sudoers state=present regexp='^{0} ALL=(ALL)' "
"dest=/etc/sudoers state=present regexp='^{0} ALL=' "
"line='{0} ALL=(ALL) NOPASSWD: {1}' "
"validate='visudo -cf %s'".format(
user['username'], user.get('sudo', '/bin/whoami')
user['username'], user.get('sudo', '/sbin/ifconfig')
))
])
task_name = 'Push user {}'.format(','.join([user['name'] for user in users]))
......
......@@ -56,8 +56,11 @@
<li id="audits">
<a href="#"><i class="fa fa-files-o"></i> <span class="nav-label">{% trans 'Audits' %}</span><span class="fa arrow"></span></a>
<ul class="nav nav-second-level">
<li id="proxy-log">
<a href="{% url 'audits:proxy-log-list' %}">{% trans 'Proxy log' %}</a>
<li id="proxy-log-offline">
<a href="{% url 'audits:proxy-log-offline-list' %}">{% trans 'Session online' %}</a>
</li>
<li id="proxy-log-online">
<a href="{% url 'audits:proxy-log-online-list' %}">{% trans 'Session history' %}</a>
</li>
<li id="command-log">
<a href="{% url 'audits:command-log-list' %}">{% trans 'Command log' %}</a>
......
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