Merge branch 'dev' of https://git.coding.net/jumpserver/jumpserver into NormalUserPageLZ

pull/26/head
liuzheng712 2015-11-21 21:24:17 +08:00
commit ea059790a9
52 changed files with 745 additions and 1994 deletions

View File

@ -19,10 +19,11 @@ import struct, fcntl, signal, socket, select
os.environ['DJANGO_SETTINGS_MODULE'] = 'jumpserver.settings' os.environ['DJANGO_SETTINGS_MODULE'] = 'jumpserver.settings'
if django.get_version() != '1.6': if django.get_version() != '1.6':
django.setup() django.setup()
from jumpserver.api import ServerError, User, Asset, AssetGroup, get_object, mkdir from jumpserver.api import ServerError, User, Asset, AssetGroup, get_object, mkdir, get_asset_info, get_role
from jumpserver.api import logger, Log, TtyLog from jumpserver.api import logger, Log, TtyLog, get_role_key
from jperm.perm_api import gen_resource, get_group_asset_perm, get_group_user_perm
from jumpserver.settings import LOG_DIR from jumpserver.settings import LOG_DIR
from jperm.ansible_api import Command
login_user = get_object(User, username=getpass.getuser()) login_user = get_object(User, username=getpass.getuser())
VIM_FLAG = False VIM_FLAG = False
@ -73,15 +74,15 @@ class Tty(object):
A virtual tty class A virtual tty class
一个虚拟终端类实现连接ssh和记录日志基类 一个虚拟终端类实现连接ssh和记录日志基类
""" """
def __init__(self, username, asset_name): def __init__(self, user, asset, role):
self.username = username self.username = user.username
self.asset_name = asset_name self.asset_name = asset.hostname
self.ip = None self.ip = None
self.port = 22 self.port = 22
self.channel = None self.channel = None
#self.asset = get_object(Asset, name=asset_name) self.asset = asset
#self.user = get_object(User, username=username) self.user = user
self.role = None self.role = role
self.ssh = None self.ssh = None
self.connect_info = None self.connect_info = None
self.login_type = 'ssh' self.login_type = 'ssh'
@ -287,7 +288,10 @@ class Tty(object):
# 2. get 映射用户 # 2. get 映射用户
# 3. get 映射用户的账号密码或者key # 3. get 映射用户的账号密码或者key
# self.connect_info = {'user': '', 'asset': '', 'ip': '', 'port': 0, 'role_name': '', 'role_pass': '', 'role_key': ''} # self.connect_info = {'user': '', 'asset': '', 'ip': '', 'port': 0, 'role_name': '', 'role_pass': '', 'role_key': ''}
self.connect_info = {'user': 'a', 'asset': 'b', 'ip': '127.0.0.1', 'port': 22, 'role_name': 'root', 'role_pass': 'redhat', 'role_key': ''} asset_info = get_asset_info(self.asset)
self.connect_info = {'user': self.user, 'asset': self.asset, 'ip': asset_info.get('ip'),
'port': int(asset_info.get('port')), 'role_name': self.role.name,
'role_pass': self.role.password, 'role_key': self.role.key_path}
return self.connect_info return self.connect_info
def get_connection(self): def get_connection(self):
@ -301,18 +305,24 @@ class Tty(object):
ssh.load_system_host_keys() ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try: try:
if connect_info.get('role_pass'): role_key = get_role_key(self.user, self.role)
ssh.connect(connect_info.get('ip'), if role_key and os.path.isfile(role_key):
port=connect_info.get('port'), try:
username=connect_info.get('role_name'), ssh.connect(connect_info.get('ip'),
password=connect_info.get('role_pass'), port=connect_info.get('port'),
look_for_keys=False) username=connect_info.get('role_name'),
else: key_filename=role_key,
ssh.connect(connect_info.get('ip'), look_for_keys=False)
port=connect_info.get('port'), self.ssh = ssh
username=connect_info.get('role_name'), return ssh
key_filename=connect_info.get('role_key'), except paramiko.ssh_exception.AuthenticationException, paramiko.ssh_exception.SSHException:
look_for_keys=False) pass
ssh.connect(connect_info.get('ip'),
port=connect_info.get('port'),
username=connect_info.get('role_name'),
password=connect_info.get('role_pass'),
look_for_keys=False)
except paramiko.ssh_exception.AuthenticationException, paramiko.ssh_exception.SSHException: except paramiko.ssh_exception.AuthenticationException, paramiko.ssh_exception.SSHException:
raise ServerError('认证失败 Authentication Error.') raise ServerError('认证失败 Authentication Error.')
@ -458,28 +468,12 @@ class SshTty(Tty):
channel.close() channel.close()
ssh.close() ssh.close()
def execute(self, cmd):
"""
execute cmd on the asset
执行命令
"""
pass
def print_user_asset_group_info(user):
asset_groups = AssetGroup.objects.all()
for asset_group in asset_groups:
if asset_group.comment:
print '[%-2s] %-10s %s' % (asset_group.id, asset_group.name, asset_group.comment)
else:
print '[%-2s] %-10s' % (asset_group.id, asset_group.name)
print
class Nav(object): class Nav(object):
def __init__(self, user): def __init__(self, user):
self.user = user self.user = user
self.search_result = {} self.search_result = {}
self.user_perm = {}
@staticmethod @staticmethod
def print_nav(): def print_nav():
@ -510,7 +504,9 @@ class Nav(object):
def search(self, str_r=''): def search(self, str_r=''):
gid_pattern = re.compile(r'^g\d+$') gid_pattern = re.compile(r'^g\d+$')
user_asset_all = list(Asset.objects.all()) 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 = [] user_asset_search = []
if str_r: if str_r:
if gid_pattern.match(str_r): if gid_pattern.match(str_r):
@ -523,13 +519,15 @@ class Nav(object):
user_asset_search = user_asset_all user_asset_search = user_asset_all
self.search_result = dict(zip(range(len(user_asset_search)), user_asset_search)) self.search_result = dict(zip(range(len(user_asset_search)), user_asset_search))
print '\033[32m[%-3s] %-15s %-15s %-5s %-10s %s \033[0m' % ('ID', 'AssetName', 'IP', 'Port', 'Role', 'Comment')
print '\033[32m[%-3s] %-15s %-15s %-5s %-5s %s \033[0m' % ('ID', 'AssetName', 'IP', 'Port', 'Role', 'Comment')
for index, asset in self.search_result.items(): for index, asset in self.search_result.items():
asset_info = get_asset_info(asset)
role = [str(role.name) for role in self.user_perm.get('asset').get(asset).get('role')]
if asset.comment: if asset.comment:
print '[%-3s] %-15s %-15s %-5s %-5s %s' % (index, 'asset_name'+str(index), asset.ip, asset.port, 'role', asset.comment) print '[%-3s] %-15s %-15s %-5s %-10s %s' % (index, asset.hostname, asset.ip, asset_info.get('port'),
role, asset.comment)
else: else:
print '[%-3s] %-15s %-15s %-5s %-5s' % (index, 'asset_name'+str(index), asset.ip, asset.port, 'role') print '[%-3s] %-15s %-15s %-5s %-10s' % (index, asset.hostname, asset.ip, asset_info.get('port'), role)
print print
@staticmethod @staticmethod
@ -544,6 +542,50 @@ class Nav(object):
print '[%-3s] %-15s' % (asset_group.id, asset_group.name) print '[%-3s] %-15s' % (asset_group.id, asset_group.name)
print print
def exec_cmd(self):
self.search()
while True:
print "请输入主机名、IP或ansile支持的pattern, q退出"
try:
pattern = raw_input("\033[1;32mPattern>:\033[0m ").strip()
if pattern == 'q':
break
else:
if not self.user_perm:
self.user_perm = get_group_user_perm(self.user)
res = gen_resource(self.user, perm=self.user_perm)
cmd = Command(res)
logger.debug(res)
for inv in cmd.inventory.get_hosts(pattern=pattern):
print inv.name
confirm_host = raw_input("\033[1;32mIs that [y/n]>:\033[0m ").strip()
if confirm_host == 'y':
while True:
print "请输入执行的命令, 按q退出"
command = raw_input("\033[1;32mCmds>:\033[0m ").strip()
if command == 'q':
break
result = cmd.run(module_name='shell', command=command, pattern=pattern)
for k, v in result.items():
if k == 'ok':
for host, output in v.items():
color_print("%s => %s" % (host, 'Ok'), 'green')
print output
print
else:
for host, output in v.items():
color_print("%s => %s" % (host, k), 'red')
color_print(output, 'red')
print
print "=" * 20
print
else:
continue
except EOFError:
print
break
def main(): def main():
""" """
@ -575,14 +617,35 @@ def main():
nav.print_asset_group() nav.print_asset_group()
continue continue
elif option in ['E', 'e']: elif option in ['E', 'e']:
# exec_cmd_servers(login_name) nav.exec_cmd()
pass continue
elif option in ['Q', 'q', 'exit']: elif option in ['Q', 'q', 'exit']:
sys.exit() sys.exit()
else: else:
try: try:
asset = nav.search_result[int(option)] asset = nav.search_result[int(option)]
ssh_tty = SshTty('a', 'b') roles = get_role(login_user, asset)
if len(roles) > 1:
role_check = dict(zip(range(len(roles)), roles))
print role_check
for index, role in role_check.items():
print "[%s] %s" % (index, role.name)
print "输入角色ID, q退出"
try:
role_index = raw_input("\033[1;32mID>:\033[0m ").strip()
if role_index == 'q':
continue
else:
role = role_check[int(role_index)]
except IndexError:
color_print('请输入正确ID', 'red')
continue
elif len(roles) == 1:
role = roles[0]
else:
color_print('没有映射用户', 'red')
continue
ssh_tty = SshTty(login_user, asset, role)
ssh_tty.connect() ssh_tty.connect()
except (KeyError, ValueError): except (KeyError, ValueError):
color_print('请输入正确ID', 'red') color_print('请输入正确ID', 'red')

View File

@ -238,7 +238,6 @@ def db_asset_alert(asset, username, alert_dic):
alert_list = [] alert_list = []
asset_tuple_dic = {'status': ASSET_STATUS, 'env': ASSET_ENV, 'asset_type': ASSET_TYPE} asset_tuple_dic = {'status': ASSET_STATUS, 'env': ASSET_ENV, 'asset_type': ASSET_TYPE}
for field, value in alert_dic.iteritems(): for field, value in alert_dic.iteritems():
print field
field_name = Asset._meta.get_field_by_name(field)[0].verbose_name field_name = Asset._meta.get_field_by_name(field)[0].verbose_name
if field == 'idc': if field == 'idc':
old = IDC.objects.filter(id=value[0]) if value[0] else u'' old = IDC.objects.filter(id=value[0]) if value[0] else u''
@ -386,9 +385,9 @@ def excel_to_db(excel_file):
if row: if row:
ip, port, hostname, use_default_auth, username, password, group = row ip, port, hostname, use_default_auth, username, password, group = row
use_default_auth = 1 if use_default_auth == u'默认' else 0 use_default_auth = 1 if use_default_auth == u'默认' else 0
if get_object(Asset, ip=ip): if get_object(Asset, hostname=hostname):
continue continue
if ip and port: if hostname:
asset = Asset(ip=ip, asset = Asset(ip=ip,
port=port, port=port,
hostname=hostname, hostname=hostname,

View File

@ -28,5 +28,10 @@ class IdcForm(forms.ModelForm):
class Meta: class Meta:
model = IDC model = IDC
fields = ['name', "bandwidth", "operator", 'linkman', 'phone', 'address', 'network', 'comment'] fields = ['name', "bandwidth", "operator", 'linkman', 'phone', 'address', 'network', 'comment']
widgets = {
'name': forms.TextInput(attrs={'placeholder': 'Name'}),
'network': forms.Textarea(
attrs={'placeholder': '192.168.1.0/24\n192.168.2.0/24'})
}

View File

@ -42,7 +42,7 @@ class IDC(models.Model):
address = models.CharField(max_length=128, blank=True, null=True, verbose_name=u"机房地址") address = models.CharField(max_length=128, blank=True, null=True, verbose_name=u"机房地址")
network = models.TextField(blank=True, null=True, verbose_name=u"IP地址段") network = models.TextField(blank=True, null=True, verbose_name=u"IP地址段")
date_added = models.DateField(auto_now=True, null=True) date_added = models.DateField(auto_now=True, null=True)
operator = models.IntegerField(blank=True, null=True, verbose_name=u"运营商") operator = models.CharField(max_length=32, blank=True, null=True, verbose_name=u"运营商")
comment = models.CharField(max_length=128, blank=True, null=True, verbose_name=u"备注") comment = models.CharField(max_length=128, blank=True, null=True, verbose_name=u"备注")
def __unicode__(self): def __unicode__(self):
@ -57,17 +57,17 @@ class Asset(models.Model):
""" """
asset modle asset modle
""" """
ip = models.GenericIPAddressField(unique=True, verbose_name=u"主机IP") ip = models.GenericIPAddressField(blank=True, null=True, verbose_name=u"主机IP")
other_ip = models.CharField(max_length=255, blank=True, null=True, verbose_name=u"其他IP") other_ip = models.CharField(max_length=255, blank=True, null=True, verbose_name=u"其他IP")
hostname = models.CharField(max_length=64, blank=True, null=True, verbose_name=u"主机名") hostname = models.CharField(unique=True, max_length=128, verbose_name=u"主机名")
port = models.IntegerField(verbose_name=u"端口号") port = models.IntegerField(blank=True, null=True, verbose_name=u"端口号")
group = models.ManyToManyField(AssetGroup, blank=True, verbose_name=u"所属主机组") group = models.ManyToManyField(AssetGroup, blank=True, verbose_name=u"所属主机组")
username = models.CharField(max_length=16, blank=True, null=True, verbose_name=u"管理用户名") username = models.CharField(max_length=16, blank=True, null=True, verbose_name=u"管理用户名")
password = models.CharField(max_length=64, blank=True, null=True, verbose_name=u"密码") password = models.CharField(max_length=64, blank=True, null=True, verbose_name=u"密码")
use_default_auth = models.BooleanField(default=True, verbose_name=u"使用默认管理账号") use_default_auth = models.BooleanField(default=True, verbose_name=u"使用默认管理账号")
idc = models.ForeignKey(IDC, blank=True, null=True, on_delete=models.SET_NULL, verbose_name=u'机房') idc = models.ForeignKey(IDC, blank=True, null=True, on_delete=models.SET_NULL, verbose_name=u'机房')
mac = models.CharField(max_length=20, blank=True, null=True, verbose_name=u"MAC地址") mac = models.CharField(max_length=20, blank=True, null=True, verbose_name=u"MAC地址")
remote_ip = models.CharField(max_length=16, blank=True, null=True, verbose_name=u'远控卡') remote_ip = models.CharField(max_length=16, blank=True, null=True, verbose_name=u'远控卡IP')
brand = models.CharField(max_length=64, blank=True, null=True, verbose_name=u'硬件厂商型号') brand = models.CharField(max_length=64, blank=True, null=True, verbose_name=u'硬件厂商型号')
cpu = models.CharField(max_length=64, blank=True, null=True, verbose_name=u'CPU') cpu = models.CharField(max_length=64, blank=True, null=True, verbose_name=u'CPU')
memory = models.CharField(max_length=128, blank=True, null=True, verbose_name=u'内存') memory = models.CharField(max_length=128, blank=True, null=True, verbose_name=u'内存')

View File

@ -17,13 +17,11 @@ urlpatterns = patterns('',
url(r'^group_list/$', group_list), url(r'^group_list/$', group_list),
url(r'^group_edit/$', group_edit), url(r'^group_edit/$', group_edit),
url(r'^group_list/$', group_list), url(r'^group_list/$', group_list),
url(r'^group_detail/$', group_detail),
# url(r'^group_del_host/$', group_del_host), # url(r'^group_del_host/$', group_del_host),
url(r'^asset_edit_batch/$', asset_edit_batch), url(r'^asset_edit_batch/$', asset_edit_batch),
# url(r'^host_edit_common/batch/$', host_edit_common_batch), # url(r'^host_edit_common/batch/$', host_edit_common_batch),
url(r'^idc_add/$', idc_add), url(r'^idc_add/$', idc_add),
url(r'^idc_list/$', idc_list), url(r'^idc_list/$', idc_list),
url(r'^idc_detail/$', idc_detail),
url(r'^idc_edit/$', idc_edit), url(r'^idc_edit/$', idc_edit),
url(r'^idc_del/$', idc_del), url(r'^idc_del/$', idc_del),
url(r'^upload/$', asset_upload), url(r'^upload/$', asset_upload),

View File

@ -26,13 +26,13 @@ def group_add(request):
try: try:
if not name: if not name:
error = u'组名不能为空' emg = u'组名不能为空'
raise ServerError(error) raise ServerError(emg)
asset_group_test = get_object(AssetGroup, name=name) asset_group_test = get_object(AssetGroup, name=name)
if asset_group_test: if asset_group_test:
error = u"该组名 %s 已存在" % name emg = u"该组名 %s 已存在" % name
raise ServerError(error) raise ServerError(emg)
except ServerError: except ServerError:
pass pass
@ -87,21 +87,6 @@ def group_edit(request):
return my_render('jasset/group_edit.html', locals(), request) return my_render('jasset/group_edit.html', locals(), request)
@require_role('admin')
def group_detail(request):
"""
Group detail view
主机组详情
"""
header_title, path1, path2 = u'主机组详情', u'资产管理', u'主机组详情'
group_id = request.GET.get('id', '')
group = get_object(AssetGroup, id=group_id)
asset_all = Asset.objects.filter(group=group).order_by('ip')
contact_list, p, contacts, page_range, current_page, show_first, show_end = pages(asset_all, request)
return my_render('jasset/group_detail.html', locals(), request)
@require_role('admin') @require_role('admin')
def group_list(request): def group_list(request):
""" """
@ -147,13 +132,13 @@ def asset_add(request):
af = AssetForm() af = AssetForm()
if request.method == 'POST': if request.method == 'POST':
af_post = AssetForm(request.POST) af_post = AssetForm(request.POST)
print af_post
ip = request.POST.get('ip', '') ip = request.POST.get('ip', '')
hostname = request.POST.get('hostname', '')
is_active = True if request.POST.get('is_active') == '1' else False is_active = True if request.POST.get('is_active') == '1' else False
use_default_auth = request.POST.get('use_default_auth', '') use_default_auth = request.POST.get('use_default_auth', '')
try: try:
if Asset.objects.filter(ip=str(ip)): if Asset.objects.filter(hostname=str(hostname)):
error = u'IP %s 已存在!' % ip error = u'主机名 %s 已存在!' % hostname
raise ServerError(error) raise ServerError(error)
except ServerError: except ServerError:
@ -165,13 +150,15 @@ def asset_add(request):
password = request.POST.get('password', '') password = request.POST.get('password', '')
password_encode = password password_encode = password
asset_save.password = password_encode asset_save.password = password_encode
if not ip:
asset_save.ip = hostname
asset_save.is_active = True if is_active else False asset_save.is_active = True if is_active else False
asset_save.save() asset_save.save()
af_post.save_m2m() af_post.save_m2m()
msg = u'主机 %s 添加成功' % ip msg = u'主机 %s 添加成功' % hostname
else: else:
esg = u'主机 %s 添加失败' % ip esg = u'主机 %s 添加失败' % hostname
return my_render('jasset/asset_add.html', locals(), request) return my_render('jasset/asset_add.html', locals(), request)
@ -215,17 +202,21 @@ def asset_edit(request):
asset_id = request.GET.get('id', '') asset_id = request.GET.get('id', '')
username = request.session.get('username', 'admin') username = request.session.get('username', 'admin')
asset = get_object(Asset, id=asset_id) asset = get_object(Asset, id=asset_id)
asset_old = copy_model_instance(asset) if asset:
password_old = asset.password
# asset_old = copy_model_instance(asset)
af = AssetForm(instance=asset) af = AssetForm(instance=asset)
if request.method == 'POST': if request.method == 'POST':
af_post = AssetForm(request.POST, instance=asset) af_post = AssetForm(request.POST, instance=asset)
ip = request.POST.get('ip', '') ip = request.POST.get('ip', '')
use_default_auth = request.POST.get('use_default_auth') hostname = request.POST.get('hostname', '')
password = request.POST.get('password', '')
use_default_auth = request.POST.get('use_default_auth', '')
try: try:
asset_test = get_object(Asset, ip=ip) asset_test = get_object(Asset, hostname=hostname)
if asset_test and asset_id != unicode(asset_test.id): if asset_test and asset_id != unicode(asset_test.id):
error = u'IP %s 已存在!' % ip error = u'主机名 %s 已存在!' % hostname
raise ServerError(error) raise ServerError(error)
except ServerError: except ServerError:
pass pass
@ -235,6 +226,10 @@ def asset_edit(request):
if use_default_auth: if use_default_auth:
af_save.username = '' af_save.username = ''
af_save.password = '' af_save.password = ''
else:
if password_old != password:
password_encode = CRYPTOR.encrypt(password)
af_save.password = password_encode
af_save.save() af_save.save()
af_post.save_m2m() af_post.save_m2m()
# asset_new = get_object(Asset, id=asset_id) # asset_new = get_object(Asset, id=asset_id)
@ -266,8 +261,19 @@ def asset_list(request):
status = request.GET.get('status', '') status = request.GET.get('status', '')
keyword = request.GET.get('keyword', '') keyword = request.GET.get('keyword', '')
export = request.GET.get("export", False) export = request.GET.get("export", False)
group_id = request.GET.get("group_id", '')
idc_id = request.GET.get("idc_id", '')
if group_id:
group = get_object(AssetGroup, id=group_id)
if group:
asset_find = Asset.objects.filter(group=group)
elif idc_id:
idc = get_object(IDC, id=idc_id)
if idc:
asset_find = Asset.objects.filter(idc=idc)
else:
asset_find = Asset.objects.all()
asset_find = Asset.objects.all()
if idc_name: if idc_name:
asset_find = asset_find.filter(idc__name__contains=idc_name) asset_find = asset_find.filter(idc__name__contains=idc_name)
@ -305,7 +311,82 @@ def asset_list(request):
@require_role('admin') @require_role('admin')
def asset_edit_batch(request): def asset_edit_batch(request):
af = AssetForm() af = AssetForm()
name = request.session.get('username', 'admin')
asset_group_all = AssetGroup.objects.all() asset_group_all = AssetGroup.objects.all()
if request.method == 'POST':
env = request.POST.get('env', '')
idc_id = request.POST.get('idc', '')
port = request.POST.get('port', '')
use_default_auth = request.POST.get('use_default_auth', '')
username = request.POST.get('username', '')
password = request.POST.get('password', '')
group = request.POST.getlist('group', [])
cabinet = request.POST.get('cabinet', '')
comment = request.POST.get('comment', '')
asset_id_all = unicode(request.GET.get('asset_id_all', ''))
asset_id_all = asset_id_all.split(',')
for asset_id in asset_id_all:
alert_list = []
asset = get_object(Asset, id=asset_id)
if asset:
if env:
if asset.env != env:
asset.env = env
alert_list.append([u'运行环境', asset.env, env])
if idc_id:
idc = get_object(IDC, id=idc_id)
name_old = asset.idc.name if asset.idc else u''
if idc and idc.name != name_old:
asset.idc = idc
alert_list.append([u'机房', name_old, idc.name])
if port:
if unicode(asset.port) != port:
asset.port = port
alert_list.append([u'端口号', asset.port, port])
if use_default_auth:
if use_default_auth == 'default':
asset.use_default_auth = 1
asset.username = ''
asset.password = ''
alert_list.append([u'使用默认管理账号', asset.use_default_auth, u'默认'])
elif use_default_auth == 'user_passwd':
asset.use_default_auth = 0
asset.username = username
password_encode = CRYPTOR.encrypt(password)
asset.password = password_encode
alert_list.append([u'使用默认管理账号', asset.use_default_auth, username])
if group:
group_new, group_old, group_new_name, group_old_name = [], asset.group.all(), [], []
for group_id in group:
g = get_object(AssetGroup, id=group_id)
if g:
group_new.append(g)
if not set(group_new) < set(group_old):
group_instance = list(set(group_new) | set(group_old))
for g in group_instance:
group_new_name.append(g.name)
for g in group_old:
group_old_name.append(g.name)
asset.group = group_instance
alert_list.append([u'主机组', ','.join(group_old_name), ','.join(group_new_name)])
if cabinet:
if asset.cabinet != cabinet:
asset.cabinet = cabinet
alert_list.append([u'机柜号', asset.cabinet, cabinet])
if comment:
if asset.comment != comment:
asset.comment = comment
alert_list.append([u'备注', asset.comment, comment])
asset.save()
if alert_list:
username = unicode(name) + ' - ' + u'批量'
print alert_list
AssetRecord.objects.create(asset=asset, username=username, content=alert_list)
return HttpResponse('ok')
return my_render('jasset/asset_edit_batch.html', locals(), request) return my_render('jasset/asset_edit_batch.html', locals(), request)
@ -437,29 +518,17 @@ def idc_edit(request):
return my_render('jasset/idc_edit.html', locals(), request) return my_render('jasset/idc_edit.html', locals(), request)
@require_role('admin')
def idc_detail(request):
"""
IDC detail view
"""
header_title, path1, path2 = u'IDC详情', u'资产管理', u'IDC详情'
idc_id = request.GET.get('id', '')
idc = get_object(IDC, id=idc_id)
posts = Asset.objects.filter(idc=idc).order_by('ip')
contact_list, p, contacts, page_range, current_page, show_first, show_end = pages(posts, request)
return my_render('jasset/idc_detail.html', locals(), request)
@require_role('admin') @require_role('admin')
def idc_del(request): def idc_del(request):
""" """
IDC delete view IDC delete view
""" """
uuid = request.GET.get('id', '') idc_ids = request.GET.get('id', '')
idc = get_object(IDC, id=uuid) idc_id_list = idc_ids.split(',')
if idc:
idc.delete() for idc_id in idc_id_list:
IDC.objects.filter(id=idc_id).delete()
return HttpResponseRedirect('/jasset/idc_list/') return HttpResponseRedirect('/jasset/idc_list/')

View File

@ -79,14 +79,17 @@ class MyInventory(object):
for host in hosts: for host in hosts:
# set connection variables # set connection variables
hostname = host.get("hostname") hostname = host.get("hostname")
hostip = host.get('ip', hostname)
hostport = host.get("port") hostport = host.get("port")
username = host.get("username") username = host.get("username")
password = host.get("password") password = host.get("password")
ssh_key = host.get("ssh_key")
my_host = Host(name=hostname, port=hostport) my_host = Host(name=hostname, port=hostport)
my_host.set_variable('ansible_ssh_host', hostname) my_host.set_variable('ansible_ssh_host', hostip)
my_host.set_variable('ansible_ssh_port', hostport) my_host.set_variable('ansible_ssh_port', hostport)
my_host.set_variable('ansible_ssh_user', username) my_host.set_variable('ansible_ssh_user', username)
my_host.set_variable('ansible_ssh_pass', password) my_host.set_variable('ansible_ssh_pass', password)
my_host.set_variable('ansible_ssh_private_key_file', ssh_key)
# set other variables # set other variables
for key, value in host.iteritems(): for key, value in host.iteritems():
if key not in ["hostname", "port", "username", "password"]: if key not in ["hostname", "port", "username", "password"]:
@ -107,43 +110,72 @@ class MyInventory(object):
self.add_group(hosts_and_vars.get("hosts"), groupname, hosts_and_vars.get("vars")) self.add_group(hosts_and_vars.get("hosts"), groupname, hosts_and_vars.get("vars"))
class MyRunner(MyInventory):
"""
This is a General object for parallel execute modules.
"""
def __init__(self, *args, **kwargs):
super(MyRunner, self).__init__(*args, **kwargs)
self.results = {}
def run(self, module_name, module_args='', timeout=10, forks=10, pattern='',
sudo=False, sudo_user='root', sudo_pass=''):
"""
run module from andible ad-hoc.
module_name: ansible module_name
module_args: ansible module args
"""
hoc = Runner(module_name=module_name,
module_args=module_args,
timeout=timeout,
inventory=self.inventory,
pattern=pattern,
forks=forks,
become=sudo,
become_method='sudo',
become_user=sudo_user,
become_pass=sudo_pass
)
self.results = hoc.run()
return self.results
class Command(MyInventory): class Command(MyInventory):
""" """
this is a command object for parallel execute command. this is a command object for parallel execute command.
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(Command, self).__init__(*args, **kwargs) super(Command, self).__init__(*args, **kwargs)
self.results = '' self.results = {}
def run(self, command, module_name="command", timeout=10, forks=10, group='default_group', pattern='*'): def run(self, command, module_name="command", timeout=10, forks=10, pattern='*'):
""" """
run command from andible ad-hoc. run command from andible ad-hoc.
command : 必须是一个需要执行的命令字符串 比如 command : 必须是一个需要执行的命令字符串 比如
'uname -a' 'uname -a'
""" """
data = {}
if module_name not in ["raw", "command", "shell"]: if module_name not in ["raw", "command", "shell"]:
raise CommandValueError("module_name", raise CommandValueError("module_name",
"module_name must be of the 'raw, command, shell'") "module_name must be of the 'raw, command, shell'")
hoc = Runner(module_name=module_name, hoc = Runner(module_name=module_name,
module_args=command, module_args=command,
timeout=timeout, timeout=timeout,
inventory=self.inventory, inventory=self.inventory,
subset=group,
pattern=pattern, pattern=pattern,
forks=forks, forks=forks,
) )
self.results = hoc.run() self.results = hoc.run()
if self.stdout: if self.stdout:
return {"ok": self.stdout} data['ok'] = self.stdout
else: if self.stderr:
msg = [] data['err'] = self.stderr
if self.stderr: if self.dark:
msg.append(self.stderr) data['dark'] = self.dark
if self.dark:
msg.append(self.dark) return data
return {"failed": msg}
@property @property
def raw_results(self): def raw_results(self):
@ -174,7 +206,7 @@ class Command(MyInventory):
result = {} result = {}
all = self.results.get("contacted") all = self.results.get("contacted")
for key, value in all.iteritems(): for key, value in all.iteritems():
result[key] = value.get("stdout") result[key] = value.get("stdout")
return result return result
@property @property
@ -185,7 +217,8 @@ class Command(MyInventory):
result = {} result = {}
all = self.results.get("contacted") all = self.results.get("contacted")
for key, value in all.iteritems(): for key, value in all.iteritems():
result[key] = { if value.get("stderr") or value.get("warnings"):
result[key] = {
"stderr": value.get("stderr"), "stderr": value.get("stderr"),
"warnings": value.get("warnings"),} "warnings": value.get("warnings"),}
return result return result
@ -371,7 +404,7 @@ class Tasks(Command):
result[key] = { result[key] = {
"all_ip": setup.get("ansible_all_ipv4_addresses"), "all_ip": setup.get("ansible_all_ipv4_addresses"),
"hostname" : setup.get("ansible_hostname" ), "hostname" : setup.get("ansible_hostname"),
"default_ip": setup.get("ansible_default_ipv4").get("address"), "default_ip": setup.get("ansible_default_ipv4").get("address"),
"default_mac": setup.get("ansible_default_ipv4").get("macaddress"), "default_mac": setup.get("ansible_default_ipv4").get("macaddress"),
"product_name": setup.get("ansible_product_name"), "product_name": setup.get("ansible_product_name"),
@ -388,8 +421,6 @@ class Tasks(Command):
return {"status": "failed", "msg": self.msg} if self.msg else {"status": "ok", "result": result} return {"status": "failed", "msg": self.msg} if self.msg else {"status": "ok", "result": result}
class CustomAggregateStats(callbacks.AggregateStats): class CustomAggregateStats(callbacks.AggregateStats):
""" """
Holds stats about per-host activity during playbook runs. Holds stats about per-host activity during playbook runs.
@ -408,7 +439,6 @@ class CustomAggregateStats(callbacks.AggregateStats):
self.results.append(runner_results) self.results.append(runner_results)
def summarize(self, host): def summarize(self, host):
""" """
Return information about a particular host Return information about a particular host

View File

@ -5,20 +5,6 @@ from jasset.models import Asset, AssetGroup
from juser.models import User, UserGroup from juser.models import User, UserGroup
class PermLog(models.Model):
datetime = models.DateTimeField(auto_now_add=True)
action = models.CharField(max_length=100, null=True, blank=True, default='')
results = models.CharField(max_length=1000, null=True, blank=True, default='')
is_success = models.BooleanField(default=False)
is_finish = models.BooleanField(default=False)
class SysUser(models.Model):
username = models.CharField(max_length=100)
password = models.CharField(max_length=100)
comment = models.CharField(max_length=100, null=True, blank=True, default='')
class PermRole(models.Model): class PermRole(models.Model):
name = models.CharField(max_length=100, unique=True) name = models.CharField(max_length=100, unique=True)
comment = models.CharField(max_length=100, null=True, blank=True, default='') comment = models.CharField(max_length=100, null=True, blank=True, default='')
@ -41,4 +27,4 @@ class PermRule(models.Model):
role = models.ManyToManyField(PermRole, related_name='perm_rule') role = models.ManyToManyField(PermRole, related_name='perm_rule')
def __unicode__(self): def __unicode__(self):
return self.name return self.name

View File

@ -1,15 +1,163 @@
# coding: utf-8 # coding: utf-8
from django.db.models.query import QuerySet
from jumpserver.api import * from jumpserver.api import *
import uuid import uuid
import re import re
from jumpserver.tasks import playbook_run
from jumpserver.models import Setting from jumpserver.models import Setting
from jperm.models import PermLog
from jperm.models import PermRole from jperm.models import PermRole
from jperm.models import PermRule
def get_group_user_perm(ob):
"""
ob为用户或用户组
获取用户用户组授权的资产资产组
return:
{asset_group': {
asset_group1: {'asset': [], 'role': [role1, role2], 'rule': [rule1, rule2]},
asset_group2: {'asset: [], 'role': [role1, role2], 'rule': [rule1, rule2]},
}
'asset':{
asset1: {'role': [role1, role2], 'rule': [rule1, rule2]},
asset2: {'role': [role1, role2], 'rule': [rule1, rule2]},
}
]},
'rule':[rule1, rule2,]
}
"""
perm = {}
if isinstance(ob, User):
rule_all = PermRule.objects.filter(user=ob)
elif isinstance(ob, UserGroup):
rule_all = PermRule.objects.filter(user_group=ob)
else:
rule_all = []
perm['rule'] = rule_all
perm_asset_group = perm['asset_group'] = {}
perm_asset = perm['asset'] = {}
for rule in rule_all:
asset_groups = rule.asset_group.all()
assets = rule.asset.all()
# 获取一个规则用户授权的资产
for asset in assets:
if perm_asset.get(asset):
perm_asset[asset].get('role', set()).update(set(rule.role.all()))
perm_asset[asset].get('rule', set()).add(rule)
else:
perm_asset[asset] = {'role': set(rule.role.all()), 'rule': set([rule])}
# 获取一个规则用户授权的资产组
for asset_group in asset_groups:
asset_group_assets = asset_group.asset_set.all()
if perm_asset_group.get(asset_group):
perm_asset_group[asset_group].get('role', set()).update(set(rule.role.all()))
perm_asset_group[asset_group].get('rule', set()).add(rule)
else:
perm_asset_group[asset_group] = {'role': set(rule.role.all()), 'rule': set([rule]),
'asset': asset_group_assets}
# 将资产组中的资产添加到资产授权中
for asset in asset_group_assets:
if perm_asset.get(asset):
perm_asset[asset].get('role', set()).update(perm_asset_group[asset_group].get('role', set()))
perm_asset[asset].get('rule', set()).update(perm_asset_group[asset_group].get('rule', set()))
else:
perm_asset[asset] = {'role': perm_asset_group[asset_group].get('role', set()),
'rule': perm_asset_group[asset_group].get('rule', set())}
return perm
def get_group_asset_perm(ob):
"""
ob为资产或资产组
获取资产资产组授权的用户用户组
return:
{user_group': {
user_group1: {'user': [], 'role': [role1, role2], 'rule': [rule1, rule2]},
user_group2: {'user: [], 'role': [role1, role2], 'rule': [rule1, rule2]},
}
'user':{
user1: {'role': [role1, role2], 'rule': [rule1, rule2]},
user2: {'role': [role1, role2], 'rule': [rule1, rule2]},
}
]},
'rule':[rule1, rule2,]
}
"""
perm = {}
if isinstance(ob, Asset):
rule_all = PermRule.objects.filter(asset=ob)
elif isinstance(ob, AssetGroup):
rule_all = PermRule.objects.filter(asset_group=ob)
else:
rule_all = []
perm['rule'] = rule_all
perm_user_group = perm['user_group'] = {}
perm_user = perm['user'] = {}
for rule in rule_all:
user_groups = rule.user_group.all()
users = rule.user.all()
# 获取一个规则资产的用户
for user in users:
if perm_user.get(user):
perm_user[user].get('role', set()).update(set(rule.role.all()))
perm_user[user].get('rule', set()).add(rule)
else:
perm_user[user] = {'role': set(rule.role.all()), 'rule': set([rule])}
# 获取一个规则资产授权的用户组
for user_group in user_groups:
user_group_users = user_group.user_set.all()
if perm_user_group.get(user_group):
perm_user_group[user_group].get('role', set()).update(set(rule.role.all()))
perm_user_group[user_group].get('rule', set()).add(rule)
else:
perm_user_group[user_group] = {'role': set(rule.role.all()), 'rule': set([rule]),
'user': user_group_users}
# 将用户组中的资产添加到用户授权中
for user in user_group_users:
if perm_user.get(user):
perm_user[user].get('role', set()).update(perm_user_group[user_group].get('role', set()))
perm_user[user].get('rule', set()).update(perm_user_group[user_group].get('rule', set()))
else:
perm_user[user] = {'role': perm_user_group[user_group].get('role', set()),
'rule': perm_user_group[user_group].get('rule', set())}
return perm
def gen_resource(ob, perm=None):
"""
ob为用户或资产列表或资产queryset
生成MyInventory需要的 resource文件
"""
res = []
if isinstance(ob, User):
if not perm:
perm = get_group_user_perm(ob)
for asset, asset_info in perm.get('asset').items():
asset_info = get_asset_info(asset)
info = {'hostname': asset.hostname, 'ip': asset.ip, 'port': asset_info.get('port', 22)}
try:
role = sorted(list(perm.get('asset').get(asset).get('role')))[0]
except IndexError:
continue
info['username'] = role.name
info['password'] = role.password
info['ssh_key'] = get_role_key(ob, role)
res.append(info)
elif isinstance(ob, (list, QuerySet)):
for asset in ob:
info = get_asset_info(asset)
res.append(info)
return res
def get_object_list(model, id_list): def get_object_list(model, id_list):
@ -22,267 +170,6 @@ def get_object_list(model, id_list):
return object_list return object_list
def get_rand_file_path(base_dir=os.path.join(BASE_DIR, 'tmp')):
"""获取随机文件路径"""
filename = uuid.uuid1().hex
return os.path.join(base_dir, filename)
def get_inventory(host_group):
"""生成资产表库存清单"""
path = get_rand_file_path()
f = open(path, 'w')
for group, host_list in host_group.items():
f.write('[%s]\n' % group)
for ip in host_list:
asset = get_object(Asset, ip=ip)
if asset.use_default:
f.write('%s\n' % ip)
else:
f.write('%s ansible_ssh_port=%s ansible_ssh_user=%s ansible_ssh_pass=%s\n' %
(ip, asset.port, asset.username, CRYPTOR.decrypt(asset.password)))
f.close()
return path
def get_playbook(template, var):
"""根据playbook模板生成playbook"""
str_playbook = open(template).read()
for k, v in var.items():
str_playbook = re.sub(r'%s' % k, v, str_playbook) # 正则来替换传入的字符
path = get_rand_file_path()
f = open(path, 'w')
f.write(str_playbook)
return path
def perm_user_api(perm_info):
"""
用户授权api通过调用ansible API完成用户新建等,传入参数必须如下,列表中可以是对象也可以是用户名和ip
perm_info = {'del': {'users': [],
'assets': [],
},
'new': {'users': [],
'assets': []}}
"""
log = PermLog(action=perm_info.get('action', ''))
try:
new_users = perm_info.get('new', {}).get('users', [])
new_assets = perm_info.get('new', {}).get('assets', [])
del_users = perm_info.get('del', {}).get('users', [])
del_assets = perm_info.get('del', {}).get('assets', [])
print new_users, new_assets
except IndexError:
raise ServerError("Error: function perm_user_api传入参数错误")
try:
new_ip = [asset.ip for asset in new_assets if isinstance(asset, Asset)]
del_ip = [asset.ip for asset in del_assets if isinstance(asset, Asset)]
new_username = [user.username for user in new_users]
del_username = [user.username for user in del_users]
except IndexError:
raise ServerError("Error: function perm_user_api传入参数类型错误")
host_group = {'new': new_ip, 'del': del_ip}
inventory = get_inventory(host_group)
the_new_users = ','.join(new_username)
the_del_users = ','.join(del_username)
playbook = get_playbook(os.path.join(BASE_DIR, 'keys/../playbook', 'user_perm.yaml'),
{'the_new_group': 'new', 'the_del_group': 'del',
'the_new_users': the_new_users, 'the_del_users': the_del_users,
'KEY_DIR': os.path.join(SSH_KEY_DIR, 'sysuser')})
print playbook, inventory
settings = get_object(Setting, name='default')
results = playbook_run(inventory, playbook, settings)
if not results.get('failures', 1) and not results.get('unreachable', ''):
is_success = True
else:
is_success = False
log.results = results
log.is_finish = True
log.is_success = is_success
log.save()
return results
def user_group_permed(user_group):
assets = user_group.asset.all()
asset_groups = user_group.asset_group.all()
for asset_group in asset_groups:
assets.extend(asset_group.asset.all())
return {'assets': assets, 'asset_groups': asset_groups}
def user_permed(user):
asset_groups = []
assets = []
user_groups = user.group.all()
asset_groups.extend(user.asset_group.all())
assets.extend(user.asset.all())
for user_group in user_groups:
asset_groups.extend(user_group_permed(user_group).get('assets', []))
assets.extend((user_group_permed(user_group).get('asset_groups', [])))
return {'assets': assets, 'asset_groups': asset_groups}
def _public_perm_api(info):
"""
公用的用户用户组主机主机组编辑修改新建调用的api用来完成授权
info like that:
{
'type': 'new_user',
'user': 'a',
'group': ['A', 'B']
}
{
'type': 'edit_user',
'user': 'a',
'group': {'new': ['A'], 'del': []}
}
{
'type': 'del_user',
'user': ['a', 'b']
}
{
'type': 'edit_user_group',
'group': 'A',
'user': {'del': ['a', 'b'], 'new': ['c', 'd']}
}
{
'type': 'del_user_group',
'group': ['A']
}
{
'type': 'new_asset',
'asset': 'a',
'group': ['A', 'B']
}
{
'type': 'edit_asset',
'asset': 'a',
'group': {
'del': ['A', ['B'],
'new': ['C', ['D']]
}
}
{
'type': 'del_asset',
'asset': ['a', 'b']
}
{
'type': 'edit_asset_group',
'group': 'A',
'asset': {'new': ['a', 'b'], 'del': ['c', 'd']}
}
{
'type': 'del_asset_group',
'group': ['A', 'B']
}
"""
if info.get('type') == 'new_user':
new_assets = []
user = info.get('user')
user_groups = info.get('group')
for user_group in user_groups:
new_assets.extend(user_group_permed(user_group).get('assets', []))
perm_info = {
'action': 'new user: ' + user.name,
'new': {'users': [user], 'assets': new_assets}
}
elif info.get('type') == 'edit_user':
new_assets = []
del_assets = []
user = info.get('user')
new_group = info.get('group').get('new')
del_group = info.get('group').get('del')
for user_group in new_group:
new_assets.extend(user_group_permed(user_group).get('assets', []))
for user_group in del_group:
del_assets.extend((user_group_permed(user_group).get('assets', [])))
perm_info = {
'action': 'edit user: ' + user.name,
'del': {'users': [user], 'assets': del_assets},
'new': {'users': [user], 'assets': new_assets}
}
elif info.get('type') == 'del_user':
user = info.get('user')
del_assets = user_permed(user).get('assets', [])
perm_info = {
'action': 'del user: ' + user.name, 'del': {'users': [user], 'assets': del_assets},
}
elif info.get('type') == 'edit_user_group':
user_group = info.get('group')
new_users = info.get('user').get('new')
del_users = info.get('user').get('del')
assets = user_group_permed(user_group).get('assets', [])
perm_info = {
'action': 'edit user group: ' + user_group.name,
'new': {'users': new_users, 'assets': assets},
'del': {'users': del_users, 'assets': assets}
}
elif info.get('type') == 'del_user_group':
user_group = info.get('group', [])
del_users = user_group.user_set.all()
assets = user_group_permed(user_group).get('assets', [])
perm_info = {
'action': "del user group: " + user_group.name, 'del': {'users': del_users, 'assets': assets}
}
else:
return
try:
results = perm_user_api(perm_info) # 通过API授权或回收
except ServerError, e:
return e
else:
return results
def push_user(user, asset_groups_id):
assets = []
if not user:
return {'error': '没有该用户'}
for group_id in asset_groups_id:
asset_group = get_object(AssetGroup, id=group_id)
if asset_group:
assets.extend(asset_group.asset_set.all())
perm_info = {
'action': 'Push user:' + user.username,
'new': {'users': [user], 'assets': assets}
}
results = perm_user_api(perm_info)
return results
def get_role_info(role_id, type="all"): def get_role_info(role_id, type="all"):
""" """
获取role对应的一些信息 获取role对应的一些信息

View File

@ -13,11 +13,4 @@ urlpatterns = patterns('jperm.views',
(r'^role/perm_role_detail/$', perm_role_detail), (r'^role/perm_role_detail/$', perm_role_detail),
(r'^role/perm_role_edit/$', perm_role_edit), (r'^role/perm_role_edit/$', perm_role_edit),
(r'^role/perm_role_push/$', perm_role_push), (r'^role/perm_role_push/$', perm_role_push),
(r'^log/$', log),
(r'^sys_user_add/$', sys_user_add),
(r'^perm_user_list/$', sys_user_list),
(r'^sys_user_del/$', sys_user_del),
(r'^sys_user_edit/$', sys_user_edit),
) )

View File

@ -51,6 +51,7 @@ def gen_keys():
private_key = os.path.join(key_path_dir, 'id_rsa') private_key = os.path.join(key_path_dir, 'id_rsa')
public_key = os.path.join(key_path_dir, 'id_rsa.pub') public_key = os.path.join(key_path_dir, 'id_rsa.pub')
key.write_private_key_file(private_key) key.write_private_key_file(private_key)
os.chmod(private_key, 0644)
with open(public_key, 'w') as content_file: with open(public_key, 'w') as content_file:
for data in [key.get_name(), for data in [key.get_name(),

View File

@ -2,8 +2,6 @@
from django.db.models import Q from django.db.models import Q
from jperm.perm_api import * from jperm.perm_api import *
from jperm.models import PermLog as Log
from jperm.models import SysUser
from juser.user_api import gen_ssh_key from juser.user_api import gen_ssh_key
@ -380,8 +378,6 @@ def perm_role_edit(request):
return my_render('jperm/perm_role_list.html', locals(), request) return my_render('jperm/perm_role_list.html', locals(), request)
@require_role('admin') @require_role('admin')
def perm_role_push(request): def perm_role_push(request):
""" """
@ -460,108 +456,3 @@ def perm_role_push(request):
else: else:
return HttpResponse(u"推送系统角色: %s" % ','.join(role_names)) return HttpResponse(u"推送系统角色: %s" % ','.join(role_names))
@require_role('admin')
def perm_group_list(request):
header_title, path1, path2 = '用户组授权', '授权管理', '用户组授权'
keyword = request.GET.get('search', '')
user_groups_list = UserGroup.objects.all()
if keyword:
request = user_groups_list.filter(Q(name=keyword) | Q(comment=keyword))
user_groups_list, p, user_groups, page_range, current_page, show_first, show_end = pages(user_groups_list, request)
return my_render('jperm/perm_group_list.html', locals(), request)
@require_role('admin')
def perm_group_edit(request):
header_title, path1, path2 = '用户组授权', '授权管理', '授权更改'
user_group_id = request.GET.get('id', '')
user_group = get_object(UserGroup, id=user_group_id)
asset_all = Asset.objects.all()
asset_group_all = AssetGroup.objects.all()
asset_permed = user_group.asset.all() # 获取授权的资产对象列表
asset_group_permed = user_group.asset_group.all() # 获取授权的资产组对象列表
if request.method == 'GET' and user_group:
assets = [asset for asset in asset_all if asset not in asset_permed]
asset_groups = [asset_group for asset_group in asset_group_all if asset_group not in asset_group_permed]
return my_render('jperm/perm_group_edit.html', locals(), request)
elif request.method == 'POST' and user_group:
asset_id_select = request.POST.getlist('asset_select', [])
asset_group_id_select = request.POST.getlist('asset_groups_select', [])
asset_select = get_object_list(Asset, asset_id_select)
asset_group_select = get_object_list(AssetGroup, asset_group_id_select)
asset_new = list(set(asset_select) - set(asset_permed)) # 计算的得到新授权的资产对象列表
asset_del = list(set(asset_permed) - set(asset_select)) # 计算得到回收权限的资产对象列表
asset_group_new = list(set(asset_group_select) - set(asset_group_permed)) # 新授权的资产组对象列表
asset_group_del = list(set(asset_group_permed) - set(asset_group_select)) # 回收的资产组对象列表
users = user_group.user_set.all()
perm_info = {
'action': 'perm group edit: ' + user_group.name,
'del': {'users': users, 'assets': asset_del},
'new': {'users': users, 'assets': asset_new}
}
results = perm_user_api(perm_info)
unreachable_asset = []
failures_asset = []
for ip in results.get('unreachable'):
unreachable_asset.extend(filter(lambda x: x, Asset.objects.filter(ip=ip)))
for ip in results.get('failures'):
failures_asset.extend(filter(lambda x: x, Asset.objects.filter(ip=ip)))
failures_asset.extend(unreachable_asset) # 失败的授权要统计
for asset in failures_asset:
if asset in asset_select:
asset_select.remove(asset)
else:
asset_select.append(asset)
user_group.asset = asset_select
user_group.asset_group = asset_group_select
user_group.save() # 保存到数据库
return HttpResponse(json.dumps(results, sort_keys=True, indent=4), content_type="application/json")
else:
return HttpResponse('输入错误')
def log(request):
header_title, path1, path2 = '授权记录', '授权管理', '授权记录'
log_all = Log.objects.all().order_by('-datetime')
log_all, p, logs, page_range, current_page, show_first, show_end = pages(log_all, request)
return my_render('jperm/perm_log.html', locals(), request)
def sys_user_add(request):
asset_group_all = AssetGroup.objects.all()
if request.method == 'POST':
username = request.POST.get('username', '')
password = request.POST.get('password', '')
asset_groups_id = request.POST.getlist('asset_groups_select', [])
comment = request.POST.get('comment')
sys_user = SysUser(username=username, password=password, comment=comment)
sys_user.save()
gen_ssh_key(username, key_dir=os.path.join(SSH_KEY_DIR, 'sysuser'), authorized_keys=False)
results = push_user(sys_user, asset_groups_id)
return HttpResponse(json.dumps(results, sort_keys=True, indent=4), content_type="application/json")
return my_render('jperm/sys_user_add.html', locals(), request)
def sys_user_list(request):
users_list = SysUser.objects.all()
users_list, p, users, page_range, current_page, show_first, show_end = pages(users_list, request)
return my_render('jperm/sys_user_list.html', locals(), request)
def sys_user_edit(request):
pass
def sys_user_del(request):
pass

View File

@ -3,24 +3,27 @@
import os, sys, time, re import os, sys, time, re
from Crypto.Cipher import AES from Crypto.Cipher import AES
import crypt import crypt
import pwd
from binascii import b2a_hex, a2b_hex from binascii import b2a_hex, a2b_hex
import hashlib import hashlib
import datetime import datetime
import random import random
import subprocess import subprocess
from settings import * import json
import logging
from settings import *
from django.core.paginator import Paginator, EmptyPage, InvalidPage from django.core.paginator import Paginator, EmptyPage, InvalidPage
from django.http import HttpResponse, Http404 from django.http import HttpResponse, Http404
from django.template import RequestContext from django.template import RequestContext
from juser.models import User, UserGroup from juser.models import User, UserGroup
from jlog.models import Log from jlog.models import Log, TtyLog
from jasset.models import Asset, AssetGroup from jasset.models import Asset, AssetGroup
from jperm.models import PermRule, PermRole
from jumpserver.models import Setting
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response from django.shortcuts import render_to_response
from django.core.mail import send_mail from django.core.mail import send_mail
import json
import logging
def set_log(level): def set_log(level):
@ -28,11 +31,15 @@ def set_log(level):
return a log file object return a log file object
根据提示设置log打印 根据提示设置log打印
""" """
log_file = os.path.join(LOG_DIR, 'jumpserver.log')
if not os.path.isfile(log_file):
os.mknod(log_file)
os.chmod(log_file, 0777)
log_level_total = {'debug': logging.DEBUG, 'info': logging.INFO, 'warning': logging.WARN, 'error': logging.ERROR, log_level_total = {'debug': logging.DEBUG, 'info': logging.INFO, 'warning': logging.WARN, 'error': logging.ERROR,
'critical': logging.CRITICAL} 'critical': logging.CRITICAL}
logger_f = logging.getLogger('jumpserver') logger_f = logging.getLogger('jumpserver')
logger_f.setLevel(logging.DEBUG) logger_f.setLevel(logging.DEBUG)
fh = logging.FileHandler(os.path.join(LOG_DIR, 'jumpserver.log')) fh = logging.FileHandler(log_file)
fh.setLevel(log_level_total.get(level, logging.DEBUG)) fh.setLevel(log_level_total.get(level, logging.DEBUG))
formatter = logging.Formatter('%(asctime)s - %(filename)s - %(levelname)s - %(message)s') formatter = logging.Formatter('%(asctime)s - %(filename)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter) fh.setFormatter(formatter)
@ -40,6 +47,60 @@ def set_log(level):
return logger_f return logger_f
def get_asset_info(asset):
default = get_object(Setting, name='default')
info = {'hostname': asset.hostname, 'ip': asset.ip}
if asset.use_default_auth:
if default:
info['port'] = default.default_port
info['username'] = default.default_user
info['password'] = CRYPTOR.decrypt(default.default_password)
info['ssh_key'] = default.default_pri_key_path
else:
info['port'] = asset.port
info['username'] = asset.username
info['password'] = asset.password
return info
def get_role(user, asset):
roles = []
rules = PermRule.objects.filter(user=user, asset=asset)
for rule in rules:
roles.extend(list(rule.role.all()))
return roles
def get_role_key(user, role):
"""
由于role的key的权限是所有人可以读的 ansible要求为600所以拷贝一份到特殊目录
:param user:
:param role:
:return: self key path
"""
user_role_key_dir = os.path.join(KEY_DIR, 'user')
user_role_key_path = os.path.join(user_role_key_dir, '%s_%s.pem' % (user.username, role.name))
mkdir(user_role_key_dir, mode=777)
if not os.path.isfile(user_role_key_path):
with open(os.path.join(role.key_path, 'id_rsa')) as fk:
with open(user_role_key_path, 'w') as fu:
fu.write(fk.read())
print user_role_key_path, user.username
chown(user_role_key_path, user.username)
os.chmod(user_role_key_path, 0600)
return user_role_key_path
def chown(path, user, group=''):
if not group:
group = user
uid = pwd.getpwnam(user).pw_uid
gid = pwd.getpwnam(group).pwd_gid
os.chown(path, uid, gid)
def page_list_return(total, current=1): def page_list_return(total, current=1):
""" """
page page
@ -56,7 +117,7 @@ def pages(post_objects, request):
page public function , return page's object tuple page public function , return page's object tuple
分页公用函数返回分页的对象元组 分页公用函数返回分页的对象元组
""" """
paginator = Paginator(post_objects, 10) paginator = Paginator(post_objects, 20)
try: try:
current_page = int(request.GET.get('page', '1')) current_page = int(request.GET.get('page', '1'))
except ValueError: except ValueError:
@ -157,8 +218,7 @@ class PyCrypt(object):
try: try:
plain_text = cryptor.decrypt(a2b_hex(text)) plain_text = cryptor.decrypt(a2b_hex(text))
except TypeError: except TypeError:
# raise ServerError('Decrypt password error, TYpe error.') raise ServerError('Decrypt password error, TYpe error.')
pass
return plain_text.rstrip('\0') return plain_text.rstrip('\0')
@ -386,16 +446,16 @@ def bash(cmd):
return subprocess.call(cmd, shell=True) return subprocess.call(cmd, shell=True)
def mkdir(dir_name, username='root', mode=0755): def mkdir(dir_name, username='', mode=0755):
""" """
insure the dir exist and mode ok insure the dir exist and mode ok
目录存在如果不存在就建立并且权限正确 目录存在如果不存在就建立并且权限正确
""" """
if not os.path.isdir(dir_name): if not os.path.isdir(dir_name):
os.makedirs(dir_name) os.makedirs(dir_name)
os.chmod(dir_name, mode) os.chmod(dir_name, mode)
if username: if username:
bash('chown %s:%s %s' % (username, username, dir_name)) chown(dir_name, username)
def http_success(request, msg): def http_success(request, msg):

View File

@ -130,7 +130,7 @@ def gen_ssh_key(username, password='',
""" """
logger.debug('生成ssh key 并设置authorized_keys') logger.debug('生成ssh key 并设置authorized_keys')
private_key_file = os.path.join(key_dir, username) private_key_file = os.path.join(key_dir, username)
mkdir(key_dir) mkdir(key_dir, mode=777)
if os.path.isfile(private_key_file): if os.path.isfile(private_key_file):
os.unlink(private_key_file) os.unlink(private_key_file)
ret = bash('echo -e "y\n"|ssh-keygen -t rsa -f %s -b %s -P "%s"' % (private_key_file, length, password)) ret = bash('echo -e "y\n"|ssh-keygen -t rsa -f %s -b %s -P "%s"' % (private_key_file, length, password))
@ -143,7 +143,7 @@ def gen_ssh_key(username, password='',
with open(authorized_key_file, 'w') as auth_f: with open(authorized_key_file, 'w') as auth_f:
auth_f.write(pub_f.read()) auth_f.write(pub_f.read())
os.chmod(authorized_key_file, 0600) os.chmod(authorized_key_file, 0600)
bash('chown %s:%s %s' % (username, username, authorized_key_file)) chown(authorized_key_file, username)
def server_add_user(username, password, ssh_key_pwd, ssh_key_login_need): def server_add_user(username, password, ssh_key_pwd, ssh_key_login_need):

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -86,17 +86,17 @@ function move(from, to, from_o, to_o) {
}); });
} }
//function move_left(from, to, from_o, to_o) { function move_left(from, to, from_o, to_o) {
// $("#" + from + " option").each(function () { $("#" + from + " option").each(function () {
// if ($(this).prop("selected") == true) { if ($(this).prop("selected") == true) {
// $("#" + to).append(this); $("#" + to).append(this);
// if( typeof from_o !== 'undefined'){ if( typeof from_o !== 'undefined'){
// $("#"+to_o).append($("#"+from_o +" option[value='"+this.value+"']")); $("#"+to_o).append($("#"+from_o +" option[value='"+this.value+"']"));
// } }
// } }
// $(this).attr("selected",'true'); $(this).attr("selected",'true');
// }); });
//} }
//function move_all(from, to) { //function move_all(from, to) {
// $("#" + from).children().each(function () { // $("#" + from).children().each(function () {

14
static/js/layer/extend/layer.ext.js Normal file → Executable file

File diff suppressed because one or more lines are too long

2
static/js/layer/layer.js Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 701 B

After

Width:  |  Height:  |  Size: 701 B

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 B

82
static/js/layer/skin/layer.css Normal file → Executable file

File diff suppressed because one or more lines are too long

41
static/js/layer/skin/layer.ext.css Normal file → Executable file
View File

@ -1,45 +1,8 @@
/** /*!
@Name: layer @Name: layer
@Date: 2012.12.13 @Date: 2012.12.13
@Author: @Author:
@blog: sentsin.com @blog: sentsin.com
**/ */.layui-layer-imgbar,.layui-layer-imgtit a,.layui-layer-tab .layui-layer-title span{text-overflow:ellipsis;white-space:nowrap}.layui-layer-iconext{background:url(default/icon-ext.png) no-repeat}html #layui_layer_skinlayerextcss{display:none;position:absolute;width:1989px}.layui-layer-prompt .layui-layer-input{display:block;width:220px;height:30px;margin:0 auto;line-height:30px;padding:0 5px;border:1px solid #ccc;box-shadow:1px 1px 5px rgba(0,0,0,.1) inset;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;border-bottom:1px solid #ccc;background-color:#eee;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;float:left;min-width:80px;max-width:260px;padding:0 20px;text-align:center;cursor:default;overflow:hidden}.layui-layer-tab .layui-layer-title span.layui-layer-tabnow{height:43px;border-left:1px solid #ccc;border-right:1px solid #ccc;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.xubox_tab_layer{display:block}.xubox_tabclose{position:absolute;right:10px;top:5px;cursor:pointer}.layui-layer-photos{-webkit-animation-duration:1s;animation-duration:1s;background:url(default/xubox_loading1.gif) center center no-repeat #000}.layui-layer-photos .layui-layer-content{overflow:hidden;text-align:center}.layui-layer-photos .layui-layer-phimg img{position:relative;width:100%;display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-imgbar,.layui-layer-imguide{display:none}.layui-layer-imgnext,.layui-layer-imgprev{position:absolute;top:50%;width:27px;_width:44px;height:44px;margin-top:-22px;outline:0;blr:expression(this.onFocus=this.blur())}.layui-layer-imgprev{left:10px;background-position:-5px -5px;_background-position:-70px -5px}.layui-layer-imgprev:hover{background-position:-33px -5px;_background-position:-120px -5px}.layui-layer-imgnext{right:10px;_right:8px;background-position:-5px -50px;_background-position:-70px -50px}.layui-layer-imgnext:hover{background-position:-33px -50px;_background-position:-120px -50px}.layui-layer-imgbar{position:absolute;left:0;bottom:0;width:100%;height:32px;line-height:32px;background-color:rgba(0,0,0,.8);background-color:#000\9;filter:Alpha(opacity=80);color:#fff;overflow:hidden;font-size:0}.layui-layer-imgtit *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:12px}.layui-layer-imgtit a{max-width:65%;overflow:hidden;color:#fff}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{padding-left:10px;font-style:normal}
.xubox_iconext{background:url(default/icon_ext.png) no-repeat;}
/* prompt模式 */
.xubox_layer .xubox_form{width:240px; height:30px; line-height:30px; padding: 0 5px; border: 1px solid #ccc; background: url(default/textbg.png) #fff repeat-x; color:#333;}
.xubox_layer .xubox_formArea{width:300px; height:100px; line-height:20px;}
/* tab模式 */
.xubox_layer .xubox_tab{position:relative; background-color:#fff; box-shadow:1px 1px 50px rgba(0,0,0,.4)}
.xubox_layer .xubox_tabmove{position:absolute; width:600px; height:30px; top:0; left:0;}
.xubox_layer .xubox_tabtit{ display:block; height:34px; border-bottom:1px solid #ccc; background-color:#eee;}
.xubox_layer .xubox_tabtit span{position:relative; float:left; width:120px; height:34px; line-height:34px; text-align:center; cursor:default;}
.xubox_layer .xubox_tabtit span.xubox_tabnow{left:-1px; _top:1px; height:35px; border-left:1px solid #ccc; border-right:1px solid #ccc; background-color:#fff; z-index:10;}
.xubox_layer .xubox_tab_main{line-height:24px; clear:both;}
.xubox_layer .xubox_tab_main .xubox_tabli{display:none;}
.xubox_layer .xubox_tab_main .xubox_tabli.xubox_tab_layer{display:block;}
.xubox_layer .xubox_tabclose{position:absolute; right:10px; top:5px; cursor:pointer;}
/* photo模式 */
.xubox_bigimg, .xubox_intro{height:300px}
.xubox_bigimg{position:relative; display:block; width:600px; text-align:center; background:url(default/xubox_loading1.gif) center center no-repeat #000; overflow:hidden; }
.xubox_bigimg img{position:relative; display:inline-block; visibility: hidden;}
.xubox_intro{position:absolute; right:-315px; top:0; width:300px; background-color:#fff; overflow-x:hidden; overflow-y:auto;}
.xubox_imgsee{display:none;}
.xubox_prev, .xubox_next{position:absolute; top:50%; width:27px; _width:44px; height:44px; margin-top:-22px; outline:none;blr:expression(this.onFocus=this.blur());}
.xubox_prev{left:10px; background-position:-5px -5px; _background-position:-70px -5px;}
.xubox_prev:hover{background-position:-33px -5px; _background-position:-120px -5px;}
.xubox_next{right:10px; _right:8px; background-position:-5px -50px; _background-position:-70px -50px;}
.xubox_next:hover{background-position:-33px -50px; _background-position:-120px -50px;}
.xubox_imgbar{position:absolute; left:0; bottom:0; width:100%; height:32px; line-height:32px; background-color:rgba(0,0,0,.8); background-color:#000\9; filter:Alpha(opacity=80); color:#fff; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; font-size:0;}
.xubox_imgtit{/*position:absolute; left:20px;*/}
.xubox_imgtit *{display:inline-block; *display:inline; *zoom:1; vertical-align:top; font-size:12px;}
.xubox_imgtit a{max-width:65%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; color:#fff;}
.xubox_imgtit a:hover{color:#fff; text-decoration:underline;}
.xubox_imgtit em{padding-left:10px;}

View File

@ -19,7 +19,7 @@
<script src="/static/js/base.js"></script> <script src="/static/js/base.js"></script>
<!-- pop windows layer--> <!-- pop windows layer-->
<script src="/static/js/layer/layer.min.js"></script> <script src="/static/js/layer/layer.js"></script>
<!-- highcharts --> <!-- highcharts -->
<script src="/static/js/highcharts/highcharts.js"></script> <script src="/static/js/highcharts/highcharts.js"></script>

View File

@ -42,13 +42,11 @@
<form id="assetForm" method="post" class="form-horizontal"> <form id="assetForm" method="post" class="form-horizontal">
{{ af.hostname|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
{{ af.ip|bootstrap_horizontal }} {{ af.ip|bootstrap_horizontal }}
<p class="col-sm-offset-2">Tips: 如果IP地址不填写, IP默认会设置与主机名一致</p>
<div class="hr-line-dashed"></div>
{{ af.port|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
{{ af.idc|bootstrap_horizontal }}
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<div class="form-group"> <div class="form-group">
@ -63,6 +61,7 @@
</div> </div>
<div class="form-group" id="admin_account" style="display: none"> <div class="form-group" id="admin_account" style="display: none">
<div class="hr-line-dashed"></div>
<label class="col-sm-2 control-label"> 管理用户名<span class="red-fonts">*</span> </label> <label class="col-sm-2 control-label"> 管理用户名<span class="red-fonts">*</span> </label>
<div class="col-sm-3"> <div class="col-sm-3">
<input type="text" placeholder="Username" name="username" class="form-control"> <input type="text" placeholder="Username" name="username" class="form-control">
@ -74,6 +73,14 @@
</div> </div>
</div> </div>
<div class="form-group" id="id_port" style="display: none">
<div class="hr-line-dashed"></div>
<label class="col-sm-2 control-label"> 端口<span class="red-fonts">*</span> </label>
<div class="col-sm-8">
<input type="text" placeholder="Port" name="port" class="form-control">
</div>
</div>
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
{{ af.group|bootstrap_horizontal }} {{ af.group|bootstrap_horizontal }}
@ -113,15 +120,17 @@
$('document').ready(function(){ $('document').ready(function(){
$('#id_use_default_auth').click(function(){ $('#id_use_default_auth').click(function(){
if ($(this).is(':checked')){ if ($(this).is(':checked')){
$('#admin_account').css('display', 'none') $('#admin_account').css('display', 'none');
$('#id_port').css('display', 'none')
} }
else { else {
$('#admin_account').css('display', 'block') $('#admin_account').css('display', 'block');
$('#id_port').css('display', 'block')
} }
}) })
}); });
var required_fields = ["id_hostname", "id_ip", "id_port"]; var required_fields = ["id_hostname", "id_port"];
required_fields.forEach(function(field) { required_fields.forEach(function(field) {
$('label[for="' + field + '"]').parent().addClass("required"); $('label[for="' + field + '"]').parent().addClass("required");
}); });
@ -134,18 +143,24 @@
check_port: [/^\d{1,5}$/, '端口号不正确'], check_port: [/^\d{1,5}$/, '端口号不正确'],
}, },
fields: { fields: {
"ip": { {# "ip": {#}
rule: "required;check_ip", {# rule: "required;check_ip",#}
tip: "输入IP", {# tip: "输入IP",#}
{# ok: "",#}
{# msg: {required: "必须填写!"}#}
{# },#}
"hostname": {
rule: "required",
tip: "填写主机名",
ok: "", ok: "",
msg: {required: "必须填写!"} msg: {required: "必须填写!"}
}, },
"port": { {# "port": {#}
rule: "required;check_port", {# rule: "required;check_port",#}
tip: "输入端口号", {# tip: "输入端口号",#}
ok: "", {# ok: "",#}
msg: {required: "必须填写!"} {# msg: {required: "必须填写!"}#}
} {# }#}
}, },
valid: function(form) { valid: function(form) {
form.submit(); form.submit();

View File

@ -1,166 +0,0 @@
{% extends 'base.html' %}
{% load mytags %}
{% block content %}
{% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-10">
<div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title">
<h5> 填写资产基本信息 </h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<div class="panel blank-panel">
<div class="panel-options">
<ul class="nav nav-tabs">
<li class="active"><a href="/jasset/asset_add/" class="text-center"><i class="fa fa-laptop"></i> 单台添加 </a></li>
<li><a href="/jasset/host_add_multi" class="text-center"><i class="fa fa-bar-chart-o"></i> 批量添加 </a></li>
</ul>
</div>
<div class="panel-body">
<div class="tab-content">
<div id="tab-1" class="ibox float-e-margins tab-pane active">
{% if error %}
<div class="alert alert-warning text-center">{{ error }}</div>
{% endif %}
{% if msg %}
<div class="alert alert-success text-center">{{ msg }}</div>
{% endif %}
<form id="assetForm" method="post" class="form-horizontal">
<div class="form-group"><label class="col-sm-2 control-label"> IP地址<span class="red-fonts">*</span> </label>
<div class="col-sm-8"><input type="text" name="ip" placeholder="IP" class="form-control"></div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<label class="col-sm-2 control-label"> 端口号<span class="red-fonts">*</span> </label>
<div class="col-sm-8">
<input type="text" placeholder="Port" name="port" class="form-control">
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<label for="j_group" class="col-sm-2 control-label">管理账号</label>
<div class="col-sm-2">
<div class="radio i-checks">
<label>
<input type="checkbox" checked="" value="1" id="use_default_auth" name="use_default_auth"><span> 使用默认 </span>
</label>
</div>
</div>
</div>
<div class="form-group" id="admin_account" style="display: none">
<label class="col-sm-2 control-label"> 管理用户名<span class="red-fonts">*</span> </label>
<div class="col-sm-3">
<input type="text" placeholder="Username" name="username" class="form-control">
</div>
<label class="col-sm-1 control-label"> 密码<span class="red-fonts">*</span> </label>
<div class="col-sm-4">
<input type="password" placeholder="Password" name="password" class="form-control">
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<label for="groups" class="col-sm-2 control-label">所属主机组</label>
<div class="col-sm-8">
<select id="groups" name="groups" class="form-control m-b" multiple size="10">
{% for asset_group in asset_group_all %}
<option type="checkbox" value="{{ asset_group.id }}">{{ asset_group.name }} {% if asset_group.comment %} --- {{ asset_group.comment }} {% endif %}</option>
{% endfor %}
</select>
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label"> 是否激活<span class="red-fonts">*</span> </label>
<div class="col-sm-8">
<div class="radio i-checks">
<label> <input type="radio" checked="" value="1" name="is_active">激活 </label>
<label> <input type="radio" value="0" name="is_active"> 禁用</label>
</div>
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label"> 备注 </label>
<div class="col-sm-8"><input type="text" placeholder="comment" name="comment" class="form-control"></div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="reset"> 重置 </button>
<button class="btn btn-primary" type="submit"> 提交 </button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block self_footer_js %}
<script>
$('document').ready(function(){
$('#use_default_auth').click(function(){
if ($(this).is(':checked')){
$('#admin_account').css('display', 'none')
}
else {
$('#admin_account').css('display', 'block')
}
})
});
$('#assetForm').validator({
timely: 2,
theme: "yellow_right_effect",
rules: {
check_ip: [/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])(\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){3}$/, 'ip地址不正确'],
check_port: [/^\d{1,5}$/, '端口号不正确'],
},
fields: {
"ip": {
rule: "required;check_ip",
tip: "输入IP",
ok: "",
msg: {required: "必须填写!"}
},
"port": {
rule: "required;check_port",
tip: "输入端口号",
ok: "",
msg: {required: "必须填写!"}
}
},
valid: function(form) {
form.submit();
}
});
</script>
{% endblock %}

View File

@ -200,6 +200,7 @@
</div> </div>
<div class="ibox-title"> <div class="ibox-title">
<h5>主机修改记录</h5> <h5>主机修改记录</h5>
<a href="/jasset/asset_edit/?id={{ asset.id }}" data-toggle="tooltip" class="text-success pull-center" data-placement="bottom" title="修改">&nbsp&nbsp&nbsp&nbsp点击修改</a>
<div class="ibox-tools"> <div class="ibox-tools">
<a class="collapse-link"> <a class="collapse-link">
<i class="fa fa-chevron-up"></i> <i class="fa fa-chevron-up"></i>

View File

@ -34,19 +34,20 @@
{% endif %} {% endif %}
<form id="assetForm" method="post" class="form-horizontal"> <form id="assetForm" method="post" class="form-horizontal">
{{ af.ip|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
{{ af.hostname|bootstrap_horizontal }} {{ af.hostname|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
{{ af.ip|bootstrap_horizontal }}
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
{{ af.other_ip|bootstrap_horizontal }} {{ af.other_ip|bootstrap_horizontal }}
<p class="col-sm-offset-2">Tips: 多个IP使用,号隔开</p>
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
{{ af.remote_ip|bootstrap_horizontal }} {{ af.remote_ip|bootstrap_horizontal }}
<div class="hr-line-dashed"></div> {# <div class="hr-line-dashed"></div>#}
{{ af.port|bootstrap_horizontal }} {# {{ af.port|bootstrap_horizontal }}#}
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<div class="form-group"> <div class="form-group">
@ -60,6 +61,7 @@
</div> </div>
</div> </div>
<div class="form-group" id="admin_account" {% if asset.use_default_auth %} style="display: none" {% endif %}> <div class="form-group" id="admin_account" {% if asset.use_default_auth %} style="display: none" {% endif %}>
<div class="hr-line-dashed"></div>
<label class="col-sm-2 control-label"> 管理用户名 <span class="red-fonts">*</span> </label> <label class="col-sm-2 control-label"> 管理用户名 <span class="red-fonts">*</span> </label>
<div class="col-sm-3"> <div class="col-sm-3">
<input type="text" value="{{ asset.username }}" name="username" class="form-control"> <input type="text" value="{{ asset.username }}" name="username" class="form-control">
@ -71,6 +73,13 @@
</div> </div>
</div> </div>
<div class="form-group" id="id_port" {% if asset.use_default_auth %} style="display: none" {% endif %}>
<div class="hr-line-dashed"></div>
<label class="col-sm-2 control-label"> 端口<span class="red-fonts">*</span> </label>
<div class="col-sm-8">
<input type="text" placeholder="Port" value="{{ asset.port }}" name="port" class="form-control">
</div>
</div>
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
{{ af.group|bootstrap_horizontal }} {{ af.group|bootstrap_horizontal }}
@ -156,15 +165,17 @@
$('document').ready(function(){ $('document').ready(function(){
$('#id_use_default_auth').click(function(){ $('#id_use_default_auth').click(function(){
if ($(this).is(':checked')){ if ($(this).is(':checked')){
$('#admin_account').css('display', 'none') $('#admin_account').css('display', 'none');
$('#id_port').css('display', 'none')
} }
else { else {
$('#admin_account').css('display', 'block') $('#admin_account').css('display', 'block');
$('#id_port').css('display', 'block')
} }
}) })
}); });
var required_fields = ["id_ip", "id_port"]; var required_fields = ["id_hostname", "id_port"];
required_fields.forEach(function(field) { required_fields.forEach(function(field) {
$('label[for="' + field + '"]').parent().addClass("required"); $('label[for="' + field + '"]').parent().addClass("required");
}); });
@ -177,18 +188,23 @@
check_port: [/^\d{1,5}$/, '端口号不正确'], check_port: [/^\d{1,5}$/, '端口号不正确'],
}, },
fields: { fields: {
"ip": { "hostname": {
rule: "required;check_ip", rule: "required",
tip: "输入IP", tip: "填写主机名",
ok: "", ok: "",
msg: {required: "必须填写!"} msg: {required: "必须填写!"}
}, },
"port": { {# "ip": {#}
rule: "required;check_port", {# rule: "required;check_ip",#}
tip: "输入端口号", {# tip: "输入IP",#}
ok: "", {# ok: "",#}
msg: {required: "必须填写!"} {# msg: {required: "必须填写!"}#}
} {# },#}
{# "port": {#}
{# rule: "required;check_port",#}
{# tip: "输入端口号",#}
{# ok: "",#}
{# msg: {required: "必须填写!"}#}
}, },
valid: function(form) { valid: function(form) {
form.submit(); form.submit();

View File

@ -7,9 +7,9 @@
<link href="/static/css/style.css" rel="stylesheet"> <link href="/static/css/style.css" rel="stylesheet">
<script src="/static/js/jquery-2.1.1.js"></script> <script src="/static/js/jquery-2.1.1.js"></script>
{# <style>#} <style>
{# body {background: #ffffff;}#} body {background: #ffffff;}
{# </style>#} </style>
</head> </head>
{% load bootstrap %} {% load bootstrap %}
@ -20,21 +20,21 @@
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-lg-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> {# <div class="ibox-title">#}
<h5 class="text-center"> 填写修改主机信息. </h5> {# <h5 class="text-center"> 填写修改主机信息. </h5>#}
<div class="ibox-tools"> {# <div class="ibox-tools">#}
<a class="collapse-link"> {# <a class="collapse-link">#}
<i class="fa fa-chevron-up"></i> {# <i class="fa fa-chevron-up"></i>#}
</a> {# </a>#}
<a class="dropdown-toggle" data-toggle="dropdown" href="#"> {# <a class="dropdown-toggle" data-toggle="dropdown" href="#">#}
<i class="fa fa-wrench"></i> {# <i class="fa fa-wrench"></i>#}
</a> {# </a>#}
<ul class="dropdown-menu dropdown-user"></ul> {# <ul class="dropdown-menu dropdown-user"></ul>#}
<a class="close-link"> {# <a class="close-link">#}
<i class="fa fa-times"></i> {# <i class="fa fa-times"></i>#}
</a> {# </a>#}
</div> {# </div>#}
</div> {# </div>#}
<div class="ibox-content"> <div class="ibox-content">
<form class="form-horizontal" action="" id="signupForm" method="post" name="horizontal" role="form" autocomplete="off"> <form class="form-horizontal" action="" id="signupForm" method="post" name="horizontal" role="form" autocomplete="off">
@ -49,33 +49,43 @@
{{ af.port|bootstrap_horizontal }} {{ af.port|bootstrap_horizontal }}
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<div class="form-group"> <div class="form-group">
<label for="j_group" class="col-sm-2 control-label">管理账号</label> <label for="j_group" class="col-sm-2 control-label">管理账号</label>
<div class="col-sm-2"> <div class="col-sm-2">
<div class="radio i-checks"> <div class="radio i-checks">
<label> <label>
<<<<<<< HEAD
<input type="radio" checked="" value="no_action" id="no" name="use_default_auth" class="auth"><span> 不修改 </span> <input type="radio" checked="" value="no_action" id="no" name="use_default_auth" class="auth"><span> 不修改 </span>
=======
<input type="radio" checked="" value="" id="no" name="use_default_auth" class="auth"><span> 不修改 </span>
>>>>>>> cmdb
</label> </label>
</div> </div>
<div class="radio i-checks"> <div class="radio i-checks">
<label> <label>
<<<<<<< HEAD
<input type="radio" id="default" name="use_default_auth" class="auth"><span> 使用默认 </span> <input type="radio" id="default" name="use_default_auth" class="auth"><span> 使用默认 </span>
=======
<input type="radio" id="default" name="use_default_auth" class="auth" value="default"><span> 使用默认 </span>
>>>>>>> cmdb
</label> </label>
</div> </div>
<div class="radio i-checks"> <div class="radio i-checks">
<label> <label>
<<<<<<< HEAD
<input type="radio" id="pass" name="use_default_auth" class="auth"><span> 用户名密码 </span> <input type="radio" id="pass" name="use_default_auth" class="auth"><span> 用户名密码 </span>
=======
<input type="radio" id="pass" name="use_default_auth" class="auth" value="user_passwd"><span> 用户名密码 </span>
>>>>>>> cmdb
</label> </label>
</div> </div>
</div> </div>
</div> </div>
<div class="form-group" id="admin_account" style="display: none"> <div class="form-group" id="admin_account" style="display: none">
<label class="col-sm-2 control-label"> 管理用户名<span class="red-fonts"> *</span></label> <label class="col-sm-2 control-label"> 管理用户名<span class="red-fonts"> *</span></label>
<div class="col-sm-3"> <div class="col-sm-3">
<input type="text" placeholder="Username" name="username" class="form-control"> <input type="text" placeholder="Username" name="username" class="form-control">
</div> </div>
<label class="col-sm-1 control-label"> 密码<span class="red-fonts">*</span> </label> <label class="col-sm-1 control-label"> 密码<span class="red-fonts">*</span> </label>
<div class="col-sm-4"> <div class="col-sm-4">
<input type="password" placeholder="Password" name="password" class="form-control"> <input type="password" placeholder="Password" name="password" class="form-control">
@ -101,7 +111,7 @@
</div> </div>
<div class="col-sm-3"> <div class="col-sm-3">
<div> <div>
<select id="groups_selected" name="project" class="form-control m-b" size="10" multiple> <select id="groups_selected" name="group" class="form-control m-b" size="10" multiple>
</select> </select>
</div> </div>
</div> </div>
@ -117,7 +127,7 @@
<div class="form-group"> <div class="form-group">
<div class="col-sm-4 col-sm-offset-5"> <div class="col-sm-4 col-sm-offset-5">
<button class="btn btn-white" type="submit"> 重置 </button> <button class="btn btn-white" type="submit"> 重置 </button>
<button class="btn btn-primary" id="host_edit"> 提交 </button> <button class="btn btn-primary"> 提交 </button>
</div> </div>
</div> </div>
</form> </form>
@ -128,6 +138,7 @@
</div> </div>
<script> <script>
$(document).ready(function() { $(document).ready(function() {
<<<<<<< HEAD
$('#host_edit').click(function () { $('#host_edit').click(function () {
var args = {}; var args = {};
var match = null; var match = null;
@ -140,6 +151,8 @@
$('#uuid').val(ids) $('#uuid').val(ids)
}); });
=======
>>>>>>> cmdb
$('.auth').click(function(){ $('.auth').click(function(){
if ($(this).attr('id') == 'pass'){ if ($(this).attr('id') == 'pass'){
$('#admin_account').css('display', 'block') $('#admin_account').css('display', 'block')

View File

@ -70,7 +70,7 @@
<div class="col-sm-2"> <div class="col-sm-2">
<label> <label>
<select name="status" class="form-control m-b" onchange="change_info()"> <select name="status" class="form-control m-b" onchange="change_info()">
<option value="">状态</option> <option value="">所有状态</option>
{% for s in asset_status %} {% for s in asset_status %}
{% ifequal s.0|int2str status %} {% ifequal s.0|int2str status %}
<option value="{{ s.0 }}" selected> {{ s.1 }}</option> <option value="{{ s.0 }}" selected> {{ s.1 }}</option>
@ -103,8 +103,8 @@
<th class="text-center"> <th class="text-center">
<input id="checkall" type="checkbox" class="i-checks" name="checkall" value="checkall" data-editable='false' onclick="check_all('asset_form')"> <input id="checkall" type="checkbox" class="i-checks" name="checkall" value="checkall" data-editable='false' onclick="check_all('asset_form')">
</th> </th>
<th class="text-center" name="ip"> IP地址 </th>
<th class="text-center"> 主机名 </th> <th class="text-center"> 主机名 </th>
<th class="text-center" name="ip"> IP地址 </th>
<th class="text-center"> IDC </th> <th class="text-center"> IDC </th>
<th class="text-center"> 所属主机组 </th> <th class="text-center"> 所属主机组 </th>
{# <th class="text-center"> 配置信息 </th>#} {# <th class="text-center"> 配置信息 </th>#}
@ -119,8 +119,8 @@
<td class="text-center" name="id" value="{{ asset.id }}" data-editable='false'> <td class="text-center" name="id" value="{{ asset.id }}" data-editable='false'>
<input name="id" value="{{ asset.id }}" type="checkbox" class="i-checks"> <input name="id" value="{{ asset.id }}" type="checkbox" class="i-checks">
</td> </td>
<td class="text-center"> {{ asset.ip|default_if_none:"" }} </td>
<td class="text-center"> {{ asset.hostname|default_if_none:"" }} </td> <td class="text-center"> {{ asset.hostname|default_if_none:"" }} </td>
<td class="text-center"> {{ asset.ip|default_if_none:"" }} </td>
<td class="text-center"> {{ asset.idc.name|default_if_none:"" }} </td> <td class="text-center"> {{ asset.idc.name|default_if_none:"" }} </td>
<td class="text-center">{{ asset.group.all|group_str2 }}</td> <td class="text-center">{{ asset.group.all|group_str2 }}</td>
{# <td class="text-center">{{ asset.cpu }}|{{ asset.memory }}|{{ asset.disk }}</td>#} {# <td class="text-center">{{ asset.cpu }}|{{ asset.memory }}|{{ asset.disk }}</td>#}
@ -184,26 +184,26 @@
}); });
$(".iframe").on('click', function(){ $(".iframe").on('click', function(){
var ids = getIDall(); var asset_id_all = getIDall();
if (ids == ''){ if (asset_id_all == ''){
alert("请至少选择一行!"); alert("请至少选择一行!");
return false; return false;
} }
var url= $(this).attr("value") + '?id=' + ids; var url= $(this).attr("value") + '?asset_id_all=' + asset_id_all;
index = $.layer({ layer.open({
type: 2, type: 2,
title: 'JumpServer - 批量修改主机', title: 'JumpServer - 批量修改主机',
maxmin: true, maxmin: true,
shift: 'top', shift: 'top',
border: [2, 0.3, '#1AB394'], border: [2, 0.3, '#1AB394'],
shade: [0.5, '#000000'], shade: [0.5, '#000000'],
shadeClose: true, shadeClose: true,
area : ['800px' , '600px'], area : ['800px' , '600px'],
iframe: {src: url}, content: url,
close: function(){ cancel: function(){
location.replace(location.href); location.replace(location.href);
} }
}); });
}); });
$('.search-btn-excel').unbind('click').bind('click',function(){ $('.search-btn-excel').unbind('click').bind('click',function(){

View File

@ -31,10 +31,6 @@
<i class="fa fa-wrench"></i> <i class="fa fa-wrench"></i>
</a> </a>
<ul class="dropdown-menu dropdown-user"> <ul class="dropdown-menu dropdown-user">
<li><a href="#">未启用 1</a>
</li>
<li><a href="#">未启用 2</a>
</li>
</ul> </ul>
<a class="close-link"> <a class="close-link">
<i class="fa fa-times"></i> <i class="fa fa-times"></i>
@ -44,7 +40,13 @@
<select id="assets_total" name="assets" class="form-control m-b" size="12" multiple style="display: none"> <select id="assets_total" name="assets" class="form-control m-b" size="12" multiple style="display: none">
{% for asset in asset_all %} {% for asset in asset_all %}
<option value="{{ asset.id }}">{{ asset.ip }}</option> <option value="{{ asset.id }}">{{ asset.hostname }} - {{ asset.ip }}</option>
{% endfor %}
</select>
<select id="asset_select_total" name="j_hosts" class="form-control m-b" size="12" multiple style="display: none">
{% for asset in asset_select %}
<option value="{{ asset.id }}">{{ asset.hostname }} - {{ asset.ip }}</option>
{% endfor %} {% endfor %}
</select> </select>
@ -80,7 +82,7 @@
<div> <div>
<select id="assets" name="assets" class="form-control m-b" size="12" multiple> <select id="assets" name="assets" class="form-control m-b" size="12" multiple>
{% for asset in asset_all %} {% for asset in asset_all %}
<option value="{{ asset.id }}">{{ asset.hostname|default_if_none:"" }} - {{ asset.ip|default_if_none:"" }} - {{ asset.port|default_if_none:"" }}</option> <option value="{{ asset.id }}">{{ asset.hostname|default_if_none:"" }} - {{ asset.ip|default_if_none:"" }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>

View File

@ -1,201 +0,0 @@
{% extends 'base.html' %}
{% load mytags %}
{% block content %}
{% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-12">
<div class="ibox float-e-margins" id="all">
<div class="ibox-title">
<h5> 主机组<span class="text-info">{{ group.name }}</span>详细信息列表</h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
<li><a href="#">未启用 1</a>
</li>
<li><a href="#">未启用 2</a>
</li>
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<div class="">
<a target="_blank" href="/jasset/asset_add" class="btn btn-sm btn-primary"> 添加主机 </a>
<b class="pull-right">提示: 此页面删除只从本主机组中剔除主机 </b>
</div>
<form id="contents_form" name="contents_form">
<table class="table table-striped table-bordered table-hover " id="editable" name="editable">
<thead>
<tr>
<th class="text-center"><input id="checkall" type="checkbox" class="i-checks" name="checkall" value="checkall" data-editable='false' onclick="check_all('contents_form')"></th>
<th class="text-center" name="j_ip"> IP地址 </th>
<th class="text-center"> 端口号 </th>
<th class="text-center" name="j_idc"> 所属IDC </th>
<th class="text-center" id="group_id" value="{{ group.id }}"> 所属主机组 </th>
<th class="text-center"> 是否激活 </th>
<th class="text-center" name="j_time"> 添加时间 </th>
<th class="text-center" name="j_comment"> 备注 </th>
<th class="text-center"> 操作 </th>
</tr>
</thead>
<tbody>
{% for asset in contacts.object_list %}
<tr class="gradeX">
<td class="text-center" name="j_id" value="{{ asset.id|default_if_none:"" }}" data-editable='false'><input name="id" value="{{ asset.id }}" type="checkbox" class="i-checks"></td>
<td class="text-center" name="j_ip"> {{ asset.ip|default_if_none:"" }} </td>
<td class="text-center" name="j_port"> {{ asset.port|default_if_none:"" }} </td>
<td class="text-center" name="j_idc"> {{ asset.idc.name|default_if_none:"" }} </td>
<td class="text-center" name="j_group">{{ asset.bis_group.all | group_str2 }}</td>
<td class="text-center" name="j_active"> {{ asset.is_active|bool2str }} </td>
<td class="text-center"> {{ asset.date_added|date:"Y-m-d H:i:s" }} </td>
<td class="text-center" name="j_comment"> {{ asset.comment|default_if_none:"" }} </td>
<td class="text-center" data-editable='false'>
<a href="/jasset/asset_detail/?id={{ asset.id }}" class="iframe btn btn-xs btn-primary">详情</a>
<a href="/jasset/asset_edit/?id={{ asset.id }}" class="btn btn-xs btn-info">编辑</a>
<a href="/jasset/group_del_host/?id={{ asset.id }}&gid={{ group.id }}" class="btn btn-xs btn-danger">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
<div class="col-sm-6">
<input type="button" id="del_button" class="btn btn-danger btn-sm" name="del_button" value="删除" onclick="del('contents_form')" />
<input type="button" id="alter_button" class="btn btn-warning btn-sm" name="alter_button" value="修改" onclick="alter('contents_form')" />
</div>
<div class="col-sm-6">
<div class="dataTables_paginate paging_simple_numbers" id="editable_paginate">
<ul class="pagination" style="margin-top: 0; float: right">
{% if keyword %}
{% if contacts.has_previous %}
<li class="paginate_button previous" aria-controls="editable" tabindex="0" id="editable_previous">
<a href="?keyword={{ keyword }}&page={{ contacts.previous_page_number }}">Previous</a>
</li>
{% else %}
<li class="paginate_button previous disabled" aria-controls="editable" tabindex="0" id="editable_previous">
<a href="#">Previous</a>
</li>
{% endif %}
{% ifequal show_first 1 %}
<li class="paginate_button" aria-controls="editable" tabindex="0"><a href="?keyword={{ keyword }}&page=1&id={{ group.id }}" title="第1页">1...</a></li>
{% endifequal %}
{% for page in page_range %}
{% ifequal current_page page %}
<li class="paginate_button active" aria-controls="editable" tabindex="0"><a href="?keyword={{ keyword }}&page={{ page }}&id={{ group.id }}" title="第{{ page }}页">{{ page }}</a></li>
{% else %}
<li class="paginate_button" aria-controls="editable" tabindex="0"><a href="?keyword={{ keyword }}&page={{ page }}&id={{ group.id }}" title="第{{ page }}页">{{ page }}</a></li>
{% endifequal %}
{% endfor %}
{% ifequal show_end 1 %}
<li class="paginate_button" aria-controls="editable" tabindex="0"><a href="?keyword={{ keyword }}&page={{ p.num_pages }}&id={{ group.id }}" title="第{{ page }}页">...{{ p.num_pages }}</a></li>
{% endifequal %}
{% if contacts.has_next %}
<li class="paginate_button next" aria-controls="editable" tabindex="0" id="editable_next">
<a href="?keyword={{ keyword }}&page={{ contacts.next_page_number }}&id={{ group.id }}">Next</a>
</li>
{% else %}
<li class="paginate_button next disabled" aria-controls="editable" tabindex="0" id="editable_next">
<a href="#">Next</a>
</li>
{% endif %}
{% else %}
{% if contacts.has_previous %}
<li class="paginate_button previous" aria-controls="editable" tabindex="0" id="editable_previous">
<a href="?page={{ contacts.previous_page_number }}&id={{ group.id }}">Previous</a>
</li>
{% else %}
<li class="paginate_button previous disabled" aria-controls="editable" tabindex="0" id="editable_previous">
<a href="#">Previous</a>
</li>
{% endif %}
{% ifequal show_first 1 %}
<li class="paginate_button" aria-controls="editable" tabindex="0"><a href="?page=1&id={{ group.id }}" title="第1页">1...</a></li>
{% endifequal %}
{% for page in page_range %}
{% ifequal current_page page %}
<li class="paginate_button active" aria-controls="editable" tabindex="0"><a href="?page={{ page }}&id={{ group.id }}" title="第{{ page }}页">{{ page }}</a></li>
{% else %}
<li class="paginate_button" aria-controls="editable" tabindex="0"><a href="?page={{ page }}&id={{ group.id }}" title="第{{ page }}页">{{ page }}</a></li>
{% endifequal %}
{% endfor %}
{% ifequal show_end 1 %}
<li class="paginate_button" aria-controls="editable" tabindex="0"><a href="?page={{ p.num_pages }}&id={{ group.id }}" title="第{{ page }}页">...{{ p.num_pages }}</a></li>
{% endifequal %}
{% if contacts.has_next %}
<li class="paginate_button next" aria-controls="editable" tabindex="0" id="editable_next">
<a href="?page={{ contacts.next_page_number }}&id={{ group.id }}">Next</a>
</li>
{% else %}
<li class="paginate_button next disabled" aria-controls="editable" tabindex="0" id="editable_next">
<a href="#">Next</a>
</li>
{% endif %}
{% endif %}
</ul>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$('#editable').editableTableWidget();
});
function alter(form) {
selectData = GetTableDataBox();
if (selectData[1] != 0) {
$.ajax({
type: "asset",
url: "/jasset/host_edit/batch/",
data: {"editable": selectData[0], "len_table": selectData[1]},
success: function (data) {
alert("修改成功");
window.open("/jasset/host_list/", "_self");
}
});
}
}
function del(form) {
var checkboxes = document.getElementById(form);
var id_list = {};
var group_id = $('#group_id').attr("value");
var j = 0;
for (var i = 0; i < checkboxes.elements.length; i++) {
if (checkboxes.elements[i].type == "checkbox" && checkboxes.elements[i].checked == true && checkboxes.elements[i].value != "checkall") {
id_list[j] = checkboxes.elements[i].value;
j++;
}
}
if (confirm("确定从主机组中删除")) {
$.ajax({
type: "POST",
url: "/jasset/group_del_host/?id=group",
data: {"id_list": id_list, "len_list": j, "group_id": group_id},
success: function (data) {
window.open(window.location.href, "_self");
}
});
}
}
</script>
{% endblock %}

View File

@ -31,10 +31,6 @@
<i class="fa fa-wrench"></i> <i class="fa fa-wrench"></i>
</a> </a>
<ul class="dropdown-menu dropdown-user"> <ul class="dropdown-menu dropdown-user">
<li><a href="#">未启用 1</a>
</li>
<li><a href="#">未启用 2</a>
</li>
</ul> </ul>
<a class="close-link"> <a class="close-link">
<i class="fa fa-times"></i> <i class="fa fa-times"></i>
@ -44,13 +40,13 @@
<select id="assets_total" name="assets" class="form-control m-b" size="12" multiple style="display: none"> <select id="assets_total" name="assets" class="form-control m-b" size="12" multiple style="display: none">
{% for asset in asset_all %} {% for asset in asset_all %}
<option value="{{ asset.id }}">{{ asset.ip }}</option> <option value="{{ asset.id }}">{{ asset.hostname }} - {{ asset.ip }}</option>
{% endfor %} {% endfor %}
</select> </select>
<select id="asset_select_total" name="asset_select" class="form-control m-b" size="12" multiple style="display: none"> <select id="asset_select_total" name="j_hosts" class="form-control m-b" size="12" multiple style="display: none">
{% for asset in asset_select %} {% for asset in asset_select %}
<option value="{{ asset.id }}">{{ asset.ip }}</option> <option value="{{ asset.id }}">{{ asset.hostname }} - {{ asset.ip }}</option>
{% endfor %} {% endfor %}
</select> </select>
@ -86,7 +82,7 @@
<div> <div>
<select id="assets" name="assets" class="form-control m-b" size="12" multiple> <select id="assets" name="assets" class="form-control m-b" size="12" multiple>
{% for asset in asset_no_select %} {% for asset in asset_no_select %}
<option value="{{ asset.id }}">{{ asset.hostname|default_if_none:"" }} - {{ asset.ip|default_if_none:"" }} - {{ asset.port|default_if_none:"" }}</option> <option value="{{ asset.id }}">{{ asset.hostname|default_if_none:"" }} - {{ asset.ip|default_if_none:"" }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
@ -103,7 +99,7 @@
<div> <div>
<select id="asset_select" name="asset_select" class="form-control m-b" size="12" multiple> <select id="asset_select" name="asset_select" class="form-control m-b" size="12" multiple>
{% for asset in asset_select %} {% for asset in asset_select %}
<option value="{{ asset.id }}">{{ asset.hostname|default_if_none:"" }} - {{ asset.ip|default_if_none:"" }} - {{ asset.port|default_if_none:"" }}</option> <option value="{{ asset.id }}">{{ asset.hostname|default_if_none:"" }} - {{ asset.ip|default_if_none:"" }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>

View File

@ -58,10 +58,10 @@
<input name="id" value="{{ asset_group.id }}" type="checkbox" class="i-checks"> <input name="id" value="{{ asset_group.id }}" type="checkbox" class="i-checks">
</td> </td>
<td class="text-center"> {{ asset_group.name }} </td> <td class="text-center"> {{ asset_group.name }} </td>
<td class="text-center"> <a href="/jasset/group_detail/?id={{ asset_group.id }}">{{ asset_group.asset_set.count }}</a> </td> <td class="text-center"> <a href="/jasset/asset_list/?group_id={{ asset_group.id }}">{{ asset_group.asset_set.count }}</a> </td>
<td class="text-center"> {{ asset_group.comment }} </td> <td class="text-center"> {{ asset_group.comment }} </td>
<td class="text-center"> <td class="text-center">
<a href="/jasset/group_detail/?id={{ asset_group.id }}" class="btn btn-xs btn-info">详情</a> <a href="/jasset/asset_list/?group_id={{ asset_group.id }}" class="btn btn-xs btn-info">详情</a>
<a href="/jasset/group_edit/?id={{ asset_group.id }}" class="btn btn-xs btn-info">编辑</a> <a href="/jasset/group_edit/?id={{ asset_group.id }}" class="btn btn-xs btn-info">编辑</a>
<a value="/jasset/group_del/?id={{ asset_group.id }}" class="btn btn-xs btn-danger group_del">删除</a> <a value="/jasset/group_del/?id={{ asset_group.id }}" class="btn btn-xs btn-danger group_del">删除</a>
</td> </td>

View File

@ -1,68 +0,0 @@
{% extends 'base.html' %}
{% block content %}
{% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-10">
<div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title">
<h5> 填写主机基本信息 </h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
<li><a href="#">未启用 1</a>
</li>
<li><a href="#">未启用 2</a>
</li>
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<div class="panel blank-panel">
<div class="panel-options">
<ul class="nav nav-tabs">
<li><a href="/jasset/host_add/" class="text-center"><i class="fa fa-laptop"></i> 单台添加 </a></li>
<li class="active"><a href="/jasset/host_add_multi/" class="text-center"><i class="fa fa-bar-chart-o"></i> 批量添加 </a></li>
</ul>
</div>
<div class="panel-body">
<div id="tab-2" class="ibox float-e-margins tab-pane active">
{% if emg %}
<div class="alert alert-warning text-center">{{ emg }}</div>
{% endif %}
{% if smg %}
<div class="alert alert-success text-center">{{ smg }}</div>
{% endif %}
<p>请严格按照文本框内主机信息格式填写, 多台主机回车换行, 具体格式如下: </p>
<p class="text-info">IP地址 端口号 登录方式 IDC名 所属主机组 所属部门 激活/禁用 备注 </p>
<form id="assetMulti" method="post" class="form-horizontal">
<div><textarea id="j_multi" name="j_multi" type="text" placeholder="192.168.1.1 22 LDAP 北京联通 [网站,数据库] 运维部 激活 网站服务器" class="form-control" style="width:700px;height:500px">192.168.1.1 22 LDAP 北京联通 ['网站','数据库'] ['运维部','测试部'] 激活 网站服务器</textarea></div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-4">
<button class="btn btn-white" type="submit"> 重置 </button>
<button class="btn btn-primary" type="submit"> 提交 </button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -1,172 +0,0 @@
{% extends 'base.html' %}
{% load mytags %}
{% block content %}
{% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-12">
<div class="ibox float-e-margins" id="all">
<div class="ibox-title">
<h5> 主机详细信息列表</h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
<li><a href="#">未启用 1</a>
</li>
<li><a href="#">未启用 2</a>
</li>
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<div>
<span>点击别名栏修改主机别名, 可在跳板机上使用别名直接登录.</span>
<form id="search_form" method="get" action="" class="pull-right mail-search">
<div class="input-group">
<input type="text" class="form-control input-sm" id="search_input" name="keyword" placeholder="Search">
<input type="text" style="display: none">
<div class="input-group-btn">
<button id='search_btn' type="button" class="btn btn-sm btn-primary" onclick="host_search()">
Search
</button>
</div>
</div>
</form>
</div>
<form id="contents_form" name="contents_form">
<table class="table table-striped table-bordered table-hover " id="editable" name="editable">
<thead>
<tr>
<th class="text-center"><input id="checkall" type="checkbox" class="i-checks" name="checkall" value="checkall" data-editable='false' onclick="check_all('contents_form')"></th>
<th class="text-center" name="j_ip"> IP地址 </th>
<th class="text-center"> 端口号 </th>
<th class="text-center" name="j_type"> 登录方式 </th>
<th class="text-center" name="j_idc"> 所属IDC </th>
<th class="text-center"> 所属部门 </th>
<th class="text-center"> 所属主机组 </th>
<th class="text-center"> 别名 </th>
<th class="text-center" name="j_comment"> 备注 </th>
<th class="text-center"> 操作 </th>
</tr>
</thead>
<tbody>
{% for post in contacts.object_list %}
<tr class="gradeX">
<td class="text-center" name="j_id" value="{{ post.id }}" data-editable='false'><input name="id" value="{{ post.id }}" type="checkbox" class="i-checks"></td>
<td class="text-center" data-editable='false' name="j_ip"> {{ post.ip }} </td>
<td class="text-center" data-editable='false' name="j_port"> {{ post.port }} </td>
<td class="text-center" data-editable='false' name="j_type"> {{ post.login_type|get_login_type }} </td>
<td class="text-center" data-editable='false' name="j_idc"> {{ post.idc.name }} </td>
<td class="text-center" data-editable='false' name="j_dept">{{ post.dept.all | group_str2 }}</td>
<td class="text-center" data-editable='false' name="j_group">{{ post.bis_group.all | group_str2_all }}</td>
<td class="text-center" name="j_alias"> {{ post|get_user_alias:user_id }} </td>
<td class="text-center" data-editable='false' name="j_comment"> {{ post.comment }} </td>
<td class="text-center" data-editable='false'>
<a href="/jasset/host_detail/?id={{ post.id }}" class="iframe btn btn-xs btn-primary">详情</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
<div class="col-sm-6">
<input type="button" id="alter_button" class="btn btn-warning btn-sm" name="alter_button" value="修改" onclick="alter('contents_form')" />
</div>
{% include 'paginator.html' %}
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$('#editable').editableTableWidget();
});
$(".iframe").on('click', function(){
var url= $(this).attr("value");
$.layer({
type: 2,
title: 'JumpServer主机详情',
maxmin: true,
shift: 'top',
border: [2, 0.3, '#1AB394'],
shade: [0.5, '#000000'],
shadeClose: true,
area : ['800px' , '600px'],
iframe: {src: url}
});
});
function alter(form) {
selectData = GetTableDataBox();
if (selectData[1] != 0) {
$.ajax({
type: "post",
url: "/jasset/host_edit_common/batch/",
data: {"editable": selectData[0], "len_table": selectData[1]},
success: function (data) {
alert("修改成功");
window.open("/jasset/host_list/", "_self");
}
});
}
}
function del(form) {
var checkboxes = document.getElementById(form);
var id_list = {};
var j = 0;
for (var i = 0; i < checkboxes.elements.length; i++) {
if (checkboxes.elements[i].type == "checkbox" && checkboxes.elements[i].checked == true && checkboxes.elements[i].value != "checkall") {
id_list[j] = checkboxes.elements[i].value;
j++;
}
}
if (confirm("确定删除")) {
$.ajax({
type: "POST",
url: "/jasset/host_del/multi/",
data: {"id_list": id_list, "len_list": j},
success: function (data) {
window.open("/jasset/host_list/", "_self");
}
});
}
}
function host_search(){
$.ajax({
type: "GET",
url: "/jasset/search/",
data: $("#search_form").serialize(),
success: function (data) {
$("#contents_form").html(data);
}
});
}
$("#search_input").keydown(function(e){
if(e.keyCode==13){
host_search()
}
})
</script>
{% endblock %}

View File

@ -1,177 +0,0 @@
{% extends 'base.html' %}
{% load mytags %}
{% block content %}
{% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-12">
<div class="ibox float-e-margins" id="all">
<div class="ibox-title">
<h5> 主机详细信息列表</h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
<li><a href="#">未启用 1</a>
</li>
<li><a href="#">未启用 2</a>
</li>
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<div>
<a target="_blank" href="/jasset/host_add" class="btn btn-sm btn-primary "> 添加 </a>
<!--<form id="search_form" method="get" action="" class="pull-right mail-search">-->
<!--<div class="input-group">-->
<!--<input type="text" class="form-control input-sm" id="search_input" name="keyword" placeholder="Search">-->
<!--<input type="text" style="display: none">-->
<!--<div class="input-group-btn">-->
<!--<button id='search_btn' type="button" class="btn btn-sm btn-primary" onclick="host_search()">-->
<!--Search-->
<!--</button>-->
<!--</div>-->
<!--</div>-->
<!--</form>-->
</div>
<form id="contents_form" name="contents_form">
<table class="table table-striped table-bordered table-hover " id="editable" name="editable">
<thead>
<tr>
<th class="text-center"><input id="checkall" type="checkbox" class="i-checks" name="checkall" value="checkall" data-editable='false' onclick="check_all('contents_form')"></th>
<th class="text-center" name="j_ip"> IP地址 </th>
<th class="text-center"> 端口号 </th>
<th class="text-center" name="j_type"> 登录方式 </th>
<th class="text-center" name="j_idc"> 所属IDC </th>
<th class="text-center"> 所属部门 </th>
<th class="text-center"> 所属主机组 </th>
<th class="text-center"> 是否激活 </th>
<th class="text-center" name="j_comment"> 备注 </th>
<th class="text-center"> 操作 </th>
</tr>
</thead>
<tbody>
{% for post in posts %}
<tr class="gradeX">
<td class="text-center" name="j_id" value="{{ post.id }}" data-editable='false'><input name="id" value="{{ post.id }}" type="checkbox" class="i-checks"></td>
<td class="text-center" name="j_ip"> {{ post.ip }} </td>
<td class="text-center" name="j_port"> {{ post.port }} </td>
<td class="text-center" name="j_type"> {{ post.login_type|get_login_type }} </td>
<td class="text-center" name="j_idc"> {{ post.idc.name }} </td>
<td class="text-center" name="j_dept">{{ post.dept.all | group_str2 }}</td>
<td class="text-center" name="j_group">{{ post.bis_group.all | group_str2_all }}</td>
<td class="text-center" name="j_active"> {{ post.is_active|bool2str }} </td>
<td class="text-center" name="j_comment"> {{ post.comment }} </td>
<td class="text-center" data-editable='false'>
<a value="/jasset/{{ post.ip }}/" class="iframe btn btn-xs btn-primary">详情</a>
{% ifnotequal session_role_id 0 %}
<a href="/jasset/host_edit/?id={{ post.id }}" class="btn btn-xs btn-info">编辑</a>
<a href="/jasset/host_del/{{ post.id }}" class="btn btn-xs btn-danger">删除</a>
{% endifnotequal %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
<div class="col-sm-6">
<input type="button" id="del_button" class="btn btn-danger btn-sm" name="del_button" value="删除" onclick="del('contents_form')" />
<input type="button" id="alter_button" class="btn btn-warning btn-sm" name="alter_button" value="修改" onclick="alter('contents_form')" />
</div>
<!--{% include 'paginator.html' %}-->
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$('#editable').editableTableWidget();
});
$(".iframe").on('click', function(){
var url= $(this).attr("value");
$.layer({
type: 2,
title: 'JumpServer主机详情',
maxmin: true,
shift: 'top',
border: [2, 0.3, '#1AB394'],
shade: [0.5, '#000000'],
shadeClose: true,
area : ['800px' , '600px'],
iframe: {src: url}
});
});
function alter(form) {
selectData = GetTableDataBox();
if (selectData[1] != 0) {
$.ajax({
type: "post",
url: "/jasset/host_edit/batch/",
data: {"editable": selectData[0], "len_table": selectData[1]},
success: function (data) {
alert("修改成功");
window.open("/jasset/host_list/", "_self");
}
});
}
}
function del(form) {
var checkboxes = document.getElementById(form);
var id_list = {};
var j = 0;
for (var i = 0; i < checkboxes.elements.length; i++) {
if (checkboxes.elements[i].type == "checkbox" && checkboxes.elements[i].checked == true && checkboxes.elements[i].value != "checkall") {
id_list[j] = checkboxes.elements[i].value;
j++;
}
}
if (confirm("确定删除")) {
$.ajax({
type: "POST",
url: "/jasset/host_del/multi/",
data: {"id_list": id_list, "len_list": j},
success: function (data) {
window.open("/jasset/host_list/", "_self");
}
});
}
}
function host_search(){
$.ajax({
type: "GET",
url: "/jasset/search/",
data: $("#search_form").serialize(),
success: function (data) {
$("#contents_form").html(data);
}
});
}
$("#search_input").keydown(function(e){
if(e.keyCode==13){
host_search()
}
})
</script>
{% endblock %}

View File

@ -1,169 +0,0 @@
{% load mytags %}
<table class="table table-striped table-bordered table-hover " id="editable" name="editable">
<thead>
<tr>
<th class="text-center"><input id="checkall" type="checkbox" class="i-checks" name="checkall" value="checkall" data-editable='false' onclick="check_all('contents_form')"></th>
<th class="text-center" name="j_ip"> IP地址 </th>
<th class="text-center"> 端口号 </th>
<th class="text-center" name="j_type"> 登录方式 </th>
<th class="text-center" name="j_idc"> 所属IDC </th>
<th class="text-center"> 所属业务组 </th>
{% ifnotequal session_role_id 0 %}
<th class="text-center"> 是否激活 </th>
{% else %}
<th class="text-center"> 别名 </th>
{% endifnotequal %}
<th class="text-center" name="j_time"> 添加时间 </th>
<th class="text-center" name="j_comment"> 备注 </th>
<th class="text-center"> 操作 </th>
</tr>
</thead>
<tbody>
{% for post in contacts.object_list %}
<tr class="gradeX">
<td class="text-center" name="j_id" value="{{ post.id }}" data-editable='false'><input name="id" value="{{ post.id }}" type="checkbox" class="i-checks"></td>
<td class="text-center" name="j_ip"> {{ post.ip }} </td>
<td class="text-center" name="j_port"> {{ post.port }} </td>
<td class="text-center" name="j_type"> {{ post.login_type|get_login_type }} </td>
<td class="text-center" name="j_idc"> {{ post.idc.name }} </td>
<td class="text-center" name="j_group">{{ post.bis_group.all | group_str2 }}</td>
{% ifnotequal session_role_id 0 %}
<td class="text-center" name="j_alias"> {{ post.is_active|bool2str }} </td>
{% else %}
<td class="text-center" name="j_active"> {{ post|get_user_alias:user_id }} </td>
{% endifnotequal %}
<td class="text-center"> {{ post.date_added|date:"Y-m-d H:i:s" }} </td>
<td class="text-center" name="j_comment"> {{ post.comment }} </td>
<td class="text-center" data-editable='false'>
<a value="/jasset/{{ post.ip }}/" class="iframe btn btn-xs btn-primary">详情</a>
{% ifnotequal session_role_id 0 %}
<a href="/jasset/host_edit/?id={{ post.id }}" class="btn btn-xs btn-info">编辑</a>
<a href="/jasset/host_del/{{ post.id }}" class="btn btn-xs btn-danger">删除</a>
{% endifnotequal %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
<div class="col-sm-6">
<input type="button" id="del_button" class="btn btn-danger btn-sm" name="del_button" value="删除" onclick="del('contents_form')" />
<input type="button" id="alter_button" class="btn btn-warning btn-sm" name="alter_button" value="修改" onclick="alter('contents_form')" />
</div>
<div class="col-sm-6">
<div class="dataTables_paginate paging_simple_numbers" id="editable_paginate">
<ul class="pagination" style="margin-top: 0; float: right">
{% if contacts.has_previous %}
<li class="paginate_button previous" aria-controls="editable" tabindex="0" id="editable_previous">
<a href="?page={{ contacts.previous_page_number }}">Previous</a>
</li>
{% else %}
<li class="paginate_button previous disabled" aria-controls="editable" tabindex="0" id="editable_previous">
<a href="#">Previous</a>
</li>
{% endif %}
{% ifequal show_first 1 %}
<li class="paginate_button" aria-controls="editable" tabindex="0"><a href="?page=1" title="第1页">1...</a></li>
{% endifequal %}
{% for page in page_range %}
{% ifequal current_page page %}
<li class="paginate_button active" aria-controls="editable" tabindex="0"><a href="?keyword={{ keyword }}&page={{ page }}" title="第{{ page }}页">{{ page }}</a></li>
{% else %}
<li class="paginate_button" aria-controls="editable" tabindex="0"><a href="?keyword={{ keyword }}&page={{ page }}" title="第{{ page }}页">{{ page }}</a></li>
{% endifequal %}
{% endfor %}
{% ifequal show_end 1 %}
<li class="paginate_button" aria-controls="editable" tabindex="0"><a href="?page={{ p.num_pages }}" title="第{{ page }}页">...{{ p.num_pages }}</a></li>
{% endifequal %}
{% if contacts.has_next %}
<li class="paginate_button next" aria-controls="editable" tabindex="0" id="editable_next">
<a href="?page={{ contacts.next_page_number }}">Next</a>
</li>
{% else %}
<li class="paginate_button next disabled" aria-controls="editable" tabindex="0" id="editable_next">
<a href="#">Next</a>
</li>
{% endif %}
</ul>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$('#editable').editableTableWidget();
});
$(".iframe").on('click', function(){
var url= $(this).attr("value");
$.layer({
type: 2,
title: 'JumpServer主机详情',
maxmin: true,
shift: 'top',
border: [2, 0.3, '#1AB394'],
shade: [0.5, '#000000'],
shadeClose: true,
area : ['800px' , '600px'],
iframe: {src: url}
});
});
function alter(form) {
selectData = GetTableDataBox();
if (selectData[1] != 0) {
$.ajax({
type: "post",
url: "/jasset/host_edit/batch/",
data: {"editable": selectData[0], "len_table": selectData[1]},
success: function (data) {
alert("修改成功");
window.open("/jasset/host_list/", "_self");
}
});
}
}
function del(form) {
var checkboxes = document.getElementById(form);
var id_list = {};
var j = 0;
for (var i = 0; i < checkboxes.elements.length; i++) {
if (checkboxes.elements[i].type == "checkbox" && checkboxes.elements[i].checked == true && checkboxes.elements[i].value != "checkall") {
id_list[j] = checkboxes.elements[i].value;
j++;
}
}
if (confirm("确定删除")) {
$.ajax({
type: "POST",
url: "/jasset/host_del/multi/",
data: {"id_list": id_list, "len_list": j},
success: function (data) {
window.open("/jasset/host_list/", "_self");
}
});
}
}
function host_search(){
$.ajax({
type: "GET",
url: "/jasset/search/",
data: $("#search_form").serialize(),
success: function (data) {
$("#contents_form").html(data);
}
});
}
$("#search_input").keydown(function(e){
if(e.keyCode==13){
host_search()
}
})
</script>

View File

@ -1,229 +0,0 @@
{% extends 'base.html' %}
{% load mytags %}
{% block content %}
{% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-12">
<div class="ibox float-e-margins" id="all">
<div class="ibox-title">
<h5> IDC<span class="text-info"> {{ idc.name }} </span>详细信息列表 </h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
<li><a href="#">未启用 1</a>
</li>
<li><a href="#">未启用 2</a>
</li>
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
{% if emg %}
<div class="alert alert-warning text-center">{{ emg }}</div>
{% endif %}
{% if smg %}
<div class="alert alert-success text-center">{{ smg }}</div>
{% endif %}
<div class="">
<a target="_blank" href="/jasset/host_add" class="btn btn-sm btn-primary "> 添加主机 </a>
</div>
<form id="asset_form" name="asset_form">
<table class="table table-striped table-bordered table-hover " id="editable" name="editable">
<thead>
<tr>
<th class="text-center">
<input id="checkall" type="checkbox" class="i-checks" name="checkall" value="checkall" data-editable='false' onclick="check_all('asset_form')">
</th>
<th class="text-center" name="ip"> IP地址 </th>
<th class="text-center"> 主机名 </th>
<th class="text-center"> IDC </th>
<th class="text-center"> 所属主机组 </th>
<th class="text-center"> 配置信息 </th>
<th class="text-center"> 使用默认管理 </th>
<th class="text-center"> 操作 </th>
</tr>
</thead>
<tbody>
{% for asset in contact_list %}
<tr class="gradeX">
<td class="text-center" name="id" value="{{ asset.id }}" data-editable='false'>
<input name="id" value="{{ asset.id }}" type="checkbox" class="i-checks">
</td>
<td class="text-center"> {{ asset.ip }} </td>
<td class="text-center"> {{ asset.hostname }} </td>
<td class="text-center"> {{ asset.idc.name }} </td>
<td class="text-center">{{ asset.group.all|group_str2 }}</td>
<td class="text-center">{{ asset.cpu }}|{{ asset.memory }}|{{ asset.disk }}</td>
<td class="text-center"> {{ asset.use_default_auth|bool2str }} </td>
<td class="text-center" data-editable='false'>
<a href="/jasset/asset_detail/?id={{ asset.id }}" class="btn btn-xs btn-primary">详情</a>
{% ifnotequal session_role_id 0 %}
<a href="/jasset/asset_edit/?id={{ asset.id }}" class="btn btn-xs btn-info">编辑</a>
<a value="/jasset/asset_del/?id={{ asset.id }}" class="btn btn-xs btn-danger asset_del">删除</a>
{% endifnotequal %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
<div class="col-sm-6">
<input type="button" id="asset_del" class="btn btn-danger btn-sm" name="del_button" value="删除" />
<a value="/jasset/asset_edit_batch/" type="button" class="btn btn-sm btn-warning iframe">修改</a>
</div>
<div class="col-sm-6">
<div class="dataTables_paginate paging_simple_numbers" id="editable_paginate">
<ul class="pagination" style="margin-top: 0; float: right">
{% if keyword %}
{% if contacts.has_previous %}
<li class="paginate_button previous" aria-controls="editable" tabindex="0" id="editable_previous">
<a href="?keyword={{ keyword }}&page={{ contacts.previous_page_number }}">Previous</a>
</li>
{% else %}
<li class="paginate_button previous disabled" aria-controls="editable" tabindex="0" id="editable_previous">
<a href="#">Previous</a>
</li>
{% endif %}
{% ifequal show_first 1 %}
<li class="paginate_button" aria-controls="editable" tabindex="0"><a href="?keyword={{ keyword }}&page=1&id={{ idc.id }}" title="第1页">1...</a></li>
{% endifequal %}
{% for page in page_range %}
{% ifequal current_page page %}
<li class="paginate_button active" aria-controls="editable" tabindex="0"><a href="?keyword={{ keyword }}&page={{ page }}&id={{ idc.id }}" title="第{{ page }}页">{{ page }}</a></li>
{% else %}
<li class="paginate_button" aria-controls="editable" tabindex="0"><a href="?keyword={{ keyword }}&page={{ page }}&id={{ idc.id }}" title="第{{ page }}页">{{ page }}</a></li>
{% endifequal %}
{% endfor %}
{% ifequal show_end 1 %}
<li class="paginate_button" aria-controls="editable" tabindex="0"><a href="?keyword={{ keyword }}&page={{ p.num_pages }}&id={{ idc.id }}" title="第{{ page }}页">...{{ p.num_pages }}</a></li>
{% endifequal %}
{% if contacts.has_next %}
<li class="paginate_button next" aria-controls="editable" tabindex="0" id="editable_next">
<a href="?keyword={{ keyword }}&page={{ contacts.next_page_number }}&id={{ idc.id }}">Next</a>
</li>
{% else %}
<li class="paginate_button next disabled" aria-controls="editable" tabindex="0" id="editable_next">
<a href="#">Next</a>
</li>
{% endif %}
{% else %}
{% if contacts.has_previous %}
<li class="paginate_button previous" aria-controls="editable" tabindex="0" id="editable_previous">
<a href="?page={{ contacts.previous_page_number }}&id={{ idc.id }}">Previous</a>
</li>
{% else %}
<li class="paginate_button previous disabled" aria-controls="editable" tabindex="0" id="editable_previous">
<a href="#">Previous</a>
</li>
{% endif %}
{% ifequal show_first 1 %}
<li class="paginate_button" aria-controls="editable" tabindex="0"><a href="?page=1&id={{ idc.id }}" title="第1页">1...</a></li>
{% endifequal %}
{% for page in page_range %}
{% ifequal current_page page %}
<li class="paginate_button active" aria-controls="editable" tabindex="0"><a href="?page={{ page }}&id={{ idc.id }}" title="第{{ page }}页">{{ page }}</a></li>
{% else %}
<li class="paginate_button" aria-controls="editable" tabindex="0"><a href="?page={{ page }}&id={{ idc.id }}" title="第{{ page }}页">{{ page }}</a></li>
{% endifequal %}
{% endfor %}
{% ifequal show_end 1 %}
<li class="paginate_button" aria-controls="editable" tabindex="0"><a href="?page={{ p.num_pages }}&id={{ idc.id }}" title="第{{ page }}页">...{{ p.num_pages }}</a></li>
{% endifequal %}
{% if contacts.has_next %}
<li class="paginate_button next" aria-controls="editable" tabindex="0" id="editable_next">
<a href="?page={{ contacts.next_page_number }}&id={{ idc.id }}">Next</a>
</li>
{% else %}
<li class="paginate_button next disabled" aria-controls="editable" tabindex="0" id="editable_next">
<a href="#">Next</a>
</li>
{% endif %}
{% endif %}
</ul>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$('#editable').editableTableWidget();
});
function alter(form) {
selectData = GetTableDataBox();
if (selectData[1] != 0) {
$.ajax({
type: "post",
url: "/jasset/host_edit/batch/",
data: {"editable": selectData[0], "len_table": selectData[1]},
success: function (data) {
alert("修改成功");
window.open("/jasset/host_list/", "_self");
}
});
}
}
$(".iframe").on('click', function(){
var ids = getIDall();
if (ids == ''){
alert("请至少选择一行!");
return false;
}
var url= $(this).attr("value") + '?id=' + ids;
index = $.layer({
type: 2,
title: 'JumpServer - 批量修改主机',
maxmin: true,
shift: 'top',
border: [2, 0.3, '#1AB394'],
shade: [0.5, '#000000'],
shadeClose: true,
area : ['800px' , '600px'],
iframe: {src: url},
close: function(){
location.replace(location.href);
}
});
});
$('#asset_del').click(function () {
var asset_id_all = getIDall();
console.log(asset_id_all);
if (asset_id_all == ''){
alert("请至少选择一行!");
return false;
}
if (confirm("确定删除")) {
$.ajax({
type: "post",
data: {asset_id_all: asset_id_all},
url: "/jasset/asset_del/?arg=batch",
success: function () {
parent.location.reload();
}
});
}
});
</script>
{% endblock %}

View File

@ -52,6 +52,8 @@
{% endifequal %} {% endifequal %}
<th class="text-center"> 机房名 </th> <th class="text-center"> 机房名 </th>
<th class="text-center"> 主机数量 </th> <th class="text-center"> 主机数量 </th>
<th class="text-center"> 联系人 </th>
<th class="text-center"> 电话 </th>
<th class="text-center"> 备注 </th> <th class="text-center"> 备注 </th>
<th class="text-center"> 操作 </th> <th class="text-center"> 操作 </th>
</tr> </tr>
@ -59,14 +61,16 @@
<tbody> <tbody>
{% for post in contacts.object_list %} {% for post in contacts.object_list %}
<tr class="gradeX"> <tr class="gradeX">
<td class="text-center" name="j_id" value="{{ post.id }}" data-editable='false'><input name="id" value="{{ post.id }}" type="checkbox" class="i-checks"></td> <td class="text-center" name="j_id" value="{{ post.id }}" data-editable='false'><input name="id" value="{{ post.id }}" type="checkbox" class="i-checks"></td>
<td class="text-center"> {{ post.name }} </td> <td class="text-center"> {{ post.name }} </td>
<td class="text-center"> <a href="/jasset/idc_detail/?id={{ post.id }}">{{ post.asset_set.count }}</a> </td> <td class="text-center"> <a href="/jasset/asset_list/?idc_id={{ post.id }}">{{ post.asset_set.count }}</a> </td>
<td class="text-center"> {{ post.linkman }} </td>
<td class="text-center"> {{ post.phone }} </td>
<td class="text-center"> {{ post.comment }} </td> <td class="text-center"> {{ post.comment }} </td>
<td class="text-center"> <td class="text-center">
<a href="/jasset/idc_detail/?id={{ post.id }}" class="iframe btn btn-xs btn-primary">详情</a> <a href="/jasset/asset_list/?idc_id={{ post.id }}" class="iframe btn btn-xs btn-primary">详情</a>
<a href="/jasset/idc_edit/?id={{ post.id }}" class="btn btn-xs btn-info">编辑</a> <a href="/jasset/idc_edit/?id={{ post.id }}" class="btn btn-xs btn-info">编辑</a>
<a href="/jasset/idc_del/?id={{ post.id }}" class="btn btn-xs btn-danger">删除</a> <a href="/jasset/idc_del/?id={{ post.id }}" class="btn btn-xs btn-danger idc_del">删除</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
@ -75,7 +79,7 @@
<div class="row"> <div class="row">
<div class="col-sm-6"> <div class="col-sm-6">
{% ifequal session_role_id 2 %} {% ifequal session_role_id 2 %}
<input type="button" id="del_button" class="btn btn-danger btn-sm" name="del_button" value="删除" onclick="del('contents_form')" /> <input type="button" id="del_check" class="btn btn-danger btn-sm" name="del_button" value="删除"/>
<!--<input type="button" id="alter_button" class="btn btn-warning btn-sm" name="alter_button" value="修改" onclick="alter('contents_form')" />--> <!--<input type="button" id="alter_button" class="btn btn-warning btn-sm" name="alter_button" value="修改" onclick="alter('contents_form')" />-->
{% endifequal %} {% endifequal %}
</div> </div>
@ -89,27 +93,37 @@
</div> </div>
<script> <script>
function del(form) { $(document).ready(function(){
var checkboxes = document.getElementById(form); $('.idc_del').click(function(){
var id_list = {}; var row = $(this).closest('tr');
var j = 0; if (confirm('确定删除?')) {
for (var i = 0; i < checkboxes.elements.length; i++) { $.get(
if (checkboxes.elements[i].type == "checkbox" && checkboxes.elements[i].checked == true && checkboxes.elements[i].value != "checkall") { $(this).attr('value'),
id_list[j] = checkboxes.elements[i].value; {},
j++; function (data) {
} row.remove();
} }
if (confirm("确定删除")) { )
$.ajax({
type: "POST",
url: "/jasset/idc_del/?id=multi",
data: {"id_list": id_list, "len_list": j},
success: function (data) {
window.open("/jasset/idc_list/", "_self");
} }
}); });
}
} $('#del_check').click(function(){
var check_array = [];
if (confirm('确定删除?')){
$('tr.gradeX input:checked').each(function(){
check_array.push($(this).attr('value'))
});
$.get(
'/jasset/idc_del/',
{id: check_array.join(',')},
function(data){
$('tr.gradeX input:checked').closest('tr').remove();
}
)
}
})
});
</script> </script>
{% endblock %} {% endblock %}

View File

@ -118,6 +118,37 @@
{% endblock %} {% endblock %}
{% block self_footer_js %} {% block self_footer_js %}
<script> <script>
$('#ruleForm').submit(function() {
var result = {}
var data = $(this).serializeArray();
$.each(data, function(i, field){
result[field.name] = field.value;
});
if (result['user'] || result['usergroup'] || result['asset'] || result['assetgroup'] || result['rulename'] || result['role']) {
if (result['rulename'] === '') {
alert("请添加授权名称")
return false
}
if (! result['user'] && ! result['usergroup']) {
alert("用户和用户组必选1个")
return false
}
if (! result['asset'] && ! result['assetgroup']) {
alert("资产和资产组必选1个")
return false
}
if (! result['role']) {
alert("请填写角色")
return false
}
return true
} else {
alert("请填必选项")
return false;
}
});
$(document).ready(function(){ $(document).ready(function(){
$("input.role").click(function(){ $("input.role").click(function(){
if($("input.role[value=GA]").is( ":checked" )){ if($("input.role[value=GA]").is( ":checked" )){

View File

@ -20,7 +20,7 @@
<ul class="nav nav-second-level"> <ul class="nav nav-second-level">
<li class="group_add"><a href="/jasset/group_add/">添加资产组</a></li> <li class="group_add"><a href="/jasset/group_add/">添加资产组</a></li>
<li class="group_list group_detail group_edit"><a href="/jasset/group_list/">查看资产组</a></li> <li class="group_list group_detail group_edit"><a href="/jasset/group_list/">查看资产组</a></li>
<li class="asset_add asset_add_multi"><a href="/jasset/asset_add/">添加资产</a></li> <li class="asset_add asset_add_batch"><a href="/jasset/asset_add/">添加资产</a></li>
<li class="asset_list asset_detail asset_edit"><a href="/jasset/asset_list/">查看资产<span class="label label-info pull-right">{{ host_active_num }}/{{ host_total_num}}</span></a></li> <li class="asset_list asset_detail asset_edit"><a href="/jasset/asset_list/">查看资产<span class="label label-info pull-right">{{ host_active_num }}/{{ host_total_num}}</span></a></li>
<li class="idc_add"><a href="/jasset/idc_add/">添加机房</a></li> <li class="idc_add"><a href="/jasset/idc_add/">添加机房</a></li>
<li class="idc_list idc_detail idc_edit"><a href="/jasset/idc_list/">查看机房</a></li> <li class="idc_list idc_detail idc_edit"><a href="/jasset/idc_list/">查看机房</a></li>
@ -29,11 +29,11 @@
<li id="jperm"> <li id="jperm">
<a href="#"><i class="fa fa-edit"></i> <span class="nav-label">授权管理</span><span class="fa arrow"></span></a> <a href="#"><i class="fa fa-edit"></i> <span class="nav-label">授权管理</span><span class="fa arrow"></span></a>
<ul class="nav nav-second-level"> <ul class="nav nav-second-level">
<li class="dept_perm_list dept_perm_edit"> <li class="rule ">
<a href="/jperm/rule/">授权规则</a> <a href="/jperm/rule/">授权规则</a>
</li> </li>
<li class="sudo_list sudo_edit sudo_add cmd_list cmd_edit cmd_add sudo_detail"> <li class="role">
<a href="/jperm/role/">系统角色</a> <a href="/jperm/role/">系统角色</a>
</li> </li>
<li class="apply_show online"><a href="/jperm/apply_show/online/">权限审批</a></li> <li class="apply_show online"><a href="/jperm/apply_show/online/">权限审批</a></li>