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
618aed32
Commit
618aed32
authored
9 years ago
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
移动api中关于tty到connect.py
parent
c8c00612
master
auditor_jym
audits
dev
dev_beta
dev_beta_db
gengmei
lagacy-0.4.0
node_service
password
rbac
restrict_access
test
v52
wph
1.5.2
1.5.1
1.5.0
1.4.10
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.3
1.3.2
1.3.1
1.3.0
1.2.1
1.2.0
1.1.1
1.1.0
1.0.0
0.3.3
0.3.2
0.3.2-rc2
0.3.1
0.3.0-beta
v1.4.10
v1.4.7
v1.4.4
No related merge requests found
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
369 additions
and
364 deletions
+369
-364
connect.py
connect.py
+369
-2
api.py
jumpserver/api.py
+0
-362
No files found.
connect.py
View file @
618aed32
...
...
@@ -8,18 +8,33 @@ sys.setdefaultencoding('utf8')
import
os
import
re
import
time
import
datetime
import
textwrap
import
getpass
import
readline
import
django
from
multiprocessing
import
Pool
import
paramiko
import
struct
,
fcntl
,
signal
,
socket
,
select
,
fnmatch
os
.
environ
[
'DJANGO_SETTINGS_MODULE'
]
=
'jumpserver.settings'
if
django
.
get_version
()
!=
'1.6'
:
django
.
setup
()
from
jumpserver.api
import
ServerError
,
User
,
Asset
,
Jtty
,
get_object
from
jumpserver.api
import
logger
from
jumpserver.api
import
ServerError
,
User
,
Asset
,
AssetGroup
,
get_object
from
jumpserver.api
import
logger
,
is_dir
,
Log
,
TtyLog
from
jumpserver.settings
import
log_dir
try
:
import
termios
import
tty
except
ImportError
:
print
'
\033
[1;31m仅支持类Unix系统 Only unix like supported.
\033
[0m'
time
.
sleep
(
3
)
sys
.
exit
()
VIM_FLAG
=
False
VIM_COMMAND
=
''
SSH_TTY
=
''
login_user
=
get_object
(
User
,
username
=
getpass
.
getuser
())
...
...
@@ -81,6 +96,358 @@ def verify_connect(user, option):
jtty
.
connect
()
def
check_vim_status
(
command
,
ssh
):
global
SSH_TTY
print
command
if
command
==
''
:
return
True
else
:
command_str
=
'ps -ef |grep "
%
s" | grep "
%
s"|grep -v grep |wc -l'
%
(
command
,
SSH_TTY
)
print
command_str
stdin
,
stdout
,
stderr
=
ssh
.
exec_command
(
command_str
)
ps_num
=
stdout
.
read
()
print
ps_num
if
int
(
ps_num
)
==
0
:
return
True
else
:
return
False
def
deal_command
(
str_r
,
ssh
):
"""
处理命令中特殊字符
"""
str_r
=
re
.
sub
(
'
\x07
'
,
''
,
str_r
)
#删除响铃
patch_char
=
re
.
compile
(
'
\x08\x1b
\
[C'
)
#删除方向左右一起的按键
while
patch_char
.
search
(
str_r
):
str_r
=
patch_char
.
sub
(
''
,
str_r
.
rstrip
())
result_command
=
''
#最后的结果
pattern_str
=
''
#模式中间中的字符串
backspace_num
=
0
#光标移动的个数
reach_backspace_flag
=
False
#没有检测到光标键则为true
end_flag
=
False
while
str_r
:
tmp
=
re
.
match
(
r'\w'
,
str_r
)
if
tmp
:
if
reach_backspace_flag
:
pattern_str
+=
str
(
tmp
.
group
(
0
))
str_r
=
str_r
[
1
:]
continue
else
:
result_command
+=
str
(
tmp
.
group
(
0
))
str_r
=
str_r
[
1
:]
continue
tmp
=
re
.
match
(
r'\x1b\[K[\x08]*'
,
str_r
)
if
tmp
:
if
backspace_num
>
0
:
if
backspace_num
>
len
(
result_command
)
:
result_command
+=
pattern_str
result_command
=
result_command
[
0
:
-
backspace_num
]
else
:
result_command
=
result_command
[
0
:
-
backspace_num
]
result_command
+=
pattern_str
del_len
=
len
(
str
(
tmp
.
group
(
0
)))
-
3
if
del_len
>
0
:
result_command
=
result_command
[
0
:
-
del_len
]
reach_backspace_flag
=
False
backspace_num
=
0
pattern_str
=
''
str_r
=
str_r
[
len
(
str
(
tmp
.
group
(
0
))):]
continue
if
re
.
match
(
r'\x08'
,
str_r
):
backspace_num
+=
1
reach_backspace_flag
=
True
str_r
=
str_r
[
1
:]
if
len
(
str_r
)
==
0
:
end_flag
=
True
continue
if
reach_backspace_flag
:
pattern_str
+=
str_r
[
0
]
else
:
result_command
+=
str_r
[
0
]
str_r
=
str_r
[
1
:]
if
backspace_num
>
0
and
not
end_flag
:
result_command
=
result_command
[:
-
backspace_num
]
result_command
+=
pattern_str
control_char
=
re
.
compile
(
r"""
\x1b[ #
%
()*+\-.\/]. |
\r | #匹配 回车符(CR)
(?:\x1b\[|\x9b) [ -?]* [@-~] | #匹配 控制顺序描述符(CSI)... Cmd
(?:\x1b\]|\x9d) .*? (?:\x1b\\|[\a\x9c]) | \x07 | #匹配 操作系统指令(OSC)...终止符或振铃符(ST|BEL)
(?:\x1b[P^_]|[\x90\x9e\x9f]) .*? (?:\x1b\\|\x9c) | #匹配 设备控制串或私讯或应用程序命令(DCS|PM|APC)...终止符(ST)
\x1b. #匹配 转义过后的字符
[\x80-\x9f] #匹配 所有控制字符
"""
,
re
.
X
)
result_command
=
control_char
.
sub
(
''
,
result_command
.
strip
())
global
VIM_FLAG
global
VIM_COMMAND
if
not
VIM_FLAG
:
if
result_command
.
startswith
(
'vim'
)
or
result_command
.
startswith
(
'vi'
)
:
VIM_FLAG
=
True
VIM_COMMAND
=
result_command
return
result_command
.
decode
(
'utf8'
,
"ignore"
)
else
:
if
check_vim_status
(
VIM_COMMAND
,
ssh
):
VIM_FLAG
=
False
VIM_COMMAND
=
''
return
result_command
.
decode
(
'utf8'
,
"ignore"
)
else
:
return
''
def
remove_control_char
(
str_r
):
"""
处理日志特殊字符
"""
control_char
=
re
.
compile
(
r"""
\x1b[ #
%
()*+\-.\/]. |
\r | #匹配 回车符(CR)
(?:\x1b\[|\x9b) [ -?]* [@-~] | #匹配 控制顺序描述符(CSI)... Cmd
(?:\x1b\]|\x9d) .*? (?:\x1b\\|[\a\x9c]) | \x07 | #匹配 操作系统指令(OSC)...终止符或振铃符(ST|BEL)
(?:\x1b[P^_]|[\x90\x9e\x9f]) .*? (?:\x1b\\|\x9c) | #匹配 设备控制串或私讯或应用程序命令(DCS|PM|APC)...终止符(ST)
\x1b. #匹配 转义过后的字符
[\x80-\x9f] #匹配 所有控制字符
"""
,
re
.
X
)
backspace
=
re
.
compile
(
r"[^\b][\b]"
)
line_filtered
=
control_char
.
sub
(
''
,
str_r
.
rstrip
())
while
backspace
.
search
(
line_filtered
):
line_filtered
=
backspace
.
sub
(
''
,
line_filtered
)
return
line_filtered
def
newline_code_in
(
strings
):
for
i
in
[
'
\r
'
,
'
\r\n
'
,
'
\n
'
]:
if
i
in
strings
:
#print "new line"
return
True
return
False
class
Jtty
(
object
):
"""
A virtual tty class
一个虚拟终端类,实现连接ssh和记录日志
"""
def
__init__
(
self
,
username
,
ip
):
self
.
chan
=
None
self
.
username
=
username
self
.
ip
=
ip
# self.user = user
# self.asset = asset
@staticmethod
def
get_win_size
():
"""
This function use to get the size of the windows!
获得terminal窗口大小
"""
if
'TIOCGWINSZ'
in
dir
(
termios
):
TIOCGWINSZ
=
termios
.
TIOCGWINSZ
else
:
TIOCGWINSZ
=
1074295912L
s
=
struct
.
pack
(
'HHHH'
,
0
,
0
,
0
,
0
)
x
=
fcntl
.
ioctl
(
sys
.
stdout
.
fileno
(),
TIOCGWINSZ
,
s
)
return
struct
.
unpack
(
'HHHH'
,
x
)[
0
:
2
]
def
set_win_size
(
self
,
sig
,
data
):
"""
This function use to set the window size of the terminal!
设置terminal窗口大小
"""
try
:
win_size
=
self
.
get_win_size
()
self
.
chan
.
resize_pty
(
height
=
win_size
[
0
],
width
=
win_size
[
1
])
except
Exception
:
pass
def
log_record
(
self
):
"""
Logging user command and output.
记录用户的日志
"""
tty_log_dir
=
os
.
path
.
join
(
log_dir
,
'tty'
)
timestamp_start
=
int
(
time
.
time
())
date_start
=
time
.
strftime
(
'
%
Y
%
m
%
d'
,
time
.
localtime
(
timestamp_start
))
time_start
=
time
.
strftime
(
'
%
H
%
M
%
S'
,
time
.
localtime
(
timestamp_start
))
today_connect_log_dir
=
os
.
path
.
join
(
tty_log_dir
,
date_start
)
log_file_path
=
os
.
path
.
join
(
today_connect_log_dir
,
'
%
s_
%
s_
%
s'
%
(
self
.
username
,
self
.
ip
,
time_start
))
pid
=
os
.
getpid
()
pts
=
os
.
popen
(
"ps axu | grep
%
s | grep -v grep | awk '{ print $7 }'"
%
pid
)
.
read
()
.
strip
()
ip_list
=
os
.
popen
(
"who | grep
%
s | awk '{ print $5 }'"
%
pts
)
.
read
()
.
strip
(
'()
\n
'
)
try
:
is_dir
(
today_connect_log_dir
)
except
OSError
:
raise
ServerError
(
'Create
%
s failed, Please modify
%
s permission.'
%
(
today_connect_log_dir
,
tty_log_dir
))
try
:
# log_file_f = open('/opt/jumpserver/logs/tty/20151102/a_b_191034.log', 'a')
log_file_f
=
open
(
log_file_path
+
'.log'
,
'a'
)
log_time_f
=
open
(
log_file_path
+
'.time'
,
'a'
)
except
IOError
:
raise
ServerError
(
'Create logfile failed, Please modify
%
s permission.'
%
today_connect_log_dir
)
log
=
Log
(
user
=
self
.
username
,
host
=
self
.
ip
,
remote_ip
=
ip_list
,
log_path
=
log_file_path
,
start_time
=
datetime
.
datetime
.
now
(),
pid
=
pid
)
log_file_f
.
write
(
'Start time is
%
s
\n
'
%
datetime
.
datetime
.
now
())
log
.
save
()
return
log_file_f
,
log_time_f
,
ip_list
,
log
def
posix_shell
(
self
,
ssh
):
"""
Use paramiko channel connect server interactive.
使用paramiko模块的channel,连接后端,进入交互式
"""
log_file_f
,
log_time_f
,
ip_list
,
log
=
self
.
log_record
()
old_tty
=
termios
.
tcgetattr
(
sys
.
stdin
)
pre_timestamp
=
time
.
time
()
input_r
=
''
input_mode
=
False
try
:
tty
.
setraw
(
sys
.
stdin
.
fileno
())
tty
.
setcbreak
(
sys
.
stdin
.
fileno
())
self
.
chan
.
settimeout
(
0.0
)
while
True
:
try
:
r
,
w
,
e
=
select
.
select
([
self
.
chan
,
sys
.
stdin
],
[],
[])
except
Exception
:
pass
if
self
.
chan
in
r
:
try
:
x
=
self
.
chan
.
recv
(
1024
)
if
len
(
x
)
==
0
:
break
sys
.
stdout
.
write
(
x
)
sys
.
stdout
.
flush
()
log_file_f
.
write
(
x
)
now_timestamp
=
time
.
time
()
log_time_f
.
write
(
'
%
s
%
s
\n
'
%
(
round
(
now_timestamp
-
pre_timestamp
,
4
),
len
(
x
)))
pre_timestamp
=
now_timestamp
log_file_f
.
flush
()
log_time_f
.
flush
()
if
input_mode
and
not
newline_code_in
(
x
):
input_r
+=
x
except
socket
.
timeout
:
pass
if
sys
.
stdin
in
r
:
x
=
os
.
read
(
sys
.
stdin
.
fileno
(),
1
)
if
not
input_mode
:
input_mode
=
True
if
str
(
x
)
in
[
'
\r
'
,
'
\n
'
,
'
\r\n
'
]:
input_r
=
deal_command
(
input_r
,
ssh
)
TtyLog
(
log
=
log
,
datetime
=
datetime
.
datetime
.
now
(),
cmd
=
input_r
)
.
save
()
input_r
=
''
input_mode
=
False
if
len
(
x
)
==
0
:
break
self
.
chan
.
send
(
x
)
finally
:
termios
.
tcsetattr
(
sys
.
stdin
,
termios
.
TCSADRAIN
,
old_tty
)
log_file_f
.
write
(
'End time is
%
s'
%
datetime
.
datetime
.
now
())
log_file_f
.
close
()
log
.
is_finished
=
True
log
.
end_time
=
datetime
.
datetime
.
now
()
log
.
save
()
def
get_connect_item
(
self
):
"""
get args for connect: ip, port, username, passwd
获取连接需要的参数,也就是服务ip, 端口, 用户账号和密码
"""
# if not self.asset.is_active:
# raise ServerError('该主机被禁用 Host %s is not active.' % self.ip)
#
# if not self.user.is_active:
# raise ServerError('该用户被禁用 User %s is not active.' % self.username)
# password = CRYPTOR.decrypt(self.])
# return self.username, password, self.ip, int(self.asset.port)
return
'root'
,
'redhat'
,
'127.0.0.1'
,
22
def
get_connection
(
self
):
"""
Get the ssh connection for reuse
获取连接套接字
"""
username
,
password
,
ip
,
port
=
self
.
get_connect_item
()
logger
.
debug
(
"username:
%
s, password:
%
s, ip:
%
s, port:
%
s"
%
(
username
,
password
,
ip
,
port
))
# 发起ssh连接请求 Make a ssh connection
ssh
=
paramiko
.
SSHClient
()
ssh
.
load_system_host_keys
()
ssh
.
set_missing_host_key_policy
(
paramiko
.
AutoAddPolicy
())
try
:
ssh
.
connect
(
ip
,
port
=
port
,
username
=
username
,
password
=
password
)
except
paramiko
.
ssh_exception
.
AuthenticationException
,
paramiko
.
ssh_exception
.
SSHException
:
raise
ServerError
(
'认证错误 Authentication Error.'
)
except
socket
.
error
:
raise
ServerError
(
'端口可能不对 Connect SSH Socket Port Error, Please Correct it.'
)
else
:
return
ssh
def
connect
(
self
):
"""
Connect server.
连接服务器
"""
ps1
=
"PS1='[
\
u@
%
s
\
W]
\
$ '
\n
"
%
self
.
ip
login_msg
=
"clear;echo -e '
\\
033[32mLogin
%
s done. Enjoy it.
\\
033[0m'
\n
"
%
self
.
ip
# 发起ssh连接请求 Make a ssh connection
ssh
=
self
.
get_connection
()
# 获取连接的隧道并设置窗口大小 Make a channel and set windows size
global
channel
win_size
=
self
.
get_win_size
()
self
.
chan
=
channel
=
ssh
.
invoke_shell
(
height
=
win_size
[
0
],
width
=
win_size
[
1
])
try
:
signal
.
signal
(
signal
.
SIGWINCH
,
self
.
set_win_size
)
except
:
pass
# 设置PS1并提示 Set PS1 and msg it
#channel.send(ps1)
#channel.send(login_msg)
channel
.
send
(
'echo ${SSH_TTY}
\n
'
)
global
SSH_TTY
while
not
channel
.
recv_ready
():
time
.
sleep
(
1
)
tmp
=
channel
.
recv
(
1024
)
#print 'ok'+tmp+'ok'
SSH_TTY
=
re
.
search
(
r'(?<=/dev/).*'
,
tmp
)
.
group
()
.
strip
()
channel
.
send
(
'clear
\n
'
)
# Make ssh interactive tunnel
self
.
posix_shell
(
ssh
)
# Shutdown channel socket
channel
.
close
()
ssh
.
close
()
def
execute
(
self
,
cmd
):
"""
execute cmd on the asset
执行命令
"""
pass
def
print_prompt
():
"""
Print prompt
...
...
This diff is collapsed.
Click to expand it.
jumpserver/api.py
View file @
618aed32
...
...
@@ -8,8 +8,6 @@ import hashlib
import
datetime
import
random
import
subprocess
import
paramiko
import
struct
,
fcntl
,
signal
,
socket
,
select
,
fnmatch
from
settings
import
*
from
django.core.paginator
import
Paginator
,
EmptyPage
,
InvalidPage
...
...
@@ -25,17 +23,7 @@ from django.shortcuts import render_to_response
from
django.core.mail
import
send_mail
import
json
import
logging
VIM_FLAG
=
False
VIM_COMMAND
=
''
SSH_TTY
=
''
try
:
import
termios
import
tty
except
ImportError
:
print
'
\033
[1;31m仅支持类Unix系统 Only unix like supported.
\033
[0m'
time
.
sleep
(
3
)
sys
.
exit
()
def
set_log
(
level
):
...
...
@@ -97,356 +85,6 @@ def pages(post_objects, request):
# 所有对象, 分页器, 本页对象, 所有页码, 本页页码,是否显示第一页,是否显示最后一页
return
post_objects
,
paginator
,
page_objects
,
page_range
,
current_page
,
show_first
,
show_end
def
check_vim_status
(
command
,
ssh
):
global
SSH_TTY
print
command
if
command
==
''
:
return
True
else
:
command_str
=
'ps -ef |grep "
%
s" | grep "
%
s"|grep -v grep |wc -l'
%
(
command
,
SSH_TTY
)
print
command_str
stdin
,
stdout
,
stderr
=
ssh
.
exec_command
(
command_str
)
ps_num
=
stdout
.
read
()
print
ps_num
if
int
(
ps_num
)
==
0
:
return
True
else
:
return
False
def
deal_command
(
str_r
,
ssh
):
"""
处理命令中特殊字符
"""
str_r
=
re
.
sub
(
'
\x07
'
,
''
,
str_r
)
#删除响铃
patch_char
=
re
.
compile
(
'
\x08\x1b
\
[C'
)
#删除方向左右一起的按键
while
patch_char
.
search
(
str_r
):
str_r
=
patch_char
.
sub
(
''
,
str_r
.
rstrip
())
result_command
=
''
#最后的结果
pattern_str
=
''
#模式中间中的字符串
backspace_num
=
0
#光标移动的个数
reach_backspace_flag
=
False
#没有检测到光标键则为true
end_flag
=
False
while
str_r
:
tmp
=
re
.
match
(
r'\w'
,
str_r
)
if
tmp
:
if
reach_backspace_flag
:
pattern_str
+=
str
(
tmp
.
group
(
0
))
str_r
=
str_r
[
1
:]
continue
else
:
result_command
+=
str
(
tmp
.
group
(
0
))
str_r
=
str_r
[
1
:]
continue
tmp
=
re
.
match
(
r'\x1b\[K[\x08]*'
,
str_r
)
if
tmp
:
if
backspace_num
>
0
:
if
backspace_num
>
len
(
result_command
)
:
result_command
+=
pattern_str
result_command
=
result_command
[
0
:
-
backspace_num
]
else
:
result_command
=
result_command
[
0
:
-
backspace_num
]
result_command
+=
pattern_str
del_len
=
len
(
str
(
tmp
.
group
(
0
)))
-
3
if
del_len
>
0
:
result_command
=
result_command
[
0
:
-
del_len
]
reach_backspace_flag
=
False
backspace_num
=
0
pattern_str
=
''
str_r
=
str_r
[
len
(
str
(
tmp
.
group
(
0
))):]
continue
if
re
.
match
(
r'\x08'
,
str_r
):
backspace_num
+=
1
reach_backspace_flag
=
True
str_r
=
str_r
[
1
:]
if
len
(
str_r
)
==
0
:
end_flag
=
True
continue
if
reach_backspace_flag
:
pattern_str
+=
str_r
[
0
]
else
:
result_command
+=
str_r
[
0
]
str_r
=
str_r
[
1
:]
if
backspace_num
>
0
and
not
end_flag
:
result_command
=
result_command
[:
-
backspace_num
]
result_command
+=
pattern_str
control_char
=
re
.
compile
(
r"""
\x1b[ #
%
()*+\-.\/]. |
\r | #匹配 回车符(CR)
(?:\x1b\[|\x9b) [ -?]* [@-~] | #匹配 控制顺序描述符(CSI)... Cmd
(?:\x1b\]|\x9d) .*? (?:\x1b\\|[\a\x9c]) | \x07 | #匹配 操作系统指令(OSC)...终止符或振铃符(ST|BEL)
(?:\x1b[P^_]|[\x90\x9e\x9f]) .*? (?:\x1b\\|\x9c) | #匹配 设备控制串或私讯或应用程序命令(DCS|PM|APC)...终止符(ST)
\x1b. #匹配 转义过后的字符
[\x80-\x9f] #匹配 所有控制字符
"""
,
re
.
X
)
result_command
=
control_char
.
sub
(
''
,
result_command
.
strip
())
global
VIM_FLAG
global
VIM_COMMAND
if
not
VIM_FLAG
:
if
result_command
.
startswith
(
'vim'
)
or
result_command
.
startswith
(
'vi'
)
:
VIM_FLAG
=
True
VIM_COMMAND
=
result_command
return
result_command
.
decode
(
'utf8'
,
"ignore"
)
else
:
if
check_vim_status
(
VIM_COMMAND
,
ssh
):
VIM_FLAG
=
False
VIM_COMMAND
=
''
return
result_command
.
decode
(
'utf8'
,
"ignore"
)
else
:
return
''
def
remove_control_char
(
str_r
):
"""
处理日志特殊字符
"""
control_char
=
re
.
compile
(
r"""
\x1b[ #
%
()*+\-.\/]. |
\r | #匹配 回车符(CR)
(?:\x1b\[|\x9b) [ -?]* [@-~] | #匹配 控制顺序描述符(CSI)... Cmd
(?:\x1b\]|\x9d) .*? (?:\x1b\\|[\a\x9c]) | \x07 | #匹配 操作系统指令(OSC)...终止符或振铃符(ST|BEL)
(?:\x1b[P^_]|[\x90\x9e\x9f]) .*? (?:\x1b\\|\x9c) | #匹配 设备控制串或私讯或应用程序命令(DCS|PM|APC)...终止符(ST)
\x1b. #匹配 转义过后的字符
[\x80-\x9f] #匹配 所有控制字符
"""
,
re
.
X
)
backspace
=
re
.
compile
(
r"[^\b][\b]"
)
line_filtered
=
control_char
.
sub
(
''
,
str_r
.
rstrip
())
while
backspace
.
search
(
line_filtered
):
line_filtered
=
backspace
.
sub
(
''
,
line_filtered
)
return
line_filtered
def
newline_code_in
(
strings
):
for
i
in
[
'
\r
'
,
'
\r\n
'
,
'
\n
'
]:
if
i
in
strings
:
#print "new line"
return
True
return
False
class
Jtty
(
object
):
"""
A virtual tty class
一个虚拟终端类,实现连接ssh和记录日志
"""
def
__init__
(
self
,
username
,
ip
):
self
.
chan
=
None
self
.
username
=
username
self
.
ip
=
ip
# self.user = user
# self.asset = asset
@staticmethod
def
get_win_size
():
"""
This function use to get the size of the windows!
获得terminal窗口大小
"""
if
'TIOCGWINSZ'
in
dir
(
termios
):
TIOCGWINSZ
=
termios
.
TIOCGWINSZ
else
:
TIOCGWINSZ
=
1074295912L
s
=
struct
.
pack
(
'HHHH'
,
0
,
0
,
0
,
0
)
x
=
fcntl
.
ioctl
(
sys
.
stdout
.
fileno
(),
TIOCGWINSZ
,
s
)
return
struct
.
unpack
(
'HHHH'
,
x
)[
0
:
2
]
def
set_win_size
(
self
,
sig
,
data
):
"""
This function use to set the window size of the terminal!
设置terminal窗口大小
"""
try
:
win_size
=
self
.
get_win_size
()
self
.
chan
.
resize_pty
(
height
=
win_size
[
0
],
width
=
win_size
[
1
])
except
Exception
:
pass
def
log_record
(
self
):
"""
Logging user command and output.
记录用户的日志
"""
tty_log_dir
=
os
.
path
.
join
(
log_dir
,
'tty'
)
timestamp_start
=
int
(
time
.
time
())
date_start
=
time
.
strftime
(
'
%
Y
%
m
%
d'
,
time
.
localtime
(
timestamp_start
))
time_start
=
time
.
strftime
(
'
%
H
%
M
%
S'
,
time
.
localtime
(
timestamp_start
))
today_connect_log_dir
=
os
.
path
.
join
(
tty_log_dir
,
date_start
)
log_file_path
=
os
.
path
.
join
(
today_connect_log_dir
,
'
%
s_
%
s_
%
s'
%
(
self
.
username
,
self
.
ip
,
time_start
))
pid
=
os
.
getpid
()
pts
=
os
.
popen
(
"ps axu | grep
%
s | grep -v grep | awk '{ print $7 }'"
%
pid
)
.
read
()
.
strip
()
ip_list
=
os
.
popen
(
"who | grep
%
s | awk '{ print $5 }'"
%
pts
)
.
read
()
.
strip
(
'()
\n
'
)
try
:
is_dir
(
today_connect_log_dir
)
except
OSError
:
raise
ServerError
(
'Create
%
s failed, Please modify
%
s permission.'
%
(
today_connect_log_dir
,
tty_log_dir
))
try
:
# log_file_f = open('/opt/jumpserver/logs/tty/20151102/a_b_191034.log', 'a')
log_file_f
=
open
(
log_file_path
+
'.log'
,
'a'
)
log_time_f
=
open
(
log_file_path
+
'.time'
,
'a'
)
except
IOError
:
raise
ServerError
(
'Create logfile failed, Please modify
%
s permission.'
%
today_connect_log_dir
)
log
=
Log
(
user
=
self
.
username
,
host
=
self
.
ip
,
remote_ip
=
ip_list
,
log_path
=
log_file_path
,
start_time
=
datetime
.
datetime
.
now
(),
pid
=
pid
)
log_file_f
.
write
(
'Start time is
%
s
\n
'
%
datetime
.
datetime
.
now
())
log
.
save
()
return
log_file_f
,
log_time_f
,
ip_list
,
log
def
posix_shell
(
self
,
ssh
):
"""
Use paramiko channel connect server interactive.
使用paramiko模块的channel,连接后端,进入交互式
"""
log_file_f
,
log_time_f
,
ip_list
,
log
=
self
.
log_record
()
old_tty
=
termios
.
tcgetattr
(
sys
.
stdin
)
pre_timestamp
=
time
.
time
()
input_r
=
''
input_mode
=
False
try
:
tty
.
setraw
(
sys
.
stdin
.
fileno
())
tty
.
setcbreak
(
sys
.
stdin
.
fileno
())
self
.
chan
.
settimeout
(
0.0
)
while
True
:
try
:
r
,
w
,
e
=
select
.
select
([
self
.
chan
,
sys
.
stdin
],
[],
[])
except
Exception
:
pass
if
self
.
chan
in
r
:
try
:
x
=
self
.
chan
.
recv
(
1024
)
if
len
(
x
)
==
0
:
break
sys
.
stdout
.
write
(
x
)
sys
.
stdout
.
flush
()
log_file_f
.
write
(
x
)
now_timestamp
=
time
.
time
()
log_time_f
.
write
(
'
%
s
%
s
\n
'
%
(
round
(
now_timestamp
-
pre_timestamp
,
4
),
len
(
x
)))
pre_timestamp
=
now_timestamp
log_file_f
.
flush
()
log_time_f
.
flush
()
if
input_mode
and
not
newline_code_in
(
x
):
input_r
+=
x
except
socket
.
timeout
:
pass
if
sys
.
stdin
in
r
:
x
=
os
.
read
(
sys
.
stdin
.
fileno
(),
1
)
if
not
input_mode
:
input_mode
=
True
if
str
(
x
)
in
[
'
\r
'
,
'
\n
'
,
'
\r\n
'
]:
input_r
=
deal_command
(
input_r
,
ssh
)
TtyLog
(
log
=
log
,
datetime
=
datetime
.
datetime
.
now
(),
cmd
=
input_r
)
.
save
()
input_r
=
''
input_mode
=
False
if
len
(
x
)
==
0
:
break
self
.
chan
.
send
(
x
)
finally
:
termios
.
tcsetattr
(
sys
.
stdin
,
termios
.
TCSADRAIN
,
old_tty
)
log_file_f
.
write
(
'End time is
%
s'
%
datetime
.
datetime
.
now
())
log_file_f
.
close
()
log
.
is_finished
=
True
log
.
end_time
=
datetime
.
datetime
.
now
()
log
.
save
()
def
get_connect_item
(
self
):
"""
get args for connect: ip, port, username, passwd
获取连接需要的参数,也就是服务ip, 端口, 用户账号和密码
"""
# if not self.asset.is_active:
# raise ServerError('该主机被禁用 Host %s is not active.' % self.ip)
#
# if not self.user.is_active:
# raise ServerError('该用户被禁用 User %s is not active.' % self.username)
# password = CRYPTOR.decrypt(self.])
# return self.username, password, self.ip, int(self.asset.port)
return
'root'
,
'redhat'
,
'127.0.0.1'
,
22
def
get_connection
(
self
):
"""
Get the ssh connection for reuse
获取连接套接字
"""
username
,
password
,
ip
,
port
=
self
.
get_connect_item
()
logger
.
debug
(
"username:
%
s, password:
%
s, ip:
%
s, port:
%
s"
%
(
username
,
password
,
ip
,
port
))
# 发起ssh连接请求 Make a ssh connection
ssh
=
paramiko
.
SSHClient
()
ssh
.
load_system_host_keys
()
ssh
.
set_missing_host_key_policy
(
paramiko
.
AutoAddPolicy
())
try
:
ssh
.
connect
(
ip
,
port
=
port
,
username
=
username
,
password
=
password
)
except
paramiko
.
ssh_exception
.
AuthenticationException
,
paramiko
.
ssh_exception
.
SSHException
:
raise
ServerError
(
'认证错误 Authentication Error.'
)
except
socket
.
error
:
raise
ServerError
(
'端口可能不对 Connect SSH Socket Port Error, Please Correct it.'
)
else
:
return
ssh
def
connect
(
self
):
"""
Connect server.
连接服务器
"""
ps1
=
"PS1='[
\
u@
%
s
\
W]
\
$ '
\n
"
%
self
.
ip
login_msg
=
"clear;echo -e '
\\
033[32mLogin
%
s done. Enjoy it.
\\
033[0m'
\n
"
%
self
.
ip
# 发起ssh连接请求 Make a ssh connection
ssh
=
self
.
get_connection
()
# 获取连接的隧道并设置窗口大小 Make a channel and set windows size
global
channel
win_size
=
self
.
get_win_size
()
self
.
chan
=
channel
=
ssh
.
invoke_shell
(
height
=
win_size
[
0
],
width
=
win_size
[
1
])
try
:
signal
.
signal
(
signal
.
SIGWINCH
,
self
.
set_win_size
)
except
:
pass
# 设置PS1并提示 Set PS1 and msg it
#channel.send(ps1)
#channel.send(login_msg)
channel
.
send
(
'echo ${SSH_TTY}
\n
'
)
global
SSH_TTY
while
not
channel
.
recv_ready
():
time
.
sleep
(
1
)
tmp
=
channel
.
recv
(
1024
)
#print 'ok'+tmp+'ok'
SSH_TTY
=
re
.
search
(
r'(?<=/dev/).*'
,
tmp
)
.
group
()
.
strip
()
channel
.
send
(
'clear
\n
'
)
# Make ssh interactive tunnel
self
.
posix_shell
(
ssh
)
# Shutdown channel socket
channel
.
close
()
ssh
.
close
()
def
execute
(
self
,
cmd
):
"""
execute cmd on the asset
执行命令
"""
pass
class
PyCrypt
(
object
):
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment