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
01e50d59
Commit
01e50d59
authored
8 years ago
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
完成AdHoc JMSHost JMSInventory
parent
0524e8dd
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
289 additions
and
823 deletions
+289
-823
asset.py
apps/assets/models/asset.py
+12
-0
user.py
apps/assets/models/user.py
+17
-2
serializers.py
apps/ops/api/serializers.py
+0
-61
views.py
apps/ops/api/views.py
+0
-72
__init__.py
apps/ops/models/__init__.py
+0
-2
cron.py
apps/ops/models/cron.py
+0
-62
sudo.py
apps/ops/models/sudo.py
+0
-322
utils.py
apps/ops/models/utils.py
+2
-4
api_urls.py
apps/ops/urls/api_urls.py
+2
-16
view_urls.py
apps/ops/urls/view_urls.py
+0
-12
ansible_api.py
apps/ops/utils/ansible_api.py
+255
-224
views.py
apps/ops/views.py
+1
-46
No files found.
apps/assets/models/asset.py
View file @
01e50d59
...
...
@@ -87,6 +87,18 @@ class Asset(models.Model):
def
to_json
(
self
):
pass
def
_to_secret_json
(
self
):
"""Ansible use it create inventory"""
return
{
'hostname'
:
self
.
hostname
,
'ip'
:
self
.
ip
,
'port'
:
self
.
port
,
'groups'
:
[
group
.
name
for
group
in
self
.
groups
.
all
()],
'username'
:
self
.
admin_user
.
username
,
'password'
:
self
.
admin_user
.
password
,
'private_key'
:
self
.
admin_user
.
private_key
,
}
class
Meta
:
unique_together
=
(
'ip'
,
'port'
)
...
...
This diff is collapsed.
Click to expand it.
apps/assets/models/user.py
View file @
01e50d59
...
...
@@ -9,7 +9,7 @@ import logging
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.core.exceptions
import
ValidationError
from
common.utils
import
signer
,
validate_ssh_private_key
from
common.utils
import
signer
,
validate_ssh_private_key
,
ssh_key_string_to_obj
__all__
=
[
'AdminUser'
,
'SystemUser'
,
'private_key_validator'
]
logger
=
logging
.
getLogger
(
__name__
)
...
...
@@ -24,12 +24,20 @@ def private_key_validator(value):
class
AdminUser
(
models
.
Model
):
BECOME_METHOD_CHOICES
=
(
(
'sudo'
,
'sudo'
),
(
'su'
,
'su'
),
)
name
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
'Name'
))
username
=
models
.
CharField
(
max_length
=
16
,
verbose_name
=
_
(
'Username'
))
_password
=
models
.
CharField
(
max_length
=
256
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Password'
))
_private_key
=
models
.
CharField
(
max_length
=
4096
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'SSH private key'
),
validators
=
[
private_key_validator
,])
_public_key
=
models
.
CharField
(
max_length
=
4096
,
blank
=
True
,
verbose_name
=
_
(
'SSH public key'
))
become
=
models
.
BooleanField
(
default
=
True
)
become_method
=
models
.
CharField
(
choices
=
BECOME_METHOD_CHOICES
,
default
=
'sudo'
,
max_length
=
4
)
become_user
=
models
.
CharField
(
default
=
'root'
,
max_length
=
64
)
become_password
=
models
.
CharField
(
default
=
''
,
max_length
=
128
)
comment
=
models
.
TextField
(
blank
=
True
,
verbose_name
=
_
(
'Comment'
))
date_created
=
models
.
DateTimeField
(
auto_now_add
=
True
,
null
=
True
)
created_by
=
models
.
CharField
(
max_length
=
32
,
null
=
True
,
verbose_name
=
_
(
'Created by'
))
...
...
@@ -41,7 +49,10 @@ class AdminUser(models.Model):
@property
def
password
(
self
):
if
self
.
_password
:
return
signer
.
unsign
(
self
.
_password
)
else
:
return
''
@password.setter
def
password
(
self
,
password_raw
):
...
...
@@ -49,7 +60,11 @@ class AdminUser(models.Model):
@property
def
private_key
(
self
):
return
signer
.
unsign
(
self
.
_private_key
)
if
self
.
_private_key
:
key_str
=
signer
.
unsign
(
self
.
_private_key
)
return
ssh_key_string_to_obj
(
key_str
)
else
:
return
None
@private_key.setter
def
private_key
(
self
,
private_key_raw
):
...
...
This diff is collapsed.
Click to expand it.
apps/ops/api/serializers.py
View file @
01e50d59
# ~*~ coding: utf-8 ~*~
from
__future__
import
unicode_literals
from
ops.models
import
*
from
rest_framework
import
serializers
class
HostAliaSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
HostAlia
class
CmdAliaSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
CmdAlia
class
UserAliaSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
UserAlia
class
RunasAliaSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
RunasAlia
class
ExtraconfSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
Extra_conf
class
PrivilegeSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
Privilege
class
SudoSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
Sudo
class
CronTableSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
CronTable
class
TaskSerializer
(
serializers
.
ModelSerializer
):
sub_tasks
=
serializers
.
PrimaryKeyRelatedField
(
many
=
True
,
read_only
=
True
)
class
Meta
:
model
=
Task
read_only_fields
=
(
'record'
,)
class
SubTaskSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
SubTask
This diff is collapsed.
Click to expand it.
apps/ops/api/views.py
View file @
01e50d59
...
...
@@ -5,75 +5,3 @@ from rest_framework import viewsets
from
serializers
import
*
from
permissions
import
*
__all__
=
[
"HostAliaViewSet"
,
"CmdAliaViewSet"
,
"UserAliaViewSet"
,
"RunasAliaViewSet"
,
"ExtraconfViewSet"
,
"PrivilegeViewSet"
,
"SudoViewSet"
,
"CronTableViewSet"
,
"TaskViewSet"
,
"SubTaskViewSet"
,
]
class
HostAliaViewSet
(
viewsets
.
ModelViewSet
):
queryset
=
HostAlia
.
objects
.
all
()
serializer_class
=
HostAliaSerializer
permission_classes
=
(
AdminUserRequired
,)
class
CmdAliaViewSet
(
viewsets
.
ModelViewSet
):
queryset
=
CmdAlia
.
objects
.
all
()
serializer_class
=
CmdAliaSerializer
permission_classes
=
(
AdminUserRequired
,)
class
UserAliaViewSet
(
viewsets
.
ModelViewSet
):
queryset
=
UserAlia
.
objects
.
all
()
serializer_class
=
UserAliaSerializer
permission_classes
=
(
AdminUserRequired
,)
class
RunasAliaViewSet
(
viewsets
.
ModelViewSet
):
queryset
=
RunasAlia
.
objects
.
all
()
serializer_class
=
RunasAliaSerializer
permission_classes
=
(
AdminUserRequired
,)
class
ExtraconfViewSet
(
viewsets
.
ModelViewSet
):
queryset
=
Extra_conf
.
objects
.
all
()
serializer_class
=
ExtraconfSerializer
permission_classes
=
(
AdminUserRequired
,)
class
PrivilegeViewSet
(
viewsets
.
ModelViewSet
):
queryset
=
Privilege
.
objects
.
all
()
serializer_class
=
PrivilegeSerializer
permission_classes
=
(
AdminUserRequired
,)
class
SudoViewSet
(
viewsets
.
ModelViewSet
):
queryset
=
Sudo
.
objects
.
all
()
serializer_class
=
SudoSerializer
permission_classes
=
(
AdminUserRequired
,)
class
CronTableViewSet
(
viewsets
.
ModelViewSet
):
queryset
=
CronTable
.
objects
.
all
()
serializer_class
=
CronTableSerializer
permission_classes
=
(
AdminUserRequired
,)
class
TaskViewSet
(
viewsets
.
ModelViewSet
):
queryset
=
Task
.
objects
.
all
()
serializer_class
=
TaskSerializer
permission_classes
=
(
AdminUserRequired
,)
class
SubTaskViewSet
(
viewsets
.
ModelViewSet
):
queryset
=
SubTask
.
objects
.
all
()
serializer_class
=
SubTaskSerializer
permission_classes
=
(
AdminUserRequired
,)
This diff is collapsed.
Click to expand it.
apps/ops/models/__init__.py
View file @
01e50d59
from
ansible
import
*
from
cron
import
*
from
sudo
import
*
from
utils
import
*
from
task
import
*
This diff is collapsed.
Click to expand it.
apps/ops/models/cron.py
deleted
100644 → 0
View file @
0524e8dd
# ~*~ coding: utf-8 ~*~
from
__future__
import
unicode_literals
,
absolute_import
import
logging
from
django.db
import
models
from
assets.models
import
Asset
from
django.utils.translation
import
ugettext_lazy
as
_
logger
=
logging
.
getLogger
(
__name__
)
__all__
=
[
"CronTable"
]
class
CronTable
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
null
=
True
,
unique
=
True
,
verbose_name
=
_
(
'Name'
),
help_text
=
_
(
"Description of a crontab entry"
))
month
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Month'
),
help_text
=
_
(
"Month of the year the job should run ( 1-12, *, */2, etc )"
))
weekday
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'WeekDay'
),
help_text
=
_
(
"Day of the week that the job should run"
" ( 0-6 for Sunday-Saturday, *, etc )"
))
day
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Day'
),
help_text
=
_
(
"Day of the month the job should run ( 1-31, *, */2, etc )"
))
hour
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Hour'
),
help_text
=
_
(
"Hour when the job should run ( 0-23, *, */2, etc )"
))
minute
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Minute'
),
help_text
=
_
(
"Minute when the job should run ( 0-59, *, */2, etc )"
))
job
=
models
.
CharField
(
max_length
=
4096
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Job'
),
help_text
=
_
(
"The command to execute or, if env is set, the value of "
"environment variable. Required if state=present."
))
user
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'User'
),
help_text
=
_
(
"The specific user whose crontab should be modified."
))
asset
=
models
.
ForeignKey
(
Asset
,
null
=
True
,
blank
=
True
,
related_name
=
'crontables'
)
@property
def
describe
(
self
):
return
"http://docs.ansible.com/ansible/cron_module.html"
@classmethod
def
generate_fake
(
cls
,
count
=
20
):
from
random
import
seed
,
choice
import
forgery_py
seed
()
for
i
in
range
(
count
):
cron
=
cls
(
name
=
forgery_py
.
name
.
full_name
(),
month
=
str
(
choice
(
range
(
1
,
13
))),
weekday
=
str
(
choice
(
range
(
0
,
7
))),
day
=
str
(
choice
(
range
(
1
,
32
))),
hour
=
str
(
choice
(
range
(
0
,
24
))),
minute
=
str
(
choice
(
range
(
0
,
60
))),
job
=
forgery_py
.
lorem_ipsum
.
sentence
(),
user
=
forgery_py
.
name
.
first_name
(),
)
try
:
cron
.
save
()
logger
.
debug
(
'Generate fake cron:
%
s'
%
cron
.
name
)
except
Exception
as
e
:
print
(
'Error:
%
s, continue...'
%
e
.
message
)
continue
\ No newline at end of file
This diff is collapsed.
Click to expand it.
apps/ops/models/sudo.py
deleted
100644 → 0
View file @
0524e8dd
# ~*~ coding: utf-8 ~*~
from
__future__
import
unicode_literals
,
absolute_import
import
logging
from
jinja2
import
Template
from
django.db
import
models
from
django.utils.timezone
import
now
from
assets.models
import
Asset
,
AssetGroup
from
django.utils.translation
import
ugettext_lazy
as
_
logger
=
logging
.
getLogger
(
__name__
)
__all__
=
[
"HostAlia"
,
"UserAlia"
,
"CmdAlia"
,
"RunasAlia"
,
"Privilege"
,
"Extra_conf"
,
"Sudo"
]
class
HostAlia
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
null
=
True
,
unique
=
True
,
verbose_name
=
_
(
'Host_Alias'
))
host_items
=
models
.
TextField
(
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Host_Items'
))
def
__unicode__
(
self
):
return
self
.
name
@classmethod
def
generate_fake
(
cls
,
count
=
20
):
from
random
import
seed
import
forgery_py
seed
()
for
i
in
range
(
count
):
hostA
=
cls
(
name
=
forgery_py
.
name
.
full_name
(),
host_items
=
forgery_py
.
lorem_ipsum
.
sentence
(),
)
try
:
hostA
.
save
()
logger
.
debug
(
'Generate fake host alia:
%
s'
%
hostA
.
name
)
except
Exception
as
e
:
print
(
'Error:
%
s, continue...'
%
e
.
message
)
continue
class
UserAlia
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
null
=
True
,
unique
=
True
,
verbose_name
=
_
(
'User_Alias'
))
user_items
=
models
.
TextField
(
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Host_Items'
))
def
__unicode__
(
self
):
return
self
.
name
@classmethod
def
generate_fake
(
cls
,
count
=
20
):
from
random
import
seed
import
forgery_py
seed
()
for
i
in
range
(
count
):
userA
=
cls
(
name
=
forgery_py
.
name
.
full_name
(),
user_items
=
forgery_py
.
lorem_ipsum
.
sentence
(),
)
try
:
userA
.
save
()
logger
.
debug
(
'Generate fake host alia:
%
s'
%
userA
.
name
)
except
Exception
as
e
:
print
(
'Error:
%
s, continue...'
%
e
.
message
)
continue
class
CmdAlia
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
null
=
True
,
unique
=
True
,
verbose_name
=
_
(
'Command_Alias'
))
cmd_items
=
models
.
TextField
(
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Host_Items'
))
def
__unicode__
(
self
):
return
self
.
name
@classmethod
def
generate_fake
(
cls
,
count
=
20
):
from
random
import
seed
import
forgery_py
seed
()
for
i
in
range
(
count
):
cmdA
=
cls
(
name
=
forgery_py
.
name
.
full_name
(),
cmd_items
=
forgery_py
.
lorem_ipsum
.
sentence
(),
)
try
:
cmdA
.
save
()
logger
.
debug
(
'Generate fake command alia:
%
s'
%
cmdA
.
name
)
except
Exception
as
e
:
print
(
'Error:
%
s, continue...'
%
e
.
message
)
continue
class
RunasAlia
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
null
=
True
,
unique
=
True
,
verbose_name
=
_
(
'Runas_Alias'
))
runas_items
=
models
.
TextField
(
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Host_Items'
))
def
__unicode__
(
self
):
return
self
.
name
@classmethod
def
generate_fake
(
cls
,
count
=
20
):
from
random
import
seed
import
forgery_py
seed
()
for
i
in
range
(
count
):
runas
=
cls
(
name
=
forgery_py
.
name
.
full_name
(),
runas_items
=
forgery_py
.
lorem_ipsum
.
sentence
(),
)
try
:
runas
.
save
()
logger
.
debug
(
'Generate fake RunAs alia:
%
s'
%
runas
.
name
)
except
Exception
as
e
:
print
(
'Error:
%
s, continue...'
%
e
.
message
)
continue
class
Privilege
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
'Name'
))
user
=
models
.
ForeignKey
(
UserAlia
,
blank
=
True
,
null
=
True
,
related_name
=
'privileges'
)
host
=
models
.
ForeignKey
(
HostAlia
,
blank
=
True
,
null
=
True
,
related_name
=
'privileges'
)
runas
=
models
.
ForeignKey
(
RunasAlia
,
blank
=
True
,
null
=
True
,
related_name
=
'privileges'
)
command
=
models
.
ForeignKey
(
CmdAlia
,
blank
=
True
,
null
=
True
,
related_name
=
'privileges'
)
nopassword
=
models
.
BooleanField
(
default
=
True
,
verbose_name
=
_
(
'Is_NoPassword'
))
comment
=
models
.
TextField
(
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Comment'
))
def
__unicode__
(
self
):
return
"[
%
s
%
s
%
s
%
s
%
s]"
%
(
self
.
user
.
name
,
self
.
host
.
name
,
self
.
runas
.
name
,
self
.
command
.
name
,
self
.
nopassword
)
def
to_tuple
(
self
):
return
self
.
user
.
name
,
self
.
host
.
name
,
self
.
runas
.
name
,
self
.
command
.
name
,
self
.
nopassword
@classmethod
def
generate_fake
(
cls
,
count
=
20
):
from
random
import
seed
,
choice
import
forgery_py
seed
()
for
i
in
range
(
count
):
pri
=
cls
(
name
=
forgery_py
.
name
.
full_name
(),
comment
=
forgery_py
.
lorem_ipsum
.
sentence
(),
)
try
:
pri
.
user
=
choice
(
UserAlia
.
objects
.
all
())
pri
.
host
=
choice
(
HostAlia
.
objects
.
all
())
pri
.
runas
=
choice
(
RunasAlia
.
objects
.
all
())
pri
.
command
=
choice
(
CmdAlia
.
objects
.
all
())
pri
.
save
()
logger
.
debug
(
'Generate fake privileges:
%
s'
%
pri
.
name
)
except
Exception
as
e
:
print
(
'Error:
%
s, continue...'
%
e
.
message
)
continue
class
Extra_conf
(
models
.
Model
):
line
=
models
.
TextField
(
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Extra_Item'
),
help_text
=
_
(
'The extra sudo config line.'
))
def
__unicode__
(
self
):
return
self
.
line
class
Sudo
(
models
.
Model
):
"""
Sudo配置文件对象, 用于配置sudo的配置文件
:param extra_lines: <list> [<line1>, <line2>,...]
:param privileges: <list> [(user, host, runas, command, nopassword),]
"""
name
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
'Name'
),
help_text
=
_
(
'Name for this sudo'
))
created_time
=
models
.
DateTimeField
(
verbose_name
=
_
(
'Created Time'
),
auto_created
=
True
,
help_text
=
_
(
'The create time of this sudo'
))
modify_time
=
models
.
DateTimeField
(
auto_now
=
True
,
verbose_name
=
_
(
'Modify Time'
),
help_text
=
_
(
'The recent modify time of this sudo'
))
assets
=
models
.
ManyToManyField
(
Asset
,
blank
=
True
,
related_name
=
'sudos'
)
asset_groups
=
models
.
ManyToManyField
(
AssetGroup
,
blank
=
True
,
related_name
=
'sudos'
)
extra_lines
=
models
.
ManyToManyField
(
Extra_conf
,
related_name
=
'sudos'
,
blank
=
True
)
privilege_items
=
models
.
ManyToManyField
(
Privilege
,
related_name
=
'sudos'
,
blank
=
True
)
@property
def
all_assets
(
self
):
assets
=
list
(
self
.
assets
.
all
())
for
group
in
self
.
asset_groups
.
all
():
for
asset
in
group
.
assets
.
all
():
if
asset
not
in
assets
:
assets
.
append
(
asset
)
return
assets
@property
def
users
(
self
):
return
{
privilege
.
user
.
name
:
privilege
.
user
.
user_items
.
split
(
','
)
for
privilege
in
self
.
privilege_items
.
all
()}
@property
def
commands
(
self
):
return
{
privilege
.
command
.
name
:
privilege
.
command
.
cmd_items
.
split
(
','
)
for
privilege
in
self
.
privilege_items
.
all
()}
@property
def
hosts
(
self
):
return
{
privilege
.
host
.
name
:
privilege
.
host
.
host_items
.
split
(
','
)
for
privilege
in
self
.
privilege_items
.
all
()}
@property
def
runas
(
self
):
return
{
privilege
.
runas
.
name
:
privilege
.
runas
.
runas_items
.
split
(
','
)
for
privilege
in
self
.
privilege_items
.
all
()}
@property
def
extras
(
self
):
return
[
extra
.
line
for
extra
in
self
.
extra_lines
.
all
()]
@property
def
privileges
(
self
):
return
[
privilege
.
to_tuple
()
for
privilege
in
self
.
privilege_items
.
all
()]
@property
def
content
(
self
):
template
=
Template
(
self
.
__sudoers_jinja2_tmp__
)
context
=
{
"User_Alias"
:
self
.
users
,
"Cmnd_Alias"
:
self
.
commands
,
"Host_Alias"
:
self
.
hosts
,
"Runas_Alias"
:
self
.
runas
,
"Extra_Lines"
:
self
.
extras
,
"Privileges"
:
self
.
privileges
}
return
template
.
render
(
context
)
@property
def
__sudoers_jinja2_tmp__
(
self
):
return
"""# management by JumpServer
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
Defaults env_reset
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
# JumpServer Generate Other Configure is here
{
%
if Extra_Lines -
%
}
{
%
for line in Extra_Lines -
%
}
{{ line }}
{
%
endfor
%
}
{
%-
endif
%
}
# Host alias specification
{
%
if Host_Alias -
%
}
{
%
for flag, items in Host_Alias.iteritems() -
%
}
Host_Alias {{ flag }} = {{ items|join(', ') }}
{
%
endfor
%
}
{
%-
endif
%
}
# User alias specification
{
%
if User_Alias -
%
}
{
%
for flag, items in User_Alias.iteritems() -
%
}
User_Alias {{ flag }} = {{ items|join(', ') }}
{
%
endfor
%
}
{
%-
endif
%
}
# Cmnd alias specification
{
%
if Cmnd_Alias -
%
}
{
%
for flag, items in Cmnd_Alias.iteritems() -
%
}
Cmnd_Alias {{ flag }} = {{ items|join(', ') }}
{
%
endfor
%
}
{
%-
endif
%
}
# Run as alias specification
{
%
if Runas_Alias -
%
}
{
%
for flag, items in Runas_Alias.iteritems() -
%
}
Runas_Alias {{ flag }} = {{ items|join(', ') }}
{
%
endfor
%
}
{
%-
endif
%
}
# User privilege specification
root ALL=(ALL:ALL) ALL
# JumpServer Generate User privilege is here.
# Note privileges is a tuple list like [(user, host, runas, command, nopassword),]
{
%
if Privileges -
%
}
{
%
for User_Flag, Host_Flag, Runas_Flag, Command_Flag, NopassWord in Privileges -
%
}
{
%
if NopassWord -
%
}
{{ User_Flag }} {{ Host_Flag }}=({{ Runas_Flag }}) NOPASSWD: {{ Command_Flag }}
{
%-
else -
%
}
{{ User_Flag }} {{ Host_Flag }}=({{ Runas_Flag }}) {{ Command_Flag }}
{
%-
endif
%
}
{
%
endfor
%
}
{
%-
endif
%
}
# Members of the admin group may gain root privileges
%
admin ALL=(ALL) ALL
# Allow members of group sudo to execute any command
%
sudo ALL=(ALL:ALL) ALL
# See sudoers(5) for more information on "#include" directives:
#includedir /etc/sudoers.d
"""
@classmethod
def
generate_fake
(
cls
,
count
=
20
):
from
random
import
seed
,
choice
import
forgery_py
seed
()
for
i
in
range
(
count
):
sudo
=
cls
(
name
=
forgery_py
.
name
.
full_name
(),
created_time
=
now
()
)
try
:
sudo
.
save
()
sudo
.
privilege_items
=
[
choice
(
Privilege
.
objects
.
all
())]
sudo
.
save
()
logger
.
debug
(
'Generate fake cron:
%
s'
%
sudo
.
name
)
except
Exception
as
e
:
print
(
'Error:
%
s, continue...'
%
e
.
message
)
continue
\ No newline at end of file
This diff is collapsed.
Click to expand it.
apps/ops/models/utils.py
View file @
01e50d59
...
...
@@ -2,13 +2,10 @@
from
__future__
import
unicode_literals
from
ansible
import
*
from
cron
import
*
from
sudo
import
*
__all__
=
[
"generate_fake"
]
def
generate_fake
():
for
cls
in
(
TaskRecord
,
AnsiblePlay
,
AnsibleTask
,
AnsibleHostResult
,
CronTable
,
HostAlia
,
UserAlia
,
CmdAlia
,
RunasAlia
,
Privilege
,
Sudo
):
for
cls
in
(
TaskRecord
,
AnsiblePlay
,
AnsibleTask
,
AnsibleHostResult
):
cls
.
generate_fake
()
\ No newline at end of file
This diff is collapsed.
Click to expand it.
apps/ops/urls/api_urls.py
View file @
01e50d59
...
...
@@ -2,20 +2,6 @@
from
__future__
import
unicode_literals
from
rest_framework.routers
import
DefaultRouter
from
ops
import
api
as
v1_api
__all__
=
[
"urlpatterns"
]
api_router
=
DefaultRouter
()
api_router
.
register
(
r'v1/host_alia'
,
v1_api
.
HostAliaViewSet
)
api_router
.
register
(
r'v1/user_alia'
,
v1_api
.
UserAliaViewSet
)
api_router
.
register
(
r'v1/cmd_alia'
,
v1_api
.
CmdAliaViewSet
)
api_router
.
register
(
r'v1/runas_alia'
,
v1_api
.
RunasAliaViewSet
)
api_router
.
register
(
r'v1/extra_conf'
,
v1_api
.
ExtraconfViewSet
)
api_router
.
register
(
r'v1/privilege'
,
v1_api
.
PrivilegeViewSet
)
api_router
.
register
(
r'v1/sudo'
,
v1_api
.
SudoViewSet
)
api_router
.
register
(
r'v1/cron'
,
v1_api
.
CronTableViewSet
)
api_router
.
register
(
r'v1/task'
,
v1_api
.
TaskViewSet
)
api_router
.
register
(
r'v1/subtask'
,
v1_api
.
SubTaskViewSet
)
urlpatterns
=
api_router
.
urls
\ No newline at end of file
urlpatterns
=
[]
\ No newline at end of file
This diff is collapsed.
Click to expand it.
apps/ops/urls/view_urls.py
View file @
01e50d59
...
...
@@ -8,18 +8,6 @@ from ops import views as page_view
__all__
=
[
"urlpatterns"
]
urlpatterns
=
[
# Resource Sudo url
url
(
r'^sudo/list$'
,
page_view
.
SudoListView
.
as_view
(),
name
=
'page-sudo-list'
),
url
(
r'^sudo/create$'
,
page_view
.
SudoCreateView
.
as_view
(),
name
=
'page-sudo-create'
),
url
(
r'^sudo/(?P<pk>[0-9]+)/detail$'
,
page_view
.
SudoDetailView
.
as_view
(),
name
=
'page-sudo-detail'
),
url
(
r'^sudo/(?P<pk>[0-9]+)/update$'
,
page_view
.
SudoUpdateView
.
as_view
(),
name
=
'page-sudo-update'
),
# Resource Cron url
url
(
r'^cron/list$'
,
page_view
.
CronListView
.
as_view
(),
name
=
'page-cron-list'
),
url
(
r'^cron/create$'
,
page_view
.
CronCreateView
.
as_view
(),
name
=
'page-cron-create'
),
url
(
r'^cron/(?P<pk>[0-9]+)/detail$'
,
page_view
.
CronDetailView
.
as_view
(),
name
=
'page-cron-detail'
),
url
(
r'^cron/(?P<pk>[0-9]+)/update$'
,
page_view
.
CronUpdateView
.
as_view
(),
name
=
'page-cron-update'
),
# TResource Task url
url
(
r'^task/list$'
,
page_view
.
TaskListView
.
as_view
(),
name
=
'page-task-list'
),
url
(
r'^task/create$'
,
page_view
.
TaskCreateView
.
as_view
(),
name
=
'page-task-create'
),
...
...
This diff is collapsed.
Click to expand it.
apps/ops/utils/ansible_api.py
View file @
01e50d59
# ~*~ coding: utf-8 ~*~
from
__future__
import
unicode_literals
,
print_function
#
from __future__ import unicode_literals, print_function
import
os
import
json
import
logging
import
traceback
import
ansible.constants
as
default_config
from
collections
import
namedtuple
from
uuid
import
uuid4
from
django.utils
import
timezone
...
...
@@ -17,11 +18,15 @@ from ansible.executor import playbook_executor
from
ansible.utils.display
import
Display
from
ansible.playbook.play
import
Play
from
ansible.plugins.callback
import
CallbackBase
import
ansible.constants
as
C
from
ansible.utils.vars
import
load_extra_vars
from
ansible.utils.vars
import
load_options_vars
from
ops
.models
import
TaskRecord
,
AnsiblePlay
,
AnsibleTask
,
AnsibleHostResult
from
.
.models
import
TaskRecord
,
AnsiblePlay
,
AnsibleTask
,
AnsibleHostResult
__all__
=
[
"ADHocRunner"
,
"Options"
]
C
.
HOST_KEY_CHECKING
=
False
logger
=
logging
.
getLogger
(
__name__
)
...
...
@@ -30,149 +35,187 @@ class AnsibleError(StandardError):
pass
class
Options
(
object
):
"""Ansible运行时配置类, 用于初始化Ansible的一些默认配置.
"""
def
__init__
(
self
,
verbosity
=
None
,
inventory
=
None
,
listhosts
=
None
,
subset
=
None
,
module_paths
=
None
,
extra_vars
=
None
,
forks
=
10
,
ask_vault_pass
=
False
,
vault_password_files
=
None
,
new_vault_password_file
=
None
,
output_file
=
None
,
tags
=
None
,
skip_tags
=
None
,
one_line
=
None
,
tree
=
None
,
ask_sudo_pass
=
False
,
ask_su_pass
=
False
,
sudo
=
None
,
sudo_user
=
None
,
become
=
None
,
become_method
=
None
,
become_user
=
None
,
become_ask_pass
=
False
,
ask_pass
=
False
,
private_key_file
=
None
,
remote_user
=
None
,
connection
=
"smart"
,
timeout
=
10
,
ssh_common_args
=
None
,
sftp_extra_args
=
None
,
scp_extra_args
=
None
,
ssh_extra_args
=
None
,
poll_interval
=
None
,
seconds
=
None
,
check
=
False
,
syntax
=
None
,
diff
=
None
,
force_handlers
=
None
,
flush_cache
=
None
,
listtasks
=
None
,
listtags
=
None
,
module_path
=
None
):
self
.
verbosity
=
verbosity
self
.
inventory
=
inventory
self
.
listhosts
=
listhosts
self
.
subset
=
subset
self
.
module_paths
=
module_paths
self
.
extra_vars
=
extra_vars
self
.
forks
=
forks
self
.
ask_vault_pass
=
ask_vault_pass
self
.
vault_password_files
=
vault_password_files
self
.
new_vault_password_file
=
new_vault_password_file
self
.
output_file
=
output_file
self
.
tags
=
tags
self
.
skip_tags
=
skip_tags
self
.
one_line
=
one_line
self
.
tree
=
tree
self
.
ask_sudo_pass
=
ask_sudo_pass
self
.
ask_su_pass
=
ask_su_pass
self
.
sudo
=
sudo
self
.
sudo_user
=
sudo_user
self
.
become
=
become
self
.
become_method
=
become_method
self
.
become_user
=
become_user
self
.
become_ask_pass
=
become_ask_pass
self
.
ask_pass
=
ask_pass
self
.
private_key_file
=
private_key_file
self
.
remote_user
=
remote_user
self
.
connection
=
connection
self
.
timeout
=
timeout
self
.
ssh_common_args
=
ssh_common_args
self
.
sftp_extra_args
=
sftp_extra_args
self
.
scp_extra_args
=
scp_extra_args
self
.
ssh_extra_args
=
ssh_extra_args
self
.
poll_interval
=
poll_interval
self
.
seconds
=
seconds
self
.
check
=
check
self
.
syntax
=
syntax
self
.
diff
=
diff
self
.
force_handlers
=
force_handlers
self
.
flush_cache
=
flush_cache
self
.
listtasks
=
listtasks
self
.
listtags
=
listtags
self
.
module_path
=
module_path
self
.
__overwrite_default
()
def
__overwrite_default
(
self
):
"""上面并不能包含Ansible所有的配置, 如果有其他的配置,
可以通过替换default_config模块里面的变量进行重载,
比如 default_config.DEFAULT_ASK_PASS = False.
"""
default_config
.
HOST_KEY_CHECKING
=
False
# class Options(object):
# """Ansible运行时配置类, 用于初始化Ansible的一些默认配置.
# """
# def __init__(self, verbosity=None, inventory=None, listhosts=None, subset=None, module_paths=None, extra_vars=None,
# forks=10, ask_vault_pass=False, vault_password_files=None, new_vault_password_file=None,
# output_file=None, tags=None, skip_tags=None, one_line=None, tree=None, ask_sudo_pass=False, ask_su_pass=False,
# sudo=None, sudo_user=None, become=None, become_method=None, become_user=None, become_ask_pass=False,
# ask_pass=False, private_key_file=None, remote_user=None, connection="smart", timeout=10, ssh_common_args=None,
# sftp_extra_args=None, scp_extra_args=None, ssh_extra_args=None, poll_interval=None, seconds=None, check=False,
# syntax=None, diff=None, force_handlers=None, flush_cache=None, listtasks=None, listtags=None, module_path=None):
# self.verbosity = verbosity
# self.inventory = inventory
# self.listhosts = listhosts
# self.subset = subset
# self.module_paths = module_paths
# self.extra_vars = extra_vars
# self.forks = forks
# self.ask_vault_pass = ask_vault_pass
# self.vault_password_files = vault_password_files
# self.new_vault_password_file = new_vault_password_file
# self.output_file = output_file
# self.tags = tags
# self.skip_tags = skip_tags
# self.one_line = one_line
# self.tree = tree
# self.ask_sudo_pass = ask_sudo_pass
# self.ask_su_pass = ask_su_pass
# self.sudo = sudo
# self.sudo_user = sudo_user
# self.become = become
# self.become_method = become_method
# self.become_user = become_user
# self.become_ask_pass = become_ask_pass
# self.ask_pass = ask_pass
# self.private_key_file = private_key_file
# self.remote_user = remote_user
# self.connection = connection
# self.timeout = timeout
# self.ssh_common_args = ssh_common_args
# self.sftp_extra_args = sftp_extra_args
# self.scp_extra_args = scp_extra_args
# self.ssh_extra_args = ssh_extra_args
# self.poll_interval = poll_interval
# self.seconds = seconds
# self.check = check
# self.syntax = syntax
# self.diff = diff
# self.force_handlers = force_handlers
# self.flush_cache = flush_cache
# self.listtasks = listtasks
# self.listtags = listtags
# self.module_path = module_path
# self.__overwrite_default()
#
# def __overwrite_default(self):
# """上面并不能包含Ansible所有的配置, 如果有其他的配置,
# 可以通过替换default_config模块里面的变量进行重载,
# 比如 default_config.DEFAULT_ASK_PASS = False.
# """
# default_config.HOST_KEY_CHECKING = False
Options
=
namedtuple
(
"Options"
,
[
'connection'
,
'module_path'
,
'private_key_file'
,
"remote_user"
,
"timeout"
,
'forks'
,
'become'
,
'become_method'
,
'become_user'
,
'check'
,
"extra_vars"
,
]
)
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
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'
])
# 添加密码和秘钥
if
asset
.
get
(
'password'
):
self
.
set_variable
(
'ansible_ssh_pass'
,
asset
[
'password'
])
if
asset
.
get
(
'key'
):
self
.
set_variable
(
'ansible_ssh_private_key_file'
,
asset
[
'private_key'
])
class
InventoryMixin
(
object
):
# 添加become支持
become
=
asset
.
get
(
"become"
,
None
)
if
become
is
not
None
:
self
.
set_variable
(
"ansible_become"
,
True
)
self
.
set_variable
(
"ansible_become_method"
,
become
.
get
(
'method'
))
self
.
set_variable
(
"ansible_become_user"
,
become
.
get
(
'user'
))
self
.
set_variable
(
"ansible_become_pass"
,
become
.
get
(
'pass'
))
else
:
self
.
set_variable
(
"ansible_become"
,
False
)
class
JMSInventory
(
Inventory
):
"""
提供生成Ansible inventory对象的方法
"""
def
gen_inventory
(
self
):
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
()
super
(
JMSInventory
,
self
)
.
__init__
(
self
.
loader
,
self
.
variable_manager
,
host_list
=
host_list
)
def
parse_inventory
(
self
,
host_list
):
"""用于生成动态构建Ansible Inventory.
self.hosts: [
{"host": <ip>,
self.host_list: [
{"name": "asset_name",
"ip": <ip>,
"port": <port>,
"user": <user>,
"pass": <pass>,
"key": <sshKey>,
"group": <default>
"groups": ['group1', 'group2'],
"other_host_var": <other>},
{...},
]
self.group_vars: {
"groupName1": {"var1": <value>, "var2": <value>, ...},
"groupName2": {"var1": <value>, "var2": <value>, ...},
}
:return: 返回一个Ansible的inventory对象
"""
# TODO: 验证输入
# 创建Ansible Group,如果没有则创建default组
for
asset
in
self
.
hosts
:
g_name
=
asset
.
get
(
'group'
,
'default'
)
if
g_name
not
in
[
g
.
name
for
g
in
self
.
groups
]:
group
=
Group
(
name
=
g_name
)
self
.
groups
.
append
(
group
)
# 添加组变量到相应的组上
for
group_name
,
variables
in
self
.
group_vars
.
iteritems
():
for
g
in
self
.
groups
:
if
g
.
name
==
group_name
:
for
v_name
,
v_value
in
variables
.
iteritems
():
g
.
set_variable
(
v_name
,
v_value
)
# 往组里面添加Host
for
asset
in
self
.
hosts
:
# 添加Host链接的常用变量(host,port,user,pass,key)
host
=
Host
(
name
=
asset
[
'name'
],
port
=
asset
[
'port'
])
host
.
set_variable
(
'ansible_host'
,
asset
[
'ip'
])
host
.
set_variable
(
'ansible_port'
,
asset
[
'port'
])
host
.
set_variable
(
'ansible_user'
,
asset
[
'username'
])
ungrouped
=
Group
(
'ungrouped'
)
all
=
Group
(
'all'
)
all
.
add_child_group
(
ungrouped
)
self
.
groups
=
dict
(
all
=
all
,
ungrouped
=
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
:
group
=
Group
(
group_name
)
self
.
groups
[
group_name
]
=
group
else
:
group
=
self
.
groups
[
group_name
]
group
.
add_host
(
host
)
else
:
ungrouped
.
add_host
(
host
)
all
.
add_host
(
host
)
# 添加密码和秘钥
if
asset
.
get
(
'password'
):
host
.
set_variable
(
'ansible_ssh_pass'
,
asset
[
'password'
])
if
asset
.
get
(
'key'
):
host
.
set_variable
(
'ansible_ssh_private_key_file'
,
asset
[
'key'
])
# 添加become支持
become
=
asset
.
get
(
"become"
,
None
)
if
become
is
not
None
:
host
.
set_variable
(
"ansible_become"
,
True
)
host
.
set_variable
(
"ansible_become_method"
,
become
.
get
(
'method'
))
host
.
set_variable
(
"ansible_become_user"
,
become
.
get
(
'user'
))
host
.
set_variable
(
"ansible_become_pass"
,
become
.
get
(
'pass'
))
else
:
host
.
set_variable
(
"ansible_become"
,
False
)
class
BasicResultCallback
(
CallbackBase
):
"""
Custom Callback
"""
def
__init__
(
self
,
display
=
None
):
self
.
result_q
=
dict
(
contacted
=
{},
dark
=
{})
super
(
BasicResultCallback
,
self
)
.
__init__
(
display
)
# 添加其他Host的额外变量
for
key
,
value
in
asset
.
iteritems
():
if
key
not
in
[
"name"
,
"port"
,
"ip"
,
"username"
,
"password"
,
"key"
]:
host
.
set_variable
(
key
,
value
)
def
gather_result
(
self
,
n
,
res
):
self
.
result_q
[
n
]
.
update
({
res
.
_host
.
name
:
res
.
_result
})
# 将host添加到组里面
for
g
in
self
.
groups
:
if
g
.
name
==
asset
.
get
(
'group'
,
'default'
):
g
.
add_host
(
host
)
def
v2_runner_on_ok
(
self
,
result
):
self
.
gather_result
(
"contacted"
,
result
)
# 将组添加到Inventory里面,生成真正的inventory对象
inventory
=
Inventory
(
loader
=
self
.
loader
,
variable_manager
=
self
.
variable_manager
,
host_list
=
[])
for
g
in
self
.
groups
:
inventory
.
add_group
(
g
)
self
.
variable_manager
.
set_inventory
(
inventory
)
return
inventory
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
)
def
v2_playbook_on_task_start
(
self
,
task
,
is_conditional
):
pass
def
v2_playbook_on_play_start
(
self
,
play
):
pass
class
CallbackModule
(
CallbackBase
):
...
...
@@ -310,7 +353,7 @@ class CallbackModule(CallbackBase):
print
(
"summary:
%
s"
,
summary
)
class
PlayBookRunner
(
InventoryMixin
):
class
PlayBookRunner
(
object
):
"""用于执行AnsiblePlaybook的接口.简化Playbook对象的使用.
"""
...
...
@@ -393,133 +436,121 @@ class PlayBookRunner(InventoryMixin):
return
stats
class
ADHocRunner
(
InventoryMixin
):
class
ADHocRunner
(
object
):
"""
ADHoc接口
"""
def
__init__
(
self
,
play_data
,
config
=
None
,
*
hosts
,
**
group_vars
):
"""
:param hosts: 见PlaybookRunner参数
:param group_vars: 见PlaybookRunner参数
:param config: Config实例
:param play_data:
play_data = dict(
name="Ansible Ad-Hoc",
hosts=pattern,
gather_facts=True,
tasks=[dict(action=dict(module='service', args={'name': 'vsftpd', 'state': 'restarted'}), async=async, poll=poll)]
)
"""
self
.
options
=
config
if
config
!=
None
else
Options
()
# 设置verbosity级别, 及命令行的--verbose选项
self
.
display
=
Display
()
self
.
display
.
verbosity
=
self
.
options
.
verbosity
# sudo的配置移到了Host级别去了,因此这里不再需要处理
self
.
passwords
=
None
# 生成Ansible inventory, 这些变量Mixin都会用到
self
.
hosts
=
hosts
self
.
group_vars
=
group_vars
self
.
loader
=
DataLoader
()
def
__init__
(
self
,
hosts
=
C
.
DEFAULT_HOST_LIST
,
module_name
=
C
.
DEFAULT_MODULE_NAME
,
# * command
module_args
=
C
.
DEFAULT_MODULE_ARGS
,
# * 'cmd args'
forks
=
C
.
DEFAULT_FORKS
,
# 5
timeout
=
C
.
DEFAULT_TIMEOUT
,
# SSH timeout = 10s
pattern
=
"all"
,
# all
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'
):
self
.
pattern
=
pattern
self
.
variable_manager
=
VariableManager
()
self
.
groups
=
[]
self
.
inventory
=
self
.
gen_inventory
()
self
.
play
=
Play
()
.
load
(
play_data
,
variable_manager
=
self
.
variable_manager
,
loader
=
self
.
loader
)
@staticmethod
def
update_db_tasker
(
tasker_id
,
ext_code
):
try
:
tasker
=
TaskRecord
.
objects
.
get
(
uuid
=
tasker_id
)
tasker
.
end
=
timezone
.
now
()
tasker
.
completed
=
True
tasker
.
exit_code
=
ext_code
tasker
.
save
()
except
Exception
as
e
:
logger
.
error
(
"Update Tasker Status into database error!,
%
s"
%
e
.
message
)
def
create_db_tasker
(
self
,
name
,
uuid
):
try
:
hosts
=
[
host
.
get
(
'name'
)
for
host
in
self
.
hosts
]
tasker
=
TaskRecord
(
name
=
name
,
uuid
=
uuid
,
hosts
=
','
.
join
(
hosts
),
start
=
timezone
.
now
())
tasker
.
save
()
except
Exception
as
e
:
logger
.
error
(
"Save Tasker to database error!,
%
s"
%
e
.
message
)
def
run
(
self
,
tasker_name
,
tasker_uuid
):
"""执行ADHoc, 执行完后, 修改AnsiblePlay的状态为完成状态.
self
.
loader
=
DataLoader
()
self
.
module_name
=
module_name
self
.
module_args
=
module_args
self
.
check_module_args
()
self
.
gather_facts
=
gather_facts
self
.
results_callback
=
BasicResultCallback
()
self
.
options
=
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
,
)
:param tasker_uuid <str> 用于标示此次task
"""
# 初始化callback插件,以及Tasker
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
.
play_source
=
dict
(
name
=
'Ansible Ad-hoc'
,
hosts
=
self
.
pattern
,
gather_facts
=
self
.
gather_facts
,
tasks
=
[
dict
(
action
=
dict
(
module
=
self
.
module_name
,
args
=
self
.
module_args
))]
)
self
.
create_db_tasker
(
tasker_name
,
tasker_uuid
)
self
.
results_callback
=
CallbackModule
(
tasker_uuid
)
self
.
play
=
Play
()
.
load
(
self
.
play_source
,
variable_manager
=
self
.
variable_manager
,
loader
=
self
.
loader
,
)
tqm
=
None
# TODO:日志和结果分析
try
:
tqm
=
TaskQueueManager
(
self
.
runner
=
TaskQueueManager
(
inventory
=
self
.
inventory
,
variable_manager
=
self
.
variable_manager
,
loader
=
self
.
loader
,
stdout_callback
=
self
.
results_callback
,
options
=
self
.
options
,
passwords
=
self
.
passwords
passwords
=
self
.
passwords
,
stdout_callback
=
self
.
results_callback
,
)
ext_code
=
tqm
.
run
(
self
.
play
)
result
=
self
.
results_callback
.
results
# 任务运行结束, 标示任务完成
self
.
update_db_tasker
(
tasker_uuid
,
ext_code
)
def
check_module_args
(
self
):
if
self
.
module_name
in
C
.
MODULE_REQUIRE_ARGS
and
not
self
.
module_args
:
err
=
"No argument passed to '
%
s' module."
%
self
.
module_name
raise
AnsibleError
(
err
)
def
run
(
self
):
if
not
self
.
inventory
.
list_hosts
(
"all"
):
raise
AnsibleError
(
"Inventory is empty."
)
ret
=
json
.
dumps
(
result
)
return
ext_code
,
ret
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
)
except
Exception
as
e
:
pass
else
:
return
self
.
results_callback
.
result_q
finally
:
if
tqm
:
tqm
.
cleanup
()
if
self
.
runner
:
self
.
runner
.
cleanup
()
if
self
.
loader
:
self
.
loader
.
cleanup_all_tmp_files
()
def
test_run
():
conf
=
Options
()
assets
=
[
{
"
name"
:
"192.168.1.11
9"
,
"ip"
:
"192.168.1
.11
9"
,
"port"
:
"22"
,
"
hostname"
:
"192.168.152.12
9"
,
"ip"
:
"192.168.1
52.12
9"
,
"port"
:
22
,
"username"
:
"root"
,
"password"
:
"tongfang_test"
,
"key"
:
"asset_private_key"
,
"password"
:
"redhat"
,
},
{
"name"
:
"192.168.232.135"
,
"ip"
:
"192.168.232.135"
,
"port"
:
"22"
,
"username"
:
"yumaojun"
,
"password"
:
"xxx"
,
"key"
:
"asset_private_key"
,
"become"
:
{
"method"
:
"sudo"
,
"user"
:
"root"
,
"pass"
:
"xxx"
}
},
]
# 初始化Play
play_source
=
{
"name"
:
"Ansible Play"
,
"hosts"
:
"default"
,
"gather_facts"
:
"no"
,
"tasks"
:
[
dict
(
action
=
dict
(
module
=
'ping'
)),
]
}
hoc
=
ADHocRunner
(
conf
,
play_source
,
*
assets
)
uuid
=
"tasker-"
+
uuid4
()
.
hex
ext_code
,
result
=
hoc
.
run
(
"test_task"
,
uuid
)
print
(
ext_code
)
print
(
result
)
hoc
=
ADHocRunner
(
module_name
=
'shell'
,
module_args
=
'ls'
,
hosts
=
assets
)
ret
=
hoc
.
run
()
print
(
ret
)
if
__name__
==
"__main__"
:
test_run
()
This diff is collapsed.
Click to expand it.
apps/ops/views.py
View file @
01e50d59
...
...
@@ -8,54 +8,9 @@ from django.views.generic.detail import DetailView, SingleObjectMixin
from
users.utils
import
AdminUserRequiredMixin
from
ops.utils.mixins
import
CreateSudoPrivilegesMixin
,
ListSudoPrivilegesMixin
from
ops.models
import
*
from
.models
import
Task
class
SudoListView
(
AdminUserRequiredMixin
,
ListSudoPrivilegesMixin
,
ListView
):
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
model
=
Sudo
context_object_name
=
'sudos'
template_name
=
'sudo/list.html'
class
SudoCreateView
(
AdminUserRequiredMixin
,
CreateSudoPrivilegesMixin
,
CreateView
):
model
=
Sudo
template_name
=
'sudo/create.html'
class
SudoUpdateView
(
AdminUserRequiredMixin
,
UpdateView
):
model
=
Sudo
template_name
=
'sudo/update.html'
class
SudoDetailView
(
DetailView
):
model
=
Sudo
context_object_name
=
'sudo'
template_name
=
'sudo/detail.html'
class
CronListView
(
AdminUserRequiredMixin
,
ListView
):
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
model
=
CronTable
context_object_name
=
'crons'
template_name
=
'cron/list.html'
class
CronCreateView
(
AdminUserRequiredMixin
,
CreateView
):
model
=
CronTable
template_name
=
'cron/create.html'
class
CronUpdateView
(
AdminUserRequiredMixin
,
UpdateView
):
model
=
CronTable
template_name
=
'cron/update.html'
class
CronDetailView
(
DetailView
):
model
=
CronTable
context_object_name
=
'cron'
template_name
=
'cron/detail.html'
class
TaskListView
(
AdminUserRequiredMixin
,
ListView
):
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
model
=
Task
...
...
This diff is collapsed.
Click to expand it.
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