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