Merge pull request #188 from jumpserver/dev

新增功能
pull/194/head
ibuler 2016-04-01 13:49:28 +08:00
commit f65290ef38
4 changed files with 93 additions and 79 deletions

View File

@ -4,10 +4,10 @@
#欢迎使用Jumpserver #欢迎使用Jumpserver
**Jumpserver** 是一款由python编写开源的跳板机(堡垒机)系统实现了跳板机应有的功能。基于ssh协议来管理客户端无需安装agent。 **Jumpserver** 是一款由python编写开源的跳板机(堡垒机)系统实现了跳板机应有的功能。基于ssh协议来管理客户端无需安装agent。
支持常见系统: 支持常见系统:
1. redhat centos 1. CentOS, RedHat, Fedora, Amazon Linux
2. debian 2. Debian
3. suse ubuntu 3. SUSE, Ubuntu
4. freebsd 4. FreeBSD
5. 其他ssh协议硬件设备 5. 其他ssh协议硬件设备
###截图: ###截图:

View File

@ -436,8 +436,11 @@ class Nav(object):
""" """
def __init__(self, user): def __init__(self, user):
self.user = user self.user = user
self.search_result = {} self.search_result = None
self.user_perm = {} self.user_perm = get_group_user_perm(self.user)
self.perm_assets = sorted(self.user_perm.get('asset', []).keys(),
key=lambda x: [int(num) for num in x.ip.split('.') if num.isdigit()])
self.perm_asset_groups = self.user_perm.get('asset_group', [])
@staticmethod @staticmethod
def print_nav(): def print_nav():
@ -460,38 +463,42 @@ class Nav(object):
""" """
print textwrap.dedent(msg) print textwrap.dedent(msg)
def search(self, str_r=''): def get_asset_group_member(self, str_r):
gid_pattern = re.compile(r'^g\d+$') gid_pattern = re.compile(r'^g\d+$')
# 获取用户授权的所有主机信息
if not self.user_perm:
self.user_perm = get_group_user_perm(self.user)
user_asset_all = self.user_perm.get('asset').keys()
# 搜索结果保存
user_asset_search = []
if str_r:
# 资产组组id匹配
if gid_pattern.match(str_r): if gid_pattern.match(str_r):
gid = int(str_r.lstrip('g')) gid = int(str_r.lstrip('g'))
# 获取资产组包含的资产 # 获取资产组包含的资产
asset_group = get_object(AssetGroup, id=gid) asset_group = get_object(AssetGroup, id=gid)
if asset_group: if asset_group:
user_asset_search = asset_group.asset_set.all() self.search_result = list(asset_group.asset_set.all())
else: else:
color_print('没有该资产组或没有权限') color_print('没有该资产组或没有权限')
return return
def search(self, str_r=''):
# 搜索结果保存
if str_r:
try:
id_ = int(str_r)
if id_ < len(self.search_result):
self.search_result = [self.search_result[id_]]
return
else: else:
raise ValueError
except (ValueError, TypeError):
# 匹配 ip, hostname, 备注 # 匹配 ip, hostname, 备注
for asset in user_asset_all: self.search_result = [asset for asset in self.perm_assets if str_r in str(asset.ip)
if str_r in asset.ip or str_r in str(asset.hostname) or str_r in str(asset.comment): or str_r in str(asset.hostname) or str_r in str(asset.comment)]
user_asset_search.append(asset)
else: else:
# 如果没有输入就展现所有 # 如果没有输入就展现所有
user_asset_search = user_asset_all self.search_result = self.perm_assets
self.search_result = dict(zip(range(len(user_asset_search)), user_asset_search)) def print_search_result(self):
color_print('[%-3s] %-12s %-15s %-5s %-10s %s' % ('ID', '主机名', 'IP', '端口', '系统用户', '备注'), 'title') color_print('[%-3s] %-12s %-15s %-5s %-10s %s' % ('ID', '主机名', 'IP', '端口', '系统用户', '备注'), 'title')
for index, asset in self.search_result.items(): if hasattr(self.search_result, '__iter__'):
for index, asset in enumerate(self.search_result):
# 获取该资产信息 # 获取该资产信息
asset_info = get_asset_info(asset) asset_info = get_asset_info(asset)
# 获取该资产包含的角色 # 获取该资产包含的角色
@ -500,6 +507,39 @@ class Nav(object):
role, asset.comment) role, asset.comment)
print print
def try_connect(self):
try:
asset = self.search_result[0]
roles = list(self.user_perm.get('asset').get(asset).get('role'))
if len(roles) == 1:
role = roles[0]
elif len(roles) > 1:
print "\033[32m[ID] 系统用户\033[0m"
for index, role in enumerate(roles):
print "[%-2s] %s" % (index, role.name)
print
print "授权系统用户超过1个请输入ID, q退出"
try:
role_index = raw_input("\033[1;32mID>:\033[0m ").strip()
if role_index == 'q':
return
else:
role = roles[int(role_index)]
except IndexError:
color_print('请输入正确ID', 'red')
return
else:
color_print('没有映射用户', 'red')
return
ssh_tty = SshTty(login_user, asset, role)
print('Connecting %s ...' % asset.hostname)
ssh_tty.connect()
except (KeyError, ValueError):
color_print('请输入正确ID', 'red')
except ServerError, e:
color_print(e, 'red')
def print_asset_group(self): def print_asset_group(self):
""" """
打印用户授权的资产组 打印用户授权的资产组
@ -515,9 +555,6 @@ class Nav(object):
批量执行命令 批量执行命令
""" """
while True: while True:
if not self.user_perm:
self.user_perm = get_group_user_perm(self.user)
roles = self.user_perm.get('role').keys() roles = self.user_perm.get('role').keys()
if len(roles) > 1: # 授权角色数大于1 if len(roles) > 1: # 授权角色数大于1
color_print('[%-2s] %-15s' % ('ID', '系统用户'), 'info') color_print('[%-2s] %-15s' % ('ID', '系统用户'), 'info')
@ -587,8 +624,6 @@ class Nav(object):
def upload(self): def upload(self):
while True: while True:
if not self.user_perm:
self.user_perm = get_group_user_perm(self.user)
try: try:
print "进入批量上传模式" print "进入批量上传模式"
print "请输入主机名或ansible支持的pattern, 多个主机:分隔 q退出" print "请输入主机名或ansible支持的pattern, 多个主机:分隔 q退出"
@ -640,8 +675,6 @@ class Nav(object):
def download(self): def download(self):
while True: while True:
if not self.user_perm:
self.user_perm = get_group_user_perm(self.user)
try: try:
print "进入批量下载模式" print "进入批量下载模式"
print "请输入主机名或ansible支持的pattern, 多个主机:分隔,q退出" print "请输入主机名或ansible支持的pattern, 多个主机:分隔,q退出"
@ -723,9 +756,14 @@ def main():
sys.exit(0) sys.exit(0)
if option in ['P', 'p', '\n', '']: if option in ['P', 'p', '\n', '']:
nav.search() nav.search()
nav.print_search_result()
continue continue
if option.startswith('/') or gid_pattern.match(option): if option.startswith('/'):
nav.search(option.lstrip('/')) nav.search(option.lstrip('/'))
nav.print_search_result()
elif gid_pattern.match(option):
nav.get_asset_group_member(str_r=option)
nav.print_search_result()
elif option in ['G', 'g']: elif option in ['G', 'g']:
nav.print_asset_group() nav.print_asset_group()
continue continue
@ -741,36 +779,12 @@ def main():
elif option in ['Q', 'q', 'exit']: elif option in ['Q', 'q', 'exit']:
sys.exit() sys.exit()
else: else:
try: nav.search(option)
asset = nav.search_result[int(option)] if len(nav.search_result) == 1:
roles = nav.user_perm.get('asset').get(asset).get('role') nav.try_connect()
if len(roles) > 1:
role_check = dict(zip(range(len(roles)), roles))
print "\033[32m[ID] 系统用户\033[0m"
for index, role in role_check.items():
print "[%-2s] %s" % (index, role.name)
print
print "授权系统用户超过1个请输入ID, q退出"
try:
role_index = raw_input("\033[1;32mID>:\033[0m ").strip()
if role_index == 'q':
continue
else: else:
role = role_check[int(role_index)] nav.print_search_result()
except IndexError:
color_print('请输入正确ID', 'red')
continue
elif len(roles) == 1:
role = list(roles)[0]
else:
color_print('没有映射用户', 'red')
continue
ssh_tty = SshTty(login_user, asset, role)
ssh_tty.connect()
except (KeyError, ValueError):
color_print('请输入正确ID', 'red')
except ServerError, e:
color_print(e, 'red')
except IndexError, e: except IndexError, e:
color_print(e) color_print(e)
time.sleep(5) time.sleep(5)

View File

@ -80,12 +80,12 @@ class PreSetup(object):
self.ip = '' self.ip = ''
self.key = ''.join(random.choice(string.ascii_lowercase + string.digits) \ self.key = ''.join(random.choice(string.ascii_lowercase + string.digits) \
for _ in range(16)) for _ in range(16))
self.dist = platform.dist()[0].lower() self.dist = platform.linux_distribution(supported_dists=['system'])[0].lower()
self.version = platform.dist()[1] self.version = platform.linux_distribution(supported_dists=['system'])[1]
@property @property
def _is_redhat(self): def _is_redhat(self):
if self.dist == "centos" or self.dist == "redhat" or self.dist == "fedora": if self.dist == "centos" or self.dist == "redhat" or self.dist == "fedora" or self.dist == "amazon linux ami":
return True return True
@property @property
@ -105,7 +105,7 @@ class PreSetup(object):
def check_platform(self): def check_platform(self):
if not (self._is_redhat or self._is_ubuntu): if not (self._is_redhat or self._is_ubuntu):
print(u"支持的平台: CentOS, RedHat, Fedora, Debian, Ubuntu, 暂不支持其他平台安装.") print(u"支持的平台: CentOS, RedHat, Fedora, Debian, Ubuntu, Amazon Linux, 暂不支持其他平台安装.")
exit() exit()
@staticmethod @staticmethod

View File

@ -109,7 +109,7 @@
timely: 2, timely: 2,
theme: "yellow_right_effect", theme: "yellow_right_effect",
rules: { rules: {
check_name: [/^\w{2,20}$/, '大小写字母数字和下划线,2-20位'], check_name: [/^(\w|\-){2,20}$/, '大小写字母、数字、中划线和下划线,2-20位'],
check_port: [/^\d{1,5}$/, '端口号不正确'], check_port: [/^\d{1,5}$/, '端口号不正确'],
either: function(){ either: function(){
return $('#password').val() == '' return $('#password').val() == ''