Merge pull request #228 from PedroLiu/master
Add settings and logs panel
This commit is contained in:
commit
d7406f5ed3
|
@ -24,6 +24,8 @@ import http.server, cgi, json, sys, shutil
|
|||
import xmlrpc.client
|
||||
from socketserver import ThreadingMixIn
|
||||
import nodemgr, vclustermgr, etcdlib, network, imagemgr, notificationmgr
|
||||
from settings import settings
|
||||
from logs import logs
|
||||
import userManager,beansapplicationmgr
|
||||
import monitor,traceback
|
||||
import threading
|
||||
|
@ -109,6 +111,35 @@ def beans_check(func):
|
|||
def isalive(user, beans, form):
|
||||
return json.dumps({'success':'true'})
|
||||
|
||||
|
||||
@app.route("/settings/list/", methods=['POST'])
|
||||
@login_required
|
||||
def settings_list(user, beans, form):
|
||||
user_group = post_to_user('/user/selfQuery/', {'token': request.form.get("token", None)}).get('data', None).get('group', None)
|
||||
return json.dumps(settings.list(user_group = user_group))
|
||||
|
||||
@app.route("/settings/update/", methods=['POST'])
|
||||
@login_required
|
||||
def settings_update(user, beans, form):
|
||||
user_group = post_to_user('/user/selfQuery/', {'token': request.form.get("token", None)}).get('data', None).get('group', None)
|
||||
newSetting = {}
|
||||
newSetting['ADMIN_EMAIL_ADDRESS'] = form.get('ADMIN_EMAIL_ADDRESS', '')
|
||||
newSetting['EMAIL_FROM_ADDRESS'] = form.get('EMAIL_FROM_ADDRESS', '')
|
||||
return json.dumps(settings.update(user_group = user_group, newSetting = newSetting))
|
||||
|
||||
@app.route("/logs/list/", methods=['POST'])
|
||||
@login_required
|
||||
def logs_list(user, beans, form):
|
||||
user_group = post_to_user('/user/selfQuery/', {'token': request.form.get("token", None)}).get('data', None).get('group', None)
|
||||
return json.dumps(logs.list(user_group = user_group))
|
||||
|
||||
@app.route("/logs/get/", methods=['POST'])
|
||||
@login_required
|
||||
def logs_get(user, beans, form):
|
||||
user_group = post_to_user('/user/selfQuery/', {'token': request.form.get("token", None)}).get('data', None).get('group', None)
|
||||
return json.dumps(logs.get(user_group = user_group, filename = form.get('filename', '')))
|
||||
|
||||
|
||||
@app.route("/cluster/create/", methods=['POST'])
|
||||
@login_required
|
||||
@beans_check
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import env
|
||||
import json, os
|
||||
from log import logger
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
logsPath = env.getenv('FS_PREFIX') + '/local/log/'
|
||||
|
||||
class logsClass:
|
||||
setting = {}
|
||||
|
||||
def list(*args, **kwargs):
|
||||
if ( ('user_group' in kwargs) == False):
|
||||
return {"success":'false', "reason":"Cannot get user_group"}
|
||||
user_group = kwargs['user_group']
|
||||
if (not ((user_group == 'admin') or (user_group == 'root'))):
|
||||
return {"success": 'false', "reason": 'Unauthorized Action'}
|
||||
s = os.listdir(logsPath)
|
||||
r = []
|
||||
for i in s:
|
||||
if ('log' in i):
|
||||
r.append(i)
|
||||
return {'success': 'true', 'result': r}
|
||||
|
||||
def get(*args, **kwargs):
|
||||
if ( ('user_group' in kwargs) == False):
|
||||
return {"success":'false', "reason":"Cannot get user_group"}
|
||||
user_group = kwargs['user_group']
|
||||
if (not ((user_group == 'admin') or (user_group == 'root'))):
|
||||
return {"success": 'false', "reason": 'Unauthorized Action'}
|
||||
filepath = logsPath + secure_filename(kwargs['filename'])
|
||||
try:
|
||||
if not os.path.exists(filepath):
|
||||
return {"success": 'false', "reason": 'file not exist'}
|
||||
logfile = open(filepath, 'r')
|
||||
logtext = logfile.read()
|
||||
logfile.close()
|
||||
return {'success': 'true', 'result': logtext}
|
||||
except:
|
||||
return {'success': 'false', 'reason': 'file read error'}
|
||||
|
||||
|
||||
|
||||
logs = logsClass()
|
10
src/model.py
10
src/model.py
|
@ -148,13 +148,13 @@ class UserUsage(db.Model):
|
|||
cpu = db.Column(db.String(10))
|
||||
memory = db.Column(db.String(10))
|
||||
disk = db.Column(db.String(10))
|
||||
|
||||
|
||||
def __init__(self, name):
|
||||
self.username = name
|
||||
self.cpu = '0'
|
||||
self.memory = '0'
|
||||
self.disk = '0'
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return '<UserUsage %r>' % self.name
|
||||
|
||||
|
@ -210,7 +210,7 @@ class VNode(db.Model):
|
|||
laststopruntime = db.Column(db.Integer)
|
||||
billing = db.Column(db.Integer)
|
||||
histories = db.relationship('History', backref='v_node', lazy='dynamic')
|
||||
|
||||
|
||||
def __init__(self, vnode_name):
|
||||
self.name = vnode_name
|
||||
self.laststopcpuval = 0
|
||||
|
@ -236,7 +236,7 @@ class History(db.Model):
|
|||
self.cputime = cputime
|
||||
self.billing = billing
|
||||
self.actionTime = datetime.now()
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return "{\"id\":\"%d\",\"vnode\":\"%s\",\"action\":\"%s\",\"runningtime\":\"%d\",\"cputime\":\"%f\",\"billing\":\"%d\",\"actionTime\":\"%s\"}" % (self.id, self.vnode, self.action, self.runningtime, self.cputime, self.billing, self.actionTime.strftime("%Y-%m-%d %H:%M:%S"))
|
||||
|
||||
|
@ -248,7 +248,7 @@ class ApplyMsg(db.Model):
|
|||
reason = db.Column(db.String(600))
|
||||
status = db.Column(db.String(10))
|
||||
time = db.Column(db.DateTime(10))
|
||||
|
||||
|
||||
def __init__(self,username, number, reason):
|
||||
self.username = username
|
||||
self.number = number
|
||||
|
|
|
@ -460,7 +460,7 @@ class NetworkMgr(object):
|
|||
usrpools = self.users[username]
|
||||
if(workerip is not None):
|
||||
ip = workerip
|
||||
worker = nodemgr.ip_to_rpc(workerip)
|
||||
worker = nodemgr.ip_to_rpc(workerip)
|
||||
logger.info("setup gateway for %s with %s and vlan=%s on %s" % (username, usrpools.get_gateway_cidr(), str(usrpools.vlanid), ip))
|
||||
self.usrgws[username] = ip
|
||||
self.dump_usrgw(username)
|
||||
|
|
|
@ -148,4 +148,3 @@ class NodeMgr(object):
|
|||
|
||||
def ip_to_rpc(self,ip):
|
||||
return xmlrpc.client.ServerProxy("http://%s:%s" % (ip, env.getenv("WORKER_PORT")))
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import env
|
||||
import json, os
|
||||
from functools import wraps
|
||||
from log import logger
|
||||
|
||||
|
||||
class settingsClass:
|
||||
setting = {}
|
||||
def __init__(self):
|
||||
settingPath = env.getenv('FS_PREFIX') + '/local/settings.conf'
|
||||
if not os.path.exists(settingPath):
|
||||
settingFile = open(settingPath,'w')
|
||||
setting = {}
|
||||
settingFile.write(json.dumps(setting))
|
||||
settingFile.close()
|
||||
else:
|
||||
settingFile = open(settingPath, 'r')
|
||||
settingText = settingFile.read()
|
||||
settingFile.close()
|
||||
self.setting = json.loads(settingText)
|
||||
|
||||
def get(self, arg):
|
||||
return self.setting.get(arg,'')
|
||||
|
||||
def list(*args, **kwargs):
|
||||
if ( ('user_group' in kwargs) == False):
|
||||
return {"success":'false', "reason":"Cannot get user_group"}
|
||||
user_group = kwargs['user_group']
|
||||
if (not ((user_group == 'admin') or (user_group == 'root'))):
|
||||
return {"success": 'false', "reason": 'Unauthorized Action'}
|
||||
return {'success': 'true', 'result': args[0].setting}
|
||||
|
||||
def update(*args, **kwargs):
|
||||
try:
|
||||
if ( ('user_group' in kwargs) == False):
|
||||
return {"success":'false', "reason":"Cannot get user_group"}
|
||||
user_group = kwargs['user_group']
|
||||
if (not ((user_group == 'admin') or (user_group == 'root'))):
|
||||
return {"success": 'false', "reason": 'Unauthorized Action'}
|
||||
newSetting = kwargs['newSetting']
|
||||
settingPath = env.getenv('FS_PREFIX') + '/local/settings.conf';
|
||||
settingText = json.dumps(newSetting)
|
||||
settingFile = open(settingPath,'w')
|
||||
settingFile.write(settingText)
|
||||
settingFile.close()
|
||||
args[0].setting = newSetting
|
||||
return {'success': 'true'}
|
||||
except:
|
||||
return {'success': 'false'}
|
||||
|
||||
|
||||
settings = settingsClass()
|
|
@ -14,6 +14,7 @@ import hashlib
|
|||
import pam
|
||||
from base64 import b64encode
|
||||
import env
|
||||
from settings import settings
|
||||
import smtplib
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
|
@ -23,8 +24,6 @@ import json
|
|||
from log import logger
|
||||
from lvmtool import *
|
||||
|
||||
email_from_address = env.getenv('EMAIL_FROM_ADDRESS')
|
||||
admin_email_address = env.getenv('ADMIN_EMAIL_ADDRESS')
|
||||
PAM = pam.pam()
|
||||
fspath = env.getenv('FS_PREFIX')
|
||||
data_quota = env.getenv('DATA_QUOTA')
|
||||
|
@ -71,6 +70,7 @@ def token_required(func):
|
|||
return wrapper
|
||||
|
||||
def send_activated_email(to_address, username):
|
||||
email_from_address = settings.get('EMAIL_FROM_ADDRESS')
|
||||
if (email_from_address in ['\'\'', '\"\"', '']):
|
||||
return
|
||||
#text = 'Dear '+ username + ':\n' + ' Your account in docklet has been activated'
|
||||
|
@ -97,8 +97,10 @@ def send_activated_email(to_address, username):
|
|||
s.close()
|
||||
|
||||
def send_remind_activating_email(username):
|
||||
admin_email_address = env.getenv('ADMIN_EMAIL_ADDRESS')
|
||||
#admin_email_address = env.getenv('ADMIN_EMAIL_ADDRESS')
|
||||
nulladdr = ['\'\'', '\"\"', '']
|
||||
email_from_address = settings.get('EMAIL_FROM_ADDRESS')
|
||||
admin_email_address = settings.get('ADMIN_EMAIL_ADDRESS')
|
||||
if (email_from_address in nulladdr or admin_email_address in nulladdr):
|
||||
return
|
||||
#text = 'Dear '+ username + ':\n' + ' Your account in docklet has been activated'
|
||||
|
@ -123,7 +125,7 @@ def send_remind_activating_email(username):
|
|||
textmsg = MIMEText(text,'html','utf-8')
|
||||
msg['Subject'] = Header(subject, 'utf-8')
|
||||
msg['From'] = email_from_address
|
||||
msg['To'] = alladdr
|
||||
msg['To'] = alladdr
|
||||
msg.attach(textmsg)
|
||||
s = smtplib.SMTP()
|
||||
s.connect()
|
||||
|
|
|
@ -26,7 +26,6 @@ G_masterips = []
|
|||
for masterip in masterips:
|
||||
G_masterips.append(masterip.split("@")[0] + ":" + str(env.getenv("MASTER_PORT")))
|
||||
|
||||
|
||||
from flask import Flask, request, session, render_template, redirect, send_from_directory, make_response, url_for, abort
|
||||
from functools import wraps
|
||||
import userManager,beansapplicationmgr, notificationmgr
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
.file-box {
|
||||
float: left;
|
||||
width: 220px;
|
||||
}
|
||||
.file {
|
||||
border: 1px solid #e7eaec;
|
||||
padding: 0;
|
||||
background-color: #ffffff;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
.file .icon {
|
||||
padding: 15px 10px;
|
||||
text-align: center;
|
||||
}
|
||||
.file .icon i {
|
||||
font-size: 70px;
|
||||
color: #dadada;
|
||||
}
|
||||
.file .file-name {
|
||||
padding: 10px;
|
||||
background-color: #f8f8f8;
|
||||
border-top: 1px solid #e7eaec;
|
||||
}
|
||||
.corner {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
line-height: 0;
|
||||
border: 0.6em solid transparent;
|
||||
border-right: 0.6em solid #f1f1f1;
|
||||
border-bottom: 0.6em solid #f1f1f1;
|
||||
right: 0em;
|
||||
bottom: 0em;
|
||||
}
|
||||
|
||||
|
||||
a:hover{
|
||||
text-decoration:none;
|
||||
}
|
|
@ -172,7 +172,7 @@
|
|||
var host = window.location.host;
|
||||
$.post("http://"+host+"/image/list/"+masterip+"/",{},function(data){
|
||||
var images = data.images;
|
||||
var imagehtml =
|
||||
var imagehtml =
|
||||
"<thread>"
|
||||
+"<tr>"
|
||||
+"<th>ImageName</th>"
|
||||
|
|
|
@ -172,9 +172,13 @@
|
|||
<li id="admin">
|
||||
<a href='/admin/'><i class="fa fa-user"></i> <span class="nav-label">Admin</span></a>
|
||||
</li>
|
||||
<li id="nav_Cloud">
|
||||
<a href='/cloud/'><i class="fa fa-cloud"></i> <span class="nav-label">Cloud</span></a>
|
||||
<li>
|
||||
|
||||
<li id="nav_Cloud">
|
||||
<a href='/cloud/'><i class="fa fa-cloud"></i> <span class="nav-label">Cloud</span></a>
|
||||
<li>
|
||||
<li id="settings">
|
||||
<a href='/settings/'><i class="fa fa-user"></i> <span class="nav-label">Settings</span></a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
</ul>
|
||||
|
@ -263,6 +267,8 @@
|
|||
$("#nav_Notification").addClass('active');
|
||||
else if(pathname[1] == 'admin')
|
||||
$("#admin").addClass('active');
|
||||
else if(pathname[1] == 'settings')
|
||||
$("#settings").addClass('active');
|
||||
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,362 +1,362 @@
|
|||
{% extends "base_AdminLTE.html"%}
|
||||
|
||||
<!--
|
||||
Config Page :
|
||||
1. images
|
||||
2. workspace templates
|
||||
|
||||
-->
|
||||
|
||||
{% block title %}Docklet | Config{% endblock %}
|
||||
|
||||
{% block panel_title %}Config{% endblock %}
|
||||
|
||||
{% block panel_list %}
|
||||
<ol class="breadcrumb">
|
||||
<li>
|
||||
<a href="/dashboard/"><i class="fa fa-dashboard"></i>Home</a>
|
||||
</li>
|
||||
<li class="active">
|
||||
<strong>Config</strong>
|
||||
</li>
|
||||
</ol>
|
||||
{% endblock %}
|
||||
|
||||
{% block css_src %}
|
||||
<link href="//cdn.bootcss.com/datatables/1.10.11/css/dataTables.bootstrap.min.css" rel="stylesheet">
|
||||
<link href="//cdn.bootcss.com/datatables/1.10.11/css/jquery.dataTables_themeroller.css" rel="stylesheet">
|
||||
<link href="/static/dist/css/modalconfig.css" rel="stylesheet">
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
{% for master in allclusters %}
|
||||
{% for clustername, clusterinfo in allclusters[master].items() %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="box box-info collapsed-box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">WorkSpace Name: {{ clustername }} <strong>@ {{master.split("@")[1]}}</strong></h3>
|
||||
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-plus"></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" style="display:none">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="box box-info">
|
||||
<div class="box-header with-border">
|
||||
<h4 class="box-title">VCLUSTER</h4>
|
||||
<h5>create_time:{{clusterinfo['create_time']}}      start_time:{{clusterinfo['start_time']}}</h5>
|
||||
|
||||
<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" data-toggle="modal" data-target="#Scaleout_{{ clustername }}_{{master.split("@")[1]}}"><i class="fa fa-plus"></i>Add Node</button>
|
||||
</p>
|
||||
<div class="modal inmodal" id="Scaleout_{{ clustername }}_{{master.split("@")[1]}}" 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-plus modal-icon"></i>
|
||||
<h4 class="modal-title">Choose Image</h4>
|
||||
<small class="font-bold">Choose an image to add node</small>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<form action="/workspace/scaleout/{{ clustername }}/{{master.split("@")[0]}}/" method="POST" >
|
||||
<table class="table table-striped table-bordered table-hover table-image">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ImageName</th>
|
||||
<th>Type</th>
|
||||
<th>Owner</th>
|
||||
<th>Choose</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>base</td>
|
||||
<td>public</td>
|
||||
<td>docklet</td>
|
||||
<td><input type="radio" name="image" value="base_base_base" checked="checked"></td>
|
||||
</tr>
|
||||
{% for image in allimages[master]['private'] %}
|
||||
<tr>
|
||||
<td>{{image['name']}}</td>
|
||||
<td>private</td>
|
||||
<td>{{mysession['username']}}</td>
|
||||
<td><input type="radio" name="image" value="{{image['name']}}_{{mysession['username']}}_private"></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% for p_user, p_images in allimages[master]['public'].items() %}
|
||||
{% for image in p_images %}
|
||||
<tr>
|
||||
<td>{{image['name']}}</td>
|
||||
<td>public</td>
|
||||
<td>{{p_user}}</td>
|
||||
<td><input type="radio" name="image" value="{{image['name']}}_{{p_user}}_public"></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="panel-group" id="accordion_{{clustername}}_{{master.split("@")[1]}}">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
<a data-toggle="collapse" data-panel="#accordion_{{clustername}}_{{master.split("@")[1]}}" href="#collapseOne_{{clustername}}_{{master.split("@")[1]}}">
|
||||
show advanced options
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="collapseOne_{{clustername}}_{{master.split("@")[1]}}" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<div class="form-group">
|
||||
<label class="control-label">CPU</label>
|
||||
<div ><input type="number" class="form-control" name="cpuSetting" id="cpuSetting" value = {{defaultsetting['cpu']}} /> {{usage['cpu']}}CORE/{{quota['cpu']}}CORE
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">MEMORY</label>
|
||||
<div ><input type="number" class="form-control" name="memorySetting" id="memorySetting" value = {{defaultsetting['memory']}} /> {{usage['memory']}}MB/{{quota['memory']}}MB
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">DISK</label>
|
||||
<div><input type="number" class="form-control" name="diskSetting" id="diskSetting" value= {{defaultsetting['disk']}} /> {{usage['disk']}} MB/{{quota['disk']}}MB
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-white" data-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-success">Add</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Node ID</th>
|
||||
<th>Node Name</th>
|
||||
<th>IP Address</th>
|
||||
<th>Status</th>
|
||||
<th>Image</th>
|
||||
<th>Save</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for container in clusterinfo['containers'] %}
|
||||
<tr>
|
||||
<td>{{ loop.index }}</td>
|
||||
<td>{{ container['containername'] }}</td>
|
||||
<td>{{ container['ip'] }}</td>
|
||||
|
||||
{% if clusterinfo['status'] == 'stopped' %}
|
||||
<td><div class="text-warning"><i class="fa fa-stop"></i> Stopped</div></td>
|
||||
{% else %}
|
||||
<td><div class="text-success"><i class="fa fa-play"></i> Running</div></td>
|
||||
{% endif %}
|
||||
|
||||
<td>{{ container['image'] }}</td>
|
||||
<td><button type="button" class="btn btn-success btn-xs" data-toggle="modal" data-target="#DelModal_{{ container['containername'] }}_{{master.split("@")[1]}}">Save</button></td>
|
||||
{% if container['containername'][-2:] == '-0' %}
|
||||
<td><button class="btn btn-xs btn-default">Delete</button></td>
|
||||
{% else %}
|
||||
<td><a class="btn btn-xs btn-danger" href="/workspace/scalein/{{ clustername }}/{{ container['containername'] }}/{{master.split("@")[0]}}/">Delete</a></td>
|
||||
{% endif %}
|
||||
<div class="modal inmodal" id="DelModal_{{ container['containername'] }}_{{master.split("@")[1]}}" 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-save modal-icon"></i>
|
||||
<h4 class="modal-title">Save Image</h4>
|
||||
<small class="font-bold">Save Your Environment As a Image</small>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<form action="/workspace/save/{{ clustername }}/{{ container['containername'] }}/{{master.split("@")[0]}}/" method="POST" id="saveImage">
|
||||
<label>Image Name</label>
|
||||
<input type="text" placeholder="Enter Image Name" class="form-control" name="ImageName" id="ImageName"/>
|
||||
<br/>
|
||||
<label>Description</label>
|
||||
<textarea rows="5" cols="60" name="description" id="description">please input your description</textarea>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-white" data-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-success">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="box box-info">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">SERVICE</h3>
|
||||
<h5><a href="{{ clusterinfo['proxy_url'] }}" title="click here jump to your proxy server">{{ clusterinfo['proxy_url'] }}</a></h5>
|
||||
|
||||
<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">
|
||||
<form action="/addproxy/{{ clustername }}/{{master.split("@")[0]}}/" id="addproxy" method="POST">
|
||||
{% if 'proxy_ip' in clusterinfo %}
|
||||
<p>ip:<input type="text" id="proxy_ip" name="proxy_ip" value={{ clusterinfo['proxy_ip'][:clusterinfo['proxy_ip'].index(':')] }} readonly="true"/>port:<input type="text" id="proxy_port" name="proxy_port" value={{ clusterinfo['proxy_ip'][clusterinfo['proxy_ip'].index(':')+1:] }} readonly="true"/>
|
||||
<button type="button" class="btn-xs btn-default">enable</button>
|
||||
<a href="/deleteproxy/{{ clustername }}/{{master.split("@")[0]}}"><button type="button" class="btn-xs btn-danger">disable</button></a></p>
|
||||
{% else %}
|
||||
<p>ip:<input type="text" id="proxy_ip" name="proxy_ip" value={{ clusterinfo["containers"][0]["ip"][:clusterinfo["containers"][0]["ip"].index("/")] }} />port:<input type="text" id="proxy_port" name="proxy_port" value="80"/>
|
||||
<button type="submit" class="btn-xs btn-success">enable</button>
|
||||
<button type="button" class="btn-xs btn-default">disable</button></p>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="box box-info collapsed-box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Image Info</h3>
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-plus"></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" style="display:none">
|
||||
|
||||
<table class="table table-striped table-bordered table-hover table-image" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ImageName</th>
|
||||
<th>Type</th>
|
||||
<th>Owner</th>
|
||||
<th>CreateTime</th>
|
||||
<th>Description</th>
|
||||
<th>Location</th>
|
||||
<th>Status</th>
|
||||
<th>Operation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>base</td>
|
||||
<td>public</td>
|
||||
<td>docklet</td>
|
||||
<td>2015-01-01 00:00:00</td>
|
||||
<td>A Base Image For You</td>
|
||||
<td>--</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{% for master in allimages %}
|
||||
{% for image in allimages[master]['private'] %}
|
||||
<tr>
|
||||
<td>{{image['name']}}</td>
|
||||
<td>private</td>
|
||||
<td>{{mysession['username']}}</td>
|
||||
<td>{{image['time']}}</td>
|
||||
<td><a href="/image/description/{{image['name']}}_{{mysession['username']}}_private/{{master.split("@")[0]}}/" target="_blank">{{image['description']}}</a></td>
|
||||
<td>{{master.split("@")[1]}}</td>
|
||||
{% if image['isshared'] == 'false' %}
|
||||
<td>unshared</td>
|
||||
<td>
|
||||
<a href="/image/share/{{ image['name'] }}/{{master.split("@")[0]}}/"><button type="button" class="btn btn-xs btn-success">share</button></a>
|
||||
<a href="/image/delete/{{ image['name'] }}/{{master.split("@")[0]}}/"><button type="button" class="btn btn-xs btn-danger">delete</button></a>
|
||||
</td>
|
||||
{% else %}
|
||||
<td>shared</td>
|
||||
<td>
|
||||
<a href="/image/unshare/{{ image['name'] }}/{{master.split("@")[0]}}/"><button type="button" class="btn btn-xs btn-warning">unshare</button></a>
|
||||
<a href="/image/delete/{{ image['name'] }}/{{master.split("@")[0]}}/"><button type="button" class="btn btn-xs btn-danger">delete</button></a>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% for p_user,p_images in allimages[master]['public'].items() %}
|
||||
{% for image in p_images %}
|
||||
<tr>
|
||||
<td>{{image['name']}}</td>
|
||||
<td>public</td>
|
||||
<td>{{p_user}}</td>
|
||||
<td>{{image['time']}}</td>
|
||||
<td><a href="/image/description/{{image['name']}}_{{p_user}}_public/{{master.split("@")[0]}}/" target="_blank">{{image['description']}}</a></td>
|
||||
<td>{{master.split("@")[1]}}</td>
|
||||
<td></td>
|
||||
{% if p_user == mysession['username'] %}
|
||||
<td><a href="/image/unshare/{{ image['name'] }}/{{master.split("@")[0]}}/"><button type="button" class="btn btn-xs btn-warning">unshare</button></a></td>
|
||||
{% else %}
|
||||
<td></td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block script_src %}
|
||||
|
||||
<script src="http://cdn.bootcss.com/datatables/1.10.11/js/jquery.dataTables.js"></script>
|
||||
<script src="http://cdn.bootcss.com/datatables/1.10.11/js/dataTables.bootstrap.js"></script>
|
||||
<script src="http://cdn.bootcss.com/datatables-tabletools/2.1.5/js/TableTools.min.js"></script>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$(".table-image").DataTable();
|
||||
$(".table-image").attr("style","");
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
{% extends "base_AdminLTE.html"%}
|
||||
|
||||
<!--
|
||||
Config Page :
|
||||
1. images
|
||||
2. workspace templates
|
||||
|
||||
-->
|
||||
|
||||
{% block title %}Docklet | Config{% endblock %}
|
||||
|
||||
{% block panel_title %}Config{% endblock %}
|
||||
|
||||
{% block panel_list %}
|
||||
<ol class="breadcrumb">
|
||||
<li>
|
||||
<a href="/dashboard/"><i class="fa fa-dashboard"></i>Home</a>
|
||||
</li>
|
||||
<li class="active">
|
||||
<strong>Config</strong>
|
||||
</li>
|
||||
</ol>
|
||||
{% endblock %}
|
||||
|
||||
{% block css_src %}
|
||||
<link href="//cdn.bootcss.com/datatables/1.10.11/css/dataTables.bootstrap.min.css" rel="stylesheet">
|
||||
<link href="//cdn.bootcss.com/datatables/1.10.11/css/jquery.dataTables_themeroller.css" rel="stylesheet">
|
||||
<link href="/static/dist/css/modalconfig.css" rel="stylesheet">
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
{% for master in allclusters %}
|
||||
{% for clustername, clusterinfo in allclusters[master].items() %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="box box-info collapsed-box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">WorkSpace Name: {{ clustername }} <strong>@ {{master.split("@")[1]}}</strong></h3>
|
||||
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-plus"></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" style="display:none">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="box box-info">
|
||||
<div class="box-header with-border">
|
||||
<h4 class="box-title">VCLUSTER</h4>
|
||||
<h5>create_time:{{clusterinfo['create_time']}}      start_time:{{clusterinfo['start_time']}}</h5>
|
||||
|
||||
<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" data-toggle="modal" data-target="#Scaleout_{{ clustername }}_{{master.split("@")[1]}}"><i class="fa fa-plus"></i>Add Node</button>
|
||||
</p>
|
||||
<div class="modal inmodal" id="Scaleout_{{ clustername }}_{{master.split("@")[1]}}" 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-plus modal-icon"></i>
|
||||
<h4 class="modal-title">Choose Image</h4>
|
||||
<small class="font-bold">Choose an image to add node</small>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<form action="/workspace/scaleout/{{ clustername }}/{{master.split("@")[0]}}/" method="POST" >
|
||||
<table class="table table-striped table-bordered table-hover table-image">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ImageName</th>
|
||||
<th>Type</th>
|
||||
<th>Owner</th>
|
||||
<th>Choose</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>base</td>
|
||||
<td>public</td>
|
||||
<td>docklet</td>
|
||||
<td><input type="radio" name="image" value="base_base_base" checked="checked"></td>
|
||||
</tr>
|
||||
{% for image in allimages[master]['private'] %}
|
||||
<tr>
|
||||
<td>{{image['name']}}</td>
|
||||
<td>private</td>
|
||||
<td>{{mysession['username']}}</td>
|
||||
<td><input type="radio" name="image" value="{{image['name']}}_{{mysession['username']}}_private"></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% for p_user, p_images in allimages[master]['public'].items() %}
|
||||
{% for image in p_images %}
|
||||
<tr>
|
||||
<td>{{image['name']}}</td>
|
||||
<td>public</td>
|
||||
<td>{{p_user}}</td>
|
||||
<td><input type="radio" name="image" value="{{image['name']}}_{{p_user}}_public"></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="panel-group" id="accordion_{{clustername}}_{{master.split("@")[1]}}">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
<a data-toggle="collapse" data-panel="#accordion_{{clustername}}_{{master.split("@")[1]}}" href="#collapseOne_{{clustername}}_{{master.split("@")[1]}}">
|
||||
show advanced options
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="collapseOne_{{clustername}}_{{master.split("@")[1]}}" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<div class="form-group">
|
||||
<label class="control-label">CPU</label>
|
||||
<div ><input type="number" class="form-control" name="cpuSetting" id="cpuSetting" value = {{defaultsetting['cpu']}} /> {{usage['cpu']}}CORE/{{quota['cpu']}}CORE
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">MEMORY</label>
|
||||
<div ><input type="number" class="form-control" name="memorySetting" id="memorySetting" value = {{defaultsetting['memory']}} /> {{usage['memory']}}MB/{{quota['memory']}}MB
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">DISK</label>
|
||||
<div><input type="number" class="form-control" name="diskSetting" id="diskSetting" value= {{defaultsetting['disk']}} /> {{usage['disk']}} MB/{{quota['disk']}}MB
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-white" data-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-success">Add</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Node ID</th>
|
||||
<th>Node Name</th>
|
||||
<th>IP Address</th>
|
||||
<th>Status</th>
|
||||
<th>Image</th>
|
||||
<th>Save</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for container in clusterinfo['containers'] %}
|
||||
<tr>
|
||||
<td>{{ loop.index }}</td>
|
||||
<td>{{ container['containername'] }}</td>
|
||||
<td>{{ container['ip'] }}</td>
|
||||
|
||||
{% if clusterinfo['status'] == 'stopped' %}
|
||||
<td><div class="text-warning"><i class="fa fa-stop"></i> Stopped</div></td>
|
||||
{% else %}
|
||||
<td><div class="text-success"><i class="fa fa-play"></i> Running</div></td>
|
||||
{% endif %}
|
||||
|
||||
<td>{{ container['image'] }}</td>
|
||||
<td><button type="button" class="btn btn-success btn-xs" data-toggle="modal" data-target="#DelModal_{{ container['containername'] }}_{{master.split("@")[1]}}">Save</button></td>
|
||||
{% if container['containername'][-2:] == '-0' %}
|
||||
<td><button class="btn btn-xs btn-default">Delete</button></td>
|
||||
{% else %}
|
||||
<td><a class="btn btn-xs btn-danger" href="/workspace/scalein/{{ clustername }}/{{ container['containername'] }}/{{master.split("@")[0]}}/">Delete</a></td>
|
||||
{% endif %}
|
||||
<div class="modal inmodal" id="DelModal_{{ container['containername'] }}_{{master.split("@")[1]}}" 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-save modal-icon"></i>
|
||||
<h4 class="modal-title">Save Image</h4>
|
||||
<small class="font-bold">Save Your Environment As a Image</small>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<form action="/workspace/save/{{ clustername }}/{{ container['containername'] }}/{{master.split("@")[0]}}/" method="POST" id="saveImage">
|
||||
<label>Image Name</label>
|
||||
<input type="text" placeholder="Enter Image Name" class="form-control" name="ImageName" id="ImageName"/>
|
||||
<br/>
|
||||
<label>Description</label>
|
||||
<textarea rows="5" cols="60" name="description" id="description">please input your description</textarea>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-white" data-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-success">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="box box-info">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">SERVICE</h3>
|
||||
<h5><a href="{{ clusterinfo['proxy_url'] }}" title="click here jump to your proxy server">{{ clusterinfo['proxy_url'] }}</a></h5>
|
||||
|
||||
<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">
|
||||
<form action="/addproxy/{{ clustername }}/{{master.split("@")[0]}}/" id="addproxy" method="POST">
|
||||
{% if 'proxy_ip' in clusterinfo %}
|
||||
<p>ip:<input type="text" id="proxy_ip" name="proxy_ip" value={{ clusterinfo['proxy_ip'][:clusterinfo['proxy_ip'].index(':')] }} readonly="true"/>port:<input type="text" id="proxy_port" name="proxy_port" value={{ clusterinfo['proxy_ip'][clusterinfo['proxy_ip'].index(':')+1:] }} readonly="true"/>
|
||||
<button type="button" class="btn-xs btn-default">enable</button>
|
||||
<a href="/deleteproxy/{{ clustername }}/{{master.split("@")[0]}}"><button type="button" class="btn-xs btn-danger">disable</button></a></p>
|
||||
{% else %}
|
||||
<p>ip:<input type="text" id="proxy_ip" name="proxy_ip" value={{ clusterinfo["containers"][0]["ip"][:clusterinfo["containers"][0]["ip"].index("/")] }} />port:<input type="text" id="proxy_port" name="proxy_port" value="80"/>
|
||||
<button type="submit" class="btn-xs btn-success">enable</button>
|
||||
<button type="button" class="btn-xs btn-default">disable</button></p>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="box box-info collapsed-box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Image Info</h3>
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-plus"></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" style="display:none">
|
||||
|
||||
<table class="table table-striped table-bordered table-hover table-image" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ImageName</th>
|
||||
<th>Type</th>
|
||||
<th>Owner</th>
|
||||
<th>CreateTime</th>
|
||||
<th>Description</th>
|
||||
<th>Location</th>
|
||||
<th>Status</th>
|
||||
<th>Operation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>base</td>
|
||||
<td>public</td>
|
||||
<td>docklet</td>
|
||||
<td>2015-01-01 00:00:00</td>
|
||||
<td>A Base Image For You</td>
|
||||
<td>--</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{% for master in allimages %}
|
||||
{% for image in allimages[master]['private'] %}
|
||||
<tr>
|
||||
<td>{{image['name']}}</td>
|
||||
<td>private</td>
|
||||
<td>{{mysession['username']}}</td>
|
||||
<td>{{image['time']}}</td>
|
||||
<td><a href="/image/description/{{image['name']}}_{{mysession['username']}}_private/{{master.split("@")[0]}}/" target="_blank">{{image['description']}}</a></td>
|
||||
<td>{{master.split("@")[1]}}</td>
|
||||
{% if image['isshared'] == 'false' %}
|
||||
<td>unshared</td>
|
||||
<td>
|
||||
<a href="/image/share/{{ image['name'] }}/{{master.split("@")[0]}}/"><button type="button" class="btn btn-xs btn-success">share</button></a>
|
||||
<a href="/image/delete/{{ image['name'] }}/{{master.split("@")[0]}}/"><button type="button" class="btn btn-xs btn-danger">delete</button></a>
|
||||
</td>
|
||||
{% else %}
|
||||
<td>shared</td>
|
||||
<td>
|
||||
<a href="/image/unshare/{{ image['name'] }}/{{master.split("@")[0]}}/"><button type="button" class="btn btn-xs btn-warning">unshare</button></a>
|
||||
<a href="/image/delete/{{ image['name'] }}/{{master.split("@")[0]}}/"><button type="button" class="btn btn-xs btn-danger">delete</button></a>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% for p_user,p_images in allimages[master]['public'].items() %}
|
||||
{% for image in p_images %}
|
||||
<tr>
|
||||
<td>{{image['name']}}</td>
|
||||
<td>public</td>
|
||||
<td>{{p_user}}</td>
|
||||
<td>{{image['time']}}</td>
|
||||
<td><a href="/image/description/{{image['name']}}_{{p_user}}_public/{{master.split("@")[0]}}/" target="_blank">{{image['description']}}</a></td>
|
||||
<td>{{master.split("@")[1]}}</td>
|
||||
<td></td>
|
||||
{% if p_user == mysession['username'] %}
|
||||
<td><a href="/image/unshare/{{ image['name'] }}/{{master.split("@")[0]}}/"><button type="button" class="btn btn-xs btn-warning">unshare</button></a></td>
|
||||
{% else %}
|
||||
<td></td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block script_src %}
|
||||
|
||||
<script src="http://cdn.bootcss.com/datatables/1.10.11/js/jquery.dataTables.js"></script>
|
||||
<script src="http://cdn.bootcss.com/datatables/1.10.11/js/dataTables.bootstrap.js"></script>
|
||||
<script src="http://cdn.bootcss.com/datatables-tabletools/2.1.5/js/TableTools.min.js"></script>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$(".table-image").DataTable();
|
||||
$(".table-image").attr("style","");
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
{% extends "base_AdminLTE.html"%}
|
||||
{% block title %}Docklet | Settings{% endblock %}
|
||||
|
||||
{% block panel_title %}Settings{% endblock %}
|
||||
|
||||
{% block panel_list %}
|
||||
<ol class="breadcrumb">
|
||||
<li>
|
||||
<a href="/dashboard/"><i class="fa fa-dashboard"></i>Home</a>
|
||||
</li>
|
||||
<li class="active">
|
||||
<strong>Settings</strong>
|
||||
</li>
|
||||
</ol>
|
||||
{% endblock %}
|
||||
|
||||
{% block css_src %}
|
||||
|
||||
<link href="/static/dist/css/filebox.css" rel="stylesheet">
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Modify Settings</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<form role="form" action="/settings/" method="POST" >
|
||||
<div class="box-body">
|
||||
<div class="form-group">
|
||||
<label for="ADMIN_EMAIL_ADDRESS">Admin Email Address</label>
|
||||
<p class="help-block">when an activating request is sent, an e-mail will be sent to this address to remind the admin. </p>
|
||||
<p class="help-block">if this address is "", no email will be sent to admin.</p>
|
||||
<input type="email" class="form-control" id="ADMIN_EMAIL_ADDRESS" value="{{ settings['ADMIN_EMAIL_ADDRESS'] }}" name="ADMIN_EMAIL_ADDRESS">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="EMAIL_FROM_ADDRESS">Email From Address</label>
|
||||
<p class="help-block">the e-mail address to send activating e-mail to user</p>
|
||||
<p class="help-block">if this address is "", no email will be sent out.</p>
|
||||
<input type="input" class="form-control" id="EMAIL_FROM_ADDRESS" name="EMAIL_FROM_ADDRESS" value="{{ settings['EMAIL_FROM_ADDRESS'] }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Logs</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
{% for filename in logs %}
|
||||
<div class="file-box">
|
||||
<div class="file">
|
||||
<a href="/logs/{{ filename }}/">
|
||||
<span class="corner"></span>
|
||||
|
||||
<div class="icon">
|
||||
<i class="fa fa-file"></i>
|
||||
</div>
|
||||
<div class="file-name">
|
||||
{{ filename }}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
21
web/web.py
21
web/web.py
|
@ -27,6 +27,7 @@ from webViews.notification.notification import CreateNotificationView, Notificat
|
|||
QueryNotificationView, ModifyNotificationView, DeleteNotificationView
|
||||
from webViews.user.userinfo import userinfoView
|
||||
from webViews.user.userActivate import userActivateView
|
||||
from webViews.settings import settingsView
|
||||
from webViews.user.grouplist import grouplistView, groupqueryView, groupdetailView, groupmodifyView
|
||||
from functools import wraps
|
||||
from webViews.dockletrequest import dockletRequest
|
||||
|
@ -42,7 +43,7 @@ import webViews.dockletrequest
|
|||
from webViews import cookie_tool
|
||||
import traceback
|
||||
|
||||
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
|
||||
|
||||
|
@ -358,6 +359,22 @@ def monitorUserAll():
|
|||
return monitorUserAllView.as_view()
|
||||
'''
|
||||
|
||||
@app.route("/settings/", methods=['GET', 'POST'])
|
||||
@administration_required
|
||||
def settings():
|
||||
return settingsView.as_view()
|
||||
|
||||
@app.route("/logs/<filename>/", methods=['GET'])
|
||||
@administration_required
|
||||
def logs_get(filename):
|
||||
data = {
|
||||
"filename": filename
|
||||
}
|
||||
result = dockletRequest.post('/logs/get/', data).get('result', '')
|
||||
response = make_response(result)
|
||||
response.headers["content-type"] = "text/plain"
|
||||
return response
|
||||
|
||||
@app.route("/user/list/", methods=['GET', 'POST'])
|
||||
@administration_required
|
||||
def userlist():
|
||||
|
@ -645,4 +662,4 @@ if __name__ == '__main__':
|
|||
elif opt in ("-p", "--port"):
|
||||
webport = int(arg)
|
||||
|
||||
app.run(host = webip, port = webport, threaded=True)
|
||||
app.run(host = webip, port = webport, debug = False, threaded=True)
|
||||
|
|
|
@ -147,7 +147,7 @@ class startClusterView(normalView):
|
|||
error_path = "error.html"
|
||||
|
||||
@classmethod
|
||||
def get(self):
|
||||
def get(self):
|
||||
masterip = self.masterip
|
||||
data = {
|
||||
"clustername": self.clustername
|
||||
|
@ -215,7 +215,7 @@ class detailClusterView(normalView):
|
|||
template_path = "listcontainer.html"
|
||||
|
||||
@classmethod
|
||||
def get(self):
|
||||
def get(self):
|
||||
masterip = self.masterip
|
||||
data = {
|
||||
"clustername": self.clustername
|
||||
|
|
|
@ -3,6 +3,7 @@ from flask import abort, session
|
|||
from webViews.log import logger
|
||||
import os,sys,inspect
|
||||
|
||||
|
||||
this_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile(inspect.currentframe ()))[0]))
|
||||
src_folder = os.path.realpath(os.path.abspath(os.path.join(this_folder,"../..", "src")))
|
||||
if src_folder not in sys.path:
|
||||
|
@ -14,6 +15,12 @@ masterips=env.getenv('MASTER_IPS').split(",")
|
|||
user_endpoint = "http://" + env.getenv('USER_IP') + ":" + str(env.getenv('USER_PORT'))
|
||||
master_port=str(env.getenv('MASTER_PORT'))
|
||||
|
||||
def getip(masterip):
|
||||
return masterip.split("@")[0]
|
||||
|
||||
def getname(masterip):
|
||||
return masterip.split("@")[1]
|
||||
|
||||
def getip(masterip):
|
||||
return masterip.split("@")[0]
|
||||
|
||||
|
@ -51,11 +58,14 @@ class dockletRequest():
|
|||
if (result.get('Unauthorized', None) == 'True'):
|
||||
session['401'] = 'Token Expired'
|
||||
abort(401)
|
||||
logger.info ("Docklet Response: user = %s result = %s, url = %s"%(session['username'], result, url))
|
||||
logstr = "Docklet Response: user = %s result = %s, url = %s" % (session['username'], result, url)
|
||||
if (sys.getsizeof(logstr) > 512):
|
||||
logstr = "Docklet Response: user = %s, url = %s"%(session['username'], url)
|
||||
logger.info(logstr)
|
||||
return result
|
||||
#except:
|
||||
#abort(500)
|
||||
|
||||
|
||||
@classmethod
|
||||
def post_to_all(self, url = '/', data={}):
|
||||
if (url == '/'):
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
from flask import session,render_template,redirect, request
|
||||
from webViews.view import normalView
|
||||
from webViews.dockletrequest import dockletRequest
|
||||
|
||||
class settingsView(normalView):
|
||||
template_path = "settings.html"
|
||||
|
||||
@classmethod
|
||||
def get(self):
|
||||
settings = dockletRequest.post('/settings/list/')['result']
|
||||
logs = dockletRequest.post('/logs/list/')['result']
|
||||
logs.sort()
|
||||
logs.sort(key = len)
|
||||
return self.render(self.template_path, settings = settings, logs = logs)
|
||||
|
||||
@classmethod
|
||||
def post(self):
|
||||
result = dockletRequest.post('/settings/update/', request.form)
|
||||
return redirect('/settings/')
|
Loading…
Reference in New Issue