Commit b60e5a7e authored by ibuler's avatar ibuler

[Change] 修改一些view

parent c940a4c0
...@@ -112,7 +112,12 @@ class Asset(models.Model): ...@@ -112,7 +112,12 @@ class Asset(models.Model):
'groups': [group.name for group in self.groups.all()], 'groups': [group.name for group in self.groups.all()],
'username': self.admin_user.username if self.admin_user else '', 'username': self.admin_user.username if self.admin_user else '',
'password': self.admin_user.password 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: class Meta:
......
...@@ -3,12 +3,14 @@ ...@@ -3,12 +3,14 @@
# #
from __future__ import unicode_literals from __future__ import unicode_literals
import os
import logging import logging
from hashlib import md5
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ 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 from common.utils import signer, validate_ssh_private_key, ssh_key_string_to_obj
...@@ -38,7 +40,7 @@ class AdminUser(models.Model): ...@@ -38,7 +40,7 @@ class AdminUser(models.Model):
become = models.BooleanField(default=True) become = models.BooleanField(default=True)
become_method = models.CharField(choices=BECOME_METHOD_CHOICES, default='sudo', max_length=4) become_method = models.CharField(choices=BECOME_METHOD_CHOICES, default='sudo', max_length=4)
become_user = models.CharField(default='root', max_length=64) 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( _public_key = models.CharField(
max_length=4096, blank=True, verbose_name=_('SSH public key')) max_length=4096, blank=True, verbose_name=_('SSH public key'))
comment = models.TextField(blank=True, verbose_name=_('Comment')) comment = models.TextField(blank=True, verbose_name=_('Comment'))
...@@ -74,6 +76,18 @@ class AdminUser(models.Model): ...@@ -74,6 +76,18 @@ class AdminUser(models.Model):
def private_key(self, private_key_raw): def private_key(self, private_key_raw):
self._private_key = signer.sign(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 @property
def public_key(self): def public_key(self):
return signer.unsign(self._public_key) 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 ...@@ -4,14 +4,16 @@ from .. import views
app_name = 'audits' app_name = 'audits'
urlpatterns = [ urlpatterns = [
url(r'^proxy-log$', views.ProxyLogListView.as_view(), url(r'^proxy-log-offline/$', views.ProxyLogOfflineListView.as_view(),
name='proxy-log-list'), name='proxy-log-offline-list'),
url(r'^proxy-log/(?P<pk>\d+)$', views.ProxyLogDetailView.as_view(), 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'), name='proxy-log-detail'),
# url(r'^proxy-log/(?P<pk>\d+)/commands$', views.ProxyLogCommandsListView.as_view(), name='proxy-log-commands-list'), # 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'), name='command-log-list'),
url(r'^login-log$', views.LoginLogListView.as_view(), url(r'^login-log/$', views.LoginLogListView.as_view(),
name='login-log-list'), name='login-log-list'),
] ]
......
...@@ -22,7 +22,7 @@ from audits.backends import CommandLogSerializer ...@@ -22,7 +22,7 @@ from audits.backends import CommandLogSerializer
class ProxyLogListView(AdminUserRequiredMixin, ListView): class ProxyLogListView(AdminUserRequiredMixin, ListView):
model = ProxyLog model = ProxyLog
template_name = 'audits/proxy_log_list.html' template_name = 'audits/proxy_log_online_list.html'
context_object_name = 'proxy_log_list' context_object_name = 'proxy_log_list'
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
keyword = user = asset = system_user = date_from_s = date_to_s = '' keyword = user = asset = system_user = date_from_s = date_to_s = ''
...@@ -89,6 +89,38 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView): ...@@ -89,6 +89,38 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
return super(ProxyLogListView, self).get_context_data(**kwargs) 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, class ProxyLogDetailView(AdminUserRequiredMixin,
SingleObjectMixin, SingleObjectMixin,
ListView): ListView):
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
# #
from __future__ import unicode_literals from __future__ import unicode_literals
from collections import OrderedDict
from six import string_types from six import string_types
import base64 import base64
import os import os
...@@ -53,6 +54,7 @@ def get_object_or_none(model, **kwargs): ...@@ -53,6 +54,7 @@ def get_object_or_none(model, **kwargs):
class Signer(object): class Signer(object):
"""用来加密,解密,和基于时间戳的方式验证token"""
def __init__(self, secret_key=SECRET_KEY): def __init__(self, secret_key=SECRET_KEY):
self.secret_key = secret_key self.secret_key = secret_key
...@@ -330,13 +332,13 @@ def encrypt_password(password): ...@@ -330,13 +332,13 @@ def encrypt_password(password):
return None return None
from collections import OrderedDict
def capacity_convert(size, expect='auto', rate=1000): def capacity_convert(size, expect='auto', rate=1000):
""" """
:param cap: '100MB', '1G' :param size: '100MB', '1G'
:param expect: 'K, M, G, T :param expect: 'K, M, G, T
:param rate: Default 1000, may be 1024
:return: :return:
""" """
rate_mapping = ( rate_mapping = (
......
...@@ -21,16 +21,16 @@ class JMSHost(Host): ...@@ -21,16 +21,16 @@ class JMSHost(Host):
# 添加密码和秘钥 # 添加密码和秘钥
if asset.get('password'): if asset.get('password'):
self.set_variable('ansible_ssh_pass', asset['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']) self.set_variable('ansible_ssh_private_key_file', asset['private_key'])
# 添加become支持 # 添加become支持
become = asset.get("become", None) become = asset.get("become", False)
if become is not None: if become:
self.set_variable("ansible_become", True) self.set_variable("ansible_become", True)
self.set_variable("ansible_become_method", become.get('method')) self.set_variable("ansible_become_method", become.get('method', 'sudo'))
self.set_variable("ansible_become_user", become.get('user')) self.set_variable("ansible_become_user", become.get('user', 'root'))
self.set_variable("ansible_become_pass", become.get('pass')) self.set_variable("ansible_become_pass", become.get('pass', ''))
else: else:
self.set_variable("ansible_become", False) self.set_variable("ansible_become", False)
......
...@@ -265,7 +265,9 @@ class AdHocRunner(object): ...@@ -265,7 +265,9 @@ class AdHocRunner(object):
result['success'].append(host) result['success'].append(host)
for host, msgs in self.results_callback.result_q['dark'].items(): for host, msgs in self.results_callback.result_q['dark'].items():
msg = '\n'.join(['{}: {}'.format(msg.get('invocation', {}).get('module_name'), msg = '\n'.join(['{} {}: {}'.format(
msg.get('module_stdout', ''),
msg.get('invocation', {}).get('module_name'),
msg.get('msg', '')) for msg in msgs]) msg.get('msg', '')) for msg in msgs])
result['failed'].append((host, msg)) result['failed'].append((host, msg))
return result return result
......
...@@ -68,7 +68,17 @@ ...@@ -68,7 +68,17 @@
</tr> </tr>
<tr> <tr>
<td>{% trans 'Is success ' %}:</td> <td>{% trans 'Is success ' %}:</td>
{% if object.is_finished %}
<td><b>{{ object.is_success|yesno:"Yes,No,Unkown" }}</b></td> <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>
<tr> <tr>
<td>{% trans 'Assets ' %}:</td> <td>{% trans 'Assets ' %}:</td>
...@@ -84,6 +94,31 @@ ...@@ -84,6 +94,31 @@
</table> </table>
</div> </div>
</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>
<div class="col-sm-5" style="padding-left: 0;padding-right: 0"> <div class="col-sm-5" style="padding-left: 0;padding-right: 0">
<div class="panel panel-danger"> <div class="panel panel-danger">
......
...@@ -18,7 +18,7 @@ logger = get_logger(__file__) ...@@ -18,7 +18,7 @@ logger = get_logger(__file__)
def run_AdHoc(task_tuple, assets, def run_AdHoc(task_tuple, assets,
task_name='Ansible AdHoc runner', task_name='Ansible AdHoc runner',
task_id=None, pattern='all', 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 task_tuple: (('module_name', 'module_args'), ('module_name', 'module_args'))
:param assets: [asset1, asset2] :param assets: [asset1, asset2]
...@@ -51,6 +51,11 @@ def run_AdHoc(task_tuple, assets, ...@@ -51,6 +51,11 @@ def run_AdHoc(task_tuple, assets,
else: else:
record = Task.objects.get(uuid=task_id) record = Task.objects.get(uuid=task_id)
record.date_start = timezone.now() 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() ts_start = time.time()
if verbose: if verbose:
logger.debug('Start runner {}'.format(task_name)) logger.debug('Start runner {}'.format(task_name))
...@@ -61,7 +66,7 @@ def run_AdHoc(task_tuple, assets, ...@@ -61,7 +66,7 @@ def run_AdHoc(task_tuple, assets,
record.date_finished = timezone.now() record.date_finished = timezone.now()
record.is_finished = True record.is_finished = True
if verbose: if verbose:
record.result = json.dumps(result) record.result = json.dumps(result, indent=4, sort_keys=True)
record.summary = json.dumps(summary) record.summary = json.dumps(summary)
record.timedelta = timedelta record.timedelta = timedelta
if len(summary['failed']) == 0: if len(summary['failed']) == 0:
......
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals from __future__ import unicode_literals
import time
import json import json
from datetime import datetime from datetime import datetime
...@@ -81,4 +82,5 @@ class TaskRunView(View): ...@@ -81,4 +82,5 @@ class TaskRunView(View):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
pk = kwargs.get(self.pk_url_kwarg) pk = kwargs.get(self.pk_url_kwarg)
rerun_task.delay(pk) rerun_task.delay(pk)
time.sleep(0.5)
return redirect(reverse('ops:task-detail', kwargs={'pk': pk})) return redirect(reverse('ops:task-detail', kwargs={'pk': pk}))
...@@ -35,10 +35,10 @@ def push_users(self, assets, users): ...@@ -35,10 +35,10 @@ def push_users(self, assets, users):
('authorized_key', "user={} state=present key='{}'".format( ('authorized_key', "user={} state=present key='{}'".format(
user['username'], user['public_key'])), user['username'], user['public_key'])),
('lineinfile', ('lineinfile',
"name=/etc/sudoers state=present regexp='^{0} ALL=(ALL)' " "dest=/etc/sudoers state=present regexp='^{0} ALL=' "
"line='{0} ALL=(ALL) NOPASSWD: {1}' " "line='{0} ALL=(ALL) NOPASSWD: {1}' "
"validate='visudo -cf %s'".format( "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])) task_name = 'Push user {}'.format(','.join([user['name'] for user in users]))
......
...@@ -56,8 +56,11 @@ ...@@ -56,8 +56,11 @@
<li id="audits"> <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> <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"> <ul class="nav nav-second-level">
<li id="proxy-log"> <li id="proxy-log-offline">
<a href="{% url 'audits:proxy-log-list' %}">{% trans 'Proxy log' %}</a> <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>
<li id="command-log"> <li id="command-log">
<a href="{% url 'audits:command-log-list' %}">{% trans 'Command log' %}</a> <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