mirror of https://github.com/jumpserver/jumpserver
Support ws (#3291)
* [Update] add ws support * [Update] 修改log使用websocket * [Update] 修复 资产用户 右侧动作菜单,字体颜色 * [Update] 修改Dockerfile * [Bugfix] 修复settings中WSG_APPLICATIONpull/3293/head
parent
e35ba52236
commit
cff009e758
|
@ -22,4 +22,5 @@ ENV LANG=zh_CN.UTF-8
|
||||||
ENV LC_ALL=zh_CN.UTF-8
|
ENV LC_ALL=zh_CN.UTF-8
|
||||||
|
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
EXPOSE 8081
|
||||||
ENTRYPOINT ["./entrypoint.sh"]
|
ENTRYPOINT ["./entrypoint.sh"]
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<style>
|
<style>
|
||||||
.btn-group>.btn+.dropdown-toggle {
|
.btn-group>.btn+.dropdown-toggle {
|
||||||
padding-right: 4px;
|
padding-right: 4px;
|
||||||
padding-left: 4px;
|
padding-left: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table.dataTable tbody tr.selected a {
|
||||||
|
color: rgb(103, 106, 108);;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<table class="table table-striped table-bordered table-hover" id="asset_user_list_table" style="width: 100%">
|
<table class="table table-striped table-bordered table-hover" id="asset_user_list_table" style="width: 100%">
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -137,8 +142,7 @@ $(document).ready(function(){
|
||||||
}
|
}
|
||||||
var success = function (data) {
|
var success = function (data) {
|
||||||
var task_id = data.task;
|
var task_id = data.task;
|
||||||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
showCeleryTaskLog(task_id);
|
||||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
|
||||||
};
|
};
|
||||||
requestApi({
|
requestApi({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
|
@ -149,4 +153,4 @@ $(document).ready(function(){
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -85,8 +85,7 @@ $(document).ready(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 success = function (data) {
|
var success = function (data) {
|
||||||
var task_id = data.task;
|
var task_id = data.task;
|
||||||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
showCeleryTaskLog(task_id);
|
||||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
|
||||||
};
|
};
|
||||||
requestApi({
|
requestApi({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
|
|
|
@ -81,8 +81,7 @@ $(document).ready(function () {
|
||||||
var the_url = "{% url 'api-assets:asset-user-connective' %}" + "?asset_id={{ asset.id }}";
|
var the_url = "{% url 'api-assets:asset-user-connective' %}" + "?asset_id={{ asset.id }}";
|
||||||
var success = function (data) {
|
var success = function (data) {
|
||||||
var task_id = data.task;
|
var task_id = data.task;
|
||||||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
showCeleryTaskLog(task_id);
|
||||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
|
||||||
};
|
};
|
||||||
requestApi({
|
requestApi({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
|
@ -92,4 +91,4 @@ $(document).ready(function () {
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -276,8 +276,7 @@ function refreshAssetHardware() {
|
||||||
var success = function(data) {
|
var success = function(data) {
|
||||||
console.log(data);
|
console.log(data);
|
||||||
var task_id = data.task;
|
var task_id = data.task;
|
||||||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
showCeleryTaskLog(task_id);
|
||||||
window.open(url, '', 'width=800,height=600')
|
|
||||||
};
|
};
|
||||||
requestApi({
|
requestApi({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
|
@ -355,8 +354,7 @@ $(document).ready(function () {
|
||||||
|
|
||||||
var success = function(data) {
|
var success = function(data) {
|
||||||
var task_id = data.task;
|
var task_id = data.task;
|
||||||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
showCeleryTaskLog(task_id);
|
||||||
window.open(url, '', 'width=800,height=600')
|
|
||||||
};
|
};
|
||||||
|
|
||||||
requestApi({
|
requestApi({
|
||||||
|
|
|
@ -523,8 +523,7 @@ $(document).ready(function(){
|
||||||
function success(data) {
|
function success(data) {
|
||||||
rMenu.css({"visibility" : "hidden"});
|
rMenu.css({"visibility" : "hidden"});
|
||||||
var task_id = data.task;
|
var task_id = data.task;
|
||||||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
showCeleryTaskLog(task_id);
|
||||||
window.open(url, '', 'width=800,height=600')
|
|
||||||
}
|
}
|
||||||
requestApi({
|
requestApi({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
|
@ -538,8 +537,7 @@ $(document).ready(function(){
|
||||||
function success(data) {
|
function success(data) {
|
||||||
rMenu.css({"visibility" : "hidden"});
|
rMenu.css({"visibility" : "hidden"});
|
||||||
var task_id = data.task;
|
var task_id = data.task;
|
||||||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
showCeleryTaskLog(task_id);
|
||||||
window.open(url, '', 'width=800,height=600')
|
|
||||||
}
|
}
|
||||||
requestApi({
|
requestApi({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
|
@ -552,4 +550,4 @@ $(document).ready(function(){
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -202,8 +202,7 @@ $(document).ready(function () {
|
||||||
};
|
};
|
||||||
var success = function (data) {
|
var success = function (data) {
|
||||||
var task_id = data.task;
|
var task_id = data.task;
|
||||||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
showCeleryTaskLog(task_id);
|
||||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
|
||||||
};
|
};
|
||||||
requestApi({
|
requestApi({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
|
@ -219,8 +218,7 @@ $(document).ready(function () {
|
||||||
the_url = the_url.replace("{{ DEFAULT_PK }}", asset_id);
|
the_url = the_url.replace("{{ DEFAULT_PK }}", asset_id);
|
||||||
var success = function (data) {
|
var success = function (data) {
|
||||||
var task_id = data.task;
|
var task_id = data.task;
|
||||||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
showCeleryTaskLog(task_id);
|
||||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
|
||||||
};
|
};
|
||||||
var error = function (data) {
|
var error = function (data) {
|
||||||
alert(data)
|
alert(data)
|
||||||
|
@ -239,8 +237,7 @@ $(document).ready(function () {
|
||||||
};
|
};
|
||||||
var success = function (data) {
|
var success = function (data) {
|
||||||
var task_id = data.task;
|
var task_id = data.task;
|
||||||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
showCeleryTaskLog(task_id);
|
||||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
|
||||||
};
|
};
|
||||||
requestApi({
|
requestApi({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
|
|
|
@ -251,8 +251,7 @@ $(document).ready(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 success = function (data) {
|
var success = function (data) {
|
||||||
var task_id = data.task;
|
var task_id = data.task;
|
||||||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
showCeleryTaskLog(task_id);
|
||||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
|
||||||
};
|
};
|
||||||
requestApi({
|
requestApi({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
|
@ -265,8 +264,7 @@ $(document).ready(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 success = function (data) {
|
var success = function (data) {
|
||||||
var task_id = data.task;
|
var task_id = data.task;
|
||||||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
showCeleryTaskLog(task_id);
|
||||||
window.open(url, '', 'width=800,height=600')
|
|
||||||
};
|
};
|
||||||
requestApi({
|
requestApi({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
|
|
|
@ -83,6 +83,8 @@ class LogTailApi(generics.RetrieveAPIView):
|
||||||
return Response({"data": data, 'end': end, 'mark': new_mark})
|
return Response({"data": data, 'end': end, 'mark': new_mark})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ResourcesIDCacheApi(APIView):
|
class ResourcesIDCacheApi(APIView):
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
spm = str(uuid.uuid4())
|
spm = str(uuid.uuid4())
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import os
|
||||||
|
import django
|
||||||
|
from channels.routing import get_default_application
|
||||||
|
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jumpserver.settings")
|
||||||
|
django.setup()
|
||||||
|
application = get_default_application()
|
|
@ -335,6 +335,7 @@ defaults = {
|
||||||
'REDIS_DB_CELERY': 3,
|
'REDIS_DB_CELERY': 3,
|
||||||
'REDIS_DB_CACHE': 4,
|
'REDIS_DB_CACHE': 4,
|
||||||
'REDIS_DB_SESSION': 5,
|
'REDIS_DB_SESSION': 5,
|
||||||
|
'REDIS_DB_WS': 6,
|
||||||
'CAPTCHA_TEST_MODE': None,
|
'CAPTCHA_TEST_MODE': None,
|
||||||
'TOKEN_EXPIRATION': 3600 * 24,
|
'TOKEN_EXPIRATION': 3600 * 24,
|
||||||
'DISPLAY_PER_PAGE': 25,
|
'DISPLAY_PER_PAGE': 25,
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
from channels.auth import AuthMiddlewareStack
|
||||||
|
from channels.routing import ProtocolTypeRouter, URLRouter
|
||||||
|
|
||||||
|
from ops.urls.ws_urls import urlpatterns as ops_urlpatterns
|
||||||
|
|
||||||
|
urlpatterns = []
|
||||||
|
urlpatterns += ops_urlpatterns
|
||||||
|
|
||||||
|
application = ProtocolTypeRouter({
|
||||||
|
'websocket': AuthMiddlewareStack(
|
||||||
|
URLRouter(urlpatterns)
|
||||||
|
),
|
||||||
|
})
|
|
@ -74,6 +74,7 @@ INSTALLED_APPS = [
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
'rest_framework_swagger',
|
'rest_framework_swagger',
|
||||||
'drf_yasg',
|
'drf_yasg',
|
||||||
|
'channels',
|
||||||
'django_filters',
|
'django_filters',
|
||||||
'bootstrap3',
|
'bootstrap3',
|
||||||
'captcha',
|
'captcha',
|
||||||
|
@ -140,7 +141,8 @@ TEMPLATES = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
# WSGI_APPLICATION = 'jumpserver.wsgi.applications'
|
WSGI_APPLICATION = 'jumpserver.wsgi.application'
|
||||||
|
ASGI_APPLICATION = 'jumpserver.routing.application'
|
||||||
|
|
||||||
LOGIN_REDIRECT_URL = reverse_lazy('index')
|
LOGIN_REDIRECT_URL = reverse_lazy('index')
|
||||||
LOGIN_URL = reverse_lazy('authentication:login')
|
LOGIN_URL = reverse_lazy('authentication:login')
|
||||||
|
@ -624,3 +626,19 @@ BACKEND_ASSET_USER_AUTH_VAULT = False
|
||||||
PERM_SINGLE_ASSET_TO_UNGROUP_NODE = CONFIG.PERM_SINGLE_ASSET_TO_UNGROUP_NODE
|
PERM_SINGLE_ASSET_TO_UNGROUP_NODE = CONFIG.PERM_SINGLE_ASSET_TO_UNGROUP_NODE
|
||||||
WINDOWS_SSH_DEFAULT_SHELL = CONFIG.WINDOWS_SSH_DEFAULT_SHELL
|
WINDOWS_SSH_DEFAULT_SHELL = CONFIG.WINDOWS_SSH_DEFAULT_SHELL
|
||||||
FLOWER_URL = CONFIG.FLOWER_URL
|
FLOWER_URL = CONFIG.FLOWER_URL
|
||||||
|
|
||||||
|
|
||||||
|
# Django channels support websocket
|
||||||
|
CHANNEL_REDIS = "redis://:{}@{}:{}/{}".format(
|
||||||
|
CONFIG.REDIS_PASSWORD, CONFIG.REDIS_HOST, CONFIG.REDIS_PORT,
|
||||||
|
CONFIG.REDIS_DB_WS,
|
||||||
|
)
|
||||||
|
|
||||||
|
CHANNEL_LAYERS = {
|
||||||
|
'default': {
|
||||||
|
'BACKEND': 'channels_redis.core.RedisChannelLayer',
|
||||||
|
'CONFIG': {
|
||||||
|
"hosts": [CHANNEL_REDIS],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
|
@ -66,6 +66,7 @@ urlpatterns = [
|
||||||
re_path('api/(?P<app>\w+)/(?P<version>v\d)/.*', views.redirect_format_api),
|
re_path('api/(?P<app>\w+)/(?P<version>v\d)/.*', views.redirect_format_api),
|
||||||
path('api/health/', views.HealthCheckView.as_view(), name="health"),
|
path('api/health/', views.HealthCheckView.as_view(), name="health"),
|
||||||
path('luna/', views.LunaView.as_view(), name='luna-view'),
|
path('luna/', views.LunaView.as_view(), name='luna-view'),
|
||||||
|
re_path('ws/.*', views.WsView.as_view(), name='ws-view'),
|
||||||
path('i18n/<str:lang>/', views.I18NView.as_view(), name='i18n-switch'),
|
path('i18n/<str:lang>/', views.I18NView.as_view(), name='i18n-switch'),
|
||||||
path('settings/', include('settings.urls.view_urls', namespace='settings')),
|
path('settings/', include('settings.urls.view_urls', namespace='settings')),
|
||||||
|
|
||||||
|
|
|
@ -226,4 +226,11 @@ class HealthCheckView(APIView):
|
||||||
return JsonResponse({"status": 1, "time": int(time.time())})
|
return JsonResponse({"status": 1, "time": int(time.time())})
|
||||||
|
|
||||||
|
|
||||||
|
class WsView(APIView):
|
||||||
|
ws_port = settings.CONFIG.HTTP_LISTEN_PORT + 1
|
||||||
|
|
||||||
|
def get(self, request):
|
||||||
|
msg = _("Websocket server run on port: {}, you should proxy it on nginx"
|
||||||
|
.format(self.ws_port))
|
||||||
|
return JsonResponse({"msg": msg})
|
||||||
|
|
||||||
|
|
|
@ -196,8 +196,7 @@ $(document).ready(function () {
|
||||||
alert("没有运行历史");
|
alert("没有运行历史");
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var url = '{% url 'ops:celery-task-log' pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', history_pk);
|
showCeleryTaskLog(history_pk);
|
||||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -145,8 +145,8 @@
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
}).on('click', '.celery-task-log', function () {
|
}).on('click', '.celery-task-log', function () {
|
||||||
var url = '{% url 'ops:celery-task-log' pk=object.pk %}';
|
var taskId = "{{ object.pk }}";
|
||||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
showCeleryTaskLog(taskId);
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -20,50 +20,13 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var rowHeight = 18;
|
var scheme = document.location.protocol === "https:" ? "wss" : "ws";
|
||||||
var colWidth = 10;
|
var port = document.location.port ? ":" + document.location.port : "";
|
||||||
var mark = '';
|
var url = "/ws/ops/tasks/" + "{{ task_id }}" + "/log/";
|
||||||
var url = "{% url 'api-ops:celery-task-log' pk=task_id %}";
|
var wsURL = scheme + "://" + document.location.hostname + port + url;
|
||||||
var term;
|
var term;
|
||||||
var end = false;
|
var ws;
|
||||||
var error = false;
|
|
||||||
var interval = 200;
|
|
||||||
var success = true;
|
|
||||||
|
|
||||||
function calWinSize() {
|
|
||||||
var t = $('#marker');
|
|
||||||
{#rowHeight = 1.00 * t.height();#}
|
|
||||||
{#colWidth = 1.00 * t.width() / 6;#}
|
|
||||||
}
|
|
||||||
function resize() {
|
|
||||||
{#var rows = Math.floor(window.innerHeight / rowHeight) - 1;#}
|
|
||||||
{#var cols = Math.floor(window.innerWidth / colWidth) - 2;#}
|
|
||||||
{#term.resize(cols, rows);#}
|
|
||||||
}
|
|
||||||
function requestAndWrite() {
|
|
||||||
if (!end && success) {
|
|
||||||
success = false;
|
|
||||||
$.ajax({
|
|
||||||
url: url + '?mark=' + mark,
|
|
||||||
method: "GET",
|
|
||||||
contentType: "application/json; charset=utf-8"
|
|
||||||
}).done(function(data, textStatue, jqXHR) {
|
|
||||||
success = true;
|
|
||||||
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 () {
|
$(document).ready(function () {
|
||||||
term = new Terminal({
|
term = new Terminal({
|
||||||
cursorBlink: false,
|
cursorBlink: false,
|
||||||
|
@ -74,18 +37,14 @@
|
||||||
disableStdin: true
|
disableStdin: true
|
||||||
});
|
});
|
||||||
term.open(document.getElementById('term'));
|
term.open(document.getElementById('term'));
|
||||||
term.resize(90, 32);
|
term.resize(120, 30);
|
||||||
resize();
|
ws = new WebSocket(wsURL);
|
||||||
term.on('data', function (data) {
|
ws.onmessage = function(e) {
|
||||||
{#term.write(data.replace('\r', '\r\n'))#}
|
var data = JSON.parse(e.data);
|
||||||
term.write(data);
|
term.write(data.message);
|
||||||
});
|
|
||||||
window.onresize = function () {
|
|
||||||
resize()
|
|
||||||
};
|
};
|
||||||
{#$('.terminal').detach().appendTo('#term');#}
|
ws.onerror = function (e) {
|
||||||
setInterval(function () {
|
term.write("Connect websocket server error")
|
||||||
requestAndWrite()
|
}
|
||||||
}, interval)
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -130,8 +130,7 @@ $(document).ready(function () {
|
||||||
alert("没有运行历史");
|
alert("没有运行历史");
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var url = '{% url 'ops:celery-task-log' pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', history_pk);
|
showCeleryTaskLog(history_pk);
|
||||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -174,8 +174,7 @@ $(document).ready(function () {
|
||||||
alert("没有运行历史");
|
alert("没有运行历史");
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var url = '{% url 'ops:celery-task-log' pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', history_pk);
|
showCeleryTaskLog(history_pk);
|
||||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -155,8 +155,7 @@ $(document).ready(function () {
|
||||||
alert("没有运行历史");
|
alert("没有运行历史");
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var url = '{% url 'ops:celery-task-log' pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', history_pk);
|
showCeleryTaskLog(history_pk);
|
||||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -98,8 +98,7 @@ $(document).ready(function () {
|
||||||
};
|
};
|
||||||
var success = function(data) {
|
var success = function(data) {
|
||||||
var task_id = data.task;
|
var task_id = data.task;
|
||||||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
showCeleryTaskLog(task_id);
|
||||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
|
||||||
};
|
};
|
||||||
requestApi({
|
requestApi({
|
||||||
url: the_url,
|
url: the_url,
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from .. import ws
|
||||||
|
|
||||||
|
app_name = 'ops'
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('ws/ops/tasks/<uuid:task_id>/log/', ws.CeleryLogWebsocket, name='task-log-ws'),
|
||||||
|
]
|
|
@ -0,0 +1,41 @@
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
|
||||||
|
from .celery.utils import get_celery_task_log_path
|
||||||
|
from channels.generic.websocket import JsonWebsocketConsumer
|
||||||
|
|
||||||
|
|
||||||
|
class CeleryLogWebsocket(JsonWebsocketConsumer):
|
||||||
|
task = ''
|
||||||
|
task_log_f = None
|
||||||
|
disconnected = False
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
task_id = self.scope['url_route']['kwargs']['task_id']
|
||||||
|
log_path = get_celery_task_log_path(task_id)
|
||||||
|
try:
|
||||||
|
self.task_log_f = open(log_path)
|
||||||
|
except OSError:
|
||||||
|
self.send({'message': "Task {} log not found".format(task_id)})
|
||||||
|
self.disconnect(None)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.accept()
|
||||||
|
self.send_log_to_client()
|
||||||
|
|
||||||
|
def disconnect(self, close_code):
|
||||||
|
self.disconnected = True
|
||||||
|
if self.task_log_f and not self.task_log_f.closed:
|
||||||
|
self.task_log_f.close()
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def send_log_to_client(self):
|
||||||
|
def func():
|
||||||
|
while not self.disconnected:
|
||||||
|
data = self.task_log_f.read(4096)
|
||||||
|
if data:
|
||||||
|
data = data.replace('\n', '\r\n')
|
||||||
|
self.send_json({'message': data})
|
||||||
|
time.sleep(0.2)
|
||||||
|
thread = threading.Thread(target=func)
|
||||||
|
thread.start()
|
|
@ -88,7 +88,7 @@ table.dataTable tbody td.selected a,
|
||||||
table.dataTable tbody tr.selected td i.text-navy,
|
table.dataTable tbody tr.selected td i.text-navy,
|
||||||
table.dataTable tbody th.selected td i.text-navy,
|
table.dataTable tbody th.selected td i.text-navy,
|
||||||
table.dataTable tbody td.selected td i.text-navy {
|
table.dataTable tbody td.selected td i.text-navy {
|
||||||
color: white !important;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.m-0 {
|
.m-0 {
|
||||||
|
@ -473,4 +473,4 @@ span.select2-selection__placeholder {
|
||||||
|
|
||||||
.p-r-5 {
|
.p-r-5 {
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1201,3 +1201,7 @@ function nodesSelect2Init(selector, url) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showCeleryTaskLog(taskId) {
|
||||||
|
var url = '/ops/celery/task/taskId/log/'.replace('taskId', taskId);
|
||||||
|
window.open(url, '', 'width=900,height=600')
|
||||||
|
}
|
||||||
|
|
22
jms
22
jms
|
@ -47,6 +47,7 @@ LOG_DIR = os.path.join(BASE_DIR, 'logs')
|
||||||
TMP_DIR = os.path.join(BASE_DIR, 'tmp')
|
TMP_DIR = os.path.join(BASE_DIR, 'tmp')
|
||||||
HTTP_HOST = CONFIG.HTTP_BIND_HOST or '127.0.0.1'
|
HTTP_HOST = CONFIG.HTTP_BIND_HOST or '127.0.0.1'
|
||||||
HTTP_PORT = CONFIG.HTTP_LISTEN_PORT or 8080
|
HTTP_PORT = CONFIG.HTTP_LISTEN_PORT or 8080
|
||||||
|
WS_PORT = HTTP_PORT + 1
|
||||||
DEBUG = CONFIG.DEBUG or False
|
DEBUG = CONFIG.DEBUG or False
|
||||||
LOG_LEVEL = CONFIG.LOG_LEVEL or 'INFO'
|
LOG_LEVEL = CONFIG.LOG_LEVEL or 'INFO'
|
||||||
|
|
||||||
|
@ -201,12 +202,15 @@ def is_running(s, unlink=True):
|
||||||
|
|
||||||
def parse_service(s):
|
def parse_service(s):
|
||||||
all_services = [
|
all_services = [
|
||||||
'gunicorn', 'celery_ansible', 'celery_default', 'beat', 'flower'
|
'gunicorn', 'celery_ansible', 'celery_default',
|
||||||
|
'beat', 'flower', 'daphne',
|
||||||
]
|
]
|
||||||
if s == 'all':
|
if s == 'all':
|
||||||
return all_services
|
return all_services
|
||||||
elif s == "web":
|
elif s == "web":
|
||||||
return ['gunicorn', 'flower']
|
return ['gunicorn', 'flower', 'daphne']
|
||||||
|
elif s == 'ws':
|
||||||
|
return ['daphne']
|
||||||
elif s == "task":
|
elif s == "task":
|
||||||
return ["celery_ansible", "celery_default", "beat"]
|
return ["celery_ansible", "celery_default", "beat"]
|
||||||
elif s == 'gunicorn':
|
elif s == 'gunicorn':
|
||||||
|
@ -225,10 +229,8 @@ def parse_service(s):
|
||||||
def get_start_gunicorn_kwargs():
|
def get_start_gunicorn_kwargs():
|
||||||
print("\n- Start Gunicorn WSGI HTTP Server")
|
print("\n- Start Gunicorn WSGI HTTP Server")
|
||||||
prepare()
|
prepare()
|
||||||
service = 'gunicorn'
|
|
||||||
bind = '{}:{}'.format(HTTP_HOST, HTTP_PORT)
|
bind = '{}:{}'.format(HTTP_HOST, HTTP_PORT)
|
||||||
log_format = '%(h)s %(t)s "%(r)s" %(s)s %(b)s '
|
log_format = '%(h)s %(t)s "%(r)s" %(s)s %(b)s '
|
||||||
pid_file = get_pid_file_path(service)
|
|
||||||
|
|
||||||
cmd = [
|
cmd = [
|
||||||
'gunicorn', 'jumpserver.wsgi',
|
'gunicorn', 'jumpserver.wsgi',
|
||||||
|
@ -238,7 +240,6 @@ def get_start_gunicorn_kwargs():
|
||||||
'-w', str(WORKERS),
|
'-w', str(WORKERS),
|
||||||
'--max-requests', '4096',
|
'--max-requests', '4096',
|
||||||
'--access-logformat', log_format,
|
'--access-logformat', log_format,
|
||||||
'-p', pid_file,
|
|
||||||
'--access-logfile', '-'
|
'--access-logfile', '-'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -247,6 +248,16 @@ def get_start_gunicorn_kwargs():
|
||||||
return {'cmd': cmd, 'cwd': APPS_DIR}
|
return {'cmd': cmd, 'cwd': APPS_DIR}
|
||||||
|
|
||||||
|
|
||||||
|
def get_start_daphne_kwargs():
|
||||||
|
print("\n- Start Daphne ASGI WS Server")
|
||||||
|
cmd = [
|
||||||
|
'daphne', 'jumpserver.asgi:application',
|
||||||
|
'-b', HTTP_HOST,
|
||||||
|
'-p', str(WS_PORT),
|
||||||
|
]
|
||||||
|
return {'cmd': cmd, 'cwd': APPS_DIR}
|
||||||
|
|
||||||
|
|
||||||
def get_start_celery_ansible_kwargs():
|
def get_start_celery_ansible_kwargs():
|
||||||
print("\n- Start Celery as Distributed Task Queue: Ansible")
|
print("\n- Start Celery as Distributed Task Queue: Ansible")
|
||||||
return get_start_worker_kwargs('ansible', 4)
|
return get_start_worker_kwargs('ansible', 4)
|
||||||
|
@ -362,6 +373,7 @@ def start_service(s):
|
||||||
"celery_default": get_start_celery_default_kwargs,
|
"celery_default": get_start_celery_default_kwargs,
|
||||||
"beat": get_start_beat_kwargs,
|
"beat": get_start_beat_kwargs,
|
||||||
"flower": get_start_flower_kwargs,
|
"flower": get_start_flower_kwargs,
|
||||||
|
"daphne": get_start_daphne_kwargs,
|
||||||
}
|
}
|
||||||
|
|
||||||
kwargs = services_kwargs.get(s)()
|
kwargs = services_kwargs.get(s)()
|
||||||
|
|
|
@ -86,3 +86,6 @@ httpsig==1.3.0
|
||||||
treelib==1.5.3
|
treelib==1.5.3
|
||||||
django-proxy==1.2.1
|
django-proxy==1.2.1
|
||||||
flower==0.9.3
|
flower==0.9.3
|
||||||
|
channels-redis==2.4.0
|
||||||
|
channels==2.3.0
|
||||||
|
daphne==2.3.0
|
||||||
|
|
Loading…
Reference in New Issue