mirror of https://github.com/jumpserver/jumpserver
[Merge] 更新ansible功能
commit
951ac252fe
|
@ -79,5 +79,5 @@ class AdminUserTestConnectiveApi(generics.RetrieveAPIView):
|
||||||
|
|
||||||
def retrieve(self, request, *args, **kwargs):
|
def retrieve(self, request, *args, **kwargs):
|
||||||
admin_user = self.get_object()
|
admin_user = self.get_object()
|
||||||
test_admin_user_connectability_manual.delay(admin_user)
|
task = test_admin_user_connectability_manual.delay(admin_user)
|
||||||
return Response({"msg": "Task created"})
|
return Response({"task": task.id})
|
||||||
|
|
|
@ -87,12 +87,8 @@ class AssetRefreshHardwareApi(generics.RetrieveAPIView):
|
||||||
def retrieve(self, request, *args, **kwargs):
|
def retrieve(self, request, *args, **kwargs):
|
||||||
asset_id = kwargs.get('pk')
|
asset_id = kwargs.get('pk')
|
||||||
asset = get_object_or_404(Asset, pk=asset_id)
|
asset = get_object_or_404(Asset, pk=asset_id)
|
||||||
summary = update_asset_hardware_info_manual(asset)[1]
|
task = update_asset_hardware_info_manual.delay(asset)
|
||||||
logger.debug("Refresh summary: {}".format(summary))
|
return Response({"task": task.id})
|
||||||
if summary.get('dark'):
|
|
||||||
return Response(summary['dark'].values(), status=501)
|
|
||||||
else:
|
|
||||||
return Response({"msg": "ok"})
|
|
||||||
|
|
||||||
|
|
||||||
class AssetAdminUserTestApi(generics.RetrieveAPIView):
|
class AssetAdminUserTestApi(generics.RetrieveAPIView):
|
||||||
|
@ -105,8 +101,5 @@ class AssetAdminUserTestApi(generics.RetrieveAPIView):
|
||||||
def retrieve(self, request, *args, **kwargs):
|
def retrieve(self, request, *args, **kwargs):
|
||||||
asset_id = kwargs.get('pk')
|
asset_id = kwargs.get('pk')
|
||||||
asset = get_object_or_404(Asset, pk=asset_id)
|
asset = get_object_or_404(Asset, pk=asset_id)
|
||||||
ok, msg = test_asset_connectability_manual(asset)
|
task = test_asset_connectability_manual.delay(asset)
|
||||||
if ok:
|
return Response({"task": task.id})
|
||||||
return Response({"msg": "pong"})
|
|
||||||
else:
|
|
||||||
return Response({"error": msg}, status=502)
|
|
||||||
|
|
|
@ -130,10 +130,9 @@ class RefreshNodeHardwareInfoApi(APIView):
|
||||||
node_id = kwargs.get('pk')
|
node_id = kwargs.get('pk')
|
||||||
node = get_object_or_404(self.model, id=node_id)
|
node = get_object_or_404(self.model, id=node_id)
|
||||||
assets = node.assets.all()
|
assets = node.assets.all()
|
||||||
# task_name = _("Refresh node assets hardware info: {}".format(node.name))
|
|
||||||
task_name = _("更新节点资产硬件信息: {}".format(node.name))
|
task_name = _("更新节点资产硬件信息: {}".format(node.name))
|
||||||
update_assets_hardware_info_util.delay(assets, task_name=task_name)
|
task = update_assets_hardware_info_util.delay(assets, task_name=task_name)
|
||||||
return Response({"msg": "Task created"})
|
return Response({"task": task.id})
|
||||||
|
|
||||||
|
|
||||||
class TestNodeConnectiveApi(APIView):
|
class TestNodeConnectiveApi(APIView):
|
||||||
|
@ -145,6 +144,6 @@ class TestNodeConnectiveApi(APIView):
|
||||||
node = get_object_or_404(self.model, id=node_id)
|
node = get_object_or_404(self.model, id=node_id)
|
||||||
assets = node.assets.all()
|
assets = node.assets.all()
|
||||||
task_name = _("测试节点下资产是否可连接: {}".format(node.name))
|
task_name = _("测试节点下资产是否可连接: {}".format(node.name))
|
||||||
test_asset_connectability_util.delay(assets, task_name=task_name)
|
task = test_asset_connectability_util.delay(assets, task_name=task_name)
|
||||||
return Response({"msg": "Task created"})
|
return Response({"task": task.id})
|
||||||
|
|
||||||
|
|
|
@ -58,8 +58,8 @@ class SystemUserPushApi(generics.RetrieveAPIView):
|
||||||
|
|
||||||
def retrieve(self, request, *args, **kwargs):
|
def retrieve(self, request, *args, **kwargs):
|
||||||
system_user = self.get_object()
|
system_user = self.get_object()
|
||||||
push_system_user_to_assets_manual.delay(system_user)
|
task = push_system_user_to_assets_manual.delay(system_user)
|
||||||
return Response({"msg": "Task created"})
|
return Response({"task": task.id})
|
||||||
|
|
||||||
|
|
||||||
class SystemUserTestConnectiveApi(generics.RetrieveAPIView):
|
class SystemUserTestConnectiveApi(generics.RetrieveAPIView):
|
||||||
|
@ -71,5 +71,5 @@ class SystemUserTestConnectiveApi(generics.RetrieveAPIView):
|
||||||
|
|
||||||
def retrieve(self, request, *args, **kwargs):
|
def retrieve(self, request, *args, **kwargs):
|
||||||
system_user = self.get_object()
|
system_user = self.get_object()
|
||||||
test_system_user_connectability_manual.delay(system_user)
|
task = test_system_user_connectability_manual.delay(system_user)
|
||||||
return Response({"msg": "Task created"})
|
return Response({"task": task.id})
|
||||||
|
|
|
@ -96,7 +96,7 @@ class Asset(models.Model):
|
||||||
return False, warning
|
return False, warning
|
||||||
|
|
||||||
def is_unixlike(self):
|
def is_unixlike(self):
|
||||||
if self.platform not in ("Windows", "Other"):
|
if self.platform not in ("Windows",):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
@ -132,6 +132,15 @@ class Asset(models.Model):
|
||||||
info["gateways"] = [d.id for d in self.domain.gateway_set.all()]
|
info["gateways"] = [d.id for d in self.domain.gateway_set.all()]
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
def get_auth_info(self):
|
||||||
|
if self.admin_user:
|
||||||
|
return {
|
||||||
|
'username': self.admin_user.username,
|
||||||
|
'password': self.admin_user.password,
|
||||||
|
'private_key': self.admin_user.private_key_file,
|
||||||
|
'become': self.admin_user.become_info,
|
||||||
|
}
|
||||||
|
|
||||||
def _to_secret_json(self):
|
def _to_secret_json(self):
|
||||||
"""
|
"""
|
||||||
Ansible use it create inventory, First using asset user,
|
Ansible use it create inventory, First using asset user,
|
||||||
|
@ -175,4 +184,3 @@ class Asset(models.Model):
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
print('Error continue')
|
print('Error continue')
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,15 @@ import json
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import paramiko
|
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from common.utils import get_object_or_none, capacity_convert, \
|
from common.utils import get_object_or_none, capacity_convert, \
|
||||||
sum_capacity, encrypt_password, get_logger
|
sum_capacity, encrypt_password, get_logger
|
||||||
from common.celery import register_as_period_task, after_app_shutdown_clean, \
|
from ops.celery.utils import register_as_period_task, after_app_shutdown_clean, \
|
||||||
after_app_ready_start, app as celery_app
|
after_app_ready_start
|
||||||
|
from ops.celery import app as celery_app
|
||||||
|
|
||||||
from .models import SystemUser, AdminUser, Asset
|
from .models import SystemUser, AdminUser, Asset
|
||||||
from . import const
|
from . import const
|
||||||
|
@ -215,7 +215,7 @@ def test_admin_user_connectability_period():
|
||||||
def test_admin_user_connectability_manual(admin_user):
|
def test_admin_user_connectability_manual(admin_user):
|
||||||
# task_name = _("Test admin user connectability: {}").format(admin_user.name)
|
# task_name = _("Test admin user connectability: {}").format(admin_user.name)
|
||||||
task_name = _("测试管理行号可连接性: {}").format(admin_user.name)
|
task_name = _("测试管理行号可连接性: {}").format(admin_user.name)
|
||||||
return test_admin_user_connectability_util.delay(admin_user, task_name)
|
return test_admin_user_connectability_util(admin_user, task_name)
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
|
@ -395,11 +395,12 @@ def get_node_push_system_user_task_name(system_user, node):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task
|
||||||
def push_system_user_to_node(system_user, node):
|
def push_system_user_to_node(system_user, node):
|
||||||
logger.info("Start push system user node: {} => {}".format(system_user.name, node.value))
|
logger.info("Start push system user node: {} => {}".format(system_user.name, node.value))
|
||||||
assets = node.get_all_assets()
|
assets = node.get_all_assets()
|
||||||
task_name = get_node_push_system_user_task_name(system_user, node)
|
task_name = get_node_push_system_user_task_name(system_user, node)
|
||||||
push_system_user_util.delay([system_user], assets, task_name)
|
push_system_user_util([system_user], assets, task_name)
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
|
|
|
@ -121,14 +121,16 @@ $(document).ready(function () {
|
||||||
})
|
})
|
||||||
.on('click', '.btn-test-connective', function () {
|
.on('click', '.btn-test-connective', function () {
|
||||||
var the_url = "{% url 'api-assets:admin-user-connective' pk=admin_user.id %}";
|
var the_url = "{% url 'api-assets:admin-user-connective' pk=admin_user.id %}";
|
||||||
var error = function (data) {
|
var success = function (data) {
|
||||||
alert(data)
|
var task_id = data.task;
|
||||||
|
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||||
|
window.open(url, '', 'width=800,height=600')
|
||||||
};
|
};
|
||||||
APIUpdateAttr({
|
APIUpdateAttr({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
error: error,
|
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
success_message: "{% trans 'Task has been send, seen left asset status' %}"
|
success: success,
|
||||||
|
flash_message: false
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -269,16 +269,15 @@ function updateAssetNodes(nodes) {
|
||||||
|
|
||||||
function refreshAssetHardware() {
|
function refreshAssetHardware() {
|
||||||
var the_url = "{% url 'api-assets:asset-refresh' pk=asset.id %}";
|
var the_url = "{% url 'api-assets:asset-refresh' pk=asset.id %}";
|
||||||
var success = function (data) {
|
var success = function(data) {
|
||||||
location.reload();
|
console.log(data);
|
||||||
};
|
var task_id = data.task;
|
||||||
var error = function (data) {
|
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||||
alert(data)
|
window.open(url, '', 'width=800,height=600')
|
||||||
};
|
};
|
||||||
APIUpdateAttr({
|
APIUpdateAttr({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
success: success,
|
success: success,
|
||||||
error: error,
|
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -344,19 +343,20 @@ $(document).ready(function () {
|
||||||
var redirect_url = "{% url 'assets:asset-list' %}";
|
var redirect_url = "{% url 'assets:asset-list' %}";
|
||||||
objectDelete($this, name, the_url, redirect_url);
|
objectDelete($this, name, the_url, redirect_url);
|
||||||
}).on('click', '#btn_refresh_asset', function () {
|
}).on('click', '#btn_refresh_asset', function () {
|
||||||
alert('关闭alert, 等待完成, 自动刷新页面');
|
|
||||||
refreshAssetHardware()
|
refreshAssetHardware()
|
||||||
}).on('click', '#btn-test-is-alive', function () {
|
}).on('click', '#btn-test-is-alive', function () {
|
||||||
var the_url = "{% url 'api-assets:asset-alive-test' pk=asset.id %}";
|
var the_url = "{% url 'api-assets:asset-alive-test' pk=asset.id %}";
|
||||||
var error = function (data) {
|
|
||||||
alert(data)
|
var success = function(data) {
|
||||||
|
var task_id = data.task;
|
||||||
|
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||||
|
window.open(url, '', 'width=800,height=600')
|
||||||
};
|
};
|
||||||
alert('关闭alert, 等待完成');
|
|
||||||
APIUpdateAttr({
|
APIUpdateAttr({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
error: error,
|
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
success_message: "{% trans "Reachable" %}"
|
success: success
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -497,14 +497,17 @@ $(document).ready(function(){
|
||||||
}
|
}
|
||||||
|
|
||||||
var the_url = url.replace("{{ DEFAULT_PK }}", current_node.id);
|
var the_url = url.replace("{{ DEFAULT_PK }}", current_node.id);
|
||||||
function success() {
|
function success(data) {
|
||||||
rMenu.css({"visibility" : "hidden"});
|
rMenu.css({"visibility" : "hidden"});
|
||||||
|
var task_id = data.task;
|
||||||
|
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||||
|
window.open(url, '', 'width=800,height=600')
|
||||||
}
|
}
|
||||||
APIUpdateAttr({
|
APIUpdateAttr({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
method: "GET",
|
method: "GET",
|
||||||
success_message: "更新硬件信息任务下发成功",
|
success: success,
|
||||||
success: success
|
flash_message: false
|
||||||
});
|
});
|
||||||
|
|
||||||
})
|
})
|
||||||
|
@ -519,14 +522,17 @@ $(document).ready(function(){
|
||||||
}
|
}
|
||||||
|
|
||||||
var the_url = url.replace("{{ DEFAULT_PK }}", current_node.id);
|
var the_url = url.replace("{{ DEFAULT_PK }}", current_node.id);
|
||||||
function success() {
|
function success(data) {
|
||||||
rMenu.css({"visibility" : "hidden"});
|
rMenu.css({"visibility" : "hidden"});
|
||||||
|
var task_id = data.task;
|
||||||
|
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||||
|
window.open(url, '', 'width=800,height=600')
|
||||||
}
|
}
|
||||||
APIUpdateAttr({
|
APIUpdateAttr({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
method: "GET",
|
method: "GET",
|
||||||
success_message: "测试可连接性任务下发成功",
|
success: success,
|
||||||
success: success
|
flash_message: false
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.on('click', '.btn_asset_delete', function () {
|
.on('click', '.btn_asset_delete', function () {
|
||||||
|
|
|
@ -293,26 +293,30 @@ $(document).ready(function () {
|
||||||
})
|
})
|
||||||
.on('click', '.btn-push', function () {
|
.on('click', '.btn-push', function () {
|
||||||
var the_url = "{% url 'api-assets:system-user-push' pk=system_user.id %}";
|
var the_url = "{% url 'api-assets:system-user-push' pk=system_user.id %}";
|
||||||
var error = function (data) {
|
var success = function (data) {
|
||||||
alert(data)
|
var task_id = data.task;
|
||||||
|
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||||
|
window.open(url, '', 'width=800,height=600')
|
||||||
};
|
};
|
||||||
APIUpdateAttr({
|
APIUpdateAttr({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
error: error,
|
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
success_message: "{% trans "Task has been send, Go to ops task list seen result" %}"
|
success: success,
|
||||||
|
flash_message: false
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.on('click', '.btn-test-connective', function () {
|
.on('click', '.btn-test-connective', function () {
|
||||||
var the_url = "{% url 'api-assets:system-user-connective' pk=system_user.id %}";
|
var the_url = "{% url 'api-assets:system-user-connective' pk=system_user.id %}";
|
||||||
var error = function (data) {
|
var success = function (data) {
|
||||||
alert(data)
|
var task_id = data.task;
|
||||||
|
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||||
|
window.open(url, '', 'width=800,height=600')
|
||||||
};
|
};
|
||||||
APIUpdateAttr({
|
APIUpdateAttr({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
error: error,
|
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
success_message: "{% trans "Task has been send, seen left assets status" %}"
|
success: success,
|
||||||
|
flash_message: false
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -2,4 +2,4 @@ from __future__ import absolute_import
|
||||||
|
|
||||||
# This will make sure the app is always imported when
|
# This will make sure the app is always imported when
|
||||||
# Django starts so that shared_task will use this app.
|
# Django starts so that shared_task will use this app.
|
||||||
from .celery import app as celery_app
|
|
||||||
|
|
|
@ -2,14 +2,13 @@
|
||||||
#
|
#
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import Response, APIView
|
||||||
from rest_framework.views import Response
|
|
||||||
from ldap3 import Server, Connection
|
from ldap3 import Server, Connection
|
||||||
from django.core.mail import get_connection, send_mail
|
from django.core.mail import get_connection, send_mail
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from .permissions import IsSuperUser, IsAppUser
|
from .permissions import IsSuperUser
|
||||||
from .serializers import MailTestSerializer, LDAPTestSerializer
|
from .serializers import MailTestSerializer, LDAPTestSerializer
|
||||||
|
|
||||||
|
|
||||||
|
@ -105,3 +104,6 @@ class DjangoSettingsAPI(APIView):
|
||||||
if i.isupper():
|
if i.isupper():
|
||||||
configs[i] = str(getattr(settings, i))
|
configs[i] = str(getattr(settings, i))
|
||||||
return Response(configs)
|
return Response(configs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
|
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
create_success_msg = _("<b>%(name)s</b> was created successfully")
|
create_success_msg = _("<b>%(name)s</b> was created successfully")
|
||||||
update_success_msg = _("<b>%(name)s</b> was updated successfully")
|
update_success_msg = _("<b>%(name)s</b> was updated successfully")
|
||||||
|
FILE_END_GUARD = ">>> Content End <<<"
|
||||||
|
celery_task_pre_key = "CELERY_"
|
||||||
|
|
|
@ -79,3 +79,4 @@ class Setting(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = "settings"
|
db_table = "settings"
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
from django.core.mail import send_mail
|
from django.core.mail import send_mail
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from .celery import app
|
from celery import shared_task
|
||||||
from .utils import get_logger
|
from .utils import get_logger
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
|
||||||
|
|
||||||
@app.task
|
@shared_task
|
||||||
def send_mail_async(*args, **kwargs):
|
def send_mail_async(*args, **kwargs):
|
||||||
""" Using celery to send email async
|
""" Using celery to send email async
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
import re
|
import re
|
||||||
|
import sys
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from six import string_types
|
from six import string_types
|
||||||
import base64
|
import base64
|
||||||
|
@ -360,3 +361,20 @@ def get_signer():
|
||||||
signer = Signer(settings.SECRET_KEY)
|
signer = Signer(settings.SECRET_KEY)
|
||||||
return signer
|
return signer
|
||||||
|
|
||||||
|
|
||||||
|
class TeeObj:
|
||||||
|
origin_stdout = sys.stdout
|
||||||
|
|
||||||
|
def __init__(self, file_obj):
|
||||||
|
self.file_obj = file_obj
|
||||||
|
|
||||||
|
def write(self, msg):
|
||||||
|
self.origin_stdout.write(msg)
|
||||||
|
self.file_obj.write(msg.replace('*', ''))
|
||||||
|
|
||||||
|
def flush(self):
|
||||||
|
self.origin_stdout.flush()
|
||||||
|
self.file_obj.flush()
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self.file_obj.close()
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
from django.views.generic import TemplateView
|
|
||||||
from django.shortcuts import render, redirect
|
from django.core.cache import cache
|
||||||
|
from django.views.generic import TemplateView, View, DetailView
|
||||||
|
from django.shortcuts import render, redirect, Http404, reverse
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from .forms import EmailSettingForm, LDAPSettingForm, BasicSettingForm, \
|
from .forms import EmailSettingForm, LDAPSettingForm, BasicSettingForm, \
|
||||||
TerminalSettingForm
|
TerminalSettingForm
|
||||||
from .models import Setting
|
|
||||||
from .mixins import AdminUserRequiredMixin
|
from .mixins import AdminUserRequiredMixin
|
||||||
from .signals import ldap_auth_enable
|
from .signals import ldap_auth_enable
|
||||||
|
|
||||||
|
@ -120,3 +121,4 @@ class TerminalSettingView(AdminUserRequiredMixin, TemplateView):
|
||||||
context.update({"form": form})
|
context.update({"form": form})
|
||||||
return render(request, self.template_name, context)
|
return render(request, self.template_name, context)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Jumpserver 0.3.3\n"
|
"Project-Id-Version: Jumpserver 0.3.3\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2018-03-28 11:13+0800\n"
|
"POT-Creation-Date: 2018-04-02 15:49+0800\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
||||||
"Language-Team: Jumpserver team<ibuler@qq.com>\n"
|
"Language-Team: Jumpserver team<ibuler@qq.com>\n"
|
||||||
|
@ -96,7 +96,7 @@ msgid "Select nodes"
|
||||||
msgstr "选择节点"
|
msgstr "选择节点"
|
||||||
|
|
||||||
#: assets/forms/domain.py:14 assets/forms/label.py:13
|
#: assets/forms/domain.py:14 assets/forms/label.py:13
|
||||||
#: assets/models/asset.py:156 assets/templates/assets/admin_user_list.html:25
|
#: assets/models/asset.py:165 assets/templates/assets/admin_user_list.html:25
|
||||||
#: assets/templates/assets/domain_detail.html:60
|
#: assets/templates/assets/domain_detail.html:60
|
||||||
#: assets/templates/assets/domain_list.html:15
|
#: assets/templates/assets/domain_list.html:15
|
||||||
#: assets/templates/assets/label_list.html:16
|
#: assets/templates/assets/label_list.html:16
|
||||||
|
@ -121,8 +121,8 @@ msgstr "资产"
|
||||||
#: assets/templates/assets/system_user_detail.html:58
|
#: assets/templates/assets/system_user_detail.html:58
|
||||||
#: assets/templates/assets/system_user_list.html:26 common/models.py:26
|
#: assets/templates/assets/system_user_list.html:26 common/models.py:26
|
||||||
#: common/templates/common/terminal_setting.html:67
|
#: common/templates/common/terminal_setting.html:67
|
||||||
#: common/templates/common/terminal_setting.html:85 ops/models.py:31
|
#: common/templates/common/terminal_setting.html:85 ops/models/adhoc.py:36
|
||||||
#: ops/templates/ops/task_detail.html:56 ops/templates/ops/task_list.html:34
|
#: ops/templates/ops/task_detail.html:59 ops/templates/ops/task_list.html:34
|
||||||
#: perms/models.py:14 perms/templates/perms/asset_permission_detail.html:62
|
#: perms/models.py:14 perms/templates/perms/asset_permission_detail.html:62
|
||||||
#: perms/templates/perms/asset_permission_user.html:54 terminal/models.py:16
|
#: perms/templates/perms/asset_permission_user.html:54 terminal/models.py:16
|
||||||
#: terminal/models.py:149 terminal/templates/terminal/terminal_detail.html:43
|
#: terminal/models.py:149 terminal/templates/terminal/terminal_detail.html:43
|
||||||
|
@ -304,7 +304,7 @@ msgstr "创建者"
|
||||||
#: assets/models/label.py:23 assets/templates/assets/admin_user_detail.html:64
|
#: assets/models/label.py:23 assets/templates/assets/admin_user_detail.html:64
|
||||||
#: assets/templates/assets/domain_detail.html:68
|
#: assets/templates/assets/domain_detail.html:68
|
||||||
#: assets/templates/assets/system_user_detail.html:92
|
#: assets/templates/assets/system_user_detail.html:92
|
||||||
#: ops/templates/ops/adhoc_detail.html:90 ops/templates/ops/task_detail.html:60
|
#: ops/templates/ops/adhoc_detail.html:90 ops/templates/ops/task_detail.html:63
|
||||||
#: perms/models.py:23 perms/models.py:80
|
#: perms/models.py:23 perms/models.py:80
|
||||||
#: perms/templates/perms/asset_permission_detail.html:90
|
#: perms/templates/perms/asset_permission_detail.html:90
|
||||||
#: terminal/templates/terminal/terminal_detail.html:59 users/models/group.py:17
|
#: terminal/templates/terminal/terminal_detail.html:59 users/models/group.py:17
|
||||||
|
@ -323,7 +323,7 @@ msgstr "创建日期"
|
||||||
#: assets/templates/assets/domain_list.html:17
|
#: assets/templates/assets/domain_list.html:17
|
||||||
#: assets/templates/assets/system_user_detail.html:100
|
#: assets/templates/assets/system_user_detail.html:100
|
||||||
#: assets/templates/assets/system_user_list.html:33 common/models.py:30
|
#: assets/templates/assets/system_user_list.html:33 common/models.py:30
|
||||||
#: ops/models.py:37 perms/models.py:24 perms/models.py:81
|
#: ops/models/adhoc.py:42 perms/models.py:24 perms/models.py:81
|
||||||
#: perms/templates/perms/asset_permission_detail.html:98 terminal/models.py:26
|
#: perms/templates/perms/asset_permission_detail.html:98 terminal/models.py:26
|
||||||
#: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15
|
#: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15
|
||||||
#: users/models/user.py:47 users/templates/users/user_detail.html:111
|
#: users/models/user.py:47 users/templates/users/user_detail.html:111
|
||||||
|
@ -602,8 +602,8 @@ msgstr "可连接"
|
||||||
#: assets/templates/assets/domain_list.html:18
|
#: assets/templates/assets/domain_list.html:18
|
||||||
#: assets/templates/assets/label_list.html:17
|
#: assets/templates/assets/label_list.html:17
|
||||||
#: assets/templates/assets/system_user_list.html:34
|
#: assets/templates/assets/system_user_list.html:34
|
||||||
#: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:61
|
#: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:64
|
||||||
#: ops/templates/ops/task_history.html:62 ops/templates/ops/task_list.html:41
|
#: ops/templates/ops/task_history.html:65 ops/templates/ops/task_list.html:41
|
||||||
#: perms/templates/perms/asset_permission_list.html:72
|
#: perms/templates/perms/asset_permission_list.html:72
|
||||||
#: terminal/templates/terminal/session_list.html:80
|
#: terminal/templates/terminal/session_list.html:80
|
||||||
#: terminal/templates/terminal/terminal_list.html:36
|
#: terminal/templates/terminal/terminal_list.html:36
|
||||||
|
@ -774,9 +774,9 @@ msgstr "重置"
|
||||||
#: assets/templates/assets/domain_gateway_list.html:18
|
#: assets/templates/assets/domain_gateway_list.html:18
|
||||||
#: assets/templates/assets/system_user_asset.html:17
|
#: assets/templates/assets/system_user_asset.html:17
|
||||||
#: assets/templates/assets/system_user_detail.html:18
|
#: assets/templates/assets/system_user_detail.html:18
|
||||||
#: ops/templates/ops/adhoc_history.html:129
|
#: ops/templates/ops/adhoc_history.html:130
|
||||||
#: ops/templates/ops/task_adhoc.html:109
|
#: ops/templates/ops/task_adhoc.html:116
|
||||||
#: ops/templates/ops/task_history.html:132
|
#: ops/templates/ops/task_history.html:136
|
||||||
#: perms/templates/perms/asset_permission_asset.html:18
|
#: perms/templates/perms/asset_permission_asset.html:18
|
||||||
#: perms/templates/perms/asset_permission_detail.html:18
|
#: perms/templates/perms/asset_permission_detail.html:18
|
||||||
#: perms/templates/perms/asset_permission_user.html:18
|
#: perms/templates/perms/asset_permission_user.html:18
|
||||||
|
@ -849,7 +849,7 @@ msgstr "不可达"
|
||||||
#: assets/templates/assets/admin_user_list.html:28
|
#: assets/templates/assets/admin_user_list.html:28
|
||||||
#: assets/templates/assets/system_user_list.html:32
|
#: assets/templates/assets/system_user_list.html:32
|
||||||
#: ops/templates/ops/adhoc_history.html:54
|
#: ops/templates/ops/adhoc_history.html:54
|
||||||
#: ops/templates/ops/task_history.html:57
|
#: ops/templates/ops/task_history.html:60
|
||||||
msgid "Ratio"
|
msgid "Ratio"
|
||||||
msgstr "比例"
|
msgstr "比例"
|
||||||
|
|
||||||
|
@ -1172,15 +1172,15 @@ msgstr "资产管理"
|
||||||
msgid "System user asset"
|
msgid "System user asset"
|
||||||
msgstr "系统用户集群资产"
|
msgstr "系统用户集群资产"
|
||||||
|
|
||||||
#: common/api.py:19
|
#: common/api.py:18
|
||||||
msgid "Test mail sent to {}, please check"
|
msgid "Test mail sent to {}, please check"
|
||||||
msgstr "邮件已经发送{}, 请检查"
|
msgstr "邮件已经发送{}, 请检查"
|
||||||
|
|
||||||
#: common/api.py:53
|
#: common/api.py:52
|
||||||
msgid "Test ldap success"
|
msgid "Test ldap success"
|
||||||
msgstr "连接LDAP成功"
|
msgstr "连接LDAP成功"
|
||||||
|
|
||||||
#: common/api.py:91
|
#: common/api.py:90
|
||||||
msgid "Match {} s users"
|
msgid "Match {} s users"
|
||||||
msgstr "匹配 {} 个用户"
|
msgstr "匹配 {} 个用户"
|
||||||
|
|
||||||
|
@ -1299,7 +1299,7 @@ msgstr "资产列表排序"
|
||||||
msgid "Heartbeat interval"
|
msgid "Heartbeat interval"
|
||||||
msgstr "心跳间隔"
|
msgstr "心跳间隔"
|
||||||
|
|
||||||
#: common/forms.py:150 ops/models.py:32
|
#: common/forms.py:150 ops/models/adhoc.py:37
|
||||||
msgid "Units: seconds"
|
msgid "Units: seconds"
|
||||||
msgstr "单位: 秒"
|
msgstr "单位: 秒"
|
||||||
|
|
||||||
|
@ -1349,28 +1349,28 @@ msgstr "启用"
|
||||||
#: common/templates/common/email_setting.html:15
|
#: common/templates/common/email_setting.html:15
|
||||||
#: common/templates/common/ldap_setting.html:15
|
#: common/templates/common/ldap_setting.html:15
|
||||||
#: common/templates/common/terminal_setting.html:16
|
#: common/templates/common/terminal_setting.html:16
|
||||||
#: common/templates/common/terminal_setting.html:42 common/views.py:21
|
#: common/templates/common/terminal_setting.html:42 common/views.py:22
|
||||||
msgid "Basic setting"
|
msgid "Basic setting"
|
||||||
msgstr "基本设置"
|
msgstr "基本设置"
|
||||||
|
|
||||||
#: common/templates/common/basic_setting.html:18
|
#: common/templates/common/basic_setting.html:18
|
||||||
#: common/templates/common/email_setting.html:18
|
#: common/templates/common/email_setting.html:18
|
||||||
#: common/templates/common/ldap_setting.html:18
|
#: common/templates/common/ldap_setting.html:18
|
||||||
#: common/templates/common/terminal_setting.html:20 common/views.py:47
|
#: common/templates/common/terminal_setting.html:20 common/views.py:48
|
||||||
msgid "Email setting"
|
msgid "Email setting"
|
||||||
msgstr "邮件设置"
|
msgstr "邮件设置"
|
||||||
|
|
||||||
#: common/templates/common/basic_setting.html:21
|
#: common/templates/common/basic_setting.html:21
|
||||||
#: common/templates/common/email_setting.html:21
|
#: common/templates/common/email_setting.html:21
|
||||||
#: common/templates/common/ldap_setting.html:21
|
#: common/templates/common/ldap_setting.html:21
|
||||||
#: common/templates/common/terminal_setting.html:24 common/views.py:73
|
#: common/templates/common/terminal_setting.html:24 common/views.py:74
|
||||||
msgid "LDAP setting"
|
msgid "LDAP setting"
|
||||||
msgstr "LDAP设置"
|
msgstr "LDAP设置"
|
||||||
|
|
||||||
#: common/templates/common/basic_setting.html:24
|
#: common/templates/common/basic_setting.html:24
|
||||||
#: common/templates/common/email_setting.html:24
|
#: common/templates/common/email_setting.html:24
|
||||||
#: common/templates/common/ldap_setting.html:24
|
#: common/templates/common/ldap_setting.html:24
|
||||||
#: common/templates/common/terminal_setting.html:28 common/views.py:103
|
#: common/templates/common/terminal_setting.html:28 common/views.py:104
|
||||||
msgid "Terminal setting"
|
msgid "Terminal setting"
|
||||||
msgstr "终端设置"
|
msgstr "终端设置"
|
||||||
|
|
||||||
|
@ -1380,97 +1380,101 @@ msgstr "终端设置"
|
||||||
msgid "Type"
|
msgid "Type"
|
||||||
msgstr "类型"
|
msgstr "类型"
|
||||||
|
|
||||||
#: common/views.py:20 common/views.py:46 common/views.py:72 common/views.py:102
|
#: common/views.py:21 common/views.py:47 common/views.py:73 common/views.py:103
|
||||||
#: templates/_nav.html:73
|
#: templates/_nav.html:73
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr "系统设置"
|
msgstr "系统设置"
|
||||||
|
|
||||||
#: common/views.py:31 common/views.py:57 common/views.py:85 common/views.py:115
|
#: common/views.py:32 common/views.py:58 common/views.py:86 common/views.py:116
|
||||||
msgid "Update setting successfully, please restart program"
|
msgid "Update setting successfully, please restart program"
|
||||||
msgstr "更新设置成功, 请手动重启程序"
|
msgstr "更新设置成功, 请手动重启程序"
|
||||||
|
|
||||||
#: ops/models.py:32
|
#: ops/api.py:79
|
||||||
|
msgid "Waiting ..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ops/models/adhoc.py:37
|
||||||
msgid "Interval"
|
msgid "Interval"
|
||||||
msgstr "间隔"
|
msgstr "间隔"
|
||||||
|
|
||||||
#: ops/models.py:33
|
#: ops/models/adhoc.py:38
|
||||||
msgid "Crontab"
|
msgid "Crontab"
|
||||||
msgstr "Crontab"
|
msgstr "Crontab"
|
||||||
|
|
||||||
#: ops/models.py:33
|
#: ops/models/adhoc.py:38
|
||||||
msgid "5 * * * *"
|
msgid "5 * * * *"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ops/models.py:35
|
#: ops/models/adhoc.py:40
|
||||||
msgid "Callback"
|
msgid "Callback"
|
||||||
msgstr "回调"
|
msgstr "回调"
|
||||||
|
|
||||||
#: ops/models.py:149 ops/templates/ops/adhoc_detail.html:114
|
#: ops/models/adhoc.py:154 ops/templates/ops/adhoc_detail.html:114
|
||||||
msgid "Tasks"
|
msgid "Tasks"
|
||||||
msgstr "任务"
|
msgstr "任务"
|
||||||
|
|
||||||
#: ops/models.py:150 ops/templates/ops/adhoc_detail.html:57
|
#: ops/models/adhoc.py:155 ops/templates/ops/adhoc_detail.html:57
|
||||||
#: ops/templates/ops/task_adhoc.html:57
|
#: ops/templates/ops/task_adhoc.html:60
|
||||||
msgid "Pattern"
|
msgid "Pattern"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ops/models.py:151 ops/templates/ops/adhoc_detail.html:61
|
#: ops/models/adhoc.py:156 ops/templates/ops/adhoc_detail.html:61
|
||||||
msgid "Options"
|
msgid "Options"
|
||||||
msgstr "选项"
|
msgstr "选项"
|
||||||
|
|
||||||
#: ops/models.py:152 ops/templates/ops/adhoc_detail.html:53
|
#: ops/models/adhoc.py:157 ops/templates/ops/adhoc_detail.html:53
|
||||||
#: ops/templates/ops/task_adhoc.html:56 ops/templates/ops/task_list.html:37
|
#: ops/templates/ops/task_adhoc.html:59 ops/templates/ops/task_list.html:37
|
||||||
msgid "Hosts"
|
msgid "Hosts"
|
||||||
msgstr "主机"
|
msgstr "主机"
|
||||||
|
|
||||||
#: ops/models.py:153
|
#: ops/models/adhoc.py:158
|
||||||
msgid "Run as admin"
|
msgid "Run as admin"
|
||||||
msgstr "再次执行"
|
msgstr "再次执行"
|
||||||
|
|
||||||
#: ops/models.py:154 ops/templates/ops/adhoc_detail.html:72
|
#: ops/models/adhoc.py:159 ops/templates/ops/adhoc_detail.html:72
|
||||||
#: ops/templates/ops/adhoc_detail.html:77 ops/templates/ops/task_adhoc.html:58
|
#: ops/templates/ops/adhoc_detail.html:77 ops/templates/ops/task_adhoc.html:61
|
||||||
msgid "Run as"
|
msgid "Run as"
|
||||||
msgstr "用户"
|
msgstr "用户"
|
||||||
|
|
||||||
#: ops/models.py:155 ops/templates/ops/adhoc_detail.html:82
|
#: ops/models/adhoc.py:160 ops/templates/ops/adhoc_detail.html:82
|
||||||
#: ops/templates/ops/task_adhoc.html:59
|
#: ops/templates/ops/task_adhoc.html:62
|
||||||
msgid "Become"
|
msgid "Become"
|
||||||
msgstr "Become"
|
msgstr "Become"
|
||||||
|
|
||||||
#: ops/models.py:156 users/templates/users/user_group_detail.html:59
|
#: ops/models/adhoc.py:161 users/templates/users/user_group_detail.html:59
|
||||||
msgid "Create by"
|
msgid "Create by"
|
||||||
msgstr "创建者"
|
msgstr "创建者"
|
||||||
|
|
||||||
#: ops/models.py:307
|
#: ops/models/adhoc.py:323
|
||||||
msgid "Start time"
|
msgid "Start time"
|
||||||
msgstr "开始时间"
|
msgstr "开始时间"
|
||||||
|
|
||||||
#: ops/models.py:308
|
#: ops/models/adhoc.py:324
|
||||||
msgid "End time"
|
msgid "End time"
|
||||||
msgstr "完成时间"
|
msgstr "完成时间"
|
||||||
|
|
||||||
#: ops/models.py:309 ops/templates/ops/adhoc_history.html:57
|
#: ops/models/adhoc.py:325 ops/templates/ops/adhoc_history.html:57
|
||||||
#: ops/templates/ops/task_history.html:60 ops/templates/ops/task_list.html:40
|
#: ops/templates/ops/task_history.html:63 ops/templates/ops/task_list.html:40
|
||||||
msgid "Time"
|
msgid "Time"
|
||||||
msgstr "时间"
|
msgstr "时间"
|
||||||
|
|
||||||
#: ops/models.py:310 ops/templates/ops/adhoc_detail.html:106
|
#: ops/models/adhoc.py:326 ops/templates/ops/adhoc_detail.html:106
|
||||||
#: ops/templates/ops/adhoc_history.html:55
|
#: ops/templates/ops/adhoc_history.html:55
|
||||||
#: ops/templates/ops/adhoc_history_detail.html:66
|
#: ops/templates/ops/adhoc_history_detail.html:69
|
||||||
#: ops/templates/ops/task_detail.html:80 ops/templates/ops/task_history.html:58
|
#: ops/templates/ops/task_detail.html:83 ops/templates/ops/task_history.html:61
|
||||||
msgid "Is finished"
|
msgid "Is finished"
|
||||||
msgstr "是否完成"
|
msgstr "是否完成"
|
||||||
|
|
||||||
#: ops/models.py:311 ops/templates/ops/adhoc_history.html:56
|
#: ops/models/adhoc.py:327 ops/templates/ops/adhoc_history.html:56
|
||||||
#: ops/templates/ops/task_history.html:59
|
#: ops/templates/ops/task_history.html:62
|
||||||
msgid "Is success"
|
msgid "Is success"
|
||||||
msgstr "是否成功"
|
msgstr "是否成功"
|
||||||
|
|
||||||
#: ops/models.py:312
|
#: ops/models/adhoc.py:328
|
||||||
msgid "Adhoc raw result"
|
msgid "Adhoc raw result"
|
||||||
msgstr "结果"
|
msgstr "结果"
|
||||||
|
|
||||||
#: ops/models.py:313
|
#: ops/models/adhoc.py:329
|
||||||
msgid "Adhoc result summary"
|
msgid "Adhoc result summary"
|
||||||
msgstr "汇总"
|
msgstr "汇总"
|
||||||
|
|
||||||
|
@ -1485,8 +1489,8 @@ msgid "Version run history"
|
||||||
msgstr "执行历史"
|
msgstr "执行历史"
|
||||||
|
|
||||||
#: ops/templates/ops/adhoc_detail.html:49
|
#: ops/templates/ops/adhoc_detail.html:49
|
||||||
#: ops/templates/ops/adhoc_history_detail.html:46
|
#: ops/templates/ops/adhoc_history_detail.html:49
|
||||||
#: ops/templates/ops/task_detail.html:52
|
#: ops/templates/ops/task_detail.html:55
|
||||||
#: terminal/templates/terminal/session_list.html:70
|
#: terminal/templates/terminal/session_list.html:70
|
||||||
#: users/templates/users/login_log_list.html:48
|
#: users/templates/users/login_log_list.html:48
|
||||||
msgid "ID"
|
msgid "ID"
|
||||||
|
@ -1496,59 +1500,59 @@ msgstr "ID"
|
||||||
msgid "Run times"
|
msgid "Run times"
|
||||||
msgstr "执行次数"
|
msgstr "执行次数"
|
||||||
|
|
||||||
#: ops/templates/ops/adhoc_detail.html:98 ops/templates/ops/task_detail.html:72
|
#: ops/templates/ops/adhoc_detail.html:98 ops/templates/ops/task_detail.html:75
|
||||||
msgid "Last run"
|
msgid "Last run"
|
||||||
msgstr "最后运行"
|
msgstr "最后运行"
|
||||||
|
|
||||||
#: ops/templates/ops/adhoc_detail.html:102
|
#: ops/templates/ops/adhoc_detail.html:102
|
||||||
#: ops/templates/ops/adhoc_history_detail.html:62
|
#: ops/templates/ops/adhoc_history_detail.html:65
|
||||||
#: ops/templates/ops/task_detail.html:76
|
#: ops/templates/ops/task_detail.html:79
|
||||||
msgid "Time delta"
|
msgid "Time delta"
|
||||||
msgstr "运行时间"
|
msgstr "运行时间"
|
||||||
|
|
||||||
#: ops/templates/ops/adhoc_detail.html:110
|
#: ops/templates/ops/adhoc_detail.html:110
|
||||||
#: ops/templates/ops/adhoc_history_detail.html:70
|
#: ops/templates/ops/adhoc_history_detail.html:73
|
||||||
#: ops/templates/ops/task_detail.html:84
|
#: ops/templates/ops/task_detail.html:87
|
||||||
msgid "Is success "
|
msgid "Is success "
|
||||||
msgstr "成功"
|
msgstr "成功"
|
||||||
|
|
||||||
#: ops/templates/ops/adhoc_detail.html:131
|
#: ops/templates/ops/adhoc_detail.html:131
|
||||||
#: ops/templates/ops/task_detail.html:105
|
#: ops/templates/ops/task_detail.html:108
|
||||||
msgid "Last run failed hosts"
|
msgid "Last run failed hosts"
|
||||||
msgstr "最后运行失败主机"
|
msgstr "最后运行失败主机"
|
||||||
|
|
||||||
#: ops/templates/ops/adhoc_detail.html:151
|
#: ops/templates/ops/adhoc_detail.html:151
|
||||||
#: ops/templates/ops/adhoc_detail.html:176
|
#: ops/templates/ops/adhoc_detail.html:176
|
||||||
#: ops/templates/ops/task_detail.html:125
|
#: ops/templates/ops/task_detail.html:128
|
||||||
#: ops/templates/ops/task_detail.html:150
|
#: ops/templates/ops/task_detail.html:153
|
||||||
msgid "No hosts"
|
msgid "No hosts"
|
||||||
msgstr "没有主机"
|
msgstr "没有主机"
|
||||||
|
|
||||||
#: ops/templates/ops/adhoc_detail.html:161
|
#: ops/templates/ops/adhoc_detail.html:161
|
||||||
#: ops/templates/ops/task_detail.html:135
|
#: ops/templates/ops/task_detail.html:138
|
||||||
msgid "Last run success hosts"
|
msgid "Last run success hosts"
|
||||||
msgstr "最后运行成功主机"
|
msgstr "最后运行成功主机"
|
||||||
|
|
||||||
#: ops/templates/ops/adhoc_history.html:30
|
#: ops/templates/ops/adhoc_history.html:30
|
||||||
#: ops/templates/ops/task_history.html:33
|
#: ops/templates/ops/task_history.html:36
|
||||||
msgid "History of "
|
msgid "History of "
|
||||||
msgstr "执行历史"
|
msgstr "执行历史"
|
||||||
|
|
||||||
#: ops/templates/ops/adhoc_history.html:52
|
#: ops/templates/ops/adhoc_history.html:52
|
||||||
#: ops/templates/ops/adhoc_history_detail.html:58
|
#: ops/templates/ops/adhoc_history_detail.html:61
|
||||||
#: ops/templates/ops/task_history.html:55 terminal/models.py:132
|
#: ops/templates/ops/task_history.html:58 terminal/models.py:132
|
||||||
#: terminal/templates/terminal/session_list.html:77
|
#: terminal/templates/terminal/session_list.html:77
|
||||||
msgid "Date start"
|
msgid "Date start"
|
||||||
msgstr "开始日期"
|
msgstr "开始日期"
|
||||||
|
|
||||||
#: ops/templates/ops/adhoc_history.html:53
|
#: ops/templates/ops/adhoc_history.html:53
|
||||||
#: ops/templates/ops/task_history.html:56
|
#: ops/templates/ops/task_history.html:59
|
||||||
msgid "F/S/T"
|
msgid "F/S/T"
|
||||||
msgstr "失败/成功/总"
|
msgstr "失败/成功/总"
|
||||||
|
|
||||||
#: ops/templates/ops/adhoc_history.html:58
|
#: ops/templates/ops/adhoc_history.html:58
|
||||||
#: ops/templates/ops/adhoc_history_detail.html:54
|
#: ops/templates/ops/adhoc_history_detail.html:57
|
||||||
#: ops/templates/ops/task_adhoc.html:55 ops/templates/ops/task_history.html:61
|
#: ops/templates/ops/task_adhoc.html:58 ops/templates/ops/task_history.html:64
|
||||||
msgid "Version"
|
msgid "Version"
|
||||||
msgstr "版本"
|
msgstr "版本"
|
||||||
|
|
||||||
|
@ -1556,24 +1560,29 @@ msgstr "版本"
|
||||||
msgid "Run history detail"
|
msgid "Run history detail"
|
||||||
msgstr "执行历史详情"
|
msgstr "执行历史详情"
|
||||||
|
|
||||||
#: ops/templates/ops/adhoc_history_detail.html:27
|
#: ops/templates/ops/adhoc_history_detail.html:22
|
||||||
|
#: terminal/backends/command/models.py:14
|
||||||
|
msgid "Output"
|
||||||
|
msgstr "输出"
|
||||||
|
|
||||||
|
#: ops/templates/ops/adhoc_history_detail.html:30
|
||||||
msgid "History detail of"
|
msgid "History detail of"
|
||||||
msgstr "执行历史详情"
|
msgstr "执行历史详情"
|
||||||
|
|
||||||
#: ops/templates/ops/adhoc_history_detail.html:50
|
#: ops/templates/ops/adhoc_history_detail.html:53
|
||||||
msgid "Task name"
|
msgid "Task name"
|
||||||
msgstr "任务名称"
|
msgstr "任务名称"
|
||||||
|
|
||||||
#: ops/templates/ops/adhoc_history_detail.html:81
|
#: ops/templates/ops/adhoc_history_detail.html:84
|
||||||
msgid "Failed assets"
|
msgid "Failed assets"
|
||||||
msgstr "失败资产"
|
msgstr "失败资产"
|
||||||
|
|
||||||
#: ops/templates/ops/adhoc_history_detail.html:101
|
#: ops/templates/ops/adhoc_history_detail.html:104
|
||||||
#: ops/templates/ops/adhoc_history_detail.html:126
|
#: ops/templates/ops/adhoc_history_detail.html:129
|
||||||
msgid "No assets"
|
msgid "No assets"
|
||||||
msgstr "没有资产"
|
msgstr "没有资产"
|
||||||
|
|
||||||
#: ops/templates/ops/adhoc_history_detail.html:111
|
#: ops/templates/ops/adhoc_history_detail.html:114
|
||||||
msgid "Success assets"
|
msgid "Success assets"
|
||||||
msgstr "成功资产"
|
msgstr "成功资产"
|
||||||
|
|
||||||
|
@ -1592,25 +1601,30 @@ msgstr "任务各版本"
|
||||||
msgid "Run history"
|
msgid "Run history"
|
||||||
msgstr "执行历史"
|
msgstr "执行历史"
|
||||||
|
|
||||||
#: ops/templates/ops/task_adhoc.html:33
|
#: ops/templates/ops/task_adhoc.html:28 ops/templates/ops/task_detail.html:28
|
||||||
|
#: ops/templates/ops/task_history.html:28
|
||||||
|
msgid "Last run output"
|
||||||
|
msgstr "输出"
|
||||||
|
|
||||||
|
#: ops/templates/ops/task_adhoc.html:36
|
||||||
msgid "Versions of "
|
msgid "Versions of "
|
||||||
msgstr "版本"
|
msgstr "版本"
|
||||||
|
|
||||||
#: ops/templates/ops/task_adhoc.html:60
|
#: ops/templates/ops/task_adhoc.html:63
|
||||||
#: terminal/templates/terminal/command_list.html:76
|
#: terminal/templates/terminal/command_list.html:76
|
||||||
#: terminal/templates/terminal/session_detail.html:50
|
#: terminal/templates/terminal/session_detail.html:50
|
||||||
msgid "Datetime"
|
msgid "Datetime"
|
||||||
msgstr "日期"
|
msgstr "日期"
|
||||||
|
|
||||||
#: ops/templates/ops/task_detail.html:64
|
#: ops/templates/ops/task_detail.html:67
|
||||||
msgid "Total versions"
|
msgid "Total versions"
|
||||||
msgstr "版本数量"
|
msgstr "版本数量"
|
||||||
|
|
||||||
#: ops/templates/ops/task_detail.html:68
|
#: ops/templates/ops/task_detail.html:71
|
||||||
msgid "Latest version"
|
msgid "Latest version"
|
||||||
msgstr "最新版本"
|
msgstr "最新版本"
|
||||||
|
|
||||||
#: ops/templates/ops/task_detail.html:88
|
#: ops/templates/ops/task_detail.html:91
|
||||||
msgid "Contents"
|
msgid "Contents"
|
||||||
msgstr "内容"
|
msgstr "内容"
|
||||||
|
|
||||||
|
@ -1639,7 +1653,7 @@ msgstr "日期"
|
||||||
msgid "Run"
|
msgid "Run"
|
||||||
msgstr "执行"
|
msgstr "执行"
|
||||||
|
|
||||||
#: ops/templates/ops/task_list.html:123
|
#: ops/templates/ops/task_list.html:124
|
||||||
msgid "Task start: "
|
msgid "Task start: "
|
||||||
msgstr "任务开始: "
|
msgstr "任务开始: "
|
||||||
|
|
||||||
|
@ -1912,10 +1926,6 @@ msgstr "过滤"
|
||||||
msgid "Input"
|
msgid "Input"
|
||||||
msgstr "输入"
|
msgstr "输入"
|
||||||
|
|
||||||
#: terminal/backends/command/models.py:14
|
|
||||||
msgid "Output"
|
|
||||||
msgstr "输出"
|
|
||||||
|
|
||||||
#: terminal/backends/command/models.py:15
|
#: terminal/backends/command/models.py:15
|
||||||
#: terminal/templates/terminal/command_list.html:75
|
#: terminal/templates/terminal/command_list.html:75
|
||||||
#: terminal/templates/terminal/terminal_list.html:33
|
#: terminal/templates/terminal/terminal_list.html:33
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
|
from .celery import app as celery_app
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
# ~*~ coding: utf-8 ~*~
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
from ansible.plugins.callback.default import CallbackModule
|
from ansible.plugins.callback.default import CallbackModule
|
||||||
|
|
||||||
|
from .display import TeeObj
|
||||||
|
|
||||||
|
|
||||||
class AdHocResultCallback(CallbackModule):
|
class AdHocResultCallback(CallbackModule):
|
||||||
"""
|
"""
|
||||||
Task result Callback
|
Task result Callback
|
||||||
"""
|
"""
|
||||||
def __init__(self, display=None, options=None):
|
def __init__(self, display=None, options=None, file_obj=None):
|
||||||
# result_raw example: {
|
# result_raw example: {
|
||||||
# "ok": {"hostname": {"task_name": {},...},..},
|
# "ok": {"hostname": {"task_name": {},...},..},
|
||||||
# "failed": {"hostname": {"task_name": {}..}, ..},
|
# "failed": {"hostname": {"task_name": {}..}, ..},
|
||||||
|
@ -22,6 +26,8 @@ class AdHocResultCallback(CallbackModule):
|
||||||
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__()
|
super().__init__()
|
||||||
|
if file_obj is not None:
|
||||||
|
sys.stdout = TeeObj(file_obj)
|
||||||
|
|
||||||
def gather_result(self, t, res):
|
def gather_result(self, t, res):
|
||||||
self._clean_results(res._result, res._task.action)
|
self._clean_results(res._result, res._task.action)
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
class TeeObj:
|
||||||
|
origin_stdout = sys.stdout
|
||||||
|
|
||||||
|
def __init__(self, file_obj):
|
||||||
|
self.file_obj = file_obj
|
||||||
|
|
||||||
|
def write(self, msg):
|
||||||
|
self.origin_stdout.write(msg)
|
||||||
|
self.file_obj.write(msg.replace('*', ''))
|
||||||
|
|
||||||
|
def flush(self):
|
||||||
|
self.origin_stdout.flush()
|
||||||
|
self.file_obj.flush()
|
|
@ -29,7 +29,6 @@ class BaseHost(Host):
|
||||||
}
|
}
|
||||||
"groups": [],
|
"groups": [],
|
||||||
"vars": {},
|
"vars": {},
|
||||||
"other_ansbile_vars":
|
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
self.host_data = host_data
|
self.host_data = host_data
|
||||||
|
@ -79,7 +78,7 @@ class BaseInventory(InventoryManager):
|
||||||
variable_manager_class = VariableManager
|
variable_manager_class = VariableManager
|
||||||
host_manager_class = BaseHost
|
host_manager_class = BaseHost
|
||||||
|
|
||||||
def __init__(self, host_list=None):
|
def __init__(self, host_list=None, group_list=None):
|
||||||
"""
|
"""
|
||||||
用于生成动态构建Ansible Inventory. super().__init__ 会自动调用
|
用于生成动态构建Ansible Inventory. super().__init__ 会自动调用
|
||||||
host_list: [{
|
host_list: [{
|
||||||
|
@ -98,11 +97,14 @@ class BaseInventory(InventoryManager):
|
||||||
"vars": {},
|
"vars": {},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
group_list: [
|
||||||
|
{"name: "", children: [""]},
|
||||||
|
]
|
||||||
:param host_list:
|
:param host_list:
|
||||||
|
:param group_list
|
||||||
"""
|
"""
|
||||||
if host_list is None:
|
self.host_list = host_list or []
|
||||||
host_list = []
|
self.group_list = group_list or []
|
||||||
self.host_list = host_list
|
|
||||||
assert isinstance(host_list, list)
|
assert isinstance(host_list, list)
|
||||||
self.loader = self.loader_class()
|
self.loader = self.loader_class()
|
||||||
self.variable_manager = self.variable_manager_class()
|
self.variable_manager = self.variable_manager_class()
|
||||||
|
@ -114,25 +116,40 @@ class BaseInventory(InventoryManager):
|
||||||
def get_group(self, name):
|
def get_group(self, name):
|
||||||
return self._inventory.groups.get(name, None)
|
return self._inventory.groups.get(name, None)
|
||||||
|
|
||||||
def parse_sources(self, cache=False):
|
def get_or_create_group(self, name):
|
||||||
group_all = self.get_group('all')
|
group = self.get_group(name)
|
||||||
ungrouped = self.get_group('ungrouped')
|
if not group:
|
||||||
|
self.add_group(name)
|
||||||
|
return self.get_or_create_group(name)
|
||||||
|
else:
|
||||||
|
return group
|
||||||
|
|
||||||
|
def parse_groups(self):
|
||||||
|
for g in self.group_list:
|
||||||
|
parent = self.get_or_create_group(g.get("name"))
|
||||||
|
children = [self.get_or_create_group(n) for n in g.get('children', [])]
|
||||||
|
for child in children:
|
||||||
|
parent.add_child_group(child)
|
||||||
|
|
||||||
|
def parse_hosts(self):
|
||||||
|
group_all = self.get_or_create_group('all')
|
||||||
|
ungrouped = self.get_or_create_group('ungrouped')
|
||||||
for host_data in self.host_list:
|
for host_data in self.host_list:
|
||||||
host = self.host_manager_class(host_data=host_data)
|
host = self.host_manager_class(host_data=host_data)
|
||||||
self.hosts[host_data['hostname']] = host
|
self.hosts[host_data['hostname']] = host
|
||||||
groups_data = host_data.get('groups')
|
groups_data = host_data.get('groups')
|
||||||
if groups_data:
|
if groups_data:
|
||||||
for group_name in groups_data:
|
for group_name in groups_data:
|
||||||
group = self.get_group(group_name)
|
group = self.get_or_create_group(group_name)
|
||||||
if group is None:
|
|
||||||
self.add_group(group_name)
|
|
||||||
group = self.get_group(group_name)
|
|
||||||
group.add_host(host)
|
group.add_host(host)
|
||||||
else:
|
else:
|
||||||
ungrouped.add_host(host)
|
ungrouped.add_host(host)
|
||||||
group_all.add_host(host)
|
group_all.add_host(host)
|
||||||
|
|
||||||
|
def parse_sources(self, cache=False):
|
||||||
|
self.parse_groups()
|
||||||
|
self.parse_hosts()
|
||||||
|
|
||||||
def get_matched_hosts(self, pattern):
|
def get_matched_hosts(self, pattern):
|
||||||
return self.get_hosts(pattern)
|
return self.get_hosts(pattern)
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ from ansible.parsing.dataloader import DataLoader
|
||||||
from ansible.executor.playbook_executor import PlaybookExecutor
|
from ansible.executor.playbook_executor import PlaybookExecutor
|
||||||
from ansible.playbook.play import Play
|
from ansible.playbook.play import Play
|
||||||
import ansible.constants as C
|
import ansible.constants as C
|
||||||
|
from ansible.utils.display import Display
|
||||||
|
|
||||||
from .callback import AdHocResultCallback, PlaybookResultCallBack, \
|
from .callback import AdHocResultCallback, PlaybookResultCallBack, \
|
||||||
CommandResultCallback
|
CommandResultCallback
|
||||||
|
@ -21,6 +22,13 @@ C.HOST_KEY_CHECKING = False
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class CustomDisplay(Display):
|
||||||
|
def display(self, msg, color=None, stderr=False, screen_only=False, log_only=False):
|
||||||
|
pass
|
||||||
|
|
||||||
|
display = CustomDisplay()
|
||||||
|
|
||||||
|
|
||||||
Options = namedtuple('Options', [
|
Options = namedtuple('Options', [
|
||||||
'listtags', 'listtasks', 'listhosts', 'syntax', 'connection',
|
'listtags', 'listtasks', 'listhosts', 'syntax', 'connection',
|
||||||
'module_path', 'forks', 'remote_user', 'private_key_file', 'timeout',
|
'module_path', 'forks', 'remote_user', 'private_key_file', 'timeout',
|
||||||
|
@ -123,20 +131,22 @@ class AdHocRunner:
|
||||||
ADHoc Runner接口
|
ADHoc Runner接口
|
||||||
"""
|
"""
|
||||||
results_callback_class = AdHocResultCallback
|
results_callback_class = AdHocResultCallback
|
||||||
|
results_callback = None
|
||||||
loader_class = DataLoader
|
loader_class = DataLoader
|
||||||
variable_manager_class = VariableManager
|
variable_manager_class = VariableManager
|
||||||
options = get_default_options()
|
|
||||||
default_options = get_default_options()
|
default_options = get_default_options()
|
||||||
|
|
||||||
def __init__(self, inventory, options=None):
|
def __init__(self, inventory, options=None):
|
||||||
if options:
|
self.options = self.update_options(options)
|
||||||
self.options = options
|
|
||||||
self.inventory = inventory
|
self.inventory = inventory
|
||||||
self.loader = DataLoader()
|
self.loader = DataLoader()
|
||||||
self.variable_manager = VariableManager(
|
self.variable_manager = VariableManager(
|
||||||
loader=self.loader, inventory=self.inventory
|
loader=self.loader, inventory=self.inventory
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_result_callback(self, file_obj=None):
|
||||||
|
return self.__class__.results_callback_class(file_obj=file_obj)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_module_args(module_name, module_args=''):
|
def check_module_args(module_name, module_args=''):
|
||||||
if module_name in C.MODULE_REQUIRE_ARGS and not module_args:
|
if module_name in C.MODULE_REQUIRE_ARGS and not module_args:
|
||||||
|
@ -160,19 +170,24 @@ class AdHocRunner:
|
||||||
cleaned_tasks.append(task)
|
cleaned_tasks.append(task)
|
||||||
return cleaned_tasks
|
return cleaned_tasks
|
||||||
|
|
||||||
def set_option(self, k, v):
|
def update_options(self, options):
|
||||||
kwargs = {k: v}
|
if options and isinstance(options, dict):
|
||||||
self.options = self.options._replace(**kwargs)
|
options = self.__class__.default_options._replace(**options)
|
||||||
|
else:
|
||||||
|
options = self.__class__.default_options
|
||||||
|
return options
|
||||||
|
|
||||||
def run(self, tasks, pattern, play_name='Ansible Ad-hoc', gather_facts='no'):
|
def run(self, tasks, pattern, play_name='Ansible Ad-hoc', gather_facts='no', file_obj=None):
|
||||||
"""
|
"""
|
||||||
:param tasks: [{'action': {'module': 'shell', 'args': 'ls'}, ...}, ]
|
:param tasks: [{'action': {'module': 'shell', 'args': 'ls'}, ...}, ]
|
||||||
:param pattern: all, *, or others
|
:param pattern: all, *, or others
|
||||||
:param play_name: The play name
|
:param play_name: The play name
|
||||||
|
:param gather_facts:
|
||||||
|
:param file_obj: logging to file_obj
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
self.check_pattern(pattern)
|
self.check_pattern(pattern)
|
||||||
results_callback = self.results_callback_class()
|
self.results_callback = self.get_result_callback(file_obj)
|
||||||
cleaned_tasks = self.clean_tasks(tasks)
|
cleaned_tasks = self.clean_tasks(tasks)
|
||||||
|
|
||||||
play_source = dict(
|
play_source = dict(
|
||||||
|
@ -193,16 +208,16 @@ class AdHocRunner:
|
||||||
variable_manager=self.variable_manager,
|
variable_manager=self.variable_manager,
|
||||||
loader=self.loader,
|
loader=self.loader,
|
||||||
options=self.options,
|
options=self.options,
|
||||||
stdout_callback=results_callback,
|
stdout_callback=self.results_callback,
|
||||||
passwords=self.options.passwords,
|
passwords=self.options.passwords,
|
||||||
)
|
)
|
||||||
logger.debug("Get inventory matched hosts: {}".format(
|
print("Get matched hosts: {}".format(
|
||||||
self.inventory.get_matched_hosts(pattern)
|
self.inventory.get_matched_hosts(pattern)
|
||||||
))
|
))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
tqm.run(play)
|
tqm.run(play)
|
||||||
return results_callback
|
return self.results_callback
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise AnsibleError(e)
|
raise AnsibleError(e)
|
||||||
finally:
|
finally:
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
# ~*~ coding: utf-8 ~*~
|
||||||
|
import uuid
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.cache import cache
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
from rest_framework import viewsets, generics
|
from rest_framework import viewsets, generics
|
||||||
from rest_framework.views import Response
|
from rest_framework.views import Response
|
||||||
|
|
||||||
from .hands import IsSuperUser
|
from .hands import IsSuperUser
|
||||||
from .models import Task, AdHoc, AdHocRunHistory
|
from .models import Task, AdHoc, AdHocRunHistory, CeleryTask
|
||||||
from .serializers import TaskSerializer, AdHocSerializer, AdHocRunHistorySerializer
|
from .serializers import TaskSerializer, AdHocSerializer, \
|
||||||
|
AdHocRunHistorySerializer
|
||||||
from .tasks import run_ansible_task
|
from .tasks import run_ansible_task
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,8 +28,8 @@ class TaskRun(generics.RetrieveAPIView):
|
||||||
|
|
||||||
def retrieve(self, request, *args, **kwargs):
|
def retrieve(self, request, *args, **kwargs):
|
||||||
task = self.get_object()
|
task = self.get_object()
|
||||||
run_ansible_task.delay(str(task.id))
|
t = run_ansible_task.delay(str(task.id))
|
||||||
return Response({"msg": "start"})
|
return Response({"task": t.id})
|
||||||
|
|
||||||
|
|
||||||
class AdHocViewSet(viewsets.ModelViewSet):
|
class AdHocViewSet(viewsets.ModelViewSet):
|
||||||
|
@ -58,3 +62,30 @@ class AdHocRunHistorySet(viewsets.ModelViewSet):
|
||||||
adhoc = get_object_or_404(AdHoc, id=adhoc_id)
|
adhoc = get_object_or_404(AdHoc, id=adhoc_id)
|
||||||
self.queryset = self.queryset.filter(adhoc=adhoc)
|
self.queryset = self.queryset.filter(adhoc=adhoc)
|
||||||
return self.queryset
|
return self.queryset
|
||||||
|
|
||||||
|
|
||||||
|
class CeleryTaskLogApi(generics.RetrieveAPIView):
|
||||||
|
permission_classes = (IsSuperUser,)
|
||||||
|
buff_size = 1024 * 10
|
||||||
|
end = False
|
||||||
|
queryset = CeleryTask.objects.all()
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
mark = request.query_params.get("mark") or str(uuid.uuid4())
|
||||||
|
task = super().get_object()
|
||||||
|
log_path = task.full_log_path
|
||||||
|
|
||||||
|
if not log_path or not os.path.isfile(log_path):
|
||||||
|
return Response({"data": _("Waiting ...")}, status=203)
|
||||||
|
|
||||||
|
with open(log_path, 'r') as f:
|
||||||
|
offset = cache.get(mark, 0)
|
||||||
|
f.seek(offset)
|
||||||
|
data = f.read(self.buff_size).replace('\n', '\r\n')
|
||||||
|
mark = str(uuid.uuid4())
|
||||||
|
cache.set(mark, f.tell(), 5)
|
||||||
|
|
||||||
|
if data == '' and task.is_finished():
|
||||||
|
self.end = True
|
||||||
|
return Response({"data": data, 'end': self.end, 'mark': mark})
|
||||||
|
|
||||||
|
|
|
@ -5,3 +5,7 @@ from django.apps import AppConfig
|
||||||
|
|
||||||
class OpsConfig(AppConfig):
|
class OpsConfig(AppConfig):
|
||||||
name = 'ops'
|
name = 'ops'
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
super().ready()
|
||||||
|
from .celery import signal_handler
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from celery import Celery
|
||||||
|
|
||||||
|
# set the default Django settings module for the 'celery' program.
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'jumpserver.settings')
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
app = Celery('jumpserver')
|
||||||
|
|
||||||
|
# Using a string here means the worker will not have to
|
||||||
|
# pickle the object when using Windows.
|
||||||
|
app.config_from_object('django.conf:settings', namespace='CELERY')
|
||||||
|
app.autodiscover_tasks(lambda: [app_config.split('.')[0] for app_config in settings.INSTALLED_APPS])
|
|
@ -0,0 +1,3 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
import os
|
||||||
|
import datetime
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.core.cache import cache
|
||||||
|
from django.db import transaction
|
||||||
|
from celery import subtask
|
||||||
|
from celery.signals import worker_ready, worker_shutdown, task_prerun, \
|
||||||
|
task_postrun, after_task_publish
|
||||||
|
from django_celery_beat.models import PeriodicTask
|
||||||
|
|
||||||
|
from common.utils import get_logger, TeeObj, get_object_or_none
|
||||||
|
from common.const import celery_task_pre_key
|
||||||
|
from .utils import get_after_app_ready_tasks, get_after_app_shutdown_clean_tasks
|
||||||
|
from ..models import CeleryTask
|
||||||
|
|
||||||
|
logger = get_logger(__file__)
|
||||||
|
|
||||||
|
|
||||||
|
@worker_ready.connect
|
||||||
|
def on_app_ready(sender=None, headers=None, body=None, **kwargs):
|
||||||
|
if cache.get("CELERY_APP_READY", 0) == 1:
|
||||||
|
return
|
||||||
|
cache.set("CELERY_APP_READY", 1, 10)
|
||||||
|
logger.debug("App ready signal recv")
|
||||||
|
tasks = get_after_app_ready_tasks()
|
||||||
|
logger.debug("Start need start task: [{}]".format(
|
||||||
|
", ".join(tasks))
|
||||||
|
)
|
||||||
|
for task in tasks:
|
||||||
|
subtask(task).delay()
|
||||||
|
|
||||||
|
|
||||||
|
@worker_shutdown.connect
|
||||||
|
def after_app_shutdown(sender=None, headers=None, body=None, **kwargs):
|
||||||
|
if cache.get("CELERY_APP_SHUTDOWN", 0) == 1:
|
||||||
|
return
|
||||||
|
cache.set("CELERY_APP_SHUTDOWN", 1, 10)
|
||||||
|
tasks = get_after_app_shutdown_clean_tasks()
|
||||||
|
logger.debug("App shutdown signal recv")
|
||||||
|
logger.debug("Clean need cleaned period tasks: [{}]".format(
|
||||||
|
', '.join(tasks))
|
||||||
|
)
|
||||||
|
PeriodicTask.objects.filter(name__in=tasks).delete()
|
||||||
|
|
||||||
|
|
||||||
|
@after_task_publish.connect
|
||||||
|
def after_task_publish_signal_handler(sender, headers=None, **kwargs):
|
||||||
|
CeleryTask.objects.create(
|
||||||
|
id=headers["id"], status=CeleryTask.WAITING, name=headers["task"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@task_prerun.connect
|
||||||
|
def pre_run_task_signal_handler(sender, task_id=None, task=None, **kwargs):
|
||||||
|
t = get_object_or_none(CeleryTask, id=task_id)
|
||||||
|
if t is None:
|
||||||
|
logger.warn("Not get the task: {}".format(task_id))
|
||||||
|
return
|
||||||
|
now = datetime.datetime.now().strftime("%Y-%m-%d")
|
||||||
|
log_path = os.path.join(now, task_id + '.log')
|
||||||
|
full_path = os.path.join(CeleryTask.LOG_DIR, log_path)
|
||||||
|
|
||||||
|
if not os.path.exists(os.path.dirname(full_path)):
|
||||||
|
os.makedirs(os.path.dirname(full_path))
|
||||||
|
with transaction.atomic():
|
||||||
|
t.date_start = timezone.now()
|
||||||
|
t.status = CeleryTask.RUNNING
|
||||||
|
t.log_path = log_path
|
||||||
|
t.save()
|
||||||
|
f = open(full_path, 'w')
|
||||||
|
tee = TeeObj(f)
|
||||||
|
sys.stdout = tee
|
||||||
|
task.log_f = tee
|
||||||
|
|
||||||
|
|
||||||
|
@task_postrun.connect
|
||||||
|
def post_run_task_signal_handler(sender, task_id=None, task=None, **kwargs):
|
||||||
|
t = get_object_or_none(CeleryTask, id=task_id)
|
||||||
|
if t is None:
|
||||||
|
logger.warn("Not get the task: {}".format(task_id))
|
||||||
|
return
|
||||||
|
with transaction.atomic():
|
||||||
|
t.status = CeleryTask.FINISHED
|
||||||
|
t.date_finished = timezone.now()
|
||||||
|
t.save()
|
||||||
|
task.log_f.flush()
|
||||||
|
sys.stdout = task.log_f.origin_stdout
|
||||||
|
task.log_f.close()
|
||||||
|
|
|
@ -1,33 +1,50 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
import os
|
|
||||||
import json
|
import json
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
from celery import Celery, subtask
|
|
||||||
from celery.signals import worker_ready, worker_shutdown
|
|
||||||
from django.db.utils import ProgrammingError, OperationalError
|
from django.db.utils import ProgrammingError, OperationalError
|
||||||
|
|
||||||
from .utils import get_logger
|
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
|
||||||
|
|
||||||
# set the default Django settings module for the 'celery' program.
|
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'jumpserver.settings')
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
from django_celery_beat.models import PeriodicTask, IntervalSchedule, CrontabSchedule
|
||||||
|
|
||||||
app = Celery('jumpserver')
|
|
||||||
|
|
||||||
# Using a string here means the worker will not have to
|
def add_register_period_task(name):
|
||||||
# pickle the object when using Windows.
|
key = "__REGISTER_PERIODIC_TASKS"
|
||||||
app.config_from_object('django.conf:settings', namespace='CELERY')
|
value = cache.get(key, [])
|
||||||
app.autodiscover_tasks(lambda: [app_config.split('.')[0] for app_config in settings.INSTALLED_APPS])
|
value.append(name)
|
||||||
|
cache.set(key, value)
|
||||||
|
|
||||||
|
|
||||||
|
def get_register_period_tasks():
|
||||||
|
key = "__REGISTER_PERIODIC_TASKS"
|
||||||
|
return cache.get(key, [])
|
||||||
|
|
||||||
|
|
||||||
|
def add_after_app_shutdown_clean_task(name):
|
||||||
|
key = "__AFTER_APP_SHUTDOWN_CLEAN_TASKS"
|
||||||
|
value = cache.get(key, [])
|
||||||
|
value.append(name)
|
||||||
|
cache.set(key, value)
|
||||||
|
|
||||||
|
|
||||||
|
def get_after_app_shutdown_clean_tasks():
|
||||||
|
key = "__AFTER_APP_SHUTDOWN_CLEAN_TASKS"
|
||||||
|
return cache.get(key, [])
|
||||||
|
|
||||||
|
|
||||||
|
def add_after_app_ready_task(name):
|
||||||
|
key = "__AFTER_APP_READY_RUN_TASKS"
|
||||||
|
value = cache.get(key, [])
|
||||||
|
value.append(name)
|
||||||
|
cache.set(key, value)
|
||||||
|
|
||||||
|
|
||||||
|
def get_after_app_ready_tasks():
|
||||||
|
key = "__AFTER_APP_READY_RUN_TASKS"
|
||||||
|
return cache.get(key, [])
|
||||||
|
|
||||||
|
|
||||||
def create_or_update_celery_periodic_tasks(tasks):
|
def create_or_update_celery_periodic_tasks(tasks):
|
||||||
from django_celery_beat.models import PeriodicTask, IntervalSchedule, CrontabSchedule
|
|
||||||
"""
|
"""
|
||||||
:param tasks: {
|
:param tasks: {
|
||||||
'add-every-monday-morning': {
|
'add-every-monday-morning': {
|
||||||
|
@ -106,11 +123,6 @@ def delete_celery_periodic_task(task_name):
|
||||||
PeriodicTask.objects.filter(name=task_name).delete()
|
PeriodicTask.objects.filter(name=task_name).delete()
|
||||||
|
|
||||||
|
|
||||||
__REGISTER_PERIODIC_TASKS = []
|
|
||||||
__AFTER_APP_SHUTDOWN_CLEAN_TASKS = []
|
|
||||||
__AFTER_APP_READY_RUN_TASKS = []
|
|
||||||
|
|
||||||
|
|
||||||
def register_as_period_task(crontab=None, interval=None):
|
def register_as_period_task(crontab=None, interval=None):
|
||||||
"""
|
"""
|
||||||
Warning: Task must be have not any args and kwargs
|
Warning: Task must be have not any args and kwargs
|
||||||
|
@ -128,7 +140,7 @@ def register_as_period_task(crontab=None, interval=None):
|
||||||
# Because when this decorator run, the task was not created,
|
# Because when this decorator run, the task was not created,
|
||||||
# So we can't use func.name
|
# So we can't use func.name
|
||||||
name = '{func.__module__}.{func.__name__}'.format(func=func)
|
name = '{func.__module__}.{func.__name__}'.format(func=func)
|
||||||
if name not in __REGISTER_PERIODIC_TASKS:
|
if name not in get_register_period_tasks():
|
||||||
create_or_update_celery_periodic_tasks({
|
create_or_update_celery_periodic_tasks({
|
||||||
name: {
|
name: {
|
||||||
'task': name,
|
'task': name,
|
||||||
|
@ -138,7 +150,7 @@ def register_as_period_task(crontab=None, interval=None):
|
||||||
'enabled': True,
|
'enabled': True,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
__REGISTER_PERIODIC_TASKS.append(name)
|
add_register_period_task(name)
|
||||||
|
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
|
@ -151,13 +163,12 @@ def after_app_ready_start(func):
|
||||||
# Because when this decorator run, the task was not created,
|
# Because when this decorator run, the task was not created,
|
||||||
# So we can't use func.name
|
# So we can't use func.name
|
||||||
name = '{func.__module__}.{func.__name__}'.format(func=func)
|
name = '{func.__module__}.{func.__name__}'.format(func=func)
|
||||||
if name not in __AFTER_APP_READY_RUN_TASKS:
|
if name not in get_after_app_ready_tasks():
|
||||||
__AFTER_APP_READY_RUN_TASKS.append(name)
|
add_after_app_ready_task(name)
|
||||||
|
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def decorate(*args, **kwargs):
|
def decorate(*args, **kwargs):
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
|
|
||||||
return decorate
|
return decorate
|
||||||
|
|
||||||
|
|
||||||
|
@ -165,37 +176,10 @@ def after_app_shutdown_clean(func):
|
||||||
# Because when this decorator run, the task was not created,
|
# Because when this decorator run, the task was not created,
|
||||||
# So we can't use func.name
|
# So we can't use func.name
|
||||||
name = '{func.__module__}.{func.__name__}'.format(func=func)
|
name = '{func.__module__}.{func.__name__}'.format(func=func)
|
||||||
if name not in __AFTER_APP_READY_RUN_TASKS:
|
if name not in get_after_app_shutdown_clean_tasks():
|
||||||
__AFTER_APP_SHUTDOWN_CLEAN_TASKS.append(name)
|
add_after_app_shutdown_clean_task(name)
|
||||||
|
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def decorate(*args, **kwargs):
|
def decorate(*args, **kwargs):
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
|
|
||||||
return decorate
|
return decorate
|
||||||
|
|
||||||
|
|
||||||
@worker_ready.connect
|
|
||||||
def on_app_ready(sender=None, headers=None, body=None, **kwargs):
|
|
||||||
if cache.get("CELERY_APP_READY", 0) == 1:
|
|
||||||
return
|
|
||||||
cache.set("CELERY_APP_READY", 1, 10)
|
|
||||||
logger.debug("App ready signal recv")
|
|
||||||
logger.debug("Start need start task: [{}]".format(
|
|
||||||
", ".join(__AFTER_APP_READY_RUN_TASKS))
|
|
||||||
)
|
|
||||||
for task in __AFTER_APP_READY_RUN_TASKS:
|
|
||||||
subtask(task).delay()
|
|
||||||
|
|
||||||
|
|
||||||
@worker_shutdown.connect
|
|
||||||
def after_app_shutdown(sender=None, headers=None, body=None, **kwargs):
|
|
||||||
if cache.get("CELERY_APP_SHUTDOWN", 0) == 1:
|
|
||||||
return
|
|
||||||
cache.set("CELERY_APP_SHUTDOWN", 1, 10)
|
|
||||||
from django_celery_beat.models import PeriodicTask
|
|
||||||
logger.debug("App shutdown signal recv")
|
|
||||||
logger.debug("Clean need cleaned period tasks: [{}]".format(
|
|
||||||
', '.join(__AFTER_APP_SHUTDOWN_CLEAN_TASKS))
|
|
||||||
)
|
|
||||||
PeriodicTask.objects.filter(name__in=__AFTER_APP_SHUTDOWN_CLEAN_TASKS).delete()
|
|
|
@ -9,29 +9,18 @@ __all__ = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def make_proxy_command(asset):
|
|
||||||
gateway = asset.domain.random_gateway()
|
|
||||||
|
|
||||||
proxy_command = [
|
|
||||||
"ssh", "-p", str(gateway.port),
|
|
||||||
"{}@{}".format(gateway.username, gateway.ip),
|
|
||||||
"-W", "%h:%p", "-q",
|
|
||||||
]
|
|
||||||
|
|
||||||
if gateway.password:
|
|
||||||
proxy_command.insert(0, "sshpass -p {}".format(gateway.password))
|
|
||||||
if gateway.private_key:
|
|
||||||
proxy_command.append("-i {}".format(gateway.private_key_file))
|
|
||||||
|
|
||||||
return {"ansible_ssh_common_args": "'-o ProxyCommand={}'".format(" ".join(proxy_command))}
|
|
||||||
|
|
||||||
|
|
||||||
class JMSInventory(BaseInventory):
|
class JMSInventory(BaseInventory):
|
||||||
"""
|
"""
|
||||||
JMS Inventory is the manager with jumpserver assets, so you can
|
JMS Inventory is the manager with jumpserver assets, so you can
|
||||||
write you own manager, construct you inventory
|
write you own manager, construct you inventory
|
||||||
"""
|
"""
|
||||||
def __init__(self, hostname_list, run_as_admin=False, run_as=None, become_info=None):
|
def __init__(self, hostname_list, run_as_admin=False, run_as=None, become_info=None):
|
||||||
|
"""
|
||||||
|
:param hostname_list: ["test1", ]
|
||||||
|
:param run_as_admin: True 是否使用管理用户去执行, 每台服务器的管理用户可能不同
|
||||||
|
:param run_as: 是否统一使用某个系统用户去执行
|
||||||
|
:param become_info: 是否become成某个用户去执行
|
||||||
|
"""
|
||||||
self.hostname_list = hostname_list
|
self.hostname_list = hostname_list
|
||||||
self.using_admin = run_as_admin
|
self.using_admin = run_as_admin
|
||||||
self.run_as = run_as
|
self.run_as = run_as
|
||||||
|
@ -41,23 +30,14 @@ class JMSInventory(BaseInventory):
|
||||||
host_list = []
|
host_list = []
|
||||||
|
|
||||||
for asset in assets:
|
for asset in assets:
|
||||||
vars = {}
|
info = self.convert_to_ansible(asset, run_as_admin=run_as_admin)
|
||||||
if run_as_admin:
|
|
||||||
info = asset._to_secret_json()
|
|
||||||
else:
|
|
||||||
info = asset.to_json()
|
|
||||||
|
|
||||||
info["vars"] = vars
|
|
||||||
if asset.domain and asset.domain.has_gateway():
|
|
||||||
vars.update(make_proxy_command(asset))
|
|
||||||
info.update(vars)
|
|
||||||
|
|
||||||
host_list.append(info)
|
host_list.append(info)
|
||||||
|
|
||||||
if run_as:
|
if run_as:
|
||||||
run_user_info = self.get_run_user_info()
|
run_user_info = self.get_run_user_info()
|
||||||
for host in host_list:
|
for host in host_list:
|
||||||
host.update(run_user_info)
|
host.update(run_user_info)
|
||||||
|
|
||||||
if become_info:
|
if become_info:
|
||||||
for host in host_list:
|
for host in host_list:
|
||||||
host.update(become_info)
|
host.update(become_info)
|
||||||
|
@ -67,9 +47,57 @@ class JMSInventory(BaseInventory):
|
||||||
assets = get_assets_by_hostname_list(self.hostname_list)
|
assets = get_assets_by_hostname_list(self.hostname_list)
|
||||||
return assets
|
return assets
|
||||||
|
|
||||||
|
def convert_to_ansible(self, asset, run_as_admin=False):
|
||||||
|
info = {
|
||||||
|
'id': asset.id,
|
||||||
|
'hostname': asset.hostname,
|
||||||
|
'ip': asset.ip,
|
||||||
|
'port': asset.port,
|
||||||
|
'vars': dict(),
|
||||||
|
'groups': [],
|
||||||
|
}
|
||||||
|
if asset.domain and asset.domain.has_gateway():
|
||||||
|
info["vars"].update(self.make_proxy_command(asset))
|
||||||
|
if run_as_admin:
|
||||||
|
info.update(asset.get_auth_info())
|
||||||
|
for node in asset.nodes.all():
|
||||||
|
info["groups"].append(node.value)
|
||||||
|
for label in asset.labels.all():
|
||||||
|
info["vars"].update({
|
||||||
|
label.name: label.value
|
||||||
|
})
|
||||||
|
info["groups"].append("{}:{}".format(label.name, label.value))
|
||||||
|
if asset.domain:
|
||||||
|
info["vars"].update({
|
||||||
|
"domain": asset.domain.name,
|
||||||
|
})
|
||||||
|
info["groups"].append("domain_"+asset.domain.name)
|
||||||
|
return info
|
||||||
|
|
||||||
def get_run_user_info(self):
|
def get_run_user_info(self):
|
||||||
system_user = get_system_user_by_name(self.run_as)
|
system_user = get_system_user_by_name(self.run_as)
|
||||||
if not system_user:
|
if not system_user:
|
||||||
return {}
|
return {}
|
||||||
else:
|
else:
|
||||||
return system_user._to_secret_json()
|
return system_user._to_secret_json()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def make_proxy_command(asset):
|
||||||
|
gateway = asset.domain.random_gateway()
|
||||||
|
proxy_command_list = [
|
||||||
|
"ssh", "-p", str(gateway.port),
|
||||||
|
"{}@{}".format(gateway.username, gateway.ip),
|
||||||
|
"-W", "%h:%p", "-q",
|
||||||
|
]
|
||||||
|
|
||||||
|
if gateway.password:
|
||||||
|
proxy_command_list.insert(
|
||||||
|
0, "sshpass -p {}".format(gateway.password)
|
||||||
|
)
|
||||||
|
if gateway.private_key:
|
||||||
|
proxy_command_list.append("-i {}".format(gateway.private_key_file))
|
||||||
|
|
||||||
|
proxy_command = "'-o ProxyCommand={}'".format(
|
||||||
|
" ".join(proxy_command_list)
|
||||||
|
)
|
||||||
|
return {"ansible_ssh_common_args": proxy_command}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
|
||||||
|
from .adhoc import *
|
||||||
|
from .celery import *
|
|
@ -2,18 +2,23 @@
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
|
import os
|
||||||
import time
|
import time
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from celery import current_task
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.conf import settings
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django_celery_beat.models import CrontabSchedule, IntervalSchedule, PeriodicTask
|
from django_celery_beat.models import PeriodicTask
|
||||||
|
|
||||||
from common.utils import get_signer, get_logger
|
from common.utils import get_signer, get_logger
|
||||||
from common.celery import delete_celery_periodic_task, create_or_update_celery_periodic_tasks, \
|
from ..celery.utils import delete_celery_periodic_task, \
|
||||||
disable_celery_periodic_task
|
create_or_update_celery_periodic_tasks, \
|
||||||
from .ansible import AdHocRunner, AnsibleError
|
disable_celery_periodic_task
|
||||||
from .inventory import JMSInventory
|
from ..ansible import AdHocRunner, AnsibleError
|
||||||
|
from ..inventory import JMSInventory
|
||||||
|
|
||||||
__all__ = ["Task", "AdHoc", "AdHocRunHistory"]
|
__all__ = ["Task", "AdHoc", "AdHocRunHistory"]
|
||||||
|
|
||||||
|
@ -85,7 +90,7 @@ class Task(models.Model):
|
||||||
|
|
||||||
def save(self, force_insert=False, force_update=False, using=None,
|
def save(self, force_insert=False, force_update=False, using=None,
|
||||||
update_fields=None):
|
update_fields=None):
|
||||||
from .tasks import run_ansible_task
|
from ..tasks import run_ansible_task
|
||||||
super().save(
|
super().save(
|
||||||
force_insert=force_insert, force_update=force_update,
|
force_insert=force_insert, force_update=force_update,
|
||||||
using=using, update_fields=update_fields,
|
using=using, update_fields=update_fields,
|
||||||
|
@ -206,10 +211,18 @@ class AdHoc(models.Model):
|
||||||
return self._run_only()
|
return self._run_only()
|
||||||
|
|
||||||
def _run_and_record(self):
|
def _run_and_record(self):
|
||||||
history = AdHocRunHistory(adhoc=self, task=self.task)
|
try:
|
||||||
|
hid = current_task.request.id
|
||||||
|
except AttributeError:
|
||||||
|
hid = str(uuid.uuid4())
|
||||||
|
history = AdHocRunHistory(id=hid, adhoc=self, task=self.task)
|
||||||
time_start = time.time()
|
time_start = time.time()
|
||||||
try:
|
try:
|
||||||
|
date_start = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
print("{} Start task: {}\r\n".format(date_start, self.task.name))
|
||||||
raw, summary = self._run_only()
|
raw, summary = self._run_only()
|
||||||
|
date_end = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
print("\r\n{} Task finished".format(date_end))
|
||||||
history.is_finished = True
|
history.is_finished = True
|
||||||
if summary.get('dark'):
|
if summary.get('dark'):
|
||||||
history.is_success = False
|
history.is_success = False
|
||||||
|
@ -221,17 +234,20 @@ class AdHoc(models.Model):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return {}, {"dark": {"all": str(e)}, "contacted": []}
|
return {}, {"dark": {"all": str(e)}, "contacted": []}
|
||||||
finally:
|
finally:
|
||||||
|
# f.close()
|
||||||
history.date_finished = timezone.now()
|
history.date_finished = timezone.now()
|
||||||
history.timedelta = time.time() - time_start
|
history.timedelta = time.time() - time_start
|
||||||
history.save()
|
history.save()
|
||||||
|
|
||||||
def _run_only(self):
|
def _run_only(self, file_obj=None):
|
||||||
runner = AdHocRunner(self.inventory)
|
runner = AdHocRunner(self.inventory, options=self.options)
|
||||||
for k, v in self.options.items():
|
|
||||||
runner.set_option(k, v)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = runner.run(self.tasks, self.pattern, self.task.name)
|
result = runner.run(
|
||||||
|
self.tasks,
|
||||||
|
self.pattern,
|
||||||
|
self.task.name,
|
||||||
|
file_obj=file_obj,
|
||||||
|
)
|
||||||
return result.results_raw, result.results_summary
|
return result.results_raw, result.results_summary
|
||||||
except AnsibleError as e:
|
except AnsibleError as e:
|
||||||
logger.warn("Failed run adhoc {}, {}".format(self.task.name, e))
|
logger.warn("Failed run adhoc {}, {}".format(self.task.name, e))
|
||||||
|
@ -316,6 +332,14 @@ class AdHocRunHistory(models.Model):
|
||||||
def short_id(self):
|
def short_id(self):
|
||||||
return str(self.id).split('-')[-1]
|
return str(self.id).split('-')[-1]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def log_path(self):
|
||||||
|
dt = datetime.datetime.now().strftime('%Y-%m-%d')
|
||||||
|
log_dir = os.path.join(settings.PROJECT_DIR, 'data', 'ansible', dt)
|
||||||
|
if not os.path.exists(log_dir):
|
||||||
|
os.makedirs(log_dir)
|
||||||
|
return os.path.join(log_dir, str(self.id) + '.log')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def result(self):
|
def result(self):
|
||||||
if self._result:
|
if self._result:
|
|
@ -0,0 +1,36 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
import uuid
|
||||||
|
import os
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class CeleryTask(models.Model):
|
||||||
|
WAITING = "waiting"
|
||||||
|
RUNNING = "running"
|
||||||
|
FINISHED = "finished"
|
||||||
|
LOG_DIR = os.path.join(settings.PROJECT_DIR, 'data', 'celery')
|
||||||
|
|
||||||
|
STATUS_CHOICES = (
|
||||||
|
(WAITING, WAITING),
|
||||||
|
(RUNNING, RUNNING),
|
||||||
|
(FINISHED, FINISHED),
|
||||||
|
)
|
||||||
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
|
||||||
|
name = models.CharField(max_length=1024)
|
||||||
|
status = models.CharField(max_length=128, choices=STATUS_CHOICES)
|
||||||
|
log_path = models.CharField(max_length=256, blank=True, null=True)
|
||||||
|
date_published = models.DateTimeField(auto_now_add=True)
|
||||||
|
date_start = models.DateTimeField(null=True)
|
||||||
|
date_finished = models.DateTimeField(null=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "{}: {}".format(self.name, self.id)
|
||||||
|
|
||||||
|
def is_finished(self):
|
||||||
|
return self.status == self.FINISHED
|
||||||
|
|
||||||
|
@property
|
||||||
|
def full_log_path(self):
|
||||||
|
return os.path.join(self.LOG_DIR, self.log_path)
|
|
@ -12,14 +12,13 @@ def rerun_task():
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def run_ansible_task(task_id, callback=None, **kwargs):
|
def run_ansible_task(tid, callback=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
:param task_id: is the tasks serialized data
|
:param tid: is the tasks serialized data
|
||||||
:param callback: callback function name
|
:param callback: callback function name
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
task = get_object_or_none(Task, id=tid)
|
||||||
task = get_object_or_none(Task, id=task_id)
|
|
||||||
if task:
|
if task:
|
||||||
result = task.run()
|
result = task.run()
|
||||||
if callback is not None:
|
if callback is not None:
|
||||||
|
|
|
@ -82,7 +82,8 @@ function initTable() {
|
||||||
select: [],
|
select: [],
|
||||||
columnDefs: [
|
columnDefs: [
|
||||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||||
$(td).html(cellData);
|
var d = new Date(cellData);
|
||||||
|
$(td).html(d);
|
||||||
}},
|
}},
|
||||||
{targets: 2, createdCell: function (td, cellData) {
|
{targets: 2, createdCell: function (td, cellData) {
|
||||||
var total = "<span>" + cellData.total + "</span>";
|
var total = "<span>" + cellData.total + "</span>";
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
<li class="active">
|
<li class="active">
|
||||||
<a href="{% url 'ops:adhoc-history-detail' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Run history detail' %} </a>
|
<a href="{% url 'ops:adhoc-history-detail' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Run history detail' %} </a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-center celery-task-log" onclick="window.open('{% url 'ops:celery-task-log' pk=object.pk %}','', 'width=800,height=600')"><i class="fa fa-laptop"></i> {% trans 'Output' %} </a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
{% load static %}
|
||||||
|
<head>
|
||||||
|
<title>term.js</title>
|
||||||
|
<script src="{% static 'js/jquery-2.1.1.js' %}"></script>
|
||||||
|
<style>
|
||||||
|
html {
|
||||||
|
background: #000;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font: 20px/1.5 sans-serif;
|
||||||
|
}
|
||||||
|
.terminal {
|
||||||
|
float: left;
|
||||||
|
font-family: 'Monaco', 'Consolas', "DejaVu Sans Mono", "Liberation Mono", monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #f0f0f0;
|
||||||
|
background-color: #555;
|
||||||
|
padding: 20px 20px 20px;
|
||||||
|
}
|
||||||
|
.terminal-cursor {
|
||||||
|
color: #000;
|
||||||
|
background: #f0f0f0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<div class="container">
|
||||||
|
<div id="term">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="{% static 'js/term.js' %}"></script>
|
||||||
|
<script>
|
||||||
|
var rowHeight = 1;
|
||||||
|
var colWidth = 1;
|
||||||
|
var mark = '';
|
||||||
|
var url = "{% url 'api-ops:celery-task-log' pk=object.id %}";
|
||||||
|
var term;
|
||||||
|
var end = false;
|
||||||
|
var error = false;
|
||||||
|
var interval = 200;
|
||||||
|
|
||||||
|
function calWinSize() {
|
||||||
|
var t = $('.terminal');
|
||||||
|
rowHeight = 1.00 * t.height() / 24;
|
||||||
|
colWidth = 1.00 * t.width() / 80;
|
||||||
|
}
|
||||||
|
function resize() {
|
||||||
|
var rows = Math.floor(window.innerHeight / rowHeight) - 2;
|
||||||
|
var cols = Math.floor(window.innerWidth / colWidth) - 10;
|
||||||
|
term.resize(cols, rows);
|
||||||
|
}
|
||||||
|
function requestAndWrite() {
|
||||||
|
if (!end) {
|
||||||
|
$.ajax({
|
||||||
|
url: url + '?mark=' + mark,
|
||||||
|
method: "GET",
|
||||||
|
contentType: "application/json; charset=utf-8"
|
||||||
|
}).done(function(data, textStatue, jqXHR) {
|
||||||
|
if (jqXHR.status === 203) {
|
||||||
|
error = true;
|
||||||
|
term.write('.');
|
||||||
|
interval = 500;
|
||||||
|
}
|
||||||
|
if (jqXHR.status === 200){
|
||||||
|
term.write(data.data);
|
||||||
|
mark = data.mark;
|
||||||
|
if (data.end){
|
||||||
|
end = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$(document).ready(function () {
|
||||||
|
term = new Terminal({
|
||||||
|
cols: 80,
|
||||||
|
rows: 24,
|
||||||
|
useStyle: true,
|
||||||
|
screenKeys: false,
|
||||||
|
convertEol: false,
|
||||||
|
cursorBlink: false
|
||||||
|
});
|
||||||
|
term.open();
|
||||||
|
term.on('data', function (data) {
|
||||||
|
term.write(data.replace('\r', '\r\n'))
|
||||||
|
});
|
||||||
|
calWinSize();
|
||||||
|
resize();
|
||||||
|
$('.terminal').detach().appendTo('#term');
|
||||||
|
setInterval(function () {
|
||||||
|
requestAndWrite()
|
||||||
|
}, interval)
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -24,6 +24,9 @@
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'ops:task-history' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Run history' %} </a>
|
<a href="{% url 'ops:task-history' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Run history' %} </a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-center celery-task-log" onclick="window.open('{% url 'ops:celery-task-log' pk=object.latest_history.pk %}','', 'width=800,height=600')"><i class="fa fa-laptop"></i> {% trans 'Last run output' %} </a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
|
@ -105,6 +108,10 @@
|
||||||
$(td).html(cellData.user)
|
$(td).html(cellData.user)
|
||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
|
{targets: 6, createdCell: function (td, cellData) {
|
||||||
|
var d = new Date(cellData);
|
||||||
|
$(td).html(d.toLocaleString())
|
||||||
|
}},
|
||||||
{targets: 7, createdCell: function (td, cellData, rowData) {
|
{targets: 7, createdCell: function (td, cellData, rowData) {
|
||||||
var detail_btn = '<a class="btn btn-xs btn-primary m-l-xs btn-run" href="{% url 'ops:adhoc-detail' pk=DEFAULT_PK %}">{% trans "Detail" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
|
var detail_btn = '<a class="btn btn-xs btn-primary m-l-xs btn-run" href="{% url 'ops:adhoc-detail' pk=DEFAULT_PK %}">{% trans "Detail" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
|
||||||
if (cellData) {
|
if (cellData) {
|
||||||
|
|
|
@ -24,6 +24,9 @@
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'ops:task-history' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Run history' %} </a>
|
<a href="{% url 'ops:task-history' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Run history' %} </a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-center celery-task-log" onclick="window.open('{% url 'ops:celery-task-log' pk=object.latest_history.pk %}','', 'width=800,height=600')"><i class="fa fa-laptop"></i> {% trans 'Last run output' %} </a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
|
@ -160,6 +163,5 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% include 'users/_user_update_pk_modal.html' %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -24,13 +24,16 @@
|
||||||
<li class="active">
|
<li class="active">
|
||||||
<a href="{% url 'ops:task-history' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Run history' %} </a>
|
<a href="{% url 'ops:task-history' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Run history' %} </a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-center celery-task-log" onclick="window.open('{% url 'ops:celery-task-log' pk=object.latest_history.pk %}','', 'width=800,height=600')"><i class="fa fa-laptop"></i> {% trans 'Last run output' %} </a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div class="col-sm-12" style="padding-left: 0">
|
<div class="col-sm-12" style="padding-left: 0">
|
||||||
<div class="ibox float-e-margins">
|
<div class="ibox float-e-margins">
|
||||||
<div class="ibox-title">
|
<div class="ibox-title">
|
||||||
<span style="float: left">{% trans 'History of ' %} <b>{{ object.task.name }}:{{ object.short_id }}</b></span>
|
<span style="float: left">{% trans 'History of ' %} <b>{{ object.name }}:{{ object.short_id }}</b></span>
|
||||||
<div class="ibox-tools">
|
<div class="ibox-tools">
|
||||||
<a class="collapse-link">
|
<a class="collapse-link">
|
||||||
<i class="fa fa-chevron-up"></i>
|
<i class="fa fa-chevron-up"></i>
|
||||||
|
@ -85,7 +88,8 @@ function initTable() {
|
||||||
select: [],
|
select: [],
|
||||||
columnDefs: [
|
columnDefs: [
|
||||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||||
$(td).html(cellData);
|
var d = new Date(cellData);
|
||||||
|
$(td).html(d.toLocaleString());
|
||||||
}},
|
}},
|
||||||
{targets: 2, createdCell: function (td, cellData) {
|
{targets: 2, createdCell: function (td, cellData) {
|
||||||
var total = "<span>" + cellData.total + "</span>";
|
var total = "<span>" + cellData.total + "</span>";
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
{% extends '_base_list.html' %}
|
{% extends '_base_list.html' %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block content_left_head %}
|
{% block content_left_head %}
|
||||||
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
|
<div class="uc pull-left m-r-5"><a class="btn btn-sm btn-primary btn-create-asset"> {% trans "Create task" %} </a></div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
@ -111,9 +112,10 @@ $(document).ready(function() {
|
||||||
var error = function (data) {
|
var error = function (data) {
|
||||||
alert(data)
|
alert(data)
|
||||||
};
|
};
|
||||||
var success = function () {
|
var success = function(data) {
|
||||||
alert("任务开始执行,重定向到任务详情页面,多刷新几次查看结果")
|
var task_id = data.task;
|
||||||
window.location = "{% url 'ops:task-detail' pk=DEFAULT_PK %}".replace('{{ DEFAULT_PK }}', uid);
|
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||||
|
window.open(url, '', 'width=800,height=600')
|
||||||
};
|
};
|
||||||
APIUpdateAttr({
|
APIUpdateAttr({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
|
|
|
@ -15,6 +15,7 @@ router.register(r'v1/history', api.AdHocRunHistorySet, 'history')
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^v1/tasks/(?P<pk>[0-9a-zA-Z\-]{36})/run/$', api.TaskRun.as_view(), name='task-run'),
|
url(r'^v1/tasks/(?P<pk>[0-9a-zA-Z\-]{36})/run/$', api.TaskRun.as_view(), name='task-run'),
|
||||||
|
url(r'^v1/celery/task/(?P<pk>[0-9a-zA-Z\-]{36})/log/$', api.CeleryTaskLogApi.as_view(), name='celery-task-log'),
|
||||||
]
|
]
|
||||||
|
|
||||||
urlpatterns += router.urls
|
urlpatterns += router.urls
|
||||||
|
|
|
@ -18,4 +18,5 @@ urlpatterns = [
|
||||||
url(r'^adhoc/(?P<pk>[0-9a-zA-Z\-]{36})/$', views.AdHocDetailView.as_view(), name='adhoc-detail'),
|
url(r'^adhoc/(?P<pk>[0-9a-zA-Z\-]{36})/$', views.AdHocDetailView.as_view(), name='adhoc-detail'),
|
||||||
url(r'^adhoc/(?P<pk>[0-9a-zA-Z\-]{36})/history/$', views.AdHocHistoryView.as_view(), name='adhoc-history'),
|
url(r'^adhoc/(?P<pk>[0-9a-zA-Z\-]{36})/history/$', views.AdHocHistoryView.as_view(), name='adhoc-history'),
|
||||||
url(r'^adhoc/history/(?P<pk>[0-9a-zA-Z\-]{36})/$', views.AdHocHistoryDetailView.as_view(), name='adhoc-history-detail'),
|
url(r'^adhoc/history/(?P<pk>[0-9a-zA-Z\-]{36})/$', views.AdHocHistoryDetailView.as_view(), name='adhoc-history-detail'),
|
||||||
|
url(r'^celery/task/(?P<pk>[0-9a-zA-Z\-]{36})/log/$', views.CeleryTaskLogView.as_view(), name='celery-task-log'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.views.generic import ListView, DetailView
|
from django.views.generic import ListView, DetailView, TemplateView
|
||||||
|
|
||||||
from common.mixins import DatetimeSearchMixin
|
from common.mixins import DatetimeSearchMixin
|
||||||
from .models import Task, AdHoc, AdHocRunHistory
|
from .models import Task, AdHoc, AdHocRunHistory, CeleryTask
|
||||||
from .hands import AdminUserRequiredMixin
|
from .hands import AdminUserRequiredMixin
|
||||||
|
|
||||||
|
|
||||||
|
@ -119,3 +119,8 @@ class AdHocHistoryDetailView(AdminUserRequiredMixin, DetailView):
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class CeleryTaskLogView(AdminUserRequiredMixin, DetailView):
|
||||||
|
template_name = 'ops/celery_task_log.html'
|
||||||
|
model = CeleryTask
|
||||||
|
|
|
@ -157,7 +157,7 @@ function APIUpdateAttr(props) {
|
||||||
props = props || {};
|
props = props || {};
|
||||||
var success_message = props.success_message || '更新成功!';
|
var success_message = props.success_message || '更新成功!';
|
||||||
var fail_message = props.fail_message || '更新时发生未知错误.';
|
var fail_message = props.fail_message || '更新时发生未知错误.';
|
||||||
var flash_message = true;
|
var flash_message = props.flash_message || true;
|
||||||
if (props.flash_message === false){
|
if (props.flash_message === false){
|
||||||
flash_message = false;
|
flash_message = false;
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,9 @@ function APIUpdateAttr(props) {
|
||||||
dataType: props.data_type || "json"
|
dataType: props.data_type || "json"
|
||||||
}).done(function(data, textStatue, jqXHR) {
|
}).done(function(data, textStatue, jqXHR) {
|
||||||
if (flash_message) {
|
if (flash_message) {
|
||||||
toastr.success(success_message);
|
if (send_message) {
|
||||||
|
toastr.success(success_message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (typeof props.success === 'function') {
|
if (typeof props.success === 'function') {
|
||||||
return props.success(data);
|
return props.success(data);
|
||||||
|
|
|
@ -5,8 +5,6 @@ from django.core.cache import cache
|
||||||
from django.db.utils import ProgrammingError, OperationalError
|
from django.db.utils import ProgrammingError, OperationalError
|
||||||
|
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from common.celery import after_app_ready_start, register_as_period_task, \
|
|
||||||
after_app_shutdown_clean
|
|
||||||
from .const import ASSETS_CACHE_KEY, USERS_CACHE_KEY, SYSTEM_USER_CACHE_KEY
|
from .const import ASSETS_CACHE_KEY, USERS_CACHE_KEY, SYSTEM_USER_CACHE_KEY
|
||||||
|
|
||||||
RUNNING = False
|
RUNNING = False
|
||||||
|
|
|
@ -6,7 +6,7 @@ import datetime
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from common.celery import register_as_period_task, after_app_ready_start, \
|
from ops.celery.utils import register_as_period_task, after_app_ready_start, \
|
||||||
after_app_shutdown_clean
|
after_app_shutdown_clean
|
||||||
from .models import Status, Session
|
from .models import Status, Session
|
||||||
|
|
||||||
|
|
4
jms
4
jms
|
@ -155,7 +155,7 @@ def start_celery():
|
||||||
|
|
||||||
cmd = [
|
cmd = [
|
||||||
'celery', 'worker',
|
'celery', 'worker',
|
||||||
'-A', 'common',
|
'-A', 'ops',
|
||||||
'-l', LOG_LEVEL.lower(),
|
'-l', LOG_LEVEL.lower(),
|
||||||
'--pidfile', pid_file,
|
'--pidfile', pid_file,
|
||||||
'-c', str(WORKERS),
|
'-c', str(WORKERS),
|
||||||
|
@ -182,7 +182,7 @@ def start_beat():
|
||||||
scheduler = "django_celery_beat.schedulers:DatabaseScheduler"
|
scheduler = "django_celery_beat.schedulers:DatabaseScheduler"
|
||||||
cmd = [
|
cmd = [
|
||||||
'celery', 'beat',
|
'celery', 'beat',
|
||||||
'-A', 'common',
|
'-A', 'ops',
|
||||||
'--pidfile', pid_file,
|
'--pidfile', pid_file,
|
||||||
'-l', LOG_LEVEL,
|
'-l', LOG_LEVEL,
|
||||||
'--scheduler', scheduler,
|
'--scheduler', scheduler,
|
||||||
|
|
Loading…
Reference in New Issue