Commit b97d5b09 authored by ibuler's avatar ibuler

[Feature] assets task 修改

parent 08e17884
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
ADMIN_USER_CONN_CACHE_KEY_PREFIX = "ADMIN_USER_CONN_" PUSH_SYSTEM_USER_PERIOD_LOCK_KEY = "PUSH_SYSTEM_USER_PERIOD_KEY"
SYSTEM_USER_CONN_CACHE_KEY_PREFIX = "SYSTEM_USER_CONN_" PUSH_SYSTEM_USER_PERIOD_TASK_NAME = "PUSH-SYSTEM-USER-PERIOD"
PUSH_SYSTEM_USER_TASK_NAME = "PUSH-SYSTEM-USER-TO-CLUSTER-{}"
PUSH_SYSTEM_USER_LOCK_KEY = "PUSH_SYSTEM_USER_TO_CLUSTER_LOCK_{}"
UPDATE_ASSETS_HARDWARE_TASK_NAME = 'UPDATE-ASSETS-HARDWARE-INFO'
UPDATE_ASSETS_HARDWARE_PERIOD_LOCK_KEY = "UPDATE_ASSETS_HARDWARE_PERIOD_LOCK_KEY" UPDATE_ASSETS_HARDWARE_PERIOD_LOCK_KEY = "UPDATE_ASSETS_HARDWARE_PERIOD_LOCK_KEY"
TEST_ADMIN_USER_CONNECTABILITY_PEROID_KEY = "TEST_ADMIN_USER_CONNECTABILITY_KEY" UPDATE_ASSETS_HARDWARE_PERIOD_TASK_NAME = 'UPDATE-ASSETS-HARDWARE-INFO-PERIOD'
TEST_SYSTEM_USER_CONNECTABILITY_PEROID_KEY = "TEST_SYSTEM_USER_CONNECTABILITY_PEROID_KEY" UPDATE_ASSETS_HARDWARE_TASKS = [
PUSH_SYSTEM_USER_PERIOD_KEY = "PUSH_SYSTEM_USER_PERIOD_KEY" {
'name': UPDATE_ASSETS_HARDWARE_TASK_NAME,
'action': {
'module': 'setup'
}
}
]
TEST_ADMIN_USER_CONN_PERIOD_LOCK_KEY = "TEST_ADMIN_USER_CONN_PERIOD_KEY"
TEST_ADMIN_USER_CONN_PERIOD_TASK_NAME = "TEST_ADMIN_USER_CONN_PERIOD_TASK"
TEST_ADMIN_USER_CONN_TASK_NAME = "TEST-ADMIN-USER-CONN-{}"
TEST_ADMIN_USER_CONN_LOCK_KEY = TEST_ADMIN_USER_CONN_TASK_NAME
ADMIN_USER_CONN_CACHE_KEY = "ADMIN_USER_CONN_{}"
TEST_ADMIN_USER_CONN_TASKS = [
{
"name": "TEST_ADMIN_CONNECTIVE",
"action": {
"module": "ping",
}
}
]
ASSET_ADMIN_CONN_CACHE_KEY = "ASSET_ADMIN_USER_CONN_{}"
TEST_ASSET_CONN_TASK_NAME = "ASSET_CONN_TEST_MANUAL"
TEST_SYSTEM_USER_CONN_PERIOD_LOCK_KEY = "TEST_SYSTEM_USER_CONN_PERIOD_KEY"
TEST_SYSTEM_USER_CONN_PERIOD_TASK_NAME = "TEST-SYSTEM-USER-CONN-PERIOD-TASK"
TEST_SYSTEM_USER_CONN_CACHE_KEY_PREFIX = "SYSTEM_USER_CONN_"
TEST_SYSTEM_USER_CONN_TASK_NAME = "TEST-ADMIN-USER-CONN-{}"
TEST_SYSTEM_USER_CONN_LOCK_KEY = "TEST_SYSTEM_USER_CONN_{}"
SYSTEM_USER_CONN_CACHE_KEY = "SYSTEM_USER_CONN_{}"
TEST_SYSTEM_USER_CONN_TASKS = [
{
"name": "TEST_SYSTEM_USER_CONNECTIVE",
"action": {
"module": "ping",
}
}
]
TASK_OPTIONS = {
'timeout': 60,
'forks': 10,
}
...@@ -9,7 +9,7 @@ from django.db import models ...@@ -9,7 +9,7 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.core.cache import cache from django.core.cache import cache
from ..const import ADMIN_USER_CONN_CACHE_KEY_PREFIX from ..const import ASSET_ADMIN_CONN_CACHE_KEY
from .cluster import Cluster from .cluster import Cluster
from .group import AssetGroup from .group import AssetGroup
from .user import AdminUser, SystemUser from .user import AdminUser, SystemUser
...@@ -110,7 +110,7 @@ class Asset(models.Model): ...@@ -110,7 +110,7 @@ class Asset(models.Model):
@property @property
def is_connective(self): def is_connective(self):
val = cache.get(ADMIN_USER_CONN_CACHE_KEY_PREFIX + self.hostname) val = cache.get(ASSET_ADMIN_CONN_CACHE_KEY.format(self.hostname))
if val == 1: if val == 1:
return True return True
else: else:
......
...@@ -5,7 +5,7 @@ from rest_framework_bulk.serializers import BulkListSerializer ...@@ -5,7 +5,7 @@ from rest_framework_bulk.serializers import BulkListSerializer
from common.mixins import BulkSerializerMixin from common.mixins import BulkSerializerMixin
from .models import AssetGroup, Asset, Cluster, AdminUser, SystemUser from .models import AssetGroup, Asset, Cluster, AdminUser, SystemUser
from .tasks import SYSTEM_USER_CONN_CACHE_KEY_PREFIX, ADMIN_USER_CONN_CACHE_KEY_PREFIX from .const import ADMIN_USER_CONN_CACHE_KEY, SYSTEM_USER_CONN_CACHE_KEY
class AssetGroupSerializer(BulkSerializerMixin, serializers.ModelSerializer): class AssetGroupSerializer(BulkSerializerMixin, serializers.ModelSerializer):
...@@ -73,7 +73,7 @@ class AdminUserSerializer(serializers.ModelSerializer): ...@@ -73,7 +73,7 @@ class AdminUserSerializer(serializers.ModelSerializer):
@staticmethod @staticmethod
def get_unreachable_amount(obj): def get_unreachable_amount(obj):
data = cache.get(ADMIN_USER_CONN_CACHE_KEY_PREFIX + obj.name) data = cache.get(ADMIN_USER_CONN_CACHE_KEY.format(obj.name))
if data: if data:
return len(data.get('dark')) return len(data.get('dark'))
else: else:
...@@ -98,7 +98,7 @@ class SystemUserSerializer(serializers.ModelSerializer): ...@@ -98,7 +98,7 @@ class SystemUserSerializer(serializers.ModelSerializer):
@staticmethod @staticmethod
def get_unreachable_amount(obj): def get_unreachable_amount(obj):
data = cache.get(SYSTEM_USER_CONN_CACHE_KEY_PREFIX + obj.name) data = cache.get(SYSTEM_USER_CONN_CACHE_KEY.format(obj.name))
if data: if data:
return len(data.get('dark')) return len(data.get('dark'))
else: else:
......
This diff is collapsed.
...@@ -9,24 +9,22 @@ import chardet ...@@ -9,24 +9,22 @@ import chardet
from io import StringIO from io import StringIO
from django.conf import settings from django.conf import settings
from django.core.exceptions import ImproperlyConfigured, FieldDoesNotExist
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic import TemplateView, ListView, View from django.views.generic import TemplateView, ListView, View
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.views.generic.detail import DetailView, SingleObjectMixin from django.views.generic.detail import DetailView
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect, Http404 from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_protect, csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.core.cache import cache from django.core.cache import cache
from django.utils import timezone from django.utils import timezone
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import get_object_or_404, redirect, reverse from django.shortcuts import redirect
from common.mixins import JSONResponseMixin from common.mixins import JSONResponseMixin
from common.utils import get_object_or_none from common.utils import get_object_or_none, get_logger
from common.imexp import ModelExportView
from .. import forms from .. import forms
from ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser from ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser
from ..hands import AdminUserRequiredMixin from ..hands import AdminUserRequiredMixin
...@@ -39,6 +37,7 @@ __all__ = [ ...@@ -39,6 +37,7 @@ __all__ = [
'AssetModalListView', 'AssetDeleteView', 'AssetExportView', 'AssetModalListView', 'AssetDeleteView', 'AssetExportView',
'BulkImportAssetView', 'BulkImportAssetView',
] ]
logger = get_logger(__file__)
class AssetListView(AdminUserRequiredMixin, TemplateView): class AssetListView(AdminUserRequiredMixin, TemplateView):
...@@ -48,12 +47,11 @@ class AssetListView(AdminUserRequiredMixin, TemplateView): ...@@ -48,12 +47,11 @@ class AssetListView(AdminUserRequiredMixin, TemplateView):
context = { context = {
'app': 'Assets', 'app': 'Assets',
'action': 'Asset list', 'action': 'Asset list',
'groups': AssetGroup.objects.all(), # 'groups': AssetGroup.objects.all(),
'system_users': SystemUser.objects.all(), 'system_users': SystemUser.objects.all(),
# 'form': forms.AssetBulkUpdateForm(),
} }
kwargs.update(context) kwargs.update(context)
return super(AssetListView, self).get_context_data(**kwargs) return super().get_context_data(**kwargs)
class UserAssetListView(LoginRequiredMixin, TemplateView): class UserAssetListView(LoginRequiredMixin, TemplateView):
...@@ -64,10 +62,9 @@ class UserAssetListView(LoginRequiredMixin, TemplateView): ...@@ -64,10 +62,9 @@ class UserAssetListView(LoginRequiredMixin, TemplateView):
'app': 'Assets', 'app': 'Assets',
'action': 'Asset list', 'action': 'Asset list',
'system_users': SystemUser.objects.all(), 'system_users': SystemUser.objects.all(),
'default_pk': '00000000-0000-0000-0000-000000000000',
} }
kwargs.update(context) kwargs.update(context)
return super(UserAssetListView, self).get_context_data(**kwargs) return super().get_context_data(**kwargs)
class AssetCreateView(AdminUserRequiredMixin, CreateView): class AssetCreateView(AdminUserRequiredMixin, CreateView):
...@@ -107,7 +104,7 @@ class AssetModalListView(AdminUserRequiredMixin, ListView): ...@@ -107,7 +104,7 @@ class AssetModalListView(AdminUserRequiredMixin, ListView):
'assets': assets 'assets': assets
} }
kwargs.update(context) kwargs.update(context)
return super(AssetModalListView, self).get_context_data(**kwargs) return super().get_context_data(**kwargs)
class AssetBulkUpdateView(AdminUserRequiredMixin, ListView): class AssetBulkUpdateView(AdminUserRequiredMixin, ListView):
...@@ -128,7 +125,7 @@ class AssetBulkUpdateView(AdminUserRequiredMixin, ListView): ...@@ -128,7 +125,7 @@ class AssetBulkUpdateView(AdminUserRequiredMixin, ListView):
) )
else: else:
self.form = self.form_class() self.form = self.form_class()
return super(AssetBulkUpdateView, self).get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
form = self.form_class(request.POST) form = self.form_class(request.POST)
...@@ -148,7 +145,7 @@ class AssetBulkUpdateView(AdminUserRequiredMixin, ListView): ...@@ -148,7 +145,7 @@ class AssetBulkUpdateView(AdminUserRequiredMixin, ListView):
'assets': Asset.objects.all(), 'assets': Asset.objects.all(),
} }
kwargs.update(context) kwargs.update(context)
return super(AssetBulkUpdateView, self).get_context_data(**kwargs) return super().get_context_data(**kwargs)
class AssetUpdateView(AdminUserRequiredMixin, UpdateView): class AssetUpdateView(AdminUserRequiredMixin, UpdateView):
...@@ -166,8 +163,8 @@ class AssetUpdateView(AdminUserRequiredMixin, UpdateView): ...@@ -166,8 +163,8 @@ class AssetUpdateView(AdminUserRequiredMixin, UpdateView):
return super(AssetUpdateView, self).get_context_data(**kwargs) return super(AssetUpdateView, self).get_context_data(**kwargs)
def form_invalid(self, form): def form_invalid(self, form):
print(form.errors) logger.error(form.errors)
return super(AssetUpdateView, self).form_invalid(form) return super().form_invalid(form)
class AssetDeleteView(AdminUserRequiredMixin, DeleteView): class AssetDeleteView(AdminUserRequiredMixin, DeleteView):
...@@ -196,11 +193,46 @@ class AssetDetailView(DetailView): ...@@ -196,11 +193,46 @@ class AssetDetailView(DetailView):
@method_decorator(csrf_exempt, name='dispatch') @method_decorator(csrf_exempt, name='dispatch')
class AssetExportView(ModelExportView): class AssetExportView(View):
filename_prefix = 'jumpserver' def get(self, request):
redirect_url = reverse_lazy('assets:asset-export') spm = request.GET.get('spm', '')
model = Asset assets_id_default = [Asset.objects.first().id] if Asset.objects.first() else [1]
fields = ('hostname', 'ip') assets_id = cache.get(spm, assets_id_default)
fields = [
field for field in Asset._meta.fields
if field.name not in [
'date_created'
]
]
filename = 'assets-{}.csv'.format(
timezone.localtime(timezone.now()).strftime('%Y-%m-%d_%H-%M-%S'))
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
response.write(codecs.BOM_UTF8)
assets = Asset.objects.filter(id__in=assets_id)
writer = csv.writer(response, dialect='excel',
quoting=csv.QUOTE_MINIMAL)
header = [field.verbose_name for field in fields]
header.append(_('Asset groups'))
writer.writerow(header)
for asset in assets:
groups = ','.join([group.name for group in asset.groups.all()])
data = [getattr(asset, field.name) for field in fields]
data.append(groups)
writer.writerow(data)
return response
def post(self, request, *args, **kwargs):
try:
assets_id = json.loads(request.body).get('assets_id', [])
except ValueError:
return HttpResponse('Json object not valid', status=400)
spm = uuid.uuid4().hex
cache.set(spm, assets_id, 300)
url = reverse_lazy('assets:asset-export') + '?spm=%s' % spm
return JsonResponse({'redirect': url})
class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView): class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
...@@ -305,4 +337,3 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView): ...@@ -305,4 +337,3 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
} }
return self.render_json_response(data) return self.render_json_response(data)
This diff is collapsed.
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
from ansible.plugins.callback import CallbackBase from ansible.plugins.callback import CallbackBase
from ansible.plugins.callback.default import CallbackModule
class AdHocResultCallback(CallbackBase): class AdHocResultCallback(CallbackModule):
""" """
Task result Callback Task result Callback
""" """
def __init__(self, display=None): def __init__(self, display=None, options=None):
# result_raw example: { # result_raw example: {
# "ok": {"hostname": {"task_name": {},...},..}, # "ok": {"hostname": {"task_name": {},...},..},
# "failed": {"hostname": {"task_name": {}..}, ..}, # "failed": {"hostname": {"task_name": {}..}, ..},
...@@ -20,9 +21,10 @@ class AdHocResultCallback(CallbackBase): ...@@ -20,9 +21,10 @@ class AdHocResultCallback(CallbackBase):
# } # }
self.results_raw = dict(ok={}, failed={}, unreachable={}, skipped={}) self.results_raw = dict(ok={}, failed={}, unreachable={}, skipped={})
self.results_summary = dict(contacted=[], dark={}) self.results_summary = dict(contacted=[], dark={})
super().__init__(display) super().__init__()
def gather_result(self, t, res): def gather_result(self, t, res):
self._clean_results(res._result, res._task.action)
host = res._host.get_name() host = res._host.get_name()
task_name = res.task_name task_name = res.task_name
task_result = res._result task_result = res._result
...@@ -49,15 +51,19 @@ class AdHocResultCallback(CallbackBase): ...@@ -49,15 +51,19 @@ class AdHocResultCallback(CallbackBase):
def v2_runner_on_failed(self, result, ignore_errors=False): def v2_runner_on_failed(self, result, ignore_errors=False):
self.gather_result("failed", result) self.gather_result("failed", result)
super().v2_runner_on_failed(result, ignore_errors=ignore_errors)
def v2_runner_on_ok(self, result): def v2_runner_on_ok(self, result):
self.gather_result("ok", result) self.gather_result("ok", result)
super().v2_runner_on_ok(result)
def v2_runner_on_skipped(self, result): def v2_runner_on_skipped(self, result):
self.gather_result("skipped", result) self.gather_result("skipped", result)
super().v2_runner_on_skipped(result)
def v2_runner_on_unreachable(self, result): def v2_runner_on_unreachable(self, result):
self.gather_result("unreachable", result) self.gather_result("unreachable", result)
super().v2_runner_on_unreachable(result)
class CommandResultCallback(AdHocResultCallback): class CommandResultCallback(AdHocResultCallback):
......
...@@ -21,37 +21,62 @@ class Task(models.Model): ...@@ -21,37 +21,62 @@ class Task(models.Model):
One task can have some versions of adhoc, run a task only run the latest version adhoc One task can have some versions of adhoc, run a task only run the latest version adhoc
""" """
id = models.UUIDField(default=uuid.uuid4, primary_key=True) id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=128, blank=True, verbose_name=_('Name')) name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
is_deleted = models.BooleanField(default=False) is_deleted = models.BooleanField(default=False)
created_by = models.CharField(max_length=128, blank=True, default='') created_by = models.CharField(max_length=128, blank=True, default='')
date_created = models.DateTimeField(auto_now_add=True) date_created = models.DateTimeField(auto_now_add=True)
__latest_adhoc = None
@property @property
def short_id(self): def short_id(self):
return str(self.id).split('-')[-1] return str(self.id).split('-')[-1]
def __str__(self): @property
return self.name def latest_adhoc(self):
if not self.__latest_adhoc:
self.__latest_adhoc = self.get_latest_adhoc()
return self.__latest_adhoc
def get_latest_adhoc(self): @latest_adhoc.setter
return self.adhoc.all().order_by('date_created').last() def latest_adhoc(self, item):
self.__latest_adhoc = item
def get_latest_history(self): @property
return self.get_latest_adhoc().get_latest_history() def latest_history(self):
try:
return self.history.all().latest()
except AdHocRunHistory.DoesNotExist:
return None
def get_all_run_history(self): def get_latest_adhoc(self):
adhocs = self.adhoc.all() try:
return AdHocRunHistory.objects.filter(adhoc__in=adhocs) return self.adhoc.all().latest()
except AdHoc.DoesNotExist:
return None
def get_all_run_times(self): @property
history_all = self.get_all_run_history() def history_summary(self):
total = len(history_all) history = self.get_run_history()
success = len([history for history in history_all if history.is_success]) total = len(history)
failed = len([history for history in history_all if not history.is_success]) success = len([history for history in history if history.is_success])
failed = len([history for history in history if not history.is_success])
return {'total': total, 'success': success, 'failed': failed} return {'total': total, 'success': success, 'failed': failed}
def get_run_history(self):
return self.history.all()
def run(self):
if self.latest_adhoc:
return self.latest_adhoc.run()
else:
return {'error': 'No adhoc'}
def __str__(self):
return self.name
class Meta: class Meta:
db_table = 'ops_task' db_table = 'ops_task'
get_latest_by = 'date_created'
class AdHoc(models.Model): class AdHoc(models.Model):
...@@ -103,6 +128,10 @@ class AdHoc(models.Model): ...@@ -103,6 +128,10 @@ class AdHoc(models.Model):
else: else:
return {} return {}
def run(self):
from .utils import run_adhoc_object
return run_adhoc_object(self, **self.options)
@become.setter @become.setter
def become(self, item): def become(self, item):
""" """
...@@ -130,14 +159,31 @@ class AdHoc(models.Model): ...@@ -130,14 +159,31 @@ class AdHoc(models.Model):
def short_id(self): def short_id(self):
return str(self.id).split('-')[-1] return str(self.id).split('-')[-1]
def get_latest_history(self): @property
return self.history.all().order_by('date_start').last() def latest_history(self):
try:
return self.history.all().latest()
except AdHocRunHistory.DoesNotExist:
return None
def __str__(self): def __str__(self):
return "{} of {}".format(self.task.name, self.short_id) return "{} of {}".format(self.task.name, self.short_id)
def __eq__(self, other):
if not isinstance(other, self.__class__):
return False
fields_check = []
for field in self.__class__._meta.fields:
if field.name not in ['id', 'date_created']:
fields_check.append(field)
for field in fields_check:
if getattr(self, field.name) != getattr(other, field.name):
return False
return True
class Meta: class Meta:
db_table = "ops_adhoc" db_table = "ops_adhoc"
get_latest_by = 'date_created'
class AdHocRunHistory(models.Model): class AdHocRunHistory(models.Model):
...@@ -145,7 +191,8 @@ class AdHocRunHistory(models.Model): ...@@ -145,7 +191,8 @@ class AdHocRunHistory(models.Model):
AdHoc running history. AdHoc running history.
""" """
id = models.UUIDField(default=uuid.uuid4, primary_key=True) id = models.UUIDField(default=uuid.uuid4, primary_key=True)
adhoc = models.ForeignKey(AdHoc, related_name='history', on_delete=models.CASCADE) task = models.ForeignKey(Task, related_name='history', on_delete=models.SET_NULL, null=True)
adhoc = models.ForeignKey(AdHoc, related_name='history', on_delete=models.SET_NULL, null=True)
date_start = models.DateTimeField(auto_now_add=True, verbose_name=_('Start time')) date_start = models.DateTimeField(auto_now_add=True, verbose_name=_('Start time'))
date_finished = models.DateTimeField(blank=True, null=True, verbose_name=_('End time')) date_finished = models.DateTimeField(blank=True, null=True, verbose_name=_('End time'))
timedelta = models.FloatField(default=0.0, verbose_name=_('Time'), null=True) timedelta = models.FloatField(default=0.0, verbose_name=_('Time'), null=True)
...@@ -179,3 +226,4 @@ class AdHocRunHistory(models.Model): ...@@ -179,3 +226,4 @@ class AdHocRunHistory(models.Model):
class Meta: class Meta:
db_table = "ops_adhoc_history" db_table = "ops_adhoc_history"
get_latest_by = 'date_start'
...@@ -52,19 +52,19 @@ ...@@ -52,19 +52,19 @@
<td class="text-center"><input type="checkbox" class="cbx-term"> </td> <td class="text-center"><input type="checkbox" class="cbx-term"> </td>
<td class="text-center"><a href="{% url 'ops:task-detail' pk=object.id %}">{{ object.name }}</a></td> <td class="text-center"><a href="{% url 'ops:task-detail' pk=object.id %}">{{ object.name }}</a></td>
<td class="text-center"> <td class="text-center">
<span class="text-danger">{{ object.get_all_run_times.failed }}</span>/<span class="text-navy">{{ object.get_all_run_times.success}}</span>/{{ object.get_all_run_times.total}} <span class="text-danger">{{ object.history_summary.failed }}</span>/<span class="text-navy">{{ object.history_summary.success}}</span>/{{ object.history_summary.total}}
</td> </td>
<td class="text-center">{{ object.adhoc.all | length}}</td> <td class="text-center">{{ object.adhoc.all | length}}</td>
<td class="text-center">{{ object.get_latest_adhoc.hosts | length}}</td> <td class="text-center">{{ object.latest_adhoc.hosts | length}}</td>
<td class="text-center"> <td class="text-center">
{% if object.get_latest_history.is_success %} {% if object.latest_history.is_success %}
<i class="fa fa-check text-navy"></i> <i class="fa fa-check text-navy"></i>
{% else %} {% else %}
<i class="fa fa-times text-danger"></i> <i class="fa fa-times text-danger"></i>
{% endif %} {% endif %}
</td> </td>
<td class="text-center">{{ object.get_latest_history.date_start }}</td> <td class="text-center">{{ object.latest_history.date_start }}</td>
<td class="text-center">{{ object.get_latest_history.timedelta|floatformat }} s</td> <td class="text-center">{{ object.latest_history.timedelta|floatformat }} s</td>
<td class="text-center"> <td class="text-center">
<a href="{% url 'ops:task-run' pk=object.id %}" class="btn btn-xs btn-info">{% trans "Run" %}</a> <a href="{% url 'ops:task-run' pk=object.id %}" class="btn btn-xs btn-info">{% trans "Run" %}</a>
<a data-uid="{{ object.uuid }}" class="btn btn-xs btn-danger btn-del">{% trans "Delete" %}</a> <a data-uid="{{ object.uuid }}" class="btn btn-xs btn-danger btn-del">{% trans "Delete" %}</a>
......
...@@ -21,10 +21,9 @@ def is_uuid(s): ...@@ -21,10 +21,9 @@ def is_uuid(s):
return False return False
def record_adhoc(func): def record_adhoc(func):
def _deco(adhoc, **options): def _deco(adhoc, **options):
record = AdHocRunHistory(adhoc=adhoc) record = AdHocRunHistory(adhoc=adhoc, task=adhoc.task)
time_start = time.time() time_start = time.time()
try: try:
result = func(adhoc, **options) result = func(adhoc, **options)
...@@ -86,7 +85,7 @@ def run_adhoc_object(adhoc, **options): ...@@ -86,7 +85,7 @@ def run_adhoc_object(adhoc, **options):
name = adhoc.task.name name = adhoc.task.name
inventory = get_adhoc_inventory(adhoc) inventory = get_adhoc_inventory(adhoc)
runner = AdHocRunner(inventory) runner = AdHocRunner(inventory)
for k, v in options: for k, v in options.items():
runner.set_option(k, v) runner.set_option(k, v)
try: try:
...@@ -113,42 +112,69 @@ def run_adhoc(hostname_list, pattern, tasks, name=None, ...@@ -113,42 +112,69 @@ def run_adhoc(hostname_list, pattern, tasks, name=None,
return runner.run(tasks, pattern, play_name=name) return runner.run(tasks, pattern, play_name=name)
def create_and_run_adhoc(hostname_list, pattern, tasks, name=None, # def create_and_run_adhoc(hostname_list, pattern, tasks, name=None,
run_as_admin=False, run_as=None, become_info=None): # run_as_admin=False, run_as=None, become_info=None):
if name is None: # if name is None:
name = "Adhoc-task-{}-{}".format( # name = "Adhoc-task-{}-{}".format(
get_short_uuid_str(), # get_short_uuid_str(),
timezone.now().strftime("%Y-%m-%d %H:%M:%S"), # timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
) # )
task = Task(name=name) # task = Task(name=name)
task.save() # task.save()
adhoc = AdHoc( # adhoc = AdHoc(
task=task, pattern=pattern, name=name, # task=task, pattern=pattern, name=name,
run_as_admin=run_as_admin, run_as=run_as # run_as_admin=run_as_admin, run_as=run_as
) # )
adhoc.hosts = hostname_list # adhoc.hosts = hostname_list
adhoc.tasks = tasks # adhoc.tasks = tasks
adhoc.become = become_info # adhoc.become = become_info
adhoc.save() # adhoc.save()
def get_task_by_name(name): # def get_task_by_name(name):
task = get_object_or_none(Task, name=name) # task = get_object_or_none(Task, name=name)
# return task
# def create_task(name, created_by=""):
# return Task.objects.create(name=name, created_by=created_by)
#
#
# def create_adhoc(task, hosts, tasks, pattern='all', options=None,
# run_as_admin=False, run_as="",
# become_info=None, created_by=""):
# adhoc = AdHoc(task=task, pattern=pattern, run_as_admin=run_as_admin,
# run_as=run_as, created_by=created_by)
# adhoc.hosts = hosts
# adhoc.tasks = tasks
# adhoc.options = options
# adhoc.become = become_info
# adhoc.save()
# return adhoc
def create_or_update_task(
task_name, hosts, tasks, pattern='all', options=None,
run_as_admin=False, run_as="", become_info=None,
created_by=None
):
task = get_object_or_none(Task, name=task_name)
if task is None:
task = Task(name=task_name, created_by=created_by)
task.save()
adhoc = task.get_latest_adhoc()
new_adhoc = AdHoc(task=task, pattern=pattern,
run_as_admin=run_as_admin,
run_as=run_as)
new_adhoc.hosts = hosts
new_adhoc.tasks = tasks
new_adhoc.options = options
new_adhoc.become = become_info
if not adhoc or adhoc != new_adhoc:
new_adhoc.save()
task.latest_adhoc = new_adhoc
return task return task
def create_task(name, created_by=""):
return Task.objects.create(name=name, created_by=created_by)
def create_adhoc(task, hosts, tasks, pattern='all', options=None,
run_as_admin=False, run_as="",
become_info=None, created_by=""):
adhoc = AdHoc(task=task, pattern=pattern, run_as_admin=run_as_admin,
run_as=run_as, created_by=created_by)
adhoc.hosts = hosts
adhoc.tasks = tasks
adhoc.options = options
adhoc.become = become_info
adhoc.save()
return adhoc
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