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
Mar 05, 2017
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
完成AdHoc JMSHost JMSInventory
parent
0524e8dd
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
302 additions
and
836 deletions
+302
-836
asset.py
apps/assets/models/asset.py
+12
-0
user.py
apps/assets/models/user.py
+18
-3
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
+267
-236
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):
...
@@ -87,6 +87,18 @@ class Asset(models.Model):
def
to_json
(
self
):
def
to_json
(
self
):
pass
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
:
class
Meta
:
unique_together
=
(
'ip'
,
'port'
)
unique_together
=
(
'ip'
,
'port'
)
...
...
apps/assets/models/user.py
View file @
01e50d59
...
@@ -9,7 +9,7 @@ import logging
...
@@ -9,7 +9,7 @@ import logging
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.core.exceptions
import
ValidationError
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'
]
__all__
=
[
'AdminUser'
,
'SystemUser'
,
'private_key_validator'
]
logger
=
logging
.
getLogger
(
__name__
)
logger
=
logging
.
getLogger
(
__name__
)
...
@@ -24,12 +24,20 @@ def private_key_validator(value):
...
@@ -24,12 +24,20 @@ def private_key_validator(value):
class
AdminUser
(
models
.
Model
):
class
AdminUser
(
models
.
Model
):
BECOME_METHOD_CHOICES
=
(
(
'sudo'
,
'sudo'
),
(
'su'
,
'su'
),
)
name
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
'Name'
))
name
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
'Name'
))
username
=
models
.
CharField
(
max_length
=
16
,
verbose_name
=
_
(
'Username'
))
username
=
models
.
CharField
(
max_length
=
16
,
verbose_name
=
_
(
'Username'
))
_password
=
models
.
CharField
(
max_length
=
256
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Password'
))
_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'
),
_private_key
=
models
.
CharField
(
max_length
=
4096
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'SSH private key'
),
validators
=
[
private_key_validator
,])
validators
=
[
private_key_validator
,])
_public_key
=
models
.
CharField
(
max_length
=
4096
,
blank
=
True
,
verbose_name
=
_
(
'SSH public key'
))
_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'
))
comment
=
models
.
TextField
(
blank
=
True
,
verbose_name
=
_
(
'Comment'
))
date_created
=
models
.
DateTimeField
(
auto_now_add
=
True
,
null
=
True
)
date_created
=
models
.
DateTimeField
(
auto_now_add
=
True
,
null
=
True
)
created_by
=
models
.
CharField
(
max_length
=
32
,
null
=
True
,
verbose_name
=
_
(
'Created by'
))
created_by
=
models
.
CharField
(
max_length
=
32
,
null
=
True
,
verbose_name
=
_
(
'Created by'
))
...
@@ -41,7 +49,10 @@ class AdminUser(models.Model):
...
@@ -41,7 +49,10 @@ class AdminUser(models.Model):
@property
@property
def
password
(
self
):
def
password
(
self
):
return
signer
.
unsign
(
self
.
_password
)
if
self
.
_password
:
return
signer
.
unsign
(
self
.
_password
)
else
:
return
''
@password.setter
@password.setter
def
password
(
self
,
password_raw
):
def
password
(
self
,
password_raw
):
...
@@ -49,7 +60,11 @@ class AdminUser(models.Model):
...
@@ -49,7 +60,11 @@ class AdminUser(models.Model):
@property
@property
def
private_key
(
self
):
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
@private_key.setter
def
private_key
(
self
,
private_key_raw
):
def
private_key
(
self
,
private_key_raw
):
...
...
apps/ops/api/serializers.py
View file @
01e50d59
# ~*~ coding: utf-8 ~*~
# ~*~ coding: utf-8 ~*~
from
__future__
import
unicode_literals
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
apps/ops/api/views.py
View file @
01e50d59
...
@@ -5,75 +5,3 @@ from rest_framework import viewsets
...
@@ -5,75 +5,3 @@ from rest_framework import viewsets
from
serializers
import
*
from
serializers
import
*
from
permissions
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
,)
apps/ops/models/__init__.py
View file @
01e50d59
from
ansible
import
*
from
ansible
import
*
from
cron
import
*
from
sudo
import
*
from
utils
import
*
from
utils
import
*
from
task
import
*
from
task
import
*
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
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
apps/ops/models/utils.py
View file @
01e50d59
...
@@ -2,13 +2,10 @@
...
@@ -2,13 +2,10 @@
from
__future__
import
unicode_literals
from
__future__
import
unicode_literals
from
ansible
import
*
from
ansible
import
*
from
cron
import
*
from
sudo
import
*
__all__
=
[
"generate_fake"
]
__all__
=
[
"generate_fake"
]
def
generate_fake
():
def
generate_fake
():
for
cls
in
(
TaskRecord
,
AnsiblePlay
,
AnsibleTask
,
AnsibleHostResult
,
CronTable
,
for
cls
in
(
TaskRecord
,
AnsiblePlay
,
AnsibleTask
,
AnsibleHostResult
):
HostAlia
,
UserAlia
,
CmdAlia
,
RunasAlia
,
Privilege
,
Sudo
):
cls
.
generate_fake
()
cls
.
generate_fake
()
\ No newline at end of file
apps/ops/urls/api_urls.py
View file @
01e50d59
...
@@ -2,20 +2,6 @@
...
@@ -2,20 +2,6 @@
from
__future__
import
unicode_literals
from
__future__
import
unicode_literals
from
rest_framework.routers
import
DefaultRouter
from
rest_framework.routers
import
DefaultRouter
from
ops
import
api
as
v1_api
__all__
=
[
"urlpatterns"
]
api_router
=
DefaultRouter
()
urlpatterns
=
[]
api_router
.
register
(
r'v1/host_alia'
,
v1_api
.
HostAliaViewSet
)
\ No newline at end of file
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
apps/ops/urls/view_urls.py
View file @
01e50d59
...
@@ -8,18 +8,6 @@ from ops import views as page_view
...
@@ -8,18 +8,6 @@ from ops import views as page_view
__all__
=
[
"urlpatterns"
]
__all__
=
[
"urlpatterns"
]
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
# TResource Task url
url
(
r'^task/list$'
,
page_view
.
TaskListView
.
as_view
(),
name
=
'page-task-list'
),
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'
),
url
(
r'^task/create$'
,
page_view
.
TaskCreateView
.
as_view
(),
name
=
'page-task-create'
),
...
...
apps/ops/utils/ansible_api.py
View file @
01e50d59
# ~*~ coding: utf-8 ~*~
# ~*~ coding: utf-8 ~*~
from
__future__
import
unicode_literals
,
print_function
#
from __future__ import unicode_literals, print_function
import
os
import
os
import
json
import
json
import
logging
import
logging
import
traceback
import
traceback
import
ansible.constants
as
default_config
import
ansible.constants
as
default_config
from
collections
import
namedtuple
from
uuid
import
uuid4
from
uuid
import
uuid4
from
django.utils
import
timezone
from
django.utils
import
timezone
...
@@ -17,11 +18,15 @@ from ansible.executor import playbook_executor
...
@@ -17,11 +18,15 @@ from ansible.executor import playbook_executor
from
ansible.utils.display
import
Display
from
ansible.utils.display
import
Display
from
ansible.playbook.play
import
Play
from
ansible.playbook.play
import
Play
from
ansible.plugins.callback
import
CallbackBase
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"
]
__all__
=
[
"ADHocRunner"
,
"Options"
]
C
.
HOST_KEY_CHECKING
=
False
logger
=
logging
.
getLogger
(
__name__
)
logger
=
logging
.
getLogger
(
__name__
)
...
@@ -30,149 +35,187 @@ class AnsibleError(StandardError):
...
@@ -30,149 +35,187 @@ class AnsibleError(StandardError):
pass
pass
class
Options
(
object
):
# class Options(object):
"""Ansible运行时配置类, 用于初始化Ansible的一些默认配置.
# """Ansible运行时配置类, 用于初始化Ansible的一些默认配置.
"""
# """
def
__init__
(
self
,
verbosity
=
None
,
inventory
=
None
,
listhosts
=
None
,
subset
=
None
,
module_paths
=
None
,
extra_vars
=
None
,
# 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
,
# 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
,
# 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
,
# 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
,
# 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
,
# 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
):
# syntax=None, diff=None, force_handlers=None, flush_cache=None, listtasks=None, listtags=None, module_path=None):
self
.
verbosity
=
verbosity
# self.verbosity = verbosity
self
.
inventory
=
inventory
# self.inventory = inventory
self
.
listhosts
=
listhosts
# self.listhosts = listhosts
self
.
subset
=
subset
# self.subset = subset
self
.
module_paths
=
module_paths
# self.module_paths = module_paths
self
.
extra_vars
=
extra_vars
# self.extra_vars = extra_vars
self
.
forks
=
forks
# self.forks = forks
self
.
ask_vault_pass
=
ask_vault_pass
# self.ask_vault_pass = ask_vault_pass
self
.
vault_password_files
=
vault_password_files
# self.vault_password_files = vault_password_files
self
.
new_vault_password_file
=
new_vault_password_file
# self.new_vault_password_file = new_vault_password_file
self
.
output_file
=
output_file
# self.output_file = output_file
self
.
tags
=
tags
# self.tags = tags
self
.
skip_tags
=
skip_tags
# self.skip_tags = skip_tags
self
.
one_line
=
one_line
# self.one_line = one_line
self
.
tree
=
tree
# self.tree = tree
self
.
ask_sudo_pass
=
ask_sudo_pass
# self.ask_sudo_pass = ask_sudo_pass
self
.
ask_su_pass
=
ask_su_pass
# self.ask_su_pass = ask_su_pass
self
.
sudo
=
sudo
# self.sudo = sudo
self
.
sudo_user
=
sudo_user
# self.sudo_user = sudo_user
self
.
become
=
become
# self.become = become
self
.
become_method
=
become_method
# self.become_method = become_method
self
.
become_user
=
become_user
# self.become_user = become_user
self
.
become_ask_pass
=
become_ask_pass
# self.become_ask_pass = become_ask_pass
self
.
ask_pass
=
ask_pass
# self.ask_pass = ask_pass
self
.
private_key_file
=
private_key_file
# self.private_key_file = private_key_file
self
.
remote_user
=
remote_user
# self.remote_user = remote_user
self
.
connection
=
connection
# self.connection = connection
self
.
timeout
=
timeout
# self.timeout = timeout
self
.
ssh_common_args
=
ssh_common_args
# self.ssh_common_args = ssh_common_args
self
.
sftp_extra_args
=
sftp_extra_args
# self.sftp_extra_args = sftp_extra_args
self
.
scp_extra_args
=
scp_extra_args
# self.scp_extra_args = scp_extra_args
self
.
ssh_extra_args
=
ssh_extra_args
# self.ssh_extra_args = ssh_extra_args
self
.
poll_interval
=
poll_interval
# self.poll_interval = poll_interval
self
.
seconds
=
seconds
# self.seconds = seconds
self
.
check
=
check
# self.check = check
self
.
syntax
=
syntax
# self.syntax = syntax
self
.
diff
=
diff
# self.diff = diff
self
.
force_handlers
=
force_handlers
# self.force_handlers = force_handlers
self
.
flush_cache
=
flush_cache
# self.flush_cache = flush_cache
self
.
listtasks
=
listtasks
# self.listtasks = listtasks
self
.
listtags
=
listtags
# self.listtags = listtags
self
.
module_path
=
module_path
# self.module_path = module_path
self
.
__overwrite_default
()
# self.__overwrite_default()
#
def
__overwrite_default
(
self
):
# def __overwrite_default(self):
"""上面并不能包含Ansible所有的配置, 如果有其他的配置,
# """上面并不能包含Ansible所有的配置, 如果有其他的配置,
可以通过替换default_config模块里面的变量进行重载,
# 可以通过替换default_config模块里面的变量进行重载,
比如 default_config.DEFAULT_ASK_PASS = False.
# 比如 default_config.DEFAULT_ASK_PASS = False.
"""
# """
default_config
.
HOST_KEY_CHECKING
=
False
# default_config.HOST_KEY_CHECKING = False
Options
=
namedtuple
(
"Options"
,
[
'connection'
,
'module_path'
,
'private_key_file'
,
"remote_user"
,
"timeout"
,
class
InventoryMixin
(
object
):
'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'
])
# 添加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对象的方法
提供生成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.
"""用于生成动态构建Ansible Inventory.
self.hosts: [
self.host_list: [
{"host": <ip>,
{"name": "asset_name",
"port": <port>,
"ip": <ip>,
"user": <user>,
"port": <port>,
"pass": <pass>,
"user": <user>,
"key": <sshKey>,
"pass": <pass>,
"group": <default>
"key": <sshKey>,
"other_host_var": <other>},
"groups": ['group1', 'group2'],
{...},
"other_host_var": <other>},
]
{...},
self.group_vars: {
]
"groupName1": {"var1": <value>, "var2": <value>, ...},
"groupName2": {"var1": <value>, "var2": <value>, ...},
}
:return: 返回一个Ansible的inventory对象
:return: 返回一个Ansible的inventory对象
"""
"""
# TODO: 验证输入
# TODO: 验证输入
# 创建Ansible Group,如果没有则创建default组
# 创建Ansible Group,如果没有则创建default组
for
asset
in
self
.
hosts
:
ungrouped
=
Group
(
'ungrouped'
)
g_name
=
asset
.
get
(
'group'
,
'default'
)
all
=
Group
(
'all'
)
if
g_name
not
in
[
g
.
name
for
g
in
self
.
groups
]:
all
.
add_child_group
(
ungrouped
)
group
=
Group
(
name
=
g_name
)
self
.
groups
=
dict
(
all
=
all
,
ungrouped
=
ungrouped
)
self
.
groups
.
append
(
group
)
for
asset
in
host_list
:
# 添加组变量到相应的组上
host
=
JMSHost
(
asset
=
asset
)
for
group_name
,
variables
in
self
.
group_vars
.
iteritems
():
asset_groups
=
asset
.
get
(
'groups'
)
for
g
in
self
.
groups
:
if
asset_groups
:
if
g
.
name
==
group_name
:
for
group_name
in
asset_groups
:
for
v_name
,
v_value
in
variables
.
iteritems
():
if
group_name
not
in
self
.
groups
:
g
.
set_variable
(
v_name
,
v_value
)
group
=
Group
(
group_name
)
self
.
groups
[
group_name
]
=
group
# 往组里面添加Host
else
:
for
asset
in
self
.
hosts
:
group
=
self
.
groups
[
group_name
]
# 添加Host链接的常用变量(host,port,user,pass,key)
group
.
add_host
(
host
)
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'
])
# 添加密码和秘钥
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
:
else
:
host
.
set_variable
(
"ansible_become"
,
False
)
ungrouped
.
add_host
(
host
)
all
.
add_host
(
host
)
# 添加其他Host的额外变量
for
key
,
value
in
asset
.
iteritems
():
if
key
not
in
[
"name"
,
"port"
,
"ip"
,
"username"
,
"password"
,
"key"
]:
host
.
set_variable
(
key
,
value
)
# 将host添加到组里面
class
BasicResultCallback
(
CallbackBase
):
for
g
in
self
.
groups
:
"""
if
g
.
name
==
asset
.
get
(
'group'
,
'default'
):
Custom Callback
g
.
add_host
(
host
)
"""
def
__init__
(
self
,
display
=
None
):
self
.
result_q
=
dict
(
contacted
=
{},
dark
=
{})
super
(
BasicResultCallback
,
self
)
.
__init__
(
display
)
def
gather_result
(
self
,
n
,
res
):
self
.
result_q
[
n
]
.
update
({
res
.
_host
.
name
:
res
.
_result
})
# 将组添加到Inventory里面,生成真正的inventory对象
def
v2_runner_on_ok
(
self
,
result
):
inventory
=
Inventory
(
loader
=
self
.
loader
,
variable_manager
=
self
.
variable_manager
,
host_list
=
[])
self
.
gather_result
(
"contacted"
,
result
)
for
g
in
self
.
groups
:
inventory
.
add_group
(
g
)
def
v2_runner_on_failed
(
self
,
result
,
ignore_errors
=
False
):
self
.
variable_manager
.
set_inventory
(
inventory
)
self
.
gather_result
(
"dark"
,
result
)
return
inventory
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
):
class
CallbackModule
(
CallbackBase
):
...
@@ -310,7 +353,7 @@ class CallbackModule(CallbackBase):
...
@@ -310,7 +353,7 @@ class CallbackModule(CallbackBase):
print
(
"summary:
%
s"
,
summary
)
print
(
"summary:
%
s"
,
summary
)
class
PlayBookRunner
(
InventoryMixin
):
class
PlayBookRunner
(
object
):
"""用于执行AnsiblePlaybook的接口.简化Playbook对象的使用.
"""用于执行AnsiblePlaybook的接口.简化Playbook对象的使用.
"""
"""
...
@@ -393,133 +436,121 @@ class PlayBookRunner(InventoryMixin):
...
@@ -393,133 +436,121 @@ class PlayBookRunner(InventoryMixin):
return
stats
return
stats
class
ADHocRunner
(
InventoryMixin
):
class
ADHocRunner
(
object
):
"""
"""
ADHoc接口
ADHoc接口
"""
"""
def
__init__
(
self
,
play_data
,
config
=
None
,
*
hosts
,
**
group_vars
):
def
__init__
(
self
,
"""
hosts
=
C
.
DEFAULT_HOST_LIST
,
:param hosts: 见PlaybookRunner参数
module_name
=
C
.
DEFAULT_MODULE_NAME
,
# * command
:param group_vars: 见PlaybookRunner参数
module_args
=
C
.
DEFAULT_MODULE_ARGS
,
# * 'cmd args'
:param config: Config实例
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
.
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 play_data:
self
.
variable_manager
.
extra_vars
=
load_extra_vars
(
self
.
loader
,
options
=
self
.
options
)
play_data = dict(
self
.
variable_manager
.
options_vars
=
load_options_vars
(
self
.
options
)
name="Ansible Ad-Hoc",
self
.
passwords
=
passwords
or
{}
hosts=pattern,
self
.
inventory
=
JMSInventory
(
hosts
)
gather_facts=True,
self
.
variable_manager
.
set_inventory
(
self
.
inventory
)
tasks=[dict(action=dict(module='service', args={'name': 'vsftpd', 'state': 'restarted'}), async=async, poll=poll)]
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
.
options
=
config
if
config
!=
None
else
Options
()
# 设置verbosity级别, 及命令行的--verbose选项
self
.
play
=
Play
()
.
load
(
self
.
display
=
Display
()
self
.
play_source
,
self
.
display
.
verbosity
=
self
.
options
.
verbosity
variable_manager
=
self
.
variable_manager
,
loader
=
self
.
loader
,
)
# sudo的配置移到了Host级别去了,因此这里不再需要处理
self
.
runner
=
TaskQueueManager
(
self
.
passwords
=
None
inventory
=
self
.
inventory
,
variable_manager
=
self
.
variable_manager
,
loader
=
self
.
loader
,
options
=
self
.
options
,
passwords
=
self
.
passwords
,
stdout_callback
=
self
.
results_callback
,
)
# 生成Ansible inventory, 这些变量Mixin都会用到
def
check_module_args
(
self
):
self
.
hosts
=
hosts
if
self
.
module_name
in
C
.
MODULE_REQUIRE_ARGS
and
not
self
.
module_args
:
self
.
group_vars
=
group_vars
err
=
"No argument passed to '
%
s' module."
%
self
.
module_name
self
.
loader
=
DataLoader
()
raise
AnsibleError
(
err
)
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
)
def
run
(
self
):
if
not
self
.
inventory
.
list_hosts
(
"all"
):
raise
AnsibleError
(
"Inventory is empty."
)
@staticmethod
if
not
self
.
inventory
.
list_hosts
(
self
.
pattern
):
def
update_db_tasker
(
tasker_id
,
ext_code
):
raise
AnsibleError
(
try
:
"pattern:
%
s dose not match any hosts."
%
self
.
pattern
)
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
:
try
:
hosts
=
[
host
.
get
(
'name'
)
for
host
in
self
.
hosts
]
self
.
runner
.
run
(
self
.
play
)
tasker
=
TaskRecord
(
name
=
name
,
uuid
=
uuid
,
hosts
=
','
.
join
(
hosts
),
start
=
timezone
.
now
())
tasker
.
save
()
except
Exception
as
e
:
except
Exception
as
e
:
logger
.
error
(
"Save Tasker to database error!,
%
s"
%
e
.
message
)
pass
else
:
def
run
(
self
,
tasker_name
,
tasker_uuid
):
return
self
.
results_callback
.
result_q
"""执行ADHoc, 执行完后, 修改AnsiblePlay的状态为完成状态.
:param tasker_uuid <str> 用于标示此次task
"""
# 初始化callback插件,以及Tasker
self
.
create_db_tasker
(
tasker_name
,
tasker_uuid
)
self
.
results_callback
=
CallbackModule
(
tasker_uuid
)
tqm
=
None
# TODO:日志和结果分析
try
:
tqm
=
TaskQueueManager
(
inventory
=
self
.
inventory
,
variable_manager
=
self
.
variable_manager
,
loader
=
self
.
loader
,
stdout_callback
=
self
.
results_callback
,
options
=
self
.
options
,
passwords
=
self
.
passwords
)
ext_code
=
tqm
.
run
(
self
.
play
)
result
=
self
.
results_callback
.
results
# 任务运行结束, 标示任务完成
self
.
update_db_tasker
(
tasker_uuid
,
ext_code
)
ret
=
json
.
dumps
(
result
)
return
ext_code
,
ret
finally
:
finally
:
if
tqm
:
if
self
.
runner
:
tqm
.
cleanup
()
self
.
runner
.
cleanup
()
if
self
.
loader
:
self
.
loader
.
cleanup_all_tmp_files
()
def
test_run
():
def
test_run
():
conf
=
Options
()
assets
=
[
assets
=
[
{
{
"
name"
:
"192.168.1.11
9"
,
"
hostname"
:
"192.168.152.12
9"
,
"ip"
:
"192.168.1
.11
9"
,
"ip"
:
"192.168.1
52.12
9"
,
"port"
:
"22"
,
"port"
:
22
,
"username"
:
"root"
,
"username"
:
"root"
,
"password"
:
"tongfang_test"
,
"password"
:
"redhat"
,
"key"
:
"asset_private_key"
,
},
},
{
"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
hoc
=
ADHocRunner
(
module_name
=
'shell'
,
module_args
=
'ls'
,
hosts
=
assets
)
play_source
=
{
ret
=
hoc
.
run
()
"name"
:
"Ansible Play"
,
print
(
ret
)
"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
)
if
__name__
==
"__main__"
:
if
__name__
==
"__main__"
:
test_run
()
test_run
()
apps/ops/views.py
View file @
01e50d59
...
@@ -8,54 +8,9 @@ from django.views.generic.detail import DetailView, SingleObjectMixin
...
@@ -8,54 +8,9 @@ from django.views.generic.detail import DetailView, SingleObjectMixin
from
users.utils
import
AdminUserRequiredMixin
from
users.utils
import
AdminUserRequiredMixin
from
ops.utils.mixins
import
CreateSudoPrivilegesMixin
,
ListSudoPrivilegesMixin
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
):
class
TaskListView
(
AdminUserRequiredMixin
,
ListView
):
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
model
=
Task
model
=
Task
...
...
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