diff --git a/apps/assets/forms.py b/apps/assets/forms.py
index e6beb3e6e..0001eeea0 100644
--- a/apps/assets/forms.py
+++ b/apps/assets/forms.py
@@ -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 = {
diff --git a/apps/assets/models/asset.py b/apps/assets/models/asset.py
index 4fa70d25e..7386b23bc 100644
--- a/apps/assets/models/asset.py
+++ b/apps/assets/models/asset.py
@@ -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:
diff --git a/apps/assets/templates/assets/asset_create.html b/apps/assets/templates/assets/asset_create.html
index 1a4aa38d5..5fbe1b772 100644
--- a/apps/assets/templates/assets/asset_create.html
+++ b/apps/assets/templates/assets/asset_create.html
@@ -20,7 +20,6 @@
{% trans 'Asset user' %}
{{ form.admin_user|bootstrap_horizontal }}
- {{ form.system_users|bootstrap_horizontal }}
{% trans 'Other' %}
diff --git a/apps/assets/templates/assets/asset_update.html b/apps/assets/templates/assets/asset_update.html
index fb46c79d0..bd9f7bde8 100644
--- a/apps/assets/templates/assets/asset_update.html
+++ b/apps/assets/templates/assets/asset_update.html
@@ -25,7 +25,6 @@
{% trans 'Asset user' %}
{{ form.admin_user|bootstrap_horizontal }}
- {{ form.system_users|bootstrap_horizontal }}
{% trans 'Hardware' %}
diff --git a/apps/ops/models.py b/apps/ops/models.py
index 0bdc65ae6..b8c8054c7 100644
--- a/apps/ops/models.py
+++ b/apps/ops/models.py
@@ -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_)
+
+
diff --git a/apps/ops/tasks.py b/apps/ops/tasks.py
index 45de3e727..5e333195e 100644
--- a/apps/ops/tasks.py
+++ b/apps/ops/tasks.py
@@ -1,6 +1,7 @@
# 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
diff --git a/apps/ops/templates/cron/_cron.html b/apps/ops/templates/cron/_cron.html
deleted file mode 100644
index 59d03e5ee..000000000
--- a/apps/ops/templates/cron/_cron.html
+++ /dev/null
@@ -1,97 +0,0 @@
-{% extends 'base.html' %}
-{% load i18n %}
-{% load static %}
-{% load bootstrap %}
-{% block custom_head_css_js %}
-
-
-
-{% endblock %}
-
-{% block content %}
-
-
-
-
-
-
{% block user_template_title %}{% trans 'Create user' %}{% endblock %}
-
-
-
-
-
-
-
-{% endblock %}
-{% block custom_foot_js %}
-
-
-{% endblock %}
diff --git a/apps/ops/templates/cron/create.html b/apps/ops/templates/cron/create.html
deleted file mode 100644
index 291a5656a..000000000
--- a/apps/ops/templates/cron/create.html
+++ /dev/null
@@ -1,16 +0,0 @@
-{% 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 %}
- {% trans 'Password' %}
-
-{% endblock %}
\ No newline at end of file
diff --git a/apps/ops/templates/cron/detail.html b/apps/ops/templates/cron/detail.html
deleted file mode 100644
index 6188962ff..000000000
--- a/apps/ops/templates/cron/detail.html
+++ /dev/null
@@ -1,280 +0,0 @@
-{% extends 'base.html' %}
-{% load static %}
-{% load i18n %}
-
-{% block custom_head_css_js %}
-
-
-
-
-{% endblock %}
-{% block content %}
-
-
-
-
-
-
-
-
-
-
-
-
-
- {% trans 'Name' %}: |
- {{ cron.name }} |
-
-
-
-
-
-
-
-
-
- {% trans 'Quick modify' %}
-
-
-
-
-
- {% trans 'Active' %}: |
-
-
- |
-
-
- {% trans 'Enable OTP' %}: |
-
-
- |
-
-
- {% trans 'Reset password' %}: |
-
-
-
-
- |
-
-
- {% trans 'Reset ssh key' %}: |
-
-
-
-
- |
-
-
- {% trans 'Update ssh key' %}: |
-
-
-
-
- |
-
-
-
-
-
-
-
-
- {% trans 'User group' %}
-
-
-
-
-
-
- {% for group in user_object.groups.all %}
-
- {{ group.name }} |
-
-
- |
-
- {% endfor %}
-
-
-
-
-
-
-
-
-
-
- {% include 'users/_user_update_pk_modal.html' %}
-{% endblock %}
-{% block custom_foot_js %}
-
-{% endblock %}
diff --git a/apps/ops/templates/cron/list.html b/apps/ops/templates/cron/list.html
deleted file mode 100644
index d1a2c78bc..000000000
--- a/apps/ops/templates/cron/list.html
+++ /dev/null
@@ -1,231 +0,0 @@
-{% extends '_base_list.html' %}
-{% load i18n static %}
-{% block table_search %}
-{% endblock %}
-{% block table_container %}
-
-{##}
-
-
-{% include "users/_user_bulk_update_modal.html" %}
-{#{% include "users/_user_import_modal.html" %}#}
-{% endblock %}
-{% block content_bottom_left %}{% endblock %}
-{% block custom_foot_js %}
-
-
-{% endblock %}
-
diff --git a/apps/ops/templates/cron/update.html b/apps/ops/templates/cron/update.html
deleted file mode 100644
index f033e1ed8..000000000
--- a/apps/ops/templates/cron/update.html
+++ /dev/null
@@ -1,20 +0,0 @@
-{% extends 'cron/_cron.html' %}
-{% load i18n %}
-{% block user_template_title %}{% trans "Update user" %}{% endblock %}
-{% block username %}
-
-{% endblock %}
-{% block password %}
- {% trans 'Password' %}
-
-{% endblock %}
diff --git a/apps/ops/templates/ops/task_record_detail.html b/apps/ops/templates/ops/task_record_detail.html
new file mode 100644
index 000000000..bd71a5a90
--- /dev/null
+++ b/apps/ops/templates/ops/task_record_detail.html
@@ -0,0 +1,147 @@
+{% extends 'base.html' %}
+{% load static %}
+{% load i18n %}
+
+{% block custom_head_css_js %}
+
+
+
+
+{% endblock %}
+{% block content %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% trans 'UUID' %}: |
+ {{ object.uuid }} |
+
+
+ {% trans 'Name' %}: |
+ {{ object.name }} |
+
+
+ {% trans 'Date start' %}: |
+ {{ object.date_start}} |
+
+
+ {% trans 'Date finished' %}: |
+ {{ object.date_finished }} |
+
+
+ {% trans 'Time delta' %}: |
+ {{ object.timedelta}} s |
+
+
+ {% trans 'Is finished' %}: |
+ {{ object.is_finished }} |
+
+
+ {% trans 'Is success ' %}: |
+ {{ object.is_success }} |
+
+
+ {% trans 'Assets ' %}: |
+
+
+ {% for asset in object.total_assets %}
+ {{ asset }}
+ {% endfor %}
+
+ |
+
+
+
+
+
+
+
+
+
+ {% trans 'Failed assets' %}
+
+
+
+
+ {% for host, msg in results.failed %}
+ {% if forloop.first %}
+
+ {% else %}
+
+ {% endif %}
+ {{ host }}: |
+ {{ msg }} |
+
+ {% empty %}
+
+ {% trans 'No assets' %} |
+
+ {% endfor %}
+
+
+
+
+
+
+
+ {% trans 'Success assets' %}
+
+
+
+
+ {% for host in results.success %}
+ {% if forloop.first %}
+
+ {% else %}
+
+ {% endif %}
+ {{ host }} |
+
+ {% empty %}
+
+ {% trans 'No assets' %} |
+
+ {% endfor %}
+
+
+
+
+
+
+
+
+
+
+ {% include 'users/_user_update_pk_modal.html' %}
+{% endblock %}
+
diff --git a/apps/ops/templates/ops/task_record_list.html b/apps/ops/templates/ops/task_record_list.html
new file mode 100644
index 000000000..fe4a2412e
--- /dev/null
+++ b/apps/ops/templates/ops/task_record_list.html
@@ -0,0 +1,136 @@
+{% extends '_base_list.html' %}
+{% load i18n %}
+{% load static %}
+{% block content_left_head %}
+
+
+{% endblock %}
+
+
+{% block table_search %}
+
+{% endblock %}
+
+{% block table_head %}
+ |
+ {% trans 'Name' %} |
+ {% trans 'Asset' %} |
+ {% trans 'Success' %} |
+ {% trans 'Finished' %} |
+ {% trans 'Date start' %} |
+ {% trans 'Time' %} |
+ {% trans 'Action' %} |
+{% endblock %}
+
+{% block table_body %}
+ {% for object in task_record_list %}
+
+ |
+ {{ object.name }} |
+ {{ object.total_assets|length }} |
+
+ {% if object.is_success %}
+
+ {% else %}
+
+ {% endif %}
+ |
+
+ {% if object.is_finished %}
+
+ {% else %}
+
+ {% endif %}
+ |
+ {{ object.date_start }} |
+ {{ object.timedelta }} s |
+
+ {% trans "Repush" %}
+ |
+
+ {% endfor %}
+{% endblock %}
+
+{# comment #}
+{% block custom_foot_js %}
+
+
+{# 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)#}
+{# })#}
+{# #}
+{% endblock %}
+
diff --git a/apps/ops/templates/sudo/_sudo.html b/apps/ops/templates/sudo/_sudo.html
deleted file mode 100644
index 59d03e5ee..000000000
--- a/apps/ops/templates/sudo/_sudo.html
+++ /dev/null
@@ -1,97 +0,0 @@
-{% extends 'base.html' %}
-{% load i18n %}
-{% load static %}
-{% load bootstrap %}
-{% block custom_head_css_js %}
-
-
-
-{% endblock %}
-
-{% block content %}
-
-
-
-
-
-
{% block user_template_title %}{% trans 'Create user' %}{% endblock %}
-
-
-
-
-
-
-
-{% endblock %}
-{% block custom_foot_js %}
-
-
-{% endblock %}
diff --git a/apps/ops/templates/sudo/create.html b/apps/ops/templates/sudo/create.html
deleted file mode 100644
index 19727e102..000000000
--- a/apps/ops/templates/sudo/create.html
+++ /dev/null
@@ -1,16 +0,0 @@
-{% 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 %}
- {% trans 'Password' %}
-
-{% endblock %}
\ No newline at end of file
diff --git a/apps/ops/templates/sudo/detail.html b/apps/ops/templates/sudo/detail.html
deleted file mode 100644
index cf6b8e879..000000000
--- a/apps/ops/templates/sudo/detail.html
+++ /dev/null
@@ -1,280 +0,0 @@
-{% extends 'base.html' %}
-{% load static %}
-{% load i18n %}
-
-{% block custom_head_css_js %}
-
-
-
-
-{% endblock %}
-{% block content %}
-
-
-
-
-
-
-
-
-
-
-
-
-
- {% trans 'Name' %}: |
- {{ sudo.name }} |
-
-
-
-
-
-
-
-
-
- {% trans 'Quick modify' %}
-
-
-
-
-
- {% trans 'Active' %}: |
-
-
- |
-
-
- {% trans 'Enable OTP' %}: |
-
-
- |
-
-
- {% trans 'Reset password' %}: |
-
-
-
-
- |
-
-
- {% trans 'Reset ssh key' %}: |
-
-
-
-
- |
-
-
- {% trans 'Update ssh key' %}: |
-
-
-
-
- |
-
-
-
-
-
-
-
-
- {% trans 'User group' %}
-
-
-
-
-
-
- {% for group in user_object.groups.all %}
-
- {{ group.name }} |
-
-
- |
-
- {% endfor %}
-
-
-
-
-
-
-
-
-
-
- {% include 'users/_user_update_pk_modal.html' %}
-{% endblock %}
-{% block custom_foot_js %}
-
-{% endblock %}
diff --git a/apps/ops/templates/sudo/list.html b/apps/ops/templates/sudo/list.html
deleted file mode 100644
index 8da993251..000000000
--- a/apps/ops/templates/sudo/list.html
+++ /dev/null
@@ -1,226 +0,0 @@
-{% extends '_base_list.html' %}
-{% load i18n static %}
-{% block table_search %}
-{% endblock %}
-{% block table_container %}
-
-{##}
-
-
-{#{% include "users/_user_bulk_update_modal.html" %}#}
-{#{% include "users/_user_import_modal.html" %}#}
-{% endblock %}
-{% block content_bottom_left %}{% endblock %}
-{% block custom_foot_js %}
-
-
-{% endblock %}
-
diff --git a/apps/ops/templates/sudo/update.html b/apps/ops/templates/sudo/update.html
deleted file mode 100644
index 3172d23f4..000000000
--- a/apps/ops/templates/sudo/update.html
+++ /dev/null
@@ -1,20 +0,0 @@
-{% extends 'sudo/_sudo.html' %}
-{% load i18n %}
-{% block user_template_title %}{% trans "Update user" %}{% endblock %}
-{% block username %}
-
-{% endblock %}
-{% block password %}
- {% trans 'Password' %}
-
-{% endblock %}
diff --git a/apps/ops/templates/task/_task.html b/apps/ops/templates/task/_task.html
deleted file mode 100644
index 59d03e5ee..000000000
--- a/apps/ops/templates/task/_task.html
+++ /dev/null
@@ -1,97 +0,0 @@
-{% extends 'base.html' %}
-{% load i18n %}
-{% load static %}
-{% load bootstrap %}
-{% block custom_head_css_js %}
-
-
-
-{% endblock %}
-
-{% block content %}
-
-
-
-
-
-
{% block user_template_title %}{% trans 'Create user' %}{% endblock %}
-
-
-
-
-
-
-
-{% endblock %}
-{% block custom_foot_js %}
-
-
-{% endblock %}
diff --git a/apps/ops/templates/task/create.html b/apps/ops/templates/task/create.html
deleted file mode 100644
index 19727e102..000000000
--- a/apps/ops/templates/task/create.html
+++ /dev/null
@@ -1,16 +0,0 @@
-{% 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 %}
- {% trans 'Password' %}
-
-{% endblock %}
\ No newline at end of file
diff --git a/apps/ops/templates/task/detail.html b/apps/ops/templates/task/detail.html
deleted file mode 100644
index cf6b8e879..000000000
--- a/apps/ops/templates/task/detail.html
+++ /dev/null
@@ -1,280 +0,0 @@
-{% extends 'base.html' %}
-{% load static %}
-{% load i18n %}
-
-{% block custom_head_css_js %}
-
-
-
-
-{% endblock %}
-{% block content %}
-
-
-
-
-
-
-
-
-
-
-
-
-
- {% trans 'Name' %}: |
- {{ sudo.name }} |
-
-
-
-
-
-
-
-
-
- {% trans 'Quick modify' %}
-
-
-
-
-
- {% trans 'Active' %}: |
-
-
- |
-
-
- {% trans 'Enable OTP' %}: |
-
-
- |
-
-
- {% trans 'Reset password' %}: |
-
-
-
-
- |
-
-
- {% trans 'Reset ssh key' %}: |
-
-
-
-
- |
-
-
- {% trans 'Update ssh key' %}: |
-
-
-
-
- |
-
-
-
-
-
-
-
-
- {% trans 'User group' %}
-
-
-
-
-
-
- {% for group in user_object.groups.all %}
-
- {{ group.name }} |
-
-
- |
-
- {% endfor %}
-
-
-
-
-
-
-
-
-
-
- {% include 'users/_user_update_pk_modal.html' %}
-{% endblock %}
-{% block custom_foot_js %}
-
-{% endblock %}
diff --git a/apps/ops/templates/task/list.html b/apps/ops/templates/task/list.html
deleted file mode 100644
index 7109e4fe8..000000000
--- a/apps/ops/templates/task/list.html
+++ /dev/null
@@ -1,225 +0,0 @@
-{% extends '_base_list.html' %}
-{% load i18n static %}
-{% block table_search %}
-{% endblock %}
-{% block table_container %}
-
-{##}
-
-
-{% endblock %}
-{% block content_bottom_left %}{% endblock %}
-{% block custom_foot_js %}
-
-
-{% endblock %}
-
diff --git a/apps/ops/templates/task/update.html b/apps/ops/templates/task/update.html
deleted file mode 100644
index 3172d23f4..000000000
--- a/apps/ops/templates/task/update.html
+++ /dev/null
@@ -1,20 +0,0 @@
-{% extends 'sudo/_sudo.html' %}
-{% load i18n %}
-{% block user_template_title %}{% trans "Update user" %}{% endblock %}
-{% block username %}
-
-{% endblock %}
-{% block password %}
- {% trans 'Password' %}
-
-{% endblock %}
diff --git a/apps/ops/urls/view_urls.py b/apps/ops/urls/view_urls.py
index 8a0fba4f7..c8ef31529 100644
--- a/apps/ops/urls/view_urls.py
+++ b/apps/ops/urls/view_urls.py
@@ -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[0-9a-zA-Z-]+)/$', views.TaskRecordDetailView.as_view(), name='task-record-detail'),
]
\ No newline at end of file
diff --git a/apps/ops/utils/callback.py b/apps/ops/utils/callback.py
index 6e0f29cb6..148117991 100644
--- a/apps/ops/utils/callback.py
+++ b/apps/ops/utils/callback.py
@@ -1,11 +1,37 @@
# ~*~ 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={})
diff --git a/apps/ops/utils/runner.py b/apps/ops/utils/runner.py
index 14ccf0afe..1a1612d91 100644
--- a/apps/ops/utils/runner.py
+++ b/apps/ops/utils/runner.py
@@ -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__":
diff --git a/apps/ops/views.py b/apps/ops/views.py
index ebaa2f033..33720dbc8 100644
--- a/apps/ops/views.py
+++ b/apps/ops/views.py
@@ -1,24 +1,39 @@
# ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals
-from django.conf import settings
-from django.views.generic.list import ListView
+import json
+
+from django.conf import settings
+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)
diff --git a/apps/templates/_nav.html b/apps/templates/_nav.html
index 25ecf136d..e9b55c48f 100644
--- a/apps/templates/_nav.html
+++ b/apps/templates/_nav.html
@@ -49,7 +49,7 @@
{% trans 'Job Center' %}