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
2ef487a9
Commit
2ef487a9
authored
Nov 14, 2019
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Update] 修改收集用户
parent
05e7311b
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
126 additions
and
53 deletions
+126
-53
0043_auto_20191114_1111.py
apps/assets/migrations/0043_auto_20191114_1111.py
+23
-0
gathered_user.py
apps/assets/models/gathered_user.py
+5
-6
gathered_user.py
apps/assets/serializers/gathered_user.py
+1
-0
const.py
apps/assets/tasks/const.py
+8
-4
gather_asset_users.py
apps/assets/tasks/gather_asset_users.py
+26
-15
_node_tree.html
apps/assets/templates/assets/_node_tree.html
+19
-1
asset_list.html
apps/assets/templates/assets/asset_list.html
+3
-3
django.mo
apps/locale/zh/LC_MESSAGES/django.mo
+0
-0
django.po
apps/locale/zh/LC_MESSAGES/django.po
+0
-0
adhoc.py
apps/ops/models/adhoc.py
+15
-8
asset_permission_list.html
apps/perms/templates/perms/asset_permission_list.html
+2
-16
0002_auto_20191114_1105.py
apps/tickets/migrations/0002_auto_20191114_1105.py
+24
-0
No files found.
apps/assets/migrations/0043_auto_20191114_1111.py
0 → 100644
View file @
2ef487a9
# Generated by Django 2.2.5 on 2019-11-14 03:11
from
django.db
import
migrations
,
models
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'assets'
,
'0042_favoriteasset'
),
]
operations
=
[
migrations
.
AddField
(
model_name
=
'gathereduser'
,
name
=
'date_last_login'
,
field
=
models
.
DateTimeField
(
null
=
True
,
verbose_name
=
'Date last login'
),
),
migrations
.
AddField
(
model_name
=
'gathereduser'
,
name
=
'ip_last_login'
,
field
=
models
.
CharField
(
default
=
''
,
max_length
=
39
,
verbose_name
=
'IP last login'
),
),
]
apps/assets/models/gathered_user.py
View file @
2ef487a9
...
...
@@ -12,13 +12,12 @@ __all__ = ['GatheredUser']
class
GatheredUser
(
OrgModelMixin
):
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
asset
=
models
.
ForeignKey
(
'assets.Asset'
,
on_delete
=
models
.
CASCADE
,
verbose_name
=
_
(
"Asset"
))
username
=
models
.
CharField
(
max_length
=
32
,
blank
=
True
,
db_index
=
True
,
verbose_name
=
_
(
'Username'
))
username
=
models
.
CharField
(
max_length
=
32
,
blank
=
True
,
db_index
=
True
,
verbose_name
=
_
(
'Username'
))
present
=
models
.
BooleanField
(
default
=
True
,
verbose_name
=
_
(
"Present"
))
date_
created
=
models
.
DateTimeField
(
auto_now_add
=
True
,
verbose_name
=
_
(
"Date created
"
))
date_
updated
=
models
.
DateTimeField
(
auto_now
=
True
,
verbose_name
=
_
(
"Date updated"
))
date_
last_login
=
models
.
DateTimeField
(
null
=
True
,
verbose_name
=
_
(
"Date last login"
))
ip_last_login
=
models
.
CharField
(
max_length
=
39
,
default
=
''
,
verbose_name
=
_
(
"IP last login
"
))
date_
created
=
models
.
DateTimeField
(
auto_now_add
=
True
,
verbose_name
=
_
(
"Date created"
))
date_updated
=
models
.
DateTimeField
(
auto_now
=
True
,
verbose_name
=
_
(
"Date updated"
))
@property
def
hostname
(
self
):
...
...
apps/assets/serializers/gathered_user.py
View file @
2ef487a9
...
...
@@ -12,6 +12,7 @@ class GatheredUserSerializer(OrgResourceModelSerializerMixin):
model
=
GatheredUser
fields
=
[
'id'
,
'asset'
,
'hostname'
,
'ip'
,
'username'
,
'date_last_login'
,
'ip_last_login'
,
'present'
,
'date_created'
,
'date_updated'
]
read_only_fields
=
fields
...
...
apps/assets/tasks/const.py
View file @
2ef487a9
...
...
@@ -7,10 +7,7 @@ from django.utils.translation import ugettext_lazy as _
ENV_PERIOD_TASK
=
os
.
environ
.
get
(
"PERIOD_TASK"
,
"on"
)
==
'on'
ENV_PERIOD_TASK_ENABLED
=
os
.
environ
.
get
(
"PERIOD_TASK_ENABLED"
,
"on"
)
==
"on"
PERIOD_TASK_ENABLED
=
settings
.
CONFIG
.
PERIOD_TASK_ENABLE
\
and
ENV_PERIOD_TASK
\
and
ENV_PERIOD_TASK_ENABLED
PERIOD_TASK_ENABLED
=
settings
.
PERIOD_TASK_ENABLED
and
ENV_PERIOD_TASK
UPDATE_ASSETS_HARDWARE_TASKS
=
[
{
...
...
@@ -97,6 +94,13 @@ GATHER_ASSET_USERS_TASKS = [
"args"
:
"database=passwd"
},
},
{
"name"
:
"get last login"
,
"action"
:
{
"module"
:
"shell"
,
"args"
:
"users=$(getent passwd | grep -v 'nologin' | grep -v 'shudown' | awk -F: '{ print $1 }');for i in $users;do last -F $i -1 | head -1 | grep -v '^$' | awk '{ print $1
\"
@
\"
$3
\"
@
\"
$5,$6,$7,$8 }';done"
}
}
]
GATHER_ASSET_USERS_TASKS_WINDOWS
=
[
...
...
apps/assets/tasks/gather_asset_users.py
View file @
2ef487a9
...
...
@@ -2,9 +2,10 @@
import
re
from
collections
import
defaultdict
from
celery
import
shared_task
from
celery
import
shared_task
from
django.utils.translation
import
ugettext
as
_
from
django.utils
import
timezone
from
orgs.utils
import
tmp_to_org
from
common.utils
import
get_logger
...
...
@@ -19,19 +20,25 @@ ignore_login_shell = re.compile(r'nologin$|sync$|shutdown$|halt$')
def
parse_linux_result_to_users
(
result
):
task_result
=
{}
for
task_name
,
raw
in
result
.
items
():
res
=
raw
.
get
(
'ansible_facts'
,
{})
.
get
(
'getent_passwd'
)
if
res
:
task_result
=
res
break
if
not
task_result
or
not
isinstance
(
task_result
,
dict
):
return
[]
users
=
[]
for
username
,
attr
in
task_result
.
items
():
users
=
defaultdict
(
dict
)
users_result
=
result
.
get
(
'gather host users'
,
{})
\
.
get
(
'ansible_facts'
,
{})
\
.
get
(
'getent_passwd'
)
if
not
isinstance
(
users_result
,
dict
):
users_result
=
{}
for
username
,
attr
in
users_result
.
items
():
if
ignore_login_shell
.
search
(
attr
[
-
1
]):
continue
users
.
append
(
username
)
users
[
username
]
=
{}
last_login_result
=
result
.
get
(
'get last login'
,
{})
.
get
(
'stdout_lines'
,
[])
for
line
in
last_login_result
:
data
=
line
.
split
(
'@'
)
if
len
(
data
)
!=
3
:
continue
username
,
ip
,
dt
=
data
dt
+=
' +0800'
date
=
timezone
.
datetime
.
strptime
(
dt
,
'
%
b
%
d
%
H:
%
M:
%
S
%
Y
%
z'
)
users
[
username
]
=
{
"ip"
:
ip
,
"date"
:
date
}
return
users
...
...
@@ -45,7 +52,7 @@ def parse_windows_result_to_users(result):
if
not
task_result
:
return
[]
users
=
[]
users
=
{}
for
i
in
range
(
4
):
task_result
.
pop
(
0
)
...
...
@@ -55,7 +62,7 @@ def parse_windows_result_to_users(result):
for
line
in
task_result
:
user
=
space
.
split
(
line
)
if
user
[
0
]:
users
.
append
(
user
[
0
])
users
[
user
[
0
]]
=
{}
return
users
...
...
@@ -82,8 +89,12 @@ def add_asset_users(assets, results):
with
tmp_to_org
(
asset
.
org_id
):
GatheredUser
.
objects
.
filter
(
asset
=
asset
,
present
=
True
)
\
.
update
(
present
=
False
)
for
username
in
users
:
for
username
,
data
in
users
.
items
()
:
defaults
=
{
'asset'
:
asset
,
'username'
:
username
,
'present'
:
True
}
if
data
.
get
(
"ip"
):
defaults
[
"ip_last_login"
]
=
data
[
"ip"
]
if
data
.
get
(
"date"
):
defaults
[
"date_last_login"
]
=
data
[
"date"
]
GatheredUser
.
objects
.
update_or_create
(
defaults
=
defaults
,
asset
=
asset
,
username
=
username
,
)
...
...
apps/assets/templates/assets/_node_tree.html
View file @
2ef487a9
...
...
@@ -303,9 +303,24 @@ function defaultCallback(action) {
return
logging
}
function
toggle
()
{
if
(
show
===
0
)
{
$
(
"#split-left"
).
hide
(
500
,
function
()
{
$
(
"#split-right"
).
attr
(
"class"
,
"col-lg-12"
);
$
(
"#toggle-icon"
).
attr
(
"class"
,
"fa fa-angle-right fa-x"
);
show
=
1
;
});
}
else
{
$
(
"#split-right"
).
attr
(
"class"
,
"col-lg-9"
);
$
(
"#toggle-icon"
).
attr
(
"class"
,
"fa fa-angle-left fa-x"
);
$
(
"#split-left"
).
show
(
500
);
show
=
0
;
}
}
$
(
document
).
ready
(
function
()
{
$
(
'.treebox'
).
css
(
'height'
,
window
.
innerHeight
-
18
0
);
$
(
'.treebox'
).
css
(
'height'
,
window
.
innerHeight
-
6
0
);
})
.
on
(
'click'
,
'.btn-show-current-asset'
,
function
(){
hideRMenu
();
...
...
@@ -320,6 +335,9 @@ $(document).ready(function () {
$
(
'#show_current_asset'
).
css
(
'display'
,
'inline-block'
);
setCookie
(
'show_current_asset'
,
''
);
location
.
reload
();
}).
on
(
'click'
,
'.tree-toggle-btn'
,
function
(
e
)
{
e
.
preventDefault
();
toggle
();
})
</script>
apps/assets/templates/assets/asset_list.html
View file @
2ef487a9
...
...
@@ -48,12 +48,12 @@
{% block content %}
<div
class=
"wrapper wrapper-content"
>
<div
class=
"row"
>
<div
class=
"col-lg-3"
id=
"split-left"
style=
"padding-left: 3px"
>
<div
class=
"col-lg-3"
id=
"split-left"
style=
"padding-left: 3px
;padding-right: 0
"
>
{% include 'assets/_node_tree.html' %}
</div>
<div
class=
"col-lg-9 animated fadeInRight"
id=
"split-right"
>
<div
class=
"tree-toggle"
>
<div
class=
"btn btn-sm btn-primary tree-toggle-btn"
onclick=
"toggle()"
>
<div
class=
"tree-toggle"
style=
"z-index: 9999"
>
<div
class=
"btn btn-sm btn-primary tree-toggle-btn"
>
<i
class=
"fa fa-angle-left fa-x"
id=
"toggle-icon"
></i>
</div>
</div>
...
...
apps/locale/zh/LC_MESSAGES/django.mo
View file @
2ef487a9
No preview for this file type
apps/locale/zh/LC_MESSAGES/django.po
View file @
2ef487a9
This diff is collapsed.
Click to expand it.
apps/ops/models/adhoc.py
View file @
2ef487a9
...
...
@@ -246,30 +246,35 @@ class AdHoc(models.Model):
time_start
=
time
.
time
()
date_start
=
timezone
.
now
()
is_success
=
False
summary
=
{}
raw
=
''
try
:
date_start_s
=
datetime
.
datetime
.
now
()
.
strftime
(
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
print
(
_
(
"{} Start task: {}"
)
.
format
(
date_start_s
,
self
.
task
.
name
))
raw
,
summary
=
self
.
_run_only
()
is_success
=
summary
.
get
(
'success'
,
False
)
return
raw
,
summary
except
Exception
as
e
:
logger
.
error
(
e
,
exc_info
=
True
)
summary
=
{}
raw
=
{
"dark"
:
{
"all"
:
str
(
e
)},
"contacted"
:
[]}
return
raw
,
summary
finally
:
date_end
=
timezone
.
now
()
date_end_s
=
date_end
.
strftime
(
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
print
(
_
(
"{} Task finish"
)
.
format
(
date_end_s
))
print
(
'.
\n\n
.'
)
try
:
summary_text
=
json
.
dumps
(
summary
)
except
json
.
JSONDecodeError
:
summary_text
=
'{}'
AdHocRunHistory
.
objects
.
filter
(
id
=
history
.
id
)
.
update
(
date_start
=
date_start
,
is_finished
=
True
,
is_success
=
is_success
,
date_finished
=
timezone
.
now
(),
timedelta
=
time
.
time
()
-
time_start
timedelta
=
time
.
time
()
-
time_start
,
_summary
=
summary_text
)
return
raw
,
summary
def
_run_only
(
self
):
Task
.
objects
.
filter
(
id
=
self
.
task
.
id
)
.
update
(
date_updated
=
timezone
.
now
())
...
...
@@ -321,10 +326,9 @@ class AdHoc(models.Model):
except
AdHocRunHistory
.
DoesNotExist
:
return
None
def
save
(
self
,
force_insert
=
False
,
force_update
=
False
,
using
=
None
,
update_fields
=
None
):
super
()
.
save
(
force_insert
=
force_insert
,
force_update
=
force_update
,
using
=
using
,
update_fields
=
update_fields
)
def
save
(
self
,
**
kwargs
):
instance
=
super
()
.
save
(
**
kwargs
)
return
instance
def
__str__
(
self
):
return
"{} of {}"
.
format
(
self
.
task
.
name
,
self
.
short_id
)
...
...
@@ -393,7 +397,10 @@ class AdHocRunHistory(models.Model):
@summary.setter
def
summary
(
self
,
item
):
try
:
self
.
_summary
=
json
.
dumps
(
item
)
except
json
.
JSONDecodeError
:
self
.
_summary
=
json
.
dumps
({})
@property
def
success_hosts
(
self
):
...
...
apps/perms/templates/perms/asset_permission_list.html
View file @
2ef487a9
...
...
@@ -23,12 +23,12 @@
{% block content %}
<div
class=
"wrapper wrapper-content"
>
<div
class=
"row"
>
<div
class=
"col-lg-3"
id=
"split-left"
style=
"padding-left: 3px"
>
<div
class=
"col-lg-3"
id=
"split-left"
style=
"padding-left: 3px
;padding-right: 0
"
>
{% include 'assets/_node_tree.html' %}
</div>
<div
class=
"col-lg-9 animated fadeInRight"
id=
"split-right"
>
<div
class=
"tree-toggle"
>
<div
class=
"btn btn-sm btn-primary tree-toggle-btn"
onclick=
"toggle()"
>
<div
class=
"btn btn-sm btn-primary tree-toggle-btn"
>
<i
class=
"fa fa-angle-left fa-x"
id=
"toggle-icon"
></i>
</div>
</div>
...
...
@@ -209,20 +209,6 @@ function initTree() {
})
}
function
toggle
()
{
if
(
show
===
0
)
{
$
(
"#split-left"
).
hide
(
500
,
function
()
{
$
(
"#split-right"
).
attr
(
"class"
,
"col-lg-12"
);
$
(
"#toggle-icon"
).
attr
(
"class"
,
"fa fa-angle-right fa-x"
);
show
=
1
;
});
}
else
{
$
(
"#split-right"
).
attr
(
"class"
,
"col-lg-9"
);
$
(
"#toggle-icon"
).
attr
(
"class"
,
"fa fa-angle-left fa-x"
);
$
(
"#split-left"
).
show
(
500
);
show
=
0
;
}
}
$
(
document
).
ready
(
function
(){
initTable
();
...
...
apps/tickets/migrations/0002_auto_20191114_1105.py
0 → 100644
View file @
2ef487a9
# Generated by Django 2.2.5 on 2019-11-14 03:05
from
django.db
import
migrations
,
models
import
django.db.models.deletion
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'tickets'
,
'0001_initial'
),
]
operations
=
[
migrations
.
AlterField
(
model_name
=
'comment'
,
name
=
'ticket'
,
field
=
models
.
ForeignKey
(
on_delete
=
django
.
db
.
models
.
deletion
.
CASCADE
,
related_name
=
'comments'
,
to
=
'tickets.Ticket'
),
),
migrations
.
AlterField
(
model_name
=
'ticket'
,
name
=
'type'
,
field
=
models
.
CharField
(
choices
=
[(
'general'
,
'General'
),
(
'login_confirm'
,
'Login confirm'
)],
default
=
'general'
,
max_length
=
16
,
verbose_name
=
'Type'
),
),
]
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