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
Nov 04, 2015
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
移动api中关于tty到connect.py
parent
c8c00612
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
...
...
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
):
...
...
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