Commit a0684985 authored by yumaojun's avatar yumaojun

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

# Conflicts:
#	jperm/ansible_api.py
parents bf98aa54 d337b929
This diff is collapsed.
#coding:utf-8
import django
import os
import sys
import random
import datetime
sys.path.append('../')
os.environ['DJANGO_SETTINGS_MODULE'] = 'jumpserver.settings'
#django.setup()
from juser.views import db_add_user, md5_crypt, CRYPTOR, db_add_group
from jasset.models import Asset, IDC, BisGroup
from juser.models import UserGroup, DEPT, User
from jperm.models import CmdGroup
from jlog.models import Log
def install():
IDC.objects.create(name='ALL', comment='ALL')
IDC.objects.create(name='默认', comment='默认')
DEPT.objects.create(name="默认", comment="默认部门")
DEPT.objects.create(name="超管部", comment="超级管理员部门")
dept = DEPT.objects.get(name='超管部')
dept2 = DEPT.objects.get(name='默认')
UserGroup.objects.create(name='ALL', dept=dept, comment='ALL')
UserGroup.objects.create(name='默认', dept=dept, comment='默认')
BisGroup.objects.create(name='ALL', dept=dept, comment='ALL')
BisGroup.objects.create(name='默认', dept=dept, comment='默认')
User(id=5000, username="admin", password=md5_crypt('admin'),
name='admin', email='admin@jumpserver.org', role='SU', is_active=True, dept=dept).save()
User(id=5001, username="group_admin", password=md5_crypt('group_admin'),
name='group_admin', email='group_admin@jumpserver.org', role='DA', is_active=True, dept=dept2).save()
def test_add_idc():
for i in range(1, 20):
name = 'IDC' + str(i)
IDC.objects.create(name=name, comment='')
print 'Add: %s' % name
def test_add_dept():
for i in range(1, 100):
name = 'DEPT' + str(i)
print "Add: %s" % name
DEPT.objects.create(name=name, comment=name)
def test_add_group():
dept_all = DEPT.objects.all()
for i in range(1, 100):
name = 'UserGroup' + str(i)
UserGroup.objects.create(name=name, dept=random.choice(dept_all), comment=name)
print 'Add: %s' % name
def test_add_cmd_group():
for i in range(1, 20):
name = 'CMD' + str(i)
cmd = '/sbin/ping%s, /sbin/ifconfig/' % str(i)
CmdGroup.objects.create(name=name, cmd=cmd, comment=name)
print 'Add: %s' % name
def test_add_user():
for i in range(1, 500):
username = "test" + str(i)
dept_all = DEPT.objects.all()
group_all = UserGroup.objects.all()
group_all_id = [group.id for group in group_all]
db_add_user(username=username,
password=md5_crypt(username),
dept=random.choice(dept_all),
name=username, email='%s@jumpserver.org' % username,
groups=[random.choice(group_all_id) for i in range(1, 4)], role='CU',
ssh_key_pwd=CRYPTOR.encrypt(username),
ldap_pwd=CRYPTOR.encrypt(username),
is_active=True,
date_joined=datetime.datetime.now())
print "Add: %s" % username
def test_add_asset_group():
dept = DEPT.objects.get(name='默认')
for i in range(1, 20):
name = 'AssetGroup' + str(i)
group = BisGroup(name=name, dept=dept, comment=name)
group.save()
print 'Add: %s' % name
def test_add_asset():
idc_all = IDC.objects.all()
test_idc = random.choice(idc_all)
bis_group_all = BisGroup.objects.all()
dept_all = DEPT.objects.all()
for i in range(1, 500):
ip = '192.168.5.' + str(i)
asset = Asset(ip=ip, port=22, login_type='L', idc=test_idc, is_active=True, comment='test')
asset.save()
asset.bis_group = [random.choice(bis_group_all) for i in range(2)]
asset.dept = [random.choice(dept_all) for i in range(2)]
print "Add: %s" % ip
def test_add_log():
li_date = []
today = datetime.date.today()
oneday = datetime.timedelta(days=1)
for i in range(0, 7):
today = today-oneday
li_date.append(today)
user_list = ['马云', '马化腾', '丁磊', '周鸿祎', '雷军', '柳传志', '陈天桥', '李彦宏', '李开复', '罗永浩']
for i in range(1, 1000):
user = random.choice(user_list)
ip = random.randint(1, 20)
start_time = random.choice(li_date)
end_time = datetime.datetime.now()
log_path = '/var/log/jumpserver/test.log'
host = '192.168.1.' + str(ip)
Log.objects.create(user=user, host=host, remote_ip='8.8.8.8', dept_name='运维部', log_path=log_path, pid=168, start_time=start_time,
is_finished=1, log_finished=1, end_time=end_time)
if __name__ == '__main__':
# install()
# test_add_dept()
# test_add_group()
# test_add_user()
# test_add_idc()
# test_add_asset_group()
test_add_asset()
# test_add_log()
......@@ -7,22 +7,3 @@
email: admin@jumpserver.org
role: SU
is_active: 1
- model: juser.user
pk: 5001
fields:
username: group_admin
name: group_admin
password: pbkdf2_sha256$20000$ttObUWd15q10$NJoyZf2OZz9oiw2g4j2TkTh9zGgyVDRFdUkhn8X0nB0=
email: group_admin@jumpserver.org
role: GA
is_active: 1
- model: juser.usergroup
pk: 1
fields:
name: ALL
comment: ALL
- model: juser.usergroup
pk: 2
fields:
name: 默认
comment: 默认
#coding:utf-8
import django
import os
import sys
import random
import datetime
sys.path.append('../')
os.environ['DJANGO_SETTINGS_MODULE'] = 'jumpserver.settings'
#django.setup()
from juser.views import db_add_user, md5_crypt, CRYPTOR, db_add_group
from jasset.models import Asset, IDC, BisGroup
from juser.models import UserGroup, DEPT, User
from jasset.views import jasset_group_add
from jperm.models import CmdGroup
from jlog.models import Log
def install():
IDC.objects.create(name='ALL', comment='ALL')
IDC.objects.create(name='默认', comment='默认')
DEPT.objects.create(name="默认", comment="默认部门")
DEPT.objects.create(name="超管部", comment="超级管理员部门")
dept = DEPT.objects.get(name='超管部')
dept2 = DEPT.objects.get(name='默认')
UserGroup.objects.create(name='ALL', dept=dept, comment='ALL')
UserGroup.objects.create(name='默认', dept=dept, comment='默认')
BisGroup.objects.create(name='ALL', dept=dept, comment='ALL')
BisGroup.objects.create(name='默认', dept=dept, comment='默认')
User(id=5000, username="admin", password=md5_crypt('admin'),
name='admin', email='admin@jumpserver.org', role='SU', is_active=True, dept=dept).save()
User(id=5001, username="group_admin", password=md5_crypt('group_admin'),
name='group_admin', email='group_admin@jumpserver.org', role='DA', is_active=True, dept=dept2).save()
def test_add_idc():
for i in range(1, 20):
name = 'IDC' + str(i)
IDC.objects.create(name=name, comment='')
print 'Add: %s' % name
def test_add_dept():
for i in range(1, 100):
name = 'DEPT' + str(i)
print "Add: %s" % name
DEPT.objects.create(name=name, comment=name)
def test_add_group():
dept_all = DEPT.objects.all()
for i in range(1, 100):
name = 'UserGroup' + str(i)
UserGroup.objects.create(name=name, dept=random.choice(dept_all), comment=name)
print 'Add: %s' % name
def test_add_cmd_group():
for i in range(1, 20):
name = 'CMD' + str(i)
cmd = '/sbin/ping%s, /sbin/ifconfig/' % str(i)
CmdGroup.objects.create(name=name, cmd=cmd, comment=name)
print 'Add: %s' % name
def test_add_user():
for i in range(1, 500):
username = "test" + str(i)
dept_all = DEPT.objects.all()
group_all = UserGroup.objects.all()
group_all_id = [group.id for group in group_all]
db_add_user(username=username,
password=md5_crypt(username),
dept=random.choice(dept_all),
name=username, email='%s@jumpserver.org' % username,
groups=[random.choice(group_all_id) for i in range(1, 4)], role='CU',
ssh_key_pwd=CRYPTOR.encrypt(username),
ldap_pwd=CRYPTOR.encrypt(username),
is_active=True,
date_joined=datetime.datetime.now())
print "Add: %s" % username
def test_add_asset_group():
dept = DEPT.objects.get(name='默认')
for i in range(1, 20):
name = 'AssetGroup' + str(i)
group = BisGroup(name=name, dept=dept, comment=name)
group.save()
print 'Add: %s' % name
def test_add_asset():
idc_all = IDC.objects.all()
test_idc = random.choice(idc_all)
bis_group_all = BisGroup.objects.all()
dept_all = DEPT.objects.all()
for i in range(1, 500):
ip = '192.168.1.' + str(i)
asset = Asset(ip=ip, port=22, login_type='L', idc=test_idc, is_active=True, comment='test')
asset.save()
asset.bis_group = [random.choice(bis_group_all) for i in range(2)]
asset.dept = [random.choice(dept_all) for i in range(2)]
print "Add: %s" % ip
def test_add_log():
li_date = []
today = datetime.date.today()
oneday = datetime.timedelta(days=1)
for i in range(0, 7):
today = today-oneday
li_date.append(today)
user_list = ['马云', '马化腾', '丁磊', '周鸿祎', '雷军', '柳传志', '陈天桥', '李彦宏', '李开复', '罗永浩']
for i in range(1, 1000):
user = random.choice(user_list)
ip = random.randint(1, 20)
start_time = random.choice(li_date)
end_time = datetime.datetime.now()
log_path = '/var/log/jumpserver/test.log'
host = '192.168.1.' + str(ip)
Log.objects.create(user=user, host=host, log_path=log_path, pid=168, start_time=start_time,
is_finished=1, log_finished=1, end_time=end_time)
if __name__ == '__main__':
install()
sphinx-me==0.3
#sphinx-me==0.3
django==1.6
pycrypto==2.6.1
paramiko==1.15.2
paramiko==1.16.0
ecdsa==0.13
MySQL-python==1.2.5
django-uuidfield==0.5.0
psutil==2.2.1
#django-uuidfield==0.5.0
psutil==3.3.0
xlsxwriter==0.7.7
xlrd==0.9.4
django-bootstrap-form
tornado
ansible
pyinotify
passlib
argparse
\ No newline at end of file
django-bootstrap-form==3.2
tornado==4.3
ansible==1.9.4
pyinotify==0.9.6
passlib==1.6.5
argparse==1.4.0
django_crontab==0.6.0
\ No newline at end of file
# coding: utf-8
from __future__ import division
import xlrd
import xlsxwriter
from django.db.models import AutoField
......@@ -6,6 +7,7 @@ from jumpserver.api import *
from jasset.models import ASSET_STATUS, ASSET_TYPE, ASSET_ENV, IDC, AssetRecord
from jperm.ansible_api import MyRunner
from jperm.perm_api import gen_resource
from jumpserver.templatetags.mytags import get_disk_info
def group_add_asset(group, asset_id=None, asset_ip=None):
......@@ -75,83 +77,6 @@ def db_asset_update(**kwargs):
Asset.objects.filter(id=asset_id).update(**kwargs)
#
#
# def batch_host_edit(host_alter_dic, j_user='', j_password=''):
# """ 批量修改主机函数 """
# j_id, j_ip, j_idc, j_port, j_type, j_group, j_dept, j_active, j_comment = host_alter_dic
# groups, depts = [], []
# is_active = {u'是': '1', u'否': '2'}
# login_types = {'LDAP': 'L', 'MAP': 'M'}
# a = Asset.objects.get(id=j_id)
# if '...' in j_group[0].split():
# groups = a.bis_group.all()
# else:
# for group in j_group[0].split():
# c = BisGroup.objects.get(name=group.strip())
# groups.append(c)
#
# if '...' in j_dept[0].split():
# depts = a.dept.all()
# else:
# for d in j_dept[0].split():
# p = DEPT.objects.get(name=d.strip())
# depts.append(p)
#
# j_type = login_types[j_type]
# j_idc = IDC.objects.get(name=j_idc)
# if j_type == 'M':
# if a.password != j_password:
# j_password = cryptor.decrypt(j_password)
# a.ip = j_ip
# a.port = j_port
# a.login_type = j_type
# a.idc = j_idc
# a.is_active = j_active
# a.comment = j_comment
# a.username = j_user
# a.password = j_password
# else:
# a.ip = j_ip
# a.port = j_port
# a.idc = j_idc
# a.login_type = j_type
# a.is_active = is_active[j_active]
# a.comment = j_comment
# a.save()
# a.bis_group = groups
# a.dept = depts
# a.save()
#
#
# def db_host_delete(request, host_id):
# """ 删除主机操作 """
# if is_group_admin(request) and not validate(request, asset=[host_id]):
# return httperror(request, '删除失败, 您无权删除!')
#
# asset = Asset.objects.filter(id=host_id)
# if asset:
# asset.delete()
# else:
# return httperror(request, '删除失败, 没有此主机!')
#
#
# def db_idc_delete(request, idc_id):
# """ 删除IDC操作 """
# if idc_id == 1:
# return httperror(request, '删除失败, 默认IDC不能删除!')
#
# default_idc = IDC.objects.get(id=1)
#
# idc = IDC.objects.filter(id=idc_id)
# if idc:
# idc_class = idc[0]
# idc_class.asset_set.update(idc=default_idc)
# idc.delete()
# else:
# return httperror(request, '删除失败, 没有这个IDC!')
def sort_ip_list(ip_list):
""" ip地址排序 """
ip_list.sort(key=lambda s: map(int, s.split('.')))
......@@ -232,7 +157,7 @@ def db_asset_alert(asset, username, alert_dic):
for group_id in value[1]:
group_name = AssetGroup.objects.get(id=int(group_id)).name
new.append(group_name)
if old == new:
if sorted(old) == sorted(new):
continue
else:
alert_info = [field_name, ','.join(old), ','.join(new)]
......@@ -274,28 +199,32 @@ def write_excel(asset_all):
workbook = xlsxwriter.Workbook('static/files/excels/%s' % file_name)
worksheet = workbook.add_worksheet(u'CMDB数据')
worksheet.set_first_sheet()
worksheet.set_column('A:Z', 14)
title = [u'主机名', u'IP', u'IDC', u'MAC', u'远控IP', u'CPU', u'内存', u'硬盘', u'操作系统', u'机柜位置',
u'所属主机组', u'机器状态', u'备注']
worksheet.set_column('A:E', 15)
worksheet.set_column('F:F', 40)
worksheet.set_column('G:Z', 15)
title = [u'主机名', u'IP', u'IDC', u'所属主机组', u'操作系统', u'CPU', u'内存(G)', u'硬盘(G)',
u'机柜位置', u'MAC', u'远控IP', u'机器状态', u'备注']
for asset in asset_all:
group_list = []
for p in asset.group.all():
group_list.append(p.name)
disk = get_disk_info(asset.disk)
group_all = '/'.join(group_list)
status = asset.get_status_display()
idc_name = asset.idc.name if asset.idc else u''
system_type = asset.system_type if asset.idc else u''
system_version = asset.system_version if asset.idc else u''
system_type = asset.system_type if asset.system_type else u''
system_version = asset.system_version if asset.system_version else u''
system_os = unicode(system_type) + unicode(system_version)
alter_dic = [asset.hostname, asset.ip, idc_name, asset.mac, asset.remote_ip, asset.cpu, asset.memory,
asset.disk, system_os, asset.cabinet, group_all, status,
asset.comment]
alter_dic = [asset.hostname, asset.ip, idc_name, group_all, system_os, asset.cpu, asset.memory,
disk, asset.cabinet, asset.mac, asset.remote_ip, status, asset.comment]
data.append(alter_dic)
format = workbook.add_format()
format.set_border(1)
format.set_align('center')
format.set_align('vcenter')
format.set_text_wrap()
format_title = workbook.add_format()
format_title.set_border(1)
......@@ -384,12 +313,21 @@ def excel_to_db(excel_file):
def get_ansible_asset_info(asset_ip, setup_info):
disk_all = setup_info.get("ansible_devices")
print asset_ip
disk_need = {}
disk_all = setup_info.get("ansible_devices")
if disk_all:
for disk_name, disk_info in disk_all.iteritems():
print disk_name, disk_info
if disk_name.startswith('sd') or disk_name.startswith('hd') or disk_name.startswith('vd'):
disk_need[disk_name] = disk_info.get("size")
disk_size = disk_info.get("size", '')
if 'M' in disk_size:
disk_format = round(float(disk_size[:-2]) / 1000, 0)
elif 'T' in disk_size:
disk_format = round(float(disk_size[:-2]) * 1000, 0)
else:
disk_format = float(disk_size[:-2])
disk_need[disk_name] = disk_format
all_ip = setup_info.get("ansible_all_ipv4_addresses")
other_ip_list = all_ip.remove(asset_ip) if asset_ip in all_ip else []
other_ip = ','.join(other_ip_list) if other_ip_list else ''
......@@ -401,13 +339,17 @@ def get_ansible_asset_info(asset_ip, setup_info):
cpu_cores = setup_info.get("ansible_processor_count")
cpu = cpu_type + ' * ' + unicode(cpu_cores)
memory = setup_info.get("ansible_memtotal_mb")
try:
memory_format = int(round((int(memory) / 1000), 0))
except Exception:
memory_format = memory
disk = disk_need
system_type = setup_info.get("ansible_distribution")
system_version = setup_info.get("ansible_distribution_version")
system_arch = setup_info.get("ansible_architecture")
# asset_type = setup_info.get("ansible_system")
sn = setup_info.get("ansible_product_serial")
asset_info = [other_ip, mac, cpu, memory, disk, sn, system_type, system_version, brand]
asset_info = [other_ip, mac, cpu, memory_format, disk, sn, system_type, system_version, brand, system_arch]
return asset_info
......@@ -415,6 +357,7 @@ def asset_ansible_update(obj_list, name=''):
resource = gen_resource(obj_list)
ansible_instance = MyRunner(resource)
ansible_asset_info = ansible_instance.run(module_name='setup', pattern='*')
logger.debug('获取硬件信息: %s' % ansible_asset_info)
for asset in obj_list:
try:
setup_info = ansible_asset_info['contacted'][asset.hostname]['ansible_facts']
......@@ -422,7 +365,7 @@ def asset_ansible_update(obj_list, name=''):
continue
else:
asset_info = get_ansible_asset_info(asset.ip, setup_info)
other_ip, mac, cpu, memory, disk, sn, system_type, system_version, brand = asset_info
other_ip, mac, cpu, memory, disk, sn, system_type, system_version, brand, system_arch = asset_info
asset_dic = {"other_ip": other_ip,
"mac": mac,
"cpu": cpu,
......@@ -431,6 +374,7 @@ def asset_ansible_update(obj_list, name=''):
"sn": sn,
"system_type": system_type,
"system_version": system_version,
"system_arch": system_arch,
"brand": brand
}
......
......@@ -12,7 +12,8 @@ class AssetForm(forms.ModelForm):
fields = [
"ip", "other_ip", "hostname", "port", "group", "username", "password", "use_default_auth",
"idc", "mac", "remote_ip", "brand", "cpu", "memory", "disk", "system_type", "system_version",
"cabinet", "position", "number", "status", "asset_type", "env", "sn", "is_active", "comment"
"cabinet", "position", "number", "status", "asset_type", "env", "sn", "is_active", "comment",
"system_arch"
]
......
......@@ -78,6 +78,7 @@ class Asset(models.Model):
disk = models.CharField(max_length=128, blank=True, null=True, verbose_name=u'硬盘')
system_type = models.CharField(max_length=32, blank=True, null=True, verbose_name=u"系统类型")
system_version = models.CharField(max_length=8, blank=True, null=True, verbose_name=u"系统版本号")
system_arch = models.CharField(max_length=16, blank=True, null=True, verbose_name=u"系统平台")
cabinet = models.CharField(max_length=32, blank=True, null=True, verbose_name=u'机柜号')
position = models.IntegerField(blank=True, null=True, verbose_name=u'机器位置')
number = models.CharField(max_length=32, blank=True, null=True, verbose_name=u'资产编号')
......
......@@ -6,8 +6,7 @@ from jumpserver.api import *
from jumpserver.models import Setting
from jasset.forms import AssetForm, IdcForm
from jasset.models import Asset, IDC, AssetGroup, ASSET_TYPE, ASSET_STATUS
from jperm.ansible_api import Tasks, MyRunner
from jperm.perm_api import gen_resource
from jperm.perm_api import get_group_asset_perm, get_group_user_perm
@require_role('admin')
......@@ -96,7 +95,9 @@ def group_list(request):
header_title, path1, path2 = u'查看资产组', u'资产管理', u'查看资产组'
keyword = request.GET.get('keyword', '')
asset_group_list = AssetGroup.objects.all()
group_id = request.GET.get('id')
if group_id:
asset_group_list = asset_group_list.filter(id=group_id)
if keyword:
asset_group_list = asset_group_list.filter(Q(name__contains=keyword) | Q(comment__contains=keyword))
......@@ -256,11 +257,13 @@ def asset_list(request):
asset list view
"""
header_title, path1, path2 = u'查看资产', u'资产管理', u'查看资产'
username = request.user.username
user_perm = request.session['role_id']
idc_all = IDC.objects.filter()
asset_group_all = AssetGroup.objects.all()
asset_types = ASSET_TYPE
asset_status = ASSET_STATUS
asset_id = request.GET.get('id')
idc_name = request.GET.get('idc', '')
group_name = request.GET.get('group', '')
asset_type = request.GET.get('asset_type', '')
......@@ -279,12 +282,19 @@ def asset_list(request):
if idc:
asset_find = Asset.objects.filter(idc=idc)
else:
if user_perm != 0:
asset_find = Asset.objects.all()
else:
user = get_object(User, username=username)
asset_perm = get_group_user_perm(user) if user else {'asset': ''}
asset_find = asset_perm['asset'].keys()
asset_group_all = list(asset_perm['asset_group'])
if idc_name:
asset_find = asset_find.filter(idc__name__contains=idc_name)
if group_name:
print asset_find, type(asset_find)
asset_find = asset_find.filter(group__name__contains=group_name)
if asset_type:
......@@ -293,6 +303,9 @@ def asset_list(request):
if status:
asset_find = asset_find.filter(status__contains=status)
if asset_id:
asset_find = asset_find.filter(id=asset_id)
if keyword:
asset_find = asset_find.filter(
Q(hostname__contains=keyword) |
......@@ -318,7 +331,10 @@ def asset_list(request):
smg = u'excel文件已生成,请点击下载!'
return my_render('jasset/asset_excel_download.html', locals(), request)
assets_list, p, assets, page_range, current_page, show_first, show_end = pages(asset_find, request)
if user_perm != 0:
return my_render('jasset/asset_list.html', locals(), request)
else:
return my_render('jasset/asset_cu_list.html', locals(), request)
@require_role('admin')
......@@ -410,6 +426,18 @@ def asset_detail(request):
header_title, path1, path2 = u'主机详细信息', u'资产管理', u'主机详情'
asset_id = request.GET.get('id', '')
asset = get_object(Asset, id=asset_id)
perm_info = get_group_asset_perm(asset)
log = Log.objects.filter(host=asset.hostname)
if perm_info:
user_perm = []
for perm, value in perm_info.items():
if perm == 'user':
for user, role_dic in value.items():
user_perm.append([user, role_dic.get('role', '')])
elif perm == 'user_group' or perm == 'rule':
user_group_perm = value
print perm_info
asset_record = AssetRecord.objects.filter(asset=asset).order_by('-alert_time')
return my_render('jasset/asset_detail.html', locals(), request)
......
......@@ -3,7 +3,7 @@ from django.db import models
class Log(models.Model):
user = models.CharField(max_length=20, null=True)
host = models.CharField(max_length=20, null=True)
host = models.CharField(max_length=200, null=True)
remote_ip = models.CharField(max_length=100)
login_type = models.CharField(max_length=100)
log_path = models.CharField(max_length=100)
......@@ -24,5 +24,26 @@ class Alert(models.Model):
class TtyLog(models.Model):
log = models.ForeignKey(Log)
datetime = models.DateTimeField()
datetime = models.DateTimeField(auto_now=True)
cmd = models.CharField(max_length=200)
class ExecLog(models.Model):
user = models.CharField(max_length=100)
host = models.TextField()
cmd = models.TextField()
remote_ip = models.CharField(max_length=100)
result = models.TextField(default='')
datetime = models.DateTimeField(auto_now=True)
class FileLog(models.Model):
user = models.CharField(max_length=100)
host = models.TextField()
filename = models.TextField()
type = models.CharField(max_length=20)
remote_ip = models.CharField(max_length=100)
result = models.TextField(default='')
datetime = models.DateTimeField(auto_now=True)
......@@ -3,11 +3,11 @@ from django.conf.urls import patterns, include, url
from jlog.views import *
urlpatterns = patterns('',
url(r'^$', log_list),
url(r'^log_list/(\w+)/$', log_list),
url(r'^history/$', log_history),
url(r'^log_kill/', log_kill),
url(r'^record/$', log_record),
url(r'^web_terminal/$', web_terminal),
url(r'^get_role_name/$', get_role_name),
(r'^$', log_list),
(r'^log_list/(\w+)/$', log_list),
(r'^log_detail/(\w+)/$', log_detail),
(r'^history/$', log_history),
(r'^log_kill/', log_kill),
(r'^record/$', log_record),
(r'^web_terminal/$', web_terminal),
)
\ No newline at end of file
......@@ -8,7 +8,7 @@ from jperm.perm_api import user_have_perm
from django.http import HttpResponseNotFound
from jlog.log_api import renderTemplate
from models import Log
from jlog.models import Log, ExecLog, FileLog
from jumpserver.settings import WEB_SOCKET_HOST
......@@ -21,9 +21,24 @@ def log_list(request, offset):
username_list = request.GET.getlist('username', [])
host_list = request.GET.getlist('host', [])
cmd = request.GET.get('cmd', '')
print date_seven_day, date_now_str
if offset == 'online':
keyword = request.GET.get('keyword', '')
posts = Log.objects.filter(is_finished=False).order_by('-start_time')
if keyword:
posts = posts.filter(Q(user__icontains=keyword) | Q(host__icontains=keyword) |
Q(login_type_icontains=keyword))
elif offset == 'exec':
posts = ExecLog.objects.all().order_by('-id')
keyword = request.GET.get('keyword', '')
if keyword:
posts = posts.filter(Q(user__icontains=keyword)|Q(host__icontains=keyword)|Q(cmd__icontains=keyword))
elif offset == 'file':
posts = FileLog.objects.all().order_by('-id')
keyword = request.GET.get('keyword', '')
if keyword:
posts = posts.filter(Q(user__icontains=keyword)|Q(host__icontains=keyword)|Q(filename__icontains=keyword))
else:
posts = Log.objects.filter(is_finished=True).order_by('-start_time')
username_all = set([log.user for log in Log.objects.all()])
......@@ -57,6 +72,11 @@ def log_list(request, offset):
return render_to_response('jlog/log_%s.html' % offset, locals(), context_instance=RequestContext(request))
@require_role('admin')
def log_detail(request):
return my_render('jlog/exec_detail.html', locals(), request)
@require_role('admin')
def log_kill(request):
""" 杀掉connect进程 """
......@@ -107,16 +127,6 @@ def log_record(request):
return HttpResponse('无日志记录!')
@require_role('user')
def get_role_name(request):
asset_id = request.GET.get('id', 9999)
asset = get_object(Asset, id=asset_id)
if asset:
role = user_have_perm(request.user, asset=asset)
return HttpResponse(','.join([i.name for i in role]))
return HttpResponse('error')
@require_role('user')
def web_terminal(request):
asset_id = request.GET.get('id')
......@@ -124,3 +134,21 @@ def web_terminal(request):
web_terminal_uri = 'ws://%s/terminal?id=%s&role=%s' % (WEB_SOCKET_HOST, asset_id, role_name)
return render_to_response('jlog/web_terminal.html', locals())
@require_role('admin')
def log_detail(request, offset):
log_id = request.GET.get('id')
if offset == 'exec':
log = get_object(ExecLog, id=log_id)
assets_hostname = log.host.split(' ')
result = eval(str(log.result))
return my_render('jlog/exec_detail.html', locals(), request)
elif offset == 'file':
log = get_object(FileLog, id=log_id)
assets_hostname = log.host.split(' ')
file_list = log.filename.split(' ')
try:
result = eval(str(log.result))
except (SyntaxError, NameError):
result = {}
return my_render('jlog/file_detail.html', locals(), request)
This diff is collapsed.
......@@ -55,6 +55,6 @@ class PermPush(models.Model):
is_public_key = models.BooleanField(default=False)
is_password = models.BooleanField(default=False)
success = models.BooleanField(default=False)
result = models.TextField()
result = models.TextField(default='')
date_added = models.DateTimeField(auto_now=True)
......@@ -43,13 +43,16 @@ def get_group_user_perm(ob):
asset_groups = rule.asset_group.all()
assets = rule.asset.all()
perm_roles = rule.role.all()
group_assets = []
for asset_group in asset_groups:
group_assets.extend(asset_group.asset_set.all())
# 获取一个规则授权的角色和对应主机
for role in perm_roles:
if perm_role.get('role'):
perm_role[role]['asset'] = perm_role[role].get('asset', set()).union(set(assets))
if perm_role.get(role):
perm_role[role]['asset'] = perm_role[role].get('asset', set()).union(set(assets).union(set(group_assets)))
perm_role[role]['asset_group'] = perm_role[role].get('asset_group', set()).union(set(asset_groups))
else:
perm_role[role] = {'asset': set(assets), 'asset_group': set(asset_groups)}
perm_role[role] = {'asset': set(assets).union(set(group_assets)), 'asset_group': set(asset_groups)}
# 获取一个规则用户授权的资产
for asset in assets:
......@@ -161,12 +164,14 @@ def gen_resource(ob, perm=None):
user = ob.get('user')
if not perm:
perm = get_group_user_perm(user)
roles = perm.get('role', {}).keys()
if role:
roles = perm.get('role', {}).keys() # 获取用户所有授权角色
if role not in roles:
return {}
role_assets_all = perm.get('role').get(role).get('asset')
assets = set(role_assets_all) & set(asset_r)
role_assets_all = perm.get('role').get(role).get('asset') # 获取用户该角色所有授权主机
assets = set(role_assets_all) & set(asset_r) # 获取用户提交中合法的主机
for asset in assets:
asset_info = get_asset_info(asset)
......@@ -178,6 +183,23 @@ def gen_resource(ob, perm=None):
'ssh_key': get_role_key(user, role)
}
res.append(info)
else:
for asset, asset_info in perm.get('asset').items():
if asset not in asset_r:
continue
asset_info = get_asset_info(asset)
try:
role = sorted(list(perm.get('asset').get(asset).get('role')))[0]
except IndexError:
continue
info = {'hostname': asset.hostname,
'ip': asset.ip,
'port': asset_info.get('port', 22),
'username': role.name,
'password': CRYPTOR.decrypt(role.password),
'ssh_key': get_role_key(user, role)
}
res.append(info)
elif isinstance(ob, User):
if not perm:
......@@ -198,6 +220,7 @@ def gen_resource(ob, perm=None):
for asset in ob:
info = get_asset_info(asset)
res.append(info)
logger.debug('生成res: %s' % res)
return res
......@@ -281,6 +304,7 @@ def get_role_push_host(role):
asset_no_push = set(asset_all) - set(asset_pushed.keys())
return asset_pushed, asset_no_push
if __name__ == "__main__":
print get_role_info(1)
......
......@@ -14,6 +14,7 @@ urlpatterns = patterns('jperm.views',
(r'^role/perm_role_edit/$', perm_role_edit),
(r'^role/push/$', perm_role_push),
(r'^role/recycle/$', perm_role_recycle),
(r'^role/get/$', perm_role_get),
(r'^sudo/$', perm_sudo_list),
(r'^sudo/perm_sudo_add/$', perm_sudo_add),
(r'^sudo/perm_sudo_delete/$', perm_sudo_delete),
......
......@@ -10,11 +10,8 @@ from uuid import uuid4
from jumpserver.api import CRYPTOR
from os import makedirs
from django.template.loader import get_template
from django.template import Context
from tempfile import NamedTemporaryFile
from jumpserver.settings import KEY_DIR
......@@ -72,45 +69,6 @@ def gen_keys(key="", key_path_dir=""):
return key_path_dir
def gen_sudo(role_custom, role_name, role_chosen):
"""
生成sudo file, 仅测试了cenos7
role_custom: 自定义支持的sudo 命令 格式: 'CMD1, CMD2, CMD3, ...'
role_name: role name
role_chosen: 选择那些sudo的命令别名:
    NETWORKING, SOFTWARE, SERVICES, STORAGE,
    DELEGATING, PROCESSES, LOCATE, DRIVERS
