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
e57121a7
Commit
e57121a7
authored
Dec 06, 2017
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Feature] 优化Ops ansible api
parent
ec8106e4
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
496 additions
and
379 deletions
+496
-379
utils.py
apps/assets/utils.py
+5
-1
django.po
apps/locale/zh/LC_MESSAGES/django.po
+6
-6
callback.py
apps/ops/ansible/callback.py
+56
-45
exceptions.py
apps/ops/ansible/exceptions.py
+6
-0
inventory.py
apps/ops/ansible/inventory.py
+91
-55
runner.py
apps/ops/ansible/runner.py
+160
-230
test_inventory.py
apps/ops/ansible/test_inventory.py
+63
-0
test_runner.py
apps/ops/ansible/test_runner.py
+54
-0
api.py
apps/ops/api.py
+2
-2
models.py
apps/ops/models.py
+22
-21
serializers.py
apps/ops/serializers.py
+2
-2
tasks.py
apps/ops/tasks.py
+2
-2
utils.py
apps/ops/utils.py
+20
-8
views.py
apps/ops/views.py
+5
-5
_nav.html
apps/templates/_nav.html
+1
-1
models.py
apps/terminal/models.py
+1
-1
No files found.
apps/assets/utils.py
View file @
e57121a7
# ~*~ coding: utf-8 ~*~
#
from
ops.utils
import
run_AdHoc
from
.models
import
Asset
def
test_admin_user_connective_manual
(
asset
):
from
ops.utils
import
run_AdHoc
if
not
isinstance
(
asset
,
list
):
asset
=
[
asset
]
task_tuple
=
(
...
...
@@ -15,3 +16,6 @@ def test_admin_user_connective_manual(asset):
else
:
return
True
def
get_assets_by_id_list
(
id_list
):
return
Asset
.
objects
.
filter
(
id__in
=
id_list
)
apps/locale/zh/LC_MESSAGES/django.po
View file @
e57121a7
...
...
@@ -1418,23 +1418,23 @@ msgid "Assets id"
msgstr "资产id"
#: ops/models.py:27
msgid "
Tas
k module and args json format"
msgid "
Playboo
k module and args json format"
msgstr ""
#: ops/models.py:28
msgid "
Tas
k run pattern"
msgid "
Playboo
k run pattern"
msgstr ""
#: ops/models.py:29
msgid "
Tas
k raw result"
msgid "
Playboo
k raw result"
msgstr ""
#: ops/models.py:30
msgid "
Tas
k summary"
msgid "
Playboo
k summary"
msgstr ""
#: ops/templates/ops/task_detail.html:19
msgid "
Tas
k replay detail"
msgid "
Playboo
k replay detail"
msgstr "任务记录详情"
#: ops/templates/ops/task_detail.html:62
...
...
@@ -1669,7 +1669,7 @@ msgid "Job Center"
msgstr "作业中心"
#: templates/_nav.html:51
msgid "
Tas
k"
msgid "
Playboo
k"
msgstr "任务"
#: templates/_nav.html:62
...
...
apps/ops/ansible/callback.py
View file @
e57121a7
# ~*~ coding: utf-8 ~*~
from
collections
import
defaultdict
from
ansible.plugins.callback
import
CallbackBase
class
CommandResultCallback
(
CallbackBase
):
def
__init__
(
self
,
display
=
None
):
self
.
result_q
=
dict
(
contacted
=
{},
dark
=
{})
super
(
CommandResultCallback
,
self
)
.
__init__
(
display
)
def
gather_result
(
self
,
n
,
res
):
self
.
result_q
[
n
][
res
.
_host
.
name
]
=
{}
self
.
result_q
[
n
][
res
.
_host
.
name
][
'cmd'
]
=
res
.
_result
.
get
(
'cmd'
)
self
.
result_q
[
n
][
res
.
_host
.
name
][
'stderr'
]
=
res
.
_result
.
get
(
'stderr'
)
self
.
result_q
[
n
][
res
.
_host
.
name
][
'stdout'
]
=
res
.
_result
.
get
(
'stdout'
)
self
.
result_q
[
n
][
res
.
_host
.
name
][
'rc'
]
=
res
.
_result
.
get
(
'rc'
)
def
v2_runner_on_ok
(
self
,
result
):
self
.
gather_result
(
"contacted"
,
result
)
def
v2_runner_on_failed
(
self
,
result
,
ignore_errors
=
False
):
self
.
gather_result
(
"dark"
,
result
)
def
v2_runner_on_unreachable
(
self
,
result
):
self
.
gather_result
(
"dark"
,
result
)
def
v2_runner_on_skipped
(
self
,
result
):
self
.
gather_result
(
"dark"
,
result
)
class
AdHocResultCallback
(
CallbackBase
):
"""
AdHoc result Callback
"""
def
__init__
(
self
,
display
=
None
):
self
.
result_q
=
dict
(
contacted
=
{},
dark
=
{})
super
(
AdHocResultCallback
,
self
)
.
__init__
(
display
)
def
gather_result
(
self
,
n
,
res
):
if
res
.
_host
.
name
in
self
.
result_q
[
n
]:
self
.
result_q
[
n
][
res
.
_host
.
name
]
.
append
(
res
.
_result
)
# result_raw example: {
# "ok": {"hostname": []},
# "failed": {"hostname": []},
# "unreachable: {"hostname": []},
# "skipped": {"hostname": []},
# }
# results_summary example: {
# "contacted": {"hostname",...},
# "dark": {"hostname": ["error",...],},
# }
self
.
results_raw
=
dict
(
ok
=
{},
failed
=
{},
unreachable
=
{},
skipped
=
{})
self
.
results_summary
=
dict
(
contacted
=
set
(),
dark
=
{})
super
()
.
__init__
(
display
)
def
gather_result
(
self
,
t
,
host
,
res
):
if
self
.
results_raw
[
t
]
.
get
(
host
):
self
.
results_raw
[
t
][
host
]
.
append
(
res
)
else
:
self
.
results_raw
[
t
][
host
]
=
[
res
]
self
.
clean_result
(
t
,
host
,
res
)
def
clean_result
(
self
,
t
,
host
,
res
):
contacted
=
self
.
results_summary
[
"contacted"
]
dark
=
self
.
results_summary
[
"dark"
]
if
t
in
(
"ok"
,
"skipped"
)
and
host
not
in
dark
:
contacted
.
add
(
host
)
else
:
self
.
result_q
[
n
][
res
.
_host
.
name
]
=
[
res
.
_result
]
dark
[
host
]
.
append
(
res
)
if
host
in
contacted
:
contacted
.
remove
(
dark
)
def
v2_runner_on_ok
(
self
,
result
):
self
.
gather_result
(
"
contacted"
,
result
)
def
runner_on_ok
(
self
,
host
,
res
):
self
.
gather_result
(
"
ok"
,
host
,
res
)
def
v2_runner_on_failed
(
self
,
result
,
ignore_errors
=
False
):
self
.
gather_result
(
"
dark"
,
result
)
def
runner_on_failed
(
self
,
host
,
res
,
ignore_errors
=
False
):
self
.
gather_result
(
"
failed"
,
host
,
res
)
def
v2_runner_on_unreachable
(
self
,
result
):
self
.
gather_result
(
"
dark"
,
result
)
def
runner_on_unreachable
(
self
,
host
,
res
):
self
.
gather_result
(
"
unreachable"
,
host
,
res
)
def
v2_runner_on_skipped
(
self
,
result
):
self
.
gather_result
(
"
dark"
,
result
)
def
runner_on_skipped
(
self
,
host
,
item
=
None
):
self
.
gather_result
(
"
skipped"
,
host
,
item
)
def
v2_playbook_on_task_start
(
self
,
task
,
is_conditional
):
pass
def
v2_playbook_on_play_start
(
self
,
play
):
pass
class
CommandResultCallback
(
AdHocResultCallback
):
def
__init__
(
self
,
display
=
None
):
self
.
results_command
=
dict
()
super
()
.
__init__
(
display
)
def
gather_result
(
self
,
t
,
host
,
res
):
super
()
.
gather_result
(
t
,
host
,
res
)
self
.
gather_cmd
(
t
,
host
,
res
)
def
gather_cmd
(
self
,
t
,
host
,
res
):
cmd
=
{}
if
t
==
"ok"
:
cmd
[
'cmd'
]
=
res
.
get
(
'cmd'
)
cmd
[
'stderr'
]
=
res
.
get
(
'stderr'
)
cmd
[
'stdout'
]
=
res
.
get
(
'stdout'
)
cmd
[
'rc'
]
=
res
.
get
(
'rc'
)
else
:
cmd
[
'err'
]
=
"Error: {}"
.
format
(
res
)
self
.
results_command
[
host
]
=
cmd
class
PlaybookResultCallBack
(
CallbackBase
):
...
...
apps/ops/ansible/exceptions.py
0 → 100644
View file @
e57121a7
# -*- coding: utf-8 -*-
#
class
AnsibleError
(
Exception
):
pass
apps/ops/ansible/inventory.py
View file @
e57121a7
# ~*~ coding: utf-8 ~*~
from
ansible.inventory
import
Inventory
,
Host
,
Group
from
ansible.vars
import
VariableManager
from
ansible.inventory.group
import
Group
from
ansible.inventory.host
import
Host
from
ansible.vars.manager
import
VariableManager
from
ansible.inventory.manager
import
InventoryManager
from
ansible.parsing.dataloader
import
DataLoader
class
JMSHost
(
Host
):
def
__init__
(
self
,
asset
):
self
.
asset
=
asset
self
.
name
=
name
=
asset
.
get
(
'hostname'
)
or
asset
.
get
(
'ip'
)
self
.
port
=
port
=
asset
.
get
(
'port'
)
or
22
super
(
JMSHost
,
self
)
.
__init__
(
name
,
port
)
self
.
set_all_variable
()
def
__init__
(
self
,
host_data
):
"""
初始化
:param host_data: {
"hostname": "",
"ip": "",
"port": "",
"username": "",
"password": "",
"private_key": "",
"become": {
"method": "",
"user": "",
"pass": "",
}
"groups": [],
"vars": {},
}
"""
self
.
host_data
=
host_data
hostname
=
host_data
.
get
(
'hostname'
)
or
host_data
.
get
(
'ip'
)
port
=
host_data
.
get
(
'port'
)
or
22
super
(
JMSHost
,
self
)
.
__init__
(
hostname
,
port
)
self
.
__set_required_variables
()
self
.
__set_extra_variables
()
def
set_all_variable
(
self
):
asset
=
self
.
asset
self
.
set_variable
(
'ansible_host'
,
asset
[
'ip'
])
self
.
set_variable
(
'ansible_port'
,
asset
[
'port'
])
self
.
set_variable
(
'ansible_user'
,
asset
[
'username'
])
def
__set_required_variables
(
self
):
host_data
=
self
.
host_data
self
.
set_variable
(
'ansible_host'
,
host_data
[
'ip'
])
self
.
set_variable
(
'ansible_port'
,
host_data
[
'port'
])
self
.
set_variable
(
'ansible_user'
,
host_data
[
'username'
])
# 添加密码和秘钥
if
asset
.
get
(
'password'
):
self
.
set_variable
(
'ansible_ssh_pass'
,
asset
[
'password'
])
if
asset
.
get
(
'private_key'
):
self
.
set_variable
(
'ansible_ssh_private_key_file'
,
asset
[
'private_key'
])
if
host_data
.
get
(
'password'
):
self
.
set_variable
(
'ansible_ssh_pass'
,
host_data
[
'password'
])
if
host_data
.
get
(
'private_key'
):
self
.
set_variable
(
'ansible_ssh_private_key_file'
,
host_data
[
'private_key'
])
# 添加become支持
become
=
asset
.
get
(
"become"
,
False
)
become
=
host_data
.
get
(
"become"
,
False
)
if
become
:
self
.
set_variable
(
"ansible_become"
,
True
)
self
.
set_variable
(
"ansible_become_method"
,
become
.
get
(
'method'
,
'sudo'
))
...
...
@@ -34,58 +55,73 @@ class JMSHost(Host):
else
:
self
.
set_variable
(
"ansible_become"
,
False
)
def
__set_extra_variables
(
self
):
for
k
,
v
in
self
.
host_data
.
get
(
'vars'
,
{})
.
items
():
self
.
set_variable
(
k
,
v
)
def
__repr__
(
self
):
return
self
.
name
class
JMSInventory
(
Inventory
):
class
JMSInventory
(
InventoryManager
):
"""
提供生成Ansible inventory对象的方法
"""
loader_class
=
DataLoader
variable_manager_class
=
VariableManager
host_manager_class
=
JMSHost
def
__init__
(
self
,
host_list
=
None
):
if
host_list
is
None
:
host_list
=
[]
assert
isinstance
(
host_list
,
list
)
self
.
host_list
=
host_list
self
.
loader
=
DataLoader
(
)
self
.
variable_manager
=
VariableManager
()
s
uper
(
JMSInventory
,
self
)
.
__init__
(
self
.
loader
,
self
.
variable_manager
,
host_list
=
host_list
)
assert
isinstance
(
host_list
,
list
)
self
.
loader
=
self
.
loader_class
()
s
elf
.
variable_manager
=
self
.
variable_manager_class
()
super
()
.
__init__
(
self
.
loader
)
def
parse_inventory
(
self
,
host_list
):
"""用于生成动态构建Ansible Inventory.
self.host_list: [
{"name": "asset_name",
"ip": <ip>,
"port": <port>,
"user": <user>,
"pass": <pass>,
"key": <sshKey>,
"groups": ['group1', 'group2'],
"other_host_var": <other>},
{...},
]
def
get_groups
(
self
):
return
self
.
_inventory
.
groups
def
get_group
(
self
,
name
):
return
self
.
_inventory
.
groups
.
get
(
name
,
None
)
:return: 返回一个Ansible的inventory对象
def
parse_sources
(
self
,
cache
=
False
):
"""
用于生成动态构建Ansible Inventory. super().__init__ 会自动调用
host_list: [{
"hostname": "",
"ip": "",
"port": "",
"username": "",
"password": "",
"private_key": "",
"become": {
"method": "",
"user": "",
"pass": "",
},
"groups": [],
"vars": {},
},
]
# TODO: 验证输入
# 创建Ansible Group,如果没有则创建default组
ungrouped
=
Group
(
'ungrouped'
)
all
=
Group
(
'all'
)
all
.
add_child_group
(
ungrouped
)
self
.
groups
=
dict
(
all
=
all
,
ungrouped
=
ungrouped
)
:return: None
"""
group_all
=
self
.
get_group
(
'all'
)
ungrouped
=
self
.
get_group
(
'ungrouped'
)
for
asset
in
host_list
:
host
=
JMSHost
(
asset
=
asset
)
asset_groups
=
asset
.
get
(
'groups'
)
if
asset_groups
:
for
group_name
in
asset_groups
:
if
group_name
not
in
self
.
groups
:
for
host_data
in
self
.
host_list
:
host
=
self
.
host_manager_class
(
host_data
=
host_data
)
self
.
hosts
[
host_data
[
'hostname'
]]
=
host
groups_data
=
host_data
.
get
(
'groups'
)
if
groups_data
:
for
group_name
in
groups_data
:
group
=
self
.
get_group
(
group_name
)
if
group
is
None
:
group
=
Group
(
group_name
)
self
.
groups
[
group_name
]
=
group
else
:
group
=
self
.
groups
[
group_name
]
self
.
add_group
(
group
)
group
.
add_host
(
host
)
else
:
ungrouped
.
add_host
(
host
)
all
.
add_host
(
host
)
group_all
.
add_host
(
host
)
apps/ops/ansible/runner.py
View file @
e57121a7
...
...
@@ -2,303 +2,233 @@
from
__future__
import
unicode_literals
import
os
from
collections
import
namedtuple
,
defaultdict
from
collections
import
namedtuple
from
ansible.executor.task_queue_manager
import
TaskQueueManager
from
ansible.vars
import
VariableManager
from
ansible.vars
.manager
import
VariableManager
from
ansible.parsing.dataloader
import
DataLoader
from
ansible.executor.playbook_executor
import
PlaybookExecutor
from
ansible.playbook.play
import
Play
import
ansible.constants
as
C
from
ansible.utils.vars
import
load_extra_vars
from
ansible.utils.vars
import
load_options_vars
from
.inventory
import
JMSInventory
from
.callback
import
AdHocResultCallback
,
PlaybookResultCallBack
,
\
CommandResultCallback
from
common.utils
import
get_logger
from
.exceptions
import
AnsibleError
__all__
=
[
"AdHocRunner"
,
"PlayBookRunner"
]
C
.
HOST_KEY_CHECKING
=
False
logger
=
get_logger
(
__name__
)
Options
=
namedtuple
(
'Options'
,
[
'listtags'
,
'listtasks'
,
'listhosts'
,
'syntax'
,
'connection'
,
'module_path'
,
'forks'
,
'remote_user'
,
'private_key_file'
,
'timeout'
,
'ssh_common_args'
,
'ssh_extra_args'
,
'sftp_extra_args'
,
'scp_extra_args'
,
'become'
,
'become_method'
,
'become_user'
,
'verbosity'
,
'check'
,
'extra_vars'
,
'playbook_path'
,
'passwords'
,
'diff'
,
])
def
get_default_options
():
options
=
Options
(
listtags
=
False
,
listtasks
=
False
,
listhosts
=
False
,
syntax
=
False
,
timeout
=
60
,
connection
=
'ssh'
,
module_path
=
''
,
forks
=
10
,
remote_user
=
'root'
,
private_key_file
=
None
,
ssh_common_args
=
""
,
ssh_extra_args
=
""
,
sftp_extra_args
=
""
,
scp_extra_args
=
""
,
become
=
None
,
become_method
=
None
,
become_user
=
None
,
verbosity
=
None
,
extra_vars
=
[],
check
=
False
,
playbook_path
=
'/etc/ansible/'
,
passwords
=
None
,
diff
=
False
,
)
return
options
# Jumpserver not use playbook
class
PlayBookRunner
(
object
)
:
class
PlayBookRunner
:
"""
用于执行AnsiblePlaybook的接口.简化Playbook对象的使用.
"""
Options
=
namedtuple
(
'Options'
,
[
'listtags'
,
'listtasks'
,
'listhosts'
,
'syntax'
,
'connection'
,
'module_path'
,
'forks'
,
'remote_user'
,
'private_key_file'
,
'timeout'
,
'ssh_common_args'
,
'ssh_extra_args'
,
'sftp_extra_args'
,
'scp_extra_args'
,
'become'
,
'become_method'
,
'become_user'
,
'verbosity'
,
'check'
,
'extra_vars'
])
def
__init__
(
self
,
hosts
=
None
,
playbook_path
=
None
,
forks
=
C
.
DEFAULT_FORKS
,
listtags
=
False
,
listtasks
=
False
,
listhosts
=
False
,
syntax
=
False
,
module_path
=
None
,
remote_user
=
'root'
,
timeout
=
C
.
DEFAULT_TIMEOUT
,
ssh_common_args
=
None
,
ssh_extra_args
=
None
,
sftp_extra_args
=
None
,
scp_extra_args
=
None
,
become
=
True
,
become_method
=
None
,
become_user
=
"root"
,
verbosity
=
None
,
extra_vars
=
None
,
connection_type
=
"ssh"
,
passwords
=
None
,
private_key_file
=
None
,
check
=
False
):
# Default results callback
results_callback_class
=
PlaybookResultCallBack
inventory_class
=
JMSInventory
loader_class
=
DataLoader
variable_manager_class
=
VariableManager
options
=
get_default_options
()
def
__init__
(
self
,
hosts
=
None
,
options
=
None
):
"""
:param options: Ansible options like ansible.cfg
:param hosts: [
{
"hostname": "",
"ip": "",
"port": "",
"username": "",
"password": "",
"private_key": "",
"become": {
"method": "",
"user": "",
"pass": "",
},
"groups": [],
"vars": {},
},
]
"""
if
options
:
self
.
options
=
options
C
.
RETRY_FILES_ENABLED
=
False
self
.
callbackmodule
=
PlaybookResultCallBack
()
if
playbook_path
is
None
or
not
os
.
path
.
exists
(
playbook_path
):
raise
AnsibleError
(
"Not Found the playbook file:
%
s."
%
playbook_path
)
self
.
playbook_path
=
playbook_path
self
.
loader
=
DataLoader
()
self
.
variable_manager
=
VariableManager
()
self
.
passwords
=
passwords
or
{}
self
.
inventory
=
JMSInventory
(
hosts
)
self
.
options
=
self
.
Options
(
listtags
=
listtags
,
listtasks
=
listtasks
,
listhosts
=
listhosts
,
syntax
=
syntax
,
timeout
=
timeout
,
connection
=
connection_type
,
module_path
=
module_path
,
forks
=
forks
,
remote_user
=
remote_user
,
private_key_file
=
private_key_file
,
ssh_common_args
=
ssh_common_args
or
""
,
ssh_extra_args
=
ssh_extra_args
or
""
,
sftp_extra_args
=
sftp_extra_args
,
scp_extra_args
=
scp_extra_args
,
become
=
become
,
become_method
=
become_method
,
become_user
=
become_user
,
verbosity
=
verbosity
,
extra_vars
=
extra_vars
or
[],
check
=
check
self
.
inventory
=
self
.
inventory_class
(
hosts
)
self
.
loader
=
self
.
loader_class
()
self
.
results_callback
=
self
.
results_callback_class
()
self
.
playbook_path
=
options
.
playbook_path
self
.
variable_manager
=
self
.
variable_manager_class
(
loader
=
self
.
loader
,
inventory
=
self
.
inventory
)
self
.
passwords
=
options
.
passwords
self
.
__check
()
self
.
variable_manager
.
extra_vars
=
load_extra_vars
(
loader
=
self
.
loader
,
options
=
self
.
options
)
self
.
variable_manager
.
options_vars
=
load_options_vars
(
self
.
options
)
self
.
variable_manager
.
set_inventory
(
self
.
inventory
)
def
__check
(
self
):
if
self
.
options
.
playbook_path
is
None
or
\
not
os
.
path
.
exists
(
self
.
options
.
playbook_path
):
raise
AnsibleError
(
"Not Found the playbook file: {}."
.
format
(
self
.
options
.
playbook_path
)
)
if
not
self
.
inventory
.
list_hosts
(
'all'
):
raise
AnsibleError
(
'Inventory is empty'
)
# 初始化playbook的executor
self
.
runne
r
=
PlaybookExecutor
(
def
run
(
self
):
executo
r
=
PlaybookExecutor
(
playbooks
=
[
self
.
playbook_path
],
inventory
=
self
.
inventory
,
variable_manager
=
self
.
variable_manager
,
loader
=
self
.
loader
,
options
=
self
.
options
,
passwords
=
self
.
passwords
)
if
self
.
runner
.
_tqm
:
self
.
runner
.
_tqm
.
_stdout_callback
=
self
.
callbackmodule
passwords
=
self
.
passwords
)
def
run
(
self
):
if
not
self
.
inventory
.
list_hosts
(
'all'
):
raise
AnsibleError
(
'Inventory is empty'
)
self
.
runner
.
run
()
self
.
runner
.
_tqm
.
cleanup
()
return
self
.
callbackmodule
.
output
if
executor
.
_tqm
:
executor
.
_tqm
.
_stdout_callback
=
self
.
results_callback
executor
.
run
()
executor
.
_tqm
.
cleanup
()
return
self
.
results_callback
.
output
class
AdHocRunner
(
object
)
:
class
AdHocRunner
:
"""
ADHoc接口
ADHoc
Runner
接口
"""
Options
=
namedtuple
(
"Options"
,
[
'connection'
,
'module_path'
,
'private_key_file'
,
"remote_user"
,
'timeout'
,
'forks'
,
'become'
,
'become_method'
,
'become_user'
,
'check'
,
'extra_vars'
,
]
)
results_callback_class
=
AdHocResultCallback
inventory_class
=
JMSInventory
loader_class
=
DataLoader
variable_manager_class
=
VariableManager
options
=
get_default_options
()
default_options
=
get_default_options
()
def
__init__
(
self
,
hosts
=
C
.
DEFAULT_HOST_LIST
,
forks
=
C
.
DEFAULT_FORKS
,
# 5
timeout
=
C
.
DEFAULT_TIMEOUT
,
# SSH timeout = 10s
remote_user
=
C
.
DEFAULT_REMOTE_USER
,
# root
module_path
=
None
,
# dirs of custome modules
connection_type
=
"smart"
,
become
=
None
,
become_method
=
None
,
become_user
=
None
,
check
=
False
,
passwords
=
None
,
extra_vars
=
None
,
private_key_file
=
None
,
gather_facts
=
'no'
):
def
__init__
(
self
,
hosts
,
options
=
None
):
if
options
:
self
.
options
=
options
self
.
pattern
=
''
self
.
variable_manager
=
VariableManager
()
self
.
loader
=
DataLoader
()
self
.
gather_facts
=
gather_facts
self
.
results_callback
=
AdHocRunner
.
results_callback_class
()
self
.
options
=
self
.
Options
(
connection
=
connection_type
,
timeout
=
timeout
,
module_path
=
module_path
,
forks
=
forks
,
become
=
become
,
become_method
=
become_method
,
become_user
=
become_user
,
check
=
check
,
remote_user
=
remote_user
,
extra_vars
=
extra_vars
or
[],
private_key_file
=
private_key_file
,
)
self
.
variable_manager
.
extra_vars
=
load_extra_vars
(
self
.
loader
,
options
=
self
.
options
)
self
.
variable_manager
.
options_vars
=
load_options_vars
(
self
.
options
)
self
.
passwords
=
passwords
or
{}
self
.
inventory
=
JMSInventory
(
hosts
)
self
.
variable_manager
.
set_inventory
(
self
.
inventory
)
self
.
tasks
=
[]
self
.
play_source
=
None
self
.
play
=
None
self
.
runner
=
None
self
.
inventory
=
self
.
inventory_class
(
hosts
)
self
.
variable_manager
=
VariableManager
(
loader
=
self
.
loader
,
inventory
=
self
.
inventory
)
@staticmethod
def
check_module_args
(
module_name
,
module_args
=
''
):
if
module_name
in
C
.
MODULE_REQUIRE_ARGS
and
not
module_args
:
err
=
"No argument passed to '
%
s' module."
%
module_name
print
(
err
)
return
False
return
True
raise
AnsibleError
(
err
)
def
check_pattern
(
self
,
pattern
):
if
not
self
.
inventory
.
list_hosts
(
"all"
):
raise
AnsibleError
(
"Inventory is empty."
)
if
not
self
.
inventory
.
list_hosts
(
pattern
):
raise
AnsibleError
(
"pattern:
%
s dose not match any hosts."
%
pattern
)
def
run
(
self
,
task
_tuple
,
pattern
=
'all'
,
task_name
=
'Ansible Ad-hoc
'
):
def
run
(
self
,
task
s
,
pattern
,
play_name
=
'Ansible Ad-hoc'
,
gather_facts
=
'no
'
):
"""
:param task
_tuple: (('shell', 'ls'), ('ping', ''))
:param pattern:
:param
task_name:
:param task
s: [{'action': {'module': 'shell', 'args': 'ls'}, ...}, ]
:param pattern:
all, *, or others
:param
play_name: The play name
:return:
"""
for
module
,
args
in
task_tuple
:
if
not
self
.
check_module_args
(
module
,
args
):
return
self
.
tasks
.
append
(
dict
(
action
=
dict
(
module
=
module
,
args
=
args
,
))
)
self
.
play_source
=
dict
(
name
=
task_name
,
results_callback
=
self
.
results_callback_class
()
clean_tasks
=
[]
for
task
in
tasks
:
self
.
check_module_args
(
task
[
'action'
][
'module'
],
task
[
'action'
]
.
get
(
'args'
))
clean_tasks
.
append
(
task
)
play_source
=
dict
(
name
=
play_name
,
hosts
=
pattern
,
gather_facts
=
self
.
gather_facts
,
tasks
=
self
.
tasks
gather_facts
=
gather_facts
,
tasks
=
clean_
tasks
)
self
.
play
=
Play
()
.
load
(
self
.
play_source
,
play
=
Play
()
.
load
(
play_source
,
variable_manager
=
self
.
variable_manager
,
loader
=
self
.
loader
,
)
self
.
runner
=
TaskQueueManager
(
tqm
=
TaskQueueManager
(
inventory
=
self
.
inventory
,
variable_manager
=
self
.
variable_manager
,
loader
=
self
.
loader
,
options
=
self
.
options
,
passwords
=
self
.
passwords
,
stdout_callback
=
self
.
results_callback
,
stdout_callback
=
results_callback
,
passwords
=
self
.
options
.
passwords
,
)
if
not
self
.
inventory
.
list_hosts
(
"all"
):
raise
AnsibleError
(
"Inventory is empty."
)
if
not
self
.
inventory
.
list_hosts
(
self
.
pattern
):
raise
AnsibleError
(
"pattern:
%
s dose not match any hosts."
%
self
.
pattern
)
try
:
self
.
runner
.
run
(
self
.
play
)
tqm
.
run
(
play
)
return
results_callback
except
Exception
as
e
:
logger
.
warning
(
e
)
else
:
logger
.
debug
(
self
.
results_callback
.
result_q
)
return
self
.
results_callback
.
result_q
raise
AnsibleError
(
e
)
finally
:
if
self
.
runner
:
self
.
runner
.
cleanup
()
if
self
.
loader
:
self
.
loader
.
cleanup_all_tmp_files
()
tqm
.
cleanup
()
self
.
loader
.
cleanup_all_tmp_files
()
def
clean_result
(
self
):
"""
:return: {
"success": ['hostname',],
"failed": [('hostname', 'msg'), {}],
}
"""
result
=
{
'success'
:
[],
'failed'
:
[]}
for
host
in
self
.
results_callback
.
result_q
[
'contacted'
]:
result
[
'success'
]
.
append
(
host
)
for
host
,
msgs
in
self
.
results_callback
.
result_q
[
'dark'
]
.
items
():
msg
=
'
\n
'
.
join
([
'{} {}: {}'
.
format
(
msg
.
get
(
'module_stdout'
,
''
),
msg
.
get
(
'invocation'
,
{})
.
get
(
'module_name'
),
msg
.
get
(
'msg'
,
''
))
for
msg
in
msgs
])
result
[
'failed'
]
.
append
((
host
,
msg
))
return
result
def
test_run
():
assets
=
[
{
"hostname"
:
"192.168.244.129"
,
"ip"
:
"192.168.244.129"
,
"port"
:
22
,
"username"
:
"root"
,
"password"
:
"redhat"
,
},
]
task_tuple
=
((
'shell'
,
'ls'
),)
hoc
=
AdHocRunner
(
hosts
=
assets
)
hoc
.
results_callback
=
CommandResultCallback
()
ret
=
hoc
.
run
(
task_tuple
)
print
(
ret
)
#play = PlayBookRunner(assets, playbook_path='/tmp/some.yml')
"""
# /tmp/some.yml
---
- name: Test the plabybook API.
hosts: all
remote_user: root
gather_facts: yes
tasks:
- name: exec uptime
shell: uptime
"""
#play.run()
class
CommandRunner
(
AdHocRunner
):
results_callback_class
=
CommandResultCallback
modules_choices
=
(
'shell'
,
'raw'
,
'command'
,
'script'
)
def
execute
(
self
,
cmd
,
pattern
,
module
=
None
):
if
module
and
module
not
in
self
.
modules_choices
:
raise
AnsibleError
(
"Module should in {}"
.
format
(
self
.
modules_choices
))
else
:
module
=
"shell"
tasks
=
[
{
"action"
:
{
"module"
:
module
,
"args"
:
cmd
}}
]
hosts
=
self
.
inventory
.
get_hosts
(
pattern
=
pattern
)
name
=
"Run command {} on {}"
.
format
(
cmd
,
", "
.
join
([
host
.
name
for
host
in
hosts
]))
return
self
.
run
(
tasks
,
pattern
,
play_name
=
name
)
if
__name__
==
"__main__"
:
test_run
()
apps/ops/ansible/test_inventory.py
0 → 100644
View file @
e57121a7
# -*- coding: utf-8 -*-
#
import
sys
import
unittest
sys
.
path
.
insert
(
0
,
'../..'
)
from
ops.ansible.inventory
import
JMSInventory
class
TestJMSInventory
(
unittest
.
TestCase
):
def
setUp
(
self
):
host_list
=
[{
"hostname"
:
"testserver1"
,
"ip"
:
"102.1.1.1"
,
"port"
:
22
,
"username"
:
"root"
,
"password"
:
"password"
,
"private_key"
:
"/tmp/private_key"
,
"become"
:
{
"method"
:
"sudo"
,
"user"
:
"root"
,
"pass"
:
None
,
},
"groups"
:
[
"group1"
,
"group2"
],
"vars"
:
{
"sexy"
:
"yes"
},
},
{
"hostname"
:
"testserver2"
,
"ip"
:
"8.8.8.8"
,
"port"
:
2222
,
"username"
:
"root"
,
"password"
:
"password"
,
"private_key"
:
"/tmp/private_key"
,
"become"
:
{
"method"
:
"su"
,
"user"
:
"root"
,
"pass"
:
"123"
,
},
"groups"
:
[
"group3"
,
"group4"
],
"vars"
:
{
"love"
:
"yes"
},
}]
self
.
inventory
=
JMSInventory
(
host_list
=
host_list
)
def
test_hosts
(
self
):
print
(
"#"
*
10
+
"Hosts"
+
"#"
*
10
)
for
host
in
self
.
inventory
.
hosts
:
print
(
host
)
def
test_groups
(
self
):
print
(
"#"
*
10
+
"Groups"
+
"#"
*
10
)
for
group
in
self
.
inventory
.
groups
:
print
(
group
)
def
test_group_all
(
self
):
print
(
"#"
*
10
+
"all group hosts"
+
"#"
*
10
)
group
=
self
.
inventory
.
get_group
(
'all'
)
print
(
group
.
hosts
)
if
__name__
==
'__main__'
:
unittest
.
main
()
apps/ops/ansible/test_runner.py
0 → 100644
View file @
e57121a7
# -*- coding: utf-8 -*-
#
import
unittest
import
sys
sys
.
path
.
insert
(
0
,
"../.."
)
from
ops.ansible.runner
import
AdHocRunner
,
CommandRunner
class
TestAdHocRunner
(
unittest
.
TestCase
):
def
setUp
(
self
):
host_data
=
[
{
"hostname"
:
"testserver"
,
"ip"
:
"192.168.244.168"
,
"port"
:
22
,
"username"
:
"root"
,
"password"
:
"redhat"
,
},
]
self
.
runner
=
AdHocRunner
(
hosts
=
host_data
)
def
test_run
(
self
):
tasks
=
[
{
"action"
:
{
"module"
:
"shell"
,
"args"
:
"ls"
}},
{
"action"
:
{
"module"
:
"shell"
,
"args"
:
"whoami"
}},
]
ret
=
self
.
runner
.
run
(
tasks
,
"all"
)
print
(
ret
.
results_summary
)
print
(
ret
.
results_raw
)
class
TestCommandRunner
(
unittest
.
TestCase
):
def
setUp
(
self
):
host_data
=
[
{
"hostname"
:
"testserver"
,
"ip"
:
"192.168.244.168"
,
"port"
:
22
,
"username"
:
"root"
,
"password"
:
"redhat"
,
},
]
self
.
runner
=
CommandRunner
(
hosts
=
host_data
)
def
test_execute
(
self
):
res
=
self
.
runner
.
execute
(
'ls'
,
'all'
)
print
(
res
.
results_command
)
if
__name__
==
"__main__"
:
unittest
.
main
()
apps/ops/api.py
View file @
e57121a7
...
...
@@ -4,12 +4,12 @@
from
rest_framework
import
viewsets
from
.hands
import
IsSuperUser
from
.models
import
Tas
k
from
.models
import
Playboo
k
from
.serializers
import
TaskSerializer
class
TaskViewSet
(
viewsets
.
ModelViewSet
):
queryset
=
Tas
k
.
objects
.
all
()
queryset
=
Playboo
k
.
objects
.
all
()
serializer_class
=
TaskSerializer
permission_classes
=
(
IsSuperUser
,)
apps/ops/models.py
View file @
e57121a7
...
...
@@ -7,40 +7,32 @@ import uuid
from
django.db
import
models
from
django.utils.translation
import
ugettext_lazy
as
_
from
assets.models
import
Asset
__all__
=
[
"
Tas
k"
]
__all__
=
[
"
Playboo
k"
]
logger
=
logging
.
getLogger
(
__name__
)
class
Task
(
models
.
Model
):
class
AdHoc
(
models
.
Model
):
uuid
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
name
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
verbose_name
=
_
(
'Name'
))
date_start
=
models
.
DateTimeField
(
auto_now_add
=
True
,
verbose_name
=
_
(
'Start time'
))
date_finished
=
models
.
DateTimeField
(
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'End time'
))
timedelta
=
models
.
FloatField
(
default
=
0.0
,
verbose_name
=
_
(
'Time'
),
null
=
True
)
is_finished
=
models
.
BooleanField
(
default
=
False
,
verbose_name
=
_
(
'Is finished'
))
is_success
=
models
.
BooleanField
(
default
=
False
,
verbose_name
=
_
(
'Is success'
))
assets
=
models
.
TextField
(
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Assets id'
))
# Asset inventory may be change
_modules_args
=
models
.
TextField
(
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Task module and args json format'
))
pattern
=
models
.
CharField
(
max_length
=
64
,
default
=
'all'
,
verbose_name
=
_
(
'Task run pattern'
))
result
=
models
.
TextField
(
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Task raw result'
))
summary
=
models
.
TextField
(
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Task summary'
))
tasks
=
models
.
TextField
(
verbose_name
=
_
(
'Tasks'
))
# [{'name': 'task_name', 'module': '', 'args': ''}, ]
hosts
=
models
.
TextField
(
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Hosts'
))
# Asset inventory may be change
pattern
=
models
.
CharField
(
max_length
=
64
,
default
=
'all'
,
verbose_name
=
_
(
'Playbook run pattern'
))
def
__
unicode
__
(
self
):
return
"
%
s"
%
self
.
uuid
def
__
str
__
(
self
):
return
"
%
s"
%
self
.
name
@property
def
total_assets
(
self
):
assets_id
=
[
i
for
i
in
self
.
assets
.
split
(
','
)
if
i
.
isdigit
(
)]
assets
=
Asset
.
objects
.
filter
(
id__in
=
assets_id
)
def
get_hosts_mapped_assets
(
self
):
from
assets.utils
import
get_assets_by_id_list
assets_id
=
[
i
for
i
in
self
.
hosts
.
split
(
','
)]
assets
=
get_assets_by_id_list
(
assets_id
)
return
assets
@property
def
assets_json
(
self
):
return
[
asset
.
_to_secret_json
()
for
asset
in
self
.
total_assets
]
def
inventory
(
self
):
return
[
asset
.
_to_secret_json
()
for
asset
in
self
.
get_hosts_mapped_assets
()
]
@property
def
module_args
(
self
):
...
...
@@ -57,3 +49,12 @@ class Task(models.Model):
self
.
_modules_args
=
json
.
dumps
(
module_args_
)
class
History
(
models
.
Model
):
uuid
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
date_start
=
models
.
DateTimeField
(
auto_now_add
=
True
,
verbose_name
=
_
(
'Start time'
))
date_finished
=
models
.
DateTimeField
(
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'End time'
))
timedelta
=
models
.
FloatField
(
default
=
0.0
,
verbose_name
=
_
(
'Time'
),
null
=
True
)
is_finished
=
models
.
BooleanField
(
default
=
False
,
verbose_name
=
_
(
'Is finished'
))
is_success
=
models
.
BooleanField
(
default
=
False
,
verbose_name
=
_
(
'Is success'
))
result
=
models
.
TextField
(
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Playbook raw result'
))
summary
=
models
.
TextField
(
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Playbook summary'
))
apps/ops/serializers.py
View file @
e57121a7
...
...
@@ -2,12 +2,12 @@
from
__future__
import
unicode_literals
from
rest_framework
import
serializers
from
.models
import
Tas
k
from
.models
import
Playboo
k
class
TaskSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
Tas
k
model
=
Playboo
k
fields
=
'__all__'
apps/ops/tasks.py
View file @
e57121a7
...
...
@@ -12,8 +12,8 @@ logger = get_logger(__file__)
@shared_task
def
rerun_task
(
task_id
):
from
.models
import
Tas
k
record
=
Tas
k
.
objects
.
get
(
uuid
=
task_id
)
from
.models
import
Playboo
k
record
=
Playboo
k
.
objects
.
get
(
uuid
=
task_id
)
assets
=
record
.
assets_json
task_tuple
=
record
.
module_args
pattern
=
record
.
pattern
...
...
apps/ops/utils.py
View file @
e57121a7
...
...
@@ -3,6 +3,7 @@
from
__future__
import
absolute_import
,
unicode_literals
import
json
import
re
import
time
import
uuid
...
...
@@ -41,16 +42,16 @@ def run_AdHoc(task_tuple, assets,
runner
=
AdHocRunner
(
assets
)
if
record
:
from
.models
import
Tas
k
if
not
Tas
k
.
objects
.
filter
(
uuid
=
task_id
):
record
=
Tas
k
(
uuid
=
task_id
,
name
=
task_name
,
assets
=
','
.
join
(
str
(
asset
[
'id'
])
for
asset
in
assets
),
module_args
=
task_tuple
,
pattern
=
pattern
)
from
.models
import
Playboo
k
if
not
Playboo
k
.
objects
.
filter
(
uuid
=
task_id
):
record
=
Playboo
k
(
uuid
=
task_id
,
name
=
task_name
,
assets
=
','
.
join
(
str
(
asset
[
'id'
])
for
asset
in
assets
),
module_args
=
task_tuple
,
pattern
=
pattern
)
record
.
save
()
else
:
record
=
Tas
k
.
objects
.
get
(
uuid
=
task_id
)
record
=
Playboo
k
.
objects
.
get
(
uuid
=
task_id
)
record
.
date_start
=
timezone
.
now
()
record
.
date_finished
=
None
record
.
timedelta
=
None
...
...
@@ -76,3 +77,14 @@ def run_AdHoc(task_tuple, assets,
record
.
is_success
=
False
record
.
save
()
return
summary
,
result
UUID_PATTERN
=
re
.
compile
(
r'[0-9a-zA-Z\-]{36}'
)
def
is_uuid
(
s
):
if
UUID_PATTERN
.
match
(
s
):
return
True
else
:
return
False
apps/ops/views.py
View file @
e57121a7
...
...
@@ -9,13 +9,13 @@ from django.views.generic import ListView, DetailView, View
from
django.utils
import
timezone
from
django.shortcuts
import
redirect
,
reverse
from
.models
import
Tas
k
from
.models
import
Playboo
k
from
ops.tasks
import
rerun_task
class
TaskListView
(
ListView
):
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
model
=
Tas
k
model
=
Playboo
k
ordering
=
(
'-date_start'
,)
context_object_name
=
'task_list'
template_name
=
'ops/task_list.html'
...
...
@@ -53,7 +53,7 @@ class TaskListView(ListView):
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'app'
:
'Ops'
,
'action'
:
'
Tas
k record list'
,
'action'
:
'
Playboo
k record list'
,
'date_from'
:
self
.
date_from_s
,
'date_to'
:
self
.
date_to_s
,
'keyword'
:
self
.
keyword
,
...
...
@@ -63,13 +63,13 @@ class TaskListView(ListView):
class
TaskDetailView
(
DetailView
):
model
=
Tas
k
model
=
Playboo
k
template_name
=
'ops/task_detail.html'
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'app'
:
'Ops'
,
'action'
:
'
Tas
k record detail'
,
'action'
:
'
Playboo
k record detail'
,
'results'
:
json
.
loads
(
self
.
object
.
summary
or
'{}'
),
}
kwargs
.
update
(
context
)
...
...
apps/templates/_nav.html
View file @
e57121a7
...
...
@@ -52,7 +52,7 @@
<i
class=
"fa fa-coffee"
></i>
<span
class=
"nav-label"
>
{% trans 'Job Center' %}
</span><span
class=
"fa arrow"
></span>
</a>
<ul
class=
"nav nav-second-level"
>
<li
id=
"task"
><a
href=
"{% url 'ops:task-list' %}"
>
{% trans '
Tas
k' %}
</a></li>
<li
id=
"task"
><a
href=
"{% url 'ops:task-list' %}"
>
{% trans '
Playboo
k' %}
</a></li>
</ul>
</li>
...
...
apps/terminal/models.py
View file @
e57121a7
...
...
@@ -113,7 +113,7 @@ class Task(models.Model):
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
name
=
models
.
CharField
(
max_length
=
128
,
choices
=
NAME_CHOICES
,
verbose_name
=
_
(
"Name"
))
args
=
models
.
CharField
(
max_length
=
1024
,
verbose_name
=
_
(
"
Tas
k Args"
))
args
=
models
.
CharField
(
max_length
=
1024
,
verbose_name
=
_
(
"
Playboo
k Args"
))
terminal
=
models
.
ForeignKey
(
Terminal
,
null
=
True
,
on_delete
=
models
.
CASCADE
)
is_finished
=
models
.
BooleanField
(
default
=
False
)
date_created
=
models
.
DateTimeField
(
auto_now_add
=
True
)
...
...
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