Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
J
jumpserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ops
jumpserver
Commits
df80e804
Commit
df80e804
authored
Apr 01, 2018
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Update] 修改日志
parent
09fc2776
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
374 additions
and
121 deletions
+374
-121
api.py
apps/common/api.py
+32
-0
celery.py
apps/common/celery.py
+15
-1
const.py
apps/common/const.py
+2
-2
tail_file.html
apps/common/templates/common/tail_file.html
+96
-0
api_urls.py
apps/common/urls/api_urls.py
+1
-0
view_urls.py
apps/common/urls/view_urls.py
+3
-0
views.py
apps/common/views.py
+35
-2
api.py
apps/ops/api.py
+19
-11
models.py
apps/ops/models.py
+14
-3
tasks.py
apps/ops/tasks.py
+4
-4
adhoc_history.html
apps/ops/templates/ops/adhoc_history.html
+2
-1
adhoc_history_detail.html
apps/ops/templates/ops/adhoc_history_detail.html
+3
-0
adhoc_history_output.html
apps/ops/templates/ops/adhoc_history_output.html
+33
-89
celery_task_output.html
apps/ops/templates/ops/celery_task_output.html
+94
-0
task_adhoc.html
apps/ops/templates/ops/task_adhoc.html
+4
-0
task_detail.html
apps/ops/templates/ops/task_detail.html
+3
-1
task_history.html
apps/ops/templates/ops/task_history.html
+3
-2
task_list.html
apps/ops/templates/ops/task_list.html
+3
-3
api_urls.py
apps/ops/urls/api_urls.py
+1
-1
view_urls.py
apps/ops/urls/view_urls.py
+1
-0
views.py
apps/ops/views.py
+6
-1
No files found.
apps/common/api.py
View file @
df80e804
# -*- coding: utf-8 -*-
#
import
os
import
json
import
uuid
from
django.core.cache
import
cache
from
rest_framework.views
import
APIView
from
rest_framework.views
import
Response
from
ldap3
import
Server
,
Connection
...
...
@@ -11,6 +14,7 @@ from django.conf import settings
from
.permissions
import
IsSuperUser
,
IsAppUser
from
.serializers
import
MailTestSerializer
,
LDAPTestSerializer
from
.const
import
FILE_END_GUARD
class
MailTestingAPI
(
APIView
):
...
...
@@ -105,3 +109,30 @@ class DjangoSettingsAPI(APIView):
if
i
.
isupper
():
configs
[
i
]
=
str
(
getattr
(
settings
,
i
))
return
Response
(
configs
)
class
FileTailApi
(
APIView
):
permission_classes
=
(
IsSuperUser
,)
default_buff_size
=
1024
*
10
end
=
False
buff_size
=
None
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
file_path
=
request
.
query_params
.
get
(
"file"
)
self
.
buff_size
=
request
.
query_params
.
get
(
'buffer'
)
or
self
.
default_buff_size
mark
=
request
.
query_params
.
get
(
"mark"
)
or
str
(
uuid
.
uuid4
())
if
not
os
.
path
.
isfile
(
file_path
):
return
Response
({
"data"
:
_
(
"Waiting ..."
)},
status
=
203
)
with
open
(
file_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
FILE_END_GUARD
in
data
:
data
=
data
.
replace
(
FILE_END_GUARD
,
''
)
self
.
end
=
True
return
Response
({
"data"
:
data
,
'end'
:
self
.
end
,
'mark'
:
mark
})
\ No newline at end of file
apps/common/celery.py
View file @
df80e804
...
...
@@ -5,7 +5,7 @@ import json
from
functools
import
wraps
from
celery
import
Celery
,
subtask
from
celery.signals
import
worker_ready
,
worker_shutdown
from
celery.signals
import
worker_ready
,
worker_shutdown
,
task_prerun
,
task_postrun
from
django.db.utils
import
ProgrammingError
,
OperationalError
from
.utils
import
get_logger
...
...
@@ -199,3 +199,16 @@ def after_app_shutdown(sender=None, headers=None, body=None, **kwargs):
', '
.
join
(
__AFTER_APP_SHUTDOWN_CLEAN_TASKS
))
)
PeriodicTask
.
objects
.
filter
(
name__in
=
__AFTER_APP_SHUTDOWN_CLEAN_TASKS
)
.
delete
()
@task_prerun.connect
def
pre_run_task_signal_handler
(
sender
,
task
,
*
args
,
**
kwargs
):
print
(
"Sender: {}"
.
format
(
sender
))
print
(
"Task: {}"
.
format
(
task
))
@task_postrun.connect
def
post_run_task_signal_handler
(
sender
,
task
,
*
args
,
**
kwargs
):
print
(
"Sender: {}"
.
format
(
sender
))
print
(
"Task: {}"
.
format
(
task
))
\ No newline at end of file
apps/common/const.py
View file @
df80e804
...
...
@@ -4,4 +4,5 @@
from
django.utils.translation
import
ugettext
as
_
create_success_msg
=
_
(
"<b>
%(name)
s</b> was created successfully"
)
update_success_msg
=
_
(
"<b>
%(name)
s</b> was updated successfully"
)
\ No newline at end of file
update_success_msg
=
_
(
"<b>
%(name)
s</b> was updated successfully"
)
FILE_END_GUARD
=
">>> Content End <<<"
apps/common/templates/common/tail_file.html
0 → 100644
View file @
df80e804
{% 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-common:tail-file' %}?file={{ file_path }}"
;
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>
apps/common/urls/api_urls.py
View file @
df80e804
...
...
@@ -10,4 +10,5 @@ urlpatterns = [
url
(
r'^v1/mail/testing/$'
,
api
.
MailTestingAPI
.
as_view
(),
name
=
'mail-testing'
),
url
(
r'^v1/ldap/testing/$'
,
api
.
LDAPTestingAPI
.
as_view
(),
name
=
'ldap-testing'
),
url
(
r'^v1/django-settings/$'
,
api
.
DjangoSettingsAPI
.
as_view
(),
name
=
'django-settings'
),
url
(
r'^v1/tail-file/$'
,
api
.
FileTailApi
.
as_view
(),
name
=
'tail-file'
),
]
apps/common/urls/view_urls.py
View file @
df80e804
...
...
@@ -11,4 +11,7 @@ urlpatterns = [
url
(
r'^email/$'
,
views
.
EmailSettingView
.
as_view
(),
name
=
'email-setting'
),
url
(
r'^ldap/$'
,
views
.
LDAPSettingView
.
as_view
(),
name
=
'ldap-setting'
),
url
(
r'^terminal/$'
,
views
.
TerminalSettingView
.
as_view
(),
name
=
'terminal-setting'
),
url
(
r'^tail-file/$'
,
views
.
TailFileView
.
as_view
(),
name
=
'tail-file'
),
url
(
r'^celery/task/log/$'
,
views
.
CeleryTaskLogView
.
as_view
(),
name
=
'celery-task-log'
),
]
apps/common/views.py
View file @
df80e804
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
from
django.shortcuts
import
render
,
redirect
,
Http404
,
reverse
from
django.contrib
import
messages
from
django.utils.translation
import
ugettext
as
_
from
django.conf
import
settings
...
...
@@ -120,3 +122,34 @@ class TerminalSettingView(AdminUserRequiredMixin, TemplateView):
context
.
update
({
"form"
:
form
})
return
render
(
request
,
self
.
template_name
,
context
)
class
TailFileView
(
AdminUserRequiredMixin
,
TemplateView
):
template_name
=
'common/tail_file.html'
def
get_context_data
(
self
,
**
kwargs
):
file_path
=
self
.
request
.
GET
.
get
(
"file"
)
context
=
super
()
.
get_context_data
(
**
kwargs
)
context
.
update
({
"file_path"
:
file_path
})
return
context
class
CeleryTaskLogView
(
AdminUserRequiredMixin
,
TemplateView
):
template_name
=
'common/tail_file.html'
task_log_path
=
None
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
task
=
self
.
request
.
GET
.
get
(
'task'
)
if
not
task
:
raise
Http404
(
"Not found task"
)
self
.
task_log_path
=
cache
.
get
(
task
)
if
not
self
.
task_log_path
:
raise
Http404
(
"Not found task log file"
)
return
super
()
.
get
(
request
,
*
args
,
**
kwargs
)
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
()
.
get_context_data
(
**
kwargs
)
context
.
update
({
'file_path'
:
self
.
task_log_path
})
return
context
apps/ops/api.py
View file @
df80e804
# ~*~ coding: utf-8 ~*~
import
uuid
import
re
import
os
from
django.core.cache
import
cache
from
django.shortcuts
import
get_object_or_404
from
django.utils.translation
import
ugettext
as
_
from
rest_framework
import
viewsets
,
generics
from
rest_framework.
generics
import
Retrieve
APIView
from
rest_framework.
views
import
APIView
from
rest_framework.views
import
Response
from
.hands
import
IsSuperUser
from
common.const
import
FILE_END_GUARD
from
.models
import
Task
,
AdHoc
,
AdHocRunHistory
from
.serializers
import
TaskSerializer
,
AdHocSerializer
,
AdHocRunHistorySerializer
from
.tasks
import
run_ansible_task
class
TaskViewSet
(
viewsets
.
ModelViewSet
):
queryset
=
Task
.
objects
.
all
()
serializer_class
=
TaskSerializer
...
...
@@ -27,8 +31,8 @@ class TaskRun(generics.RetrieveAPIView):
def
retrieve
(
self
,
request
,
*
args
,
**
kwargs
):
task
=
self
.
get_object
()
run_ansible_task
.
delay
(
str
(
task
.
id
))
return
Response
({
"
msg"
:
"start"
})
t
=
run_ansible_task
.
delay
(
str
(
task
.
id
))
return
Response
({
"
task"
:
t
.
id
})
class
AdHocViewSet
(
viewsets
.
ModelViewSet
):
...
...
@@ -63,24 +67,28 @@ class AdHocRunHistorySet(viewsets.ModelViewSet):
return
self
.
queryset
class
AdHocHistoryOutputAPI
(
RetrieveAPIView
):
queryset
=
AdHocRunHistory
.
objects
.
all
()
class
LogFileViewApi
(
APIView
):
permission_classes
=
(
IsSuperUser
,)
buff_size
=
1024
*
10
end
=
False
def
retrieve
(
self
,
request
,
*
args
,
**
kwargs
):
history
=
self
.
get_object
(
)
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
file_path
=
request
.
query_params
.
get
(
"file"
)
mark
=
request
.
query_params
.
get
(
"mark"
)
or
str
(
uuid
.
uuid4
())
with
open
(
history
.
log_path
,
'r'
)
as
f
:
if
not
os
.
path
.
isfile
(
file_path
):
print
(
file_path
)
return
Response
({
"error"
:
_
(
"Log file not found"
)},
status
=
204
)
with
open
(
file_path
,
'r'
)
as
f
:
offset
=
cache
.
get
(
mark
,
0
)
f
.
seek
(
offset
)
data
=
f
.
read
(
self
.
buff_size
)
.
replace
(
'
\n
'
,
'
\r\n
'
)
print
(
repr
(
data
))
mark
=
str
(
uuid
.
uuid4
())
cache
.
set
(
mark
,
f
.
tell
(),
5
)
if
history
.
is_finished
and
data
==
''
:
if
FILE_END_GUARD
in
data
:
data
.
replace
(
FILE_END_GUARD
,
''
)
self
.
end
=
True
return
Response
({
"data"
:
data
,
'end'
:
self
.
end
,
'mark'
:
mark
})
apps/ops/models.py
View file @
df80e804
...
...
@@ -6,6 +6,7 @@ import os
import
time
import
datetime
from
celery
import
current_task
from
django.db
import
models
from
django.conf
import
settings
from
django.utils
import
timezone
...
...
@@ -211,11 +212,20 @@ class AdHoc(models.Model):
return
self
.
_run_only
()
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
()
# f = open(history.log_path, 'w')
try
:
with
open
(
history
.
log_path
,
'w'
)
as
f
:
raw
,
summary
=
self
.
_run_only
(
file_obj
=
f
)
date_start
=
timezone
.
now
()
.
strftime
(
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
# f.write("{} {}\r\n\r\n".format(date_start, self.task.name))
raw
,
summary
=
self
.
_run_only
()
# raw, summary = self._run_only(file_obj=f)
date_end
=
timezone
.
now
()
.
strftime
(
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
# f.write("\r\n{} Task finish\r\n".format(date_end))
history
.
is_finished
=
True
if
summary
.
get
(
'dark'
):
history
.
is_success
=
False
...
...
@@ -227,6 +237,7 @@ class AdHoc(models.Model):
except
Exception
as
e
:
return
{},
{
"dark"
:
{
"all"
:
str
(
e
)},
"contacted"
:
[]}
finally
:
# f.close()
history
.
date_finished
=
timezone
.
now
()
history
.
timedelta
=
time
.
time
()
-
time_start
history
.
save
()
...
...
apps/ops/tasks.py
View file @
df80e804
# coding: utf-8
from
celery
import
shared_task
,
subtask
from
common.utils
import
get_logger
,
get_object_or_none
from
.models
import
Task
...
...
@@ -12,14 +13,13 @@ def rerun_task():
@shared_task
def
run_ansible_task
(
t
ask_
id
,
callback
=
None
,
**
kwargs
):
def
run_ansible_task
(
tid
,
callback
=
None
,
**
kwargs
):
"""
:param t
ask_
id: is the tasks serialized data
:param tid: is the tasks serialized data
:param callback: callback function name
:return:
"""
task
=
get_object_or_none
(
Task
,
id
=
task_id
)
task
=
get_object_or_none
(
Task
,
id
=
tid
)
if
task
:
result
=
task
.
run
()
if
callback
is
not
None
:
...
...
apps/ops/templates/ops/adhoc_history.html
View file @
df80e804
...
...
@@ -82,7 +82,8 @@ function initTable() {
select
:
[],
columnDefs
:
[
{
targets
:
1
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
$
(
td
).
html
(
cellData
);
var
d
=
new
Date
(
cellData
);
$
(
td
).
html
(
d
);
}},
{
targets
:
2
,
createdCell
:
function
(
td
,
cellData
)
{
var
total
=
"<span>"
+
cellData
.
total
+
"</span>"
;
...
...
apps/ops/templates/ops/adhoc_history_detail.html
View file @
df80e804
...
...
@@ -18,6 +18,9 @@
<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>
</li>
<li>
<a
href=
"{% url 'ops:adhoc-history-output' pk=object.pk %}"
class=
"text-center"
><i
class=
"fa fa-laptop"
></i>
{% trans 'History output' %}
</a>
</li>
</ul>
</div>
<div
class=
"tab-content"
>
...
...
apps/ops/templates/ops/adhoc_history_output.html
View file @
df80e804
{% extends 'base.html' %}
{% load static %}
<!doctype html>
<html>
<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
:
14px
;
color
:
#f0f0f0
;
background-color
:
#555
;
padding
:
20px
20px
20px
;
}
.terminal-cursor
{
color
:
#000
;
background
:
#f0f0f0
;
}
</style>
</head>
<body>
<div
class=
"container"
>
<div
id=
"term"
>
</div>
</div>
</body>
{% load i18n %}
{% block custom_head_css_js %}
<link
href=
"{% static 'css/plugins/select2/select2.min.css' %}"
rel=
"stylesheet"
>
<link
href=
"{% static "
css
/
plugins
/
sweetalert
/
sweetalert
.
css
"
%}"
rel=
"stylesheet"
>
<script
src=
"{% static 'js/plugins/select2/select2.full.min.js' %}"
></script>
<script
src=
"{% static "
js
/
plugins
/
sweetalert
/
sweetalert
.
min
.
js
"
%}"
></script>
</head>
{% endblock %}
{% block content %}
<div
class=
"wrapper wrapper-content animated fadeInRight"
>
<div
class=
"row"
>
<div
class=
"col-sm-12"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"panel-options"
>
<ul
class=
"nav nav-tabs"
>
<li>
<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
class=
"active"
>
<a
href=
"{% url 'ops:adhoc-history-output' pk=object.pk %}"
class=
"text-center"
><i
class=
"fa fa-laptop"
></i>
{% trans 'History output' %}
</a>
</li>
</ul>
</div>
<div
class=
"tab-content"
style=
"height: 800px"
>
<iframe
src=
"{% url 'ops:adhoc-history-output-alone' pk=object.pk %}"
width=
"100%"
height=
"100%"
>
<script
src=
"{% static 'js/term.js' %}"
></script>
<script>
var
rowHeight
=
1
;
var
colWidth
=
1
;
var
mark
=
''
;
var
url
=
"{% url 'api-ops:history-output' pk=object.id %}"
;
var
term
;
var
end
=
false
;
</iframe>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
function
calWinSize
()
{
var
t
=
$
(
'.terminal'
);
console
.
log
(
t
.
height
());
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
)
-
5
;
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
)
{
term
.
write
(
data
.
data
);
mark
=
data
.
mark
;
if
(
data
.
end
){
end
=
true
}
}).
fail
(
function
(
jqXHR
,
textStatus
,
errorThrown
)
{
});
}
}
$
(
document
).
ready
(
function
()
{
term
=
new
Terminal
({
cols
:
80
,
rows
:
24
,
useStyle
:
true
,
screenKeys
:
false
});
term
.
open
();
term
.
on
(
'data'
,
function
(
data
)
{
term
.
write
(
data
.
replace
(
'
\
r'
,
'
\
r
\
n'
))
});
calWinSize
();
resize
();
$
(
'.terminal'
).
detach
().
appendTo
(
'#term'
);
term
.
write
(
'
\
x1b[31mWelcome to term.js!
\
x1b[m
\
r
\
n'
);
setInterval
(
function
()
{
requestAndWrite
()
},
100
)
});
</script>
</html>
apps/ops/templates/ops/celery_task_output.html
0 → 100644
View file @
df80e804
{% 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:history-output' pk=object.id %}"
;
var
term
;
var
end
=
false
;
var
has_error
=
false
;
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
)
-
5
;
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
)
{
term
.
write
(
data
.
data
);
mark
=
data
.
mark
;
if
(
data
.
end
){
end
=
true
}
}).
fail
(
function
(
jqXHR
,
textStatus
,
errorThrown
)
{
if
(
!
has_error
)
{
var
error
=
jqXHR
.
responseJSON
.
error
;
term
.
write
(
'
\
x1b[31m'
+
error
+
'
\
x1b[m
\
r
\
n'
);
has_error
=
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
()
},
200
)
});
</script>
apps/ops/templates/ops/task_adhoc.html
View file @
df80e804
...
...
@@ -105,6 +105,10 @@
$
(
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
)
{
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
)
{
...
...
apps/ops/templates/ops/task_detail.html
View file @
df80e804
...
...
@@ -24,6 +24,9 @@
<li>
<a
href=
"{% url 'ops:task-history' pk=object.pk %}"
class=
"text-center"
><i
class=
"fa fa-laptop"
></i>
{% trans 'Run history' %}
</a>
</li>
<li>
<a
href=
"{% url 'ops:adhoc-history-output' pk=object.latest_history.pk %}"
class=
"text-center"
><i
class=
"fa fa-laptop"
></i>
{% trans 'Last run output' %}
</a>
</li>
</ul>
</div>
<div
class=
"tab-content"
>
...
...
@@ -160,6 +163,5 @@
</div>
</div>
</div>
{% include 'users/_user_update_pk_modal.html' %}
{% endblock %}
apps/ops/templates/ops/task_history.html
View file @
df80e804
...
...
@@ -30,7 +30,7 @@
<div
class=
"col-sm-12"
style=
"padding-left: 0"
>
<div
class=
"ibox float-e-margins"
>
<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"
>
<a
class=
"collapse-link"
>
<i
class=
"fa fa-chevron-up"
></i>
...
...
@@ -85,7 +85,8 @@ function initTable() {
select
:
[],
columnDefs
:
[
{
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
)
{
var
total
=
"<span>"
+
cellData
.
total
+
"</span>"
;
...
...
apps/ops/templates/ops/task_list.html
View file @
df80e804
...
...
@@ -111,9 +111,9 @@ $(document).ready(function() {
var
error
=
function
(
data
)
{
alert
(
data
)
};
var
success
=
function
(
)
{
alert
(
"任务开始执行,重定向到任务详情页面,多刷新几次查看结果"
)
window
.
location
=
"{% url 'ops:
task-detail' pk=DEFAULT_PK %}"
.
replace
(
'{{ DEFAULT_PK }}'
,
u
id
);
var
success
=
function
(
data
)
{
var
task_id
=
data
.
task
;
window
.
location
=
"{% url 'ops:
adhoc-history-output' pk=DEFAULT_PK %}"
.
replace
(
"{{ DEFAULT_PK }}"
,
task_
id
);
};
APIUpdateAttr
({
url
:
the_url
,
...
...
apps/ops/urls/api_urls.py
View file @
df80e804
...
...
@@ -15,7 +15,7 @@ router.register(r'v1/history', api.AdHocRunHistorySet, 'history')
urlpatterns
=
[
url
(
r'^v1/tasks/(?P<pk>[0-9a-zA-Z\-]{36})/run/$'
,
api
.
TaskRun
.
as_view
(),
name
=
'task-run'
),
url
(
r'^v1/history/(?P<pk>[0-9a-zA-Z\-]{36})/output/$'
,
api
.
AdHocHistoryOutputAPI
.
as_view
(),
name
=
'history-output'
),
# url(r'^v1/history/(?P<pk>[0-9a-zA-Z\-]{36})/output/$', api.CeleryTaskOutputApi
.as_view(), name='history-output'),
]
urlpatterns
+=
router
.
urls
apps/ops/urls/view_urls.py
View file @
df80e804
...
...
@@ -18,5 +18,6 @@ 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})/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})/_output/$'
,
views
.
CeleryTaskOutputView
.
as_view
(),
name
=
'adhoc-history-output-alone'
),
url
(
r'^adhoc/history/(?P<pk>[0-9a-zA-Z\-]{36})/output/$'
,
views
.
AdHocHistoryOutputView
.
as_view
(),
name
=
'adhoc-history-output'
),
]
apps/ops/views.py
View file @
df80e804
...
...
@@ -2,7 +2,7 @@
from
django.utils.translation
import
ugettext
as
_
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
.models
import
Task
,
AdHoc
,
AdHocRunHistory
...
...
@@ -121,6 +121,11 @@ class AdHocHistoryDetailView(AdminUserRequiredMixin, DetailView):
return
super
()
.
get_context_data
(
**
kwargs
)
class
CeleryTaskOutputView
(
AdminUserRequiredMixin
,
TemplateView
):
model
=
AdHocRunHistory
template_name
=
'ops/celery_task_output.html'
class
AdHocHistoryOutputView
(
AdminUserRequiredMixin
,
DetailView
):
model
=
AdHocRunHistory
template_name
=
'ops/adhoc_history_output.html'
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment