mirror of https://github.com/jumpserver/jumpserver
merge
commit
1f5fa9a9bd
|
@ -37,6 +37,7 @@ nosetests.xml
|
|||
.mr.developer.cfg
|
||||
.project
|
||||
.pydevproject
|
||||
*.xlsx
|
||||
node_modules
|
||||
logs
|
||||
keys
|
||||
|
|
198
connect.py
198
connect.py
|
@ -13,16 +13,19 @@ import textwrap
|
|||
import getpass
|
||||
import readline
|
||||
import django
|
||||
from multiprocessing import Pool
|
||||
import paramiko
|
||||
import struct, fcntl, signal, socket, select, fnmatch
|
||||
import struct, fcntl, signal, socket, select
|
||||
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'jumpserver.settings'
|
||||
if django.get_version() != '1.6':
|
||||
django.setup()
|
||||
from jumpserver.api import ServerError, User, Asset, AssetGroup, get_object
|
||||
from jumpserver.api import logger, is_dir, Log, TtyLog
|
||||
from jumpserver.settings import log_dir
|
||||
from jumpserver.api import logger, mkdir, Log, TtyLog
|
||||
from jumpserver.settings import LOG_DIR
|
||||
|
||||
|
||||
login_user = get_object(User, username=getpass.getuser())
|
||||
|
||||
|
||||
try:
|
||||
import termios
|
||||
|
@ -32,11 +35,6 @@ except ImportError:
|
|||
time.sleep(3)
|
||||
sys.exit()
|
||||
|
||||
VIM_FLAG = False
|
||||
VIM_COMMAND = ''
|
||||
SSH_TTY = ''
|
||||
login_user = get_object(User, username=getpass.getuser())
|
||||
|
||||
|
||||
def color_print(msg, color='red', exits=False):
|
||||
"""
|
||||
|
@ -53,49 +51,6 @@ def color_print(msg, color='red', exits=False):
|
|||
sys.exit()
|
||||
|
||||
|
||||
def verify_connect(user, option):
|
||||
"""
|
||||
Check user was permed or not . Check ip is unique or not.
|
||||
鉴定用户是否有该主机权限 或 匹配到的ip是否唯一
|
||||
"""
|
||||
ip_matched = []
|
||||
try:
|
||||
assets_info = login_user.get_asset_info()
|
||||
except ServerError, e:
|
||||
color_print(e, 'red')
|
||||
return False
|
||||
|
||||
for ip, asset_info in assets_info.items():
|
||||
if option in asset_info[1:] and option:
|
||||
ip_matched = [asset_info[1]]
|
||||
break
|
||||
|
||||
for info in asset_info[1:]:
|
||||
if option in info:
|
||||
ip_matched.append(ip)
|
||||
|
||||
logger.debug('%s matched input %s: %s' % (login_user.username, option, ip_matched))
|
||||
ip_matched = list(set(ip_matched))
|
||||
|
||||
if len(ip_matched) > 1: # 如果匹配ip不唯一
|
||||
ip_comment = {}
|
||||
for ip in ip_matched:
|
||||
ip_comment[ip] = assets_info[ip][2]
|
||||
|
||||
for ip in sorted(ip_comment):
|
||||
if ip_comment[ip]:
|
||||
print '%-15s -- %s' % (ip, ip_comment[ip])
|
||||
else:
|
||||
print '%-15s' % ip
|
||||
print ''
|
||||
elif len(ip_matched) < 1: # 如果没匹配到
|
||||
color_print('没有该主机,或者您没有该主机的权限 No Permission or No host.', 'red')
|
||||
else: # 恰好是1个
|
||||
asset = get_object(Asset, ip=ip_matched[0])
|
||||
jtty = Jtty(user, asset)
|
||||
jtty.connect()
|
||||
|
||||
|
||||
def check_vim_status(command, ssh):
|
||||
global SSH_TTY
|
||||
print command
|
||||
|
@ -114,67 +69,99 @@ def check_vim_status(command, ssh):
|
|||
|
||||
|
||||
def deal_command(str_r, ssh):
|
||||
|
||||
|
||||
"""
|
||||
处理命令中特殊字符
|
||||
"""
|
||||
t = time.time()
|
||||
str_r = re.sub('\x07','',str_r) #删除响铃
|
||||
patch_char = re.compile('\x08\x1b\[C') #删除方向左右一起的按键
|
||||
while patch_char.search(str_r):
|
||||
str_r = patch_char.sub('', str_r.rstrip())
|
||||
|
||||
|
||||
result_command = '' #最后的结果
|
||||
pattern_str = '' #模式中间中的字符串
|
||||
backspace_num = 0 #光标移动的个数
|
||||
backspace_list = []
|
||||
reach_backspace_flag = False #没有检测到光标键则为true
|
||||
end_flag = False
|
||||
reach_backspace_second_flag = False
|
||||
pattern_list = []
|
||||
pattern_str=''
|
||||
while str_r:
|
||||
tmp = re.match(r'\w', str_r)
|
||||
tmp = re.match(r'\s*\w+\s*', str_r) #获取字符串,其它特殊字符匹配暂时还不知道。。
|
||||
if tmp:
|
||||
if reach_backspace_flag:
|
||||
pattern_str += str(tmp.group(0))
|
||||
str_r = str_r[1:]
|
||||
if reach_backspace_flag :
|
||||
if not reach_backspace_second_flag:
|
||||
pattern_str +=str(tmp.group(0))
|
||||
else:
|
||||
pattern_list.append(pattern_str)
|
||||
pattern_str=str(tmp.group(0))
|
||||
reach_backspace_second_flag=False
|
||||
str_r = str_r[len(str(tmp.group(0))):]
|
||||
continue
|
||||
else:
|
||||
result_command += str(tmp.group(0))
|
||||
str_r = str_r[1:]
|
||||
str_r = str_r[len(str(tmp.group(0))):]
|
||||
continue
|
||||
|
||||
tmp = re.match(r'\x1b\[K[\x08]*', str_r)
|
||||
|
||||
tmp = re.match(r'\x1b\[K[\x08]*', str_r) #遇到删除确认符,确定删除数据
|
||||
if tmp:
|
||||
for x in backspace_list:
|
||||
backspace_num += int(x)
|
||||
if backspace_num > 0:
|
||||
if backspace_num > len(result_command) :
|
||||
result_command += ''.join(pattern_list)
|
||||
result_command += pattern_str
|
||||
result_command = result_command[0:-backspace_num]
|
||||
else:
|
||||
result_command = result_command[0:-backspace_num]
|
||||
result_command += ''.join(pattern_list)
|
||||
result_command += pattern_str
|
||||
del_len = len(str(tmp.group(0)))-3
|
||||
if del_len > 0:
|
||||
result_command = result_command[0:-del_len]
|
||||
reach_backspace_flag = False
|
||||
reach_backspace_second_flag =False
|
||||
backspace_num =0
|
||||
del pattern_list[:]
|
||||
del backspace_list[:]
|
||||
pattern_str=''
|
||||
str_r = str_r[len(str(tmp.group(0))):]
|
||||
continue
|
||||
if re.match(r'\x08', str_r):
|
||||
backspace_num += 1
|
||||
reach_backspace_flag = True
|
||||
str_r = str_r[1:]
|
||||
if len(str_r) == 0:
|
||||
end_flag = True
|
||||
|
||||
tmp = re.match(r'\x08+', str_r) #将遇到的退格数字存放到队列中
|
||||
if tmp:
|
||||
if reach_backspace_flag:
|
||||
reach_backspace_second_flag = True
|
||||
else:
|
||||
reach_backspace_flag = True
|
||||
str_r = str_r[len(str(tmp.group(0))):]
|
||||
if len(str_r) != 0: #如果退格键在最后,则放弃
|
||||
backspace_list.append(len(str(tmp.group(0))))
|
||||
continue
|
||||
if reach_backspace_flag :
|
||||
pattern_str += str_r[0]
|
||||
|
||||
if reach_backspace_flag :
|
||||
if not reach_backspace_second_flag:
|
||||
pattern_str +=str_r[0]
|
||||
else:
|
||||
pattern_list.append(pattern_str)
|
||||
pattern_str=str_r[0]
|
||||
reach_backspace_second_flag=False
|
||||
else :
|
||||
result_command += str_r[0]
|
||||
str_r = str_r[1:]
|
||||
|
||||
if backspace_num > 0 and not end_flag:
|
||||
result_command = result_command[:-backspace_num]
|
||||
result_command += pattern_str
|
||||
|
||||
|
||||
if pattern_str !='':
|
||||
pattern_list.append(pattern_str)
|
||||
|
||||
#退格队列中还有腿哥键,则进行删除操作
|
||||
if len(backspace_list) > 0 :
|
||||
for backspace in backspace_list:
|
||||
if int(backspace) >= len(result_command):
|
||||
result_command = pattern_list[0]
|
||||
else:
|
||||
result_command = result_command[:-int(backspace)]
|
||||
result_command += pattern_list[0]
|
||||
pattern_list = pattern_list[1:]
|
||||
|
||||
control_char = re.compile(r"""
|
||||
\x1b[ #%()*+\-.\/]. |
|
||||
|
@ -183,13 +170,13 @@ def deal_command(str_r, ssh):
|
|||
(?:\x1b\]|\x9d) .*? (?:\x1b\\|[\a\x9c]) | \x07 | #匹配 操作系统指令(OSC)...终止符或振铃符(ST|BEL)
|
||||
(?:\x1b[P^_]|[\x90\x9e\x9f]) .*? (?:\x1b\\|\x9c) | #匹配 设备控制串或私讯或应用程序命令(DCS|PM|APC)...终止符(ST)
|
||||
\x1b. #匹配 转义过后的字符
|
||||
[\x80-\x9f] #匹配 所有控制字符
|
||||
[\x80-\x9f] | (?:\x1b\]0.*) | \[.*@.*\][\$#] | (.*mysql>.*) #匹配 所有控制字符
|
||||
""", re.X)
|
||||
result_command = control_char.sub('', result_command.strip())
|
||||
global VIM_FLAG
|
||||
global VIM_COMMAND
|
||||
if not VIM_FLAG:
|
||||
if result_command.startswith('vim') or result_command.startswith('vi') :
|
||||
if result_command.startswith('vi'):
|
||||
VIM_FLAG = True
|
||||
VIM_COMMAND = result_command
|
||||
return result_command.decode('utf8',"ignore")
|
||||
|
@ -197,19 +184,13 @@ def deal_command(str_r, ssh):
|
|||
if check_vim_status(VIM_COMMAND, ssh):
|
||||
VIM_FLAG = False
|
||||
VIM_COMMAND=''
|
||||
if result_command.endswith(':wq') or result_command.endswith(':wq!') or result_command.endswith(':q!'):
|
||||
return ''
|
||||
return result_command.decode('utf8',"ignore")
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
def newline_code_in(strings):
|
||||
for i in ['\r', '\r\n', '\n']:
|
||||
if i in strings:
|
||||
#print "new line"
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class Tty(object):
|
||||
"""
|
||||
A virtual tty class
|
||||
|
@ -221,8 +202,8 @@ class Tty(object):
|
|||
self.ip = None
|
||||
self.port = 22
|
||||
self.channel = None
|
||||
self.user = None
|
||||
self.asset = None
|
||||
#self.asset = get_object(Asset, name=asset_name)
|
||||
#self.user = get_object(User, username=username)
|
||||
self.role = None
|
||||
self.ssh = None
|
||||
self.connect_info = None
|
||||
|
@ -257,44 +238,45 @@ class Tty(object):
|
|||
|
||||
return line_filtered
|
||||
|
||||
def get_log_file(self):
|
||||
def get_log(self):
|
||||
"""
|
||||
Logging user command and output.
|
||||
记录用户的日志
|
||||
"""
|
||||
tty_log_dir = os.path.join(log_dir, 'tty')
|
||||
timestamp_start = int(time.time())
|
||||
date_start = time.strftime('%Y%m%d', time.localtime(timestamp_start))
|
||||
time_start = time.strftime('%H%M%S', time.localtime(timestamp_start))
|
||||
tty_log_dir = os.path.join(LOG_DIR, 'tty')
|
||||
date_today = datetime.datetime.now()
|
||||
date_start = date_today.strftime('%Y%m%d')
|
||||
time_start = date_today.strftime('%H%M%S')
|
||||
today_connect_log_dir = os.path.join(tty_log_dir, date_start)
|
||||
log_file_path = os.path.join(today_connect_log_dir, '%s_%s_%s' % (self.username, self.asset_name, time_start))
|
||||
|
||||
try:
|
||||
is_dir(today_connect_log_dir, mode=0777)
|
||||
mkdir(today_connect_log_dir, mode=0777)
|
||||
except OSError:
|
||||
logger.debug('创建目录 %s 失败,请修改%s目录权限' % (today_connect_log_dir, tty_log_dir))
|
||||
raise ServerError('Create %s failed, Please modify %s permission.' % (today_connect_log_dir, tty_log_dir))
|
||||
|
||||
try:
|
||||
log_file_f = open(log_file_path + '.log', 'a')
|
||||
log_time_f = open(log_file_path + '.time', 'a')
|
||||
except IOError:
|
||||
logger.debug('创建tty日志文件失败, 请修改目录%s权限' % today_connect_log_dir)
|
||||
raise ServerError('Create logfile failed, Please modify %s permission.' % today_connect_log_dir)
|
||||
|
||||
if self.login_type == 'ssh':
|
||||
if self.login_type == 'ssh': # 如果是ssh连接过来,记录connect.py的pid,web terminal记录为日志的id
|
||||
pid = os.getpid()
|
||||
remote_ip = os.popen("who -m | awk '{ print $5 }'").read().strip('()\n')
|
||||
remote_ip = os.popen("who -m | awk '{ print $5 }'").read().strip('()\n') # 获取远端IP
|
||||
log = Log(user=self.username, host=self.asset_name, remote_ip=remote_ip,
|
||||
log_path=log_file_path, start_time=datetime.datetime.now(), pid=pid)
|
||||
log_path=log_file_path, start_time=date_today, pid=pid)
|
||||
else:
|
||||
remote_ip = 'Web'
|
||||
log = Log(user=self.username, host=self.asset_name, remote_ip=remote_ip,
|
||||
log_path=log_file_path, start_time=datetime.datetime.now(), pid=0)
|
||||
log_path=log_file_path, start_time=date_today, pid=0)
|
||||
log.save()
|
||||
log.pid = log.id
|
||||
log.save()
|
||||
|
||||
log_file_f.write('Start at %s\n' % datetime.datetime.now())
|
||||
log.save()
|
||||
log_file_f.write('Start at %s\n' % datetime.datetime.now())
|
||||
return log_file_f, log_time_f, log
|
||||
|
||||
def get_connect_info(self):
|
||||
|
@ -378,10 +360,10 @@ class SshTty(Tty):
|
|||
Use paramiko channel connect server interactive.
|
||||
使用paramiko模块的channel,连接后端,进入交互式
|
||||
"""
|
||||
log_file_f, log_time_f, log = self.get_log_file()
|
||||
log_file_f, log_time_f, log = self.get_log()
|
||||
old_tty = termios.tcgetattr(sys.stdin)
|
||||
pre_timestamp = time.time()
|
||||
input_r = ''
|
||||
data = ''
|
||||
input_mode = False
|
||||
|
||||
try:
|
||||
|
@ -410,22 +392,20 @@ class SshTty(Tty):
|
|||
log_time_f.flush()
|
||||
|
||||
if input_mode and not self.is_output(x):
|
||||
input_r += x
|
||||
data += x
|
||||
|
||||
except socket.timeout:
|
||||
pass
|
||||
|
||||
if sys.stdin in r:
|
||||
x = os.read(sys.stdin.fileno(), 1)
|
||||
if not input_mode:
|
||||
input_mode = True
|
||||
input_mode = True
|
||||
|
||||
if str(x) in ['\r', '\n', '\r\n']:
|
||||
# input_r = deal_command(input_r,ssh)
|
||||
input_r = self.remove_control_char(input_r)
|
||||
data = self.remove_control_char(data)
|
||||
|
||||
TtyLog(log=log, datetime=datetime.datetime.now(), cmd=input_r).save()
|
||||
input_r = ''
|
||||
TtyLog(log=log, datetime=datetime.datetime.now(), cmd=data).save()
|
||||
data = ''
|
||||
input_mode = False
|
||||
|
||||
if len(x) == 0:
|
||||
|
|
|
@ -6,4 +6,7 @@ paramiko==1.15.2
|
|||
ecdsa==0.13
|
||||
MySQL-python==1.2.5
|
||||
django-uuidfield==0.5.0
|
||||
psutil==2.2.1
|
||||
psutil==2.2.1
|
||||
xlsxwriter==0.7.7
|
||||
xlrd==0.9.4
|
||||
django-bootstrap-form
|
|
@ -0,0 +1,459 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ansible.inventory.group import Group
|
||||
from ansible.inventory.host import Host
|
||||
from ansible.inventory import Inventory
|
||||
from ansible.runner import Runner
|
||||
from ansible.playbook import PlayBook
|
||||
|
||||
from ansible import callbacks
|
||||
from ansible import utils
|
||||
from passlib.hash import sha512_crypt
|
||||
|
||||
# from utils import get_rand_pass
|
||||
|
||||
import random
|
||||
import os.path
|
||||
API_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
ANSIBLE_DIR = os.path.join(API_DIR, 'playbooks')
|
||||
|
||||
def get_rand_pass():
|
||||
"""
|
||||
get a reandom password.
|
||||
"""
|
||||
lower = [chr(i) for i in range(97,123)]
|
||||
upper = [chr(i).upper() for i in range(97,123)]
|
||||
digit = [str(i) for i in range(10)]
|
||||
password_pool = []
|
||||
password_pool.extend(lower)
|
||||
password_pool.extend(upper)
|
||||
password_pool.extend(digit)
|
||||
pass_list = [random.choice(password_pool) for i in range(1,14)]
|
||||
pass_list.insert(random.choice(range(1,14)), '@')
|
||||
pass_list.insert(random.choice(range(1,14)), random.choice(digit))
|
||||
password = ''.join(pass_list)
|
||||
return password
|
||||
|
||||
class AnsibleError(StandardError):
|
||||
"""
|
||||
the base AnsibleError which contains error(required),
|
||||
data(optional) and message(optional).
|
||||
存储所有Ansible 异常对象
|
||||
"""
|
||||
def __init__(self, error, data='', message=''):
|
||||
super(AnsibleError, self).__init__(message)
|
||||
self.error = error
|
||||
self.data = data
|
||||
self.message = message
|
||||
|
||||
|
||||
class CommandValueError(AnsibleError):
|
||||
"""
|
||||
indicate the input value has error or invalid.
|
||||
the data specifies the error field of input form.
|
||||
输入不合法 异常对象
|
||||
"""
|
||||
def __init__(self, field, message=''):
|
||||
super(CommandValueError, self).__init__('value:invalid', field, message)
|
||||
|
||||
|
||||
class MyInventory(object):
|
||||
"""
|
||||
this is my ansible inventory object.
|
||||
"""
|
||||
def __init__(self, resource):
|
||||
"""
|
||||
resource的数据格式是一个列表字典,比如
|
||||
{
|
||||
"group1": {
|
||||
"hosts": [{"hostname": "10.10.10.10", "port": "22", "username": "test", "password": "mypass"}, ...],
|
||||
"vars": {"var1": value1, "var2": value2, ...}
|
||||
}
|
||||
}
|
||||
|
||||
如果你只传入1个列表,这默认该列表内的所有主机属于my_group组,比如
|
||||
[{"hostname": "10.10.10.10", "port": "22", "username": "test", "password": "mypass"}, ...]
|
||||
"""
|
||||
self.resource = resource
|
||||
self.inventory = Inventory()
|
||||
self.gen_inventory()
|
||||
|
||||
def add_group(self, hosts, groupname, groupvars=None):
|
||||
"""
|
||||
add hosts to a group
|
||||
"""
|
||||
my_group = Group(name=groupname)
|
||||
|
||||
# if group variables exists, add them to group
|
||||
if groupvars:
|
||||
for key, value in groupvars.iteritems():
|
||||
my_group.set_variable(key, value)
|
||||
|
||||
# add hosts to group
|
||||
for host in hosts:
|
||||
# set connection variables
|
||||
hostname = host.get("hostname")
|
||||
hostport = host.get("port")
|
||||
username = host.get("username")
|
||||
password = host.get("password")
|
||||
my_host = Host(name=hostname, port=hostport)
|
||||
my_host.set_variable('ansible_ssh_host', hostname)
|
||||
my_host.set_variable('ansible_ssh_port', hostport)
|
||||
my_host.set_variable('ansible_ssh_user', username)
|
||||
my_host.set_variable('ansible_ssh_pass', password)
|
||||
# set other variables
|
||||
for key, value in host.iteritems():
|
||||
if key not in ["hostname", "port", "username", "password"]:
|
||||
my_host.set_variable(key, value)
|
||||
# add to group
|
||||
my_group.add_host(my_host)
|
||||
|
||||
self.inventory.add_group(my_group)
|
||||
|
||||
def gen_inventory(self):
|
||||
"""
|
||||
add hosts to inventory.
|
||||
"""
|
||||
if isinstance(self.resource, list):
|
||||
self.add_group(self.resource, 'my_group')
|
||||
elif isinstance(self.resource, dict):
|
||||
for groupname, hosts_and_vars in self.resource.iteritems():
|
||||
self.add_group(hosts_and_vars.get("hosts"), groupname, hosts_and_vars.get("vars"))
|
||||
|
||||
|
||||
class Command(MyInventory):
|
||||
"""
|
||||
this is a command object for parallel execute command.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Command, self).__init__(*args, **kwargs)
|
||||
self.results = ''
|
||||
|
||||
def run(self, command, module_name="command", timeout=5, forks=10, group='my_group'):
|
||||
"""
|
||||
run command from andible ad-hoc.
|
||||
command : 必须是一个需要执行的命令字符串, 比如
|
||||
'uname -a'
|
||||
"""
|
||||
if module_name not in ["raw", "command", "shell"]:
|
||||
raise CommandValueError("module_name",
|
||||
"module_name must be of the 'raw, command, shell'")
|
||||
hoc = Runner(module_name=module_name,
|
||||
module_args=command,
|
||||
timeout=timeout,
|
||||
inventory=self.inventory,
|
||||
subset=group,
|
||||
forks=forks
|
||||
)
|
||||
self.results = hoc.run()
|
||||
|
||||
if self.stdout:
|
||||
return {"ok": self.stdout}
|
||||
else:
|
||||
msg = []
|
||||
if self.stderr:
|
||||
msg.append(self.stderr)
|
||||
if self.dark:
|
||||
msg.append(self.dark)
|
||||
return {"failed": msg}
|
||||
|
||||
@property
|
||||
def raw_results(self):
|
||||
"""
|
||||
get the ansible raw results.
|
||||
"""
|
||||
return self.results
|
||||
|
||||
@property
|
||||
def exec_time(self):
|
||||
"""
|
||||
get the command execute time.
|
||||
"""
|
||||
result = {}
|
||||
all = self.results.get("contacted")
|
||||
for key, value in all.iteritems():
|
||||
result[key] = {
|
||||
"start": value.get("start"),
|
||||
"end" : value.get("end"),
|
||||
"delta": value.get("delta"),}
|
||||
return result
|
||||
|
||||
@property
|
||||
def stdout(self):
|
||||
"""
|
||||
get the comamnd standard output.
|
||||
"""
|
||||
result = {}
|
||||
all = self.results.get("contacted")
|
||||
for key, value in all.iteritems():
|
||||
result[key] = value.get("stdout")
|
||||
return result
|
||||
|
||||
@property
|
||||
def stderr(self):
|
||||
"""
|
||||
get the command standard error.
|
||||
"""
|
||||
result = {}
|
||||
all = self.results.get("contacted")
|
||||
for key, value in all.iteritems():
|
||||
result[key] = {
|
||||
"stderr": value.get("stderr"),
|
||||
"warnings": value.get("warnings"),}
|
||||
return result
|
||||
|
||||
@property
|
||||
def dark(self):
|
||||
"""
|
||||
get the dark results.
|
||||
"""
|
||||
return self.results.get("dark")
|
||||
|
||||
|
||||
class Tasks(Command):
|
||||
"""
|
||||
this is a tasks object for include the common command.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Tasks, self).__init__(*args, **kwargs)
|
||||
|
||||
def __run(self, module_args, module_name="command", timeout=5, forks=10, group='my_group'):
|
||||
"""
|
||||
run command from andible ad-hoc.
|
||||
command : 必须是一个需要执行的命令字符串, 比如
|
||||
'uname -a'
|
||||
"""
|
||||
hoc = Runner(module_name=module_name,
|
||||
module_args=module_args,
|
||||
timeout=timeout,
|
||||
inventory=self.inventory,
|
||||
subset=group,
|
||||
forks=forks
|
||||
)
|
||||
|
||||
self.results = hoc.run()
|
||||
|
||||
@property
|
||||
def msg(self):
|
||||
"""
|
||||
get the contacted and dark msg
|
||||
"""
|
||||
msg = {}
|
||||
for result in ["contacted", "dark"]:
|
||||
all = self.results.get(result)
|
||||
for key, value in all.iteritems():
|
||||
if value.get("msg"):
|
||||
msg[key] = value.get("msg")
|
||||
return msg
|
||||
|
||||
def push_key(self, user, key_path):
|
||||
"""
|
||||
push the ssh authorized key to target.
|
||||
"""
|
||||
module_args = 'user="%s" key="{{ lookup("file", "%s") }}"' % (user, key_path)
|
||||
self.__run(module_args, "authorized_key")
|
||||
|
||||
return {"status": "failed","msg": self.msg} if self.msg else {"status": "ok"}
|
||||
|
||||
def del_key(self, user, key_path):
|
||||
"""
|
||||
push the ssh authorized key to target.
|
||||
"""
|
||||
module_args = 'user="%s" key="{{ lookup("file", "%s") }}" state="absent"' % (user, key_path)
|
||||
self.__run(module_args, "authorized_key")
|
||||
|
||||
return {"status": "failed","msg": self.msg} if self.msg else {"status": "ok"}
|
||||
|
||||
def add_user(self, username, password):
|
||||
"""
|
||||
add a host user.
|
||||
"""
|
||||
encrypt_pass = sha512_crypt.encrypt(password)
|
||||
module_args = 'name=%s shell=/bin/bash password=%s' % (username, encrypt_pass)
|
||||
self.__run(module_args, "user")
|
||||
|
||||
return {"status": "failed","msg": self.msg} if self.msg else {"status": "ok"}
|
||||
|
||||
def add_multi_user(self, *args):
|
||||
"""
|
||||
add multi user
|
||||
:param args:
|
||||
user
|
||||
:return:
|
||||
"""
|
||||
results = {}
|
||||
users = {}
|
||||
action = results["action_info"] = {}
|
||||
for user in args:
|
||||
users[user] = get_rand_pass()
|
||||
for user, password in users.iteritems():
|
||||
ret = self.add_user(user, password)
|
||||
action[user] = ret
|
||||
results["user_info"] = users
|
||||
|
||||
return results
|
||||
|
||||
def del_user(self, username):
|
||||
"""
|
||||
delete a host user.
|
||||
"""
|
||||
module_args = 'name=%s state=absent remove=yes move_home=yes force=yes' % (username)
|
||||
self.__run(module_args, "user")
|
||||
|
||||
return {"status": "failed","msg": self.msg} if self.msg else {"status": "ok"}
|
||||
|
||||
def add_init_users(self):
|
||||
"""
|
||||
add initail users: SA, DBA, DEV
|
||||
"""
|
||||
results = {}
|
||||
action = results["action_info"] = {}
|
||||
users = {"SA": get_rand_pass(), "DBA": get_rand_pass(), "DEV": get_rand_pass()}
|
||||
for user, password in users.iteritems():
|
||||
ret = self.add_user(user, password)
|
||||
action[user] = ret
|
||||
results["user_info"] = users
|
||||
|
||||
return results
|
||||
|
||||
def del_init_users(self):
|
||||
"""
|
||||
delete initail users: SA, DBA, DEV
|
||||
"""
|
||||
results = {}
|
||||
action = results["action_info"] = {}
|
||||
for user in ["SA", "DBA", "DEV"]:
|
||||
ret = self.del_user(user)
|
||||
action[user] = ret
|
||||
return results
|
||||
|
||||
def get_host_info(self):
|
||||
"""
|
||||
use the setup module get host informations
|
||||
:return:
|
||||
all_ip is list
|
||||
processor_count is int
|
||||
system_dist_version is string
|
||||
system_type is string
|
||||
disk is dict (device_name: device_size}
|
||||
system_dist is string
|
||||
processor_type is string
|
||||
default_ip is string
|
||||
hostname is string
|
||||
product_sn is string
|
||||
memory_total is int (MB)
|
||||
default_mac is string
|
||||
product_name is string
|
||||
"""
|
||||
self.__run('', 'setup')
|
||||
|
||||
result = {}
|
||||
all = self.results.get("contacted")
|
||||
for key, value in all.iteritems():
|
||||
setup =value.get("ansible_facts")
|
||||
# get disk informations
|
||||
disk_all = setup.get("ansible_devices")
|
||||
disk_need = {}
|
||||
for disk_name, disk_info in disk_all.iteritems():
|
||||
if disk_name.startswith('sd') or disk_name.startswith('hd') or disk_name.startswith('vd'):
|
||||
disk_need[disk_name] = disk_info.get("size")
|
||||
|
||||
result[key] = {
|
||||
"other_ip": setup.get("ansible_all_ipv4_addresses"),
|
||||
"hostname": setup.get("ansible_hostname" ),
|
||||
"ip": setup.get("ansible_default_ipv4").get("address"),
|
||||
"mac": setup.get("ansible_default_ipv4").get("macaddress"),
|
||||
"brand": setup.get("ansible_product_name"),
|
||||
"cpu_type": setup.get("ansible_processor"),
|
||||
"cpu_cores": setup.get("ansible_processor_count"),
|
||||
"memory": setup.get("ansible_memtotal_mb"),
|
||||
"disk": disk_need,
|
||||
"system_type": setup.get("ansible_distribution"),
|
||||
"system_version": setup.get("ansible_distribution_version"),
|
||||
"asset_type": setup.get("ansible_system"),
|
||||
"sn": setup.get("ansible_product_serial")
|
||||
}
|
||||
|
||||
return {"status": "failed", "msg": self.msg} if self.msg else {"status": "ok", "result": result}
|
||||
|
||||
|
||||
class CustomAggregateStats(callbacks.AggregateStats):
|
||||
"""
|
||||
Holds stats about per-host activity during playbook runs.
|
||||
"""
|
||||
def __init__(self):
|
||||
super(CustomAggregateStats, self).__init__()
|
||||
self.results = []
|
||||
|
||||
def compute(self, runner_results, setup=False, poll=False,
|
||||
ignore_errors=False):
|
||||
"""
|
||||
Walk through all results and increment stats.
|
||||
"""
|
||||
super(CustomAggregateStats, self).compute(runner_results, setup, poll,
|
||||
ignore_errors)
|
||||
|
||||
self.results.append(runner_results)
|
||||
|
||||
|
||||
def summarize(self, host):
|
||||
"""
|
||||
Return information about a particular host
|
||||
"""
|
||||
summarized_info = super(CustomAggregateStats, self).summarize(host)
|
||||
|
||||
# Adding the info I need
|
||||
summarized_info['result'] = self.results
|
||||
|
||||
return summarized_info
|
||||
|
||||
|
||||
class MyPlaybook(MyInventory):
|
||||
"""
|
||||
this is my playbook object for execute playbook.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MyPlaybook, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
def run(self, playbook_relational_path, extra_vars=None):
|
||||
"""
|
||||
run ansible playbook,
|
||||
only surport relational path.
|
||||
"""
|
||||
stats = callbacks.AggregateStats()
|
||||
playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)
|
||||
runner_cb = callbacks.PlaybookRunnerCallbacks(stats, verbose=utils.VERBOSITY)
|
||||
playbook_path = os.path.join(ANSIBLE_DIR, playbook_relational_path)
|
||||
|
||||
pb = PlayBook(
|
||||
playbook = playbook_path,
|
||||
stats = stats,
|
||||
callbacks = playbook_cb,
|
||||
runner_callbacks = runner_cb,
|
||||
inventory = self.inventory,
|
||||
extra_vars = extra_vars,
|
||||
check=False)
|
||||
|
||||
self.results = pb.run()
|
||||
|
||||
@property
|
||||
def raw_results(self):
|
||||
"""
|
||||
get the raw results after playbook run.
|
||||
"""
|
||||
return self.results
|
||||
|
||||
|
||||
class App(MyPlaybook):
|
||||
"""
|
||||
this is a app object for inclue the common playbook.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(App, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
|
||||
|
|
@ -1,5 +1,9 @@
|
|||
# coding: utf-8
|
||||
import xlrd
|
||||
import xlsxwriter
|
||||
from django.db.models import AutoField
|
||||
from jumpserver.api import *
|
||||
from jasset.models import ASSET_STATUS, ASSET_TYPE, ASSET_ENV, IDC, AssetRecord
|
||||
|
||||
|
||||
def group_add_asset(group, asset_id=None, asset_ip=None):
|
||||
|
@ -32,6 +36,21 @@ def db_add_group(**kwargs):
|
|||
group_add_asset(group, asset_id)
|
||||
|
||||
|
||||
def db_update_group(**kwargs):
|
||||
"""
|
||||
add a asset group in database
|
||||
数据库中更新资产
|
||||
"""
|
||||
group_id = kwargs.pop('id')
|
||||
asset_id_list = kwargs.pop('asset_select')
|
||||
group = get_object(AssetGroup, id=group_id)
|
||||
|
||||
for asset_id in asset_id_list:
|
||||
group_add_asset(group, asset_id)
|
||||
|
||||
AssetGroup.objects.filter(id=group_id).update(**kwargs)
|
||||
|
||||
|
||||
def db_asset_add(**kwargs):
|
||||
"""
|
||||
add asset to db
|
||||
|
@ -80,11 +99,12 @@ def db_asset_update(**kwargs):
|
|||
asset_id = kwargs.pop('id')
|
||||
Asset.objects.filter(id=asset_id).update(**kwargs)
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
# def batch_host_edit(host_info, j_user='', j_password=''):
|
||||
# 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_info
|
||||
# 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'}
|
||||
|
@ -156,3 +176,230 @@ def db_asset_update(**kwargs):
|
|||
# else:
|
||||
# return httperror(request, '删除失败, 没有这个IDC!')
|
||||
|
||||
|
||||
def sort_ip_list(ip_list):
|
||||
""" ip地址排序 """
|
||||
ip_list.sort(key=lambda s: map(int, s.split('.')))
|
||||
return ip_list
|
||||
|
||||
|
||||
def get_tuple_name(asset_tuple, value):
|
||||
""""""
|
||||
for t in asset_tuple:
|
||||
if t[0] == value:
|
||||
return t[1]
|
||||
|
||||
return ''
|
||||
|
||||
|
||||
def get_tuple_diff(asset_tuple, field_name, value):
|
||||
""""""
|
||||
old_name = get_tuple_name(asset_tuple, int(value[0])) if value[0] else u''
|
||||
new_name = get_tuple_name(asset_tuple, int(value[1])) if value[1] else u''
|
||||
alert_info = [field_name, old_name, new_name]
|
||||
return alert_info
|
||||
|
||||
|
||||
def asset_diff(before, after):
|
||||
"""
|
||||
asset change before and after
|
||||
"""
|
||||
alter_dic = {}
|
||||
before_dic, after_dic = before, dict(after.iterlists())
|
||||
for k, v in before_dic.items():
|
||||
after_dic_values = after_dic.get(k, [])
|
||||
if k == 'group':
|
||||
after_dic_value = after_dic_values if len(after_dic_values) > 0 else u''
|
||||
uv = v if v is not None else u''
|
||||
else:
|
||||
after_dic_value = after_dic_values[0] if len(after_dic_values) > 0 else u''
|
||||
uv = unicode(v) if v is not None else u''
|
||||
if uv != after_dic_value:
|
||||
alter_dic.update({k: [uv, after_dic_value]})
|
||||
|
||||
for k, v in alter_dic.items():
|
||||
if v == [None, u'']:
|
||||
alter_dic.pop(k)
|
||||
|
||||
return alter_dic
|
||||
|
||||
|
||||
def asset_diff_one(before, after):
|
||||
print before.__dict__, after.__dict__
|
||||
fields = Asset._meta.get_all_field_names()
|
||||
for field in fields:
|
||||
print before.field, after.field
|
||||
|
||||
|
||||
def db_asset_alert(asset, username, alert_dic):
|
||||
"""
|
||||
asset alert info to db
|
||||
"""
|
||||
alert_list = []
|
||||
asset_tuple_dic = {'status': ASSET_STATUS, 'env': ASSET_ENV, 'asset_type': ASSET_TYPE}
|
||||
for field, value in alert_dic.iteritems():
|
||||
print field
|
||||
field_name = Asset._meta.get_field_by_name(field)[0].verbose_name
|
||||
if field == 'idc':
|
||||
old = IDC.objects.filter(id=value[0]) if value[0] else u''
|
||||
new = IDC.objects.filter(id=value[1]) if value[1] else u''
|
||||
old_name = old[0].name if old else u''
|
||||
new_name = new[0].name if new else u''
|
||||
alert_info = [field_name, old_name, new_name]
|
||||
|
||||
elif field in ['status', 'env', 'asset_type']:
|
||||
alert_info = get_tuple_diff(asset_tuple_dic.get(field), field_name, value)
|
||||
|
||||
elif field == 'group':
|
||||
old, new = [], []
|
||||
for group_id in value[0]:
|
||||
group_name = AssetGroup.objects.get(id=int(group_id)).name
|
||||
old.append(group_name)
|
||||
for group_id in value[1]:
|
||||
group_name = AssetGroup.objects.get(id=int(group_id)).name
|
||||
new.append(group_name)
|
||||
if old == new:
|
||||
continue
|
||||
else:
|
||||
alert_info = [field_name, ','.join(old), ','.join(new)]
|
||||
|
||||
elif field == 'use_default_auth':
|
||||
if unicode(value[0]) == 'True' and unicode(value[1]) == 'on' or \
|
||||
unicode(value[0]) == 'False' and unicode(value[1]) == '':
|
||||
continue
|
||||
else:
|
||||
name = asset.username
|
||||
alert_info = [field_name, u'默认', name] if unicode(value[0]) == 'True' else \
|
||||
[field_name, name, u'默认']
|
||||
|
||||
elif field in ['username', 'password']:
|
||||
continue
|
||||
|
||||
elif field == 'is_active':
|
||||
if unicode(value[0]) == 'True' and unicode(value[1]) == '1' or \
|
||||
unicode(value[0]) == 'False' and unicode(value[1]) == '0':
|
||||
continue
|
||||
else:
|
||||
alert_info = [u'是否激活', u'激活', u'禁用'] if unicode(value[0]) == 'True' else \
|
||||
[u'是否激活', u'禁用', u'激活']
|
||||
|
||||
else:
|
||||
alert_info = [field_name, unicode(value[0]), unicode(value[1])]
|
||||
|
||||
if 'alert_info' in dir():
|
||||
alert_list.append(alert_info)
|
||||
|
||||
if alert_list:
|
||||
AssetRecord.objects.create(asset=asset, username=username, content=alert_list)
|
||||
|
||||
|
||||
def write_excel(asset_all):
|
||||
data = []
|
||||
now = datetime.datetime.now().strftime('%Y_%m_%d_%H_%M')
|
||||
file_name = 'cmdb_excel_' + now + '.xlsx'
|
||||
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'备注']
|
||||
for asset in asset_all:
|
||||
group_list = []
|
||||
for p in asset.group.all():
|
||||
group_list.append(p.name)
|
||||
|
||||
group_all = '/'.join(group_list)
|
||||
status = asset.get_status_display()
|
||||
idc_name = asset.idc.name if asset.idc else u''
|
||||
alter_dic = [asset.hostname, asset.ip, idc_name, asset.mac, asset.remote_ip, asset.cpu, asset.memory,
|
||||
asset.disk, (asset.system_type + asset.system_version), asset.cabinet, group_all, status,
|
||||
asset.comment]
|
||||
data.append(alter_dic)
|
||||
format = workbook.add_format()
|
||||
format.set_border(1)
|
||||
format.set_align('center')
|
||||
|
||||
format_title = workbook.add_format()
|
||||
format_title.set_border(1)
|
||||
format_title.set_bg_color('#cccccc')
|
||||
format_title.set_align('center')
|
||||
format_title.set_bold()
|
||||
|
||||
format_ave = workbook.add_format()
|
||||
format_ave.set_border(1)
|
||||
format_ave.set_num_format('0.00')
|
||||
|
||||
worksheet.write_row('A1', title, format_title)
|
||||
i = 2
|
||||
for alter_dic in data:
|
||||
location = 'A' + str(i)
|
||||
worksheet.write_row(location, alter_dic, format)
|
||||
i += 1
|
||||
|
||||
workbook.close()
|
||||
ret = (True, file_name)
|
||||
return ret
|
||||
|
||||
|
||||
def copy_model_instance(obj):
|
||||
initial = dict([(f.name, getattr(obj, f.name))
|
||||
for f in obj._meta.fields
|
||||
if not isinstance(f, AutoField) and \
|
||||
not f in obj._meta.parents.values()])
|
||||
return obj.__class__(**initial)
|
||||
|
||||
|
||||
def ansible_record(asset, ansible_dic, username):
|
||||
alert_dic = {}
|
||||
asset_dic = asset.__dict__
|
||||
for field, value in ansible_dic.items():
|
||||
old = asset_dic.get(field)
|
||||
new = ansible_dic.get(field)
|
||||
if unicode(old) != unicode(new):
|
||||
print old, new, type(old), type(new)
|
||||
setattr(asset, field, value)
|
||||
asset.save()
|
||||
alert_dic[field] = [old, new]
|
||||
|
||||
db_asset_alert(asset, username, alert_dic)
|
||||
|
||||
|
||||
def excel_to_db(excel_file):
|
||||
"""
|
||||
Asset add batch function
|
||||
"""
|
||||
try:
|
||||
data = xlrd.open_workbook(filename=None, file_contents=excel_file.read())
|
||||
except Exception, e:
|
||||
return False
|
||||
|
||||
else:
|
||||
table = data.sheets()[0]
|
||||
rows = table.nrows
|
||||
group_instance = []
|
||||
for row_num in range(1, rows):
|
||||
row = table.row_values(row_num)
|
||||
if row:
|
||||
ip, port, hostname, use_default_auth, username, password, group = row
|
||||
print ip
|
||||
use_default_auth = 1 if use_default_auth == u'默认' else 0
|
||||
if get_object(Asset, ip=ip):
|
||||
continue
|
||||
if ip and port:
|
||||
asset = Asset(ip=ip,
|
||||
port=port,
|
||||
use_default_auth=use_default_auth,
|
||||
username=username,
|
||||
password=password
|
||||
)
|
||||
asset.save()
|
||||
group_list = group.split('/')
|
||||
for group_name in group_list:
|
||||
group = get_object(AssetGroup, name=group_name)
|
||||
if group:
|
||||
group_instance.append(group)
|
||||
if group_instance:
|
||||
print group_instance
|
||||
asset.group = group_instance
|
||||
asset.save()
|
||||
return True
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# coding:utf-8
|
||||
from django import forms
|
||||
|
||||
from jasset.models import IDC, Asset, AssetGroup
|
||||
|
||||
|
||||
class AssetForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = Asset
|
||||
|
||||
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"
|
||||
]
|
||||
|
||||
|
||||
class AssetGroupForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = AssetGroup
|
||||
fields = [
|
||||
"name", "comment"
|
||||
]
|
||||
|
||||
|
||||
class IdcForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = IDC
|
||||
fields = ['name', "bandwidth", "operator", 'linkman', 'phone', 'address', 'network', 'comment']
|
||||
|
||||
|
155
jasset/models.py
155
jasset/models.py
|
@ -1,6 +1,25 @@
|
|||
# coding: utf-8
|
||||
|
||||
import datetime
|
||||
from django.db import models
|
||||
# from juser.models import User, UserGroup
|
||||
from juser.models import User, UserGroup
|
||||
|
||||
ASSET_ENV = (
|
||||
(1, U'生产环境'),
|
||||
(2, U'测试环境')
|
||||
)
|
||||
|
||||
ASSET_STATUS = (
|
||||
(1, u"已使用"),
|
||||
(2, u"未使用"),
|
||||
(3, u"报废")
|
||||
)
|
||||
|
||||
ASSET_TYPE = (
|
||||
(1, u"服务器"),
|
||||
(2, u"网络设备"),
|
||||
(3, u"其他")
|
||||
)
|
||||
|
||||
|
||||
class AssetGroup(models.Model):
|
||||
|
@ -14,86 +33,74 @@ class AssetGroup(models.Model):
|
|||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
# def get_asset(self):
|
||||
# return self.asset_set.all()
|
||||
#
|
||||
# def get_asset_info(self, printable=False):
|
||||
# assets = self.get_asset()
|
||||
# ip_comment = {}
|
||||
# for asset in assets:
|
||||
# ip_comment[asset.ip] = asset.comment
|
||||
#
|
||||
# for ip in sorted(ip_comment):
|
||||
# if ip_comment[ip]:
|
||||
# print '%-15s -- %s' % (ip, ip_comment[ip])
|
||||
# else:
|
||||
# print '%-15s' % ip
|
||||
# print ''
|
||||
#
|
||||
# def get_asset_num(self):
|
||||
# return len(self.get_asset())
|
||||
#
|
||||
# def get_user_group(self):
|
||||
# perm_list = self.perm_set.all()
|
||||
# user_group_list = []
|
||||
# for perm in perm_list:
|
||||
# user_group_list.append(perm.user_group)
|
||||
# return user_group_list
|
||||
#
|
||||
# def get_user(self):
|
||||
# user_list = []
|
||||
# user_group_list = self.get_user_group()
|
||||
# for user_group in user_group_list:
|
||||
# user_list.extend(user_group.user_set.all())
|
||||
# return user_list
|
||||
#
|
||||
# def is_permed(self, user=None, user_group=None):
|
||||
# if user:
|
||||
# if user in self.get_user():
|
||||
# return True
|
||||
#
|
||||
# if user_group:
|
||||
# if user_group in self.get_user_group():
|
||||
# return True
|
||||
# return False
|
||||
|
||||
class IDC(models.Model):
|
||||
name = models.CharField(max_length=32, verbose_name=u'机房名称')
|
||||
bandwidth = models.CharField(max_length=32, blank=True, null=True, verbose_name=u'机房带宽')
|
||||
linkman = models.CharField(max_length=16, null=True, verbose_name=u'联系人')
|
||||
phone = models.CharField(max_length=32, 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地址段")
|
||||
date_added = models.DateField(auto_now=True, null=True)
|
||||
operator = models.IntegerField(blank=True, null=True, verbose_name=u"运营商")
|
||||
comment = models.CharField(max_length=128, blank=True, null=True, verbose_name=u"备注")
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = u"IDC机房"
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
|
||||
class Asset(models.Model):
|
||||
ip = models.GenericIPAddressField(unique=True)
|
||||
port = models.IntegerField()
|
||||
group = models.ManyToManyField(AssetGroup)
|
||||
username = models.CharField(max_length=20, blank=True, null=True)
|
||||
password = models.CharField(max_length=80, blank=True, null=True)
|
||||
use_default_auth = models.BooleanField(default=True)
|
||||
date_added = models.DateTimeField(auto_now_add=True)
|
||||
is_active = models.BooleanField(default=True)
|
||||
comment = models.CharField(max_length=100, blank=True, null=True)
|
||||
"""
|
||||
asset modle
|
||||
"""
|
||||
ip = models.GenericIPAddressField(unique=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"主机名")
|
||||
port = models.IntegerField(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"管理用户名")
|
||||
password = models.CharField(max_length=64, blank=True, null=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'机房')
|
||||
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'远控卡')
|
||||
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')
|
||||
memory = models.CharField(max_length=128, blank=True, null=True, verbose_name=u'内存')
|
||||
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"版本号")
|
||||
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'资产编号')
|
||||
status = models.IntegerField(choices=ASSET_STATUS, blank=True, null=True, default=1, verbose_name=u"机器状态")
|
||||
asset_type = models.IntegerField(choices=ASSET_TYPE, blank=True, null=True, verbose_name=u"主机类型")
|
||||
env = models.IntegerField(choices=ASSET_ENV, blank=True, null=True, verbose_name=u"运行环境")
|
||||
sn = models.CharField(max_length=128, blank=True, null=True, verbose_name=u"SN编号")
|
||||
date_added = models.DateTimeField(auto_now=True, null=True)
|
||||
is_active = models.BooleanField(default=True, verbose_name=u"是否激活")
|
||||
comment = models.CharField(max_length=128, blank=True, null=True, verbose_name=u"备注")
|
||||
|
||||
def __unicode__(self):
|
||||
return self.ip
|
||||
|
||||
# def get_user(self):
|
||||
# perm_list = []
|
||||
# asset_group_all = self.bis_group.all()
|
||||
# for asset_group in asset_group_all:
|
||||
# perm_list.extend(asset_group.perm_set.all())
|
||||
#
|
||||
# user_group_list = []
|
||||
# for perm in perm_list:
|
||||
# user_group_list.append(perm.user_group)
|
||||
#
|
||||
# user_permed_list = []
|
||||
# for user_group in user_group_list:
|
||||
# user_permed_list.extend(user_group.user_set.all())
|
||||
# user_permed_list = list(set(user_permed_list))
|
||||
# return user_permed_list
|
||||
|
||||
class AssetRecord(models.Model):
|
||||
asset = models.ForeignKey(Asset)
|
||||
username = models.CharField(max_length=30, null=True)
|
||||
alert_time = models.DateTimeField(auto_now_add=True)
|
||||
content = models.TextField(null=True, blank=True)
|
||||
comment = models.TextField(null=True, blank=True)
|
||||
|
||||
|
||||
class AssetAlias(models.Model):
|
||||
pass
|
||||
# user = models.ForeignKey(User)
|
||||
# asset = models.ForeignKey(Asset)
|
||||
# alias = models.CharField(max_length=100, blank=True, null=True)
|
||||
#
|
||||
# def __unicode__(self):
|
||||
# return self.alias
|
||||
user = models.ForeignKey(User)
|
||||
asset = models.ForeignKey(Asset)
|
||||
alias = models.CharField(max_length=100, blank=True, null=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.alias
|
||||
|
|
|
@ -4,23 +4,27 @@ from jasset.views import *
|
|||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^asset_add/$', asset_add),
|
||||
# url(r"^host_add_multi/$", host_add_batch),
|
||||
url(r'^group_add/$', group_add),
|
||||
url(r'^group_list/$', group_list),
|
||||
url(r"^asset_add_batch/$", asset_add_batch),
|
||||
url(r'^group_del/$', group_del),
|
||||
url(r'^asset_list/$', asset_list),
|
||||
url(r'^asset_del/$', asset_del),
|
||||
url(r"^asset_detail/$", asset_detail),
|
||||
url(r'^asset_edit/$', asset_edit),
|
||||
url(r'^asset_update/$', asset_update),
|
||||
# url(r'^search/$', host_search),
|
||||
# url(r"^host_detail/$", host_detail),
|
||||
# url(r"^dept_host_ajax/$", dept_host_ajax),
|
||||
# url(r"^show_all_ajax/$", show_all_ajax),
|
||||
# url(r'^group_edit/$', group_edit),
|
||||
# url(r'^group_list/$', group_list),
|
||||
# url(r'^group_detail/$', group_detail),
|
||||
url(r'^group_add/$', group_add),
|
||||
url(r'^group_list/$', group_list),
|
||||
url(r'^group_edit/$', group_edit),
|
||||
url(r'^group_list/$', group_list),
|
||||
url(r'^group_detail/$', group_detail),
|
||||
# url(r'^group_del_host/$', group_del_host),
|
||||
|
||||
# url(r'^host_edit/batch/$', host_edit_batch),
|
||||
url(r'^asset_edit_batch/$', asset_edit_batch),
|
||||
# url(r'^host_edit_common/batch/$', host_edit_common_batch),
|
||||
url(r'^idc_add/$', idc_add),
|
||||
url(r'^idc_list/$', idc_list),
|
||||
url(r'^idc_detail/$', idc_detail),
|
||||
url(r'^idc_edit/$', idc_edit),
|
||||
url(r'^idc_del/$', idc_del),
|
||||
url(r'^upload/$', asset_upload),
|
||||
)
|
401
jasset/views.py
401
jasset/views.py
|
@ -1,13 +1,13 @@
|
|||
# coding:utf-8
|
||||
|
||||
import ast
|
||||
|
||||
from django.db.models import Q
|
||||
from django.template import RequestContext
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
from jasset.asset_api import *
|
||||
from jumpserver.api import *
|
||||
from jasset.forms import AssetForm, IdcForm
|
||||
from jasset.models import Asset, IDC, AssetGroup, ASSET_TYPE, ASSET_STATUS
|
||||
from ansible_api import Tasks
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
|
@ -36,13 +36,69 @@ def group_add(request):
|
|||
|
||||
except ServerError:
|
||||
pass
|
||||
|
||||
else:
|
||||
db_add_group(name=name, comment=comment, asset_select=asset_select)
|
||||
msg = u"主机组 %s 添加成功" % name
|
||||
smg = u"主机组 %s 添加成功" % name
|
||||
|
||||
return my_render('jasset/group_add.html', locals(), request)
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
def group_edit(request):
|
||||
"""
|
||||
Edit asset group
|
||||
编辑资产组
|
||||
"""
|
||||
header_title, path1, path2 = u'编辑主机组', u'资产管理', u'编辑主机组'
|
||||
group_id = request.GET.get('id', '')
|
||||
group = get_object(AssetGroup, id=group_id)
|
||||
|
||||
asset_all = Asset.objects.all()
|
||||
asset_select = Asset.objects.filter(group=group)
|
||||
asset_no_select = [a for a in asset_all if a not in asset_select]
|
||||
|
||||
if request.method == 'POST':
|
||||
name = request.POST.get('name', '')
|
||||
asset_select = request.POST.getlist('asset_select', [])
|
||||
comment = request.POST.get('comment', '')
|
||||
|
||||
try:
|
||||
if not name:
|
||||
emg = u'组名不能为空'
|
||||
raise ServerError(emg)
|
||||
|
||||
if group.name != name:
|
||||
asset_group_test = get_object(AssetGroup, name=name)
|
||||
if asset_group_test:
|
||||
emg = u"该组名 %s 已存在" % name
|
||||
raise ServerError(emg)
|
||||
|
||||
except ServerError:
|
||||
pass
|
||||
|
||||
else:
|
||||
group.asset_set.clear()
|
||||
db_update_group(id=group_id, name=name, comment=comment, asset_select=asset_select)
|
||||
smg = u"主机组 %s 添加成功" % name
|
||||
|
||||
return HttpResponseRedirect('/jasset/group_list')
|
||||
|
||||
return my_render('jasset/group_edit.html', locals(), request)
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
def group_detail(request):
|
||||
""" 主机组详情 """
|
||||
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')
|
||||
def group_list(request):
|
||||
"""
|
||||
|
@ -85,23 +141,13 @@ def asset_add(request):
|
|||
"""
|
||||
header_title, path1, path2 = u'添加资产', u'资产管理', u'添加资产'
|
||||
asset_group_all = AssetGroup.objects.all()
|
||||
af = AssetForm()
|
||||
if request.method == 'POST':
|
||||
ip = request.POST.get('ip')
|
||||
groups = request.POST.getlist('groups')
|
||||
use_default = True if request.POST.getlist('use_default', []) else False
|
||||
is_active = True if request.POST.get('is_active') else False
|
||||
comment = request.POST.get('comment')
|
||||
|
||||
if not use_default:
|
||||
username = request.POST.get('username')
|
||||
password = request.POST.get('password')
|
||||
port = request.POST.get('port')
|
||||
password_encode = CRYPTOR.encrypt(password)
|
||||
else:
|
||||
username = None
|
||||
port = None
|
||||
password_encode = None
|
||||
|
||||
af_post = AssetForm(request.POST)
|
||||
print af_post
|
||||
ip = request.POST.get('ip', '')
|
||||
is_active = True if request.POST.get('is_active') == '1' else False
|
||||
use_default_auth = request.POST.get('use_default_auth', '')
|
||||
try:
|
||||
if Asset.objects.filter(ip=str(ip)):
|
||||
error = u'该IP %s 已存在!' % ip
|
||||
|
@ -110,34 +156,27 @@ def asset_add(request):
|
|||
except ServerError:
|
||||
pass
|
||||
else:
|
||||
db_asset_add(
|
||||
ip=ip, port=port, use_default=use_default, is_active=is_active, comment=comment,
|
||||
groups=groups, username=username, password=password_encode
|
||||
)
|
||||
if af_post.is_valid():
|
||||
asset_save = af_post.save(commit=False)
|
||||
if not use_default_auth:
|
||||
password = request.POST.get('password', '')
|
||||
password_encode = CRYPTOR.encrypt(password)
|
||||
asset_save.password = password_encode
|
||||
asset_save.is_active = True if is_active else False
|
||||
asset_save.save()
|
||||
af_post.save_m2m()
|
||||
|
||||
msg = u'主机 %s 添加成功' % ip
|
||||
msg = u'主机 %s 添加成功' % ip
|
||||
else:
|
||||
esg = u'主机 %s 添加失败' % ip
|
||||
|
||||
return my_render('jasset/asset_add.html', locals(), request)
|
||||
|
||||
|
||||
@require_role(role='user')
|
||||
def asset_list(request):
|
||||
"""
|
||||
list assets
|
||||
列出资产表
|
||||
"""
|
||||
header_title, path1, path2 = u'查看主机', u'资产管理', u'查看主机'
|
||||
keyword = request.GET.get('keyword', '')
|
||||
gid = request.GET.get('gid', '') # asset group id
|
||||
sid = request.GET.get('sid', '')
|
||||
assets_list = Asset.objects.all().order_by('ip')
|
||||
|
||||
if keyword:
|
||||
assets_list = assets_list.filter(Q(ip__contains=keyword) |
|
||||
Q(comment__contains=keyword)).distinct().order_by('ip')
|
||||
|
||||
assets_list, p, assets, page_range, current_page, show_first, show_end = pages(assets_list, request)
|
||||
return my_render('jasset/asset_list.html', locals(), request)
|
||||
@require_role('admin')
|
||||
def asset_add_batch(request):
|
||||
header_title, path1, path2 = u'添加资产', u'资产管理', u'批量添加'
|
||||
return my_render('jasset/asset_add_batch.html', locals(), request)
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
|
@ -149,64 +188,280 @@ def asset_del(request):
|
|||
asset_id = request.GET.get('id', '')
|
||||
if asset_id:
|
||||
Asset.objects.filter(id=asset_id).delete()
|
||||
return HttpResponse(u'删除成功')
|
||||
return Http404
|
||||
|
||||
if request.method == 'POST':
|
||||
asset_batch = request.GET.get('arg', '')
|
||||
asset_id_all = str(request.POST.get('asset_id_all', ''))
|
||||
|
||||
if asset_batch:
|
||||
for asset_id in asset_id_all.split(','):
|
||||
asset = get_object(Asset, id=asset_id)
|
||||
asset.delete()
|
||||
|
||||
return HttpResponse(u'删除成功')
|
||||
|
||||
|
||||
@require_role(role='super')
|
||||
def asset_edit(request):
|
||||
""" 修改主机 """
|
||||
"""
|
||||
edit a asset
|
||||
修改主机
|
||||
"""
|
||||
header_title, path1, path2 = u'修改资产', u'资产管理', u'修改资产'
|
||||
|
||||
asset_id = request.GET.get('id', '')
|
||||
if not asset_id:
|
||||
return HttpResponse('没有该主机')
|
||||
username = request.session.get('username', 'admin')
|
||||
asset = get_object(Asset, id=asset_id)
|
||||
|
||||
asset_old = copy_model_instance(asset)
|
||||
af = AssetForm(instance=asset)
|
||||
if request.method == 'POST':
|
||||
ip = request.POST.get('ip')
|
||||
groups = request.POST.getlist('groups')
|
||||
use_default = True if request.POST.getlist('use_default', []) else False
|
||||
is_active = True if request.POST.get('is_active') else False
|
||||
comment = request.POST.get('comment')
|
||||
|
||||
if not use_default:
|
||||
username = request.POST.get('username')
|
||||
password = request.POST.get('password')
|
||||
port = request.POST.get('port')
|
||||
if password == asset.password:
|
||||
password_encode = password
|
||||
else:
|
||||
password_encode = CRYPTOR.encrypt(password)
|
||||
else:
|
||||
username = None
|
||||
password_encode = None
|
||||
port = 22
|
||||
af_post = AssetForm(request.POST, instance=asset)
|
||||
ip = request.POST.get('ip', '')
|
||||
use_default_auth = request.POST.get('use_default_auth')
|
||||
|
||||
try:
|
||||
asset_test = get_object(Asset, ip=ip)
|
||||
if asset_test and asset_id != str(asset_test.id):
|
||||
if asset_test and asset_id != unicode(asset_test.id):
|
||||
error = u'该IP %s 已存在!' % ip
|
||||
raise ServerError(error)
|
||||
except ServerError:
|
||||
pass
|
||||
else:
|
||||
db_asset_update(id=asset_id, ip=ip, port=port, use_default=use_default,
|
||||
username=username, password=password_encode,
|
||||
is_active=is_active, comment=comment)
|
||||
msg = u'主机 %s 修改成功' % ip
|
||||
if af_post.is_valid():
|
||||
af_save = af_post.save(commit=False)
|
||||
if use_default_auth:
|
||||
af_save.username = ''
|
||||
af_save.password = ''
|
||||
af_save.save()
|
||||
af_post.save_m2m()
|
||||
# asset_new = get_object(Asset, id=asset_id)
|
||||
# asset_diff_one(asset_old, asset_new)
|
||||
info = asset_diff(af_post.__dict__.get('initial'), request.POST)
|
||||
db_asset_alert(asset, username, info)
|
||||
|
||||
msg = u'主机 %s 修改成功' % ip
|
||||
else:
|
||||
emg = u'主机 %s 修改失败' % ip
|
||||
return HttpResponseRedirect('/jasset/asset_detail/?id=%s' % asset_id)
|
||||
|
||||
return my_render('jasset/asset_edit.html', locals(), request)
|
||||
|
||||
|
||||
@require_role('user')
|
||||
def asset_list(request):
|
||||
"""
|
||||
asset list view
|
||||
"""
|
||||
idc_all = IDC.objects.filter()
|
||||
asset_group_all = AssetGroup.objects.all()
|
||||
asset_types = ASSET_TYPE
|
||||
asset_status = ASSET_STATUS
|
||||
|
||||
idc_name = request.GET.get('idc', '')
|
||||
group_name = request.GET.get('group', '')
|
||||
asset_type = request.GET.get('asset_type', '')
|
||||
status = request.GET.get('status', '')
|
||||
keyword = request.GET.get('keyword', '')
|
||||
export = request.GET.get("export", False)
|
||||
|
||||
asset_find = Asset.objects.all()
|
||||
if idc_name:
|
||||
asset_find = asset_find.filter(idc__name__contains=idc_name)
|
||||
|
||||
if group_name:
|
||||
asset_find = asset_find.filter(group__name__contains=group_name)
|
||||
|
||||
if asset_type:
|
||||
asset_find = asset_find.filter(asset_type__contains=asset_type)
|
||||
|
||||
if status:
|
||||
asset_find = asset_find.filter(status__contains=status)
|
||||
|
||||
if keyword:
|
||||
asset_find = asset_find.filter(
|
||||
Q(hostname__contains=keyword) |
|
||||
Q(other_ip__contains=keyword) |
|
||||
Q(ip__contains=keyword) |
|
||||
Q(remote_ip__contains=keyword) |
|
||||
Q(comment__contains=keyword) |
|
||||
Q(group__name__contains=keyword) |
|
||||
Q(cpu__contains=keyword) |
|
||||
Q(memory__contains=keyword) |
|
||||
Q(disk__contains=keyword))
|
||||
|
||||
if export:
|
||||
s = write_excel(asset_find)
|
||||
if s[0]:
|
||||
file_name = s[1]
|
||||
smg = '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)
|
||||
return my_render('jasset/asset_list.html', locals(), request)
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
def asset_edit_batch(request):
|
||||
af = AssetForm()
|
||||
asset_group_all = AssetGroup.objects.all()
|
||||
return my_render('jasset/asset_edit_batch.html', locals(), request)
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
def asset_detail(request):
|
||||
""" 主机详情 """
|
||||
"""
|
||||
Asset detail view
|
||||
"""
|
||||
header_title, path1, path2 = u'主机详细信息', u'资产管理', u'主机详情'
|
||||
asset_id = request.GET.get('id', '')
|
||||
asset = get_object(Asset, id=asset_id)
|
||||
asset_record = AssetRecord.objects.filter(asset=asset).order_by('-alert_time')
|
||||
|
||||
return my_render('jasset/asset_detail.html', locals(), request)
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
def asset_update(request):
|
||||
"""
|
||||
Asset update host info via ansible view
|
||||
"""
|
||||
asset_id = request.GET.get('id', '')
|
||||
asset = get_object(Asset, id=asset_id)
|
||||
if not asset:
|
||||
return HttpResponseRedirect('/jasset/asset_detail/?id=%s' % asset_id)
|
||||
name = request.session.get('username', 'admin')
|
||||
if asset.use_default_auth:
|
||||
username = 'root'
|
||||
password = '123456'
|
||||
else:
|
||||
username = asset.username
|
||||
password = asset.password
|
||||
|
||||
resource = [{"hostname": asset.ip, "port": asset.port,
|
||||
"username": username, "password": password}]
|
||||
|
||||
ansible_instance = Tasks(resource)
|
||||
ansible_asset_info = ansible_instance.get_host_info()
|
||||
if ansible_asset_info['status'] == 'ok':
|
||||
asset_info = ansible_asset_info['result'][asset.ip]
|
||||
if asset_info:
|
||||
hostname = asset_info.get('hostname')
|
||||
other_ip = ','.join(asset_info.get('other_ip'))
|
||||
cpu_type = asset_info.get('cpu_type')[1]
|
||||
cpu_cores = asset_info.get('cpu_cores')
|
||||
cpu = cpu_type + ' * ' + unicode(cpu_cores)
|
||||
memory = asset_info.get('memory')
|
||||
disk = asset_info.get('disk')
|
||||
sn = asset_info.get('sn')
|
||||
brand = asset_info.get('brand')
|
||||
system_type = asset_info.get('system_type')
|
||||
system_version = asset_info.get('system_version')
|
||||
|
||||
asset_dic = {"hostname": hostname, "other_ip": other_ip, "cpu": cpu,
|
||||
"memory": memory, "disk": disk, "system_type": system_type,
|
||||
"system_version": system_version, "brand": brand, "sn": sn
|
||||
}
|
||||
|
||||
ansible_record(asset, asset_dic, name)
|
||||
|
||||
return HttpResponseRedirect('/jasset/asset_detail/?id=%s' % asset_id)
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
def idc_add(request):
|
||||
"""
|
||||
IDC add view
|
||||
"""
|
||||
header_title, path1, path2 = u'添加IDC', u'资产管理', u'添加IDC'
|
||||
if request.method == 'POST':
|
||||
idc_form = IdcForm(request.POST)
|
||||
if idc_form.is_valid():
|
||||
idc_name = idc_form.cleaned_data['name']
|
||||
|
||||
if IDC.objects.filter(name=idc_name):
|
||||
emg = u'添加失败, 此IDC %s 已存在!' % idc_name
|
||||
return my_render('jasset/idc_add.html', locals(), request)
|
||||
else:
|
||||
idc_form.save()
|
||||
smg = u'IDC: %s添加成功' % idc_name
|
||||
return HttpResponseRedirect("/jasset/idc_list/")
|
||||
else:
|
||||
idc_form = IdcForm()
|
||||
return render_to_response('jasset/idc_add.html',
|
||||
locals(),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
def idc_list(request):
|
||||
"""
|
||||
IDC list view
|
||||
"""
|
||||
header_title, path1, path2 = u'查看IDC', u'资产管理', u'查看IDC'
|
||||
posts = IDC.objects.all()
|
||||
keyword = request.GET.get('keyword', '')
|
||||
if keyword:
|
||||
posts = IDC.objects.filter(Q(name__contains=keyword) | Q(comment__contains=keyword))
|
||||
else:
|
||||
posts = IDC.objects.exclude(name='ALL').order_by('id')
|
||||
contact_list, p, contacts, page_range, current_page, show_first, show_end = pages(posts, request)
|
||||
return render_to_response('jasset/idc_list.html',
|
||||
locals(),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
def idc_edit(request):
|
||||
"""
|
||||
IDC edit view
|
||||
"""
|
||||
header_title, path1, path2 = u'编辑IDC', u'资产管理', u'编辑IDC'
|
||||
idc_id = request.GET.get('id', '')
|
||||
idc = get_object(IDC, id=idc_id)
|
||||
if request.method == 'POST':
|
||||
idc_form = IdcForm(request.POST, instance=idc)
|
||||
if idc_form.is_valid():
|
||||
idc_form.save()
|
||||
return HttpResponseRedirect("/jasset/idc_list/")
|
||||
else:
|
||||
idc_form = IdcForm(instance=idc)
|
||||
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')
|
||||
def idc_del(request):
|
||||
"""
|
||||
IDC delete view
|
||||
"""
|
||||
uuid = request.GET.get('uuid', '')
|
||||
idc = get_object_or_404(IDC, uuid=uuid)
|
||||
idc.delete()
|
||||
return HttpResponseRedirect('/jasset/idc_list/')
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
def asset_upload(request):
|
||||
"""
|
||||
Upload file view
|
||||
"""
|
||||
if request.method == 'POST':
|
||||
excel_file = request.FILES.get('file_name', '')
|
||||
ret = excel_to_db(excel_file)
|
||||
if ret:
|
||||
smg = u'批量添加成功'
|
||||
else:
|
||||
emg = u'批量添加失败,请检查格式.'
|
||||
return my_render('jasset/asset_add_batch.html', locals(), request)
|
||||
|
|
|
@ -8,7 +8,7 @@ from django.http import HttpResponseNotFound
|
|||
from jlog.log_api import renderTemplate
|
||||
|
||||
from models import Log
|
||||
from jumpserver.settings import web_socket_host
|
||||
from jumpserver.settings import WEB_SOCKET_HOST
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
|
@ -48,8 +48,8 @@ def log_list(request, offset):
|
|||
|
||||
contact_list, p, contacts, page_range, current_page, show_first, show_end = pages(posts, request)
|
||||
|
||||
web_monitor_uri = 'ws://%s/monitor' % web_socket_host
|
||||
web_kill_uri = 'http://%s/kill' % web_socket_host
|
||||
web_monitor_uri = 'ws://%s/monitor' % WEB_SOCKET_HOST
|
||||
web_kill_uri = 'http://%s/kill' % WEB_SOCKET_HOST
|
||||
return render_to_response('jlog/log_%s.html' % offset, locals(), context_instance=RequestContext(request))
|
||||
|
||||
|
||||
|
@ -85,7 +85,7 @@ def log_history(request):
|
|||
content += '%s: %s\n' % (tty_log.datetime.strftime('%Y-%m-%d %H:%M:%S'), tty_log.cmd)
|
||||
return HttpResponse(content)
|
||||
|
||||
return HttpResponse('无日志记录, 请查看日志处理脚本是否开启!')
|
||||
return HttpResponse('无日志记录!')
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
|
@ -100,7 +100,7 @@ def log_record(request):
|
|||
content = renderTemplate(log_file, log_time)
|
||||
return HttpResponse(content)
|
||||
else:
|
||||
return HttpResponse('无日志记录, 请查看日志处理脚本是否开启!')
|
||||
return HttpResponse('无日志记录!')
|
||||
|
||||
|
||||
def web_terminal(request):
|
||||
|
@ -108,6 +108,6 @@ def web_terminal(request):
|
|||
token = request.COOKIES.get('sessionid')
|
||||
username = request.user.username
|
||||
asset_name = '127.0.0.1'
|
||||
web_terminal_uri = 'ws://%s/terminal?username=%s&asset_name=%s&token=%s' % (web_socket_host, username, asset_name, token)
|
||||
web_terminal_uri = 'ws://%s/terminal?username=%s&asset_name=%s&token=%s' % (WEB_SOCKET_HOST, username, asset_name, token)
|
||||
return render_to_response('jlog/web_terminal.html', locals())
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
# Jperm App
|
||||
|
||||
---
|
||||
|
||||
### 模块 ansible_api
|
||||
|
||||
> 使用说明
|
||||
|
||||
+ 依赖rpm安装包: ansible、 sshpass
|
||||
+ 依赖pip安装包: passlib
|
||||
+ 关于ansible配置: 需要启用配置文件(/etc/ansible/ansible.cfg)的 host_key_checking = False
|
||||
|
|
@ -0,0 +1,496 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
from ansible.inventory.group import Group
|
||||
from ansible.inventory.host import Host
|
||||
from ansible.inventory import Inventory
|
||||
from ansible.runner import Runner
|
||||
from ansible.playbook import PlayBook
|
||||
|
||||
from ansible import callbacks
|
||||
from ansible import utils
|
||||
from passlib.hash import sha512_crypt
|
||||
|
||||
from utils import get_rand_pass
|
||||
|
||||
|
||||
import os.path
|
||||
API_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
ANSIBLE_DIR = os.path.join(API_DIR, 'playbooks')
|
||||
|
||||
|
||||
|
||||
class AnsibleError(StandardError):
|
||||
"""
|
||||
the base AnsibleError which contains error(required),
|
||||
data(optional) and message(optional).
|
||||
存储所有Ansible 异常对象
|
||||
"""
|
||||
def __init__(self, error, data='', message=''):
|
||||
super(AnsibleError, self).__init__(message)
|
||||
self.error = error
|
||||
self.data = data
|
||||
self.message = message
|
||||
|
||||
|
||||
class CommandValueError(AnsibleError):
|
||||
"""
|
||||
indicate the input value has error or invalid.
|
||||
the data specifies the error field of input form.
|
||||
输入不合法 异常对象
|
||||
"""
|
||||
def __init__(self, field, message=''):
|
||||
super(CommandValueError, self).__init__('value:invalid', field, message)
|
||||
|
||||
|
||||
class MyInventory(object):
|
||||
"""
|
||||
this is my ansible inventory object.
|
||||
"""
|
||||
def __init__(self, resource):
|
||||
"""
|
||||
resource的数据格式是一个列表字典,比如
|
||||
{
|
||||
"group1": {
|
||||
"hosts": [{"hostname": "10.10.10.10", "port": "22", "username": "test", "password": "mypass"}, ...],
|
||||
"vars": {"var1": value1, "var2": value2, ...}
|
||||
}
|
||||
}
|
||||
|
||||
如果你只传入1个列表,这默认该列表内的所有主机属于my_group组,比如
|
||||
[{"hostname": "10.10.10.10", "port": "22", "username": "test", "password": "mypass"}, ...]
|
||||
"""
|
||||
self.resource = resource
|
||||
self.inventory = Inventory()
|
||||
self.gen_inventory()
|
||||
|
||||
def add_group(self, hosts, groupname, groupvars=None):
|
||||
"""
|
||||
add hosts to a group
|
||||
"""
|
||||
my_group = Group(name=groupname)
|
||||
|
||||
# if group variables exists, add them to group
|
||||
if groupvars:
|
||||
for key, value in groupvars.iteritems():
|
||||
my_group.set_variable(key, value)
|
||||
|
||||
# add hosts to group
|
||||
for host in hosts:
|
||||
# set connection variables
|
||||
hostname = host.get("hostname")
|
||||
hostport = host.get("port")
|
||||
username = host.get("username")
|
||||
password = host.get("password")
|
||||
my_host = Host(name=hostname, port=hostport)
|
||||
my_host.set_variable('ansible_ssh_host', hostname)
|
||||
my_host.set_variable('ansible_ssh_port', hostport)
|
||||
my_host.set_variable('ansible_ssh_user', username)
|
||||
my_host.set_variable('ansible_ssh_pass', password)
|
||||
# set other variables
|
||||
for key, value in host.iteritems():
|
||||
if key not in ["hostname", "port", "username", "password"]:
|
||||
my_host.set_variable(key, value)
|
||||
# add to group
|
||||
my_group.add_host(my_host)
|
||||
|
||||
self.inventory.add_group(my_group)
|
||||
|
||||
def gen_inventory(self):
|
||||
"""
|
||||
add hosts to inventory.
|
||||
"""
|
||||
if isinstance(self.resource, list):
|
||||
self.add_group(self.resource, 'my_group')
|
||||
elif isinstance(self.resource, dict):
|
||||
for groupname, hosts_and_vars in self.resource.iteritems():
|
||||
self.add_group(hosts_and_vars.get("hosts"), groupname, hosts_and_vars.get("vars"))
|
||||
|
||||
|
||||
class Command(MyInventory):
|
||||
"""
|
||||
this is a command object for parallel execute command.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Command, self).__init__(*args, **kwargs)
|
||||
self.results = ''
|
||||
|
||||
def run(self, command, module_name="command", timeout=5, forks=10, group='my_group'):
|
||||
"""
|
||||
run command from andible ad-hoc.
|
||||
command : 必须是一个需要执行的命令字符串, 比如
|
||||
'uname -a'
|
||||
"""
|
||||
if module_name not in ["raw", "command", "shell"]:
|
||||
raise CommandValueError("module_name",
|
||||
"module_name must be of the 'raw, command, shell'")
|
||||
hoc = Runner(module_name=module_name,
|
||||
module_args=command,
|
||||
timeout=timeout,
|
||||
inventory=self.inventory,
|
||||
subset=group,
|
||||
forks=forks
|
||||
)
|
||||
self.results = hoc.run()
|
||||
|
||||
if self.stdout:
|
||||
return {"ok": self.stdout}
|
||||
else:
|
||||
msg = []
|
||||
if self.stderr:
|
||||
msg.append(self.stderr)
|
||||
if self.dark:
|
||||
msg.append(self.dark)
|
||||
return {"failed": msg}
|
||||
|
||||
@property
|
||||
def raw_results(self):
|
||||
"""
|
||||
get the ansible raw results.
|
||||
"""
|
||||
return self.results
|
||||
|
||||
@property
|
||||
def exec_time(self):
|
||||
"""
|
||||
get the command execute time.
|
||||
"""
|
||||
result = {}
|
||||
all = self.results.get("contacted")
|
||||
for key, value in all.iteritems():
|
||||
result[key] = {
|
||||
"start": value.get("start"),
|
||||
"end" : value.get("end"),
|
||||
"delta": value.get("delta"),}
|
||||
return result
|
||||
|
||||
@property
|
||||
def stdout(self):
|
||||
"""
|
||||
get the comamnd standard output.
|
||||
"""
|
||||
result = {}
|
||||
all = self.results.get("contacted")
|
||||
for key, value in all.iteritems():
|
||||
result[key] = value.get("stdout")
|
||||
return result
|
||||
|
||||
@property
|
||||
def stderr(self):
|
||||
"""
|
||||
get the command standard error.
|
||||
"""
|
||||
result = {}
|
||||
all = self.results.get("contacted")
|
||||
for key, value in all.iteritems():
|
||||
result[key] = {
|
||||
"stderr": value.get("stderr"),
|
||||
"warnings": value.get("warnings"),}
|
||||
return result
|
||||
|
||||
@property
|
||||
def dark(self):
|
||||
"""
|
||||
get the dark results.
|
||||
"""
|
||||
return self.results.get("dark")
|
||||
|
||||
|
||||
class Tasks(Command):
|
||||
"""
|
||||
this is a tasks object for include the common command.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Tasks, self).__init__(*args, **kwargs)
|
||||
|
||||
def __run(self, module_args, module_name="command", timeout=5, forks=10, group='my_group'):
|
||||
"""
|
||||
run command from andible ad-hoc.
|
||||
command : 必须是一个需要执行的命令字符串, 比如
|
||||
'uname -a'
|
||||
"""
|
||||
hoc = Runner(module_name=module_name,
|
||||
module_args=module_args,
|
||||
timeout=timeout,
|
||||
inventory=self.inventory,
|
||||
subset=group,
|
||||
forks=forks
|
||||
)
|
||||
|
||||
self.results = hoc.run()
|
||||
|
||||
@property
|
||||
def msg(self):
|
||||
"""
|
||||
get the contacted and dark msg
|
||||
"""
|
||||
msg = {}
|
||||
for result in ["contacted", "dark"]:
|
||||
all = self.results.get(result)
|
||||
for key, value in all.iteritems():
|
||||
if value.get("msg"):
|
||||
msg[key] = value.get("msg")
|
||||
return msg
|
||||
|
||||
def push_key(self, user, key_path):
|
||||
"""
|
||||
push the ssh authorized key to target.
|
||||
"""
|
||||
module_args = 'user="%s" key="{{ lookup("file", "%s") }}"' % (user, key_path)
|
||||
self.__run(module_args, "authorized_key")
|
||||
|
||||
return {"status": "failed","msg": self.msg} if self.msg else {"status": "ok"}
|
||||
|
||||
def push_multi_key(self, **user_info):
|
||||
"""
|
||||
push multi key
|
||||
:param user_info:
|
||||
:return:
|
||||
"""
|
||||
ret_failed = []
|
||||
ret_success = []
|
||||
for user, key_path in user_info.iteritems():
|
||||
ret = self.push_key(user, key_path)
|
||||
if ret.get("status") == "ok":
|
||||
ret_success.append(ret)
|
||||
if ret.get("status") == "failed":
|
||||
ret_failed.append(ret)
|
||||
|
||||
if ret_failed:
|
||||
return {"status": "failed", "msg": ret_failed}
|
||||
else:
|
||||
return {"status": "success", "msg": ret_success}
|
||||
|
||||
def del_key(self, user, key_path):
|
||||
"""
|
||||
push the ssh authorized key to target.
|
||||
"""
|
||||
module_args = 'user="%s" key="{{ lookup("file", "%s") }}" state="absent"' % (user, key_path)
|
||||
self.__run(module_args, "authorized_key")
|
||||
|
||||
return {"status": "failed","msg": self.msg} if self.msg else {"status": "ok"}
|
||||
|
||||
def add_user(self, username, password):
|
||||
"""
|
||||
add a host user.
|
||||
"""
|
||||
encrypt_pass = sha512_crypt.encrypt(password)
|
||||
module_args = 'name=%s shell=/bin/bash password=%s' % (username, encrypt_pass)
|
||||
self.__run(module_args, "user")
|
||||
|
||||
return {"status": "failed","msg": self.msg} if self.msg else {"status": "ok"}
|
||||
|
||||
def add_multi_user(self, **user_info):
|
||||
"""
|
||||
add multi user
|
||||
:param user_info: keyword args
|
||||
{username: password}
|
||||
:return:
|
||||
"""
|
||||
ret_success = []
|
||||
ret_failed = []
|
||||
for user, password in user_info.iteritems():
|
||||
ret = self.add_user(user, password)
|
||||
if ret.get("status") == "ok":
|
||||
ret_success.append(ret)
|
||||
if ret.get("status") == "failed":
|
||||
ret_failed.append(ret)
|
||||
|
||||
if ret_failed:
|
||||
return {"status": "failed", "msg": ret_failed}
|
||||
else:
|
||||
return {"status": "success", "msg": ret_success}
|
||||
|
||||
def del_user(self, username):
|
||||
"""
|
||||
delete a host user.
|
||||
"""
|
||||
module_args = 'name=%s state=absent remove=yes move_home=yes force=yes' % (username)
|
||||
self.__run(module_args, "user")
|
||||
|
||||
return {"status": "failed","msg": self.msg} if self.msg else {"status": "ok"}
|
||||
|
||||
def add_init_users(self):
|
||||
"""
|
||||
add initail users: SA, DBA, DEV
|
||||
"""
|
||||
results = {}
|
||||
action = results["action_info"] = {}
|
||||
users = {"SA": get_rand_pass(), "DBA": get_rand_pass(), "DEV": get_rand_pass()}
|
||||
for user, password in users.iteritems():
|
||||
ret = self.add_user(user, password)
|
||||
action[user] = ret
|
||||
results["user_info"] = users
|
||||
|
||||
return results
|
||||
|
||||
def del_init_users(self):
|
||||
"""
|
||||
delete initail users: SA, DBA, DEV
|
||||
"""
|
||||
results = {}
|
||||
action = results["action_info"] = {}
|
||||
for user in ["SA", "DBA", "DEV"]:
|
||||
ret = self.del_user(user)
|
||||
action[user] = ret
|
||||
return results
|
||||
|
||||
def get_host_info(self):
|
||||
"""
|
||||
use the setup module get host informations
|
||||
:return:
|
||||
all_ip is list
|
||||
processor_count is int
|
||||
system_dist_version is string
|
||||
system_type is string
|
||||
disk is dict (device_name: device_size}
|
||||
system_dist is string
|
||||
processor_type is string
|
||||
default_ip is string
|
||||
hostname is string
|
||||
product_sn is string
|
||||
memory_total is int (MB)
|
||||
default_mac is string
|
||||
product_name is string
|
||||
"""
|
||||
self.__run('', 'setup')
|
||||
|
||||
result = {}
|
||||
all = self.results.get("contacted")
|
||||
for key, value in all.iteritems():
|
||||
setup =value.get("ansible_facts")
|
||||
# get disk informations
|
||||
disk_all = setup.get("ansible_devices")
|
||||
disk_need = {}
|
||||
for disk_name, disk_info in disk_all.iteritems():
|
||||
if disk_name.startswith('sd') or disk_name.startswith('hd'):
|
||||
disk_need[disk_name] = disk_info.get("size")
|
||||
|
||||
result[key] = {
|
||||
"all_ip": setup.get("ansible_all_ipv4_addresses"),
|
||||
"hostname" : setup.get("ansible_hostname" ),
|
||||
"default_ip": setup.get("ansible_default_ipv4").get("address"),
|
||||
"default_mac": setup.get("ansible_default_ipv4").get("macaddress"),
|
||||
"product_name": setup.get("ansible_product_name"),
|
||||
"processor_type": ' '.join(setup.get("ansible_processor")),
|
||||
"processor_count": setup.get("ansible_processor_count"),
|
||||
"memory_total": setup.get("ansible_memtotal_mb"),
|
||||
"disk": disk_need,
|
||||
"system_type": setup.get("ansible_system"),
|
||||
"system_dist": setup.get("ansible_distribution"),
|
||||
"system_dist_verion": setup.get("ansible_distribution_major_version"),
|
||||
"product_sn": setup.get("ansible_product_serial")
|
||||
}
|
||||
|
||||
return {"status": "failed", "msg": self.msg} if self.msg else {"status": "ok", "result": result}
|
||||
|
||||
|
||||
|
||||
|
||||
class CustomAggregateStats(callbacks.AggregateStats):
|
||||
"""
|
||||
Holds stats about per-host activity during playbook runs.
|
||||
"""
|
||||
def __init__(self):
|
||||
super(CustomAggregateStats, self).__init__()
|
||||
self.results = []
|
||||
|
||||
def compute(self, runner_results, setup=False, poll=False,
|
||||
ignore_errors=False):
|
||||
"""
|
||||
Walk through all results and increment stats.
|
||||
"""
|
||||
super(CustomAggregateStats, self).compute(runner_results, setup, poll,
|
||||
ignore_errors)
|
||||
|
||||
self.results.append(runner_results)
|
||||
|
||||
|
||||
def summarize(self, host):
|
||||
"""
|
||||
Return information about a particular host
|
||||
"""
|
||||
summarized_info = super(CustomAggregateStats, self).summarize(host)
|
||||
|
||||
# Adding the info I need
|
||||
summarized_info['result'] = self.results
|
||||
|
||||
return summarized_info
|
||||
|
||||
|
||||
class MyPlaybook(MyInventory):
|
||||
"""
|
||||
this is my playbook object for execute playbook.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MyPlaybook, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
def run(self, playbook_relational_path, extra_vars=None):
|
||||
"""
|
||||
run ansible playbook,
|
||||
only surport relational path.
|
||||
"""
|
||||
stats = callbacks.AggregateStats()
|
||||
playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)
|
||||
runner_cb = callbacks.PlaybookRunnerCallbacks(stats, verbose=utils.VERBOSITY)
|
||||
playbook_path = os.path.join(ANSIBLE_DIR, playbook_relational_path)
|
||||
|
||||
pb = PlayBook(
|
||||
playbook = playbook_path,
|
||||
stats = stats,
|
||||
callbacks = playbook_cb,
|
||||
runner_callbacks = runner_cb,
|
||||
inventory = self.inventory,
|
||||
extra_vars = extra_vars,
|
||||
check=False)
|
||||
|
||||
self.results = pb.run()
|
||||
|
||||
@property
|
||||
def raw_results(self):
|
||||
"""
|
||||
get the raw results after playbook run.
|
||||
"""
|
||||
return self.results
|
||||
|
||||
|
||||
class App(MyPlaybook):
|
||||
"""
|
||||
this is a app object for inclue the common playbook.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(App, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
|
||||
# resource = {
|
||||
# "group1": {
|
||||
# "hosts": [{"hostname": "127.0.0.1", "port": "22", "username": "root", "password": "xxx"},],
|
||||
# "vars" : {"var1": "value1", "var2": "value2"},
|
||||
# },
|
||||
# }
|
||||
# command = Command(resource)
|
||||
# print command.run("who", group="group1")
|
||||
|
||||
# resource = [{"hostname": "192.168.10.148", "port": "22", "username": "root", "password": "xxx"}]
|
||||
# task = Tasks(resource)
|
||||
# print task.get_host_info()
|
||||
|
||||
# playbook = MyPlaybook(resource)
|
||||
# playbook.run('test.yml')
|
||||
# print playbook.raw_results
|
||||
|
||||
# task = Tasks(resource)
|
||||
# print task.add_user('test', 'mypass')
|
||||
# print task.del_user('test')
|
||||
# print task.push_key('root', '/root/.ssh/id_rsa.pub')
|
||||
# print task.del_key('root', '/root/.ssh/id_rsa.pub')
|
||||
|
||||
# task = Tasks(resource)
|
||||
# print task.add_init_users()
|
||||
# print task.del_init_users()
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import datetime
|
||||
|
||||
from django.db import models
|
||||
from juser.models import User, UserGroup
|
||||
from jasset.models import Asset, AssetGroup
|
||||
from juser.models import User, UserGroup
|
||||
|
||||
|
||||
class PermLog(models.Model):
|
||||
|
@ -19,3 +19,27 @@ class SysUser(models.Model):
|
|||
comment = models.CharField(max_length=100, null=True, blank=True, default='')
|
||||
|
||||
|
||||
class PermRole(models.Model):
|
||||
name = models.CharField(max_length=100, unique=True)
|
||||
comment = models.CharField(max_length=100, null=True, blank=True, default='')
|
||||
password = models.CharField(max_length=100)
|
||||
key_path = models.CharField(max_length=100)
|
||||
date_added = models.DateTimeField(auto_now=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class PermRule(models.Model):
|
||||
date_added = models.DateTimeField(auto_now=True)
|
||||
name = models.CharField(max_length=100)
|
||||
comment = models.CharField(max_length=100)
|
||||
asset = models.ManyToManyField(Asset, related_name='perm_rule')
|
||||
asset_group = models.ManyToManyField(AssetGroup, related_name='perm_rule')
|
||||
user = models.ManyToManyField(User, related_name='perm_rule')
|
||||
user_group = models.ManyToManyField(UserGroup, related_name='perm_rule')
|
||||
role = models.ManyToManyField(PermRole, related_name='perm_rule')
|
||||
ssh_type = models.BooleanField()
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
|
@ -1,6 +1,6 @@
|
|||
# coding: utf-8
|
||||
|
||||
from jasset.models import *
|
||||
|
||||
from jumpserver.api import *
|
||||
import uuid
|
||||
import re
|
||||
|
@ -9,6 +9,8 @@ from jumpserver.tasks import playbook_run
|
|||
from jumpserver.models import Setting
|
||||
from jperm.models import PermLog
|
||||
|
||||
from jperm.models import PermRole
|
||||
|
||||
|
||||
def get_object_list(model, id_list):
|
||||
"""根据id列表获取对象列表"""
|
||||
|
@ -281,8 +283,62 @@ def push_user(user, asset_groups_id):
|
|||
return results
|
||||
|
||||
|
||||
|
||||
|
||||
def get_role_info(role_id, type="all"):
|
||||
"""
|
||||
获取role对应的一些信息
|
||||
:return: 返回值 均为对象列表
|
||||
"""
|
||||
# 获取role对应的授权规则
|
||||
role_obj = PermRole.objects.get(id=role_id)
|
||||
rules_obj = role_obj.perm_rule.all()
|
||||
# 获取role 对应的用户 和 用户组
|
||||
# 获取role 对应的主机 和主机组
|
||||
users_obj = []
|
||||
assets_obj = []
|
||||
user_groups_obj = []
|
||||
group_users_obj = []
|
||||
asset_groups_obj = []
|
||||
group_assets_obj = []
|
||||
for rule in rules_obj:
|
||||
for user in rule.user.all():
|
||||
users_obj.append(user)
|
||||
for asset in rule.asset.all():
|
||||
assets_obj.append(asset)
|
||||
for user_group in rule.user_group.all():
|
||||
user_groups_obj.append(user_group)
|
||||
for user in user_group.user_set.all():
|
||||
group_users_obj.append(user)
|
||||
for asset_group in rule.asset_group.all():
|
||||
asset_groups_obj.append(asset_group)
|
||||
for asset in asset_group.asset_set.all():
|
||||
group_assets_obj.append(asset)
|
||||
|
||||
calc_users = set(users_obj) | set(group_users_obj)
|
||||
calc_assets = set(assets_obj) | set(group_assets_obj)
|
||||
|
||||
if type == "all":
|
||||
return {"rules": rules_obj,
|
||||
"users": list(calc_users),
|
||||
"user_groups": user_groups_obj,
|
||||
"assets": list(calc_assets),
|
||||
"asset_groups": asset_groups_obj,
|
||||
}
|
||||
elif type == "rule":
|
||||
return rules_obj
|
||||
elif type == "user":
|
||||
return calc_users
|
||||
elif type == "user_group":
|
||||
return user_groups_obj
|
||||
elif type == "asset":
|
||||
return calc_assets
|
||||
elif type == "asset_group":
|
||||
return asset_groups_obj
|
||||
else:
|
||||
return u"不支持的查询"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print get_role_info(1)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
|
||||
- hosts: 'add_users_group'
|
||||
gather_facts: no
|
||||
tasks:
|
||||
- name: add SA user
|
||||
command: uname -a
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
|
||||
- hosts: test
|
||||
gather_facts: no
|
||||
tasks:
|
||||
- name: just for test
|
||||
command: uname -a
|
||||
|
||||
|
|
@ -2,13 +2,22 @@ from django.conf.urls import patterns, include, url
|
|||
from jperm.views import *
|
||||
|
||||
urlpatterns = patterns('jperm.views',
|
||||
(r'^user/$', perm_user_list),
|
||||
(r'^perm_user_edit/$', perm_user_edit),
|
||||
(r'^group/$', perm_group_list),
|
||||
(r'^perm_group_edit/$', perm_group_edit),
|
||||
(r'^rule/$', perm_rule_list),
|
||||
(r'^perm_rule_add/$', perm_rule_add),
|
||||
(r'^perm_rule_detail/$', perm_rule_detail),
|
||||
(r'^perm_rule_edit/$', perm_rule_edit),
|
||||
(r'^perm_rule_delete/$', perm_rule_delete),
|
||||
(r'^role/$', perm_role_list),
|
||||
(r'^role/perm_role_add/$', perm_role_add),
|
||||
(r'^role/perm_role_delete/$', perm_role_delete),
|
||||
(r'^role/perm_role_detail/$', perm_role_detail),
|
||||
(r'^role/perm_role_edit/$', perm_role_edit),
|
||||
(r'^role/perm_role_push/$', perm_role_push),
|
||||
|
||||
|
||||
(r'^log/$', log),
|
||||
(r'^sys_user_add/$', sys_user_add),
|
||||
(r'^sys_user_list/$', sys_user_list),
|
||||
(r'^perm_user_list/$', sys_user_list),
|
||||
(r'^sys_user_del/$', sys_user_del),
|
||||
(r'^sys_user_edit/$', sys_user_edit),
|
||||
)
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import random
|
||||
import os.path
|
||||
|
||||
from paramiko.rsakey import RSAKey
|
||||
from os import chmod, mkdir
|
||||
from uuid import uuid4
|
||||
|
||||
from jumpserver.settings import KEY_DIR
|
||||
|
||||
|
||||
def get_rand_pass():
|
||||
"""
|
||||
get a reandom password.
|
||||
"""
|
||||
lower = [chr(i) for i in range(97,123)]
|
||||
upper = [chr(i).upper() for i in range(97,123)]
|
||||
digit = [str(i) for i in range(10)]
|
||||
password_pool = []
|
||||
password_pool.extend(lower)
|
||||
password_pool.extend(upper)
|
||||
password_pool.extend(digit)
|
||||
pass_list = [random.choice(password_pool) for i in range(1,14)]
|
||||
pass_list.insert(random.choice(range(1,14)), '@')
|
||||
pass_list.insert(random.choice(range(1,14)), random.choice(digit))
|
||||
password = ''.join(pass_list)
|
||||
return password
|
||||
|
||||
|
||||
def updates_dict(*args):
|
||||
"""
|
||||
surport update multi dict
|
||||
"""
|
||||
result = {}
|
||||
for d in args:
|
||||
result.update(d)
|
||||
return result
|
||||
|
||||
|
||||
def gen_keys():
|
||||
"""
|
||||
在KEY_DIR下创建一个 uuid命名的目录,
|
||||
并且在该目录下 生产一对秘钥
|
||||
:return: 返回目录名(uuid)
|
||||
"""
|
||||
key_basename = "key-" + uuid4().hex
|
||||
key_path_dir = os.path.join(KEY_DIR, key_basename)
|
||||
mkdir(key_path_dir, 0700)
|
||||
|
||||
key = RSAKey.generate(2048)
|
||||
private_key = os.path.join(key_path_dir, 'id_rsa')
|
||||
public_key = os.path.join(key_path_dir, 'id_rsa.pub')
|
||||
key.write_private_key_file(private_key)
|
||||
|
||||
with open(public_key, 'w') as content_file:
|
||||
for data in [key.get_name(),
|
||||
" ",
|
||||
key.get_base64(),
|
||||
" %s@%s" % ("jumpserver", os.uname()[1])]:
|
||||
content_file.write(data)
|
||||
return key_path_dir
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print gen_keys()
|
||||
|
||||
|
449
jperm/views.py
449
jperm/views.py
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,30 +1,19 @@
|
|||
#coding: utf8
|
||||
|
||||
[base]
|
||||
url = http://192.168.244.129
|
||||
url = http://127.0.0.1
|
||||
key = 88aaaf7ffe3c6c04
|
||||
log = debug
|
||||
|
||||
|
||||
[db]
|
||||
host = 127.0.0.1
|
||||
port = 3306
|
||||
user = jumpserver
|
||||
password = mysql234
|
||||
password = mysql1234
|
||||
database = jumpserver
|
||||
|
||||
|
||||
[ldap]
|
||||
ldap_enable = 1
|
||||
host_url = ldap://127.0.0.1:389
|
||||
base_dn = dc=jumpserver, dc=org
|
||||
root_dn = cn=admin,dc=jumpserver,dc=org
|
||||
root_pw = secret234
|
||||
|
||||
|
||||
[websocket]
|
||||
web_socket_host = 192.168.244.129:3000
|
||||
|
||||
web_socket_host = 127.0.0.1:3000
|
||||
|
||||
[mail]
|
||||
mail_enable = 1
|
||||
|
|
|
@ -25,7 +25,6 @@ import json
|
|||
import logging
|
||||
|
||||
|
||||
|
||||
def set_log(level):
|
||||
"""
|
||||
return a log file object
|
||||
|
@ -35,7 +34,7 @@ def set_log(level):
|
|||
'critical': logging.CRITICAL}
|
||||
logger_f = logging.getLogger('jumpserver')
|
||||
logger_f.setLevel(logging.DEBUG)
|
||||
fh = logging.FileHandler(JLOG_FILE)
|
||||
fh = logging.FileHandler(os.path.join(LOG_DIR, 'jumpserver.log'))
|
||||
fh.setLevel(log_level_total.get(level, logging.DEBUG))
|
||||
formatter = logging.Formatter('%(asctime)s - %(filename)s - %(levelname)s - %(message)s')
|
||||
fh.setFormatter(formatter)
|
||||
|
@ -86,7 +85,6 @@ def pages(post_objects, request):
|
|||
return post_objects, paginator, page_objects, page_range, current_page, show_first, show_end
|
||||
|
||||
|
||||
|
||||
class PyCrypt(object):
|
||||
"""
|
||||
This class used to encrypt and decrypt password.
|
||||
|
@ -98,7 +96,7 @@ class PyCrypt(object):
|
|||
self.mode = AES.MODE_CBC
|
||||
|
||||
@staticmethod
|
||||
def random_pass(length, especial=False):
|
||||
def gen_rand_pass(length, especial=False):
|
||||
"""
|
||||
random password
|
||||
随机生成密码
|
||||
|
@ -139,7 +137,7 @@ class PyCrypt(object):
|
|||
对称加密之加密生成密码
|
||||
"""
|
||||
if not passwd:
|
||||
passwd = self.random_pass()
|
||||
passwd = self.gen_rand_pass()
|
||||
|
||||
cryptor = AES.new(self.key, self.mode, b'8122ca7d906ad5e1')
|
||||
try:
|
||||
|
@ -256,6 +254,7 @@ def get_session_user_info(request):
|
|||
# return [user.id, user.username, user]
|
||||
return [request.user.id, request.user.username, request.user]
|
||||
|
||||
|
||||
def get_user_dept(request):
|
||||
"""
|
||||
get the user dept id
|
||||
|
@ -389,7 +388,7 @@ def bash(cmd):
|
|||
return subprocess.call(cmd, shell=True)
|
||||
|
||||
|
||||
def is_dir(dir_name, username='root', mode=0755):
|
||||
def mkdir(dir_name, username='root', mode=0755):
|
||||
"""
|
||||
insure the dir exist and mode ok
|
||||
目录存在,如果不存在就建立,并且权限正确
|
||||
|
@ -414,5 +413,5 @@ def my_render(template, data, request):
|
|||
|
||||
|
||||
CRYPTOR = PyCrypt(KEY)
|
||||
logger = set_log(log_level)
|
||||
|
||||
logger = set_log(LOG_LEVEL)
|
||||
KEY_DIR = os.path.join(BASE_DIR, 'keys')
|
||||
|
|
|
@ -6,7 +6,7 @@ from django.db import models
|
|||
class Setting(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
default_user = models.CharField(max_length=100, null=True, blank=True)
|
||||
default_port = models.IntegerField(max_length=10, null=True, blank=True)
|
||||
default_port = models.IntegerField(null=True, blank=True)
|
||||
default_password = models.CharField(max_length=100, null=True, blank=True)
|
||||
default_pri_key_path = models.CharField(max_length=100, null=True, blank=True)
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@ config = ConfigParser.ConfigParser()
|
|||
BASE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
|
||||
config.read(os.path.join(BASE_DIR, 'jumpserver.conf'))
|
||||
|
||||
KEY_DIR = os.path.join(BASE_DIR, 'role_keys')
|
||||
|
||||
DB_HOST = config.get('db', 'host')
|
||||
DB_PORT = config.getint('db', 'port')
|
||||
DB_USER = config.get('db', 'user')
|
||||
|
@ -34,18 +36,12 @@ EMAIL_USE_TLS = config.getboolean('mail', 'email_use_tls')
|
|||
EMAIL_TIMEOUT = 5
|
||||
|
||||
# ======== Log ==========
|
||||
LOG = False
|
||||
LOG_DIR = os.path.join(BASE_DIR, 'logs')
|
||||
JLOG_FILE = os.path.join(LOG_DIR, 'jumpserver.log')
|
||||
SSH_KEY_DIR = os.path.join(BASE_DIR, 'keys')
|
||||
# SERVER_KEY_DIR = os.path.join(SSH_KEY_DIR, 'server')
|
||||
SSH_KEY_DIR = os.path.join(BASE_DIR, 'role_keys')
|
||||
KEY = config.get('base', 'key')
|
||||
LOGIN_NAME = getpass.getuser()
|
||||
# LDAP_ENABLE = CONF.getint('ldap', 'ldap_enable')
|
||||
URL = config.get('base', 'url')
|
||||
log_dir = os.path.join(BASE_DIR, 'logs')
|
||||
log_level = config.get('base', 'log')
|
||||
web_socket_host = config.get('websocket', 'web_socket_host')
|
||||
LOG_LEVEL = config.get('base', 'log')
|
||||
WEB_SOCKET_HOST = config.get('websocket', 'web_socket_host')
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
|
||||
|
@ -70,6 +66,7 @@ INSTALLED_APPS = (
|
|||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.humanize',
|
||||
'bootstrapform',
|
||||
'jumpserver',
|
||||
'juser',
|
||||
'jasset',
|
||||
|
@ -150,3 +147,5 @@ USE_TZ = False
|
|||
# https://docs.djangoproject.com/en/1.7/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
BOOTSTRAP_COLUMN_COUNT = 10
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# coding: utf-8
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ansible.playbook import PlayBook
|
||||
from ansible import callbacks, utils
|
||||
|
@ -44,4 +44,5 @@ def playbook_run(inventory, playbook, default_user=None, default_port=None, defa
|
|||
else:
|
||||
results_r['success'].append(hostname)
|
||||
print "%s >>> Success" % hostname
|
||||
return results_r
|
||||
return results_r
|
||||
|
||||
|
|
Binary file not shown.
|
@ -123,3 +123,106 @@ def result2bool(result=''):
|
|||
return '<b style="color: red">失败</b>'
|
||||
else:
|
||||
return '<b style="color: green">成功</b>'
|
||||
|
||||
|
||||
@register.filter(name='rule_member_count')
|
||||
def rule_member_count(instance, member):
|
||||
"""
|
||||
instance is a rule object,
|
||||
use to get the number of the members
|
||||
:param instance:
|
||||
:param member:
|
||||
:return:
|
||||
"""
|
||||
member = getattr(instance, member)
|
||||
counts = member.all().count()
|
||||
return str(counts)
|
||||
|
||||
|
||||
@register.filter(name='rule_member_name')
|
||||
def rule_member_name(instance, member):
|
||||
"""
|
||||
instance is a rule object,
|
||||
use to get the name of the members
|
||||
:param instance:
|
||||
:param member:
|
||||
:return:
|
||||
"""
|
||||
member = getattr(instance, member)
|
||||
names = member.all()
|
||||
|
||||
return names
|
||||
|
||||
|
||||
@register.filter(name='user_which_groups')
|
||||
def user_which_group(user, member):
|
||||
"""
|
||||
instance is a user object,
|
||||
use to get the group of the user
|
||||
:param instance:
|
||||
:param member:
|
||||
:return:
|
||||
"""
|
||||
member = getattr(user, member)
|
||||
names = [members.name for members in member.all()]
|
||||
|
||||
return ','.join(names)
|
||||
|
||||
|
||||
@register.filter(name='asset_which_groups')
|
||||
def asset_which_group(asset, member):
|
||||
"""
|
||||
instance is a user object,
|
||||
use to get the group of the user
|
||||
:param instance:
|
||||
:param member:
|
||||
:return:
|
||||
"""
|
||||
member = getattr(asset, member)
|
||||
names = [members.name for members in member.all()]
|
||||
|
||||
return ','.join(names)
|
||||
|
||||
|
||||
@register.filter(name='group_str2')
|
||||
def groups_str2(group_list):
|
||||
"""
|
||||
将用户组列表转换为str
|
||||
"""
|
||||
if len(group_list) < 3:
|
||||
return ' '.join([group.name for group in group_list])
|
||||
else:
|
||||
return '%s ...' % ' '.join([group.name for group in group_list[0:2]])
|
||||
|
||||
|
||||
@register.filter(name='str_to_list')
|
||||
def str_to_list(info):
|
||||
"""
|
||||
str to list
|
||||
"""
|
||||
print ast.literal_eval(info), type(ast.literal_eval(info))
|
||||
return ast.literal_eval(info)
|
||||
|
||||
|
||||
@register.filter(name='str_to_dic')
|
||||
def str_to_dic(info):
|
||||
"""
|
||||
str to list
|
||||
"""
|
||||
return ast.literal_eval(info).iteritems()
|
||||
|
||||
|
||||
@register.filter(name='str_to_code')
|
||||
def str_to_code(char_str):
|
||||
if char_str:
|
||||
return char_str
|
||||
else:
|
||||
return u'空'
|
||||
|
||||
|
||||
@register.filter(name='ip_str_to_list')
|
||||
def ip_str_to_list(ip_str):
|
||||
"""
|
||||
ip str to list
|
||||
"""
|
||||
return ip_str.split(',')
|
||||
|
|
|
@ -19,5 +19,6 @@ urlpatterns = patterns('',
|
|||
(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'download/(\d{4}/\d\d/\d\d/.*)', 'jumpserver.views.download_file'),
|
||||
(r'test2', 'jumpserver.views.test2'),
|
||||
)
|
||||
|
|
|
@ -20,35 +20,58 @@ from jlog.models import Log
|
|||
|
||||
|
||||
def getDaysByNum(num):
|
||||
"""
|
||||
输出格式:([datetime.date(2015, 11, 6), datetime.date(2015, 11, 8)], ['11-06', '11-08'])
|
||||
"""
|
||||
|
||||
today = datetime.date.today()
|
||||
oneday = datetime.timedelta(days=1)
|
||||
li_date, li_str = [], []
|
||||
date_li, date_str = [], []
|
||||
for i in range(0, num):
|
||||
today = today-oneday
|
||||
li_date.append(today)
|
||||
li_str.append(str(today)[5:10])
|
||||
li_date.reverse()
|
||||
li_str.reverse()
|
||||
t = (li_date, li_str)
|
||||
return t
|
||||
date_li.append(today)
|
||||
date_str.append(str(today)[5:10])
|
||||
date_li.reverse()
|
||||
date_str.reverse()
|
||||
return date_li, date_str
|
||||
|
||||
|
||||
def get_data(data, items, option):
|
||||
dic = {}
|
||||
li_date, li_str = getDaysByNum(7)
|
||||
for item in items:
|
||||
li = []
|
||||
name = item[option]
|
||||
if option == 'user':
|
||||
option_data = data.filter(user=name)
|
||||
elif option == 'host':
|
||||
option_data = data.filter(host=name)
|
||||
for t in li_date:
|
||||
year, month, day = t.year, t.month, t.day
|
||||
times = option_data.filter(start_time__year=year, start_time__month=month, start_time__day=day).count()
|
||||
li.append(times)
|
||||
dic[name] = li
|
||||
return dic
|
||||
def get_data(x, y, z):
|
||||
pass
|
||||
|
||||
|
||||
def get_data_by_day(date_li, item):
|
||||
data_li = []
|
||||
for d in date_li:
|
||||
logs = Log.objects.filter(start_time__year=d.year,
|
||||
start_time__month=d.month,
|
||||
start_time__day=d.day)
|
||||
if item == 'user':
|
||||
data_li.append(set([log.user for log in logs]))
|
||||
elif item == 'asset':
|
||||
data_li.append(set([log.host for log in logs]))
|
||||
elif item == 'login':
|
||||
data_li.append(logs)
|
||||
else:
|
||||
pass
|
||||
return data_li
|
||||
|
||||
|
||||
def get_count_by_day(date_li, item):
|
||||
data_li = get_data_by_day(date_li, item)
|
||||
data_count_li = []
|
||||
for data in data_li:
|
||||
data_count_li.append(len(data))
|
||||
return data_count_li
|
||||
|
||||
|
||||
def get_count_by_date(date_li, item):
|
||||
data_li = get_data_by_day(date_li, item)
|
||||
data_count_tmp = []
|
||||
for data in data_li:
|
||||
data_count_tmp.extend(list(data))
|
||||
|
||||
return len(set(data_count_tmp))
|
||||
|
||||
|
||||
@require_role(role='user')
|
||||
|
@ -59,6 +82,7 @@ def index_cu(request):
|
|||
username = request.user.username
|
||||
posts = Asset.object.all()
|
||||
host_count = len(posts)
|
||||
|
||||
new_posts = []
|
||||
post_five = []
|
||||
for post in posts:
|
||||
|
@ -81,6 +105,7 @@ def index(request):
|
|||
return index_cu(request)
|
||||
|
||||
elif is_role_request(request, 'super'):
|
||||
# dashboard 显示汇总
|
||||
users = User.objects.all()
|
||||
hosts = Asset.objects.all()
|
||||
online = Log.objects.filter(is_finished=0)
|
||||
|
@ -88,68 +113,52 @@ def index(request):
|
|||
online_user = online.values('user').distinct()
|
||||
active_users = User.objects.filter(is_active=1)
|
||||
active_hosts = Asset.objects.filter(is_active=1)
|
||||
|
||||
# 一个月历史汇总
|
||||
date_li, date_str = getDaysByNum(30)
|
||||
date_month = repr(date_str)
|
||||
active_user_per_month = str(get_count_by_day(date_li, 'user'))
|
||||
active_asset_per_month = str(get_count_by_day(date_li, 'asset'))
|
||||
active_login_per_month = str(get_count_by_day(date_li, 'login'))
|
||||
|
||||
# 活跃用户资产图
|
||||
active_user_month = get_count_by_date(date_li, 'user')
|
||||
disabled_user_count = len(users.filter(is_active=False))
|
||||
inactive_user_month = len(users) - active_user_month
|
||||
active_asset_month = get_count_by_date(date_li, 'asset')
|
||||
disabled_asset_count = len(hosts.filter(is_active=False)) if hosts.filter(is_active=False) else 0
|
||||
inactive_asset_month = len(hosts) - active_asset_month if len(hosts) > active_asset_month else 0
|
||||
|
||||
# 一周top10用户和主机
|
||||
week_data = Log.objects.filter(start_time__range=[from_week, datetime.datetime.now()])
|
||||
user_top_ten = week_data.values('user').annotate(times=Count('user')).order_by('-times')[:10]
|
||||
host_top_ten = week_data.values('host').annotate(times=Count('host')).order_by('-times')[:10]
|
||||
|
||||
elif is_role_request(request, 'admin'):
|
||||
return index_cu(request)
|
||||
# user = get_session_user_info(request)[2]
|
||||
# users = User.objects.filter(dept=dept)
|
||||
# hosts = Asset.objects.filter(dept=dept)
|
||||
# online = Log.objects.filter(dept_name=dept_name, is_finished=0)
|
||||
# online_host = online.values('host').distinct()
|
||||
# online_user = online.values('user').distinct()
|
||||
# active_users = users.filter(is_active=1)
|
||||
# active_hosts = hosts.filter(is_active=1)
|
||||
# week_data = Log.objects.filter(dept_name=dept_name, start_time__range=[from_week, datetime.datetime.now()])
|
||||
for user_info in user_top_ten:
|
||||
username = user_info.get('user')
|
||||
last = Log.objects.filter(user=username).latest('start_time')
|
||||
user_info['last'] = last
|
||||
|
||||
# percent of dashboard
|
||||
if users.count() == 0:
|
||||
percent_user, percent_online_user = '0%', '0%'
|
||||
else:
|
||||
percent_user = format(active_users.count() / users.count(), '.0%')
|
||||
percent_online_user = format(online_user.count() / users.count(), '.0%')
|
||||
if hosts.count() == 0:
|
||||
percent_host, percent_online_host = '0%', '0%'
|
||||
else:
|
||||
percent_host = format(active_hosts.count() / hosts.count(), '.0%')
|
||||
percent_online_host = format(online_host.count() / hosts.count(), '.0%')
|
||||
for host_info in host_top_ten:
|
||||
host = host_info.get('host')
|
||||
last = Log.objects.filter(host=host).latest('start_time')
|
||||
host_info['last'] = last
|
||||
|
||||
user_top_ten = week_data.values('user').annotate(times=Count('user')).order_by('-times')[:10]
|
||||
host_top_ten = week_data.values('host').annotate(times=Count('host')).order_by('-times')[:10]
|
||||
user_dic, host_dic = get_data(week_data, user_top_ten, 'user'), get_data(week_data, host_top_ten, 'host')
|
||||
# 一周top5
|
||||
week_users = week_data.values('user').distinct().count()
|
||||
week_hosts = week_data.count()
|
||||
|
||||
# a week data
|
||||
week_users = week_data.values('user').distinct().count()
|
||||
week_hosts = week_data.count()
|
||||
user_top_five = week_data.values('user').annotate(times=Count('user')).order_by('-times')[:5]
|
||||
color = ['label-success', 'label-info', 'label-primary', 'label-default', 'label-warnning']
|
||||
|
||||
user_top_five = week_data.values('user').annotate(times=Count('user')).order_by('-times')[:5]
|
||||
color = ['label-success', 'label-info', 'label-primary', 'label-default', 'label-warnning']
|
||||
# 最后10次权限申请
|
||||
# perm apply latest 10
|
||||
# perm_apply_10 = Apply.objects.order_by('-date_add')[:10]
|
||||
|
||||
# perm apply latest 10
|
||||
# perm_apply_10 = Apply.objects.order_by('-date_add')[:10]
|
||||
# 最后10次登陆
|
||||
login_10 = Log.objects.order_by('-start_time')[:10]
|
||||
login_more_10 = Log.objects.order_by('-start_time')[10:21]
|
||||
|
||||
# latest 10 login
|
||||
login_10 = Log.objects.order_by('-start_time')[:10]
|
||||
login_more_10 = Log.objects.order_by('-start_time')[10:21]
|
||||
|
||||
# a week top 10
|
||||
for user_info in user_top_ten:
|
||||
username = user_info.get('user')
|
||||
last = Log.objects.filter(user=username).latest('start_time')
|
||||
user_info['last'] = last
|
||||
|
||||
top = {'user': '活跃用户数', 'host': '活跃主机数', 'times': '登录次数'}
|
||||
top_dic = {}
|
||||
for key, value in top.items():
|
||||
li = []
|
||||
for t in li_date:
|
||||
year, month, day = t.year, t.month, t.day
|
||||
if key != 'times':
|
||||
times = week_data.filter(start_time__year=year, start_time__month=month, start_time__day=day).values(key).distinct().count()
|
||||
else:
|
||||
times = week_data.filter(start_time__year=year, start_time__month=month, start_time__day=day).count()
|
||||
li.append(times)
|
||||
top_dic[value] = li
|
||||
return render_to_response('index.html', locals(), context_instance=RequestContext(request))
|
||||
|
||||
|
||||
|
@ -259,7 +268,7 @@ def setting(request):
|
|||
if '' in [username, port] and ('' in password or '' in private_key):
|
||||
return HttpResponse('所填内容不能为空, 且密码和私钥填一个')
|
||||
else:
|
||||
private_key_path = os.path.join(BASE_DIR, 'keys', 'default', 'default_private_key.pem')
|
||||
private_key_path = os.path.join(BASE_DIR, 'role_keys', 'default', 'default_private_key.pem')
|
||||
if private_key:
|
||||
with open(private_key_path, 'w') as f:
|
||||
f.write(private_key)
|
||||
|
@ -282,6 +291,10 @@ def setting(request):
|
|||
|
||||
msg = "设置成功"
|
||||
return my_render('setting.html', locals(), request)
|
||||
|
||||
|
||||
def test2(request):
|
||||
return my_render('test2.html', locals(), request)
|
||||
#
|
||||
# def filter_ajax_api(request):
|
||||
# attr = request.GET.get('attr', 'user')
|
||||
|
|
|
@ -9,8 +9,6 @@ from jasset.models import Asset, AssetGroup
|
|||
class UserGroup(models.Model):
|
||||
name = models.CharField(max_length=80, unique=True)
|
||||
comment = models.CharField(max_length=160, blank=True, null=True)
|
||||
asset = models.ManyToManyField(Asset)
|
||||
asset_group = models.ManyToManyField(AssetGroup)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
@ -27,6 +25,9 @@ class User(AbstractUser):
|
|||
role = models.CharField(max_length=2, choices=USER_ROLE_CHOICES, default='CU')
|
||||
group = models.ManyToManyField(UserGroup)
|
||||
ssh_key_pwd = models.CharField(max_length=200)
|
||||
# is_active = models.BooleanField(default=True)
|
||||
# last_login = models.DateTimeField(null=True)
|
||||
# date_joined = models.DateTimeField(null=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.username
|
||||
|
|
|
@ -121,7 +121,9 @@ def db_del_user(username):
|
|||
|
||||
|
||||
def gen_ssh_key(username, password='',
|
||||
key_dir=os.path.join(BASE_DIR, 'keys/user/'),
|
||||
|
||||
key_dir=os.path.join(BASE_DIR, 'role_keys/user/'),
|
||||
|
||||
authorized_keys=True, home="/home", length=2048):
|
||||
"""
|
||||
generate a user ssh key in a property dir
|
||||
|
@ -134,7 +136,7 @@ def gen_ssh_key(username, password='',
|
|||
|
||||
if authorized_keys:
|
||||
auth_key_dir = os.path.join(home, username, '.ssh')
|
||||
is_dir(auth_key_dir, username, mode=0700)
|
||||
mkdir(auth_key_dir, username, mode=0700)
|
||||
authorized_key_file = os.path.join(auth_key_dir, 'authorized_keys')
|
||||
with open(private_key_file+'.pub') as pub_f:
|
||||
with open(authorized_key_file, 'w') as auth_f:
|
||||
|
@ -205,49 +207,3 @@ def get_display_msg(user, password, ssh_key_pwd, ssh_key_login_need, send_mail_n
|
|||
|
||||
return msg
|
||||
|
||||
# def ldap_add_user(username, ldap_pwd):
|
||||
# """
|
||||
# add a user in ldap database
|
||||
# 在LDAP中添加用户
|
||||
# """
|
||||
# user_dn = "uid=%s,ou=People,%s" % (username, LDAP_BASE_DN)
|
||||
# password_sha512 = PyCrypt.gen_sha512(PyCrypt.random_pass(6), ldap_pwd)
|
||||
# user = get_object(User, username=username)
|
||||
# if not user:
|
||||
# raise ServerError(u'用户 %s 不存在' % username)
|
||||
#
|
||||
# user_attr = {'uid': [str(username)],
|
||||
# 'cn': [str(username)],
|
||||
# 'objectClass': ['account', 'posixAccount', 'top', 'shadowAccount'],
|
||||
# 'userPassword': ['{crypt}%s' % password_sha512],
|
||||
# 'shadowLastChange': ['16328'],
|
||||
# 'shadowMin': ['0'],
|
||||
# 'shadowMax': ['99999'],
|
||||
# 'shadowWarning': ['7'],
|
||||
# 'loginShell': ['/bin/bash'],
|
||||
# 'uidNumber': [str(user.id)],
|
||||
# 'gidNumber': [str(user.id)],
|
||||
# 'homeDirectory': [str('/home/%s' % username)]}
|
||||
#
|
||||
# group_dn = "cn=%s,ou=Group,%s" % (username, LDAP_BASE_DN)
|
||||
# group_attr = {'objectClass': ['posixGroup', 'top'],
|
||||
# 'cn': [str(username)],
|
||||
# 'userPassword': ['{crypt}x'],
|
||||
# 'gidNumber': [str(user.id)]}
|
||||
#
|
||||
# ldap_conn.add(user_dn, user_attr)
|
||||
# ldap_conn.add(group_dn, group_attr)
|
||||
|
||||
|
||||
# def ldap_del_user(username):
|
||||
# """
|
||||
# delete a user in ldap database
|
||||
# 在ldap中删除某用户
|
||||
# """
|
||||
# user_dn = "uid=%s,ou=People,%s" % (username, LDAP_BASE_DN)
|
||||
# group_dn = "cn=%s,ou=Group,%s" % (username, LDAP_BASE_DN)
|
||||
# sudo_dn = 'cn=%s,ou=Sudoers,%s' % (username, LDAP_BASE_DN)
|
||||
#
|
||||
# ldap_conn.delete(user_dn)
|
||||
# ldap_conn.delete(group_dn)
|
||||
# ldap_conn.delete(sudo_dn)
|
|
@ -201,14 +201,14 @@ def user_add(request):
|
|||
|
||||
if request.method == 'POST':
|
||||
username = request.POST.get('username', '')
|
||||
password = PyCrypt.random_pass(16)
|
||||
password = PyCrypt.gen_rand_pass(16)
|
||||
name = request.POST.get('name', '')
|
||||
email = request.POST.get('email', '')
|
||||
groups = request.POST.getlist('groups', [])
|
||||
admin_groups = request.POST.getlist('admin_groups', [])
|
||||
role = request.POST.get('role', 'CU')
|
||||
uuid = uuid_r.uuid1()
|
||||
ssh_key_pwd = PyCrypt.random_pass(16)
|
||||
ssh_key_pwd = PyCrypt.gen_rand_pass(16)
|
||||
extra = request.POST.getlist('extra', [])
|
||||
is_active = True if '0' in extra else False
|
||||
ssh_key_login_need = True if '1' in extra else False
|
||||
|
@ -241,14 +241,11 @@ def user_add(request):
|
|||
for user_group_id in groups:
|
||||
user_groups.extend(UserGroup.objects.filter(id=user_group_id))
|
||||
print user_groups
|
||||
results = _public_perm_api({'type': 'new_user', 'user': user, 'group': user_groups})
|
||||
print results
|
||||
except IndexError, e:
|
||||
error = u'添加用户 %s 失败 %s ' % (username, e)
|
||||
try:
|
||||
db_del_user(username)
|
||||
server_del_user(username)
|
||||
_public_perm_api({'type': 'del_user', 'user': user, 'group': user_groups})
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
|
@ -512,7 +509,7 @@ def regen_ssh_key(request):
|
|||
return HttpResponse('没有该用户')
|
||||
|
||||
username = user.username
|
||||
ssh_key_pass = PyCrypt.random_pass(16)
|
||||
ssh_key_pass = PyCrypt.gen_rand_pass(16)
|
||||
gen_ssh_key(username, ssh_key_pass)
|
||||
return HttpResponse('ssh密钥已生成,密码为 %s, 请到下载页面下载' % ssh_key_pass)
|
||||
|
||||
|
@ -530,7 +527,7 @@ def down_key(request):
|
|||
user = get_object(User, id=user_id)
|
||||
if user:
|
||||
username = user.username
|
||||
private_key_file = os.path.join(BASE_DIR, 'keys/jumpserver', username+".pem")
|
||||
private_key_file = os.path.join(BASE_DIR, 'role_keys/jumpserver', username + ".pem")
|
||||
if os.path.isfile(private_key_file):
|
||||
f = open(private_key_file)
|
||||
data = f.read()
|
||||
|
|
|
@ -179,7 +179,7 @@ class WebTty(Tty):
|
|||
super(WebTty, self).__init__(*args, **kwargs)
|
||||
self.login_type = 'web'
|
||||
self.ws = None
|
||||
self.input_r = ''
|
||||
self.data = ''
|
||||
self.input_mode = False
|
||||
|
||||
|
||||
|
@ -197,12 +197,11 @@ class WebTerminalKillHandler(tornado.web.RequestHandler):
|
|||
|
||||
|
||||
class WebTerminalHandler(tornado.websocket.WebSocketHandler):
|
||||
tasks = []
|
||||
clients = []
|
||||
tasks = []
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.term = None
|
||||
self.channel = None
|
||||
self.log_file_f = None
|
||||
self.log_time_f = None
|
||||
self.log = None
|
||||
|
@ -220,7 +219,7 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler):
|
|||
print asset_name, username, token
|
||||
self.term = WebTty('a', 'b')
|
||||
self.term.get_connection()
|
||||
self.channel = self.term.ssh.invoke_shell(term='xterm')
|
||||
self.term.channel = self.term.ssh.invoke_shell(term='xterm')
|
||||
WebTerminalHandler.tasks.append(MyThread(target=self.forward_outbound))
|
||||
WebTerminalHandler.clients.append(self)
|
||||
|
||||
|
@ -237,10 +236,10 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler):
|
|||
if data.get('data'):
|
||||
self.term.input_mode = True
|
||||
if str(data['data']) in ['\r', '\n', '\r\n']:
|
||||
TtyLog(log=self.log, datetime=datetime.datetime.now(), cmd=self.term.remove_control_char(self.term.input_r)).save()
|
||||
self.term.input_r = ''
|
||||
TtyLog(log=self.log, datetime=datetime.datetime.now(), cmd=self.term.remove_control_char(self.term.data)).save()
|
||||
self.term.data = ''
|
||||
self.term.input_mode = False
|
||||
self.channel.send(data['data'])
|
||||
self.term.channel.send(data['data'])
|
||||
|
||||
def on_close(self):
|
||||
print 'On_close'
|
||||
|
@ -256,15 +255,15 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler):
|
|||
pass
|
||||
|
||||
def forward_outbound(self):
|
||||
self.log_file_f, self.log_time_f, self.log = self.term.get_log_file()
|
||||
self.log_file_f, self.log_time_f, self.log = self.term.get_log()
|
||||
self.id = self.log.id
|
||||
try:
|
||||
data = ''
|
||||
pre_timestamp = time.time()
|
||||
while True:
|
||||
r, w, e = select.select([self.channel, sys.stdin], [], [])
|
||||
if self.channel in r:
|
||||
recv = self.channel.recv(1024)
|
||||
r, w, e = select.select([self.term.channel, sys.stdin], [], [])
|
||||
if self.term.channel in r:
|
||||
recv = self.term.channel.recv(1024)
|
||||
if not len(recv):
|
||||
return
|
||||
data += recv
|
||||
|
@ -277,7 +276,7 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler):
|
|||
self.log_file_f.flush()
|
||||
self.log_time_f.flush()
|
||||
if self.term.input_mode and not self.term.is_output(data):
|
||||
self.term.input_r += data
|
||||
self.term.data += data
|
||||
data = ''
|
||||
except UnicodeDecodeError:
|
||||
pass
|
||||
|
|
|
@ -4562,3 +4562,8 @@ body.skin-3 {
|
|||
.red-fonts {
|
||||
color: #ed5565;
|
||||
}
|
||||
|
||||
.form-group.required .control-label:after {
|
||||
content: " *";
|
||||
color: red;
|
||||
}
|
|
@ -135,3 +135,11 @@ function selectAll(){
|
|||
// })
|
||||
//}
|
||||
|
||||
function getIDall() {
|
||||
var check_array = [];
|
||||
$(".gradeX input:checked").each(function () {
|
||||
var id = $(this).attr("value");
|
||||
check_array.push(id);
|
||||
});
|
||||
return check_array.join(",");
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
define("echarts/chart/heatmap",["require","./base","../layer/heatmap","../config","../util/ecData","zrender/tool/util","zrender/tool/color","zrender/shape/Image","../chart"],function(e){function t(e,t,n,a,o){i.call(this,e,t,n,a,o),this.refresh(a)}var i=e("./base"),n=e("../layer/heatmap"),a=e("../config"),o=(e("../util/ecData"),e("zrender/tool/util")),r=(e("zrender/tool/color"),e("zrender/shape/Image"));return a.heatmap={zlevel:0,z:2,clickable:!0},t.prototype={type:a.CHART_TYPE_HEATMAP,refresh:function(e){this.clear(),e&&(this.option=e,this.series=e.series),this._init()},_init:function(){var e=this.series;this.backupShapeList();for(var t=e.length,i=0;t>i;++i)if(e[i].type===a.CHART_TYPE_HEATMAP){e[i]=this.reformOption(e[i]);var o=new n(e[i]),s=o.getCanvas(e[i].data,this.zr.getWidth(),this.zr.getHeight()),l=new r({position:[0,0],scale:[1,1],hoverable:this.option.hoverable,style:{x:0,y:0,image:s,width:s.width,height:s.height}});this.shapeList.push(l)}this.addShapeList()}},o.inherits(t,i),e("../chart").define("heatmap",t),t}),define("echarts/layer/heatmap",["require"],function(){function e(e){if(this.option=e,e)for(var i in t)this.option[i]=void 0!==e[i]?e[i]:t[i];else this.option=t}var t={blurSize:30,gradientColors:["blue","cyan","lime","yellow","red"],minAlpha:.05,valueScale:1,opacity:1},i=20,n=256;return e.prototype={getCanvas:function(e,t,a){var o=this._getBrush(),r=this._getGradient(),s=i+this.option.blurSize,l=document.createElement("canvas");l.width=t,l.height=a;for(var h=l.getContext("2d"),m=e.length,V=0;m>V;++V){var d=e[V],U=d[0],p=d[1],c=d[2],u=Math.min(1,Math.max(c*this.option.valueScale||this.option.minAlpha,this.option.minAlpha));h.globalAlpha=u,h.drawImage(o,U-s,p-s)}for(var g=h.getImageData(0,0,l.width,l.height),y=g.data,m=y.length/4;m--;){var b=4*m+3,u=y[b]/256,f=Math.floor(u*(n-1));y[b-3]=r[4*f],y[b-2]=r[4*f+1],y[b-1]=r[4*f+2],y[b]*=this.option.opacity}return h.putImageData(g,0,0),l},_getBrush:function(){if(!this._brushCanvas){this._brushCanvas=document.createElement("canvas");var e=i+this.option.blurSize,t=2*e;this._brushCanvas.width=t,this._brushCanvas.height=t;var n=this._brushCanvas.getContext("2d");n.shadowOffsetX=t,n.shadowBlur=this.option.blurSize,n.shadowColor="black",n.beginPath(),n.arc(-e,e,i,0,2*Math.PI,!0),n.closePath(),n.fill()}return this._brushCanvas},_getGradient:function(){if(!this._gradientPixels){var e=n,t=document.createElement("canvas");t.width=1,t.height=e;for(var i=t.getContext("2d"),a=i.createLinearGradient(0,0,0,e),o=this.option.gradientColors.length,r=0;o>r;++r)"string"==typeof this.option.gradientColors[r]?a.addColorStop((r+1)/o,this.option.gradientColors[r]):a.addColorStop(this.option.gradientColors[r].offset,this.option.gradientColors[r].color);i.fillStyle=a,i.fillRect(0,0,1,e),this._gradientPixels=i.getImageData(0,0,1,e).data}return this._gradientPixels}},e}),define("echarts/layer/heatmap",["require"],function(){function e(e){if(this.option=e,e)for(var i in t)this.option[i]=void 0!==e[i]?e[i]:t[i];else this.option=t}var t={blurSize:30,gradientColors:["blue","cyan","lime","yellow","red"],minAlpha:.05,valueScale:1,opacity:1},i=20,n=256;return e.prototype={getCanvas:function(e,t,a){var o=this._getBrush(),r=this._getGradient(),s=i+this.option.blurSize,l=document.createElement("canvas");l.width=t,l.height=a;for(var h=l.getContext("2d"),m=e.length,V=0;m>V;++V){var d=e[V],U=d[0],p=d[1],c=d[2],u=Math.min(1,Math.max(c*this.option.valueScale||this.option.minAlpha,this.option.minAlpha));h.globalAlpha=u,h.drawImage(o,U-s,p-s)}for(var g=h.getImageData(0,0,l.width,l.height),y=g.data,m=y.length/4;m--;){var b=4*m+3,u=y[b]/256,f=Math.floor(u*(n-1));y[b-3]=r[4*f],y[b-2]=r[4*f+1],y[b-1]=r[4*f+2],y[b]*=this.option.opacity}return h.putImageData(g,0,0),l},_getBrush:function(){if(!this._brushCanvas){this._brushCanvas=document.createElement("canvas");var e=i+this.option.blurSize,t=2*e;this._brushCanvas.width=t,this._brushCanvas.height=t;var n=this._brushCanvas.getContext("2d");n.shadowOffsetX=t,n.shadowBlur=this.option.blurSize,n.shadowColor="black",n.beginPath(),n.arc(-e,e,i,0,2*Math.PI,!0),n.closePath(),n.fill()}return this._brushCanvas},_getGradient:function(){if(!this._gradientPixels){var e=n,t=document.createElement("canvas");t.width=1,t.height=e;for(var i=t.getContext("2d"),a=i.createLinearGradient(0,0,0,e),o=this.option.gradientColors.length,r=0;o>r;++r)"string"==typeof this.option.gradientColors[r]?a.addColorStop((r+1)/o,this.option.gradientColors[r]):a.addColorStop(this.option.gradientColors[r].offset,this.option.gradientColors[r].color);i.fillStyle=a,i.fillRect(0,0,1,e),this._gradientPixels=i.getImageData(0,0,1,e).data}return this._gradientPixels}},e});
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -180,7 +180,7 @@ function merge() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Take an array and turn into a hash with even number arguments as keys and odd numbers as
|
||||
* Take an array and turn into a hash with even number arguments as role_keys and odd numbers as
|
||||
* values. Allows creating constants for commonly used style properties, attributes etc.
|
||||
* Avoid it in performance critical situations like looping
|
||||
*/
|
||||
|
@ -448,7 +448,7 @@ dateFormat = function (format, timestamp, capitalize) {
|
|||
lang = defaultOptions.lang,
|
||||
langWeekdays = lang.weekdays,
|
||||
|
||||
// List all format keys. Custom formats can be added from the outside.
|
||||
// List all format role_keys. Custom formats can be added from the outside.
|
||||
replacements = extend({
|
||||
|
||||
// Day
|
||||
|
@ -14895,7 +14895,7 @@ var AreaSeries = extendClass(Series, {
|
|||
pointMap[points[i].x] = points[i];
|
||||
}
|
||||
|
||||
// Sort the keys (#1651)
|
||||
// Sort the role_keys (#1651)
|
||||
for (x in stack) {
|
||||
if (stack[x].total !== null) { // nulled after switching between grouping and not (#1651, #2336)
|
||||
keys.push(+x);
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -358,7 +358,7 @@
|
|||
getRelated(settings.get('rel'));
|
||||
|
||||
if (!open) {
|
||||
open = active = true; // Prevents the page-change action from queuing up if the visitor holds down the left or right keys.
|
||||
open = active = true; // Prevents the page-change action from queuing up if the visitor holds down the left or right role_keys.
|
||||
|
||||
setClass(settings.get('className'));
|
||||
|
||||
|
|
|
@ -2777,7 +2777,7 @@ Terminal.prototype.deviceStatus = function(params) {
|
|||
// this.send('\x1b[?11n');
|
||||
break;
|
||||
case 25:
|
||||
// dont support user defined keys
|
||||
// dont support user defined role_keys
|
||||
// this.send('\x1b[?21n');
|
||||
break;
|
||||
case 26:
|
||||
|
@ -2964,7 +2964,7 @@ Terminal.prototype.HPositionRelative = function(params) {
|
|||
// Ps = 1 -> 132-columns.
|
||||
// Ps = 2 -> Printer.
|
||||
// Ps = 6 -> Selective erase.
|
||||
// Ps = 8 -> User-defined keys.
|
||||
// Ps = 8 -> User-defined role_keys.
|
||||
// Ps = 9 -> National replacement character sets.
|
||||
// Ps = 1 5 -> Technical characters.
|
||||
// Ps = 2 2 -> ANSI color, e.g., VT525.
|
||||
|
@ -3105,7 +3105,7 @@ Terminal.prototype.HVPosition = function(params) {
|
|||
// Ps = 1 0 3 4 -> Interpret "meta" key, sets eighth bit.
|
||||
// (enables the eightBitInput resource).
|
||||
// Ps = 1 0 3 5 -> Enable special modifiers for Alt and Num-
|
||||
// Lock keys. (This enables the numLock resource).
|
||||
// Lock role_keys. (This enables the numLock resource).
|
||||
// Ps = 1 0 3 6 -> Send ESC when Meta modifies a key. (This
|
||||
// enables the metaSendsEscape resource).
|
||||
// Ps = 1 0 3 7 -> Send DEL from the editing-keypad Delete
|
||||
|
@ -3304,7 +3304,7 @@ Terminal.prototype.setMode = function(params) {
|
|||
// Ps = 1 0 3 4 -> Don't interpret "meta" key. (This disables
|
||||
// the eightBitInput resource).
|
||||
// Ps = 1 0 3 5 -> Disable special modifiers for Alt and Num-
|
||||
// Lock keys. (This disables the numLock resource).
|
||||
// Lock role_keys. (This disables the numLock resource).
|
||||
// Ps = 1 0 3 6 -> Don't send ESC when Meta modifies a key.
|
||||
// (This disables the metaSendsEscape resource).
|
||||
// Ps = 1 0 3 7 -> Send VT220 Remove from the editing-keypad
|
||||
|
@ -3588,7 +3588,7 @@ Terminal.prototype.setResources = function(params) {
|
|||
// Ps = 4 -> modifyOtherKeys.
|
||||
// If the parameter is omitted, modifyFunctionKeys is disabled.
|
||||
// When modifyFunctionKeys is disabled, xterm uses the modifier
|
||||
// keys to make an extended sequence of functions rather than
|
||||
// role_keys to make an extended sequence of functions rather than
|
||||
// adding a parameter to each function key to denote the modi-
|
||||
// fiers.
|
||||
Terminal.prototype.disableModifiers = function(params) {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
<!-- highcharts -->
|
||||
<script src="/static/js/highcharts/highcharts.js"></script>
|
||||
|
||||
|
||||
<script src="/static/js/dropzone/dropzone.js"></script>
|
||||
<!-- active menu -->
|
||||
<script>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
</div>
|
||||
<div class="ibox-content">
|
||||
<h1 class="no-margins"><a href="/juser/user_list/">{{ users.count}}</a></h1>
|
||||
<div class="stat-percent font-bold text-success">{{ percent_user }} <i class="fa fa-bolt"></i></div>
|
||||
{# <div class="stat-percent font-bold text-success">{{ percent_user }} <i class="fa fa-bolt"></i></div>#}
|
||||
<small>All user</small>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -27,7 +27,7 @@
|
|||
</div>
|
||||
<div class="ibox-content">
|
||||
<h1 class="no-margins"><a href="/jasset/host_list/">{{ hosts.count }}</a></h1>
|
||||
<div class="stat-percent font-bold text-info">{{ percent_host }} <i class="fa fa-level-up"></i></div>
|
||||
{# <div class="stat-percent font-bold text-info">{{ percent_host }} <i class="fa fa-level-up"></i></div>#}
|
||||
<small>All host</small>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -40,8 +40,8 @@
|
|||
<h5>实时在线用户</h5>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<h1 class="no-margins"><a href="/jlog/log_list/online/"> <span id="online_users"></span></a></h1>
|
||||
<div class="stat-percent font-bold text-navy">{{ percent_online_user }} <i class="fa fa-level-up"></i></div>
|
||||
<h1 class="no-margins"><a href="/jlog/log_list/online/"> <span id="online_users">{{ online_user | length }}</span></a></h1>
|
||||
{# <div class="stat-percent font-bold text-navy">{{ percent_online_user }} <i class="fa fa-level-up"></i></div>#}
|
||||
<small>Online user</small>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -54,15 +54,15 @@
|
|||
<h5>已连接服务器</h5>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<h1 class="no-margins"><a href="/jlog/log_list/online/"> <span id="online_hosts"></span></a></h1>
|
||||
<div class="stat-percent font-bold text-danger">{{ percent_online_host }} <i class="fa fa-level-down"></i></div>
|
||||
<h1 class="no-margins"><a href="/jlog/log_list/online/"> <span id="online_hosts">{{ online_host | length }}</span></a></h1>
|
||||
{# <div class="stat-percent font-bold text-danger">{{ percent_online_host }} <i class="fa fa-level-down"></i></div>#}
|
||||
<small>Connected host</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 border-bottom white-bg dashboard-header" style="margin-left:15px;height: 346px">
|
||||
<div class="col-sm-2 border-bottom white-bg dashboard-header" style="margin-left:15px;height: 346px">
|
||||
<h2>活跃用户TOP5</h2>
|
||||
<small>过去一周共有<span class="text-info">{{ week_users }}</span>位用户登录<span class="text-success">{{ week_hosts }}</span>次服务器.</small>
|
||||
<ul class="list-group clear-list m-t">
|
||||
|
@ -76,7 +76,32 @@
|
|||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-lg-9" id="top10" style="margin-left: -15px;height: 345px"></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="statistic-box">
|
||||
<h4>
|
||||
活跃用户资产占比
|
||||
</h4>
|
||||
<p>
|
||||
以下图形分别描述一个月活跃用户和资产占所有用户主机的百分比
|
||||
</p>
|
||||
<div class="row text-center">
|
||||
<div class="col-lg-6">
|
||||
<div id="activeUser" style="width: 140px; height: 140px;">
|
||||
|
||||
</div>
|
||||
<h5>用户</h5>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div id="activeAsset" style="width: 140px; height: 140px;"></div>
|
||||
<h5>主机</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="m-t">
|
||||
<small></small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
|
@ -126,6 +151,51 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<h5>一周Top10资产</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"></ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content ibox-heading">
|
||||
<h3><i class="fa fa-user"></i> 一周Top10资产 </h3>
|
||||
<small><i class="fa fa-map-marker"></i> 登录次数及最近一次登录记录. </small>
|
||||
</div>
|
||||
<div class="ibox-content inspinia-timeline">
|
||||
{% if host_top_ten %}
|
||||
{% for data in host_top_ten %}
|
||||
<div class="timeline-item">
|
||||
<div class="row">
|
||||
<div class="col-xs-5 date">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
<strong>{{ data.host }}</strong>
|
||||
<br/>
|
||||
<small class="text-navy">{{ data.times }}次</small>
|
||||
</div>
|
||||
<div class="col-xs-7 content no-top-border">
|
||||
<p class="m-b-xs">最近一次登录用户</p>
|
||||
<p>{{ data.last.user }}</p>
|
||||
<p>于{{ data.last.start_time |date:"Y-m-d H:i:s" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p class="text-center">(暂无)</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="ibox float-e-margins">
|
||||
|
@ -137,7 +207,7 @@
|
|||
</div>
|
||||
<div class="ibox-content ibox-heading">
|
||||
<h3><i class="fa fa-paper-plane-o"></i> 登录记录 </h3>
|
||||
<small<i class="fa fa-map-marker"></i> 最近十次登录记录. </small>
|
||||
<small><i class="fa fa-map-marker"></i> 最近十次登录记录. </small>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<div>
|
||||
|
@ -212,7 +282,7 @@
|
|||
</div>
|
||||
<div class="ibox-content ibox-heading">
|
||||
<h3><i class="fa fa-user"></i> 一周Top10用户 </h3>
|
||||
<small><i class="fa fa-map-marker"></i> 一周Top10用户登录次数及最近一次登录记录. </small>
|
||||
<small><i class="fa fa-map-marker"></i> 用户登录次数及最近一次登录记录. </small>
|
||||
</div>
|
||||
<div class="ibox-content inspinia-timeline">
|
||||
{% if user_top_ten %}
|
||||
|
@ -226,7 +296,7 @@
|
|||
<small class="text-navy">{{ data.times }}次</small>
|
||||
</div>
|
||||
<div class="col-xs-7 content no-top-border">
|
||||
<p class="m-b-xs">最近一次登录</p>
|
||||
<p class="m-b-xs">最近一次登录主机</p>
|
||||
<p>{{ data.last.host }}</p>
|
||||
<p>于{{ data.last.start_time |date:"Y-m-d H:i:s" }}</p>
|
||||
</div>
|
||||
|
@ -247,162 +317,257 @@
|
|||
<!--<div class="col-lg-6" id="hosttop10" style="width:50%;height:400px; margin-top: 20px"></div>-->
|
||||
<!--</div>-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block self_footer_js %}
|
||||
<script src="/static/js/echarts/echarts.js"></script>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$('#show').click(function(){
|
||||
$('#show').css('display', 'none');
|
||||
$('#more').css('display', 'block');
|
||||
})
|
||||
})
|
||||
var cate = {{ li_str|safe }};
|
||||
$(function () {
|
||||
$('#top10').highcharts({
|
||||
// chart: {
|
||||
// type: 'column'
|
||||
// },
|
||||
title: {
|
||||
text: '一周数据总览',
|
||||
x: -20 //center
|
||||
},
|
||||
subtitle: {
|
||||
text: 'Source: JumpServer',
|
||||
x: -20
|
||||
},
|
||||
rangeSelector: {
|
||||
allButtonsEnabled: true,
|
||||
selected: 2
|
||||
},
|
||||
xAxis: {
|
||||
type: 'datetime',
|
||||
categories: cate
|
||||
},
|
||||
yAxis:{
|
||||
min: 0,
|
||||
title: {
|
||||
text: ''
|
||||
},
|
||||
plotLines: [{
|
||||
value: 0,
|
||||
width: 1,
|
||||
color: '#808080'
|
||||
}]
|
||||
},
|
||||
tooltip: {
|
||||
valueSuffix: '次'
|
||||
},
|
||||
navigation: {
|
||||
buttonOptions: {
|
||||
align: 'right'
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{% for k,v in top_dic.items %}
|
||||
{
|
||||
name: '{{ k }}',
|
||||
data: {{ v }}
|
||||
},
|
||||
{% endfor %}
|
||||
]
|
||||
});
|
||||
|
||||
$('#usertop10').highcharts({
|
||||
title: {
|
||||
text: '一周用户登录TOP10',
|
||||
x: -20 //center
|
||||
},
|
||||
subtitle: {
|
||||
text: 'Source: JumpServer',
|
||||
x: -20
|
||||
},
|
||||
xAxis: {
|
||||
type: 'datetime',
|
||||
categories: cate
|
||||
},
|
||||
yAxis:{
|
||||
min: 0,
|
||||
title: {
|
||||
text: '登录次数'
|
||||
},
|
||||
plotLines: [{
|
||||
value: 0,
|
||||
width: 1,
|
||||
color: '#808080'
|
||||
}]
|
||||
},
|
||||
tooltip: {
|
||||
valueSuffix: '次'
|
||||
},
|
||||
series: [
|
||||
{% for k,v in user_dic.items %}
|
||||
{
|
||||
name: '{{ k }}',
|
||||
data: {{ v }}
|
||||
},
|
||||
{% endfor %}
|
||||
]
|
||||
});
|
||||
|
||||
$('#hosttop10').highcharts({
|
||||
title: {
|
||||
text: '一周主机登录TOP10',
|
||||
x: -20 //center
|
||||
},
|
||||
subtitle: {
|
||||
text: 'Source: JumpServer',
|
||||
x: -20
|
||||
},
|
||||
xAxis: {
|
||||
type: 'datetime',
|
||||
categories: cate
|
||||
},
|
||||
yAxis:{
|
||||
min: 0,
|
||||
title: {
|
||||
text: '登录次数'
|
||||
},
|
||||
plotLines: [{
|
||||
value: 0,
|
||||
width: 1,
|
||||
color: '#808080'
|
||||
}]
|
||||
},
|
||||
tooltip: {
|
||||
valueSuffix: '次'
|
||||
},
|
||||
series: [
|
||||
{% for k,v in host_dic.items %}
|
||||
{
|
||||
name: '{{ k }}',
|
||||
data: {{ v }}
|
||||
},
|
||||
{% endfor %}
|
||||
]
|
||||
});
|
||||
|
||||
function magic_number(value, id) {
|
||||
var num = $("#"+id);
|
||||
num.animate({count: value}, {
|
||||
duration: 500,
|
||||
step: function() {
|
||||
num.text(String(parseInt(this.count)));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function update() {
|
||||
$.getJSON('api/user/', function(data) {
|
||||
var users = data.users;
|
||||
var hosts = data.hosts;
|
||||
magic_number(users, 'online_users');
|
||||
magic_number(hosts, 'online_hosts')
|
||||
});
|
||||
};
|
||||
|
||||
setInterval(update, 5000); //5秒钟执行一次
|
||||
update();
|
||||
|
||||
});
|
||||
|
||||
require.config({
|
||||
paths: {
|
||||
'echarts': '/static/js/echarts/chart',
|
||||
'echarts/chart/line': '/static/js/echarts/chart/line',
|
||||
'echarts/chart/pie': '/static/js/echarts/chart/pie'
|
||||
}
|
||||
});
|
||||
require(
|
||||
[
|
||||
'echarts',
|
||||
'echarts/chart/line'
|
||||
],
|
||||
function (ec) {
|
||||
var top10Chart = ec.init(document.getElementById('top10'));
|
||||
var option = {
|
||||
title : {
|
||||
text: '月数据总览',
|
||||
subtext: '一个月内历史汇总',
|
||||
x: 'center'
|
||||
},
|
||||
tooltip : {
|
||||
trigger: 'axis'
|
||||
},
|
||||
backgroundColor: '#fff',
|
||||
legend: {
|
||||
data:['登陆次数', '活跃用户','活跃资产'],
|
||||
y: 'bottom'
|
||||
},
|
||||
toolbox: {
|
||||
show : false,
|
||||
feature : {
|
||||
{# mark : {show: true},#}
|
||||
{# dataView : {show: true, readOnly: false},#}
|
||||
magicType : {show: true, type: ['line', 'bar']}
|
||||
}
|
||||
},
|
||||
calculable : true,
|
||||
xAxis : [
|
||||
{
|
||||
type : 'category',
|
||||
boundaryGap : false,
|
||||
data : {{ date_month | safe}}
|
||||
}
|
||||
],
|
||||
yAxis : [
|
||||
{
|
||||
type : 'value'
|
||||
}
|
||||
],
|
||||
series : [
|
||||
{
|
||||
name:'登陆次数',
|
||||
type:'line',
|
||||
smooth:true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data: {{ active_login_per_month | safe }}
|
||||
},
|
||||
{
|
||||
name:'活跃用户',
|
||||
type:'line',
|
||||
smooth:true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data: {{ active_user_per_month | safe }}
|
||||
},
|
||||
{
|
||||
name:'活跃资产',
|
||||
type:'line',
|
||||
smooth:true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data: {{ active_asset_per_month | safe }}
|
||||
}
|
||||
|
||||
]
|
||||
};
|
||||
|
||||
top10Chart.setOption(option);
|
||||
}
|
||||
);
|
||||
|
||||
require(
|
||||
[
|
||||
'echarts',
|
||||
'echarts/chart/pie'
|
||||
],
|
||||
function (ec) {
|
||||
var auChart = ec.init(document.getElementById('activeUser'));
|
||||
var option = {
|
||||
tooltip : {
|
||||
trigger: 'item',
|
||||
formatter: "{b} <br> {c} ({d}%)"
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
orient : 'vertical',
|
||||
x : 'left',
|
||||
data:['月活跃用户','禁用用户','月未登陆用户']
|
||||
},
|
||||
toolbox: {
|
||||
show : false,
|
||||
feature : {
|
||||
mark : {show: true},
|
||||
dataView : {show: true, readOnly: false},
|
||||
magicType : {
|
||||
show: true,
|
||||
type: ['pie', 'funnel'],
|
||||
option: {
|
||||
funnel: {
|
||||
x: '25%',
|
||||
width: '50%',
|
||||
funnelAlign: 'center',
|
||||
max: 1548
|
||||
}
|
||||
}
|
||||
},
|
||||
restore : {show: true},
|
||||
saveAsImage : {show: true}
|
||||
}
|
||||
},
|
||||
calculable : true,
|
||||
series : [
|
||||
{
|
||||
name:'访问来源',
|
||||
type:'pie',
|
||||
radius : ['50%', '70%'],
|
||||
itemStyle : {
|
||||
normal : {
|
||||
label : {
|
||||
show : false
|
||||
},
|
||||
labelLine : {
|
||||
show : false
|
||||
}
|
||||
},
|
||||
emphasis : {
|
||||
label : {
|
||||
show : true,
|
||||
position : 'center',
|
||||
textStyle : {
|
||||
fontSize : '5',
|
||||
fontWeight : 'bold'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data:[
|
||||
{value:{{ active_user_month }}, name:'月活跃用户'},
|
||||
{value:{{ disabled_user_count }}, name:'禁用用户'},
|
||||
{value:{{ inactive_user_month }}, name:'月未登陆用户'}
|
||||
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
auChart.setOption(option);
|
||||
}
|
||||
);
|
||||
|
||||
require(
|
||||
[
|
||||
'echarts',
|
||||
'echarts/chart/pie'
|
||||
],
|
||||
function (ec) {
|
||||
var aaChart = ec.init(document.getElementById('activeAsset'));
|
||||
var option = {
|
||||
tooltip : {
|
||||
trigger: 'item',
|
||||
formatter: "{b} <br> {c} ({d}%)"
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
orient : 'vertical',
|
||||
x : 'left',
|
||||
data:['月被登陆主机','禁用主机','月未登陆主机']
|
||||
},
|
||||
toolbox: {
|
||||
show : false,
|
||||
feature : {
|
||||
mark : {show: true},
|
||||
dataView : {show: true, readOnly: false},
|
||||
magicType : {
|
||||
show: true,
|
||||
type: ['pie', 'funnel'],
|
||||
option: {
|
||||
funnel: {
|
||||
x: '25%',
|
||||
width: '50%',
|
||||
funnelAlign: 'center',
|
||||
max: 1548
|
||||
}
|
||||
}
|
||||
},
|
||||
restore : {show: true},
|
||||
saveAsImage : {show: true}
|
||||
}
|
||||
},
|
||||
calculable : true,
|
||||
series : [
|
||||
{
|
||||
name:'访问来源',
|
||||
type:'pie',
|
||||
radius : ['50%', '70%'],
|
||||
itemStyle : {
|
||||
normal : {
|
||||
label : {
|
||||
show : false
|
||||
},
|
||||
labelLine : {
|
||||
show : false
|
||||
}
|
||||
},
|
||||
emphasis : {
|
||||
label : {
|
||||
show : true,
|
||||
position : 'center',
|
||||
textStyle : {
|
||||
fontSize : '5',
|
||||
fontWeight : 'bold'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data:[
|
||||
{value:{{ active_asset_month }}, name:'月被登陆主机'},
|
||||
{value:{{ disabled_asset_count }}, name:'禁用主机'},
|
||||
{value:{{ inactive_asset_month }}, name:'月未登陆主机'}
|
||||
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
aaChart.setOption(option);
|
||||
}
|
||||
);
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
|
@ -1,5 +1,6 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load mytags %}
|
||||
{% load bootstrap %}
|
||||
{% block content %}
|
||||
{% include 'nav_cat_bar.html' %}
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
|
@ -26,7 +27,7 @@
|
|||
<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>
|
||||
<li><a href="/jasset/asset_add_batch" class="text-center"><i class="fa fa-bar-chart-o"></i> 批量添加 </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
|
@ -38,28 +39,29 @@
|
|||
{% 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>
|
||||
|
||||
{{ af.ip|bootstrap_horizontal }}
|
||||
|
||||
<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="form-group">
|
||||
<label for="j_group" class="col-sm-2 control-label">使用默认</label>
|
||||
<div class="col-sm-1">
|
||||
<label for="j_group" class="col-sm-2 control-label">管理账号<span class="red-fonts"> *</span></label>
|
||||
<div class="col-sm-2">
|
||||
<div class="radio i-checks">
|
||||
<label>
|
||||
<input type="checkbox" checked="" value="1" id="use_default" name="use_default">
|
||||
<input type="checkbox" checked="" id="id_use_default_auth" name="use_default_auth"><span> 使用默认 </span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="port" style="display: none">
|
||||
<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="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">
|
||||
|
@ -73,32 +75,20 @@
|
|||
</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>
|
||||
{{ af.group|bootstrap_horizontal }}
|
||||
|
||||
{# {{ af.is_active|bootstrap_horizontal }}#}
|
||||
|
||||
<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="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>
|
||||
<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">
|
||||
|
@ -120,39 +110,47 @@
|
|||
|
||||
{% block self_footer_js %}
|
||||
<script>
|
||||
$('document').ready(function(){
|
||||
$('#id_use_default_auth').click(function(){
|
||||
if ($(this).is(':checked')){
|
||||
$('#admin_account').css('display', 'none')
|
||||
}
|
||||
else {
|
||||
$('#admin_account').css('display', 'block')
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
$('document').ready(function(){
|
||||
$('#use_default').click(function(){
|
||||
if ($(this).is(':checked')){
|
||||
$('#admin_account').css('display', 'none');
|
||||
$('#port').css('display', 'none')
|
||||
}
|
||||
else {
|
||||
$('#admin_account').css('display', 'block');
|
||||
$('#port').css('display', 'block')
|
||||
}
|
||||
})
|
||||
});
|
||||
var required_fields = ["id_hostname", "id_ip", "id_port"];
|
||||
required_fields.forEach(function(field) {
|
||||
$('label[for="' + field + '"]').parent().addClass("required");
|
||||
});
|
||||
|
||||
$('#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: "必须填写!"}
|
||||
$('#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();
|
||||
}
|
||||
},
|
||||
valid: function(form) {
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
{% 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 %}
|
|
@ -0,0 +1,65 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
{% include 'nav_cat_bar.html' %}
|
||||
<style>
|
||||
.file-box{ position:relative;width:340px}
|
||||
.txt{ height:22px; border:1px solid #cdcdcd; width:180px;}
|
||||
.file{ position:absolute; top:0; right:80px; height:24px; filter:alpha(opacity:0);opacity: 0;width:260px }
|
||||
</style>
|
||||
<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">
|
||||
</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/asset_add/" class="text-center"><i class="fa fa-laptop"></i> 单台添加 </a></li>
|
||||
<li class="active"><a href="/jasset/asset_add_batch/" 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>请下载Excel文件, 按照格式填写主机信息, 上传导入. <a href="/static/files/excels/asset.xlsx">点击下载模板</a></p>
|
||||
<form action="/jasset/upload/" method="POST" enctype="multipart/form-data">
|
||||
<div class="file-box">
|
||||
<input id='textfield' />
|
||||
<input type="button" class="btn btn-info btn-sm" name="file_name" value="点击选择文件">
|
||||
<input type="file" name="file_name" class="file" id="fileField" size="28" onchange="document.getElementById('textfield').value=this.value" />
|
||||
<button class="btn btn-primary btn-sm" type="submit">上传文件</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -1,6 +1,6 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load mytags %}
|
||||
|
||||
{% load humanize %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'nav_cat_bar.html' %}
|
||||
|
@ -33,6 +33,28 @@
|
|||
<td class="text-navy">IP</td>
|
||||
<td>{{ asset.ip }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">主机名</td>
|
||||
<td>{{ asset.hostname }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">其他IP</td>
|
||||
<td>
|
||||
<table class="table">
|
||||
{% if asset.other_ip %}
|
||||
{% for ip in asset.other_ip|ip_str_to_list %}
|
||||
<tr>
|
||||
<td>{{ ip }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">远控IP</td>
|
||||
<td>{{ asset.remote_ip }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">端口</td>
|
||||
<td>{{ asset.port }}</td>
|
||||
|
@ -42,12 +64,80 @@
|
|||
<td class="text-navy">主机组</td>
|
||||
<td>
|
||||
<table class="table">
|
||||
{% for asset_group in asset.group.all %}
|
||||
<tr>
|
||||
<td>{{ asset_group.name }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">使用默认管理账号</td>
|
||||
<td>{{ asset.use_default_auth|bool2str }}</td>
|
||||
{# <td>{{ asset.use_default_auth|bool2str }}</td>#}
|
||||
<td>{{ asset.use_default_auth|bool2str }} {% if not asset.use_default_auth %} <span class="text-info">{{ asset.username }}</span> {% endif %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">机房</td>
|
||||
<td>{{ asset.idc.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">硬件厂商型号</td>
|
||||
<td>{{ asset.brand }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">CPU</td>
|
||||
<td>{{ asset.cpu }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">内存</td>
|
||||
<td>{{ asset.memory }}M</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">硬盘</td>
|
||||
<td>
|
||||
<table class="table">
|
||||
{% if asset.disk %}
|
||||
{% for disk, value in asset.disk|str_to_dic %}
|
||||
<tr>
|
||||
<td><span class="text-navy">{{ disk }}</span>     {{ value }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">资产编号</td>
|
||||
<td>{{ asset.number }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">SN</td>
|
||||
<td>{{ asset.sn }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">主机类型</td>
|
||||
<td>{{ asset.get_asset_type_display }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">系统版本</td>
|
||||
<td>{{ asset.system_type }} {{ asset.system_version }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">运行环境</td>
|
||||
<td>{{ asset.get_env_display }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">机器状态</td>
|
||||
<td>{{ asset.get_status_display }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">机柜号</td>
|
||||
<td>{{ asset.cabinet }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">机柜位置</td>
|
||||
<td>{{ asset.position }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">激活</td>
|
||||
|
@ -91,8 +181,8 @@
|
|||
</div>
|
||||
<div class="ibox-content">
|
||||
<div>
|
||||
<div class="text-left">
|
||||
<table class="table">
|
||||
{# <div class="text-left">#}
|
||||
{# <table class="table">#}
|
||||
{# {% if user_permed_list %}#}
|
||||
{# {% for user in user_permed_list %}#}
|
||||
{# <tr>#}
|
||||
|
@ -104,8 +194,48 @@
|
|||
{# {% else %}#}
|
||||
{# <p class="text-center">(暂无)</p>#}
|
||||
{# {% endif %}#}
|
||||
</table>
|
||||
</div>
|
||||
{# </table>#}
|
||||
{# </div>#}
|
||||
</div>
|
||||
</div>
|
||||
<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">
|
||||
</ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content ibox-heading">
|
||||
<h3>主机修改记录</h3>
|
||||
<small><i class="fa fa-map-marker"></i> 包含了此主机所有历史修改记录.</small>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<div class="feed-activity-list">
|
||||
{% if asset_record %}
|
||||
{% for r in asset_record %}
|
||||
<div class="feed-element">
|
||||
<div>
|
||||
<small class="pull-right">{{ r.alert_time|naturaltime }}</small>
|
||||
<strong class="text-navy">{{ r.username }}</strong>
|
||||
{% for i in r.content|str_to_list %}
|
||||
<div>{{ i.0 }} 由 <span class="text-success">{{ i.1|str_to_code }}</span> 改为 <span class="text-warning">{{ i.2|str_to_code }}</span></div>
|
||||
{% endfor %}
|
||||
<small class="text-success">{{ r.alert_time }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p class="text-center">(暂无)</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load mytags %}
|
||||
{% load bootstrap %}
|
||||
{% block content %}
|
||||
{% include 'nav_cat_bar.html' %}
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
|
@ -32,53 +33,86 @@
|
|||
<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" value="{{ asset.ip }}" class="form-control"></div>
|
||||
</div>
|
||||
|
||||
{{ af.ip|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.hostname|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.other_ip|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.remote_ip|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.port|bootstrap_horizontal }}
|
||||
|
||||
<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" value="{{ asset.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-1">
|
||||
<label for="j_group" class="col-sm-2 control-label">管理账号 <span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-2">
|
||||
<div class="radio i-checks">
|
||||
<label>
|
||||
<input type="checkbox" {% ifequal asset.use_default 1 %} checked="" {% endifequal %} value="1" id="use_default" name="use_default">
|
||||
<input type="checkbox" {% if asset.use_default_auth %} checked="" {% endif %} id="id_use_default_auth" name="use_default_auth"><span> 使用默认 </span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="admin_account" {% ifequal asset.use_default 1 %} style="display: none" {% endifequal %}>
|
||||
<label class="col-sm-2 control-label"> 管理用户名<span class="red-fonts">*</span> </label>
|
||||
<div class="form-group" id="admin_account" {% if asset.use_default_auth %} style="display: none" {% endif %}>
|
||||
<label class="col-sm-2 control-label"> 管理用户名 <span class="red-fonts">*</span> </label>
|
||||
<div class="col-sm-3">
|
||||
<input type="text" {% ifnotequal asset.use_default 1 %} value="{{ asset.username }}" {% endifnotequal %} name="username" class="form-control">
|
||||
<input type="text" value="{{ asset.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" {% ifnotequal asset.use_default 1 %} value="{{ asset.password }}" {% endifnotequal %} name="password" class="form-control">
|
||||
<input type="password" value="{{ asset.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 g in egroup %}
|
||||
<option type="checkbox" value="{{ g.id }}">{{ g.name }} {% if g.comment %} --- {{ g.comment }} {% endif %}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{{ af.group|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.idc|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.brand|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.cpu|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.memory|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.disk|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.number|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.sn|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.cabinet|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.position|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.asset_type|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.env|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.status|bootstrap_horizontal }}
|
||||
|
||||
{# <div class="hr-line-dashed"></div>#}
|
||||
{# {{ af.is_active|bootstrap_horizontal }}#}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group"><label class="col-sm-2 control-label"> 是否激活<span class="red-fonts">*</span> </label>
|
||||
|
@ -95,10 +129,8 @@
|
|||
</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" value="{{ asset.comment }}" name="comment" class="form-control"></div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.comment|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
|
@ -121,43 +153,47 @@
|
|||
|
||||
{% block self_footer_js %}
|
||||
<script>
|
||||
$('document').ready(function(){
|
||||
$('#id_use_default_auth').click(function(){
|
||||
if ($(this).is(':checked')){
|
||||
$('#admin_account').css('display', 'none')
|
||||
}
|
||||
else {
|
||||
$('#admin_account').css('display', 'block')
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
$('document').ready(function(){
|
||||
$('#use_default').click(function(){
|
||||
if ($(this).is(':checked')){
|
||||
$('#admin_account').css('display', 'none')
|
||||
}
|
||||
else {
|
||||
$('#admin_account').css('display', 'block')
|
||||
}
|
||||
})
|
||||
});
|
||||
var required_fields = ["id_ip", "id_port"];
|
||||
required_fields.forEach(function(field) {
|
||||
$('label[for="' + field + '"]').parent().addClass("required");
|
||||
});
|
||||
|
||||
$('#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: "必须填写!"}
|
||||
$('#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}$/, '端口号不正确'],
|
||||
},
|
||||
"port": {
|
||||
rule: "required;check_port",
|
||||
tip: "输入端口号",
|
||||
ok: "",
|
||||
msg: {required: "必须填写!"}
|
||||
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();
|
||||
}
|
||||
},
|
||||
valid: function(form) {
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
<html>
|
||||
<head>
|
||||
<link href="/static/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="/static/font-awesome/css/font-awesome.css" rel="stylesheet">
|
||||
<link href="/static/css/plugins/iCheck/custom.css" rel="stylesheet">
|
||||
<link href="/static/css/animate.css" rel="stylesheet">
|
||||
<link href="/static/css/style.css" rel="stylesheet">
|
||||
|
||||
<script src="/static/js/jquery-2.1.1.js"></script>
|
||||
{# <style>#}
|
||||
{# body {background: #ffffff;}#}
|
||||
{# </style>#}
|
||||
</head>
|
||||
|
||||
{% load bootstrap %}
|
||||
{% block content %}
|
||||
|
||||
<body>
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="row">
|
||||
<div class="col-lg-10">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<h5 class="text-center"> 填写修改主机信息. </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"></ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ibox-content">
|
||||
<form class="form-horizontal" action="" id="signupForm" method="post" name="horizontal" role="form" autocomplete="off">
|
||||
{% csrf_token %}
|
||||
<input id="ids" style="display: none">
|
||||
{{ af.env|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.idc|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.port|bootstrap_horizontal }}
|
||||
|
||||
<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="radio" checked="" value="no_action" name="use_default_auth"><span> 不修改 </span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio i-checks">
|
||||
<label>
|
||||
<input type="radio" name="use_default_auth"><span> 使用默认 </span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio i-checks">
|
||||
<label>
|
||||
<input type="radio" id="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-3">
|
||||
<select id="groups" size="10" class="form-control m-b" multiple>
|
||||
{% for asset_group in asset_group_all %}
|
||||
<option value="{{ asset_group.id }}">{{ asset_group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-1">
|
||||
<div class="btn-group" style="margin-top: 50px;">
|
||||
<button type="button" class="btn btn-white" onclick="move_right('groups', 'groups_selected')"><i class="fa fa-chevron-right"></i></button>
|
||||
<button type="button" class="btn btn-white" onclick="move_left('groups_selected', 'groups')"><i class="fa fa-chevron-left"></i> </button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<div>
|
||||
<select id="groups_selected" name="project" class="form-control m-b" size="10" multiple>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.cabinet|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ af.comment|bootstrap_horizontal }}
|
||||
<div class="hr-line-dashed"></div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-4 col-sm-offset-5">
|
||||
<button class="btn btn-white" type="submit"> 重置 </button>
|
||||
<button class="btn btn-primary" id="host_edit"> 提交 </button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#host_edit').click(function () {
|
||||
var args = {};
|
||||
var match = null;
|
||||
var uuid = decodeURIComponent(location.search.substring(1));
|
||||
var reg = /(?:([^&]+)=([^&]+))/g;
|
||||
while((match = reg.exec(uuid))!==null){
|
||||
args[match[1]] = match[2];
|
||||
}
|
||||
var ids = args['uuid'];
|
||||
$('#uuid').val(ids)
|
||||
});
|
||||
|
||||
$('#id_use_default_auth').click(function(){
|
||||
if ($(this).is(':checked')){
|
||||
$('#admin_account').css('display', 'block')
|
||||
}
|
||||
else {
|
||||
$('#admin_account').css('display', 'none')
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
function move_left(from, to) {
|
||||
$("#"+from+" option").each(function(){
|
||||
if ( $(this).prop("selected") == true ) {
|
||||
$("#"+to).append(this);
|
||||
$(this).attr("selected",'false');
|
||||
}
|
||||
$(this).attr("selected",'true');
|
||||
});
|
||||
}
|
||||
function move_right(from, to) {
|
||||
$("#"+from+" option").each(function(){
|
||||
if ( $(this).prop("selected") == true ) {
|
||||
$("#"+to).append(this);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function move_all(from, to){
|
||||
$("#"+from).children().each(function(){
|
||||
$("#"+to).append(this);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock content %}
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<div class="col-md-12 column">
|
||||
<div class="alert alert-success alert-dismissable">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
|
||||
<h4>
|
||||
</h4> <strong>Nice!</strong> excel文件已生成请点击 <a href="/static/files/excels/{{ file_name }}" target="_blank" class="alert-link">下载</a>
|
||||
</div>
|
||||
</div>
|
|
@ -23,69 +23,128 @@
|
|||
</div>
|
||||
|
||||
<div class="ibox-content">
|
||||
<div>
|
||||
{% if session_role_id > 0 %}
|
||||
<a target="_blank" href="/jasset/asset_add/" class="btn btn-sm btn-primary "> 添加 </a>
|
||||
{% endif %}
|
||||
<form id="search_form" method="get" action="" class="pull-right mail-search">
|
||||
<form id="asset_form">
|
||||
<div class="col-sm-2" style="padding-left: 0px">
|
||||
<label>
|
||||
<select name="idc" class="form-control m-b" onchange="change_info()">
|
||||
<option value="">IDC机房</option>
|
||||
{% for idc in idc_all %}
|
||||
{% ifequal idc.name idc_name %}
|
||||
<option value="{{idc.name}}" selected> {{ idc.name }}</option>
|
||||
{% else %}
|
||||
<option value="{{idc.name}}"> {{ idc.name }}</option>
|
||||
{% endifequal %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<label>
|
||||
<select name="group" class="form-control m-b" onchange="change_info()">
|
||||
<option value="">主机组</option>
|
||||
{% for asset_group in asset_group_all %}
|
||||
{% ifequal asset_group.name group_name %}
|
||||
<option value="{{ asset_group.name }}" selected> {{ asset_group.name }} </option>
|
||||
{% else %}
|
||||
<option value="{{ asset_group.name }}"> {{ asset_group.name }} </option>
|
||||
{% endifequal %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-2">
|
||||
<label>
|
||||
<select name="asset_type" class="form-control m-b" onchange="change_info()">
|
||||
<option value="">所有类型</option>
|
||||
{% for type in asset_types %}
|
||||
{% ifequal type.0|int2str asset_type %}
|
||||
<option value="{{ type.0 }}" selected> {{ type.1 }}</option>
|
||||
{% else %}
|
||||
<option value="{{ type.0 }}"> {{ type.1 }}</option>
|
||||
{% endifequal %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<label>
|
||||
<select name="status" class="form-control m-b" onchange="change_info()">
|
||||
<option value="">状态</option>
|
||||
{% for s in asset_status %}
|
||||
{% ifequal s.0|int2str status %}
|
||||
<option value="{{ s.0 }}" selected> {{ s.1 }}</option>
|
||||
{% else %}
|
||||
<option value="{{ s.0 }}"> {{ s.1 }}</option>
|
||||
{% endifequal %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control input-sm" id="search_input" name="keyword" placeholder="Search">
|
||||
<input type="text" class="form-control m-b" id="search_input" name="keyword" value="{{ keyword }}" placeholder="Search">
|
||||
<input type="text" style="display: none">
|
||||
<div class="input-group-btn">
|
||||
<button type="submit" class="btn btn-sm btn-primary">
|
||||
<button id='search_btn' href="/jasset/asset_list/?search=true" type="button" class="btn btn-xm btn-primary search-btn" onclick="change_info()">
|
||||
- 搜索 -
|
||||
</button>
|
||||
<button type="button" href="/jasset/asset_list/?export=true" name="export" class="btn btn-xm btn-success search-btn-excel" onclick="return false">
|
||||
- 导出 -
|
||||
</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="ip"> IP地址 </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" name="comment"> 备注 </th>
|
||||
<th class="text-center"> 操作 </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for asset in assets.object_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.port }} </td>
|
||||
<td class="text-center">{{ asset.port }}</td>
|
||||
<td class="text-center"> {{ asset.use_default_auth|bool2str }} </td>
|
||||
<td class="text-center"> {{ asset.is_active|bool2str }} </td>
|
||||
<td class="text-center"> {{ asset.comment }} </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="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>
|
||||
|
||||
<div id="export"></div>
|
||||
<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>
|
||||
<th class="text-center"> 操作 </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for asset in assets.object_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.system_type }}{{ asset.system_version }}</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 href="/jasset/asset_update/?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>
|
||||
{% include 'paginator.html' %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -124,60 +183,70 @@
|
|||
})
|
||||
});
|
||||
|
||||
|
||||
function alter(form) {
|
||||
selectData = GetTableDataBox();
|
||||
console.log(selectData[0])
|
||||
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");
|
||||
error: 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
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++;
|
||||
$('.search-btn-excel').unbind('click').bind('click',function(){
|
||||
var url= $(this).attr("href");
|
||||
console.log(url);
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
data: $("#asset_form").serialize(),
|
||||
success: function (data) {
|
||||
$("#export").html(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#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",
|
||||
url: "/jasset/host_del/multi/",
|
||||
data: {"id_list": id_list, "len_list": j},
|
||||
success: function (data) {
|
||||
window.open("/jasset/host_list/", "_self");
|
||||
type: "post",
|
||||
data: {asset_id_all: asset_id_all},
|
||||
url: "/jasset/asset_del/?arg=batch",
|
||||
success: function () {
|
||||
parent.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
{# function host_search(){#}
|
||||
{# $.ajax({#}
|
||||
{# type: "GET",#}
|
||||
{# url: "/jasset/search/",#}
|
||||
{# data: $("#search_form").serialize(),#}
|
||||
{# success: function (data) {#}
|
||||
{# $("#contents_form").html(data);#}
|
||||
{# }#}
|
||||
{# });#}
|
||||
{# }#}
|
||||
|
||||
function change_info(){
|
||||
var args = $("#asset_form").serialize();
|
||||
window.location = "/jasset/asset_list/?" + args
|
||||
}
|
||||
|
||||
$("#search_input").keydown(function(e){
|
||||
if(e.keyCode==13){
|
||||
host_search()
|
||||
change_info()
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -187,7 +256,6 @@
|
|||
$.ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
// data: $("#search_form").serialize(),
|
||||
success: function (data) {
|
||||
$("#j_group_" + id).html(data);
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
{% for field in af %}
|
||||
<div class="alert alert-warning text-center"> {{ field.errors }}</div>
|
||||
{{ field.label_tag }}: {{ field }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% if af.errors %}
|
||||
<ul>
|
||||
{% for error in af.errors %}
|
||||
<li><strong>{{ error }}</strong></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
|
@ -22,7 +22,7 @@
|
|||
<div class="col-lg-10">
|
||||
<div class="ibox float-e-margins">
|
||||
<div id="ibox-content" class="ibox-title">
|
||||
<h5> 填写资产组基本信息 </h5>
|
||||
<h5> 填写主机组基本信息 </h5>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
|
@ -30,37 +30,34 @@
|
|||
<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>
|
||||
|
||||
{# <select id="assets_total" name="assets" class="form-control m-b" size="12" multiple style="display: none">#}
|
||||
{# {% for asset in assets_all %}#}
|
||||
{# <option value="{{ asset.id }}">{{ 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 eposts %}#}
|
||||
{# <option value="{{ asset.id }}">{{ asset.ip }}</option>#}
|
||||
{# {% endfor %}#}
|
||||
{# </select>#}
|
||||
<select id="assets_total" name="assets" class="form-control m-b" size="12" multiple style="display: none">
|
||||
{% for asset in asset_all %}
|
||||
<option value="{{ asset.id }}">{{ asset.ip }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<div class="ibox-content">
|
||||
{% if error %}
|
||||
<div class="alert alert-warning text-center">{{ error }}</div>
|
||||
{% if emg %}
|
||||
<div class="alert alert-warning text-center">{{ emg }}</div>
|
||||
{% endif %}
|
||||
{% if msg %}
|
||||
<div class="alert alert-success text-center">{{ msg }}</div>
|
||||
{% if smg %}
|
||||
<div class="alert alert-success text-center">{{ smg }}</div>
|
||||
{% endif %}
|
||||
<form id="assetForm" method="post" class="form-horizontal">
|
||||
<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="Name" name="name" class="form-control">
|
||||
</div>
|
||||
<div class="form-group"><label class="col-sm-2 control-label"> 主机组名<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8" name="group_id" value="{{ post.id }}"><input type="text" value="{{ group.name }}" placeholder="Name" name="name" class="form-control"></div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
|
@ -83,7 +80,7 @@
|
|||
<div>
|
||||
<select id="assets" name="assets" class="form-control m-b" size="12" multiple>
|
||||
{% for asset in asset_all %}
|
||||
<option value="{{ asset.id }}">{{ asset.ip }}</option>
|
||||
<option value="{{ asset.id }}">{{ asset.ip }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
@ -92,7 +89,7 @@
|
|||
<div class="col-sm-1">
|
||||
<div class="btn-group" style="margin-top: 60px;">
|
||||
<button type="button" class="btn btn-white" onclick="move('assets', 'asset_select', 'assets_total', 'asset_select_total' )"><i class="fa fa-chevron-right"></i></button>
|
||||
<button type="button" class="btn btn-white" onclick="move('asset_select', 'assets', 'asset_select_total', 'assets_total')"><i class="fa fa-chevron-left"></i> </button>
|
||||
<button type="button" class="btn btn-white" onclick="move_left('asset_select', 'assets', 'asset_select_total', 'assets_total')"><i class="fa fa-chevron-left"></i> </button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -104,18 +101,15 @@
|
|||
</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 class="form-group"><label class="col-sm-2 control-label"> 备注 </label>
|
||||
<div class="col-sm-8"><input type="text" value="" 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" onclick="on_submit('groups_selected') "> 提交 </button>
|
||||
<div class="col-sm-4 col-sm-offset-5">
|
||||
<button class="btn btn-white" type="submit"> 重置 </button>
|
||||
<button class="btn btn-primary" id="submit_button" type="submit" onclick="on_submit('groups_selected') "> 提交 </button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -159,16 +153,6 @@
|
|||
})
|
||||
}
|
||||
|
||||
// $('#search').keyup(function() {
|
||||
// var $rows = $('#hosts option');
|
||||
// var val = $.trim($(this).val()).replace(/ +/g, ' ').toLowerCase();
|
||||
//
|
||||
// $rows.show().filter(function() {
|
||||
// var text = $(this).text().replace(/\s+/g, ' ').toLowerCase();
|
||||
// return !~text.indexOf(val);
|
||||
// }).hide();
|
||||
// });
|
||||
|
||||
function change_dept(dept_id){
|
||||
$.get('/jasset/dept_host_ajax/',
|
||||
{'id': dept_id},
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
<div class="ibox-content">
|
||||
<div class="">
|
||||
<a target="_blank" href="/jasset/host_add" class="btn btn-sm btn-primary"> 添加主机 </a>
|
||||
<a target="_blank" href="/jasset/asset_add" class="btn btn-sm btn-primary"> 添加主机 </a>
|
||||
<b class="pull-right">提示: 此页面删除只从本主机组中剔除主机 </b>
|
||||
</div>
|
||||
|
||||
|
@ -41,9 +41,8 @@
|
|||
<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" id="group_id" value="{{ group.id }}"> 所属业务组 </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>
|
||||
|
@ -51,21 +50,20 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for post in contacts.object_list %}
|
||||
{% for asset 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>
|
||||
<td class="text-center" name="j_active"> {{ post.is_active|bool2str }} </td>
|
||||
<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" name="j_id" value="{{ asset.id }}" data-editable='false'><input name="id" value="{{ asset.id }}" type="checkbox" class="i-checks"></td>
|
||||
<td class="text-center" name="j_ip"> {{ asset.ip }} </td>
|
||||
<td class="text-center" name="j_port"> {{ asset.port }} </td>
|
||||
<td class="text-center" name="j_idc"> {{ asset.idc.name }} </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 }} </td>
|
||||
<td class="text-center" data-editable='false'>
|
||||
<a href="/jasset/host_detail/?id={{ post.id }}" class="iframe btn btn-xs btn-primary">详情</a>
|
||||
<a href="/jasset/host_edit/?id={{ post.id }}" class="btn btn-xs btn-info">编辑</a>
|
||||
<a href="/jasset/group_del_host/?id={{ post.id }}&gid={{ group.id }}" class="btn btn-xs btn-danger">删除</a>
|
||||
<a href="/jasset/host_detail/?id={{ asset.id }}" class="iframe btn btn-xs btn-primary">详情</a>
|
||||
<a href="/jasset/host_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 %}
|
||||
|
@ -165,7 +163,7 @@
|
|||
selectData = GetTableDataBox();
|
||||
if (selectData[1] != 0) {
|
||||
$.ajax({
|
||||
type: "post",
|
||||
type: "asset",
|
||||
url: "/jasset/host_edit/batch/",
|
||||
data: {"editable": selectData[0], "len_table": selectData[1]},
|
||||
success: function (data) {
|
||||
|
|
|
@ -43,13 +43,13 @@
|
|||
</div>
|
||||
|
||||
<select id="assets_total" name="assets" class="form-control m-b" size="12" multiple style="display: none">
|
||||
{% for asset in posts %}
|
||||
{% for asset in asset_all %}
|
||||
<option value="{{ asset.id }}">{{ 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 eposts %}
|
||||
<select id="asset_select_total" name="asset_select" class="form-control m-b" size="12" multiple style="display: none">
|
||||
{% for asset in asset_select %}
|
||||
<option value="{{ asset.id }}">{{ asset.ip }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
@ -63,14 +63,7 @@
|
|||
{% endif %}
|
||||
<form id="assetForm" method="post" class="form-horizontal">
|
||||
<div class="form-group"><label class="col-sm-2 control-label"> 主机组名<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8" name="group_id" value="{{ post.id }}"><input type="text" value="{{ group.name }}" placeholder="网站" name="j_group" class="form-control"></div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="j_dept" class="col-lg-2 control-label">所属部门<span class="red-fonts" style="">*</span></label>
|
||||
<input type="text" name="j_dept" value="{{ group.dept.id }}" style="display: none">
|
||||
<div class="col-sm-8"><input type="text" value="{{ group.dept.name }}" class="form-control" readonly="readonly"></div>
|
||||
<div class="col-sm-8" name="group_id" value="{{ group.id }}"><input type="text" value="{{ group.name }}" placeholder="Name" name="name" class="form-control"></div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
|
@ -92,8 +85,8 @@
|
|||
<div class="col-sm-4">
|
||||
<div>
|
||||
<select id="assets" name="assets" class="form-control m-b" size="12" multiple>
|
||||
{% for post in posts %}
|
||||
<option value="{{ post.id }}">{{ post.ip }}</option>
|
||||
{% for asset in asset_no_select %}
|
||||
<option value="{{ asset.id }}">{{ asset.ip }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
@ -108,9 +101,9 @@
|
|||
|
||||
<div class="col-sm-3">
|
||||
<div>
|
||||
<select id="asset_select" name="j_hosts" class="form-control m-b" size="12" multiple>
|
||||
{% for asset in eposts %}
|
||||
<option value="{{ asset.id }}">{{ asset.ip }}</option>
|
||||
<select id="asset_select" name="asset_select" class="form-control m-b" size="12" multiple>
|
||||
{% for asset in asset_select %}
|
||||
<option value="{{ asset.id }}">{{ asset.ip }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
@ -119,7 +112,7 @@
|
|||
|
||||
<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" value="{{ group.comment }}" placeholder=包括web组所有主机 name="j_comment" class="form-control"></div>
|
||||
<div class="col-sm-8"><input type="text" value="{{ group.comment }}" name="comment" class="form-control"></div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
{% load bootstrap %}
|
||||
{% 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> 填写IDC基本信息 </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">
|
||||
</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 %}
|
||||
<form id="assetForm" method="post" class="form-horizontal">
|
||||
{{ idc_form.name|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ idc_form.bandwidth|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ idc_form.operator|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ idc_form.linkman|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ idc_form.phone|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ idc_form.address|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ idc_form.network|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ idc_form.comment|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-4 col-sm-offset-5">
|
||||
<button class="btn btn-white" type="submit"> 重置 </button>
|
||||
<button class="btn btn-primary" type="sumbit"> 提交 </button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var required_fields = ["id_name"];
|
||||
required_fields.forEach(function(field) {
|
||||
$('label[for="' + field + '"]').parent().addClass("required");
|
||||
});
|
||||
|
||||
$('#assetForm').validator({
|
||||
timely: 2,
|
||||
theme: "yellow_right_effect",
|
||||
fields: {
|
||||
"j_idc": {
|
||||
rule: "required",
|
||||
tip: "输入IDC名",
|
||||
ok: "",
|
||||
msg: {required: "IDC名必须填写!"},
|
||||
data: {'data-ok':"主机名可以使用", 'data-msg-required': '主机名已正确'}
|
||||
}
|
||||
},
|
||||
valid: function(form) {
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
|
@ -0,0 +1,229 @@
|
|||
{% 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 %}
|
|
@ -0,0 +1,99 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
{% load bootstrap %}
|
||||
{% 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> 填写IDC基本信息 </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 %}
|
||||
<form id="assetForm" method="post" class="form-horizontal">
|
||||
{{ idc_form.name|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ idc_form.bandwidth|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ idc_form.operator|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ idc_form.linkman|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ idc_form.phone|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ idc_form.address|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ idc_form.network|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ idc_form.comment|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-4 col-sm-offset-5">
|
||||
<button class="btn btn-white" type="submit"> 重置 </button>
|
||||
<button class="btn btn-primary" type="sumbit"> 提交 </button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var required_fields = ["id_name"];
|
||||
required_fields.forEach(function(field) {
|
||||
$('label[for="' + field + '"]').parent().addClass("required");
|
||||
});
|
||||
|
||||
$('#assetForm').validator({
|
||||
timely: 2,
|
||||
theme: "yellow_right_effect",
|
||||
fields: {
|
||||
"j_idc": {
|
||||
rule: "required",
|
||||
tip: "输入IDC名",
|
||||
ok: "",
|
||||
msg: {required: "IDC名必须填写!"},
|
||||
data: {'data-ok':"主机名可以使用", 'data-msg-required': '主机名已正确'}
|
||||
}
|
||||
},
|
||||
valid: function(form) {
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
|
@ -0,0 +1,115 @@
|
|||
{% 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 class="ibox-title">
|
||||
<h5> IDC详细信息列表</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/idc_add" class="btn btn-sm btn-primary "> 添加IDC </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="submit" class="btn btn-sm btn-primary">
|
||||
Search
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<form id="contents_form" name="contents_form">
|
||||
<table class="table table-striped table-bordered table-hover " id="editable" >
|
||||
<thead>
|
||||
<tr>
|
||||
{% ifequal session_role_id 2 %}
|
||||
<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>
|
||||
{% endifequal %}
|
||||
<th class="text-center"> 机房名 </th>
|
||||
<th class="text-center"> 主机数量 </th>
|
||||
<th class="text-center"> 备注 </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"> {{ 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"> {{ post.comment }} </td>
|
||||
<td class="text-center">
|
||||
<a href="/jasset/idc_detail/?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_del/?id={{ post.id }}" class="btn btn-xs btn-danger">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
{% 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="alter_button" class="btn btn-warning btn-sm" name="alter_button" value="修改" onclick="alter('contents_form')" />-->
|
||||
{% endifequal %}
|
||||
</div>
|
||||
{% include 'paginator.html' %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
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/idc_del/?id=multi",
|
||||
data: {"id_list": id_list, "len_list": j},
|
||||
success: function (data) {
|
||||
window.open("/jasset/idc_list/", "_self");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
|
@ -0,0 +1,120 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block self_head_css_js %}
|
||||
<link href="/static/css/plugins/datapicker/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 %}
|
||||
{% 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 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">
|
||||
<form method="post" id="userForm" class="form-horizontal" action="">
|
||||
{% 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="role_name" class="col-sm-2 control-label">规则名称<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<input id="role_name" name="role_name" placeholder="Role Name" type="text" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="role_password_label" class="col-sm-2 control-label">角色密码<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<input id="role_password" name="role_password" type="password" class="form-control" value="{{ default_password }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="role_comment" class="col-sm-2 control-label">备注</label>
|
||||
<div class="col-sm-8">
|
||||
<input id="role_comment" name="role_comment" placeholder="Role Comment" type="text" 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 id="submit_button" class="btn btn-primary" type="submit">确认保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block self_footer_js %}
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$("input.role").click(function(){
|
||||
if($("input.role[value=GA]").is( ":checked" )){
|
||||
$("#admin_groups").css("display", 'none');
|
||||
}
|
||||
else {
|
||||
|
||||
$("#admin_groups").css("display", 'block');
|
||||
}
|
||||
});
|
||||
|
||||
$('#use_password').click(function(){
|
||||
if ($(this).is(':checked')){
|
||||
$('#admin_account_password').css('display', 'block')
|
||||
}
|
||||
else {
|
||||
|
||||
$('#admin_account_password').css('display', 'none')
|
||||
}
|
||||
});
|
||||
|
||||
$('#use_publicKey').click(function(){
|
||||
if ($(this).is(':checked')){
|
||||
|
||||
$('#admin_account_publicKey').css('display', 'block')
|
||||
}
|
||||
else {
|
||||
$('#admin_account_publicKey').css('display', 'none')
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
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>
|
||||
<script src="/static/js/cropper/cropper.min.js"></script>
|
||||
<script src="/static/js/datapicker/bootstrap-datepicker.js"></script>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
{% 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-4">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-primary"><b>授权规则</b></span>
|
||||
<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="#"></a>
|
||||
</li>
|
||||
<li><a href="#"></a>
|
||||
</li>
|
||||
</ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<div>
|
||||
<div class="text-left">
|
||||
<table class="table table-striped" id="ugedit" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">时间</th>
|
||||
<th class="text-center">名称</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for rule in rules %}
|
||||
<tr class="gradeX">
|
||||
<td class="text-center"> {{ rule.date_added | date:"Y-m-d H:i:s"}} </td>
|
||||
<td class="text-center"> {{ rule.name }} </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-primary"><b>授权用户/用户组</b></span>
|
||||
<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="#"></a>
|
||||
</li>
|
||||
<li><a href="#"></a>
|
||||
</li>
|
||||
</ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<div>
|
||||
<div class="text-left">
|
||||
<table class="table table-striped" id="ugedit" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">用户</th>
|
||||
<th class="text-center">用户组</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr class="gradeX">
|
||||
<td class="text-center"> {{ user.name }} </td>
|
||||
<td class="text-center"> {{ user | user_which_groups:"group" }} </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-primary"><b>授权主机/主机组</b></span>
|
||||
<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="#"></a>
|
||||
</li>
|
||||
<li><a href="#"></a>
|
||||
</li>
|
||||
</ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<div>
|
||||
<div class="text-left">
|
||||
<table class="table table-striped" id="agedit" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">主机</th>
|
||||
<th class="text-center">主机组</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for asset in assets %}
|
||||
<tr class="gradeX">
|
||||
<td class="text-center"> {{ asset.ip }} </td>
|
||||
<td class="text-center"> {{ asset | asset_which_groups:"group" }} </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$('#show').click(function(){
|
||||
$('#last').css('display', 'none');
|
||||
$('#all').css('display', 'block');
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
{% endblock %}
|
|
@ -0,0 +1,113 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block self_head_css_js %}
|
||||
<link href="/static/css/plugins/datapicker/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 %}
|
||||
{% 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 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">
|
||||
<form method="post" id="userForm" class="form-horizontal" action="">
|
||||
{% 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="role_name" class="col-sm-2 control-label">规则名称<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<input id="role_name" name="role_name" placeholder="Role Name" type="text" class="form-control" value="{{ role.name }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="role_comment" class="col-sm-2 control-label">备注</label>
|
||||
<div class="col-sm-8">
|
||||
<input id="role_comment" name="role_comment" placeholder="Role Comment" type="text" class="form-control" value="{{ role.comment }}">
|
||||
</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 id="submit_button" class="btn btn-primary" type="submit">确认保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block self_footer_js %}
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$("input.role").click(function(){
|
||||
if($("input.role[value=GA]").is( ":checked" )){
|
||||
$("#admin_groups").css("display", 'none');
|
||||
}
|
||||
else {
|
||||
|
||||
$("#admin_groups").css("display", 'block');
|
||||
}
|
||||
});
|
||||
|
||||
$('#use_password').click(function(){
|
||||
if ($(this).is(':checked')){
|
||||
$('#admin_account_password').css('display', 'block')
|
||||
}
|
||||
else {
|
||||
|
||||
$('#admin_account_password').css('display', 'none')
|
||||
}
|
||||
});
|
||||
|
||||
$('#use_publicKey').click(function(){
|
||||
if ($(this).is(':checked')){
|
||||
|
||||
$('#admin_account_publicKey').css('display', 'block')
|
||||
}
|
||||
else {
|
||||
$('#admin_account_publicKey').css('display', 'none')
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
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>
|
||||
<script src="/static/js/cropper/cropper.min.js"></script>
|
||||
<script src="/static/js/datapicker/bootstrap-datepicker.js"></script>
|
||||
{% endblock %}
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
<div class="col-lg-10">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<h5> 查看小组</h5>
|
||||
<h5> 所有系统角色</h5>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
|
@ -24,7 +24,9 @@
|
|||
|
||||
<div class="ibox-content">
|
||||
<div class="">
|
||||
<a target="_blank" href="/juser/user_add/" class="btn btn-sm btn-primary "> 添加用户 </a>
|
||||
<a href="/jperm/role/perm_role_add/" class="btn btn-sm btn-primary "> 添加角色 </a>
|
||||
<a href="/jperm/role/perm_role_push/" class="btn btn-sm btn-primary "> 推送角色 </a>
|
||||
<a id="del_btn" class="btn btn-sm btn-danger "> 删除所选 </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="search" placeholder="Search">
|
||||
|
@ -40,25 +42,22 @@
|
|||
<table class="table table-striped table-bordered table-hover " id="editable" >
|
||||
<thead>
|
||||
<tr>
|
||||
<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>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users.object_list %}
|
||||
<tr class="gradeX">
|
||||
<td class="text-center"> {{ user.name }} </td>
|
||||
<tbody id="edittbody">
|
||||
{% for role in roles %}
|
||||
<tr class="gradeX" id={{ role.id }}>
|
||||
<td class="text-center"> {{ role.name }} </td>
|
||||
<td class="text-center"> {{ role.comment }} </td>
|
||||
<td class="text-center"> {{ role.date_added | date:"Y-m-d H:i:s"}} </td>
|
||||
<td class="text-center">
|
||||
<a href="/juser/user_list/?gid={{ user.id }}">{{ user.group.all | groups2str }} </a>
|
||||
</td>
|
||||
<td class="text-center"> <a href="/jasset/asset_list/?gid={{ user.id }}">{{ user.name }} </a> </td>
|
||||
<td class="text-center"> <a href="/jasset/group_list/?gid={{ user.id }}">{{ user.name }}</a></td>
|
||||
<td class="text-center">
|
||||
<a href="../perm_user_detail/?id={{ user.id }}" class="btn btn-xs btn-primary">详情</a>
|
||||
<a href="../perm_user_edit/?id={{ user.id }}" class="btn btn-xs btn-danger">编辑</a>
|
||||
<a href="/jperm/role/perm_role_detail/?id={{ role.id }}" class="btn btn-xs btn-primary">详情</a>
|
||||
<a href="/jperm/role/perm_role_edit/?id={{ role.id }}" class="btn btn-xs btn-info">编辑</a>
|
||||
<button onclick="remove_role({{ role.id }})" class="btn btn-xs btn-danger">删除</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -78,4 +77,29 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
<script>
|
||||
function remove_role(role_id){
|
||||
if (confirm("确认删除")) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/jperm/role/perm_role_delete/",
|
||||
data: "id=" + role_id,
|
||||
success: function(msg){
|
||||
alert( "成功: " + msg );
|
||||
var del_row = $('tbody#edittbody>tr#' + role_id);
|
||||
del_row.remove()
|
||||
},
|
||||
error: function (msg) {
|
||||
alert("失败: " + msg)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block self_head_css_js %}
|
||||
<link href="/static/css/plugins/datapicker/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 %}
|
||||
{% 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 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">
|
||||
<form method="post" id="userForm" class="form-horizontal" action="">
|
||||
{% 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="asset" class="col-sm-2 control-label">资产<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<select name="assets" data-placeholder="请选择资产" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for asset in assets %}
|
||||
<option value="{{ asset.ip }}">{{ asset.ip }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="assetgroup" class="col-sm-2 control-label">资产组<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<select name="asset_groups" data-placeholder="请选择资产组" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for asset_group in asset_groups %}
|
||||
<option value="{{ asset_group.name }}">{{ asset_group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="role" class="col-sm-2 control-label">角色<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<select name="roles" data-placeholder="请选择角色" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for role in roles %}
|
||||
<option value="{{ role.name }}">{{ role.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="row">
|
||||
<div class="form-group">
|
||||
<label for="j_group" class="col-sm-2 control-label">使用密码</label>
|
||||
<div class="col-sm-1">
|
||||
<div class="radio i-checks">
|
||||
<label>
|
||||
<input type="checkbox" value="1" id="use_password" name="use_password">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="j_group" class="col-sm-2 control-label">使用秘钥</label>
|
||||
<div class="col-sm-1">
|
||||
<div class="radio i-checks">
|
||||
<label>
|
||||
<input type="checkbox" value="1" id="use_publicKey" name="use_publicKey">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="comment" class="col-sm-2 control-label">备注</label>
|
||||
<div class="col-sm-8">
|
||||
<input id="comment" name="comment" placeholder="Comment" type="text" class="form-control" {% if error %}value="{{ username }}" {% endif %}>
|
||||
</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 id="submit_button" class="btn btn-primary" type="submit">推送</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block self_footer_js %}
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$("input.role").click(function(){
|
||||
if($("input.role[value=GA]").is( ":checked" )){
|
||||
$("#admin_groups").css("display", 'none');
|
||||
}
|
||||
else {
|
||||
|
||||
$("#admin_groups").css("display", 'block');
|
||||
}
|
||||
});
|
||||
|
||||
$('#use_password').click(function(){
|
||||
if ($(this).is(':checked')){
|
||||
$('#admin_account_password').css('display', 'block')
|
||||
}
|
||||
else {
|
||||
|
||||
$('#admin_account_password').css('display', 'none')
|
||||
}
|
||||
});
|
||||
|
||||
$('#use_publicKey').click(function(){
|
||||
if ($(this).is(':checked')){
|
||||
|
||||
$('#admin_account_publicKey').css('display', 'block')
|
||||
}
|
||||
else {
|
||||
$('#admin_account_publicKey').css('display', 'none')
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
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>
|
||||
<script src="/static/js/cropper/cropper.min.js"></script>
|
||||
<script src="/static/js/datapicker/bootstrap-datepicker.js"></script>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block self_head_css_js %}
|
||||
<link href="/static/css/plugins/datapicker/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 %}
|
||||
{% 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 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">
|
||||
<form method="post" id="userForm" class="form-horizontal" action="">
|
||||
{% 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="username" class="col-sm-2 control-label">授权名称<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<input id="rulename" name="rulename" placeholder="Rule Name" type="text" class="form-control" {% if error %}value="{{ username }}" {% endif %}>
|
||||
</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="user" data-placeholder="用户名" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for user in users %}
|
||||
<option value="{{ user.name }}">{{ user.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="usergroup" class="col-sm-2 control-label">用户组<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<select name="usergroup" data-placeholder="请选择用户组" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for user_group in user_groups %}
|
||||
<option value="{{ user_group.name }}">{{ user_group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="asset" class="col-sm-2 control-label">资产<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<select name="asset" data-placeholder="请选择资产" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for asset in assets %}
|
||||
<option value="{{ asset.ip }}">{{ asset.ip }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="assetgroup" class="col-sm-2 control-label">资产组<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<select name="assetgroup" data-placeholder="请选择资产组" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for asset_group in asset_groups %}
|
||||
<option value="{{ asset_group.name }}">{{ asset_group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="role" class="col-sm-2 control-label">角色<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<select name="role" data-placeholder="请选择角色" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for role in roles %}
|
||||
<option value="{{ role.name }}">{{ role.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</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-1">
|
||||
<div class="radio i-checks">
|
||||
<label>
|
||||
<input type="checkbox" value="0" id="use_password" name="use_password">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="admin_account_password" style="display: none">
|
||||
<label class="col-sm-1 control-label"> 密码<span class="red-fonts">*</span> </label>
|
||||
<div class="col-sm-4">
|
||||
<input type="password" name="password" 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-1">
|
||||
<div class="radio i-checks">
|
||||
<label>
|
||||
<input type="checkbox" value="1" id="use_publicKey" name="use_publicKey">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="admin_account_publicKey" style="display: none">
|
||||
<label class="col-sm-1 control-label"> 秘钥<span class="red-fonts">*</span> </label>
|
||||
<div class="col-sm-4">
|
||||
<input type="password" name="password" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="comment" class="col-sm-2 control-label">备注</label>
|
||||
<div class="col-sm-8">
|
||||
<input id="comment" name="comment" placeholder="Rule Comment" type="text" class="form-control" {% if error %}value="{{ username }}" {% endif %}>
|
||||
</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 id="submit_button" class="btn btn-primary" type="submit">确认保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block self_footer_js %}
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$("input.role").click(function(){
|
||||
if($("input.role[value=GA]").is( ":checked" )){
|
||||
$("#admin_groups").css("display", 'none');
|
||||
}
|
||||
else {
|
||||
|
||||
$("#admin_groups").css("display", 'block');
|
||||
}
|
||||
});
|
||||
|
||||
$('#use_password').click(function(){
|
||||
if ($(this).is(':checked')){
|
||||
$('#admin_account_password').css('display', 'block')
|
||||
}
|
||||
else {
|
||||
|
||||
$('#admin_account_password').css('display', 'none')
|
||||
}
|
||||
});
|
||||
|
||||
$('#use_publicKey').click(function(){
|
||||
if ($(this).is(':checked')){
|
||||
|
||||
$('#admin_account_publicKey').css('display', 'block')
|
||||
}
|
||||
else {
|
||||
$('#admin_account_publicKey').css('display', 'none')
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
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>
|
||||
<script src="/static/js/cropper/cropper.min.js"></script>
|
||||
<script src="/static/js/datapicker/bootstrap-datepicker.js"></script>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
{% 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-4">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-primary"><b>{{ rule.name }}</b></span>
|
||||
<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="#"></a>
|
||||
</li>
|
||||
<li><a href="#"></a>
|
||||
</li>
|
||||
</ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<div>
|
||||
<div class="text-left">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td class="text-navy">ID</td>
|
||||
<td>{{ rule.id }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">名称</td>
|
||||
<td>{{ rule.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">时间</td>
|
||||
<td>{{ rule.date_added | date:"Y-m-d H:i:s"}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">角色</td>
|
||||
<td>{{ roles_name }}</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">激活</td>
|
||||
<td>是</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-primary"><b>授权用户/用户组</b></span>
|
||||
<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="#"></a>
|
||||
</li>
|
||||
<li><a href="#"></a>
|
||||
</li>
|
||||
</ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<div>
|
||||
<div class="text-left">
|
||||
<table class="table table-striped" id="ugedit" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">用户</th>
|
||||
<th class="text-center">用户组</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr class="gradeX">
|
||||
<td class="text-center"> {{ user.name }} </td>
|
||||
<td class="text-center"> {{ user | user_which_groups:"group" }} </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-primary"><b>授权主机/主机组</b></span>
|
||||
<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="#"></a>
|
||||
</li>
|
||||
<li><a href="#"></a>
|
||||
</li>
|
||||
</ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<div>
|
||||
<div class="text-left">
|
||||
<table class="table table-striped" id="agedit" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">主机</th>
|
||||
<th class="text-center">主机组</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for asset in assets %}
|
||||
<tr class="gradeX">
|
||||
<td class="text-center"> {{ asset.ip }} </td>
|
||||
<td class="text-center"> {{ asset | asset_which_groups:"group" }} </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$('#show').click(function(){
|
||||
$('#last').css('display', 'none');
|
||||
$('#all').css('display', 'block');
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
{% endblock %}
|
|
@ -0,0 +1,209 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block self_head_css_js %}
|
||||
<link href="/static/css/plugins/datapicker/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 %}
|
||||
{% 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 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">
|
||||
<form method="post" id="userForm" class="form-horizontal" action="">
|
||||
{% 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="username_lab" class="col-sm-2 control-label">授权名称<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<input id="rule_name" name="rule_name" placeholder="RuleName" type="text" class="form-control" value="{{ rule.name }}">
|
||||
</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="user" data-placeholder="用户名" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for user in users %}
|
||||
<option value="{{ user.name }}">{{ user.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="usergroup" class="col-sm-2 control-label">用户组<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<select name="usergroup" data-placeholder="请选择用户组" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for user_group in user_groups %}
|
||||
<option value="{{ user_group.name }}">{{ user_group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="asset" class="col-sm-2 control-label">资产<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<select name="asset" data-placeholder="请选择资产" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for asset in assets %}
|
||||
<option value="{{ asset.ip }}">{{ asset.ip }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="assetgroup" class="col-sm-2 control-label">资产组<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<select name="assetgroup" data-placeholder="请选择资产组" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for asset_group in asset_groups %}
|
||||
<option value="{{ asset_group.name }}">{{ asset_group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="role" class="col-sm-2 control-label">角色<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<select name="role" data-placeholder="请选择角色" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for role in roles %}
|
||||
<option value="{{ role.name }}">{{ role.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</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-1">
|
||||
<div class="radio i-checks">
|
||||
<label>
|
||||
<input type="checkbox" value="0" id="use_password" name="use_password">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="admin_account_password" style="display: none">
|
||||
<label class="col-sm-1 control-label"> 密码<span class="red-fonts">*</span> </label>
|
||||
<div class="col-sm-4">
|
||||
<input type="password" name="password" 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-1">
|
||||
<div class="radio i-checks">
|
||||
<label>
|
||||
<input type="checkbox" value="1" id="use_publicKey" name="use_publicKey">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="admin_account_publicKey" style="display: none">
|
||||
<label class="col-sm-1 control-label"> 秘钥<span class="red-fonts">*</span> </label>
|
||||
<div class="col-sm-4">
|
||||
<input type="password" name="password" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="comment" class="col-sm-2 control-label">备注</label>
|
||||
<div class="col-sm-8">
|
||||
<input id="comment" name="comment" placeholder="Comment" type="text" class="form-control" {% if error %}value="{{ username }}" {% endif %}>
|
||||
</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 id="submit_button" class="btn btn-primary" type="submit">确认保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block self_footer_js %}
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$("input.role").click(function(){
|
||||
if($("input.role[value=GA]").is( ":checked" )){
|
||||
$("#admin_groups").css("display", 'none');
|
||||
}
|
||||
else {
|
||||
|
||||
$("#admin_groups").css("display", 'block');
|
||||
}
|
||||
});
|
||||
|
||||
$('#use_password').click(function(){
|
||||
if ($(this).is(':checked')){
|
||||
$('#admin_account_password').css('display', 'block')
|
||||
}
|
||||
else {
|
||||
|
||||
$('#admin_account_password').css('display', 'none')
|
||||
}
|
||||
});
|
||||
|
||||
$('#use_publicKey').click(function(){
|
||||
if ($(this).is(':checked')){
|
||||
|
||||
$('#admin_account_publicKey').css('display', 'block')
|
||||
}
|
||||
else {
|
||||
$('#admin_account_publicKey').css('display', 'none')
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
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>
|
||||
<script src="/static/js/cropper/cropper.min.js"></script>
|
||||
<script src="/static/js/datapicker/bootstrap-datepicker.js"></script>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
{% 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 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="">
|
||||
<a href="/jperm/perm_rule_add/" class="btn btn-sm btn-primary "> 添加规则 </a>
|
||||
<a id="del_btn" class="btn btn-sm btn-danger "> 删除所选 </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="search" placeholder="Search">
|
||||
<div class="input-group-btn">
|
||||
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
|
||||
- 搜索 -
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<table class="table table-striped table-bordered table-hover " id="editable" >
|
||||
<thead>
|
||||
<tr>
|
||||
<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>
|
||||
</thead>
|
||||
<tbody id="edittbody">
|
||||
{% for rule in rules %}
|
||||
<tr class="gradeX" id={{ rule.id }}>
|
||||
<td class="text-center"> {{ rule.name }} </td>
|
||||
<td class="text-center">
|
||||
<a href="/jasset/asset_list/?gid={{ user.id }}">{{ rule | rule_member_count:"user" }} </a>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="/jasset/group_list/?gid={{ user.id }}">{{ rule | rule_member_count:"user_group" }}</a>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="/jasset/group_list/?gid={{ user.id }}">{{ rule | rule_member_count:"asset" }}</a>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="/jasset/group_list/?gid={{ user.id }}">{{ rule | rule_member_count:"asset_group" }}</a>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="/jasset/group_list/?gid={{ user.id }}">{{ rule | rule_member_count:"role" }}</a>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="/jperm/perm_rule_detail/?id={{ rule.id }}" class="btn btn-xs btn-primary">详情</a>
|
||||
<a href="/jperm/perm_rule_edit/?id={{ rule.id }}" class="btn btn-xs btn-info">编辑</a>
|
||||
<button onclick="remove_rule({{ rule.id }})" class="btn btn-xs btn-danger">删除</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div class="dataTables_info" id="editable_info" role="status" aria-live="polite">
|
||||
Showing {{ users.start_index }} to {{ users.end_index }} of {{ p.count }} entries
|
||||
</div>
|
||||
</div>
|
||||
{% include 'paginator.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
function remove_rule(rule_id){
|
||||
if (confirm("确认删除")) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/jperm/perm_rule_delete/",
|
||||
data: "id=" + rule_id,
|
||||
success: function(msg){
|
||||
alert( "成功: " + msg );
|
||||
var del_row = $('tbody#edittbody>tr#' + rule_id);
|
||||
del_row.remove()
|
||||
},
|
||||
error: function (msg) {
|
||||
alert("失败: " + msg)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
|
@ -1,122 +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 class="ibox-title">
|
||||
<h5> {{ user.name }}授权修改</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">
|
||||
<form id="userPerm" method="post" class="form-horizontal" action="../perm_user_edit/?id={{ user.id }}">
|
||||
{% 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="row">
|
||||
<div class="form-group">
|
||||
<label for="" class="col-sm-2 control-label">用户<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-4">
|
||||
<input id="user_group_name" name="user_group_name" type="text" class="form-control" value="{{ user.name }}" readonly>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="" class="col-sm-2 control-label">资产<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-4">
|
||||
<div>
|
||||
<select id="assets" name="assets" class="form-control m-b" size="12" multiple>
|
||||
{% for asset in assets %}
|
||||
<option value="{{ asset.id }}">{{ asset.ip }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-1">
|
||||
<div class="btn-group" style="margin-top: 42px;">
|
||||
<button type="button" class="btn btn-white" onclick="move('assets', 'asset_select')"><i class="fa fa-chevron-right"></i></button>
|
||||
<button type="button" class="btn btn-white" onclick="move('asset_select', 'assets')"><i class="fa fa-chevron-left"></i> </button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3">
|
||||
<div>
|
||||
<select id="asset_select" name="asset_select" class="form-control m-b" size="12" multiple>
|
||||
{% for asset in asset_permed %}
|
||||
<option value="{{ asset.id }}">{{ asset.ip }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="" class="col-sm-2 control-label">资产组<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-4">
|
||||
<div>
|
||||
<select id="asset_groups" name="asset_groups" class="form-control m-b" size="12" multiple>
|
||||
{% for asset_group in asset_groups %}
|
||||
<option value="{{ asset_group.id }}">{{ asset_group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-1">
|
||||
<div class="btn-group" style="margin-top: 42px;">
|
||||
<button type="button" class="btn btn-white" onclick="move('asset_groups', 'asset_groups_select')"><i class="fa fa-chevron-right"></i></button>
|
||||
<button type="button" class="btn btn-white" onclick="move('asset_groups_select', 'asset_groups')"><i class="fa fa-chevron-left"></i> </button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3">
|
||||
<div>
|
||||
<select id="asset_groups_select" name="asset_groups_select" class="form-control m-b" size="12" multiple>
|
||||
{% for asset_group in asset_group_permed %}
|
||||
<option value="{{ asset_group.id }}">{{ asset_group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<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" onclick="selectAll()">确认保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -21,22 +21,20 @@
|
|||
<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="asset_add asset_add_multi"><a href="/jasset/asset_add/">添加资产</a></li>
|
||||
<li class="host_list host_detail host_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_list idc_detail idc_edit"><a href="/jasset/idc_list/">查看机房</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li id="jperm">
|
||||
<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">
|
||||
<li class="dept_perm_list dept_perm_edit">
|
||||
<a href="/jperm/user/">用户授权</a>
|
||||
</li>
|
||||
|
||||
<li class="perm_list perm_edit perm_detail">
|
||||
<a href="/jperm/group/">用户组授权</a>
|
||||
<a href="/jperm/rule/">授权规则</a>
|
||||
</li>
|
||||
|
||||
<li class="sudo_list sudo_edit sudo_add cmd_list cmd_edit cmd_add sudo_detail">
|
||||
<a href="/jperm/sys_user_list/">系统用户</a>
|
||||
<a href="/jperm/role/">系统角色</a>
|
||||
</li>
|
||||
<li class="apply_show online"><a href="/jperm/apply_show/online/">权限审批</a></li>
|
||||
<li class="apply_show online"><a href="/jperm/log/">授权记录</a></li>
|
||||
|
|
|
@ -36,18 +36,22 @@
|
|||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function sleep(n) { //n表示的毫秒数
|
||||
var start = new Date().getTime();
|
||||
while (true) if (new Date().getTime() - start > n) break;
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
$('.page').click(function(){
|
||||
var searchStr = location.search;
|
||||
var old_href = $(this).attr('href').replace('?', '');
|
||||
var searchArray = searchStr.split('&');
|
||||
|
||||
if (searchStr.indexOf('page')){
|
||||
if (searchStr.indexOf('page')>=0){
|
||||
searchArray.pop();
|
||||
}
|
||||
searchArray.push(old_href);
|
||||
|
||||
if (searchArray.length > 2){
|
||||
if (searchArray.length > 1){
|
||||
$(this).attr('href', searchArray.join('&'));
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,10 +1,85 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title>Poem Maker Pro</title></head>
|
||||
<body>
|
||||
<h1>Your poem</h1>
|
||||
<p>Two {{roads}} diverged in a {{wood}}, and I—<br>
|
||||
I took the one less travelled by,<br>
|
||||
And that has {{made}} all the {{difference}}.</p>
|
||||
</body>
|
||||
</html>
|
||||
<body>
|
||||
<div id="main" style="height:400px;"></div>
|
||||
...
|
||||
<script src="/static/js/echarts/echarts.js"></script>
|
||||
<script type="text/javascript">
|
||||
require.config({
|
||||
paths: {
|
||||
'echarts': '/static/js/echarts/chart',
|
||||
'echarts/chart/line': '/static/js/echarts/chart/line'
|
||||
}
|
||||
});
|
||||
require(
|
||||
[
|
||||
'echarts',
|
||||
'echarts/chart/line'
|
||||
],
|
||||
function (ec) {
|
||||
var myChart = ec.init(document.getElementById('main'));
|
||||
var option = {
|
||||
title : {
|
||||
text: '某楼盘销售情况',
|
||||
subtext: '纯属虚构'
|
||||
},
|
||||
tooltip : {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
data:['意向','预购','成交']
|
||||
},
|
||||
toolbox: {
|
||||
show : true,
|
||||
feature : {
|
||||
mark : {show: true},
|
||||
dataView : {show: true, readOnly: false},
|
||||
magicType : {show: true, type: ['line', 'bar', 'stack', 'tiled']},
|
||||
restore : {show: true},
|
||||
saveAsImage : {show: true}
|
||||
}
|
||||
},
|
||||
calculable : true,
|
||||
xAxis : [
|
||||
{
|
||||
type : 'category',
|
||||
boundaryGap : false,
|
||||
data : ['周一','周二','周三','周四','周五','周六','周日']
|
||||
}
|
||||
],
|
||||
yAxis : [
|
||||
{
|
||||
type : 'value'
|
||||
}
|
||||
],
|
||||
series : [
|
||||
{
|
||||
name:'成交',
|
||||
type:'line',
|
||||
smooth:true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data:[10, 12, 21, 54, 260, 830, 710]
|
||||
},
|
||||
{
|
||||
name:'预购',
|
||||
type:'line',
|
||||
smooth:true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data:[30, 182, 434, 791, 390, 30, 10]
|
||||
},
|
||||
{
|
||||
name:'意向',
|
||||
type:'line',
|
||||
smooth:true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data:[1320, 1132, 601, 234, 120, 90, 20]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
myChart.setOption(option);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in New Issue