:return:
"""
sudo_file_basename = os.path.join(os.path.dirname(KEY_DIR), 'role_sudo_file')
makedirs(sudo_file_basename)
sudo_file_path = os.path.join(sudo_file_basename, role_name)
t = get_template('role_sudo.j2')
content = t.render(Context({"role_custom": role_custom,
"role_name": role_name,
"role_chosen": role_chosen,
}))
with open(sudo_file_path, 'w') as f:
f.write(content)
return sudo_file_path
def get_add_sudo_script(role_chosen_aliase, sudo_alias):
"""
get the sudo file
:param kwargs:
:return:
"""
sudo_j2 = get_template('jperm/role_sudo.j2')
sudo_content = sudo_j2.render(Context({"role_chosen_aliase": role_chosen_aliase,
"sudo_alias": sudo_alias}))
sudo_file = NamedTemporaryFile(delete=False)
sudo_file.write(sudo_content)
sudo_file.close()
print(sudo_file.name)
return sudo_file.name
if __name__ == "__main__":
print gen_keys()
......
This diff is collapsed.
......@@ -9,6 +9,7 @@ import hashlib
import datetime
import random
import subprocess
import uuid
import json
import logging
......@@ -47,9 +48,16 @@ def set_log(level):
return logger_f
def list_drop_str(a_list, a_str):
for i in a_list:
if i == a_str:
a_list.remove(a_str)
return a_list
def get_asset_info(asset):
"""
获取资产的相关账号端口信息
获取资产的相关管理账号端口等信息
"""
default = get_object(Setting, name='default')
info = {'hostname': asset.hostname, 'ip': asset.ip}
......@@ -70,17 +78,6 @@ def get_asset_info(asset):
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,所以拷贝一份到特殊目录
......@@ -95,7 +92,7 @@ def get_role_key(user, role):
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())
logger.debug("创建新的用户角色key %s" % user_role_key_path)
logger.debug(u"创建新的用户角色key %s, Owner: %s" % (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
......@@ -482,5 +479,10 @@ def my_render(template, data, request):
return render_to_response(template, data, context_instance=RequestContext(request))
def get_tmp_dir():
dir_name = os.path.join('/tmp', uuid.uuid4().hex)
mkdir(dir_name, mode=0777)
return dir_name
CRYPTOR = PyCrypt(KEY)
logger = set_log(LOG_LEVEL)
......@@ -7,7 +7,7 @@ import time
from django import template
from jperm.models import PermPush
from jumpserver.api import *
from jasset.models import AssetAlias
from jperm.perm_api import get_group_user_perm
register = template.Library()
......@@ -237,7 +237,7 @@ def key_exist(username):
"""
ssh key is exist or not
"""
if os.path.isfile(os.path.join(KEY_DIR, 'user', username)):
if os.path.isfile(os.path.join(KEY_DIR, 'user', username+'.pem')):
return True
else:
return False
......@@ -272,3 +272,35 @@ def get_push_info(push_id, arg):
return [role.name for role in push.role.all()]
else:
return []
@register.filter(name='get_cpu_core')
def get_cpu_core(cpu_info):
cpu_core = cpu_info.split('* ')[1] if cpu_info and '*' in cpu_info else cpu_info
return cpu_core
@register.filter(name='get_disk_info')
def get_disk_info(disk_info):
try:
disk_size = 0
if disk_info:
disk_dic = ast.literal_eval(disk_info)
for disk, size in disk_dic.items():
disk_size += size
disk_size = int(disk_size)
else:
disk_size = ''
except Exception:
disk_size = ''
return disk_size
@register.filter(name='user_perm_asset_num')
def user_perm_asset_num(user_id):
user = get_object(User, id=user_id)
if user:
user_perm_info = get_group_user_perm(user)
return len(user_perm_info.get('asset').keys())
else:
return 0
......@@ -6,19 +6,14 @@ urlpatterns = patterns('',
(r'^$', 'jumpserver.views.index'),
(r'^api/user/$', 'jumpserver.api.api_user'),
(r'^skin_config/$', 'jumpserver.views.skin_config'),
(r'^install/$', 'jumpserver.views.install'),
(r'^base/$', 'jumpserver.views.base'),
(r'^login/$', 'jumpserver.views.Login'),
(r'^logout/$', 'jumpserver.views.Logout'),
(r'^exec_cmd/$', 'jumpserver.views.exec_cmd'),
(r'^file/upload/$', 'jumpserver.views.upload'),
(r'^file/download/$', 'jumpserver.views.download'),
(r'^setting', 'jumpserver.views.setting'),
(r'^error/$', 'jumpserver.views.httperror'),
(r'^juser/', include('juser.urls')),
(r'^jasset/', include('jasset.urls')),
(r'^jlog/', include('jlog.urls')),
(r'^jperm/', include('jperm.urls')),
(r'^node_auth/', 'jumpserver.views.node_auth'),
(r'download/(\d{4}/\d\d/\d\d/.*)', 'jumpserver.views.download_file'),
(r'test2', 'jumpserver.views.test2'),
)
This diff is collapsed.
......@@ -25,9 +25,6 @@ urlpatterns = patterns('juser.views',
(r'^forget_password/$', forget_password),
(r'^change_info/$', 'change_info'),
(r'^change_role/$', 'chg_role'),
(r'^regen_ssh_key/$', 'regen_ssh_key'),
(r'^down_key/$', 'down_key'),
(r'runcommand/$', 'RunCommand'),
)
......@@ -129,8 +129,8 @@ def gen_ssh_key(username, password='',
生成一个用户ssh密钥对
"""
logger.debug('生成ssh key, 并设置authorized_keys')
private_key_file = os.path.join(key_dir, username)
mkdir(key_dir, mode=777)
private_key_file = os.path.join(key_dir, username+'.pem')
mkdir(key_dir, mode=0700)
if os.path.isfile(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))
......@@ -166,7 +166,7 @@ def user_add_mail(user, kwargs):
mail_msg = u"""
Hi, %s
您的用户名: %s
您的角色%s
您的权限%s
您的web登录密码: %s
您的ssh密钥文件密码: %s
密钥下载地址: %s/juser/down_key/?uuid=%s
......@@ -195,9 +195,9 @@ def get_display_msg(user, password, ssh_key_pwd, ssh_key_login_need, send_mail_n
用户名:%s
密码:%s
密钥密码:%s
密钥下载url: %s/juser/down_key/?id=%s
密钥下载url: %s/juser/down_key/?uuid=%s
该账号密码可以登陆web和跳板机。
""" % (URL, user.username, password, ssh_key_pwd, URL, user.id)
""" % (URL, user.username, password, ssh_key_pwd, URL, user.uuid)
else:
msg = u"""
跳板机地址: %s \n
......
This diff is collapsed.
......@@ -8,7 +8,7 @@ import sys
import os.path
import threading
import datetime
import urllib
import re
import tornado.ioloop
import tornado.options
......@@ -23,8 +23,8 @@ from tornado.options import define, options
from pyinotify import WatchManager, Notifier, ProcessEvent, IN_DELETE, IN_CREATE, IN_MODIFY, AsyncNotifier
import select
from connect import Tty, User, Asset, PermRole, logger, get_object
from connect import TtyLog, Log, Session, user_have_perm
from connect import Tty, User, Asset, PermRole, logger, get_object, PermRole, gen_resource
from connect import TtyLog, Log, Session, user_have_perm, get_group_user_perm, MyRunner, ExecLog
try:
import simplejson as json
......@@ -67,22 +67,6 @@ def require_auth(role='user'):
except AttributeError:
pass
logger.warning('Websocket: Request auth failed.')
# asset_id = int(request.get_argument('id', 9999))
# print asset_id
# asset = Asset.objects.filter(id=asset_id)
# if asset:
# asset = asset[0]
# request.asset = asset
# else:
# request.close()
#
# if user:
# user = user[0]
# request.user = user
#
# else:
# print("No session user.")
# request.close()
return _deco2
return _deco
......@@ -138,6 +122,7 @@ class Application(tornado.web.Application):
(r'/monitor', MonitorHandler),
(r'/terminal', WebTerminalHandler),
(r'/kill', WebTerminalKillHandler),
(r'/exec', ExecHandler),
]
setting = {
......@@ -206,7 +191,6 @@ class MonitorHandler(tornado.websocket.WebSocketHandler):
class WebTty(Tty):
def __init__(self, *args, **kwargs):
super(WebTty, self).__init__(*args, **kwargs)
self.login_type = 'web'
self.ws = None
self.data = ''
self.input_mode = False
......@@ -225,6 +209,82 @@ class WebTerminalKillHandler(tornado.web.RequestHandler):
logger.debug('Websocket: web terminal client num: %s' % len(WebTerminalHandler.clients))
class ExecHandler(tornado.websocket.WebSocketHandler):
clients = []
tasks = []
def __init__(self, *args, **kwargs):
self.id = 0
self.user = None
self.role = None
self.runner = None
self.assets = []
self.perm = {}
self.remote_ip = ''
super(ExecHandler, self).__init__(*args, **kwargs)
def check_origin(self, origin):
return True
@require_auth('user')
def open(self):
logger.debug('Websocket: Open exec request')
role_name = self.get_argument('role', 'sb')
self.remote_ip = self.request.remote_ip
logger.debug('Web执行命令: 请求角色 %s' % role_name)
self.role = get_object(PermRole, name=role_name)
self.perm = get_group_user_perm(self.user)
roles = self.perm.get('role').keys()
if self.role not in roles:
self.write_message('No perm that role %s' % role_name)
self.close()
self.assets = self.perm.get('role').get(self.role).get('asset')
res = gen_resource({'user': self.user, 'asset': self.assets, 'role': self.role})
self.runner = MyRunner(res)
message = '有权限的主机: ' + ', '.join([asset.hostname for asset in self.assets])
self.__class__.clients.append(self)
self.write_message(message)
def on_message(self, message):
data = json.loads(message)
pattern = data.get('pattern', '')
command = data.get('command', '')
asset_name_str = ''
if pattern and command:
for inv in self.runner.inventory.get_hosts(pattern=pattern):
asset_name_str += '%s ' % inv.name
self.write_message('匹配主机: ' + asset_name_str)
self.write_message('<span style="color: yellow">Ansible> %s</span>\n\n' % command)
self.__class__.tasks.append(MyThread(target=self.run_cmd, args=(command, pattern)))
ExecLog(host=asset_name_str, cmd=command, user=self.user.username, remote_ip=self.remote_ip).save()
for t in self.__class__.tasks:
if t.is_alive():
continue
try:
t.setDaemon(True)
t.start()
except RuntimeError:
pass
def run_cmd(self, command, pattern):
self.runner.run('shell', command, pattern=pattern)
for k, v in self.runner.results.items():
for host, output in v.items():
if k == 'ok':
header = "<span style='color: green'>[ %s => %s]</span>\n" % (host, 'Ok')
else:
header = "<span style='color: red'>[ %s => %s]</span>\n" % (host, 'failed')
self.write_message(header)
self.write_message(output)
self.write_message('\n~o~ Task finished ~o~\n')
def on_close(self):
logger.debug('关闭web_exec请求')
class WebTerminalHandler(tornado.websocket.WebSocketHandler):
clients = []
tasks = []
......@@ -236,6 +296,8 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler):
self.log = None
self.id = 0
self.user = None
self.ssh = None
self.channel = None
super(WebTerminalHandler, self).__init__(*args, **kwargs)
def check_origin(self, origin):
......@@ -250,7 +312,7 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler):
if asset:
roles = user_have_perm(self.user, asset)
logger.debug(roles)
logger.debug('rolename: %s' % role_name)
logger.debug('角色: %s' % role_name)
login_role = ''
for role in roles:
if role.name == role_name:
......@@ -267,10 +329,10 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler):
return
logger.debug('Websocket: request web terminal Host: %s User: %s Role: %s' % (asset.hostname, self.user.username,
login_role.name))
self.term = WebTty(self.user, asset, login_role)
self.term = WebTty(self.user, asset, login_role, login_type='web')
self.term.remote_ip = self.request.remote_ip
self.term.get_connection()
self.term.channel = self.term.ssh.invoke_shell(term='xterm')
self.ssh = self.term.get_connection()
self.channel = self.ssh.invoke_shell(term='xterm')
WebTerminalHandler.tasks.append(MyThread(target=self.forward_outbound))
WebTerminalHandler.clients.append(self)
......@@ -303,7 +365,7 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler):
self.term.vim_data = ''
self.term.data = ''
self.term.input_mode = False
self.term.channel.send(data['data'])
self.channel.send(data['data'])
def on_close(self):
logger.debug('Websocket: Close request')
......@@ -326,9 +388,9 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler):
data = ''
pre_timestamp = time.time()
while True:
r, w, e = select.select([self.term.channel, sys.stdin], [], [])
if self.term.channel in r:
recv = self.term.channel.recv(1024)
r, w, e = select.select([self.channel, sys.stdin], [], [])
if self.channel in r:
recv = self.channel.recv(1024)
if not len(recv):
return
data += recv
......@@ -347,8 +409,8 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler):
data = ''
except UnicodeDecodeError:
pass
finally:
self.close()
except IndexError:
pass
if __name__ == '__main__':
tornado.options.parse_command_line()
......
......@@ -2822,7 +2822,9 @@ body.body-small .footer.fixed {
.table > thead > tr > td,
.table > tbody > tr > td,
.table > tfoot > tr > td {
border-top: 1px solid #e7eaec;
/*border-top: 1px solid #e7eaec;*/
border-bottom: 1px solid #e7eaec;
border-top: none;
line-height: 1.42857;
padding: 8px;
vertical-align: top;
......
......@@ -16,9 +16,9 @@ function check_all(form) {
}
}
function checkAll(){
var checklist = document.getElementsByName ("checked");
if(document.getElementById("check_all").checked)
function checkAll(id, name){
var checklist = document.getElementsByName(name);
if(document.getElementById(id).checked)
{
for(var i=0;i<checklist.length;i++)
{
......
......@@ -2,7 +2,6 @@
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
......@@ -12,8 +11,6 @@
{% include 'link_css.html' %}
{% include 'head_script.html' %}
{% block self_head_css_js %} {% endblock %}
</head>
<body>
......
{% extends 'base.html' %}
{% load mytags %}
{% block self_head_css_js %}
<link href="/static/css/plugins/datepicker/datepicker3.css" rel="stylesheet">
<link href="/static/css/plugins/chosen/chosen.css" rel="stylesheet">
<script src="/static/js/plugins/chosen/chosen.jquery.js"></script>
{% endblock %}
{% block content %}
{% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeIn">
<div class="row">
<div class="col-lg-12">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>下载文件</h5>
......@@ -16,30 +21,62 @@
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
<li><a href="#">Config option 1</a>
</li>
<li><a href="#">Config option 2</a>
</li>
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<h2>下载文件可联系管理员在服务器安装lrzsz,使用sz命令下载。 </h2>
<div>
{% for document in documents %}
<a href="/download/{{ document }}">{{ document }}</a>
<form id="downForm" class="form-horizontal" method="post">
{% if error %}
<div class="alert alert-warning text-center">{{ error }}</div>
{% endif %}
{% if msg %}
<div class="alert alert-success text-center">{{ msg }}</div>
{% endif %}
<div class="form-group">
<label for="file_path" class="col-sm-2 control-label">文件路径<span class="red-fonts">*</span></label>
<div class="col-sm-8">
<input id="file_path" name="file_path" placeholder="File Path" type="text" class="form-control">
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<label for="user" class="col-sm-2 control-label">选择主机<span class="red-fonts">*</span></label>
<div class="col-sm-8">
<select name="asset_ids" id="asset_ids" data-placeholder="请输入" class="chosen-select form-control m-b" multiple tabindex="2">
{% for asset in assets %}
<option value="{{ asset.id }}">{{ asset.hostname }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="reset">取消</button>
<button id="submit_button" class="btn btn-primary" type="submit">下载</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block self_footer_js %}
<script>
var config = {
'.chosen-select' : {},
'.chosen-select-deselect' : {allow_single_deselect:true},
'.chosen-select-no-single' : {disable_search_threshold:10},
'.chosen-select-no-results': {no_results_text:'Oops, nothing found!'},
'.chosen-select-width' : {width:"95%"}
};
for (var selector in config) {
$(selector).chosen(config[selector]);
}
</script>
{% endblock %}
\ No newline at end of file
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=320, initial-scale=1">
<title>Jumpserver Exec Terminal</title>
<style type="text/css"></style>
</head>
<body>
<div id="wrapper">
<div id="chat_box" class="content">
<p class="system"></p>
</div>
<div id="footer">
<div class="content">
<input type="text" id="pattern" value="{{ check_assets }}" placeholder="Ansible Pattern">
<input type="text" id="command" placeholder="Command to execute">
<input type="button" id="send_btn" value="Send" onclick="sendMessage()">
</div>
</div>
</div>
<script type="text/javascript">
var wsUri = "{{ web_terminal_uri }}"; //请求的websocket url
var ws = new WebSocket(wsUri);
function createSystemMessage(message) {
var message = document.createTextNode(message);
var messageBox = document.createElement('p');
messageBox.className = 'system';
messageBox.appendChild(message);
var chat = document.getElementById('chat_box');
chat.appendChild(messageBox);
}
function createUserMessage(message) {
message = message.replace('/\n/g', '<br>');
var messageOb = document.createElement('div');
messageOb.innerHTML = message;
var messageBox = document.createElement('p');
messageBox.appendChild(messageOb);
var chat = document.getElementById('chat_box');
chat.appendChild(messageBox);
}
ws.onopen = function(ev) {
createSystemMessage('[Connected]');
};
ws.onclose = function(ev) {
createSystemMessage('[Disconnected]');
};
ws.onmessage = function(ev) {
createUserMessage(ev.data);
var chat = document.getElementById('chat_box');
chat.scrollTop = chat.scrollHeight;
};
function sendMessage() {
var pattern = document.getElementById('pattern');
var command = document.getElementById('command');
var data = {
pattern: pattern.value,
command: command.value,
{# ts: (new Date()).getTime()#}
};
ws.send(JSON.stringify(data));
command.value = ''
}
</script>
<style type="text/css">
* {
font-family: "Monaco", "DejaVu Sans Mono", "Liberation Mono", monospace;
font-size: 11px;
}
html, body {
margin: 0;
padding: 0;
height: 100%;
background-color: #fff;
}
#wrapper {
{# background-color: #ecf0f1;#}
{# border: #000 solid 5px;#}
background: #000;
width: 800px;
box-shadow: rgba(0, 0, 0, 0.8) 2px 2px 20px;
color: #fff;
}
#chat_box {
box-sizing: border-box;
height: 100%;
overflow: auto;
padding-bottom: 50px;
}
#footer {
box-sizing: border-box;
position: fixed;
bottom: 0;
height: 50px;
width: 800px;
{# border: #000 solid -10px;#}
background-color: #2980b9;
}
#footer .content {
padding-top: 4px;
position: relative;
}
#pattern { width: 25%; }
#command { width: 60%; }
#send_btn {
width: 10%;
{# position: absolute;#}
margin-left: 5px;
right: 0;
bottom: 0;
}
.content {
width: 800px;
margin-left: 5px;
}
input[type="text"],
input[type="button"] {
border: 0;
color: #fff;
}
input[type="text"] {
background-color: #146EA8;
padding: 3px 10px;
}
input[type="button"] {
background-color: #f39c12;
border-right: 2px solid #e67e22;
border-bottom: 2px solid #e67e22;
min-width: 70px;
display: inline-block;
}
input[type="button"]:hover {
background-color: #e67e22;
border-right: 2px solid #f39c12;
border-bottom: 2px solid #f39c12;
cursor: pointer;
}
.system,
.username {
color: #aaa;
font-style: italic;
font-family: monospace;
font-size: 16px;
}
@media(max-width: 1000px) {
.content { width: 90%; }
}
@media(max-width: 780px) {
#footer { height: 91px; }
#chat_box { padding-bottom: 91px; }
#user { width: 100%; }
#message { width: 80%; }
}
@media(max-width: 400px) {
#footer { height: 135px; }
#chat_box { padding-bottom: 135px; }
#message { width: 100%; }
#send_btn {
position: relative;
margin-top: 3px;
width: 100%;
}
}
</style>
</body>
<div></div>
<div></div>
</html>
\ No newline at end of file
<div class="footer fixed">
<div class="pull-right">
Version <strong>0.2.0</strong> GPL.
Version <strong>0.3.0</strong> GPL.
</div>
<div>
<strong>Copyright</strong> Jumpserver.org Team &copy; 2014-2015
......
......@@ -6,7 +6,7 @@
<div class="wrapper wrapper-content">
<div class="row">
<div class="col-lg-3">
<div class="col-sm-3">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label label-success pull-right">Users</span>
......@@ -18,7 +18,7 @@
</div>
</div>
</div>
<div class="col-lg-3">
<div class="col-sm-3">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label label-info pull-right">Hosts</span>
......@@ -31,7 +31,7 @@
</div>
</div>
<div class="col-lg-3">
<div class="col-sm-3">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label label-primary pull-right">Online</span>
......@@ -45,7 +45,7 @@
</div>
</div>
<div class="col-lg-3">
<div class="col-sm-3">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label label-danger pull-right">Connected</span>
......@@ -74,7 +74,7 @@
</ul>
</div>
<div class="col-sm-7" id="top10" style="margin-left: -15px;height: 346px;padding: 15px 0 15px 0;"></div>
<div class="col-lg-3 white-bg" id="top1" style="margin-left: -15px;height: 346px">
<div class="col-sm-3 white-bg" id="top1" style="margin-left: -15px;height: 346px">
<div class="statistic-box">
<h4>
活跃用户资产占比
......@@ -83,13 +83,13 @@
以下图形分别描述一个月活跃用户和资产占所有用户主机的百分比
</p>
<div class="row text-center">
<div class="col-lg-6">
<div class="col-sm-6">
<div id="activeUser" style="width: 140px; height: 140px;">
</div>
<h5>用户</h5>
</div>
<div class="col-lg-6">
<div class="col-sm-6">
<div id="activeAsset" style="width: 140px; height: 140px;"></div>
<h5>主机</h5>
</div>
......@@ -103,7 +103,7 @@
<br/>
<div class="row">
<div class="col-lg-4">
<div class="col-sm-4">
{# <div class="ibox float-e-margins">#}
{# <div class="ibox-title">#}
{# <h5>权限申请</h5>#}
......@@ -192,7 +192,7 @@
</div>
</div>
</div>
<div class="col-lg-4">
<div class="col-sm-4">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>最近十次登录</h5>
......@@ -258,7 +258,7 @@
</div>
</div>
<div class="col-lg-4">
<div class="col-sm-4">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>一周Top10用户</h5>
......
This diff is collapsed.
......@@ -5,7 +5,7 @@
{% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-10">
<div class="col-sm-10">
<div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title">
<h5> 填写资产基本信息 </h5>
......@@ -118,6 +118,13 @@
{% block self_footer_js %}
<script>
$('document').ready(function(){
var check_default = "{{ default_setting.name }}";
console.log(check_default);
if (check_default != 'default'){
$('#id_use_default_auth').attr('disabled', true);
$('#id_use_default_auth').attr('checked', false);
$('#admin_account').css('display', 'block');
} else {
$('#id_use_default_auth').click(function(){
if ($(this).is(':checked')){
$('#admin_account').css('display', 'none');
......@@ -126,6 +133,8 @@
$('#admin_account').css('display', 'block');
}
})
}
});
var required_fields = ["id_hostname", "id_port"];
......
......@@ -8,7 +8,7 @@
</style>
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-10">
<div class="col-sm-10">
<div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title">
<h5> 填写主机基本信息 </h5>
......
This diff is collapsed.
This diff is collapsed.
......@@ -5,7 +5,7 @@
{% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-10">
<div class="col-sm-10">
<div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title">
<h5> 修改资产基本信息 </h5>
......@@ -46,6 +46,9 @@
<div class="hr-line-dashed"></div>
{{ af.remote_ip|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
{{ af.mac|bootstrap_horizontal }}
{# <div class="hr-line-dashed"></div>#}
{# {{ af.port|bootstrap_horizontal }}#}
......@@ -105,6 +108,9 @@
<div class="hr-line-dashed"></div>
{{ af.system_version|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
{{ af.system_arch|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
{{ af.number|bootstrap_horizontal }}
......
......@@ -18,7 +18,7 @@
<body>
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-10">
<div class="col-sm-10">
<div class="ibox float-e-margins">
{# <div class="ibox-title">#}
{# <h5 class="text-center"> 填写修改主机信息. </h5>#}
......
This diff is collapsed.
......@@ -19,7 +19,7 @@
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-10">
<div class="col-sm-10">
<div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title">
<h5> 填写主机组基本信息 </h5>
......
......@@ -19,7 +19,7 @@
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-10">
<div class="col-sm-10">
<div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title">
<h5> 填写主机组基本信息 </h5>
......
......@@ -5,7 +5,7 @@
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-10">
<div class="col-sm-10">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5> 主机组详细信息列表</h5>
......
......@@ -4,7 +4,7 @@
{% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-10">
<div class="col-sm-10">
<div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title">
<h5> 填写IDC基本信息 </h5>
......
......@@ -4,7 +4,7 @@
{% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-10">
<div class="col-sm-10">
<div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title">
<h5> 填写IDC基本信息 </h5>
......
......@@ -5,7 +5,7 @@
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-10">
<div class="col-sm-10">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5> IDC详细信息列表</h5>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -9,7 +9,7 @@
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-12">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title">
<h5> 用户日志详细信息列表 </h5>
......
This diff is collapsed.
......@@ -32,7 +32,7 @@
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-12">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title">
<h5> 用户日志详细信息列表 </h5>
......@@ -54,9 +54,10 @@
<ul class="nav nav-tabs">
<li><a href="/jlog/log_list/online/" class="text-center"><i class="fa fa-laptop"></i> 在线 </a></li>
<li class="active"><a href="/jlog/log_list/offline/" class="text-center"><i class="fa fa-bar-chart-o"></i> 历史记录 </a></li>
<li><a href="/jlog/log_list/exec/" class="text-center"><i class="fa fa-bar-chart-o"></i> 命令记录 </a></li>
<li><a href="/jlog/log_list/file/" class="text-center"><i class="fa fa-bar-chart-o"></i> 上传下载 </a></li>
</ul>
</div>
<br/>
<form class="form-inline" action="" method="get">
<div class="form-group" id="date_5">
<div class="input-daterange input-group" id="datepicker">
......@@ -87,7 +88,7 @@
<input id="cmd" name="cmd" placeholder="命令" type="text" class="form-control" value="{{ cmd }}" style="width: 200px;">
</div>
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
Search
- 搜索 -
</button>
</form>
<div class="tab-content">
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment