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
99c4875d
Unverified
Commit
99c4875d
authored
Jun 05, 2018
by
老广
Committed by
GitHub
Jun 05, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1395 from jumpserver/dev
Dev
parents
4f521e5a
482d1bb2
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
378 additions
and
582 deletions
+378
-582
asset.py
apps/assets/api/asset.py
+20
-23
node.py
apps/assets/api/node.py
+31
-40
hands.py
apps/assets/hands.py
+0
-1
asset.py
apps/assets/models/asset.py
+67
-27
node.py
apps/assets/models/node.py
+65
-59
asset.py
apps/assets/serializers/asset.py
+0
-25
node.py
apps/assets/serializers/node.py
+3
-9
signals_handler.py
apps/assets/signals_handler.py
+18
-14
_asset_list_modal.html
apps/assets/templates/assets/_asset_list_modal.html
+1
-1
asset_list.html
apps/assets/templates/assets/asset_list.html
+3
-4
api_urls.py
apps/assets/urls/api_urls.py
+18
-11
utils.py
apps/assets/utils.py
+15
-13
api.py
apps/common/api.py
+6
-16
tasks.py
apps/common/tasks.py
+5
-0
utils.py
apps/common/utils.py
+15
-0
api.py
apps/perms/api.py
+21
-17
utils.py
apps/perms/utils.py
+84
-320
login.py
apps/users/views/login.py
+3
-1
jms
jms
+1
-0
upgrade.sh
utils/upgrade.sh
+2
-1
No files found.
apps/assets/api/asset.py
View file @
99c4875d
...
...
@@ -11,9 +11,8 @@ from django.db.models import Q
from
common.mixins
import
IDInFilterMixin
from
common.utils
import
get_logger
from
..hands
import
IsSuperUser
,
IsValidUser
,
IsSuperUserOrAppUser
,
\
NodePermissionUtil
from
..models
import
Asset
,
SystemUser
,
AdminUser
,
Node
from
..hands
import
IsSuperUser
,
IsValidUser
,
IsSuperUserOrAppUser
from
..models
import
Asset
,
SystemUser
,
AdminUser
,
Node
from
..
import
serializers
from
..tasks
import
update_asset_hardware_info_manual
,
\
test_asset_connectability_manual
...
...
@@ -22,7 +21,7 @@ from ..utils import LabelFilter
logger
=
get_logger
(
__file__
)
__all__
=
[
'AssetViewSet'
,
'
UserAssetListView'
,
'
AssetListUpdateApi'
,
'AssetViewSet'
,
'AssetListUpdateApi'
,
'AssetRefreshHardwareApi'
,
'AssetAdminUserTestApi'
]
...
...
@@ -40,7 +39,9 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet):
permission_classes
=
(
IsSuperUserOrAppUser
,)
def
get_queryset
(
self
):
queryset
=
super
()
.
get_queryset
()
queryset
=
super
()
.
get_queryset
()
\
.
prefetch_related
(
'labels'
,
'nodes'
)
\
.
select_related
(
'admin_user'
)
admin_user_id
=
self
.
request
.
query_params
.
get
(
'admin_user_id'
)
node_id
=
self
.
request
.
query_params
.
get
(
"node_id"
)
show_current_asset
=
self
.
request
.
query_params
.
get
(
"show_current_asset"
)
...
...
@@ -48,28 +49,24 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet):
if
admin_user_id
:
admin_user
=
get_object_or_404
(
AdminUser
,
id
=
admin_user_id
)
queryset
=
queryset
.
filter
(
admin_user
=
admin_user
)
if
node_id
:
if
node_id
and
show_current_asset
:
node
=
get_object_or_404
(
Node
,
id
=
node_id
)
if
no
t
no
de
.
is_root
():
if
node
.
is_root
():
queryset
=
queryset
.
filter
(
nodes__key__regex
=
'^{}(:[0-9]+)*$'
.
format
(
node
.
key
),
Q
(
nodes
=
node_id
)
|
Q
(
nodes__isnull
=
True
)
)
.
distinct
()
if
show_current_asset
and
node_id
:
queryset
=
queryset
.
filter
(
nodes
=
node_id
)
.
distinct
()
return
queryset
else
:
queryset
=
queryset
.
filter
(
nodes
=
node
)
.
distinct
()
class
UserAssetListView
(
generics
.
ListAPIView
):
queryset
=
Asset
.
objects
.
all
()
serializer_class
=
serializers
.
AssetSerializer
permission_classes
=
(
IsValidUser
,)
def
get_queryset
(
self
):
assets_granted
=
NodePermissionUtil
.
get_user_assets
(
self
.
request
.
user
)
.
keys
()
queryset
=
self
.
queryset
.
filter
(
id__in
=
[
asset
.
id
for
asset
in
assets_granted
]
)
if
node_id
and
not
show_current_asset
:
node
=
get_object_or_404
(
Node
,
id
=
node_id
)
if
node
.
is_root
():
queryset
=
Asset
.
objects
.
all
()
else
:
queryset
=
queryset
.
filter
(
nodes__key__regex
=
'^{}(:[0-9]+)*$'
.
format
(
node
.
key
),
)
.
distinct
()
return
queryset
...
...
apps/assets/api/node.py
View file @
99c4875d
...
...
@@ -31,7 +31,7 @@ from .. import serializers
logger
=
get_logger
(
__file__
)
__all__
=
[
'NodeViewSet'
,
'NodeChildrenApi'
,
'NodeAssetsApi'
,
'NodeWithAssetsApi'
,
'NodeAssetsApi'
,
'NodeAddAssetsApi'
,
'NodeRemoveAssetsApi'
,
'NodeReplaceAssetsApi'
,
'NodeAddChildrenApi'
,
'RefreshNodeHardwareInfoApi'
,
...
...
@@ -42,14 +42,7 @@ __all__ = [
class
NodeViewSet
(
BulkModelViewSet
):
queryset
=
Node
.
objects
.
all
()
permission_classes
=
(
IsSuperUser
,)
# serializer_class = serializers.NodeSerializer
def
get_serializer_class
(
self
):
show_current_asset
=
self
.
request
.
query_params
.
get
(
'show_current_asset'
)
if
show_current_asset
:
return
serializers
.
NodeCurrentSerializer
else
:
return
serializers
.
NodeSerializer
serializer_class
=
serializers
.
NodeSerializer
def
perform_create
(
self
,
serializer
):
child_key
=
Node
.
root
()
.
get_next_child_key
()
...
...
@@ -57,32 +50,32 @@ class NodeViewSet(BulkModelViewSet):
serializer
.
save
()
class
NodeWithAssetsApi
(
generics
.
ListAPIView
):
permission_classes
=
(
IsSuperUser
,)
serializers
=
serializers
.
NodeSerializer
def
get_node
(
self
):
pk
=
self
.
kwargs
.
get
(
'pk'
)
or
self
.
request
.
query_params
.
get
(
'node'
)
if
not
pk
:
node
=
Node
.
root
()
else
:
node
=
get_object_or_404
(
Node
,
pk
)
return
node
def
get_queryset
(
self
):
queryset
=
[]
node
=
self
.
get_node
()
children
=
node
.
get_children
()
assets
=
node
.
get_assets
()
queryset
.
extend
(
list
(
children
))
for
asset
in
assets
:
node
=
Node
()
node
.
id
=
asset
.
id
node
.
parent
=
node
.
id
node
.
value
=
asset
.
hostname
queryset
.
append
(
node
)
return
queryset
#
class NodeWithAssetsApi(generics.ListAPIView):
#
permission_classes = (IsSuperUser,)
#
serializers = serializers.NodeSerializer
#
#
def get_node(self):
#
pk = self.kwargs.get('pk') or self.request.query_params.get('node')
#
if not pk:
#
node = Node.root()
#
else:
#
node = get_object_or_404(Node, pk)
#
return node
#
#
def get_queryset(self):
#
queryset = []
#
node = self.get_node()
#
children = node.get_children()
#
assets = node.get_assets()
#
queryset.extend(list(children))
#
#
for asset in assets:
#
node = Node()
#
node.id = asset.id
#
node.parent = node.id
#
node.value = asset.hostname
#
queryset.append(node)
#
return queryset
class
NodeChildrenApi
(
mixins
.
ListModelMixin
,
generics
.
CreateAPIView
):
...
...
@@ -146,9 +139,9 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
for
asset
in
assets
:
node_fake
=
Node
()
node_fake
.
id
=
asset
.
id
node_fake
.
parent
=
node
node_fake
.
value
=
asset
.
hostname
node_fake
.
is_node
=
False
node_fake
.
parent_id
=
node
.
id
node_fake
.
value
=
asset
.
hostname
queryset
.
append
(
node_fake
)
queryset
=
sorted
(
queryset
,
key
=
lambda
x
:
x
.
is_node
,
reverse
=
True
)
return
queryset
...
...
@@ -184,9 +177,7 @@ class NodeAddChildrenApi(generics.UpdateAPIView):
for
node
in
children
:
if
not
node
:
continue
# node.parent = instance
# node.save()
node
.
set_parent
(
instance
)
node
.
parent
=
instance
return
Response
(
"OK"
)
...
...
apps/assets/hands.py
View file @
99c4875d
...
...
@@ -14,4 +14,3 @@
from
common.mixins
import
AdminUserRequiredMixin
from
common.permissions
import
IsAppUser
,
IsSuperUser
,
IsValidUser
,
IsSuperUserOrAppUser
from
users.models
import
User
,
UserGroup
from
perms.utils
import
NodePermissionUtil
apps/assets/models/asset.py
View file @
99c4875d
...
...
@@ -4,6 +4,8 @@
import
uuid
import
logging
import
random
from
functools
import
reduce
from
django.db
import
models
from
django.utils.translation
import
ugettext_lazy
as
_
...
...
@@ -58,42 +60,70 @@ class Asset(models.Model):
(
'Other'
,
'Other'
),
)
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
ip
=
models
.
GenericIPAddressField
(
max_length
=
32
,
verbose_name
=
_
(
'IP'
),
db_index
=
True
)
hostname
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
'Hostname'
))
ip
=
models
.
GenericIPAddressField
(
max_length
=
32
,
verbose_name
=
_
(
'IP'
),
db_index
=
True
)
hostname
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
'Hostname'
))
port
=
models
.
IntegerField
(
default
=
22
,
verbose_name
=
_
(
'Port'
))
platform
=
models
.
CharField
(
max_length
=
128
,
choices
=
PLATFORM_CHOICES
,
default
=
'Linux'
,
verbose_name
=
_
(
'Platform'
))
domain
=
models
.
ForeignKey
(
"assets.Domain"
,
null
=
True
,
blank
=
True
,
related_name
=
'assets'
,
verbose_name
=
_
(
"Domain"
),
on_delete
=
models
.
SET_NULL
)
nodes
=
models
.
ManyToManyField
(
'assets.Node'
,
default
=
default_node
,
related_name
=
'assets'
,
verbose_name
=
_
(
"Nodes"
))
platform
=
models
.
CharField
(
max_length
=
128
,
choices
=
PLATFORM_CHOICES
,
default
=
'Linux'
,
verbose_name
=
_
(
'Platform'
))
domain
=
models
.
ForeignKey
(
"assets.Domain"
,
null
=
True
,
blank
=
True
,
related_name
=
'assets'
,
verbose_name
=
_
(
"Domain"
),
on_delete
=
models
.
SET_NULL
)
nodes
=
models
.
ManyToManyField
(
'assets.Node'
,
default
=
default_node
,
related_name
=
'assets'
,
verbose_name
=
_
(
"Nodes"
))
is_active
=
models
.
BooleanField
(
default
=
True
,
verbose_name
=
_
(
'Is active'
))
# Auth
admin_user
=
models
.
ForeignKey
(
'assets.AdminUser'
,
on_delete
=
models
.
PROTECT
,
null
=
True
,
verbose_name
=
_
(
"Admin user"
))
admin_user
=
models
.
ForeignKey
(
'assets.AdminUser'
,
on_delete
=
models
.
PROTECT
,
null
=
True
,
verbose_name
=
_
(
"Admin user"
))
# Some information
public_ip
=
models
.
GenericIPAddressField
(
max_length
=
32
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Public IP'
))
number
=
models
.
CharField
(
max_length
=
32
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Asset number'
))
public_ip
=
models
.
GenericIPAddressField
(
max_length
=
32
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Public IP'
))
number
=
models
.
CharField
(
max_length
=
32
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Asset number'
))
# Collect
vendor
=
models
.
CharField
(
max_length
=
64
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Vendor'
))
model
=
models
.
CharField
(
max_length
=
54
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Model'
))
sn
=
models
.
CharField
(
max_length
=
128
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Serial number'
))
cpu_model
=
models
.
CharField
(
max_length
=
64
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'CPU model'
))
vendor
=
models
.
CharField
(
max_length
=
64
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Vendor'
))
model
=
models
.
CharField
(
max_length
=
54
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Model'
))
sn
=
models
.
CharField
(
max_length
=
128
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Serial number'
))
cpu_model
=
models
.
CharField
(
max_length
=
64
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'CPU model'
))
cpu_count
=
models
.
IntegerField
(
null
=
True
,
verbose_name
=
_
(
'CPU count'
))
cpu_cores
=
models
.
IntegerField
(
null
=
True
,
verbose_name
=
_
(
'CPU cores'
))
memory
=
models
.
CharField
(
max_length
=
64
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Memory'
))
disk_total
=
models
.
CharField
(
max_length
=
1024
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Disk total'
))
disk_info
=
models
.
CharField
(
max_length
=
1024
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Disk info'
))
os
=
models
.
CharField
(
max_length
=
128
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'OS'
))
os_version
=
models
.
CharField
(
max_length
=
16
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'OS version'
))
os_arch
=
models
.
CharField
(
max_length
=
16
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'OS arch'
))
hostname_raw
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Hostname raw'
))
labels
=
models
.
ManyToManyField
(
'assets.Label'
,
blank
=
True
,
related_name
=
'assets'
,
verbose_name
=
_
(
"Labels"
))
created_by
=
models
.
CharField
(
max_length
=
32
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Created by'
))
date_created
=
models
.
DateTimeField
(
auto_now_add
=
True
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Date created'
))
comment
=
models
.
TextField
(
max_length
=
128
,
default
=
''
,
blank
=
True
,
verbose_name
=
_
(
'Comment'
))
memory
=
models
.
CharField
(
max_length
=
64
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Memory'
))
disk_total
=
models
.
CharField
(
max_length
=
1024
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Disk total'
))
disk_info
=
models
.
CharField
(
max_length
=
1024
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Disk info'
))
os
=
models
.
CharField
(
max_length
=
128
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'OS'
))
os_version
=
models
.
CharField
(
max_length
=
16
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'OS version'
))
os_arch
=
models
.
CharField
(
max_length
=
16
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'OS arch'
))
hostname_raw
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Hostname raw'
))
labels
=
models
.
ManyToManyField
(
'assets.Label'
,
blank
=
True
,
related_name
=
'assets'
,
verbose_name
=
_
(
"Labels"
))
created_by
=
models
.
CharField
(
max_length
=
32
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Created by'
))
date_created
=
models
.
DateTimeField
(
auto_now_add
=
True
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Date created'
))
comment
=
models
.
TextField
(
max_length
=
128
,
default
=
''
,
blank
=
True
,
verbose_name
=
_
(
'Comment'
))
objects
=
AssetManager
()
...
...
@@ -120,6 +150,15 @@ class Asset(models.Model):
nodes
=
self
.
nodes
.
all
()
or
[
Node
.
root
()]
return
nodes
def
get_all_nodes
(
self
,
flat
=
False
):
nodes
=
[]
for
node
in
self
.
get_nodes
():
_nodes
=
node
.
get_ancestor
(
with_self
=
True
)
_nodes
.
append
(
_nodes
)
if
flat
:
nodes
=
list
(
reduce
(
lambda
x
,
y
:
set
(
x
)
|
set
(
y
),
nodes
))
return
nodes
@property
def
hardware_info
(
self
):
if
self
.
cpu_count
:
...
...
@@ -191,7 +230,8 @@ class Asset(models.Model):
seed
()
for
i
in
range
(
count
):
asset
=
cls
(
ip
=
'
%
s.
%
s.
%
s.
%
s'
%
(
i
,
i
,
i
,
i
),
ip
=
[
str
(
i
)
for
i
in
random
.
sample
(
range
(
255
),
4
)]
asset
=
cls
(
ip
=
'.'
.
join
(
ip
),
hostname
=
forgery_py
.
internet
.
user_name
(
True
),
admin_user
=
choice
(
AdminUser
.
objects
.
all
()),
port
=
22
,
...
...
apps/assets/models/node.py
View file @
99c4875d
...
...
@@ -5,7 +5,7 @@ import uuid
from
django.db
import
models
,
transaction
from
django.db.models
import
Q
from
django.utils.translation
import
ugettext_lazy
as
_
from
common.utils
import
with_cache
__all__
=
[
'Node'
]
...
...
@@ -13,9 +13,6 @@ __all__ = ['Node']
class
Node
(
models
.
Model
):
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
key
=
models
.
CharField
(
unique
=
True
,
max_length
=
64
,
verbose_name
=
_
(
"Key"
))
# '1:1:1:1'
# value = models.CharField(
# max_length=128, unique=True, verbose_name=_("Value")
# )
value
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
_
(
"Value"
))
child_mark
=
models
.
IntegerField
(
default
=
0
)
date_create
=
models
.
DateTimeField
(
auto_now_add
=
True
)
...
...
@@ -25,31 +22,36 @@ class Node(models.Model):
def
__str__
(
self
):
return
self
.
full_value
def
__eq__
(
self
,
other
):
return
self
.
key
==
other
.
key
def
__gt__
(
self
,
other
):
if
self
.
is_root
():
return
True
self_key
=
[
int
(
k
)
for
k
in
self
.
key
.
split
(
':'
)]
other_key
=
[
int
(
k
)
for
k
in
other
.
key
.
split
(
':'
)]
if
len
(
self_key
)
<
len
(
other_key
):
return
True
elif
len
(
self_key
)
>
len
(
other_key
):
return
False
else
:
return
self_key
[
-
1
]
<
other_key
[
-
1
]
@property
def
name
(
self
):
return
self
.
value
@property
def
full_value
(
self
):
if
self
==
self
.
__class__
.
root
():
ancestor
=
[
a
.
value
for
a
in
self
.
get_ancestor
(
with_self
=
True
)]
if
self
.
is_root
():
return
self
.
value
else
:
return
'{} / {}'
.
format
(
self
.
parent
.
full_value
,
self
.
value
)
return
' / '
.
join
(
ancestor
)
@property
def
level
(
self
):
return
len
(
self
.
key
.
split
(
':'
))
def
set_parent
(
self
,
instance
):
children
=
self
.
get_all_children
()
old_key
=
self
.
key
with
transaction
.
atomic
():
self
.
parent
=
instance
for
child
in
children
:
child
.
key
=
child
.
key
.
replace
(
old_key
,
self
.
key
,
1
)
child
.
save
()
self
.
save
()
def
get_next_child_key
(
self
):
mark
=
self
.
child_mark
self
.
child_mark
+=
1
...
...
@@ -57,32 +59,35 @@ class Node(models.Model):
return
"{}:{}"
.
format
(
self
.
key
,
mark
)
def
create_child
(
self
,
value
):
child_key
=
self
.
get_next_child_key
()
child
=
self
.
__class__
.
objects
.
create
(
key
=
child_key
,
value
=
value
)
return
child
def
get_children
(
self
):
return
self
.
__class__
.
objects
.
filter
(
key__regex
=
r'^{}:[0-9]+$'
.
format
(
self
.
key
)
)
with
transaction
.
atomic
():
child_key
=
self
.
get_next_child_key
()
child
=
self
.
__class__
.
objects
.
create
(
key
=
child_key
,
value
=
value
)
return
child
def
get_children_with_self
(
self
):
def
get_children
(
self
,
with_self
=
False
):
pattern
=
r'^{0}$|^{}:[0-9]+$'
if
with_self
else
r'^{}:[0-9]+$'
return
self
.
__class__
.
objects
.
filter
(
key__regex
=
r'^{0}$|^{0}:[0-9]+$'
.
format
(
self
.
key
)
key__regex
=
pattern
.
format
(
self
.
key
)
)
def
get_all_children
(
self
):
def
get_all_children
(
self
,
with_self
=
False
):
pattern
=
r'^{0}$|^{0}:'
if
with_self
else
r'^{0}'
return
self
.
__class__
.
objects
.
filter
(
key__
startswith
=
'{}:'
.
format
(
self
.
key
)
key__
regex
=
pattern
.
format
(
self
.
key
)
)
def
get_all_children_with_self
(
self
):
return
self
.
__class__
.
objects
.
filter
(
key__regex
=
r'^{0}$|^{0}:'
.
format
(
self
.
key
)
def
get_sibling
(
self
,
with_self
=
False
):
key
=
':'
.
join
(
self
.
key
.
split
(
':'
)[:
-
1
])
pattern
=
r'^{}:[0-9]+$'
.
format
(
key
)
sibling
=
self
.
__class__
.
objects
.
filter
(
key__regex
=
pattern
.
format
(
self
.
key
)
)
if
not
with_self
:
sibling
=
sibling
.
exclude
(
key
=
self
.
key
)
return
sibling
def
get_family
(
self
):
ancestor
=
self
.
ancestor
ancestor
=
self
.
get_ancestor
()
children
=
self
.
get_all_children
()
return
[
*
tuple
(
ancestor
),
self
,
*
tuple
(
children
)]
...
...
@@ -93,7 +98,7 @@ class Node(models.Model):
Q
(
nodes__id
=
self
.
id
)
|
Q
(
nodes__isnull
=
True
)
)
else
:
assets
=
Asset
.
objects
.
filter
(
nodes__id
=
self
.
id
)
assets
=
self
.
assets
.
all
(
)
return
assets
def
get_valid_assets
(
self
):
...
...
@@ -104,18 +109,10 @@ class Node(models.Model):
if
self
.
is_root
():
assets
=
Asset
.
objects
.
all
()
else
:
nodes
=
self
.
get_all_children_with_self
(
)
assets
=
Asset
.
objects
.
filter
(
nodes__
in
=
nodes
)
.
distinct
(
)
pattern
=
r'^{0}$|^{0}:'
.
format
(
self
.
key
)
assets
=
Asset
.
objects
.
filter
(
nodes__
key__regex
=
pattern
)
return
assets
def
get_current_assets
(
self
):
from
.asset
import
Asset
assets
=
Asset
.
objects
.
filter
(
nodes
=
self
)
.
distinct
()
return
assets
def
has_assets
(
self
):
return
self
.
get_all_assets
()
def
get_all_valid_assets
(
self
):
return
self
.
get_all_assets
()
.
valid
()
...
...
@@ -126,7 +123,6 @@ class Node(models.Model):
def
parent
(
self
):
if
self
.
key
==
"0"
or
not
self
.
key
.
startswith
(
"0"
):
return
self
.
__class__
.
root
()
parent_key
=
":"
.
join
(
self
.
key
.
split
(
":"
)[:
-
1
])
try
:
parent
=
self
.
__class__
.
objects
.
get
(
key
=
parent_key
)
...
...
@@ -136,25 +132,33 @@ class Node(models.Model):
@parent.setter
def
parent
(
self
,
parent
):
self
.
key
=
parent
.
get_next_child_key
()
@property
def
ancestor
(
self
):
_key
=
self
.
key
.
split
(
':'
)
ancestor_keys
=
[]
if
self
.
is_node
:
children
=
self
.
get_all_children
()
old_key
=
self
.
key
with
transaction
.
atomic
():
self
.
key
=
parent
.
get_next_child_key
()
for
child
in
children
:
child
.
key
=
child
.
key
.
replace
(
old_key
,
self
.
key
,
1
)
child
.
save
()
self
.
save
()
else
:
self
.
key
=
parent
.
key
+
':fake'
def
get_ancestor
(
self
,
with_self
=
False
):
if
self
.
is_root
():
return
[
self
.
__class__
.
root
()]
ancestor
=
self
.
__class__
.
objects
.
filter
(
key
=
'0'
)
return
ancestor
for
i
in
range
(
len
(
_key
)
-
1
):
_key
=
self
.
key
.
split
(
':'
)
if
not
with_self
:
_key
.
pop
()
ancestor_keys
=
[]
for
i
in
range
(
len
(
_key
)):
ancestor_keys
.
append
(
':'
.
join
(
_key
))
return
self
.
__class__
.
objects
.
filter
(
key__in
=
ancestor_keys
)
@property
def
ancestor_with_self
(
self
):
ancestor
=
list
(
self
.
ancestor
)
ancestor
.
insert
(
0
,
self
)
_key
.
pop
()
ancestor
=
self
.
__class__
.
objects
.
filter
(
key__in
=
ancestor_keys
)
.
order_by
(
'key'
)
return
ancestor
@classmethod
...
...
@@ -162,4 +166,6 @@ class Node(models.Model):
obj
,
created
=
cls
.
objects
.
get_or_create
(
key
=
'0'
,
defaults
=
{
"key"
:
'0'
,
'value'
:
"ROOT"
}
)
print
(
obj
)
return
obj
apps/assets/serializers/asset.py
View file @
99c4875d
...
...
@@ -12,35 +12,10 @@ __all__ = [
]
class
NodeTMPSerializer
(
serializers
.
ModelSerializer
):
parent
=
serializers
.
SerializerMethodField
()
assets_amount
=
serializers
.
SerializerMethodField
()
class
Meta
:
model
=
Node
fields
=
[
'id'
,
'key'
,
'value'
,
'parent'
,
'assets_amount'
,
'is_node'
]
list_serializer_class
=
BulkListSerializer
@staticmethod
def
get_parent
(
obj
):
return
obj
.
parent
.
id
@staticmethod
def
get_assets_amount
(
obj
):
return
obj
.
get_all_assets
()
.
count
()
def
get_fields
(
self
):
fields
=
super
()
.
get_fields
()
field
=
fields
[
"key"
]
field
.
required
=
False
return
fields
class
AssetSerializer
(
BulkSerializerMixin
,
serializers
.
ModelSerializer
):
"""
资产的数据结构
"""
class
Meta
:
model
=
Asset
list_serializer_class
=
BulkListSerializer
...
...
apps/assets/serializers/node.py
View file @
99c4875d
...
...
@@ -9,7 +9,7 @@ from .asset import AssetGrantedSerializer
__all__
=
[
'NodeSerializer'
,
"NodeGrantedSerializer"
,
"NodeAddChildrenSerializer"
,
"NodeAssetsSerializer"
,
"NodeCurrentSerializer"
,
"NodeAssetsSerializer"
,
]
...
...
@@ -64,11 +64,11 @@ class NodeSerializer(serializers.ModelSerializer):
@staticmethod
def
get_parent
(
obj
):
return
obj
.
parent
.
id
return
obj
.
parent
.
id
if
obj
.
is_node
else
obj
.
parent_id
@staticmethod
def
get_assets_amount
(
obj
):
return
obj
.
get_all_assets
()
.
count
()
return
obj
.
get_all_assets
()
.
count
()
if
obj
.
is_node
else
0
def
get_fields
(
self
):
fields
=
super
()
.
get_fields
()
...
...
@@ -77,12 +77,6 @@ class NodeSerializer(serializers.ModelSerializer):
return
fields
class
NodeCurrentSerializer
(
NodeSerializer
):
@staticmethod
def
get_assets_amount
(
obj
):
return
obj
.
get_current_assets
()
.
count
()
class
NodeAssetsSerializer
(
serializers
.
ModelSerializer
):
assets
=
serializers
.
PrimaryKeyRelatedField
(
many
=
True
,
queryset
=
Asset
.
objects
.
all
())
...
...
apps/assets/signals_handler.py
View file @
99c4875d
...
...
@@ -63,22 +63,26 @@ def on_system_user_assets_change(sender, instance=None, **kwargs):
@receiver
(
m2m_changed
,
sender
=
Asset
.
nodes
.
through
)
def
on_asset_node_changed
(
sender
,
instance
=
None
,
**
kwargs
):
if
isinstance
(
instance
,
Asset
)
and
kwargs
[
'action'
]
==
'post_add'
:
logger
.
debug
(
"Asset node change signal received"
)
nodes
=
kwargs
[
'model'
]
.
objects
.
filter
(
pk__in
=
kwargs
[
'pk_set'
])
system_users_assets
=
defaultdict
(
set
)
system_users
=
SystemUser
.
objects
.
filter
(
nodes__in
=
nodes
)
for
system_user
in
system_users
:
system_users_assets
[
system_user
]
.
update
({
instance
})
for
system_user
,
assets
in
system_users_assets
.
items
():
system_user
.
assets
.
add
(
*
tuple
(
assets
))
if
isinstance
(
instance
,
Asset
):
if
kwargs
[
'action'
]
==
'post_add'
:
logger
.
debug
(
"Asset node change signal received"
)
nodes
=
kwargs
[
'model'
]
.
objects
.
filter
(
pk__in
=
kwargs
[
'pk_set'
])
system_users_assets
=
defaultdict
(
set
)
system_users
=
SystemUser
.
objects
.
filter
(
nodes__in
=
nodes
)
# 清理节点缓存
for
system_user
in
system_users
:
system_users_assets
[
system_user
]
.
update
({
instance
})
for
system_user
,
assets
in
system_users_assets
.
items
():
system_user
.
assets
.
add
(
*
tuple
(
assets
))
@receiver
(
m2m_changed
,
sender
=
Asset
.
nodes
.
through
)
def
on_node_assets_changed
(
sender
,
instance
=
None
,
**
kwargs
):
if
isinstance
(
instance
,
Node
)
and
kwargs
[
'action'
]
==
'post_add'
:
logger
.
debug
(
"Node assets change signal received"
)
if
isinstance
(
instance
,
Node
):
assets
=
kwargs
[
'model'
]
.
objects
.
filter
(
pk__in
=
kwargs
[
'pk_set'
])
system_users
=
SystemUser
.
objects
.
filter
(
nodes
=
instance
)
for
system_user
in
system_users
:
system_user
.
assets
.
add
(
*
tuple
(
assets
))
if
kwargs
[
'action'
]
==
'post_add'
:
logger
.
debug
(
"Node assets change signal received"
)
# 重新关联系统用户和资产的关系
system_users
=
SystemUser
.
objects
.
filter
(
nodes
=
instance
)
for
system_user
in
system_users
:
system_user
.
assets
.
add
(
*
tuple
(
assets
))
apps/assets/templates/assets/_asset_list_modal.html
View file @
99c4875d
...
...
@@ -59,7 +59,7 @@ var zTree2, asset_table2 = 0;
function
initTable2
()
{
var
options
=
{
ele
:
$
(
'#asset_list_modal_table'
),
ajax_url
:
'{% url "api-assets:asset-list" %}'
,
ajax_url
:
'{% url "api-assets:asset-list" %}
?show_current_asset=1
'
,
columns
:
[
{
data
:
"id"
},
{
data
:
"hostname"
},
{
data
:
"ip"
}
],
...
...
apps/assets/templates/assets/asset_list.html
View file @
99c4875d
...
...
@@ -399,8 +399,7 @@ function initTree() {
};
var
zNodes
=
[];
var
query_params
=
{
'show_current_asset'
:
getCookie
(
'show_current_asset'
)};
$
.
get
(
"{% url 'api-assets:node-list' %}"
,
query_params
,
function
(
data
,
status
){
$
.
get
(
"{% url 'api-assets:node-list' %}"
,
function
(
data
,
status
){
$
.
each
(
data
,
function
(
index
,
value
)
{
value
[
"pId"
]
=
value
[
"parent"
];
if
(
value
[
"key"
]
===
"0"
)
{
...
...
@@ -436,7 +435,7 @@ $(document).ready(function(){
initTable
();
initTree
();
if
(
getCookie
(
'show_current_asset'
)
===
'
yes
'
){
if
(
getCookie
(
'show_current_asset'
)
===
'
1
'
){
$
(
'#show_all_asset'
).
css
(
'display'
,
'inline-block'
);
}
else
{
...
...
@@ -564,7 +563,7 @@ $(document).ready(function(){
hideRMenu
();
$
(
this
).
css
(
'display'
,
'none'
);
$
(
'#show_all_asset'
).
css
(
'display'
,
'inline-block'
);
setCookie
(
'show_current_asset'
,
'
yes
'
);
setCookie
(
'show_current_asset'
,
'
1
'
);
location
.
reload
();
})
.
on
(
'click'
,
'.btn-show-all-asset'
,
function
(){
...
...
apps/assets/urls/api_urls.py
View file @
99c4875d
...
...
@@ -23,8 +23,6 @@ urlpatterns = [
api
.
AssetRefreshHardwareApi
.
as_view
(),
name
=
'asset-refresh'
),
url
(
r'^v1/assets/(?P<pk>[0-9a-zA-Z\-]{36})/alive/$'
,
api
.
AssetAdminUserTestApi
.
as_view
(),
name
=
'asset-alive-test'
),
url
(
r'^v1/assets/user-assets/$'
,
api
.
UserAssetListView
.
as_view
(),
name
=
'user-asset-list'
),
url
(
r'^v1/admin-user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/$'
,
api
.
ReplaceNodesAdminUserApi
.
as_view
(),
name
=
'replace-nodes-admin-user'
),
url
(
r'^v1/admin-user/(?P<pk>[0-9a-zA-Z\-]{36})/auth/$'
,
...
...
@@ -35,17 +33,26 @@ urlpatterns = [
api
.
SystemUserPushApi
.
as_view
(),
name
=
'system-user-push'
),
url
(
r'^v1/system-user/(?P<pk>[0-9a-zA-Z\-]{36})/connective/$'
,
api
.
SystemUserTestConnectiveApi
.
as_view
(),
name
=
'system-user-connective'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/children/$'
,
api
.
NodeChildrenApi
.
as_view
(),
name
=
'node-children'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/children/$'
,
api
.
NodeChildrenApi
.
as_view
(),
name
=
'node-children'
),
url
(
r'^v1/nodes/children/$'
,
api
.
NodeChildrenApi
.
as_view
(),
name
=
'node-children-2'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/children/add/$'
,
api
.
NodeAddChildrenApi
.
as_view
(),
name
=
'node-add-children'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$'
,
api
.
NodeAssetsApi
.
as_view
(),
name
=
'node-assets'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/add/$'
,
api
.
NodeAddAssetsApi
.
as_view
(),
name
=
'node-add-assets'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/replace/$'
,
api
.
NodeReplaceAssetsApi
.
as_view
(),
name
=
'node-replace-assets'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/remove/$'
,
api
.
NodeRemoveAssetsApi
.
as_view
(),
name
=
'node-remove-assets'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/refresh-hardware-info/$'
,
api
.
RefreshNodeHardwareInfoApi
.
as_view
(),
name
=
'node-refresh-hardware-info'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/test-connective/$'
,
api
.
TestNodeConnectiveApi
.
as_view
(),
name
=
'node-test-connective'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/children/add/$'
,
api
.
NodeAddChildrenApi
.
as_view
(),
name
=
'node-add-children'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$'
,
api
.
NodeAssetsApi
.
as_view
(),
name
=
'node-assets'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/add/$'
,
api
.
NodeAddAssetsApi
.
as_view
(),
name
=
'node-add-assets'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/replace/$'
,
api
.
NodeReplaceAssetsApi
.
as_view
(),
name
=
'node-replace-assets'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/remove/$'
,
api
.
NodeRemoveAssetsApi
.
as_view
(),
name
=
'node-remove-assets'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/refresh-hardware-info/$'
,
api
.
RefreshNodeHardwareInfoApi
.
as_view
(),
name
=
'node-refresh-hardware-info'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/test-connective/$'
,
api
.
TestNodeConnectiveApi
.
as_view
(),
name
=
'node-test-connective'
),
url
(
r'^v1/gateway/(?P<pk>[0-9a-zA-Z\-]{36})/test-connective/$'
,
api
.
GatewayTestConnectionApi
.
as_view
(),
name
=
'test-gateway-connective'
),
url
(
r'^v1/gateway/(?P<pk>[0-9a-zA-Z\-]{36})/test-connective/$'
,
api
.
GatewayTestConnectionApi
.
as_view
(),
name
=
'test-gateway-connective'
),
]
urlpatterns
+=
router
.
urls
...
...
apps/assets/utils.py
View file @
99c4875d
# ~*~ coding: utf-8 ~*~
#
import
os
import
paramiko
from
paramiko.ssh_exception
import
SSHException
from
common.utils
import
get_object_or_none
from
.models
import
Asset
,
SystemUser
,
Label
...
...
@@ -49,22 +50,23 @@ def test_gateway_connectability(gateway):
"""
client
=
paramiko
.
SSHClient
()
client
.
set_missing_host_key_policy
(
paramiko
.
AutoAddPolicy
())
proxy_command
=
[
"ssh"
,
"{}@{}"
.
format
(
gateway
.
username
,
gateway
.
ip
),
"-p"
,
str
(
gateway
.
port
),
"-W"
,
"127.0.0.1:{}"
.
format
(
gateway
.
port
),
]
if
gateway
.
password
:
proxy_command
.
insert
(
0
,
"sshpass -p '{}'"
.
format
(
gateway
.
password
))
if
gateway
.
private_key
:
proxy_command
.
append
(
"-i {}"
.
format
(
gateway
.
private_key_file
))
proxy
=
paramiko
.
SSHClient
()
proxy
.
load_host_keys
(
os
.
path
.
expanduser
(
'~/.ssh/known_hosts'
))
proxy
.
set_missing_host_key_policy
(
paramiko
.
AutoAddPolicy
())
try
:
sock
=
paramiko
.
ProxyCommand
(
" "
.
join
(
proxy_command
))
except
paramiko
.
ProxyCommandFailure
as
e
:
proxy
.
connect
(
gateway
.
ip
,
username
=
gateway
.
username
,
password
=
gateway
.
password
,
pkey
=
gateway
.
private_key_obj
)
except
(
paramiko
.
AuthenticationException
,
paramiko
.
BadAuthenticationType
,
SSHException
)
as
e
:
return
False
,
str
(
e
)
sock
=
proxy
.
get_transport
()
.
open_channel
(
'direct-tcpip'
,
(
'127.0.0.1'
,
gateway
.
port
),
(
'127.0.0.1'
,
0
)
)
try
:
client
.
connect
(
"127.0.0.1"
,
port
=
gateway
.
port
,
username
=
gateway
.
username
,
...
...
apps/common/api.py
View file @
99c4875d
...
...
@@ -21,23 +21,13 @@ class MailTestingAPI(APIView):
serializer
=
self
.
serializer_class
(
data
=
request
.
data
)
if
serializer
.
is_valid
():
email_host_user
=
serializer
.
validated_data
[
"EMAIL_HOST_USER"
]
kwargs
=
{
"host"
:
serializer
.
validated_data
[
"EMAIL_HOST"
],
"port"
:
serializer
.
validated_data
[
"EMAIL_PORT"
],
"username"
:
serializer
.
validated_data
[
"EMAIL_HOST_USER"
],
"password"
:
serializer
.
validated_data
[
"EMAIL_HOST_PASSWORD"
],
"use_ssl"
:
serializer
.
validated_data
[
"EMAIL_USE_SSL"
],
"use_tls"
:
serializer
.
validated_data
[
"EMAIL_USE_TLS"
]
}
connection
=
get_connection
(
timeout
=
5
,
**
kwargs
)
for
k
,
v
in
serializer
.
validated_data
.
items
():
if
k
.
startswith
(
'EMAIL'
):
setattr
(
settings
,
k
,
v
)
try
:
connection
.
open
()
except
Exception
as
e
:
return
Response
({
"error"
:
str
(
e
)},
status
=
401
)
try
:
send_mail
(
"Test"
,
"Test smtp setting"
,
email_host_user
,
[
email_host_user
],
connection
=
connection
)
subject
=
"Test"
message
=
"Test smtp setting"
send_mail
(
subject
,
message
,
email_host_user
,
[
email_host_user
])
except
Exception
as
e
:
return
Response
({
"error"
:
str
(
e
)},
status
=
401
)
...
...
apps/common/tasks.py
View file @
99c4875d
...
...
@@ -2,6 +2,7 @@ from django.core.mail import send_mail
from
django.conf
import
settings
from
celery
import
shared_task
from
.utils
import
get_logger
from
.models
import
Setting
logger
=
get_logger
(
__file__
)
...
...
@@ -21,6 +22,10 @@ def send_mail_async(*args, **kwargs):
Example:
send_mail_sync.delay(subject, message, recipient_list, fail_silently=False, html_message=None)
"""
configs
=
Setting
.
objects
.
filter
(
name__startswith
=
'EMAIL'
)
for
config
in
configs
:
setattr
(
settings
,
config
.
name
,
config
.
cleaned_value
)
if
len
(
args
)
==
3
:
args
=
list
(
args
)
args
[
0
]
=
settings
.
EMAIL_SUBJECT_PREFIX
+
args
[
0
]
...
...
apps/common/utils.py
View file @
99c4875d
...
...
@@ -16,6 +16,7 @@ import calendar
import
threading
from
io
import
StringIO
import
uuid
from
functools
import
wraps
import
paramiko
import
sshpubkeys
...
...
@@ -395,3 +396,17 @@ class TeeObj:
def
close
(
self
):
self
.
file_obj
.
close
()
def
with_cache
(
func
):
cache
=
{}
key
=
"_{}.{}"
.
format
(
func
.
__module__
,
func
.
__name__
)
@wraps
(
func
)
def
wrapper
(
*
args
,
**
kwargs
):
cached
=
cache
.
get
(
key
)
if
cached
:
return
cached
res
=
func
(
*
args
,
**
kwargs
)
cache
[
key
]
=
res
return
res
return
wrapper
apps/perms/api.py
View file @
99c4875d
...
...
@@ -41,11 +41,11 @@ class AssetPermissionViewSet(viewsets.ModelViewSet):
asset
=
get_object_or_404
(
Asset
,
pk
=
asset_id
)
permissions
=
set
(
queryset
.
filter
(
assets
=
asset
))
for
node
in
asset
.
nodes
.
all
():
inherit_nodes
.
update
(
set
(
node
.
ancestor_with_self
))
inherit_nodes
.
update
(
set
(
node
.
get_ancestor
(
with_self
=
True
)
))
elif
node_id
:
node
=
get_object_or_404
(
Node
,
pk
=
node_id
)
permissions
=
set
(
queryset
.
filter
(
nodes
=
node
))
inherit_nodes
=
node
.
ancestor
inherit_nodes
=
node
.
get_ancestor
()
for
n
in
inherit_nodes
:
_permissions
=
queryset
.
filter
(
nodes
=
n
)
...
...
@@ -70,7 +70,8 @@ class UserGrantedAssetsApi(ListAPIView):
else
:
user
=
self
.
request
.
user
for
k
,
v
in
AssetPermissionUtil
.
get_user_assets
(
user
)
.
items
():
util
=
AssetPermissionUtil
(
user
)
for
k
,
v
in
util
.
get_assets
()
.
items
():
if
k
.
is_unixlike
():
system_users_granted
=
[
s
for
s
in
v
if
s
.
protocol
==
'ssh'
]
else
:
...
...
@@ -95,7 +96,8 @@ class UserGrantedNodesApi(ListAPIView):
user
=
get_object_or_404
(
User
,
id
=
user_id
)
else
:
user
=
self
.
request
.
user
nodes
=
AssetPermissionUtil
.
get_user_nodes_with_assets
(
user
)
util
=
AssetPermissionUtil
(
user
)
nodes
=
util
.
get_nodes_with_assets
()
return
nodes
.
keys
()
def
get_permissions
(
self
):
...
...
@@ -116,7 +118,8 @@ class UserGrantedNodesWithAssetsApi(ListAPIView):
else
:
user
=
get_object_or_404
(
User
,
id
=
user_id
)
nodes
=
AssetPermissionUtil
.
get_user_nodes_with_assets
(
user
)
util
=
AssetPermissionUtil
(
user
)
nodes
=
util
.
get_nodes_with_assets
()
for
node
,
_assets
in
nodes
.
items
():
assets
=
_assets
.
keys
()
for
k
,
v
in
_assets
.
items
():
...
...
@@ -147,13 +150,9 @@ class UserGrantedNodeAssetsApi(ListAPIView):
user
=
get_object_or_404
(
User
,
id
=
user_id
)
else
:
user
=
self
.
request
.
user
nodes
=
AssetPermissionUtil
.
get_user_nodes_with_assets
(
user
)
node
=
get_object_or_none
(
Node
,
id
=
node_id
)
if
not
node
:
unnode
=
[
node
for
node
in
nodes
if
node
.
name
==
'Unnode'
]
node
=
unnode
[
0
]
if
unnode
else
None
util
=
AssetPermissionUtil
(
user
)
node
=
get_object_or_404
(
Node
,
id
=
node_id
)
nodes
=
util
.
get_nodes_with_assets
()
assets
=
nodes
.
get
(
node
,
[])
for
asset
,
system_users
in
assets
.
items
():
asset
.
system_users_granted
=
system_users
...
...
@@ -177,7 +176,8 @@ class UserGroupGrantedAssetsApi(ListAPIView):
return
queryset
user_group
=
get_object_or_404
(
UserGroup
,
id
=
user_group_id
)
assets
=
AssetPermissionUtil
.
get_user_group_assets
(
user_group
)
util
=
AssetPermissionUtil
(
user_group
)
assets
=
util
.
get_assets
()
for
k
,
v
in
assets
.
items
():
k
.
system_users_granted
=
v
queryset
.
append
(
k
)
...
...
@@ -194,7 +194,8 @@ class UserGroupGrantedNodesApi(ListAPIView):
if
group_id
:
group
=
get_object_or_404
(
UserGroup
,
id
=
group_id
)
nodes
=
AssetPermissionUtil
.
get_user_group_nodes_with_assets
(
group
)
util
=
AssetPermissionUtil
(
group
)
nodes
=
util
.
get_nodes_with_assets
()
return
nodes
.
keys
()
return
queryset
...
...
@@ -211,7 +212,8 @@ class UserGroupGrantedNodesWithAssetsApi(ListAPIView):
return
queryset
user_group
=
get_object_or_404
(
UserGroup
,
id
=
user_group_id
)
nodes
=
AssetPermissionUtil
.
get_user_group_nodes_with_assets
(
user_group
)
util
=
AssetPermissionUtil
(
user_group
)
nodes
=
util
.
get_nodes_with_assets
()
for
node
,
_assets
in
nodes
.
items
():
assets
=
_assets
.
keys
()
for
asset
,
system_users
in
_assets
.
items
():
...
...
@@ -231,7 +233,8 @@ class UserGroupGrantedNodeAssetsApi(ListAPIView):
user_group
=
get_object_or_404
(
UserGroup
,
id
=
user_group_id
)
node
=
get_object_or_404
(
Node
,
id
=
node_id
)
nodes
=
AssetPermissionUtil
.
get_user_group_nodes_with_assets
(
user_group
)
util
=
AssetPermissionUtil
(
user_group
)
nodes
=
util
.
get_nodes_with_assets
()
assets
=
nodes
.
get
(
node
,
[])
for
asset
,
system_users
in
assets
.
items
():
asset
.
system_users_granted
=
system_users
...
...
@@ -251,7 +254,8 @@ class ValidateUserAssetPermissionView(APIView):
asset
=
get_object_or_404
(
Asset
,
id
=
asset_id
)
system_user
=
get_object_or_404
(
SystemUser
,
id
=
system_id
)
assets_granted
=
AssetPermissionUtil
.
get_user_assets
(
user
)
util
=
AssetPermissionUtil
(
user
)
assets_granted
=
util
.
get_assets
()
if
system_user
in
assets_granted
.
get
(
asset
,
[]):
return
Response
({
'msg'
:
True
},
status
=
200
)
else
:
...
...
apps/perms/utils.py
View file @
99c4875d
# coding: utf-8
from
__future__
import
absolute_import
,
unicode_literals
import
collections
from
collections
import
defaultdict
from
django.utils
import
timezone
import
copy
from
django.db.models
import
Q
from
common.utils
import
set_or_append_attr_bulk
,
get_logger
from
common.utils
import
get_logger
from
.models
import
AssetPermission
from
.hands
import
Node
logger
=
get_logger
(
__file__
)
class
Tree
:
def
__init__
(
self
):
self
.
__all_nodes
=
list
(
Node
.
objects
.
all
())
self
.
__node_asset_map
=
defaultdict
(
set
)
self
.
nodes
=
defaultdict
(
dict
)
self
.
root
=
Node
.
root
()
self
.
init_node_asset_map
()
def
init_node_asset_map
(
self
):
for
node
in
self
.
__all_nodes
:
assets
=
node
.
get_assets
()
.
values_list
(
'id'
,
flat
=
True
)
for
asset
in
assets
:
self
.
__node_asset_map
[
str
(
asset
)]
.
add
(
node
)
def
get_user_permissions
(
user
,
include_group
=
True
):
if
include_group
:
groups
=
user
.
groups
.
all
()
arg
=
Q
(
users
=
user
)
|
Q
(
user_groups
=
groups
)
else
:
arg
=
Q
(
users
=
user
)
return
AssetPermission
.
objects
.
all
()
.
valid
()
.
filter
(
arg
)
def
add_asset
(
self
,
asset
,
system_users
):
nodes
=
self
.
__node_asset_map
.
get
(
str
(
asset
.
id
),
[])
self
.
add_nodes
(
nodes
)
for
node
in
nodes
:
self
.
nodes
[
node
][
asset
]
.
update
(
system_users
)
def
add_node
(
self
,
node
):
if
node
in
self
.
nodes
:
return
else
:
self
.
nodes
[
node
]
=
defaultdict
(
set
)
if
node
.
key
==
self
.
root
.
key
:
return
parent_key
=
':'
.
join
(
node
.
key
.
split
(
':'
)[:
-
1
])
for
n
in
self
.
__all_nodes
:
if
n
.
key
==
parent_key
:
self
.
add_node
(
n
)
break
def
get_user_group_permissions
(
user_group
):
return
AssetPermission
.
objects
.
all
()
.
valid
()
.
filter
(
user_groups
=
user_group
)
def
add_nodes
(
self
,
nodes
):
for
node
in
nodes
:
self
.
add_node
(
node
)
def
get_asset_permissions
(
asset
,
include_node
=
True
):
if
include_node
:
nodes
=
asset
.
get_all_nodes
(
flat
=
True
)
arg
=
Q
(
assets
=
asset
)
|
Q
(
nodes
=
nodes
)
else
:
arg
=
Q
(
assets
=
asset
)
return
AssetPermission
.
objects
.
all
()
.
valid
()
.
filter
(
arg
)
class
AssetPermissionUtil
:
@staticmethod
def
get_user_permissions
(
user
):
return
AssetPermission
.
objects
.
all
()
.
valid
()
.
filter
(
users
=
user
)
@staticmethod
def
get_user_group_permissions
(
user_group
):
return
AssetPermission
.
objects
.
all
()
.
valid
()
.
filter
(
user_groups
=
user_group
)
def
get_node_permissions
(
node
):
return
AssetPermission
.
objects
.
all
()
.
valid
()
.
filter
(
nodes
=
node
)
@staticmethod
def
get_asset_permissions
(
asset
):
return
AssetPermission
.
objects
.
all
()
.
valid
()
.
filter
(
assets
=
asset
)
@staticmethod
def
get_node_permissions
(
node
):
return
AssetPermission
.
objects
.
all
()
.
valid
()
.
filter
(
nodes
=
node
)
def
get_system_user_permissions
(
system_user
):
return
AssetPermission
.
objects
.
valid
()
.
all
()
.
filter
(
system_users
=
system_user
)
@staticmethod
def
get_system_user_permissions
(
system_user
):
return
AssetPermission
.
objects
.
valid
()
.
all
()
.
filter
(
system_users
=
system_user
)
@classmethod
def
get_user_group_nodes
(
cls
,
group
):
class
AssetPermissionUtil
:
get_permissions_map
=
{
"User"
:
get_user_permissions
,
"UserGroup"
:
get_user_group_permissions
,
"Asset"
:
get_asset_permissions
,
"Node"
:
get_node_permissions
,
"SystemUser"
:
get_node_permissions
,
}
def
__init__
(
self
,
obj
):
self
.
object
=
obj
self
.
_permissions
=
None
@property
def
permissions
(
self
):
if
self
.
_permissions
:
return
self
.
_permissions
object_cls
=
self
.
object
.
__class__
.
__name__
func
=
self
.
get_permissions_map
[
object_cls
]
permissions
=
func
(
self
.
object
)
self
.
_permissions
=
permissions
return
permissions
def
get_nodes_direct
(
self
):
"""
返回用户/组授权规则直接关联的节点
:return: {node1: set(system_user1,)}
"""
nodes
=
defaultdict
(
set
)
permissions
=
cls
.
get_user_group_permissions
(
group
)
permissions
=
self
.
permissions
.
prefetch_related
(
'nodes'
,
'system_users'
)
for
perm
in
permissions
:
_nodes
=
perm
.
nodes
.
all
()
_system_users
=
perm
.
system_users
.
all
()
set_or_append_attr_bulk
(
_nodes
,
'permission'
,
perm
.
id
)
for
node
in
_nodes
:
nodes
[
node
]
.
update
(
set
(
_system_users
))
for
node
in
perm
.
nodes
.
all
():
nodes
[
node
]
.
update
(
perm
.
system_users
.
all
())
return
nodes
@classmethod
def
get_user_group_assets_direct
(
cls
,
group
):
assets
=
defaultdict
(
set
)
permissions
=
cls
.
get_user_group_permissions
(
group
)
for
perm
in
permissions
:
_assets
=
perm
.
assets
.
all
()
.
valid
()
_system_users
=
perm
.
system_users
.
all
()
set_or_append_attr_bulk
(
_assets
,
'permission'
,
perm
.
id
)
for
asset
in
_assets
:
assets
[
asset
]
.
update
(
set
(
_system_users
))
return
assets
@classmethod
def
get_user_group_nodes_assets
(
cls
,
group
):
assets
=
defaultdict
(
set
)
nodes
=
cls
.
get_user_group_nodes
(
group
)
for
node
,
_system_users
in
nodes
.
items
():
_assets
=
node
.
get_all_valid_assets
()
set_or_append_attr_bulk
(
_assets
,
'inherit_node'
,
node
.
id
)
set_or_append_attr_bulk
(
_assets
,
'permission'
,
getattr
(
node
,
'permission'
,
None
))
for
asset
in
_assets
:
assets
[
asset
]
.
update
(
set
(
_system_users
))
return
assets
@classmethod
def
get_user_group_assets
(
cls
,
group
):
assets
=
defaultdict
(
set
)
_assets
=
cls
.
get_user_group_assets_direct
(
group
)
_nodes_assets
=
cls
.
get_user_group_nodes_assets
(
group
)
for
asset
,
_system_users
in
_assets
.
items
():
assets
[
asset
]
.
update
(
set
(
_system_users
))
for
asset
,
_system_users
in
_nodes_assets
.
items
():
assets
[
asset
]
.
update
(
set
(
_system_users
))
return
assets
@classmethod
def
get_user_group_nodes_with_assets
(
cls
,
group
):
def
get_assets_direct
(
self
):
"""
:param group:
:return: {
node: {asset: set(su1, su2)}
}
返回用户授权规则直接关联的资产
:return: {
asset1: set(system_user1,)
}
"""
_assets
=
cls
.
get_user_group_assets
(
group
)
tree
=
Tree
()
for
asset
,
_system_users
in
_assets
.
items
():
_nodes
=
asset
.
get_nodes
()
tree
.
add_nodes
(
_nodes
)
for
node
in
_nodes
:
tree
.
nodes
[
node
][
asset
]
.
update
(
_system_users
)
return
tree
.
nodes
@classmethod
def
get_user_assets_direct
(
cls
,
user
):
assets
=
defaultdict
(
set
)
permissions
=
list
(
cls
.
get_user_permissions
(
user
)
)
permissions
=
self
.
permissions
.
prefetch_related
(
'assets'
,
'system_users'
)
for
perm
in
permissions
:
_assets
=
perm
.
assets
.
all
()
.
valid
()
_system_users
=
perm
.
system_users
.
all
()
set_or_append_attr_bulk
(
_assets
,
'permission'
,
perm
.
id
)
for
asset
in
_assets
:
assets
[
asset
]
.
update
(
set
(
_system_users
))
for
asset
in
perm
.
assets
.
all
()
.
valid
()
.
prefetch_related
(
'nodes'
):
assets
[
asset
]
.
update
(
perm
.
system_users
.
all
())
return
assets
@classmethod
def
get_user_nodes_direct
(
cls
,
user
):
nodes
=
defaultdict
(
set
)
permissions
=
cls
.
get_user_permissions
(
user
)
for
perm
in
permissions
:
_nodes
=
perm
.
nodes
.
all
()
_system_users
=
perm
.
system_users
.
all
()
set_or_append_attr_bulk
(
_nodes
,
'permission'
,
perm
.
id
)
for
node
in
_nodes
:
nodes
[
node
]
.
update
(
set
(
_system_users
))
return
nodes
@classmethod
def
get_user_nodes_inherit_group
(
cls
,
user
):
nodes
=
defaultdict
(
set
)
groups
=
user
.
groups
.
all
()
for
group
in
groups
:
_nodes
=
cls
.
get_user_group_nodes
(
group
)
for
node
,
system_users
in
_nodes
.
items
():
nodes
[
node
]
.
update
(
set
(
system_users
))
return
nodes
@classmethod
def
get_user_nodes
(
cls
,
user
):
nodes
=
cls
.
get_user_nodes_direct
(
user
)
nodes_inherit
=
cls
.
get_user_nodes_inherit_group
(
user
)
for
node
,
system_users
in
nodes_inherit
.
items
():
nodes
[
node
]
.
update
(
set
(
system_users
))
return
nodes
@classmethod
def
get_user_nodes_assets_direct
(
cls
,
user
):
assets
=
defaultdict
(
set
)
nodes
=
cls
.
get_user_nodes_direct
(
user
)
for
node
,
_system_users
in
nodes
.
items
():
_assets
=
node
.
get_all_valid_assets
()
set_or_append_attr_bulk
(
_assets
,
'inherit_node'
,
node
.
id
)
set_or_append_attr_bulk
(
_assets
,
'permission'
,
getattr
(
node
,
'permission'
,
None
))
def
get_assets
(
self
):
assets
=
self
.
get_assets_direct
()
nodes
=
self
.
get_nodes_direct
()
for
node
,
system_users
in
nodes
.
items
():
_assets
=
node
.
get_all_assets
()
.
valid
()
.
prefetch_related
(
'nodes'
)
for
asset
in
_assets
:
assets
[
asset
]
.
update
(
set
(
_system_users
))
if
isinstance
(
asset
,
Node
):
print
(
_assets
)
assets
[
asset
]
.
update
(
system_users
)
return
assets
@classmethod
def
get_user_assets_inherit_group
(
cls
,
user
):
assets
=
defaultdict
(
set
)
for
group
in
user
.
groups
.
all
():
_assets
=
cls
.
get_user_group_assets
(
group
)
set_or_append_attr_bulk
(
_assets
,
'inherit_group'
,
group
.
id
)
for
asset
,
_system_users
in
_assets
.
items
():
assets
[
asset
]
.
update
(
_system_users
)
return
assets
@classmethod
def
get_user_assets
(
cls
,
user
):
assets
=
defaultdict
(
set
)
_assets_direct
=
cls
.
get_user_assets_direct
(
user
)
_nodes_assets_direct
=
cls
.
get_user_nodes_assets_direct
(
user
)
_assets_inherit_group
=
cls
.
get_user_assets_inherit_group
(
user
)
for
asset
,
_system_users
in
_assets_direct
.
items
():
assets
[
asset
]
.
update
(
_system_users
)
for
asset
,
_system_users
in
_nodes_assets_direct
.
items
():
assets
[
asset
]
.
update
(
_system_users
)
for
asset
,
_system_users
in
_assets_inherit_group
.
items
():
assets
[
asset
]
.
update
(
_system_users
)
return
assets
@classmethod
def
get_user_nodes_with_assets
(
cls
,
user
):
"""
:param user:
:return: {node: {asset: set(su1, su2)}}
"""
tree
=
Tree
()
_assets
=
cls
.
get_user_assets
(
user
)
for
asset
,
_system_users
in
_assets
.
items
():
tree
.
add_asset
(
asset
,
_system_users
)
# _nodes = asset.get_nodes()
# tree.add_nodes(_nodes)
# for node in _nodes:
# tree.nodes[node][asset].update(_system_users)
return
tree
.
nodes
@classmethod
def
get_system_user_assets
(
cls
,
system_user
):
assets
=
set
()
permissions
=
cls
.
get_system_user_permissions
(
system_user
)
for
perm
in
permissions
:
assets
.
update
(
set
(
perm
.
assets
.
all
()
.
valid
()))
nodes
=
perm
.
nodes
.
all
()
for
node
in
nodes
:
assets
.
update
(
set
(
node
.
get_all_valid_assets
()))
return
assets
@classmethod
def
get_node_system_users
(
cls
,
node
):
system_users
=
set
()
permissions
=
cls
.
get_node_permissions
(
node
)
for
perm
in
permissions
:
system_users
.
update
(
perm
.
system_users
.
all
())
return
system_users
# Abandon
class
NodePermissionUtil
:
"""
"""
@staticmethod
def
get_user_group_permissions
(
user_group
):
return
user_group
.
nodepermission_set
.
all
()
\
.
filter
(
is_active
=
True
)
\
.
filter
(
date_expired__gt
=
timezone
.
now
())
@staticmethod
def
get_system_user_permissions
(
system_user
):
return
system_user
.
nodepermission_set
.
all
()
\
.
filter
(
is_active
=
True
)
\
.
filter
(
date_expired__gt
=
timezone
.
now
())
@classmethod
def
get_user_group_nodes
(
cls
,
user_group
):
"""
获取用户组授权的node和系统用户
:param user_group:
:return: {"node": set(systemuser1, systemuser2), ..}
"""
permissions
=
cls
.
get_user_group_permissions
(
user_group
)
nodes_directed
=
collections
.
defaultdict
(
set
)
for
perm
in
permissions
:
nodes_directed
[
perm
.
node
]
.
add
(
perm
.
system_user
)
nodes
=
copy
.
deepcopy
(
nodes_directed
)
for
node
,
system_users
in
nodes_directed
.
items
():
for
child
in
node
.
get_all_children_with_self
():
nodes
[
child
]
.
update
(
system_users
)
return
nodes
@classmethod
def
get_user_group_nodes_with_assets
(
cls
,
user_group
):
def
get_nodes_with_assets
(
self
):
"""
获取用户组授权的节点和系统用户,节点下带有
资产
:param user_group:
:return:
{"node": {"assets": "", "system_user": ""}, {}}
返回节点并且包含
资产
{"node": {"assets": set("system_user")}}
:return:
"""
nodes
=
cls
.
get_user_group_nodes
(
user_group
)
nodes_with_assets
=
dict
()
for
node
,
system_users
in
nodes
.
items
():
nodes_with_assets
[
node
]
=
{
'assets'
:
node
.
get_valid_assets
(),
'system_users'
:
system_users
}
return
nodes_with_assets
@classmethod
def
get_user_group_assets
(
cls
,
user_group
):
assets
=
collections
.
defaultdict
(
set
)
permissions
=
cls
.
get_user_group_permissions
(
user_group
)
for
perm
in
permissions
:
for
asset
in
perm
.
node
.
get_all_assets
():
assets
[
asset
]
.
add
(
perm
.
system_user
)
return
assets
@classmethod
def
get_user_nodes
(
cls
,
user
):
nodes
=
collections
.
defaultdict
(
set
)
groups
=
user
.
groups
.
all
()
for
group
in
groups
:
group_nodes
=
cls
.
get_user_group_nodes
(
group
)
for
node
,
system_users
in
group_nodes
.
items
():
nodes
[
node
]
.
update
(
system_users
)
assets
=
self
.
get_assets
()
nodes
=
defaultdict
(
dict
)
for
asset
,
system_users
in
assets
.
items
():
_nodes
=
asset
.
nodes
.
all
()
for
node
in
_nodes
:
if
asset
in
nodes
[
node
]:
nodes
[
node
][
asset
]
.
update
(
system_users
)
else
:
nodes
[
node
][
asset
]
=
system_users
return
nodes
@classmethod
def
get_user_nodes_with_assets
(
cls
,
user
):
nodes
=
cls
.
get_user_nodes
(
user
)
nodes_with_assets
=
dict
()
for
node
,
system_users
in
nodes
.
items
():
nodes_with_assets
[
node
]
=
{
'assets'
:
node
.
get_valid_assets
(),
'system_users'
:
system_users
}
return
nodes_with_assets
@classmethod
def
get_user_assets
(
cls
,
user
):
assets
=
collections
.
defaultdict
(
set
)
nodes_with_assets
=
cls
.
get_user_nodes_with_assets
(
user
)
for
v
in
nodes_with_assets
.
values
():
for
asset
in
v
[
'assets'
]:
assets
[
asset
]
.
update
(
v
[
'system_users'
])
return
assets
@classmethod
def
get_system_user_assets
(
cls
,
system_user
):
assets
=
set
()
permissions
=
cls
.
get_system_user_permissions
(
system_user
)
for
perm
in
permissions
:
assets
.
update
(
perm
.
node
.
get_all_assets
())
return
assets
apps/users/views/login.py
View file @
99c4875d
...
...
@@ -50,7 +50,9 @@ class UserLoginView(FormView):
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
if
request
.
user
.
is_staff
:
return
redirect
(
self
.
get_success_url
())
return
redirect
(
redirect_user_first_login_or_index
(
request
,
self
.
redirect_field_name
)
)
request
.
session
.
set_test_cookie
()
return
super
()
.
get
(
request
,
*
args
,
**
kwargs
)
...
...
jms
View file @
99c4875d
...
...
@@ -123,6 +123,7 @@ def start_gunicorn():
'gunicorn'
,
'jumpserver.wsgi'
,
'-b'
,
bind
,
'-w'
,
str
(
WORKERS
),
'-k'
,
'eventlet'
,
'--access-logformat'
,
log_format
,
'-p'
,
pid_file
,
]
...
...
utils/upgrade.sh
View file @
99c4875d
#!/bin/bash
if
grep
-q
'source
~/.
autoenv/activate.sh'
~/.bashrc
;
then
if
grep
-q
'source
/opt/
autoenv/activate.sh'
~/.bashrc
;
then
echo
-e
"
\0
33[31m 正在自动载入 python 环境
\0
33[0m"
else
echo
-e
"
\0
33[31m 不支持自动升级,请参考 http://docs.jumpserver.org/zh/docs/upgrade.html 手动升级
\0
33[0m"
...
...
@@ -40,5 +40,6 @@ git pull && pip install -r requirements/requirements.txt && cd utils && sh make_
cd
..
&&
./jms start all
-d
echo
-e
"
\0
33[31m 请检查jumpserver是否启动成功
\0
33[0m"
echo
-e
"
\0
33[31m 备份文件存放于
$jumpserver_backup
目录
\0
33[0m"
stty
erase ^?
exit
0
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