Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
d5585e55d3
|
@ -41,6 +41,8 @@ lxc.cgroup.memory.limit_in_bytes = %CONTAINER_MEMORY%M
|
|||
# lxc.cgroup.cpu.cfs_quota_us : quota time of this process
|
||||
lxc.cgroup.cpu.cfs_quota_us = %CONTAINER_CPU%
|
||||
|
||||
lxc.cap.drop = sys_admin net_admin mac_admin mac_override sys_time sys_module
|
||||
|
||||
lxc.mount.entry = %FS_PREFIX%/global/users/%USERNAME%/data %ROOTFS%/root/nfs none bind,rw,create=dir 0 0
|
||||
lxc.mount.entry = %FS_PREFIX%/global/users/%USERNAME%/hosts/%CLUSTERID%.hosts %ROOTFS%/etc/hosts none bind,ro,create=file 0 0
|
||||
lxc.mount.entry = %FS_PREFIX%/global/users/%USERNAME%/ssh %ROOTFS%/root/.ssh none bind,ro,create=dir 0 0
|
||||
|
|
|
@ -135,11 +135,13 @@
|
|||
# default: ""
|
||||
# ADMIN_EMAIL_ADDRESS=""
|
||||
|
||||
# DATA_QUOTA : whether enable the quota of data or not
|
||||
# default: "NO"
|
||||
# DATA_QUOTA=""
|
||||
# DATA_QUOTA : whether enable the quota of data volume or not
|
||||
# True or False, default: False
|
||||
# DATA_QUOTA=False
|
||||
|
||||
# DATA_QUOTA_CMD : the cmd to set the data quota, the argument of it should be directory name
|
||||
# and the quota value.
|
||||
# DATA_QUOTA_CMD : the cmd to set the quota of a given directory. It accepts two arguments:
|
||||
# arg1: the directory name, relative path from the data volume root, e.g, "/users/bob/data"
|
||||
# arg2: the quota value in GB of string, e.g., "100"
|
||||
# default: "gluster volume quota docklet-volume limit-usage %s %s"
|
||||
# DATA_QUOTA_CMD=""
|
||||
# DATA_QUOTA_CMD="gluster volume quota docklet-volume limit-usage %s %s"
|
||||
|
||||
|
|
|
@ -95,10 +95,8 @@ class Container(object):
|
|||
else:
|
||||
logger.error ("get AUTH COOKIE URL failed for jupyter")
|
||||
authurl = "error"
|
||||
if (username=='guest'):
|
||||
cookiename='guest-cookie'
|
||||
else:
|
||||
cookiename='docklet-jupyter-cookie'
|
||||
|
||||
cookiename='docklet-jupyter-cookie'
|
||||
|
||||
rundir = self.lxcpath+'/'+lxc_name+'/rootfs' + self.rundir
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ def getenv(key):
|
|||
elif key =="ADMIN_EMAIL_ADDRESS":
|
||||
return os.environ.get("ADMIN_EMAIL_ADDRESS", "")
|
||||
elif key =="DATA_QUOTA":
|
||||
return os.environ.get("DATA_QUOTA", "NO")
|
||||
return os.environ.get("DATA_QUOTA", "False")
|
||||
elif key =="DATA_QUOTA_CMD":
|
||||
return os.environ.get("DATA_QUOTA_CMD", "gluster volume quota docklet-volume limit-usage %s %s")
|
||||
else:
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import os,time,subprocess
|
||||
import env
|
||||
import json
|
||||
|
||||
class Guest(object):
|
||||
def __init__(self,vclusterMgr,nodemgr):
|
||||
self.libpath = env.getenv('DOCKLET_LIB')
|
||||
self.fspath = env.getenv('FS_PREFIX')
|
||||
self.lxcpath = "/var/lib/lxc"
|
||||
self.G_vclustermgr = vclusterMgr
|
||||
self.nodemgr = nodemgr
|
||||
|
||||
def work(self):
|
||||
image = {}
|
||||
image['name'] = "base"
|
||||
image['type'] = "base"
|
||||
image['owner'] = "docklet"
|
||||
while len(self.nodemgr.get_rpcs()) < 1:
|
||||
time.sleep(10)
|
||||
if not os.path.isdir(self.fspath+"/global/users/guest"):
|
||||
subprocess.getoutput(self.libpath+"/userinit.sh guest")
|
||||
user_info = {}
|
||||
user_info["data"] = {}
|
||||
user_info["data"]["group"] = "primary"
|
||||
user_info["data"]["groupinfo"] = {}
|
||||
user_info["data"]["groupinfo"]["cpu"] = 4
|
||||
user_info["data"]["groupinfo"]["memory"] = 2000
|
||||
user_info["data"]["groupinfo"]["disk"] = 2000
|
||||
user_info = json.dumps(user_info)
|
||||
self.G_vclustermgr.create_cluster("guestspace", "guest", image, user_info)
|
||||
while True:
|
||||
self.G_vclustermgr.start_cluster("guestspace", "guest")
|
||||
time.sleep(3600)
|
||||
self.G_vclustermgr.stop_cluster("guestspace", "guest")
|
||||
fspath = self.fspath + "/local/volume/guest-1-0/"
|
||||
nfspath = self.fspath + "/global/users/guest/data/"
|
||||
subprocess.getoutput("(cd %s && rm -rf *)" % fspath)
|
||||
subprocess.getoutput("(cd %s && rm -rf *)" % nfspath)
|
|
@ -24,7 +24,8 @@ from socketserver import ThreadingMixIn
|
|||
import nodemgr, vclustermgr, etcdlib, network, imagemgr
|
||||
import userManager
|
||||
import monitor
|
||||
import guest_control, threading
|
||||
import threading
|
||||
import sysmgr
|
||||
|
||||
#default EXTERNAL_LOGIN=False
|
||||
external_login = env.getenv('EXTERNAL_LOGIN')
|
||||
|
@ -356,7 +357,7 @@ def deleteproxy(cur_user, user, form):
|
|||
logger.info ("handle request : delete proxy")
|
||||
clustername = form.get("clustername", None)
|
||||
G_vclustermgr.deleteproxy(user,clustername)
|
||||
self.response(200, {'success':'true', 'action':'deleteproxy'})
|
||||
return json.dumps({'success':'true', 'action':'deleteproxy'})
|
||||
|
||||
@app.route("/monitor/hosts/<com_id>/<issue>/", methods=['POST'])
|
||||
@login_required
|
||||
|
@ -365,7 +366,7 @@ def hosts_monitor(cur_user, user, form, com_id, issue):
|
|||
|
||||
logger.info("handle request: monitor/hosts")
|
||||
res = {}
|
||||
fetcher = monitor.Fetcher(etcdaddr,G_clustername,com_id)
|
||||
fetcher = monitor.Fetcher(com_id)
|
||||
if issue == 'meminfo':
|
||||
res['meminfo'] = fetcher.get_meminfo()
|
||||
elif issue == 'cpuinfo':
|
||||
|
@ -404,7 +405,7 @@ def vnodes_monitor(cur_user, user, form, con_id, issue):
|
|||
global G_clustername
|
||||
logger.info("handle request: monitor/vnodes")
|
||||
res = {}
|
||||
fetcher = monitor.Container_Fetcher(etcdaddr,G_clustername)
|
||||
fetcher = monitor.Container_Fetcher()
|
||||
if issue == 'cpu_use':
|
||||
res['cpu_use'] = fetcher.get_cpu_use(con_id)
|
||||
elif issue == 'mem_use':
|
||||
|
@ -574,6 +575,84 @@ def selfModify_user(cur_user, user, form):
|
|||
result = G_usermgr.selfModify(cur_user = cur_user, newValue = form)
|
||||
return json.dumps(result)
|
||||
|
||||
@app.route("/system/parmList/", methods=['POST'])
|
||||
@login_required
|
||||
def parmList_system(cur_user, user, form):
|
||||
global G_sysmgr
|
||||
logger.info("handle request: system/parmList/")
|
||||
result = G_sysmgr.getParmList()
|
||||
return json.dumps(result)
|
||||
|
||||
@app.route("/system/modify/", methods=['POST'])
|
||||
@login_required
|
||||
def modify_system(cur_user, user, form):
|
||||
global G_sysmgr
|
||||
logger.info("handle request: system/modify/")
|
||||
field = form.get("field", None)
|
||||
parm = form.get("parm", None)
|
||||
val = form.get("val", None)
|
||||
[status, message] = G_sysmgr.modify(field,parm,val)
|
||||
if status is True:
|
||||
return json.dumps({'success':'true', 'action':'modify_system'})
|
||||
else:
|
||||
return json.dumps({'success':'false', 'message': message})
|
||||
return json.dumps(result)
|
||||
|
||||
@app.route("/system/clear_history/", methods=['POST'])
|
||||
@login_required
|
||||
def clear_system(cur_user, user, form):
|
||||
global G_sysmgr
|
||||
logger.info("handle request: system/clear_history/")
|
||||
field = form.get("field", None)
|
||||
parm = form.get("parm", None)
|
||||
[status, message] = G_sysmgr.clear(field,parm)
|
||||
if status is True:
|
||||
return json.dumps({'success':'true', 'action':'clear_history'})
|
||||
else:
|
||||
return json.dumps({'success':'false', 'message': message})
|
||||
return json.dumps(result)
|
||||
|
||||
@app.route("/system/add/", methods=['POST'])
|
||||
@login_required
|
||||
def add_system(cur_user, user, form):
|
||||
global G_sysmgr
|
||||
logger.info("handle request: system/add/")
|
||||
field = form.get("field", None)
|
||||
parm = form.get("parm", None)
|
||||
val = form.get("val", None)
|
||||
[status, message] = G_sysmgr.add(field, parm, val)
|
||||
if status is True:
|
||||
return json.dumps({'success':'true', 'action':'add_parameter'})
|
||||
else:
|
||||
return json.dumps({'success':'false', 'message': message})
|
||||
return json.dumps(result)
|
||||
|
||||
@app.route("/system/delete/", methods=['POST'])
|
||||
@login_required
|
||||
def delete_system(cur_user, user, form):
|
||||
global G_sysmgr
|
||||
logger.info("handle request: system/delete/")
|
||||
field = form.get("field", None)
|
||||
parm = form.get("parm", None)
|
||||
[status, message] = G_sysmgr.delete(field,parm)
|
||||
if status is True:
|
||||
return json.dumps({'success':'true', 'action':'delete_parameter'})
|
||||
else:
|
||||
return json.dumps({'success':'false', 'message': message})
|
||||
return json.dumps(result)
|
||||
|
||||
@app.route("/system/reset_all/", methods=['POST'])
|
||||
@login_required
|
||||
def resetall_system(cur_user, user, form):
|
||||
global G_sysmgr
|
||||
logger.info("handle request: system/reset_all/")
|
||||
field = form.get("field", None)
|
||||
[status, message] = G_sysmgr.reset_all(field)
|
||||
if status is True:
|
||||
return json.dumps({'success':'true', 'action':'reset_all'})
|
||||
else:
|
||||
return json.dumps({'success':'false', 'message': message})
|
||||
return json.dumps(result)
|
||||
|
||||
@app.errorhandler(500)
|
||||
def internal_server_error(error):
|
||||
|
@ -608,6 +687,7 @@ if __name__ == '__main__':
|
|||
global etcdclient
|
||||
global G_networkmgr
|
||||
global G_clustername
|
||||
global G_sysmgr
|
||||
# move 'tools.loadenv' to the beginning of this file
|
||||
|
||||
fs_path = env.getenv("FS_PREFIX")
|
||||
|
@ -687,6 +767,8 @@ if __name__ == '__main__':
|
|||
clusternet = env.getenv("CLUSTER_NET")
|
||||
logger.info("using CLUSTER_NET %s" % clusternet)
|
||||
|
||||
G_sysmgr = sysmgr.SystemManager()
|
||||
|
||||
G_networkmgr = network.NetworkMgr(clusternet, etcdclient, mode)
|
||||
G_networkmgr.printpools()
|
||||
|
||||
|
@ -697,9 +779,8 @@ if __name__ == '__main__':
|
|||
logger.info("vclustermgr started")
|
||||
G_imagemgr = imagemgr.ImageMgr()
|
||||
logger.info("imagemgr started")
|
||||
Guest_control = guest_control.Guest(G_vclustermgr,G_nodemgr)
|
||||
logger.info("guest control started")
|
||||
threading.Thread(target=Guest_control.work, args=()).start()
|
||||
master_collector = monitor.Master_Collector(G_nodemgr)
|
||||
master_collector.start()
|
||||
|
||||
logger.info("startting to listen on: ")
|
||||
masterip = env.getenv('MASTER_IP')
|
||||
|
|
287
src/monitor.py
287
src/monitor.py
|
@ -5,13 +5,17 @@ import time,threading,json,traceback,platform
|
|||
|
||||
from log import logger
|
||||
|
||||
monitor_hosts = {}
|
||||
monitor_vnodes = {}
|
||||
|
||||
workerinfo = {}
|
||||
workercinfo = {}
|
||||
|
||||
class Container_Collector(threading.Thread):
|
||||
|
||||
def __init__(self,etcdaddr,cluster_name,host,test=False):
|
||||
def __init__(self,test=False):
|
||||
threading.Thread.__init__(self)
|
||||
self.thread_stop = False
|
||||
self.host = host
|
||||
self.etcdser = etcdlib.Client(etcdaddr,"/%s/monitor" % (cluster_name))
|
||||
self.interval = 2
|
||||
self.test = test
|
||||
self.cpu_last = {}
|
||||
|
@ -27,6 +31,7 @@ class Container_Collector(threading.Thread):
|
|||
return containers
|
||||
|
||||
def collect_containerinfo(self,container_name):
|
||||
global workercinfo
|
||||
output = subprocess.check_output("sudo lxc-info -n %s" % (container_name),shell=True)
|
||||
output = output.decode('utf-8')
|
||||
parts = re.split('\n',output)
|
||||
|
@ -41,11 +46,11 @@ class Container_Collector(threading.Thread):
|
|||
basic_info['Name'] = info['Name']
|
||||
basic_info['State'] = info['State']
|
||||
if(info['State'] == 'STOPPED'):
|
||||
self.etcdser.setkey('/vnodes/%s/basic_info'%(container_name), basic_info)
|
||||
workercinfo[container_name]['basic_info'] = basic_info
|
||||
return False
|
||||
basic_info['PID'] = info['PID']
|
||||
basic_info['IP'] = info['IP']
|
||||
self.etcdser.setkey('/vnodes/%s/basic_info'%(container_name), basic_info)
|
||||
workercinfo[container_name]['basic_info'] = basic_info
|
||||
|
||||
cpu_parts = re.split(' +',info['CPU use'])
|
||||
cpu_val = cpu_parts[0].strip()
|
||||
|
@ -69,7 +74,7 @@ class Container_Collector(threading.Thread):
|
|||
self.cpu_quota[container_name] = tmp/100000.0
|
||||
quota = {'cpu':self.cpu_quota[container_name],'memory':self.mem_quota[container_name]}
|
||||
#logger.info(quota)
|
||||
self.etcdser.setkey('/vnodes/%s/quota'%(container_name),quota)
|
||||
workercinfo[container_name]['quota'] = quota
|
||||
else:
|
||||
logger.error("Cant't find config file %s"%(confpath))
|
||||
return False
|
||||
|
@ -82,7 +87,7 @@ class Container_Collector(threading.Thread):
|
|||
cpu_usedp = 1
|
||||
cpu_use['usedp'] = cpu_usedp
|
||||
self.cpu_last[container_name] = cpu_val;
|
||||
self.etcdser.setkey('/vnodes/%s/cpu_use'%(container_name), cpu_use)
|
||||
workercinfo[container_name]['cpu_use'] = cpu_use
|
||||
|
||||
mem_parts = re.split(' +',info['Memory use'])
|
||||
mem_val = mem_parts[0].strip()
|
||||
|
@ -96,12 +101,14 @@ class Container_Collector(threading.Thread):
|
|||
mem_val = float(mem_val) * 1024 * 1024
|
||||
mem_usedp = float(mem_val) / self.mem_quota[container_name]
|
||||
mem_use['usedp'] = mem_usedp
|
||||
self.etcdser.setkey('/vnodes/%s/mem_use'%(container_name), mem_use)
|
||||
workercinfo[container_name]['mem_use'] = mem_use
|
||||
#print(output)
|
||||
#print(parts)
|
||||
return True
|
||||
|
||||
def run(self):
|
||||
global workercinfo
|
||||
global workerinfo
|
||||
cnt = 0
|
||||
while not self.thread_stop:
|
||||
containers = self.list_container()
|
||||
|
@ -110,8 +117,11 @@ class Container_Collector(threading.Thread):
|
|||
for container in containers:
|
||||
if not container == '':
|
||||
conlist.append(container)
|
||||
if not container in workercinfo.keys():
|
||||
workercinfo[container] = {}
|
||||
try:
|
||||
if(self.collect_containerinfo(container)):
|
||||
success= self.collect_containerinfo(container)
|
||||
if(success):
|
||||
countR += 1
|
||||
except Exception as err:
|
||||
logger.warning(traceback.format_exc())
|
||||
|
@ -120,10 +130,10 @@ class Container_Collector(threading.Thread):
|
|||
concnt = {}
|
||||
concnt['total'] = containers_num
|
||||
concnt['running'] = countR
|
||||
self.etcdser.setkey('/hosts/%s/containers'%(self.host), concnt)
|
||||
workerinfo['containers'] = concnt
|
||||
time.sleep(self.interval)
|
||||
if cnt == 0:
|
||||
self.etcdser.setkey('/hosts/%s/containerslist'%(self.host), conlist)
|
||||
workerinfo['containerslist'] = conlist
|
||||
cnt = (cnt+1)%5
|
||||
if self.test:
|
||||
break
|
||||
|
@ -135,12 +145,9 @@ class Container_Collector(threading.Thread):
|
|||
|
||||
class Collector(threading.Thread):
|
||||
|
||||
def __init__(self,etcdaddr,cluster_name,host,test=False):
|
||||
def __init__(self,test=False):
|
||||
threading.Thread.__init__(self)
|
||||
self.host = host
|
||||
self.thread_stop = False
|
||||
self.etcdser = etcdlib.Client(etcdaddr,"/%s/monitor/hosts/%s" % (cluster_name,host))
|
||||
self.vetcdser = etcdlib.Client(etcdaddr,"/%s/monitor/vnodes" % (cluster_name))
|
||||
self.interval = 1
|
||||
self.test=test
|
||||
return
|
||||
|
@ -154,10 +161,9 @@ class Collector(threading.Thread):
|
|||
memdict['buffers'] = meminfo.buffers/1024
|
||||
memdict['cached'] = meminfo.cached/1024
|
||||
memdict['percent'] = meminfo.percent
|
||||
self.etcdser.setkey('/meminfo',memdict)
|
||||
#print(output)
|
||||
#print(memparts)
|
||||
return
|
||||
return memdict
|
||||
|
||||
def collect_cpuinfo(self):
|
||||
cpuinfo = psutil.cpu_times_percent(interval=1,percpu=False)
|
||||
|
@ -166,7 +172,6 @@ class Collector(threading.Thread):
|
|||
cpuset['system'] = cpuinfo.system
|
||||
cpuset['idle'] = cpuinfo.idle
|
||||
cpuset['iowait'] = cpuinfo.iowait
|
||||
self.etcdser.setkey('/cpuinfo',cpuset)
|
||||
output = subprocess.check_output(["cat /proc/cpuinfo"],shell=True)
|
||||
output = output.decode('utf-8')
|
||||
parts = output.split('\n')
|
||||
|
@ -182,10 +187,10 @@ class Collector(threading.Thread):
|
|||
val = key_val[1].lstrip()
|
||||
if key=='processor' or key=='model name' or key=='core id' or key=='cpu MHz' or key=='cache size' or key=='physical id':
|
||||
info[idx][key] = val
|
||||
self.etcdser.setkey('/cpuconfig',info)
|
||||
return
|
||||
return [cpuset, info]
|
||||
|
||||
def collect_diskinfo(self):
|
||||
global workercinfo
|
||||
parts = psutil.disk_partitions()
|
||||
setval = []
|
||||
devices = {}
|
||||
|
@ -204,15 +209,16 @@ class Collector(threading.Thread):
|
|||
if(part.mountpoint.startswith('/opt/docklet/local/volume')):
|
||||
names = re.split('/',part.mountpoint)
|
||||
container = names[len(names)-1]
|
||||
self.vetcdser.setkey('/%s/disk_use'%(container), diskval)
|
||||
if not container in workercinfo.keys():
|
||||
workercinfo[container] = {}
|
||||
workercinfo[container]['disk_use'] = diskval
|
||||
setval.append(diskval)
|
||||
except Exception as err:
|
||||
logger.warning(traceback.format_exc())
|
||||
logger.warning(err)
|
||||
self.etcdser.setkey('/diskinfo', setval)
|
||||
#print(output)
|
||||
#print(diskparts)
|
||||
return
|
||||
return setval
|
||||
|
||||
def collect_osinfo(self):
|
||||
uname = platform.uname()
|
||||
|
@ -224,16 +230,18 @@ class Collector(threading.Thread):
|
|||
osinfo['version'] = uname.version
|
||||
osinfo['machine'] = uname.machine
|
||||
osinfo['processor'] = uname.processor
|
||||
self.etcdser.setkey('/osinfo',osinfo)
|
||||
return
|
||||
return osinfo
|
||||
|
||||
def run(self):
|
||||
self.collect_osinfo()
|
||||
global workerinfo
|
||||
workerinfo['osinfo'] = self.collect_osinfo()
|
||||
while not self.thread_stop:
|
||||
self.collect_meminfo()
|
||||
self.collect_cpuinfo()
|
||||
self.collect_diskinfo()
|
||||
self.etcdser.setkey('/running','True',6)
|
||||
workerinfo['meminfo'] = self.collect_meminfo()
|
||||
[cpuinfo,cpuconfig] = self.collect_cpuinfo()
|
||||
workerinfo['cpuinfo'] = cpuinfo
|
||||
workerinfo['cpuconfig'] = cpuconfig
|
||||
workerinfo['diskinfo'] = self.collect_diskinfo()
|
||||
workerinfo['running'] = True
|
||||
time.sleep(self.interval)
|
||||
if self.test:
|
||||
break
|
||||
|
@ -243,61 +251,96 @@ class Collector(threading.Thread):
|
|||
def stop(self):
|
||||
self.thread_stop = True
|
||||
|
||||
def workerFetchInfo():
|
||||
global workerinfo
|
||||
global workercinfo
|
||||
return str([workerinfo, workercinfo])
|
||||
|
||||
class Master_Collector(threading.Thread):
|
||||
|
||||
def __init__(self,nodemgr):
|
||||
threading.Thread.__init__(self)
|
||||
self.thread_stop = False
|
||||
self.nodemgr = nodemgr
|
||||
return
|
||||
|
||||
def run(self):
|
||||
global monitor_hosts
|
||||
global monitor_vnodes
|
||||
while not self.thread_stop:
|
||||
for worker in monitor_hosts.keys():
|
||||
monitor_hosts[worker]['running'] = False
|
||||
workers = self.nodemgr.get_rpcs()
|
||||
for worker in workers:
|
||||
try:
|
||||
ip = self.nodemgr.rpc_to_ip(worker)
|
||||
#[info,cinfo] = worker.workerFetchInfo()
|
||||
info = list(eval(worker.workerFetchInfo()))
|
||||
logger.info(info[1])
|
||||
monitor_hosts[ip] = info[0]
|
||||
for container in info[1].keys():
|
||||
monitor_vnodes[container] = info[1][container]
|
||||
except Exception as err:
|
||||
logger.warning(traceback.format_exc())
|
||||
logger.warning(err)
|
||||
time.sleep(2)
|
||||
return
|
||||
|
||||
def stop(self):
|
||||
self.thread_stop = True
|
||||
return
|
||||
|
||||
class Container_Fetcher:
|
||||
def __init__(self,etcdaddr,cluster_name):
|
||||
self.etcdser = etcdlib.Client(etcdaddr,"/%s/monitor/vnodes" % (cluster_name))
|
||||
def __init__(self):
|
||||
return
|
||||
|
||||
def get_cpu_use(self,container_name):
|
||||
res = {}
|
||||
[ret, ans] = self.etcdser.getkey('/%s/cpu_use'%(container_name))
|
||||
if ret == True :
|
||||
res = dict(eval(ans))
|
||||
[ret,quota] = self.etcdser.getkey('/%s/quota'%(container_name))
|
||||
if ret == False:
|
||||
res['quota'] = {'cpu':0}
|
||||
logger.warning(quota)
|
||||
res['quota'] = dict(eval(quota))
|
||||
return res
|
||||
else:
|
||||
logger.warning(ans)
|
||||
return res
|
||||
global monitor_vnodes
|
||||
try:
|
||||
res = monitor_vnodes[container_name]['cpu_use']
|
||||
res['quota'] = monitor_vnodes[container_name]['quota']
|
||||
except Exception as err:
|
||||
logger.warning(traceback.format_exc())
|
||||
logger.warning(err)
|
||||
res = {}
|
||||
return res
|
||||
|
||||
def get_mem_use(self,container_name):
|
||||
res = {}
|
||||
[ret, ans] = self.etcdser.getkey('/%s/mem_use'%(container_name))
|
||||
if ret == True :
|
||||
res = dict(eval(ans))
|
||||
[ret,quota] = self.etcdser.getkey('/%s/quota'%(container_name))
|
||||
if ret == False:
|
||||
res['quota'] = {'memory':0}
|
||||
logger.warning(quota)
|
||||
res['quota'] = dict(eval(quota))
|
||||
return res
|
||||
else:
|
||||
logger.warning(ans)
|
||||
return res
|
||||
global monitor_vnodes
|
||||
try:
|
||||
res = monitor_vnodes[container_name]['mem_use']
|
||||
res['quota'] = monitor_vnodes[container_name]['quota']
|
||||
except Exception as err:
|
||||
logger.warning(traceback.format_exc())
|
||||
logger.warning(err)
|
||||
res = {}
|
||||
return res
|
||||
|
||||
def get_disk_use(self,container_name):
|
||||
res = {}
|
||||
[ret, ans] = self.etcdser.getkey('/%s/disk_use'%(container_name))
|
||||
if ret == True :
|
||||
res = dict(eval(ans))
|
||||
else:
|
||||
logger.warning(ans)
|
||||
global monitor_vnodes
|
||||
try:
|
||||
res = monitor_vnodes[container_name]['disk_use']
|
||||
except Exception as err:
|
||||
logger.warning(traceback.format_exc())
|
||||
logger.warning(err)
|
||||
res = {}
|
||||
return res
|
||||
|
||||
def get_basic_info(self,container_name):
|
||||
res = self.etcdser.getkey("/%s/basic_info"%(container_name))
|
||||
if res[0] == False:
|
||||
return {}
|
||||
res = dict(eval(res[1]))
|
||||
global monitor_vnodes
|
||||
try:
|
||||
res = monitor_vnodes[container_name]['basic_info']
|
||||
except Exception as err:
|
||||
logger.warning(traceback.format_exc())
|
||||
logger.warning(err)
|
||||
res = {}
|
||||
return res
|
||||
|
||||
class Fetcher:
|
||||
|
||||
def __init__(self,etcdaddr,cluster_name,host):
|
||||
self.etcdser = etcdlib.Client(etcdaddr,"/%s/monitor/hosts/%s" % (cluster_name,host))
|
||||
def __init__(self,host):
|
||||
global monitor_hosts
|
||||
self.info = monitor_hosts[host]
|
||||
return
|
||||
|
||||
#def get_clcnt(self):
|
||||
|
@ -310,72 +353,76 @@ class Fetcher:
|
|||
# return self.get_meminfo_('172.31.0.1')
|
||||
|
||||
def get_meminfo(self):
|
||||
res = {}
|
||||
[ret, ans] = self.etcdser.getkey('/meminfo')
|
||||
if ret == True :
|
||||
res = dict(eval(ans))
|
||||
return res
|
||||
else:
|
||||
logger.warning(ans)
|
||||
return res
|
||||
try:
|
||||
res = self.info['meminfo']
|
||||
except Exception as err:
|
||||
logger.warning(traceback.format_exc())
|
||||
logger.warning(err)
|
||||
res = {}
|
||||
return res
|
||||
|
||||
def get_cpuinfo(self):
|
||||
res = {}
|
||||
[ret, ans] = self.etcdser.getkey('/cpuinfo')
|
||||
if ret == True :
|
||||
res = dict(eval(ans))
|
||||
return res
|
||||
else:
|
||||
logger.warning(ans)
|
||||
return res
|
||||
try:
|
||||
res = self.info['cpuinfo']
|
||||
except Exception as err:
|
||||
logger.warning(traceback.format_exc())
|
||||
logger.warning(err)
|
||||
res = {}
|
||||
return res
|
||||
|
||||
def get_cpuconfig(self):
|
||||
res = {}
|
||||
[ret, ans] = self.etcdser.getkey('/cpuconfig')
|
||||
if ret == True :
|
||||
res = list(eval(ans))
|
||||
return res
|
||||
else:
|
||||
logger.warning(ans)
|
||||
return res
|
||||
try:
|
||||
res = self.info['cpuconfig']
|
||||
except Exception as err:
|
||||
logger.warning(traceback.format_exc())
|
||||
logger.warning(err)
|
||||
res = {}
|
||||
return res
|
||||
|
||||
def get_diskinfo(self):
|
||||
res = []
|
||||
[ret, ans] = self.etcdser.getkey('/diskinfo')
|
||||
if ret == True :
|
||||
res = list(eval(ans))
|
||||
return res
|
||||
else:
|
||||
logger.warning(ans)
|
||||
return res
|
||||
try:
|
||||
res = self.info['diskinfo']
|
||||
except Exception as err:
|
||||
logger.warning(traceback.format_exc())
|
||||
logger.warning(err)
|
||||
res = {}
|
||||
return res
|
||||
|
||||
def get_osinfo(self):
|
||||
res = {}
|
||||
[ret, ans] = self.etcdser.getkey('/osinfo')
|
||||
if ret == True:
|
||||
res = dict(eval(ans))
|
||||
return res
|
||||
else:
|
||||
logger.warning(ans)
|
||||
return res
|
||||
try:
|
||||
res = self.info['osinfo']
|
||||
except Exception as err:
|
||||
logger.warning(traceback.format_exc())
|
||||
logger.warning(err)
|
||||
res = {}
|
||||
return res
|
||||
|
||||
def get_containers(self):
|
||||
res = {}
|
||||
[ret, ans] = self.etcdser.getkey('/containers')
|
||||
if ret == True:
|
||||
res = dict(eval(ans))
|
||||
return res
|
||||
else:
|
||||
logger.warning(ans)
|
||||
return res
|
||||
try:
|
||||
res = self.info['containers']
|
||||
except Exception as err:
|
||||
logger.warning(traceback.format_exc())
|
||||
logger.warning(err)
|
||||
res = {}
|
||||
return res
|
||||
|
||||
def get_status(self):
|
||||
isexist = self.etcdser.getkey('/running')[0]
|
||||
try:
|
||||
isexist = self.info['running']
|
||||
except Exception as err:
|
||||
logger.warning(traceback.format_exc())
|
||||
logger.warning(err)
|
||||
isexist = False
|
||||
if(isexist):
|
||||
return 'RUNNING'
|
||||
else:
|
||||
return 'STOPPED'
|
||||
|
||||
def get_containerslist(self):
|
||||
res = list(eval(self.etcdser.getkey('/containerslist')[1]))
|
||||
try:
|
||||
res = self.info['containerslist']
|
||||
except Exception as err:
|
||||
logger.warning(traceback.format_exc())
|
||||
logger.warning(err)
|
||||
res = {}
|
||||
return res
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
import re, string, os
|
||||
|
||||
configPath = {"docklet": os.environ.get("DOCKLET_CONF")+"/docklet.conf",
|
||||
"container": os.environ.get("DOCKLET_CONF")+"/container.conf"}
|
||||
#configPath = "../conf/docklet.conf"
|
||||
#lxcconfigPath = "../conf/container.conf"
|
||||
defaultPattern = re.compile(u'# *\S+ *= *\S+')
|
||||
activePattern = re.compile(u'\S+ *= *\S+')
|
||||
historyPattern = re.compile(u'## *\S+ *= *\S+')
|
||||
|
||||
def parse_line(line):
|
||||
kind = ""
|
||||
parm = ""
|
||||
val = ""
|
||||
if defaultPattern.match(line) != None and not "==" in line:
|
||||
kind = "default"
|
||||
elif activePattern.match(line) != None and not "#" in line:
|
||||
kind = "active"
|
||||
elif historyPattern.match(line) != None and not "==" in line:
|
||||
kind = "history"
|
||||
if kind != "":
|
||||
line = line.replace("#", "").replace("\n", "")
|
||||
parm = line[:line.find("=")].strip()
|
||||
val = line[line.find("=")+1:].strip()
|
||||
return [kind, parm, val]
|
||||
|
||||
class SystemManager():
|
||||
|
||||
def getParmList(*args, **kwargs):
|
||||
result = {"docklet": "", "container": ""}
|
||||
for field in ["docklet", "container"]:
|
||||
configFile = open(configPath[field])
|
||||
lines = configFile.readlines()
|
||||
configFile.close()
|
||||
conf = {}
|
||||
for line in lines:
|
||||
[linekind, lineparm, lineval] = parse_line(line)
|
||||
if linekind == "default":
|
||||
conf[lineparm] = {"val": lineval, "default": lineval, "history": []}
|
||||
for line in lines:
|
||||
[linekind, lineparm, lineval] = parse_line(line)
|
||||
if linekind == "active":
|
||||
try:
|
||||
conf[lineparm]["val"] = lineval
|
||||
except:
|
||||
conf[lineparm] = {"val": lineval, "default": lineval, "history": []}
|
||||
for line in lines:
|
||||
[linekind, lineparm, lineval] = parse_line(line)
|
||||
if linekind == "history":
|
||||
conf[lineparm]["history"].append(lineval)
|
||||
result[field] = [({'parm': parm, 'val': conf[parm]['val'],
|
||||
'default': conf[parm]['default'], "history": conf[parm]['history']}) for parm in sorted(conf.keys())]
|
||||
return result
|
||||
|
||||
# 1. def and not act 2. act and not def 3. def and act
|
||||
# have def and act and hist
|
||||
def modify(self, field, parm, val):
|
||||
configFile = open(configPath[field])
|
||||
lines = configFile.readlines()
|
||||
configFile.close()
|
||||
finish = False
|
||||
for i in range(0, len(lines)):
|
||||
line = lines[i]
|
||||
[linekind, lineparm, lineval] = parse_line(line)
|
||||
if linekind == "active" and lineparm == parm:
|
||||
lines[i] = "## " + parm + "=" + lineval + "\n"
|
||||
lines.insert(i, parm + "=" + val + "\n")
|
||||
if i == 0 or not parm in lines[i-1] or not "=" in lines[i-1]:
|
||||
lines.insert(i, "# " + parm + "=" + lineval + "\n")
|
||||
finish = True
|
||||
break
|
||||
if finish == False:
|
||||
for i in range(0, len(lines)):
|
||||
line = lines[i]
|
||||
[linekind, lineparm, lineval] = parse_line(line)
|
||||
if linekind == "default" and parm == lineparm:
|
||||
lines.insert(i+1, "## " + parm + "=" + lineval + "\n")
|
||||
lines.insert(i+1, parm + "=" + val + "\n")
|
||||
break
|
||||
for i in range(0, len(lines)):
|
||||
line = lines[i]
|
||||
[linekind, lineparm, lineval] = parse_line(line)
|
||||
if linekind == "history" and parm == lineparm and val == lineval:
|
||||
lines.pop(i)
|
||||
break
|
||||
configFile = open(configPath[field], "w")
|
||||
for line in lines:
|
||||
configFile.write(line)
|
||||
configFile.close()
|
||||
return [True, ""]
|
||||
|
||||
def clear(self, field, parm):
|
||||
configFile = open(configPath[field])
|
||||
lines = configFile.readlines()
|
||||
configFile.close()
|
||||
finish = False
|
||||
for i in range(0, len(lines)):
|
||||
line = lines[i]
|
||||
[linekind, lineparm, lineval] = parse_line(line)
|
||||
if linekind == "history" and parm == lineparm:
|
||||
lines[i] = ""
|
||||
configFile = open(configPath[field], "w")
|
||||
for line in lines:
|
||||
configFile.write(line)
|
||||
configFile.close()
|
||||
return [True, ""]
|
||||
|
||||
def add(self, field, parm, val):
|
||||
configFile = open(configPath[field], "a")
|
||||
configFile.write("\n" + "# " + parm + "=" + val + "\n" + parm + "=" + val + "\n")
|
||||
configFile.close()
|
||||
return [True, ""]
|
||||
|
||||
def delete(self, field, parm):
|
||||
configFile = open(configPath[field])
|
||||
lines = configFile.readlines()
|
||||
configFile.close()
|
||||
for i in range(0, len(lines)):
|
||||
line = lines[i]
|
||||
if parm in line:
|
||||
lines[i] = ""
|
||||
configFile = open(configPath[field], "w")
|
||||
for line in lines:
|
||||
configFile.write(line)
|
||||
configFile.close()
|
||||
return [True, ""]
|
||||
|
||||
def reset_all(self, field):
|
||||
configFile = open(configPath[field])
|
||||
lines = configFile.readlines()
|
||||
configFile.close()
|
||||
conf = {}
|
||||
for line in lines:
|
||||
[linekind, lineparm, lineval] = parse_line(line)
|
||||
if linekind == "default":
|
||||
conf[lineparm] = {"val": lineval, "default": lineval, "history": []}
|
||||
for line in lines:
|
||||
[linekind, lineparm, lineval] = parse_line(line)
|
||||
if linekind == "active":
|
||||
try:
|
||||
conf[lineparm]["val"] = lineval
|
||||
except:
|
||||
conf[lineparm] = {"val": lineval, "default": lineval, "history": []}
|
||||
for line in lines:
|
||||
[linekind, lineparm, lineval] = parse_line(line)
|
||||
if linekind == "history":
|
||||
conf[lineparm]["history"].append(lineval)
|
||||
|
||||
for i in range(0, len(lines)):
|
||||
line = lines[i]
|
||||
if activePattern.match(line) != None and not "#" in line:
|
||||
segs = line.replace("\n", "").split("=")
|
||||
lines[i] = segs[0].strip() + "=" + conf[segs[0].strip()]["default"] + "\n"
|
||||
elif historyPattern.match(line) != None and not "==" in line:
|
||||
lines[i] = ""
|
||||
configFile = open(configPath[field], "w")
|
||||
for line in lines:
|
||||
configFile.write(line)
|
||||
configFile.close()
|
||||
return [True, ""]
|
||||
|
||||
#sysmgr = SystemManager()
|
||||
#print(sysmgr.getParmList())
|
||||
|
|
@ -156,13 +156,13 @@ class userManager:
|
|||
groups.append({'name':'root', 'quotas':{ 'cpu':'4', 'disk':'2000', 'data':'100', 'memory':'2000', 'image':'10', 'idletime':'24', 'vnode':'8' }})
|
||||
groups.append({'name':'admin', 'quotas':{'cpu':'4', 'disk':'2000', 'data':'100', 'memory':'2000', 'image':'10', 'idletime':'24', 'vnode':'8'}})
|
||||
groups.append({'name':'primary', 'quotas':{'cpu':'4', 'disk':'2000', 'data':'100', 'memory':'2000', 'image':'10', 'idletime':'24', 'vnode':'8'}})
|
||||
groups.append({'name':'fundation', 'quotas':{'cpu':'4', 'disk':'2000', 'data':'100', 'memory':'2000', 'image':'10', 'idletime':'24', 'vnode':'8'}})
|
||||
groups.append({'name':'foundation', 'quotas':{'cpu':'4', 'disk':'2000', 'data':'100', 'memory':'2000', 'image':'10', 'idletime':'24', 'vnode':'8'}})
|
||||
groupfile.write(json.dumps(groups))
|
||||
groupfile.close()
|
||||
if not os.path.exists(fspath+"/global/sys/quotainfo"):
|
||||
quotafile = open(fspath+"/global/sys/quotainfo",'w')
|
||||
quotas = {}
|
||||
quotas['default'] = 'fundation'
|
||||
quotas['default'] = 'foundation'
|
||||
quotas['quotainfo'] = []
|
||||
quotas['quotainfo'].append({'name':'cpu', 'hint':'the cpu quota, number of cores, e.g. 4'})
|
||||
quotas['quotainfo'].append({'name':'memory', 'hint':'the memory quota, number of MB , e.g. 4000'})
|
||||
|
@ -309,16 +309,16 @@ class userManager:
|
|||
'''
|
||||
user = User.verify_auth_token(token)
|
||||
return user
|
||||
|
||||
|
||||
def set_nfs_quota_bygroup(self,groupname, quota):
|
||||
if not data_quota == "YES":
|
||||
if not data_quota == "True":
|
||||
return
|
||||
users = User.query.filter_by(user_group = groupname).all()
|
||||
for user in users:
|
||||
self.set_nfs_quota(user.username, quota)
|
||||
|
||||
|
||||
def set_nfs_quota(self, username, quota):
|
||||
if not data_quota == "YES":
|
||||
if not data_quota == "True":
|
||||
return
|
||||
nfspath = "/users/%s/data" % username
|
||||
try:
|
||||
|
@ -326,7 +326,7 @@ class userManager:
|
|||
sys_run(cmd.strip('"'))
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
|
||||
|
||||
@administration_required
|
||||
def query(*args, **kwargs):
|
||||
|
@ -607,8 +607,8 @@ class userManager:
|
|||
if (user_modify.status == 'applying' and form.get('status', '') == 'normal'):
|
||||
send_activated_email(user_modify.e_mail, user_modify.username)
|
||||
user_modify.status = form.get('status', '')
|
||||
if (form.get('Chpassword', '') == 'Yes'):
|
||||
new_password = form.get('password','no_password')
|
||||
if (form.get('password', '') != ''):
|
||||
new_password = form.get('password','')
|
||||
new_password = hashlib.sha512(new_password.encode('utf-8')).hexdigest()
|
||||
user_modify.password = new_password
|
||||
#self.chpassword(cur_user = user_modify, password = form.get('password','no_password'))
|
||||
|
@ -629,8 +629,8 @@ class userManager:
|
|||
cur_user = kwargs['cur_user']
|
||||
cur_user.password = hashlib.sha512(kwargs['password'].encode('utf-8')).hexdigest()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def newuser(*args, **kwargs):
|
||||
'''
|
||||
Usage : newuser()
|
||||
|
|
|
@ -159,7 +159,7 @@ class VclusterMgr(object):
|
|||
def deleteproxy(self, username, clustername):
|
||||
[status, clusterinfo] = self.get_clusterinfo(clustername, username)
|
||||
if 'proxy_ip' not in clusterinfo:
|
||||
return [False, "proxy not exists"]
|
||||
return [True, clusterinfo]
|
||||
clusterinfo.pop('proxy_ip')
|
||||
clusterfile = open(self.fspath + "/global/users/" + username + "/clusters/" + clustername, 'w')
|
||||
clusterfile.write(json.dumps(clusterinfo))
|
||||
|
|
|
@ -120,6 +120,7 @@ class Worker(object):
|
|||
self.rpcserver = ThreadXMLRPCServer((self.addr, int(self.port)), allow_none=True)
|
||||
self.rpcserver.register_introspection_functions()
|
||||
self.rpcserver.register_instance(Containers)
|
||||
self.rpcserver.register_function(monitor.workerFetchInfo)
|
||||
# register functions or instances to server for rpc
|
||||
#self.rpcserver.register_function(function_name)
|
||||
|
||||
|
@ -199,10 +200,6 @@ if __name__ == '__main__':
|
|||
sys.exit(1)
|
||||
else:
|
||||
logger.info("etcd connected")
|
||||
|
||||
# init collector to collect monitor infomation
|
||||
collector = monitor.Collector(etcdaddr,clustername,ipaddr)
|
||||
collector.start()
|
||||
|
||||
cpu_quota = env.getenv('CONTAINER_CPU')
|
||||
logger.info ("using CONTAINER_CPU %s" % cpu_quota )
|
||||
|
@ -213,9 +210,11 @@ if __name__ == '__main__':
|
|||
worker_port = env.getenv('WORKER_PORT')
|
||||
logger.info ("using WORKER_PORT %s" % worker_port )
|
||||
|
||||
con_collector = monitor.Container_Collector(etcdaddr, clustername,
|
||||
ipaddr)
|
||||
# init collector to collect monitor infomation
|
||||
con_collector = monitor.Container_Collector()
|
||||
con_collector.start()
|
||||
collector = monitor.Collector()
|
||||
collector.start()
|
||||
logger.info("CPU and Memory usage monitor started")
|
||||
|
||||
logger.info("Starting worker")
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import os, json, sys
|
||||
|
||||
sys.path.append("../src/")
|
||||
from model import db, User
|
||||
fspath="/opt/docklet"
|
||||
|
||||
def update_quotainfo():
|
||||
|
@ -13,7 +14,7 @@ def update_quotainfo():
|
|||
quotafile.close()
|
||||
if type(quotas) is list:
|
||||
new_quotas = {}
|
||||
new_quotas['default'] = 'fundation'
|
||||
new_quotas['default'] = 'foundation'
|
||||
new_quotas['quotainfo'] = quotas
|
||||
quotas = new_quotas
|
||||
print("change the type of quotafile from list to dict")
|
||||
|
@ -38,6 +39,58 @@ def update_quotainfo():
|
|||
quotafile = open(fspath+"/global/sys/quotainfo", 'w')
|
||||
quotafile.write(json.dumps(quotas))
|
||||
quotafile.close()
|
||||
if not os.path.exists(fspath+"/global/sys/quota"):
|
||||
print("quota file not exists, please run docklet to init it")
|
||||
return False
|
||||
groupfile = open(fspath+"/global/sys/quota",'r')
|
||||
groups = json.loads(groupfile.read())
|
||||
groupfile.close()
|
||||
for group in groups:
|
||||
if 'cpu' not in group['quotas'].keys():
|
||||
group['quotas']['cpu'] = "4"
|
||||
if 'memory' not in group['quotas'].keys():
|
||||
group['quotas']['memory'] = "2000"
|
||||
if 'disk' not in group['quotas'].keys():
|
||||
group['quotas']['disk'] = "2000"
|
||||
if 'data' not in group['quotas'].keys():
|
||||
group['quotas']['data'] = "100"
|
||||
if 'image' not in group['quotas'].keys():
|
||||
group['quotas']['image'] = "10"
|
||||
if 'idletime' not in group['quotas'].keys():
|
||||
group['quotas']['idletime'] = "24"
|
||||
if 'vnode' not in group['quotas'].keys():
|
||||
group['quotas']['vnode'] = "8"
|
||||
print("quota updated")
|
||||
groupfile = open(fspath+"/global/sys/quota",'w')
|
||||
groupfile.write(json.dumps(groups))
|
||||
groupfile.close()
|
||||
|
||||
|
||||
def name_error():
|
||||
quotafile = open(fspath+"/global/sys/quotainfo", 'r')
|
||||
quotas = json.loads(quotafile.read())
|
||||
quotafile.close()
|
||||
if quotas['default'] == 'fundation':
|
||||
quotas['default'] = 'foundation'
|
||||
quotafile = open(fspath+"/global/sys/quotainfo",'w')
|
||||
quotafile.write(json.dumps(quotas))
|
||||
quotafile.close()
|
||||
|
||||
groupfile = open(fspath+"/global/sys/quota", 'r')
|
||||
groups = json.loads(groupfile.read())
|
||||
groupfile.close()
|
||||
for group in groups:
|
||||
if group['name'] == 'fundation':
|
||||
group['name'] = 'foundation'
|
||||
groupfile = open(fspath+"/global/sys/quota",'w')
|
||||
groupfile.write(json.dumps(groups))
|
||||
groupfile.close()
|
||||
|
||||
users = User.query.filter_by(user_group = 'fundation').all()
|
||||
for user in users:
|
||||
user.user_group = 'foundation'
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def allquota():
|
||||
try:
|
||||
|
@ -98,4 +151,6 @@ def enable_gluster_quota():
|
|||
|
||||
if __name__ == '__main__':
|
||||
update_quotainfo()
|
||||
if "fix-name-error" in sys.argv:
|
||||
name_error()
|
||||
# enable_gluster_quota()
|
||||
|
|
|
@ -154,7 +154,7 @@
|
|||
<th> {{ group['quotas'][quota['name']] }} </th>
|
||||
{% endfor %}
|
||||
<th><a class="btn btn-xs btn-info" data-toggle="modal" data-target="#ModifyGroupModal_{{ group['name'] }}">Edit</a>
|
||||
{% if group['name'] in [ "root", "primary", "admin", "fundation" ] %}
|
||||
{% if group['name'] in [ "root", "primary", "admin", "foundation" ] %}
|
||||
<a class="btn btn-xs btn-default" href="javascript:void(0)">Delete</a>
|
||||
{% else %}
|
||||
<a class="btn btn-xs btn-danger" href="/group/delete/{{group['name']}}">Delete</a>
|
||||
|
@ -201,7 +201,253 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% for field in ["docklet", "container"] %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="box box-info">
|
||||
<div class="box-header with-border">
|
||||
{% if field == "docklet" %}
|
||||
<h3 class="box-title">Docklet Config</h3>
|
||||
{% else %}
|
||||
<h3 class="box-title">Container Config</h3>
|
||||
{% endif %}
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-box-tool" data-widget="remove"><i class="fa fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<button type="button" class="btn btn-primary btn-sm" data-toggle="modal" data-target="#AddParmModal_{{field}}"><i class="fa fa-plus"></i>Add Parameter</button>
|
||||
<div class="modal inmodal" id="AddParmModal_{{field}}" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content animated fadeIn">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
|
||||
<i class="fa fa-laptop modal-icon"></i>
|
||||
<h4 class="modal-title">Add Parameter</h4>
|
||||
<small class="font-bold">Add a parameter to Docklet</small>
|
||||
</div>
|
||||
<form action="/system/add/" method="POST" >
|
||||
<div class="modal-body">
|
||||
<div style="display:none">
|
||||
<input type="text" placeholder="" class="" name="field" value={{field}} />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Parameter Name</label>
|
||||
<input type="text" placeholder="Enter Parameter Name" class="form-control" name="parm" value="" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Default value</label>
|
||||
<input type="text" placeholder="Enter Default Value" class="form-control" name="val" value="" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
<button type="button" class="btn btn-white" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary btn-sm" data-toggle="modal" data-target="#ResetAllModal_{{field}}"><i class="fa fa-plus"></i> Reset All to Default</button>
|
||||
<div class="modal inmodal" id="ResetAllModal_{{field}}" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content animated fadeIn">
|
||||
<div class="modal-header">
|
||||
<i class="fa fa-laptop modal-icon"></i>
|
||||
<h4>Sure to reset all parameters to default ?</h4>
|
||||
</div>
|
||||
<form action="/system/resetall/" method="POST">
|
||||
<div style="display:none">
|
||||
<input type="text" placeholder="" class="" name="field" value={{field}} />
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Yes</button>
|
||||
<button type="button" class="btn btn-white" data-dismiss="modal">No</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table table-responsive">
|
||||
<table id="myGroupTable" class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Parameter</th>
|
||||
<th>Value</th>
|
||||
<th>History (Click to Reuse)</th>
|
||||
<th>Default</th>
|
||||
<th>Command</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for parm in parms[field] %}
|
||||
<tr>
|
||||
<th>{{ parm["parm"]|truncate(20) }}</th>
|
||||
<th>{{ parm["val"]|truncate(20) }}</th>
|
||||
<th>
|
||||
{% for history in parm["history"] %}
|
||||
<a class="btn btn-xs btn-default" data-toggle="modal" data-target="#UseHistoryModal_{{field}}_{{ parm["parm"]|replace(".","") }}_{{ loop.indexo }}">{{ history|truncate(20) }}</a>
|
||||
<div class="modal inmodal" id="UseHistoryModal_{{field}}_{{ parm["parm"]|replace(".","") }}_{{ loop.indexo }}" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content animated fadeIn">
|
||||
<div class="modal-header">
|
||||
<i class="fa fa-laptop modal-icon"></i>
|
||||
<h4>Sure to set <strong> {{ parm["parm"] }} </strong>to <strong>{{ history }} </strong>?</h4>
|
||||
</div>
|
||||
<form action="/system/modify/" method="POST">
|
||||
<div style="display:none">
|
||||
<input type="text" placeholder="" class="" name="field" value={{field}} />
|
||||
</div>
|
||||
<div class="modal-body" style="display:none">
|
||||
<div class="form-group">
|
||||
<label>Parameter</label>
|
||||
<input type="text" placeholder="Enter Parameter" class="form-control" name="parm" value="{{ parm['parm'] }}" readonly="true" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Value</label>
|
||||
<input type="text" placeholder="Enter Value" class="form-control" name="val" value="{{ history }}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Yes</button>
|
||||
<button type="button" class="btn btn-white" data-dismiss="modal">No</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</th>
|
||||
<th><a class="btn btn-xs btn-default" data-toggle="modal" data-target="#UseDefaultModal_{{field}}_{{ parm["parm"]|replace(".","") }}">{{ parm["default"]|truncate(20) }}</a></th>
|
||||
<th>
|
||||
<a class="btn btn-xs btn-info" data-toggle="modal" data-target="#ModifyParmModal_{{field}}_{{ parm["parm"]|replace(".","") }}">Edit</a>
|
||||
<a class="btn btn-xs btn-default" data-toggle="modal" data-target="#ClearHistoryModal_{{field}}_{{ parm["parm"]|replace(".","") }}">Clear History</a>
|
||||
<a class="btn btn-xs btn-danger" data-toggle="modal" data-target="#DeleteParmModal_{{field}}_{{ parm["parm"]|replace(".","")}}">Delete</a>
|
||||
</th>
|
||||
<div class="modal inmodal" id="ModifyParmModal_{{field}}_{{ parm["parm"]|replace(".","") }}" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content animated fadeIn">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
|
||||
<i class="fa fa-laptop modal-icon"></i>
|
||||
<h4 class="modal-title">Modify Parameter</h4>
|
||||
<small class="font-bold">Modify a parameter in Docklet</small>
|
||||
</div>
|
||||
<form action="/system/modify/" method="POST" >
|
||||
<div style="display:none">
|
||||
<input type="text" placeholder="" class="" name="field" value={{field}} />
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label>Parameter</label>
|
||||
<input type="text" placeholder="Enter Parameter" class="form-control" name="parm" value="{{ parm['parm'] }}" readonly="true" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Value</label>
|
||||
<input type="text" placeholder="Enter Value" class="form-control" name="val" value="{{ parm['val'] }}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
<button type="button" class="btn btn-white" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal inmodal" id="UseDefaultModal_{{field}}_{{ parm["parm"]|replace(".","") }}" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content animated fadeIn">
|
||||
<div class="modal-header">
|
||||
<i class="fa fa-laptop modal-icon"></i>
|
||||
<h4>Sure to set <strong> {{ parm["parm"] }} </strong> to <strong> {{ parm["default"] }} </strong> ?</h4>
|
||||
</div>
|
||||
<form action="/system/modify/" method="POST">
|
||||
<div style="display:none">
|
||||
<input type="text" placeholder="" class="" name="field" value={{field}} />
|
||||
</div>
|
||||
<div class="modal-body" style="display:none">
|
||||
<div class="form-group">
|
||||
<label>Parameter</label>
|
||||
<input type="text" placeholder="Enter Parameter" class="form-control" name="parm" value="{{ parm['parm'] }}" readonly="true" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Value</label>
|
||||
<input type="text" placeholder="Enter Value" class="form-control" name="val" value="{{ parm["default"] }}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Yes</button>
|
||||
<button type="button" class="btn btn-white" data-dismiss="modal">No</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal inmodal" id="ClearHistoryModal_{{field}}_{{ parm["parm"]|replace(".","") }}" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content animated fadeIn">
|
||||
<div class="modal-header">
|
||||
<i class="fa fa-laptop modal-icon"></i>
|
||||
<h4>Sure to clear history for <strong> {{ parm["parm"] }} </strong> ?</h4>
|
||||
</div>
|
||||
<form action="/system/clear_history/" method="POST">
|
||||
<div style="display:none">
|
||||
<input type="text" placeholder="" class="" name="field" value={{field}} />
|
||||
</div>
|
||||
<div class="modal-body" style="display:none">
|
||||
<div class="form-group">
|
||||
<label>Parameter</label>
|
||||
<input type="text" placeholder="Enter Parameter" class="form-control" name="parm" value="{{ parm['parm'] }}" readonly="true" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Yes</button>
|
||||
<button type="button" class="btn btn-white" data-dismiss="modal">No</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal inmodal" id="DeleteParmModal_{{field}}_{{parm["parm"]|replace(".","") }}" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content animated fadeIn">
|
||||
<div class="modal-header">
|
||||
<i class="fa fa-laptop modal-icon"></i>
|
||||
<h4>Sure to delete the parameter <strong> {{ parm["parm"] }} </strong> ?</h4>
|
||||
</div>
|
||||
<form action="/system/delete/" method="POST">
|
||||
<div style="display:none">
|
||||
<input type="text" placeholder="" class="" name="field" value={{field}} />
|
||||
</div>
|
||||
<div class="modal-body" style="display:none">
|
||||
<div class="form-group">
|
||||
<label>Parameter</label>
|
||||
<input type="text" placeholder="Enter Parameter" class="form-control" name="parm" value="{{ parm['parm'] }}" readonly="true" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Yes</button>
|
||||
<button type="button" class="btn btn-white" data-dismiss="modal">No</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -1,329 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Docklet | Dashboard</title>
|
||||
<!-- Tell the browser to be responsive to screen width -->
|
||||
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
||||
<link rel="shortcut icon" href="/static/img/favicon.ico">
|
||||
|
||||
<link href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
|
||||
|
||||
<!-- Font Awesome -->
|
||||
<link href="//cdn.bootcss.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet">
|
||||
|
||||
<!-- Ionicons -->
|
||||
<link href="//cdn.bootcss.com/ionicons/2.0.1/css/ionicons.min.css" rel="stylesheet">
|
||||
|
||||
<link href="//cdn.bootcss.com/animate.css/3.5.1/animate.min.css" rel="stylesheet">
|
||||
<link href="//cdn.bootcss.com/toastr.js/latest/css/toastr.min.css" rel="stylesheet">
|
||||
|
||||
<!-- Theme style -->
|
||||
|
||||
<link rel="stylesheet" href="/static/dist/css/AdminLTE.min.css">
|
||||
|
||||
<link rel="stylesheet" href="/static/dist/css/skins/skin-blue.min.css">
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body class="hold-transition skin-blue sidebar-mini">
|
||||
<div class="wrapper">
|
||||
|
||||
<!-- Main Header -->
|
||||
<header class="main-header">
|
||||
|
||||
<!-- Logo -->
|
||||
<a href="" class="logo">
|
||||
<!-- mini logo for sidebar mini 50x50 pixels -->
|
||||
<span class="logo-mini"></span>
|
||||
<!-- logo for regular state and mobile devices -->
|
||||
<span class="logo-lg"><b>Docklet</b></span>
|
||||
</a>
|
||||
|
||||
<!-- Header Navbar -->
|
||||
<nav class="navbar navbar-static-top" role="navigation">
|
||||
<!-- Sidebar toggle button-->
|
||||
<a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
</a>
|
||||
<!-- Navbar Right Menu -->
|
||||
<div class="navbar-custom-menu">
|
||||
<ul class="nav navbar-nav">
|
||||
<!-- Messages: style can be found in dropdown.less-->
|
||||
|
||||
<li class="dropdown user user-menu">
|
||||
<!-- Menu Toggle Button -->
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<!-- The user image in the navbar-->
|
||||
<img src="{{ mysession['avatar'] }}" class="user-image" alt="User Image">
|
||||
<!-- hidden-xs hides the username on small devices so only the image appears. -->
|
||||
<span class="hidden-xs">{{ mysession['nickname'] }}</span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<!-- The user image in the menu -->
|
||||
<li class="user-header">
|
||||
<img src="{{ mysession['avatar'] }}" class="img-circle" alt="User Image">
|
||||
|
||||
<p>
|
||||
{{ mysession['nickname'] }}
|
||||
<small>{{ mysession['description'] }}</small>
|
||||
</p>
|
||||
</li>
|
||||
<!-- Menu Body -->
|
||||
|
||||
<!-- Menu Footer-->
|
||||
<li class="user-footer">
|
||||
<div class="pull-left">
|
||||
Profile
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
Sign out
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<!-- Control Sidebar Toggle Button -->
|
||||
<li>
|
||||
<a href="/document/" target="_blank"><strong>Help</strong></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<!-- Left side column. contains the logo and sidebar -->
|
||||
<aside class="main-sidebar">
|
||||
|
||||
<!-- sidebar: style can be found in sidebar.less -->
|
||||
<section class="sidebar">
|
||||
|
||||
<!-- Sidebar user panel (optional) -->
|
||||
<div class="user-panel">
|
||||
<div class="pull-left image">
|
||||
<img src="{{ mysession['avatar'] }}" class="img-circle" alt="User Image">
|
||||
</div>
|
||||
<div class="pull-left info">
|
||||
<p>{{ mysession['nickname'] }}</p>
|
||||
<!-- Status -->
|
||||
<i class="fa fa-circle text-success"></i> {{ mysession['status']}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar Menu -->
|
||||
<ul class="sidebar-menu">
|
||||
<li class="header">USER OPERATIONS</li>
|
||||
<!-- Optionally, you can add icons to the links -->
|
||||
<li class="active" id="nav_Dashboard">
|
||||
<a href="javascript:void(0)"><i class="fa fa-th-large"></i> <span class="nav-label">Dashboard</span></a>
|
||||
</li>
|
||||
<li id="nav_Config">
|
||||
<a href="javascript:void(0)"><i class="fa fa-gears"></i> <span class="nav-label">Config</span></a>
|
||||
</li>
|
||||
|
||||
<li id="nav_Status">
|
||||
<a href="javascript:void(0)"><i class="fa fa-bar-chart"></i> <span class="nav-label">Status</span></a>
|
||||
</li>
|
||||
|
||||
|
||||
{% if mysession['usergroup'] == 'root' or mysession['usergroup'] == 'admin'%}
|
||||
<li class="header">ADMIN OPERATIONS</li>
|
||||
<li id="nav_Hosts">
|
||||
<i class="fa fa-sitemap"></i> <span class="nav-label">Hosts</span>
|
||||
</li>
|
||||
<li id="user_List">
|
||||
<i class="fa fa-users"></i> <span class="nav-label">Users</span>
|
||||
</li>
|
||||
<li id="admin">
|
||||
<i class="fa fa-gears"></i> <span class="nav-label">Admin</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
</ul>
|
||||
<!-- /.sidebar-menu -->
|
||||
</section>
|
||||
<!-- /.sidebar -->
|
||||
</aside>
|
||||
|
||||
<!-- Content Wrapper. Contains page content -->
|
||||
<div class="content-wrapper">
|
||||
<!-- Content Header (Page header) -->
|
||||
<section class="content-header">
|
||||
<h1>
|
||||
<strong>Dashboard</strong>
|
||||
</h1>
|
||||
|
||||
<ol class="breadcrumb">
|
||||
<li>
|
||||
<i class="fa fa-dashboard"></i>Home
|
||||
</li>
|
||||
<li class="active">
|
||||
<strong>Dashboard</strong>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
</section>
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="box box-info">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Workspaces</h3>
|
||||
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-box-tool" data-widget="remove"><i class="fa fa-times"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
|
||||
<p>
|
||||
<button type="button" class="btn btn-primary btn-sm"><i class="fa fa-plus"></i> Add Workspace</button>
|
||||
</p>
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Status</th>
|
||||
<th>Operation</th>
|
||||
<th>WorkSpace</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>guest-1-0</td>
|
||||
<td><div class="text-success"><i class="fa fa-play"></i> Running</div></td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-xs btn-warning"> Stop </button>
|
||||
<button type="button" class="btn btn-xs btn-default"> Delete </button>
|
||||
</td>
|
||||
<td>
|
||||
<a href="/go/guest/guestspace" target="_blank"><button type="button" class="btn btn-xs btn-success"> Go </button></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</section>
|
||||
<!-- /.content -->
|
||||
</div>
|
||||
<!-- /.content-wrapper -->
|
||||
|
||||
<!-- Main Footer -->
|
||||
<footer class="main-footer">
|
||||
<!-- To the right -->
|
||||
<div class="pull-right hidden-xs">
|
||||
<i>Docklet</i> 0.25
|
||||
</div>
|
||||
<!-- Default to the left -->
|
||||
<strong>Copyright</strong>© 2016 <a href="http://docklet.unias.org">UniAS</a>@<a href="http://www.sei.pku.edu.cn"> SEI, PKU</a>
|
||||
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
<!-- ./wrapper -->
|
||||
|
||||
<!-- REQUIRED JS SCRIPTS -->
|
||||
|
||||
<!-- jQuery 2.2.1 -->
|
||||
<script src="//cdn.bootcss.com/jquery/2.2.1/jquery.min.js"></script>
|
||||
<!-- Bootstrap 3.3.5 -->
|
||||
<script src="//cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
|
||||
<!-- AdminLTE App -->
|
||||
<script src="/static/dist/js/app.min.js"></script>
|
||||
|
||||
<script src="//cdn.bootcss.com/fastclick/1.0.6/fastclick.min.js"></script>
|
||||
<script src="//cdn.bootcss.com/jQuery-slimScroll/1.3.7/jquery.slimscroll.min.js"></script>
|
||||
<script src="//cdn.bootcss.com/toastr.js/latest/js/toastr.min.js"></script>
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var pathname = window.location.pathname;
|
||||
pathname = pathname.split(/\//);
|
||||
if(pathname[1] != 'dashboard')
|
||||
$("#nav_Dashboard").removeClass("active");
|
||||
if(pathname[1] == 'vclusters')
|
||||
$("#nav_Status").addClass("active");
|
||||
else if(pathname[1] == 'hosts')
|
||||
$("#nav_Hosts").addClass("active");
|
||||
else if(pathname[1] == 'config')
|
||||
$("#nav_Config").addClass("active");
|
||||
else if(pathname[1] == 'user')
|
||||
{
|
||||
if (pathname[2] == 'list')
|
||||
$("#user_List").addClass("active");
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
{% if mysession['status'] == 'init' %}
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
toastr.options = {
|
||||
"closeButton": false,
|
||||
"debug": true,
|
||||
"progressBar": false,
|
||||
"preventDuplicates": false,
|
||||
"positionClass": "toast-top-left",
|
||||
"onclick": function(){
|
||||
window.location.href="/activate/";
|
||||
},
|
||||
"showDuration": "0",
|
||||
"hideDuration": "0",
|
||||
"timeOut": "0",
|
||||
"extendedTimeOut": "0",
|
||||
"showEasing": "swing",
|
||||
"hideEasing": "linear",
|
||||
"showMethod": "fadeIn",
|
||||
"hideMethod": "fadeOut"
|
||||
};
|
||||
toastr.error("You are not activated. Click this notification to activate your account.");
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if mysession['status'] == 'applying' %}
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
toastr.options = {
|
||||
"closeButton": false,
|
||||
"debug": true,
|
||||
"progressBar": false,
|
||||
"preventDuplicates": false,
|
||||
"positionClass": "toast-top-left",
|
||||
"onclick": function(){
|
||||
},
|
||||
"showDuration": "0",
|
||||
"hideDuration": "0",
|
||||
"timeOut": "0",
|
||||
"extendedTimeOut": "0",
|
||||
"showEasing": "swing",
|
||||
"hideEasing": "linear",
|
||||
"showMethod": "fadeIn",
|
||||
"hideMethod": "fadeOut"
|
||||
};
|
||||
toastr.warning("You applying is being checked.");
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -132,16 +132,10 @@
|
|||
<label>Telephone Number</label>
|
||||
<input type = "text" placeholder="Enter Telephone Number" class="form-control" name="tel" id="mTel">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Change Password?</label>
|
||||
<select class="form-control" name="Chpassword" id="mChpassword">
|
||||
<option>Yes</option>
|
||||
<option>No</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Password</label>
|
||||
<input type = "text" placeholder="Enter Password" class="form-control" name="password" id="mPassword">
|
||||
<input type="password" placeholder="Enter Password" class="form-control" name="password" id="mPassword">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
|
@ -249,8 +243,6 @@
|
|||
$("#mDepartment").val(result.department);
|
||||
$("#mStudentNumber").val(result.student_number);
|
||||
$("#mTel").val(result.tel);
|
||||
$("#mChpassword").val('No');
|
||||
$("#mPassword").val(result.password);
|
||||
$("#mStatus").val(result.status);
|
||||
$("#mUserGroup").val(result.group);
|
||||
$("#mAuthMethod").val(result.auth_method);
|
||||
|
|
30
web/web.py
30
web/web.py
|
@ -101,12 +101,6 @@ def activate():
|
|||
def dashboard():
|
||||
return dashboardView.as_view()
|
||||
|
||||
@app.route("/dashboard_guest/", methods=['GET'])
|
||||
def dashboard_guest():
|
||||
resp = make_response(dashboard_guestView.as_view())
|
||||
resp.set_cookie('guest-cookie', cookie_tool.generate_cookie('guest', app.secret_key))
|
||||
return resp
|
||||
|
||||
@app.route("/document/", methods=['GET'])
|
||||
def redirect_dochome():
|
||||
return redirect("http://docklet.unias.org/userguide")
|
||||
|
@ -354,6 +348,30 @@ def userinfo():
|
|||
def userquery():
|
||||
return userqueryView.as_view()
|
||||
|
||||
@app.route("/system/modify/", methods=['POST'])
|
||||
@administration_required
|
||||
def systemmodify():
|
||||
return systemmodifyView.as_view()
|
||||
|
||||
@app.route("/system/clear_history/", methods=['POST'])
|
||||
@administration_required
|
||||
def systemclearhistory():
|
||||
return systemclearView.as_view()
|
||||
|
||||
@app.route("/system/add/", methods=['POST'])
|
||||
@administration_required
|
||||
def systemadd():
|
||||
return systemaddView.as_view()
|
||||
|
||||
@app.route("/system/delete/", methods=['POST'])
|
||||
@administration_required
|
||||
def systemdelete():
|
||||
return systemdeleteView.as_view()
|
||||
|
||||
@app.route("/system/resetall/", methods=['POST'])
|
||||
@administration_required
|
||||
def systemresetall():
|
||||
return systemresetallView.as_view()
|
||||
|
||||
@app.route("/admin/", methods=['GET', 'POST'])
|
||||
@administration_required
|
||||
|
|
|
@ -13,7 +13,8 @@ class adminView(normalView):
|
|||
groups = result["groups"]
|
||||
quotas = result["quotas"]
|
||||
defaultgroup = result["default"]
|
||||
return self.render(self.template_path, groups = groups, quotas = quotas, defaultgroup = defaultgroup)
|
||||
parms = dockletRequest.post('/system/parmList/')
|
||||
return self.render(self.template_path, groups = groups, quotas = quotas, defaultgroup = defaultgroup, parms = parms)
|
||||
|
||||
class groupaddView(normalView):
|
||||
@classmethod
|
||||
|
@ -21,6 +22,36 @@ class groupaddView(normalView):
|
|||
dockletRequest.post('/user/groupadd/', request.form)
|
||||
return redirect('/admin/')
|
||||
|
||||
class systemmodifyView(normalView):
|
||||
@classmethod
|
||||
def post(self):
|
||||
dockletRequest.post('/system/modify/', request.form)
|
||||
return redirect('/admin/')
|
||||
|
||||
class systemclearView(normalView):
|
||||
@classmethod
|
||||
def post(self):
|
||||
dockletRequest.post('/system/clear_history/', request.form)
|
||||
return redirect('/admin/')
|
||||
|
||||
class systemaddView(normalView):
|
||||
@classmethod
|
||||
def post(self):
|
||||
dockletRequest.post('/system/add/', request.form)
|
||||
return redirect('/admin/')
|
||||
|
||||
class systemdeleteView(normalView):
|
||||
@classmethod
|
||||
def post(self):
|
||||
dockletRequest.post('/system/delete/', request.form)
|
||||
return redirect('/admin/')
|
||||
|
||||
class systemresetallView(normalView):
|
||||
@classmethod
|
||||
def post(self):
|
||||
dockletRequest.post('/system/reset_all/', request.form)
|
||||
return redirect('/admin/')
|
||||
|
||||
class quotaaddView(normalView):
|
||||
@classmethod
|
||||
def post(self):
|
||||
|
@ -45,3 +76,14 @@ class groupdelView(normalView):
|
|||
@classmethod
|
||||
def get(self):
|
||||
return self.post()
|
||||
|
||||
class chparmView(normalView):
|
||||
@classmethod
|
||||
def post(self):
|
||||
dockletRequest.post('/system/chparm/', request.form)
|
||||
|
||||
class historydelView(normalView):
|
||||
@classmethod
|
||||
def post(self):
|
||||
dockletRequest.post('/system/historydel/', request.form)
|
||||
return redirect('/admin/')
|
||||
|
|
|
@ -34,20 +34,3 @@ class dashboardView(normalView):
|
|||
@classmethod
|
||||
def post(self):
|
||||
return self.get()
|
||||
|
||||
class dashboard_guestView(normalView):
|
||||
template_path = "dashboard_guest.html"
|
||||
|
||||
@classmethod
|
||||
def get(self):
|
||||
mysession = {}
|
||||
mysession['avatar'] = "/static/avatar/default.png"
|
||||
mysession['nickname'] = "guest"
|
||||
mysession['description'] = "you are a guest"
|
||||
mysession['status'] = "guest"
|
||||
mysession['usergroup'] = "normal"
|
||||
return render_template(self.template_path, mysession = mysession)
|
||||
|
||||
@classmethod
|
||||
def post(self):
|
||||
return self.get()
|
||||
|
|
Loading…
Reference in New Issue