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
90b77fdb
Commit
90b77fdb
authored
Dec 18, 2018
by
ibuler
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dev' of github.com:jumpserver/jumpserver into dev
parents
068a2803
a609f170
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
255 additions
and
157 deletions
+255
-157
admin_user.py
apps/assets/api/admin_user.py
+22
-3
asset.py
apps/assets/api/asset.py
+3
-3
node.py
apps/assets/api/node.py
+2
-2
system_user.py
apps/assets/api/system_user.py
+8
-7
user.py
apps/assets/forms/user.py
+3
-3
asset.py
apps/assets/models/asset.py
+49
-64
base.py
apps/assets/models/base.py
+7
-0
user.py
apps/assets/models/user.py
+72
-27
asset.py
apps/assets/serializers/asset.py
+8
-2
system_user.py
apps/assets/serializers/system_user.py
+9
-7
signals_handler.py
apps/assets/signals_handler.py
+3
-3
tasks.py
apps/assets/tasks.py
+0
-0
admin_user_assets.html
apps/assets/templates/assets/admin_user_assets.html
+35
-12
system_user_asset.html
apps/assets/templates/assets/system_user_asset.html
+6
-4
system_user_list.html
apps/assets/templates/assets/system_user_list.html
+1
-1
api_urls.py
apps/assets/urls/api_urls.py
+8
-6
admin_user.py
apps/assets/views/admin_user.py
+1
-1
conf.py
apps/jumpserver/conf.py
+2
-1
django.mo
apps/locale/zh/LC_MESSAGES/django.mo
+0
-0
django.po
apps/locale/zh/LC_MESSAGES/django.po
+9
-9
adhoc.py
apps/ops/api/adhoc.py
+3
-1
adhoc.py
apps/ops/views/adhoc.py
+1
-1
user.py
apps/users/api/user.py
+3
-0
No files found.
apps/assets/api/admin_user.py
View file @
90b77fdb
...
...
@@ -14,6 +14,7 @@
# limitations under the License.
from
django.db
import
transaction
from
django.shortcuts
import
get_object_or_404
from
rest_framework
import
generics
from
rest_framework.response
import
Response
from
rest_framework_bulk
import
BulkModelViewSet
...
...
@@ -24,13 +25,14 @@ from common.utils import get_logger
from
..hands
import
IsOrgAdmin
from
..models
import
AdminUser
,
Asset
from
..
import
serializers
from
..tasks
import
test_admin_user_connect
abil
ity_manual
from
..tasks
import
test_admin_user_connect
iv
ity_manual
logger
=
get_logger
(
__file__
)
__all__
=
[
'AdminUserViewSet'
,
'ReplaceNodesAdminUserApi'
,
'AdminUserTestConnectiveApi'
,
'AdminUserAuthApi'
,
'AdminUserAssetsListView'
,
]
...
...
@@ -81,12 +83,29 @@ class ReplaceNodesAdminUserApi(generics.UpdateAPIView):
class
AdminUserTestConnectiveApi
(
generics
.
RetrieveAPIView
):
"""
Test asset admin user connectivity
Test asset admin user
assets_
connectivity
"""
queryset
=
AdminUser
.
objects
.
all
()
permission_classes
=
(
IsOrgAdmin
,)
def
retrieve
(
self
,
request
,
*
args
,
**
kwargs
):
admin_user
=
self
.
get_object
()
task
=
test_admin_user_connect
abil
ity_manual
.
delay
(
admin_user
)
task
=
test_admin_user_connect
iv
ity_manual
.
delay
(
admin_user
)
return
Response
({
"task"
:
task
.
id
})
class
AdminUserAssetsListView
(
generics
.
ListAPIView
):
permission_classes
=
(
IsOrgAdmin
,)
serializer_class
=
serializers
.
AssetSimpleSerializer
pagination_class
=
LimitOffsetPagination
filter_fields
=
(
"hostname"
,
"ip"
)
http_method_names
=
[
'get'
]
search_fields
=
filter_fields
def
get_object
(
self
):
pk
=
self
.
kwargs
.
get
(
'pk'
)
return
get_object_or_404
(
AdminUser
,
pk
=
pk
)
def
get_queryset
(
self
):
admin_user
=
self
.
get_object
()
return
admin_user
.
get_related_assets
()
apps/assets/api/asset.py
View file @
90b77fdb
...
...
@@ -17,7 +17,7 @@ from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser
from
..models
import
Asset
,
AdminUser
,
Node
from
..
import
serializers
from
..tasks
import
update_asset_hardware_info_manual
,
\
test_asset_connect
abil
ity_manual
test_asset_connect
iv
ity_manual
from
..utils
import
LabelFilter
...
...
@@ -109,7 +109,7 @@ class AssetRefreshHardwareApi(generics.RetrieveAPIView):
class
AssetAdminUserTestApi
(
generics
.
RetrieveAPIView
):
"""
Test asset admin user connectivity
Test asset admin user
assets_
connectivity
"""
queryset
=
Asset
.
objects
.
all
()
permission_classes
=
(
IsOrgAdmin
,)
...
...
@@ -117,7 +117,7 @@ class AssetAdminUserTestApi(generics.RetrieveAPIView):
def
retrieve
(
self
,
request
,
*
args
,
**
kwargs
):
asset_id
=
kwargs
.
get
(
'pk'
)
asset
=
get_object_or_404
(
Asset
,
pk
=
asset_id
)
task
=
test_asset_connect
abil
ity_manual
.
delay
(
asset
)
task
=
test_asset_connect
iv
ity_manual
.
delay
(
asset
)
return
Response
({
"task"
:
task
.
id
})
...
...
apps/assets/api/node.py
View file @
90b77fdb
...
...
@@ -24,7 +24,7 @@ from common.utils import get_logger, get_object_or_none
from
common.tree
import
TreeNodeSerializer
from
..hands
import
IsOrgAdmin
from
..models
import
Node
from
..tasks
import
update_assets_hardware_info_util
,
test_asset_connect
abil
ity_util
from
..tasks
import
update_assets_hardware_info_util
,
test_asset_connect
iv
ity_util
from
..
import
serializers
...
...
@@ -273,5 +273,5 @@ class TestNodeConnectiveApi(APIView):
assets
=
node
.
assets
.
all
()
# task_name = _("测试节点下资产是否可连接: {}".format(node.name))
task_name
=
_
(
"Test if the assets under the node are connectable: {}"
.
format
(
node
.
name
))
task
=
test_asset_connect
abil
ity_util
.
delay
(
assets
,
task_name
=
task_name
)
task
=
test_asset_connect
iv
ity_util
.
delay
(
assets
,
task_name
=
task_name
)
return
Response
({
"task"
:
task
.
id
})
apps/assets/api/system_user.py
View file @
90b77fdb
...
...
@@ -24,8 +24,8 @@ from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser
from
..models
import
SystemUser
,
Asset
from
..
import
serializers
from
..tasks
import
push_system_user_to_assets_manual
,
\
test_system_user_connect
abil
ity_manual
,
push_system_user_a_asset_manual
,
\
test_system_user_connect
abil
ity_a_asset
test_system_user_connect
iv
ity_manual
,
push_system_user_a_asset_manual
,
\
test_system_user_connect
iv
ity_a_asset
logger
=
get_logger
(
__file__
)
...
...
@@ -33,7 +33,7 @@ __all__ = [
'SystemUserViewSet'
,
'SystemUserAuthInfoApi'
,
'SystemUserPushApi'
,
'SystemUserTestConnectiveApi'
,
'SystemUserAssetsListView'
,
'SystemUserPushToAssetApi'
,
'SystemUserTestAssetConnect
abil
ityApi'
,
'SystemUserCommandFilterRuleListApi'
,
'SystemUserTestAssetConnect
iv
ityApi'
,
'SystemUserCommandFilterRuleListApi'
,
]
...
...
@@ -93,15 +93,16 @@ class SystemUserTestConnectiveApi(generics.RetrieveAPIView):
def
retrieve
(
self
,
request
,
*
args
,
**
kwargs
):
system_user
=
self
.
get_object
()
task
=
test_system_user_connect
abil
ity_manual
.
delay
(
system_user
)
task
=
test_system_user_connect
iv
ity_manual
.
delay
(
system_user
)
return
Response
({
"task"
:
task
.
id
})
class
SystemUserAssetsListView
(
generics
.
ListAPIView
):
permission_classes
=
(
IsOrgAdmin
,)
serializer_class
=
serializers
.
AssetSerializer
serializer_class
=
serializers
.
AssetS
impleS
erializer
pagination_class
=
LimitOffsetPagination
filter_fields
=
(
"hostname"
,
"ip"
)
http_method_names
=
[
'get'
]
search_fields
=
filter_fields
def
get_object
(
self
):
...
...
@@ -125,7 +126,7 @@ class SystemUserPushToAssetApi(generics.RetrieveAPIView):
return
Response
({
"task"
:
task
.
id
})
class
SystemUserTestAssetConnect
abil
ityApi
(
generics
.
RetrieveAPIView
):
class
SystemUserTestAssetConnect
iv
ityApi
(
generics
.
RetrieveAPIView
):
queryset
=
SystemUser
.
objects
.
all
()
permission_classes
=
(
IsOrgAdmin
,)
...
...
@@ -133,7 +134,7 @@ class SystemUserTestAssetConnectabilityApi(generics.RetrieveAPIView):
system_user
=
self
.
get_object
()
asset_id
=
self
.
kwargs
.
get
(
'aid'
)
asset
=
get_object_or_404
(
Asset
,
id
=
asset_id
)
task
=
test_system_user_connect
abil
ity_a_asset
.
delay
(
system_user
,
asset
)
task
=
test_system_user_connect
iv
ity_a_asset
.
delay
(
system_user
,
asset
)
return
Response
({
"task"
:
task
.
id
})
...
...
apps/assets/forms/user.py
View file @
90b77fdb
...
...
@@ -99,8 +99,8 @@ class SystemUserForm(OrgModelForm, PasswordAndKeyAuthForm):
auto_generate_key
=
self
.
cleaned_data
.
get
(
'auto_generate_key'
,
False
)
private_key
,
public_key
=
super
()
.
gen_keys
()
if
login_mode
==
SystemUser
.
MANUAL_LOGIN
or
\
protocol
in
[
SystemUser
.
RDP_PROTOCOL
,
SystemUser
.
TELNET_PROTOCOL
]:
if
login_mode
==
SystemUser
.
LOGIN_MANUAL
or
\
protocol
in
[
SystemUser
.
PROTOCOL_RDP
,
SystemUser
.
PROTOCOL_TELNET
]:
system_user
.
auto_push
=
0
auto_generate_key
=
False
system_user
.
save
()
...
...
@@ -124,7 +124,7 @@ class SystemUserForm(OrgModelForm, PasswordAndKeyAuthForm):
validated
=
super
()
.
is_valid
()
username
=
self
.
cleaned_data
.
get
(
'username'
)
login_mode
=
self
.
cleaned_data
.
get
(
'login_mode'
)
if
login_mode
==
SystemUser
.
AUTO_LOGIN
and
not
username
:
if
login_mode
==
SystemUser
.
LOGIN_AUTO
and
not
username
:
self
.
add_error
(
"username"
,
_
(
'* Automatic login mode,'
' must fill in the username.'
)
...
...
apps/assets/models/asset.py
View file @
90b77fdb
...
...
@@ -13,7 +13,6 @@ from django.db.models import Q
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.core.cache
import
cache
from
..const
import
ASSET_ADMIN_CONN_CACHE_KEY
from
.user
import
AdminUser
,
SystemUser
from
orgs.mixins
import
OrgModelMixin
,
OrgManager
...
...
@@ -75,63 +74,48 @@ class Asset(OrgModelMixin):
protocol
=
models
.
CharField
(
max_length
=
128
,
default
=
SSH_PROTOCOL
,
choices
=
PROTOCOL_CHOICES
,
verbose_name
=
_
(
'Protocol'
))
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"
))
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'
))
# 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'
))
cpu_vcpus
=
models
.
IntegerField
(
null
=
True
,
verbose_name
=
_
(
'CPU vcpus'
))
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
=
OrgManager
.
from_queryset
(
AssetQuerySet
)()
CONNECTIVITY_CACHE_KEY
=
'_JMS_ASSET_CONNECTIVITY_{}'
UNREACHABLE
,
REACHABLE
,
UNKNOWN
=
range
(
0
,
3
)
CONNECTIVITY_CHOICES
=
(
(
UNREACHABLE
,
_
(
"Unreachable"
)),
(
REACHABLE
,
_
(
'Reachable'
)),
(
UNKNOWN
,
_
(
"Unknown"
)),
)
def
__str__
(
self
):
return
'{0.hostname}({0.ip})'
.
format
(
self
)
...
...
@@ -197,25 +181,17 @@ class Asset(OrgModelMixin):
return
''
@property
def
is_connective
(
self
):
def
connectivity
(
self
):
if
not
self
.
is_unixlike
():
return
True
val
=
cache
.
get
(
ASSET_ADMIN_CONN_CACHE_KEY
.
format
(
self
.
hostname
))
if
val
==
1
:
return
True
else
:
return
False
return
self
.
UNKNOWN
key
=
self
.
CONNECTIVITY_CACHE_KEY
.
format
(
str
(
self
.
id
))
cached
=
cache
.
get
(
key
,
None
)
return
cached
if
cached
is
not
None
else
self
.
UNKNOWN
def
to_json
(
self
):
info
=
{
'id'
:
self
.
id
,
'hostname'
:
self
.
hostname
,
'ip'
:
self
.
ip
,
'port'
:
self
.
port
,
}
if
self
.
domain
and
self
.
domain
.
gateway_set
.
all
():
info
[
"gateways"
]
=
[
d
.
id
for
d
in
self
.
domain
.
gateway_set
.
all
()]
return
info
@connectivity.setter
def
connectivity
(
self
,
value
):
key
=
self
.
CONNECTIVITY_CACHE_KEY
.
format
(
str
(
self
.
id
))
cache
.
set
(
key
,
value
,
3600
*
2
)
def
get_auth_info
(
self
):
if
self
.
admin_user
:
...
...
@@ -236,11 +212,20 @@ class Asset(OrgModelMixin):
fake_node
.
is_node
=
False
return
fake_node
def
to_json
(
self
):
info
=
{
'id'
:
self
.
id
,
'hostname'
:
self
.
hostname
,
'ip'
:
self
.
ip
,
'port'
:
self
.
port
,
}
if
self
.
domain
and
self
.
domain
.
gateway_set
.
all
():
info
[
"gateways"
]
=
[
d
.
id
for
d
in
self
.
domain
.
gateway_set
.
all
()]
return
info
def
_to_secret_json
(
self
):
"""
Ansible use it create inventory, First using asset user,
otherwise using cluster admin user
Ansible use it create inventory
Todo: May be move to ops implements it
"""
data
=
self
.
to_json
()
...
...
apps/assets/models/base.py
View file @
90b77fdb
...
...
@@ -29,6 +29,13 @@ class AssetUser(OrgModelMixin):
date_updated
=
models
.
DateTimeField
(
auto_now
=
True
)
created_by
=
models
.
CharField
(
max_length
=
128
,
null
=
True
,
verbose_name
=
_
(
'Created by'
))
UNREACHABLE
,
REACHABLE
,
UNKNOWN
=
range
(
0
,
3
)
CONNECTIVITY_CHOICES
=
(
(
UNREACHABLE
,
_
(
"Unreachable"
)),
(
REACHABLE
,
_
(
'Reachable'
)),
(
UNKNOWN
,
_
(
"Unknown"
)),
)
@property
def
password
(
self
):
if
self
.
_password
:
...
...
apps/assets/models/user.py
View file @
90b77fdb
...
...
@@ -14,7 +14,7 @@ from ..const import SYSTEM_USER_CONN_CACHE_KEY
from
.base
import
AssetUser
__all__
=
[
'AdminUser'
,
'SystemUser'
,
]
__all__
=
[
'AdminUser'
,
'SystemUser'
]
logger
=
logging
.
getLogger
(
__name__
)
signer
=
get_signer
()
...
...
@@ -31,6 +31,7 @@ class AdminUser(AssetUser):
become_method
=
models
.
CharField
(
choices
=
BECOME_METHOD_CHOICES
,
default
=
'sudo'
,
max_length
=
4
)
become_user
=
models
.
CharField
(
default
=
'root'
,
max_length
=
64
)
_become_pass
=
models
.
CharField
(
default
=
''
,
max_length
=
128
)
CONNECTIVE_CACHE_KEY
=
'_JMS_ADMIN_USER_CONNECTIVE_{}'
def
__str__
(
self
):
return
self
.
name
...
...
@@ -67,6 +68,23 @@ class AdminUser(AssetUser):
def
assets_amount
(
self
):
return
self
.
get_related_assets
()
.
count
()
@property
def
connectivity
(
self
):
from
.asset
import
Asset
assets
=
self
.
get_related_assets
()
.
values_list
(
'id'
,
'hostname'
,
flat
=
True
)
data
=
{
'unreachable'
:
[],
'reachable'
:
[],
}
for
asset_id
,
hostname
in
assets
:
key
=
Asset
.
CONNECTIVITY_CACHE_KEY
.
format
(
str
(
self
.
id
))
value
=
cache
.
get
(
key
,
Asset
.
UNKNOWN
)
if
value
==
Asset
.
REACHABLE
:
data
[
'reachable'
]
.
append
(
hostname
)
elif
value
==
Asset
.
UNREACHABLE
:
data
[
'unreachable'
]
.
append
(
hostname
)
return
data
class
Meta
:
ordering
=
[
'name'
]
unique_together
=
[(
'name'
,
'org_id'
)]
...
...
@@ -94,34 +112,34 @@ class AdminUser(AssetUser):
class
SystemUser
(
AssetUser
):
SSH_PROTOCOL
=
'ssh'
RDP_PROTOCOL
=
'rdp'
TELNET_PROTOCOL
=
'telnet'
PROTOCOL_SSH
=
'ssh'
PROTOCOL_RDP
=
'rdp'
PROTOCOL_TELNET
=
'telnet'
PROTOCOL_CHOICES
=
(
(
SSH_PROTOCOL
,
'ssh'
),
(
RDP_PROTOCOL
,
'rdp'
),
(
TELNET_PROTOCOL
,
'telnet (beta)'
),
(
PROTOCOL_SSH
,
'ssh'
),
(
PROTOCOL_RDP
,
'rdp'
),
(
PROTOCOL_TELNET
,
'telnet (beta)'
),
)
AUTO_LOGIN
=
'auto'
MANUAL_LOGIN
=
'manual'
LOGIN_AUTO
=
'auto'
LOGIN_MANUAL
=
'manual'
LOGIN_MODE_CHOICES
=
(
(
AUTO_LOGIN
,
_
(
'Automatic login'
)),
(
MANUAL_LOGIN
,
_
(
'Manually login'
))
(
LOGIN_AUTO
,
_
(
'Automatic login'
)),
(
LOGIN_MANUAL
,
_
(
'Manually login'
))
)
nodes
=
models
.
ManyToManyField
(
'assets.Node'
,
blank
=
True
,
verbose_name
=
_
(
"Nodes"
))
assets
=
models
.
ManyToManyField
(
'assets.Asset'
,
blank
=
True
,
verbose_name
=
_
(
"Assets"
))
priority
=
models
.
IntegerField
(
default
=
20
,
verbose_name
=
_
(
"Priority"
),
validators
=
[
MinValueValidator
(
1
),
MaxValueValidator
(
100
)])
priority
=
models
.
IntegerField
(
default
=
20
,
verbose_name
=
_
(
"Priority"
),
validators
=
[
MinValueValidator
(
1
),
MaxValueValidator
(
100
)])
protocol
=
models
.
CharField
(
max_length
=
16
,
choices
=
PROTOCOL_CHOICES
,
default
=
'ssh'
,
verbose_name
=
_
(
'Protocol'
))
auto_push
=
models
.
BooleanField
(
default
=
True
,
verbose_name
=
_
(
'Auto push'
))
sudo
=
models
.
TextField
(
default
=
'/bin/whoami'
,
verbose_name
=
_
(
'Sudo'
))
shell
=
models
.
CharField
(
max_length
=
64
,
default
=
'/bin/bash'
,
verbose_name
=
_
(
'Shell'
))
login_mode
=
models
.
CharField
(
choices
=
LOGIN_MODE_CHOICES
,
default
=
AUTO_LOGIN
,
max_length
=
10
,
verbose_name
=
_
(
'Login mode'
))
login_mode
=
models
.
CharField
(
choices
=
LOGIN_MODE_CHOICES
,
default
=
LOGIN_AUTO
,
max_length
=
10
,
verbose_name
=
_
(
'Login mode'
))
cmd_filters
=
models
.
ManyToManyField
(
'CommandFilter'
,
related_name
=
'system_users'
,
verbose_name
=
_
(
"Command filter"
),
blank
=
True
)
cache_key
=
"__SYSTEM_USER_CACHED_{}"
SYSTEM_USER_CACHE_KEY
=
"__SYSTEM_USER_CACHED_{}"
CONNECTIVE_CACHE_KEY
=
'_JMS_SYSTEM_USER_CONNECTIVE_{}'
def
__str__
(
self
):
return
'{0.name}({0.username})'
.
format
(
self
)
...
...
@@ -136,34 +154,61 @@ class SystemUser(AssetUser):
'auto_push'
:
self
.
auto_push
,
}
def
get_assets
(
self
):
def
get_
related_
assets
(
self
):
assets
=
set
(
self
.
assets
.
all
())
return
assets
@property
def
assets_connective
(
self
):
_result
=
cache
.
get
(
SYSTEM_USER_CONN_CACHE_KEY
.
format
(
self
.
name
),
{})
return
_result
def
connectivity
(
self
):
cache_key
=
self
.
CONNECTIVE_CACHE_KEY
.
format
(
str
(
self
.
id
))
value
=
cache
.
get
(
cache_key
,
None
)
if
not
value
or
'unreachable'
not
in
value
:
return
{
'unreachable'
:
[],
'reachable'
:
[]}
else
:
return
value
@connectivity.setter
def
connectivity
(
self
,
value
):
data
=
self
.
connectivity
unreachable
=
data
[
'unreachable'
]
reachable
=
data
[
'reachable'
]
for
host
in
value
.
get
(
'dark'
,
{})
.
keys
():
if
host
not
in
unreachable
:
unreachable
.
append
(
host
)
if
host
in
reachable
:
reachable
.
remove
(
host
)
for
host
in
value
.
get
(
'contacted'
):
if
host
not
in
reachable
:
reachable
.
append
(
host
)
if
host
in
unreachable
:
unreachable
.
remove
(
host
)
cache_key
=
self
.
CONNECTIVE_CACHE_KEY
.
format
(
str
(
self
.
id
))
cache
.
set
(
cache_key
,
data
,
3600
)
@property
def
assets_unreachable
(
self
):
return
self
.
connectivity
.
get
(
'unreachable'
)
@property
def
unreachable_assets
(
self
):
return
list
(
self
.
assets_connective
.
get
(
'dark'
,
{})
.
keys
()
)
def
assets_reachable
(
self
):
return
self
.
connectivity
.
get
(
'reachable'
)
@property
def
reachable_assets
(
self
):
return
self
.
assets_connective
.
get
(
'contacted'
,
[]
)
def
login_mode_display
(
self
):
return
self
.
get_login_mode_display
(
)
def
is_need_push
(
self
):
if
self
.
auto_push
and
self
.
protocol
==
self
.
__class__
.
SSH_PROTOCOL
:
if
self
.
auto_push
and
self
.
protocol
==
self
.
PROTOCOL_SSH
:
return
True
else
:
return
False
def
set_cache
(
self
):
cache
.
set
(
self
.
cache_key
.
format
(
self
.
id
),
self
,
3600
)
cache
.
set
(
self
.
SYSTEM_USER_CACHE_KEY
.
format
(
self
.
id
),
self
,
3600
)
def
expire_cache
(
self
):
cache
.
delete
(
self
.
cache_key
.
format
(
self
.
id
))
cache
.
delete
(
self
.
SYSTEM_USER_CACHE_KEY
.
format
(
self
.
id
))
@property
def
cmd_filter_rules
(
self
):
...
...
@@ -184,7 +229,7 @@ class SystemUser(AssetUser):
@classmethod
def
get_system_user_by_id_or_cached
(
cls
,
sid
):
cached
=
cache
.
get
(
cls
.
cache_key
.
format
(
sid
))
cached
=
cache
.
get
(
cls
.
SYSTEM_USER_CACHE_KEY
.
format
(
sid
))
if
cached
:
return
cached
try
:
...
...
apps/assets/serializers/asset.py
View file @
90b77fdb
...
...
@@ -9,7 +9,7 @@ from .system_user import AssetSystemUserSerializer
__all__
=
[
'AssetSerializer'
,
'AssetGrantedSerializer'
,
'MyAssetGrantedSerializer'
,
'AssetAsNodeSerializer'
,
'AssetAsNodeSerializer'
,
'AssetSimpleSerializer'
,
]
...
...
@@ -33,7 +33,7 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer):
def
get_field_names
(
self
,
declared_fields
,
info
):
fields
=
super
()
.
get_field_names
(
declared_fields
,
info
)
fields
.
extend
([
'hardware_info'
,
'
is_connective
'
,
'org_name'
'hardware_info'
,
'
connectivity
'
,
'org_name'
])
return
fields
...
...
@@ -78,3 +78,9 @@ class MyAssetGrantedSerializer(AssetGrantedSerializer):
"is_active"
,
"system_users_join"
,
"org_name"
,
"os"
,
"platform"
,
"comment"
,
"org_id"
,
"protocol"
)
class
AssetSimpleSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
Asset
fields
=
[
'id'
,
'hostname'
,
'port'
,
'ip'
,
'connectivity'
]
apps/assets/serializers/system_user.py
View file @
90b77fdb
from
rest_framework
import
serializers
from
..models
import
SystemUser
from
..models
import
SystemUser
,
Asset
from
.base
import
AuthSerializer
...
...
@@ -21,17 +21,17 @@ class SystemUserSerializer(serializers.ModelSerializer):
def
get_field_names
(
self
,
declared_fields
,
info
):
fields
=
super
(
SystemUserSerializer
,
self
)
.
get_field_names
(
declared_fields
,
info
)
fields
.
extend
([
'
get_
login_mode_display'
,
'login_mode_display'
,
])
return
fields
@staticmethod
def
get_unreachable_assets
(
obj
):
return
obj
.
unreachable_assets
return
obj
.
assets_unreachable
@staticmethod
def
get_reachable_assets
(
obj
):
return
obj
.
reachable_assets
return
obj
.
assets_reachable
def
get_unreachable_amount
(
self
,
obj
):
return
len
(
self
.
get_unreachable_assets
(
obj
))
...
...
@@ -41,7 +41,7 @@ class SystemUserSerializer(serializers.ModelSerializer):
@staticmethod
def
get_assets_amount
(
obj
):
return
len
(
obj
.
get_assets
())
return
len
(
obj
.
get_
related_
assets
())
class
SystemUserAuthSerializer
(
AuthSerializer
):
...
...
@@ -75,4 +75,7 @@ class SystemUserSimpleSerializer(serializers.ModelSerializer):
"""
class
Meta
:
model
=
SystemUser
fields
=
(
'id'
,
'name'
,
'username'
)
\ No newline at end of file
fields
=
(
'id'
,
'name'
,
'username'
)
apps/assets/signals_handler.py
View file @
90b77fdb
...
...
@@ -7,7 +7,7 @@ from django.dispatch import receiver
from
common.utils
import
get_logger
from
.models
import
Asset
,
SystemUser
,
Node
from
.tasks
import
update_assets_hardware_info_util
,
\
test_asset_connect
abil
ity_util
,
push_system_user_to_assets
test_asset_connect
iv
ity_util
,
push_system_user_to_assets
logger
=
get_logger
(
__file__
)
...
...
@@ -19,8 +19,8 @@ def update_asset_hardware_info_on_created(asset):
def
test_asset_conn_on_created
(
asset
):
logger
.
debug
(
"Test asset `{}` connect
abil
ity"
.
format
(
asset
))
test_asset_connect
abil
ity_util
.
delay
([
asset
])
logger
.
debug
(
"Test asset `{}` connect
iv
ity"
.
format
(
asset
))
test_asset_connect
iv
ity_util
.
delay
([
asset
])
def
set_asset_root_node
(
asset
):
...
...
apps/assets/tasks.py
View file @
90b77fdb
This diff is collapsed.
Click to expand it.
apps/assets/templates/assets/admin_user_assets.html
View file @
90b77fdb
...
...
@@ -45,13 +45,11 @@
<table
class=
"table table-striped table-bordered table-hover"
id=
"asset_list_table"
>
<thead>
<tr>
<th
class=
"text-center"
>
<input
type=
"checkbox"
id=
"check_all"
class=
"ipt_check_all"
>
</th>
<th>
{% trans 'Hostname' %}
</th>
<th>
{% trans 'IP' %}
</th>
<th>
{% trans 'Port' %}
</th>
<th>
{% trans 'Reachable' %}
</th>
<th>
{% trans 'Action' %}
</th>
</tr>
</thead>
<tbody>
...
...
@@ -91,26 +89,36 @@
<script>
function
initTable
()
{
var
reachable
=
{{
admin_user
.
REACHABLE
}};
var
unreachable
=
{{
admin_user
.
UNREACHABLE
}};
var
options
=
{
ele
:
$
(
'#asset_list_table'
),
buttons
:
[],
order
:
[],
columnDefs
:
[
{
targets
:
1
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
{
targets
:
0
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
detail_btn
=
'<a href="{% url "assets:asset-detail" pk=DEFAULT_PK %}" data-aid="'
+
rowData
.
id
+
'">'
+
cellData
+
'</a>'
;
$
(
td
).
html
(
detail_btn
.
replace
(
'{{ DEFAULT_PK }}'
,
rowData
.
id
));
}},
{
targets
:
4
,
createdCell
:
function
(
td
,
cellData
)
{
if
(
!
cellData
)
{
{
targets
:
3
,
createdCell
:
function
(
td
,
cellData
)
{
if
(
cellData
===
unreachable
)
{
$
(
td
).
html
(
'<i class="fa fa-times text-danger"></i>'
)
}
else
{
}
else
if
(
cellData
===
reachable
)
{
$
(
td
).
html
(
'<i class="fa fa-check text-navy"></i>'
)
}
}}],
ajax_url
:
'{% url "api-assets:asset-list" %}?admin_user_id={{ admin_user.id }}'
,
}
else
{
$
(
td
).
html
(
''
)
}
}},
{
targets
:
4
,
createdCell
:
function
(
td
,
cellData
)
{
var
test_btn
=
' <a class="btn btn-xs btn-info btn-test-asset" data-uid="{{ DEFAULT_PK }}" >{% trans "Test" %}</a>'
.
replace
(
"{{ DEFAULT_PK }}"
,
cellData
);
$
(
td
).
html
(
test_btn
);
}}
],
ajax_url
:
'{% url "api-assets:admin-user-assets" pk=admin_user.id %}'
,
columns
:
[
{
data
:
function
(){
return
""
}},
{
data
:
"hostname"
},
{
data
:
"ip"
},
{
data
:
"port"
},
{
data
:
"
is_connective"
}],
{
data
:
"hostname"
},
{
data
:
"ip"
},
{
data
:
"port"
},
{
data
:
"
connectivity"
},
{
data
:
"id"
}],
op_html
:
$
(
'#actions'
).
html
()
};
jumpserver
.
initServerSideDataTable
(
options
);
...
...
@@ -119,6 +127,21 @@ function initTable() {
$
(
document
).
ready
(
function
()
{
initTable
();
})
.
on
(
'click'
,
'.btn-test-asset'
,
function
()
{
var
asset_id
=
$
(
this
).
data
(
'uid'
);
var
the_url
=
"{% url 'api-assets:asset-alive-test' pk=DEFAULT_PK %}"
.
replace
(
'{{ DEFAULT_PK }}'
,
asset_id
);
var
success
=
function
(
data
)
{
var
task_id
=
data
.
task
;
var
url
=
'{% url "ops:celery-task-log" pk=DEFAULT_PK %}'
.
replace
(
"{{ DEFAULT_PK }}"
,
task_id
);
window
.
open
(
url
,
''
,
'width=800,height=600,left=400,top=400'
)
};
APIUpdateAttr
({
url
:
the_url
,
method
:
'GET'
,
success
:
success
,
flash_message
:
false
});
})
.
on
(
'click'
,
'.btn-test-connective'
,
function
()
{
var
the_url
=
"{% url 'api-assets:admin-user-connective' pk=admin_user.id %}"
;
var
success
=
function
(
data
)
{
...
...
apps/assets/templates/assets/system_user_asset.html
View file @
90b77fdb
...
...
@@ -136,7 +136,7 @@
{% block custom_foot_js %}
<script>
function
initAssetsTable
()
{
var
unreachable
=
{{
system_user
.
unreachable_assets
|
safe
}};
var
connectivity
=
{{
system_user
.
connectivity
|
safe
}};
var
options
=
{
ele
:
$
(
'#system_user_list'
),
buttons
:
[],
...
...
@@ -147,11 +147,13 @@ function initAssetsTable() {
$
(
td
).
html
(
detail_btn
.
replace
(
'{{ DEFAULT_PK }}'
,
rowData
.
id
));
}},
{
targets
:
3
,
createdCell
:
function
(
td
,
cellData
)
{
if
(
unreachable
.
indexOf
(
cellData
)
>=
0
)
{
if
(
connectivity
.
unreachable
.
indexOf
(
cellData
)
>=
0
)
{
$
(
td
).
html
(
'<i class="fa fa-times text-danger"></i>'
)
}
else
{
}
else
if
(
connectivity
.
reachable
.
indexOf
(
cellData
)
>=
0
)
{
$
(
td
).
html
(
'<i class="fa fa-check text-navy"></i>'
)
}
}
else
{
$
(
td
).
html
(
''
)
}
}},
{
targets
:
4
,
createdCell
:
function
(
td
,
cellData
)
{
var
push_btn
=
''
;
...
...
apps/assets/templates/assets/system_user_list.html
View file @
90b77fdb
...
...
@@ -95,7 +95,7 @@ function initTable() {
}}],
ajax_url
:
'{% url "api-assets:system-user-list" %}'
,
columns
:
[
{
data
:
"id"
},
{
data
:
"name"
},
{
data
:
"username"
},
{
data
:
"protocol"
},
{
data
:
"
get_
login_mode_display"
},
{
data
:
"assets_amount"
},
{
data
:
"id"
},
{
data
:
"name"
},
{
data
:
"username"
},
{
data
:
"protocol"
},
{
data
:
"login_mode_display"
},
{
data
:
"assets_amount"
},
{
data
:
"reachable_amount"
},
{
data
:
"unreachable_amount"
},
{
data
:
"id"
},
{
data
:
"comment"
},
{
data
:
"id"
}
],
op_html
:
$
(
'#actions'
).
html
()
...
...
apps/assets/urls/api_urls.py
View file @
90b77fdb
...
...
@@ -24,32 +24,34 @@ cmd_filter_router.register(r'rules', api.CommandFilterRuleViewSet, 'cmd-filter-r
urlpatterns
=
[
path
(
'assets-bulk/'
,
api
.
AssetListUpdateApi
.
as_view
(),
name
=
'asset-bulk-update'
),
path
(
'system-user/<uuid:pk>/auth-info/'
,
api
.
SystemUserAuthInfoApi
.
as_view
(),
name
=
'system-user-auth-info'
),
path
(
'system-user/<uuid:pk>/assets/'
,
api
.
SystemUserAssetsListView
.
as_view
(),
name
=
'system-user-assets'
),
path
(
'assets/<uuid:pk>/refresh/'
,
api
.
AssetRefreshHardwareApi
.
as_view
(),
name
=
'asset-refresh'
),
path
(
'assets/<uuid:pk>/alive/'
,
api
.
AssetAdminUserTestApi
.
as_view
(),
name
=
'asset-alive-test'
),
path
(
'assets/<uuid:pk>/gateway/'
,
api
.
AssetGatewayApi
.
as_view
(),
name
=
'asset-gateway'
),
path
(
'admin-user/<uuid:pk>/nodes/'
,
api
.
ReplaceNodesAdminUserApi
.
as_view
(),
name
=
'replace-nodes-admin-user'
),
path
(
'admin-user/<uuid:pk>/auth/'
,
api
.
AdminUserAuthApi
.
as_view
(),
name
=
'admin-user-auth'
),
path
(
'admin-user/<uuid:pk>/connective/'
,
api
.
AdminUserTestConnectiveApi
.
as_view
(),
name
=
'admin-user-connective'
),
path
(
'admin-user/<uuid:pk>/assets/'
,
api
.
AdminUserAssetsListView
.
as_view
(),
name
=
'admin-user-assets'
),
path
(
'system-user/<uuid:pk>/auth-info/'
,
api
.
SystemUserAuthInfoApi
.
as_view
(),
name
=
'system-user-auth-info'
),
path
(
'system-user/<uuid:pk>/assets/'
,
api
.
SystemUserAssetsListView
.
as_view
(),
name
=
'system-user-assets'
),
path
(
'system-user/<uuid:pk>/push/'
,
api
.
SystemUserPushApi
.
as_view
(),
name
=
'system-user-push'
),
path
(
'system-user/<uuid:pk>/asset/<uuid:aid>/push/'
,
api
.
SystemUserPushToAssetApi
.
as_view
(),
name
=
'system-user-push-to-asset'
),
path
(
'system-user/<uuid:pk>/asset/<uuid:aid>/test/'
,
api
.
SystemUserTestAssetConnect
abil
ityApi
.
as_view
(),
name
=
'system-user-test-to-asset'
),
api
.
SystemUserTestAssetConnect
iv
ityApi
.
as_view
(),
name
=
'system-user-test-to-asset'
),
path
(
'system-user/<uuid:pk>/connective/'
,
api
.
SystemUserTestConnectiveApi
.
as_view
(),
name
=
'system-user-connective'
),
path
(
'system-user/<uuid:pk>/cmd-filter-rules/'
,
api
.
SystemUserCommandFilterRuleListApi
.
as_view
(),
name
=
'system-user-cmd-filter-rule-list'
),
...
...
apps/assets/views/admin_user.py
View file @
90b77fdb
...
...
@@ -102,7 +102,7 @@ class AdminUserAssetsView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
'app'
:
_
(
'Assets'
),
'action'
:
_
(
'Admin user detail'
),
"total_amount"
:
len
(
self
.
queryset
),
'unreachable_amount'
:
len
([
asset
for
asset
in
self
.
queryset
if
asset
.
is_connective
is
False
])
'unreachable_amount'
:
len
([
asset
for
asset
in
self
.
queryset
if
asset
.
connectivity
is
False
])
}
kwargs
.
update
(
context
)
return
super
()
.
get_context_data
(
**
kwargs
)
...
...
apps/jumpserver/conf.py
View file @
90b77fdb
...
...
@@ -304,7 +304,7 @@ defaults = {
'REDIS_DB_CELERY'
:
3
,
'REDIS_DB_CACHE'
:
4
,
'CAPTCHA_TEST_MODE'
:
None
,
'TOKEN_EXPIRATION'
:
3600
,
'TOKEN_EXPIRATION'
:
3600
*
24
,
'DISPLAY_PER_PAGE'
:
25
,
'DEFAULT_EXPIRED_YEARS'
:
70
,
'SESSION_COOKIE_DOMAIN'
:
None
,
...
...
@@ -312,6 +312,7 @@ defaults = {
'SESSION_COOKIE_AGE'
:
3600
*
24
,
'SESSION_EXPIRE_AT_BROWSER_CLOSE'
:
False
,
'AUTH_OPENID'
:
False
,
'OTP_ISSUER_NAME'
:
'Jumpserver'
,
'EMAIL_SUFFIX'
:
'jumpserver.org'
,
'TERMINAL_PASSWORD_AUTH'
:
True
,
'TERMINAL_PUBLIC_KEY_AUTH'
:
True
,
...
...
apps/locale/zh/LC_MESSAGES/django.mo
View file @
90b77fdb
No preview for this file type
apps/locale/zh/LC_MESSAGES/django.po
View file @
90b77fdb
...
...
@@ -637,7 +637,7 @@ msgstr "分类"
#: assets/models/node.py:20
msgid "Key"
msgstr ""
msgstr "
键
"
#: assets/models/node.py:127
msgid "New node"
...
...
@@ -739,15 +739,15 @@ msgid "Update asset hardware info: {}"
msgstr "更新资产硬件信息: {}"
#: assets/tasks.py:230
msgid "Test admin user connect
abil
ity period: {}"
msgid "Test admin user connect
iv
ity period: {}"
msgstr "定期测试管理账号可连接性: {}"
#: assets/tasks.py:236
msgid "Test admin user connect
abil
ity: {}"
msgid "Test admin user connect
iv
ity: {}"
msgstr "测试管理行号可连接性: {}"
#: assets/tasks.py:246
msgid "Test assets connect
abil
ity"
msgid "Test assets connect
iv
ity"
msgstr "测试资产可连接性"
#: assets/tasks.py:251 assets/tasks.py:316 assets/tasks.py:423
...
...
@@ -763,15 +763,15 @@ msgid "No assets, task stop"
msgstr "没有匹配到资产,结束任务"
#: assets/tasks.py:280
msgid "Test assets connect
abil
ity: {}"
msgid "Test assets connect
iv
ity: {}"
msgstr "测试资产可连接性: {}"
#: assets/tasks.py:339
msgid "Test system user connect
abil
ity: {}"
msgid "Test system user connect
iv
ity: {}"
msgstr "测试系统用户可连接性: {}"
#: assets/tasks.py:346
msgid "Test system user connect
abil
ity: {} => {}"
msgid "Test system user connect
iv
ity: {} => {}"
msgstr "测试系统用户可连接性: {} => {}"
#: assets/tasks.py:414
...
...
@@ -4508,7 +4508,7 @@ msgstr "创建账户"
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_create.html:91
msgid "Loading..."
msgstr ""
msgstr "
加载中...
"
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_create.html:106
msgid "Load failed"
...
...
@@ -4634,7 +4634,7 @@ msgstr "更新组织"
#~ msgid "Update assets hardware info period"
#~ msgstr "定期更新资产硬件信息"
#~ msgid "Test system user connect
abil
ity period: {}"
#~ msgid "Test system user connect
iv
ity period: {}"
#~ msgstr "定期测试系统用户可连接性: {}"
#~ msgid "Date finished"
...
...
apps/ops/api/adhoc.py
View file @
90b77fdb
...
...
@@ -24,8 +24,10 @@ class TaskViewSet(viewsets.ModelViewSet):
def
get_queryset
(
self
):
queryset
=
super
()
.
get_queryset
()
if
current_org
:
if
current_org
.
is_real
()
:
queryset
=
queryset
.
filter
(
created_by
=
current_org
.
id
)
else
:
queryset
=
queryset
.
filter
(
created_by
=
''
)
return
queryset
...
...
apps/ops/views/adhoc.py
View file @
90b77fdb
...
...
@@ -27,7 +27,7 @@ class TaskListView(AdminUserRequiredMixin, DatetimeSearchMixin, ListView):
def
get_queryset
(
self
):
queryset
=
super
()
.
get_queryset
()
if
current_org
:
if
current_org
.
is_real
()
:
queryset
=
queryset
.
filter
(
created_by
=
current_org
.
id
)
else
:
queryset
=
queryset
.
filter
(
created_by
=
''
)
...
...
apps/users/api/user.py
View file @
90b77fdb
...
...
@@ -46,6 +46,9 @@ class UserViewSet(IDInFilterMixin, BulkModelViewSet):
self
.
permission_classes
=
(
IsOrgAdminOrAppUser
,)
return
super
()
.
get_permissions
()
def
allow_bulk_destroy
(
self
,
qs
,
filtered
):
return
qs
.
count
()
==
filtered
.
count
()
class
UserChangePasswordApi
(
generics
.
RetrieveUpdateAPIView
):
permission_classes
=
(
IsOrgAdmin
,)
...
...
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