Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
L
luna
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
luna
Commits
555448c4
Commit
555448c4
authored
Feb 28, 2017
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Fixture] 完成日志记录
parent
86cf253e
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
147 additions
and
100 deletions
+147
-100
app.py
luna/app.py
+40
-7
channel.py
luna/channel.py
+11
-4
service.js
luna/dist/ts/service.js
+2
-0
logger.py
luna/logger.py
+44
-43
proxy.py
luna/proxy.py
+38
-38
websocket.py
luna/views/websocket.py
+8
-8
run_server.py
run_server.py
+4
-0
No files found.
luna/app.py
View file @
555448c4
...
...
@@ -2,9 +2,9 @@
import
logging
import
time
import
threading
from
flask
import
Flask
import
socketio
from
flask_socketio
import
SocketIO
from
.conf
import
config
from
.service
import
service
...
...
@@ -18,19 +18,52 @@ __version__ = '0.4.0'
class
Luna
(
Flask
):
service
=
service
clients
=
{}
proxy_list
=
{}
clients
=
{}
active
=
True
def
run
(
self
,
host
=
None
,
port
=
None
,
debug
=
None
,
**
options
):
def
bootstrap
(
self
):
print
(
time
.
ctime
())
print
(
'Luna version
%
s, more see https://www.jumpserver.org'
%
__version__
)
print
(
'Luna version
%
s, more see https://www.jumpserver.org'
%
__version__
)
print
(
'Starting ssh server at
%(host)
s:
%(port)
s'
%
{
'host'
:
self
.
config
[
'BIND_HOST'
],
'port'
:
self
.
config
[
'LISTEN_PORT'
]})
print
(
'Quit the server with CONTROL-C.'
)
self
.
heatbeat
()
def
handle_task
(
self
,
tasks
):
for
task
in
tasks
:
if
task
[
'name'
]
==
'kill_proxy'
:
try
:
proxy_log_id
=
int
(
task
[
'proxy_log_id'
])
except
ValueError
:
pass
if
proxy_log_id
in
self
.
proxy_list
:
client_channel
,
backend_channel
=
self
.
proxy_list
.
get
(
proxy_log_id
)
client_channel
.
send
(
'Terminated by admin '
)
backend_channel
.
close
()
client_channel
.
close
()
def
heatbeat
(
self
):
def
_keep
():
while
True
:
result
=
service
.
terminal_heatbeat
()
if
result
is
None
:
logger
.
warning
(
'Terminal heatbeat failed or '
'Terminal need accepted by administrator'
)
else
:
tasks
=
result
.
get
(
'tasks'
)
if
tasks
:
logger
.
info
(
'Receive task:
%
s'
%
tasks
)
print
(
tasks
)
self
.
handle_task
(
tasks
)
time
.
sleep
(
config
.
HEATBEAT_INTERVAL
)
return
Flask
.
run
(
self
,
host
=
host
,
port
=
port
,
debug
=
debug
,
**
options
)
thread
=
threading
.
Thread
(
target
=
_keep
)
thread
.
daemon
=
True
thread
.
start
()
def
stop
(
self
):
self
.
active
=
False
...
...
@@ -38,9 +71,9 @@ class Luna(Flask):
i
.
disconnect
()
socket_io
.
stop
()
async_mode
=
'
threading
'
async_mode
=
'
gevent
'
app
=
Luna
(
__name__
,
template_folder
=
'dist'
)
socket_io
=
SocketIO
(
app
)
socket_io
=
SocketIO
(
app
,
async_mode
=
async_mode
)
app
.
config
.
update
(
**
config
)
#socket_io = socketio.Server(logger=False, async_mode=async_mode)
#app.wsgi_app = socketio.Middleware(socket_io, app.wsgi_app)
luna/channel.py
View file @
555448c4
...
...
@@ -16,7 +16,7 @@ class ProxyChannel(object):
def
send
(
self
,
s
):
"""Proxy server中使用select, 通过socketio发送给用户"""
return
socket_io
.
emit
(
'data'
,
s
,
roo
t
=
self
.
sid
)
return
socket_io
.
emit
(
'data'
,
s
,
roo
m
=
self
.
sid
)
def
recv
(
self
,
size
):
"""Proxy server使用select, 接受socketio客户端数据发送来的数据"""
...
...
@@ -24,10 +24,17 @@ class ProxyChannel(object):
def
write
(
self
,
s
):
"""socket io写数据,proxy可以通过recv收到"""
print
(
'Client write message:
%
s'
%
s
)
self
.
cli
.
send
(
s
)
def
set_win_size
(
self
,
size
):
self
.
win_width
,
self
.
win_height
=
size
win_width
,
win_height
=
size
try
:
self
.
win_width
=
int
(
win_width
)
self
.
win_height
=
int
(
win_height
)
except
TypeError
:
pass
def
close
(
self
):
self
.
srv
.
close
()
self
.
cli
.
close
()
luna/dist/ts/service.js
View file @
555448c4
...
...
@@ -328,6 +328,8 @@ var AppService = (function () {
socket
.
on
(
'connect'
,
function
()
{
socket
.
emit
(
'machine'
,
uuid
);
exports
.
DataStore
.
term
[
id
][
"term"
].
on
(
'data'
,
function
(
data
)
{
// console.log(data);
// socket.emit('data', 'echo 你好');
socket
.
emit
(
'data'
,
data
);
});
socket
.
on
(
'data'
,
function
(
data
)
{
...
...
luna/logger.py
View file @
555448c4
# # ~*~ coding: utf-8 ~*~
# #
#
# import os
# import logging
# from logging import StreamHandler
# from logging.handlers import TimedRotatingFileHandler
#
# from .conf import config
# PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
#
#
# LOG_LEVELS = {
# 'DEBUG': logging.DEBUG,
# 'INFO': logging.INFO,
# 'WARN': logging.WARNING,
# 'WARNING': logging.WARNING,
# 'ERROR': logging.ERROR,
# 'FATAL': logging.FATAL,
# 'CRITICAL': logging.CRITICAL,
# }
#
#
# def create_logger():
# level = config.get('LOG_LEVEL', None)
# level = LOG_LEVELS.get(level, logging.INFO)
# log_dir = config.get('LOG_DIR', os.path.join(PROJECT_DIR, 'logs'))
# log_path = os.path.join(log_dir, 'luna.log')
# logger_root = logging.getLogger()
# logger = logging.getLogger(config.get('NAME', 'luna'))
#
# main_formatter = logging.Formatter(
# fmt='%(asctime)s [%(module)s %(levelname)s] %(message)s',
# datefmt='%Y-%m-%d %H:%M:%S')
# console_handler = StreamHandler()
# file_handler = TimedRotatingFileHandler(
# filename=log_path, when='D', backupCount=10)
#
# for handler in [console_handler, file_handler]:
# handler.setFormatter(main_formatter)
# logger.addHandler(handler)
# logger_root.addHandler(console_handler)
# logger_root.setLevel(logging.WARNING)
# logger.setLevel(level)
#
#
import
os
import
logging
from
logging
import
StreamHandler
from
logging.handlers
import
TimedRotatingFileHandler
from
.conf
import
config
from
.app
import
app
PROJECT_DIR
=
os
.
path
.
dirname
(
os
.
path
.
dirname
(
os
.
path
.
dirname
(
__file__
)))
LOG_LEVELS
=
{
'DEBUG'
:
logging
.
DEBUG
,
'INFO'
:
logging
.
INFO
,
'WARN'
:
logging
.
WARNING
,
'WARNING'
:
logging
.
WARNING
,
'ERROR'
:
logging
.
ERROR
,
'FATAL'
:
logging
.
FATAL
,
'CRITICAL'
:
logging
.
CRITICAL
,
}
def
create_logger
():
level
=
config
.
get
(
'LOG_LEVEL'
,
None
)
level
=
LOG_LEVELS
.
get
(
level
,
logging
.
INFO
)
log_dir
=
config
.
get
(
'LOG_DIR'
,
os
.
path
.
join
(
PROJECT_DIR
,
'logs'
))
log_path
=
os
.
path
.
join
(
log_dir
,
'luna.log'
)
logger_root
=
logging
.
getLogger
()
logger
=
logging
.
getLogger
(
config
.
get
(
'NAME'
,
'luna'
))
main_formatter
=
logging
.
Formatter
(
fmt
=
'
%(asctime)
s [
%(module)
s
%(levelname)
s]
%(message)
s'
,
datefmt
=
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
console_handler
=
StreamHandler
()
file_handler
=
TimedRotatingFileHandler
(
filename
=
log_path
,
when
=
'D'
,
backupCount
=
10
)
for
handler
in
[
console_handler
,
file_handler
]:
handler
.
setFormatter
(
main_formatter
)
logger
.
addHandler
(
handler
)
logger_root
.
addHandler
(
console_handler
)
logger_root
.
setLevel
(
logging
.
WARNING
)
logger
.
setLevel
(
level
)
# def get_logger(name):
# return logging.getLogger('luna.%s' % name)
#
...
...
luna/proxy.py
View file @
555448c4
...
...
@@ -34,7 +34,7 @@ class ProxyServer(object):
IGNORE_OUTPUT_COMMAND
=
[
re
.
compile
(
r'^cat\s+'
),
re
.
compile
(
r'^tailf?\s+'
)]
def
__init__
(
self
,
app
,
user
,
asset
,
system_user
,
client_channel
):
def
__init__
(
self
,
app
,
user
,
asset
,
system_user
,
client_channel
,
stop_event
):
self
.
app
=
app
self
.
user
=
user
self
.
asset
=
asset
...
...
@@ -42,6 +42,7 @@ class ProxyServer(object):
self
.
service
=
app
.
service
self
.
client_channel
=
client_channel
self
.
change_win_size_event
=
threading
.
Event
()
self
.
stop_event
=
stop_event
self
.
input
=
''
self
.
output
=
''
...
...
@@ -66,7 +67,7 @@ class ProxyServer(object):
def
get_output
(
self
):
width
=
self
.
client_channel
.
win_width
height
=
self
.
client_channel
.
win_heig
th
height
=
self
.
client_channel
.
win_heig
ht
parser
=
TtyIOParser
(
width
=
width
,
height
=
height
)
self
.
output
=
parser
.
parse_output
(
b
''
.
join
(
self
.
output_data
))
if
self
.
input
:
...
...
@@ -85,7 +86,7 @@ class ProxyServer(object):
def
get_input
(
self
):
width
=
self
.
client_channel
.
win_width
height
=
self
.
client_channel
.
win_heig
th
height
=
self
.
client_channel
.
win_heig
ht
parser
=
TtyIOParser
(
width
=
width
,
height
=
height
)
self
.
input
=
parser
.
parse_input
(
b
''
.
join
(
self
.
input_data
))
...
...
@@ -103,6 +104,12 @@ class ProxyServer(object):
asset
=
self
.
asset
system_user
=
self
.
system_user
client_channel
=
self
.
client_channel
try
:
width
=
int
(
client_channel
.
win_width
)
height
=
int
(
client_channel
.
win_height
)
print
(
'term
%
s*
%
s'
%
(
width
,
height
))
except
TypeError
:
pass
if
not
self
.
validate_user_asset_permission
():
logger
.
warning
(
'User
%
s have no permission connect
%
s with
%
s'
%
(
user
.
username
,
asset
.
ip
,
system_user
.
username
))
...
...
@@ -115,6 +122,7 @@ class ProxyServer(object):
"system_user"
:
system_user
.
username
,
"login_type"
:
"WT"
,
"date_start"
:
time
.
time
(),
"is_failed"
:
0
}
self
.
proxy_log_id
=
proxy_log_id
=
self
.
service
.
send_proxy_log
(
data
)
self
.
app
.
proxy_list
[
proxy_log_id
]
=
self
.
client_channel
,
self
.
backend_channel
try
:
client_channel
.
send
(
wr
(
'Connecting
%
s@
%
s:
%
s ... '
%
...
...
@@ -171,42 +179,32 @@ class ProxyServer(object):
self
.
app
.
proxy_list
[
self
.
proxy_log_id
]
=
\
[
self
.
client_channel
,
backend_channel
]
#while True:
# r, w, x = select.select([client_channel], [], [])
# if client_channel in r:
# data = client_channel.recv(100)
# if len(data) == 0:
# break
# print('Receive from client: %s' % data)
#return
if
backend_channel
is
None
:
return
while
True
:
while
not
self
.
stop_event
.
set
()
:
r
,
w
,
x
=
select
.
select
([
client_channel
,
backend_channel
],
[],
[])
#if self.change_win_size_event.is_set():
# self.change_win_size_event.clear()
# width = self.client_channel.win_width
# height = self.client_channel.win_heig
th
# height = self.client_channel.win_heig
ht
# backend_channel.resize_pty(width=width, height=height)
if
client_channel
in
r
:
# Get output of the command
print
(
'Recive from client'
)
# self.is_first_input = False
# if self.in_input_state is False:
# self.get_output()
# del self.output_data[:]
self
.
is_first_input
=
False
if
self
.
in_input_state
is
False
:
self
.
get_output
()
del
self
.
output_data
[:]
#
self.in_input_state = True
self
.
in_input_state
=
True
client_data
=
client_channel
.
recv
(
1024
)
#
if self.is_finish_input(client_data):
#
self.in_input_state = False
#
self.get_input()
#
del self.input_data[:]
if
self
.
is_finish_input
(
client_data
):
self
.
in_input_state
=
False
self
.
get_input
()
del
self
.
input_data
[:]
if
len
(
client_data
)
==
0
:
break
...
...
@@ -214,25 +212,26 @@ class ProxyServer(object):
if
backend_channel
in
r
:
backend_data
=
backend_channel
.
recv
(
1024
)
#
if self.in_input_state:
#
self.input_data.append(backend_data)
#
else:
#
self.output_data.append(backend_data)
if
self
.
in_input_state
:
self
.
input_data
.
append
(
backend_data
)
else
:
self
.
output_data
.
append
(
backend_data
)
if
len
(
backend_data
)
==
0
:
#
client_channel.send(
#
wr('Disconnect from %s' % self.asset.ip))
#
logger.info('Logout from asset %(host)s: %(username)s' % {
#
'host': self.asset.ip,
#
'username': self.user.username,
#
})
client_channel
.
send
(
wr
(
'Disconnect from
%
s'
%
self
.
asset
.
ip
))
logger
.
info
(
'Logout from asset
%(host)
s:
%(username)
s'
%
{
'host'
:
self
.
asset
.
ip
,
'username'
:
self
.
user
.
username
,
})
break
client_channel
.
send
(
backend_data
)
if
self
.
is_match_ignore_command
(
self
.
input
):
output
=
'ignore output ...'
else
:
output
=
backend_data
# Todo: record log send
# if self.is_match_ignore_command(self.input):
# output = 'ignore output ...'
# else:
# output = backend_data
# record_data = {
# 'proxy_log_id': self.proxy_log_id,
# 'output': output,
...
...
@@ -245,4 +244,5 @@ class ProxyServer(object):
"date_finished"
:
time
.
time
(),
}
self
.
service
.
finish_proxy_log
(
data
)
del
self
.
app
.
proxy_list
[
self
.
proxy_log_id
]
luna/views/websocket.py
View file @
555448c4
...
...
@@ -41,20 +41,20 @@ def handle_machine(message):
clients
[
sid
][
'port'
]
=
port
=
8022
user
=
to_dotmap
({
'username'
:
'root'
,
'name'
:
'redhat'
})
asset
=
to_dotmap
({
'hostname'
:
host
,
'ip'
:
host
,
'port'
:
8022
})
# win_width = request.cookies.get('col
')
# win_height = request.cookies.get('row
')
win_width
=
request
.
cookies
.
get
(
'cols
'
)
win_height
=
request
.
cookies
.
get
(
'rows
'
)
system_user
=
to_dotmap
({
'name'
:
'jms'
,
'username'
:
'jms'
,
'id'
:
102
})
clients
[
sid
][
'proxy_chan'
]
=
proxy_chan
=
ProxyChannel
(
sid
)
# proxy_chan.set_win_size((win_width, win_height))
proxy_server
=
ProxyServer
(
app
,
user
,
asset
,
system_user
,
proxy_chan
)
proxy_chan
.
set_win_size
((
win_width
,
win_height
))
stop_event
=
threading
.
Event
()
clients
[
sid
][
'stop_event'
]
=
stop_event
proxy_server
=
ProxyServer
(
app
,
user
,
asset
,
system_user
,
proxy_chan
,
stop_event
)
socket_io
.
start_background_task
(
proxy_server
.
proxy
)
# t = threading.Thread(target=proxy_server.proxy, args=())
# t.daemon = True
# t.start()
@socket_io.on
(
'data'
)
def
handle_data
(
message
):
def
handle_data
(
message
):
sid
=
request
.
sid
logger
.
debug
(
'Receive data:
%
s'
%
message
)
if
clients
[
sid
][
'proxy_chan'
]:
...
...
run_server.py
View file @
555448c4
...
...
@@ -5,6 +5,7 @@ import sys
import
os
from
luna
import
app
,
socket_io
from
luna.tasks
import
command_task
,
record_task
host
=
app
.
config
[
'BIND_HOST'
]
port
=
app
.
config
[
'LISTEN_PORT'
]
...
...
@@ -18,6 +19,9 @@ if __name__ == '__main__':
pass
try
:
command_task
.
run
()
record_task
.
run
()
app
.
bootstrap
()
socket_io
.
run
(
app
)
# app.run(threaded=True, host=host, port=port)
except
KeyboardInterrupt
:
...
...
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