Merge pull request #46 from zhongyehong/quotaadd

Quotaadd
This commit is contained in:
zhong yehong 2016-04-12 18:15:13 +08:00
commit ce0d18a8df
15 changed files with 240 additions and 188 deletions

View File

@ -75,6 +75,8 @@ pre_start_master () {
[ ! -d $FS_PREFIX/global ] && mkdir -p $FS_PREFIX/global [ ! -d $FS_PREFIX/global ] && mkdir -p $FS_PREFIX/global
[ ! -d $FS_PREFIX/local ] && mkdir -p $FS_PREFIX/local [ ! -d $FS_PREFIX/local ] && mkdir -p $FS_PREFIX/local
[ ! -d $FS_PREFIX/global/users ] && mkdir -p $FS_PREFIX/global/users [ ! -d $FS_PREFIX/global/users ] && mkdir -p $FS_PREFIX/global/users
[ ! -d $FS_PREFIX/global/sys ] && mkdir -p $FS_PREFIX/global/sys
[ ! -d $FS_PREFIX/global/images ] && mkdir -p $FS_PREFIX/global/images
[ ! -d $FS_PREFIX/local/volume ] && mkdir -p $FS_PREFIX/local/volume [ ! -d $FS_PREFIX/local/volume ] && mkdir -p $FS_PREFIX/local/volume
[ ! -d $FS_PREFIX/local/temp ] && mkdir -p $FS_PREFIX/local/temp [ ! -d $FS_PREFIX/local/temp ] && mkdir -p $FS_PREFIX/local/temp
[ ! -d $FS_PREFIX/local/run ] && mkdir -p $FS_PREFIX/local/run [ ! -d $FS_PREFIX/local/run ] && mkdir -p $FS_PREFIX/local/run

View File

@ -27,8 +27,9 @@ class Container(object):
user_info = json.loads(user_info) user_info = json.loads(user_info)
cpu = user_info["data"]["groupinfo"]["cpu"] cpu = user_info["data"]["groupinfo"]["cpu"]
memory = user_info["data"]["groupinfo"]["memory"] memory = user_info["data"]["groupinfo"]["memory"]
disk = user_info["data"]["groupinfo"]["disk"]
image = json.loads(image) image = json.loads(image)
status = self.imgmgr.prepareFS(username,image,lxc_name) status = self.imgmgr.prepareFS(username,image,lxc_name,disk)
if not status: if not status:
return [False, "Create container failed when preparing filesystem, possibly insufficient space"] return [False, "Create container failed when preparing filesystem, possibly insufficient space"]
@ -327,8 +328,8 @@ IP=%s
onlyglobal.append(container) onlyglobal.append(container)
return [both, onlylocal, onlyglobal] return [both, onlylocal, onlyglobal]
def create_image(self,username,imagename,containername,description="not thing",isforce = False): def create_image(self,username,imagename,containername,description="not thing",imagenum=10):
return self.imgmgr.createImage(username,imagename,containername,description,isforce) return self.imgmgr.createImage(username,imagename,containername,description,imagenum)
def flush_container(self,username,imagename,containername): def flush_container(self,username,imagename,containername):
self.imgmgr.flush_one(username,imagename,containername) self.imgmgr.flush_one(username,imagename,containername)

View File

@ -234,17 +234,19 @@ class DockletHttpHandler(http.server.BaseHTTPRequestHandler):
description = form.getvalue("description") description = form.getvalue("description")
containername = form.getvalue("containername") containername = form.getvalue("containername")
isforce = form.getvalue("isforce") isforce = form.getvalue("isforce")
if isforce == "true": if not isforce == "true":
isforce = True [status,message] = G_vclustermgr.image_check(user,imagename)
else: if not status:
isforce = False self.response(200, {'success':'false','reason':'exists', 'message':message})
[status,message] = G_vclustermgr.create_image(user,clustername,containername,imagename,description,isforce) return [False, "image already exists"]
user_info = G_usermgr.selfQuery(cur_user = cur_user)
[status,message] = G_vclustermgr.create_image(user,clustername,containername,imagename,description,user_info["data"]["groupinfo"]["image"])
if status: if status:
logger.info("image has been saved") logger.info("image has been saved")
self.response(200, {'success':'true', 'action':'save'}) self.response(200, {'success':'true', 'action':'save'})
else: else:
logger.debug(message) logger.debug(message)
self.response(400, {'success':'false', 'message':message}) self.response(200, {'success':'false', 'reason':'exceed', 'message':message})
else: else:
logger.warning ("request not supported ") logger.warning ("request not supported ")
@ -423,6 +425,9 @@ class DockletHttpHandler(http.server.BaseHTTPRequestHandler):
elif cmds[1] == 'groupadd': elif cmds[1] == 'groupadd':
result = G_usermgr.groupadd(form = form, cur_user = cur_user) result = G_usermgr.groupadd(form = form, cur_user = cur_user)
self.response(200, result) self.response(200, result)
elif cmds[1] == 'quotaadd':
result = G_usermgr.quotaadd(form = form, cur_user = cur_user)
self.response(200, result)
elif cmds[1] == 'groupdel': elif cmds[1] == 'groupdel':
result = G_usermgr.groupdel(name = form.getvalue('name', None), cur_user = cur_user) result = G_usermgr.groupdel(name = form.getvalue('name', None), cur_user = cur_user)
self.response(200, result) self.response(200, result)

View File

@ -58,14 +58,18 @@ class ImageMgr():
return self.dealpath(fspath[:-1]) return self.dealpath(fspath[:-1])
else: else:
return fspath return fspath
def createImage(self,user,image,lxc,description="Not thing",isforce = False): def createImage(self,user,image,lxc,description="Not thing", imagenum=10):
fspath = self.NFS_PREFIX + "/local/volume/" + lxc fspath = self.NFS_PREFIX + "/local/volume/" + lxc
imgpath = self.imgpath + "private/" + user + "/" imgpath = self.imgpath + "private/" + user + "/"
if isforce is False:
logger.info("this save operation is not force") if not os.path.exists(imgpath+image):
if os.path.exists(imgpath+image): cur_imagenum = 0
return [False,"target image is exists"] for filename in os.listdir(imgpath):
if os.path.isdir(imgpath+filename):
cur_imagenum += 1
if cur_imagenum >= int(imagenum):
return [False,"image number limit exceeded"]
try: try:
sys_run("mkdir -p %s" % imgpath+image,True) sys_run("mkdir -p %s" % imgpath+image,True)
sys_run("rsync -a --delete --exclude=lost+found/ --exclude=root/nfs/ --exclude=dev/ --exclude=mnt/ --exclude=tmp/ --exclude=media/ --exclude=proc/ --exclude=sys/ %s/ %s/" % (self.dealpath(fspath),imgpath+image),True) sys_run("rsync -a --delete --exclude=lost+found/ --exclude=root/nfs/ --exclude=dev/ --exclude=mnt/ --exclude=tmp/ --exclude=media/ --exclude=proc/ --exclude=sys/ %s/ %s/" % (self.dealpath(fspath),imgpath+image),True)

View File

@ -40,7 +40,7 @@ import env
fsdir = env.getenv('FS_PREFIX') fsdir = env.getenv('FS_PREFIX')
app = Flask(__name__) app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///'+fsdir+'/local/UserTable.db' app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///'+fsdir+'/global/sys/UserTable.db'
try: try:
secret_key_file = open(env.getenv('FS_PREFIX') + '/local/token_secret_key.txt') secret_key_file = open(env.getenv('FS_PREFIX') + '/local/token_secret_key.txt')
app.secret_key = secret_key_file.read() app.secret_key = secret_key_file.read()

View File

@ -20,6 +20,7 @@ from email.mime.multipart import MIMEMultipart
from email.header import Header from email.header import Header
from datetime import datetime from datetime import datetime
import json import json
from log import logger
email_from_address = env.getenv('EMAIL_FROM_ADDRESS') email_from_address = env.getenv('EMAIL_FROM_ADDRESS')
admin_email_address = env.getenv('ADMIN_EMAIL_ADDRESS') admin_email_address = env.getenv('ADMIN_EMAIL_ADDRESS')
@ -145,12 +146,13 @@ class userManager:
path = env.getenv('DOCKLET_LIB') path = env.getenv('DOCKLET_LIB')
subprocess.call([path+"/userinit.sh", username]) subprocess.call([path+"/userinit.sh", username])
db.session.commit() db.session.commit()
if not os.path.exists(fspath+"/global/group"): if not os.path.exists(fspath+"/global/sys/quota"):
groupfile = open(fspath+"/global/group",'w') groupfile = open(fspath+"/global/sys/quota",'w')
groups = [] groups = []
groups.append({'name':'root', 'cpu':'100000', 'memory':'2000', 'imageQuantity':'10', 'lifeCycle':'24'}) groups.append({'name':'root', 'quotas':{ 'cpu':'100000', 'disk':'2000', 'memory':'2000', 'image':'10', 'idletime':'24', 'network':'8' }})
groups.append({'name':'admin', 'cpu':'100000', 'memory':'2000', 'imageQuantity':'10', 'lifeCycle':'24'}) groups.append({'name':'admin', 'quotas':{'cpu':'100000', 'disk':'2000', 'memory':'2000', 'image':'10', 'idletime':'24', 'network':'8'}})
groups.append({'name':'primary', 'cpu':'100000', 'memory':'2000', 'imageQuantity':'10', 'lifeCycle':'24'}) groups.append({'name':'primary', 'quotas':{'cpu':'100000', 'disk':'2000', 'memory':'2000', 'image':'10', 'idletime':'24', 'network':'8'}})
groups.append({'name':'fundation', 'quotas':{'cpu':'100000', 'disk':'2000', 'memory':'2000', 'image':'10', 'idletime':'24', 'network':'8'}})
groupfile.write(json.dumps(groups)) groupfile.write(json.dumps(groups))
groupfile.close() groupfile.close()
@ -356,18 +358,18 @@ class userManager:
List informantion for oneself List informantion for oneself
''' '''
user = kwargs['cur_user'] user = kwargs['cur_user']
groupfile = open(fspath+"/global/group",'r') groupfile = open(fspath+"/global/sys/quota",'r')
groups = json.loads(groupfile.read()) groups = json.loads(groupfile.read())
groupfile.close() groupfile.close()
group = None group = None
for one_group in groups: for one_group in groups:
if one_group['name'] == user.user_group: if one_group['name'] == user.user_group:
group = one_group group = one_group['quotas']
break break
else: else:
for one_group in groups: for one_group in groups:
if one_group['name'] == "primary": if one_group['name'] == "primary":
group = one_group group = one_group['quotas']
break break
result = { result = {
"success": 'true', "success": 'true',
@ -385,12 +387,7 @@ class userManager:
"tel" : user.tel, "tel" : user.tel,
"register_date" : "%s"%(user.register_date), "register_date" : "%s"%(user.register_date),
"group" : user.user_group, "group" : user.user_group,
"groupinfo": { "groupinfo": group,
"cpu": group['cpu'],
"memory": group['memory'],
"imageQuantity": group['imageQuantity'],
"lifeCycle":group['lifeCycle'],
},
}, },
} }
return result return result
@ -458,24 +455,14 @@ class userManager:
Usage: list(cur_user = token_from_auth) Usage: list(cur_user = token_from_auth)
List all groups for an administrator List all groups for an administrator
''' '''
groupfile = open(fspath+"/global/group",'r') groupfile = open(fspath+"/global/sys/quota",'r')
groups = json.loads(groupfile.read()) groups = json.loads(groupfile.read())
groupfile.close() groupfile.close()
result = { result = {
"success": 'true', "success": 'true',
"data":[] "groups": groups,
"quotas": list(groups[0]['quotas'].keys()),
} }
for group in groups:
groupinfo = [
group['name'],
group['cpu'],
group['memory'],
group['imageQuantity'],
group['lifeCycle'],
'',
]
result["data"].append(groupinfo)
return result return result
@administration_required @administration_required
@ -484,20 +471,14 @@ class userManager:
Usage: groupQuery(name = XXX, cur_user = token_from_auth) Usage: groupQuery(name = XXX, cur_user = token_from_auth)
List a group for an administrator List a group for an administrator
''' '''
groupfile = open(fspath+"/global/group",'r') groupfile = open(fspath+"/global/sys/quota",'r')
groups = json.loads(groupfile.read()) groups = json.loads(groupfile.read())
groupfile.close() groupfile.close()
for group in groups: for group in groups:
if group['name'] == kwargs['name']: if group['name'] == kwargs['name']:
result = { result = {
"success":'true', "success":'true',
"data":{ "data": group,
"name" : group['name'] ,
"cpu" : group['cpu'] ,
"memory" : group['memory'],
"imageQuantity" : group['imageQuantity'],
"lifeCycle" : group['lifeCycle'],
}
} }
return result return result
else: else:
@ -509,7 +490,7 @@ class userManager:
Usage: grouplist(cur_user = token_from_auth) Usage: grouplist(cur_user = token_from_auth)
List all group names for an administrator List all group names for an administrator
''' '''
groupfile = open(fspath+"/global/group",'r') groupfile = open(fspath+"/global/sys/quota",'r')
groups = json.loads(groupfile.read()) groups = json.loads(groupfile.read())
groupfile.close() groupfile.close()
result = { result = {
@ -524,17 +505,18 @@ class userManager:
''' '''
Usage: groupModify(newValue = dict_from_form, cur_user = token_from_auth) Usage: groupModify(newValue = dict_from_form, cur_user = token_from_auth)
''' '''
groupfile = open(fspath+"/global/group",'r') groupfile = open(fspath+"/global/sys/quota",'r')
groups = json.loads(groupfile.read()) groups = json.loads(groupfile.read())
groupfile.close() groupfile.close()
for group in groups: for group in groups:
if group['name'] == kwargs['newValue'].getvalue('groupname',None): if group['name'] == kwargs['newValue'].getvalue('groupname',None):
form = kwargs['newValue'] form = kwargs['newValue']
group['cpu'] = form.getvalue('cpu', '') for key in form.keys():
group['memory'] = form.getvalue('memory', '') if key == "groupname" or key == "token":
group['imageQuantity'] = form.getvalue('image', '') pass
group['lifeCycle'] = form.getvalue('lifecycle', '') else:
groupfile = open(fspath+"/global/group",'w') group['quotas'][key] = form.getvalue(key)
groupfile = open(fspath+"/global/sys/quota",'w')
groupfile.write(json.dumps(groups)) groupfile.write(json.dumps(groups))
groupfile.close() groupfile.close()
return {"success":'true'} return {"success":'true'}
@ -622,15 +604,44 @@ class userManager:
return {"success":'true'} return {"success":'true'}
@administration_required @administration_required
def groupadd(*args, **kwargs): def quotaadd(*args, **kwargs):
form = kwargs.get('form') form = kwargs.get('form')
if (form.getvalue("name") == None): quotaname = form.getvalue("quotaname")
return {"success":'false', "reason": "Empty group name"} default_value = form.getvalue("default_value")
groupfile = open(fspath+"/global/group",'r') if (quotaname == None):
return { "success":'false', "reason": "Empty quota name"}
if (default_value == None):
default_value = "--"
groupfile = open(fspath+"/global/sys/quota",'r')
groups = json.loads(groupfile.read()) groups = json.loads(groupfile.read())
groupfile.close() groupfile.close()
groups.append({'name':form.getvalue("name"), 'cpu':form.getvalue("cpu"), 'memory':form.getvalue("memory"), 'imageQuantity':form.getvalue("image"), 'lifeCycle':form.getvalue("lifecycle")}) for group in groups:
groupfile = open(fspath+"/global/group",'w') group['quotas'][quotaname] = default_value
groupfile = open(fspath+"/global/sys/quota",'w')
groupfile.write(json.dumps(groups))
groupfile.close()
return {"success":'true'}
@administration_required
def groupadd(*args, **kwargs):
form = kwargs.get('form')
groupname = form.getvalue("groupname")
if (groupname == None):
return {"success":'false', "reason": "Empty group name"}
groupfile = open(fspath+"/global/sys/quota",'r')
groups = json.loads(groupfile.read())
groupfile.close()
group = {
'name': groupname,
'quotas': {}
}
for key in form.keys():
if key == "groupname" or key == "token":
pass
else:
group['quotas'][key] = form.getvalue(key)
groups.append(group)
groupfile = open(fspath+"/global/sys/quota",'w')
groupfile.write(json.dumps(groups)) groupfile.write(json.dumps(groups))
groupfile.close() groupfile.close()
return {"success":'true'} return {"success":'true'}
@ -640,14 +651,14 @@ class userManager:
name = kwargs.get('name', None) name = kwargs.get('name', None)
if (name == None): if (name == None):
return {"success":'false', "reason": "Empty group name"} return {"success":'false', "reason": "Empty group name"}
groupfile = open(fspath+"/global/group",'r') groupfile = open(fspath+"/global/sys/quota",'r')
groups = json.loads(groupfile.read()) groups = json.loads(groupfile.read())
groupfile.close() groupfile.close()
for group in groups: for group in groups:
if group['name'] == name: if group['name'] == name:
groups.remove(group) groups.remove(group)
break break
groupfile = open(fspath+"/global/group",'w') groupfile = open(fspath+"/global/sys/quota",'w')
groupfile.write(json.dumps(groups)) groupfile.write(json.dumps(groups))
groupfile.close() groupfile.close()
return {"success":'true'} return {"success":'true'}

View File

@ -204,7 +204,14 @@ class VclusterMgr(object):
logger.info("flush success") logger.info("flush success")
def create_image(self,username,clustername,containername,imagename,description,isforce=False): def image_check(self,username,imagename):
imagepath = self.fspath + "/global/images/private/" + username + "/"
if os.path.exists(imagepath + imagename):
return [False, "image already exists"]
else:
return [True, "image not exists"]
def create_image(self,username,clustername,containername,imagename,description,imagenum=10):
[status, info] = self.get_clusterinfo(clustername,username) [status, info] = self.get_clusterinfo(clustername,username)
if not status: if not status:
return [False, "cluster not found"] return [False, "cluster not found"]
@ -213,7 +220,7 @@ class VclusterMgr(object):
if container['containername'] == containername: if container['containername'] == containername:
logger.info("container: %s found" % containername) logger.info("container: %s found" % containername)
onework = self.nodemgr.ip_to_rpc(container['host']) onework = self.nodemgr.ip_to_rpc(container['host'])
res = onework.create_image(username,imagename,containername,description,isforce) res = onework.create_image(username,imagename,containername,description,imagenum)
container['lastsave'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") container['lastsave'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
container['image'] = imagename container['image'] = imagename
break break

View File

@ -56,7 +56,7 @@
<tbody> <tbody>
<tr> <tr>
<td>base</td> <td>base</td>
<td><div class="label label-outline-success">public</div></td> <td>public</td>
<td>docklet</td> <td>docklet</td>
<td>A base image for you</td> <td>A base image for you</td>
<td><div class="i-checks"><label><input type="radio" name="image" value="base_base_base" checked="checked"></label></div></td> <td><div class="i-checks"><label><input type="radio" name="image" value="base_base_base" checked="checked"></label></div></td>
@ -64,7 +64,7 @@
{% for image in images['private'] %} {% for image in images['private'] %}
<tr> <tr>
<td>{{image['name']}}</td> <td>{{image['name']}}</td>
<td><div class="label label-outline-warning">{{"private"}}</div></td> <td>private</td>
<td>{{user}}</td> <td>{{user}}</td>
<td><a href="/image/description/{{image['name']}}_{{user}}_private/" target="_blank">{{image['description']}}</a></td> <td><a href="/image/description/{{image['name']}}_{{user}}_private/" target="_blank">{{image['description']}}</a></td>
<td><div class="i-checks"><label><input type="radio" name="image" value="{{image['name']}}_{{user}}_private"></label></div></td> <td><div class="i-checks"><label><input type="radio" name="image" value="{{image['name']}}_{{user}}_private"></label></div></td>
@ -74,7 +74,7 @@
{% for image in p_images %} {% for image in p_images %}
<tr> <tr>
<td>{{image['name']}}</td> <td>{{image['name']}}</td>
<td><div class="label label-outline-success">{{"public"}}</div></td> <td>public</td>
<td>{{p_user}}</td> <td>{{p_user}}</td>
<td><a href="/image/description/{{image['name']}}_{{p_user}}_public" target="_blank">{{image['description']}}</a></td> <td><a href="/image/description/{{image['name']}}_{{p_user}}_public" target="_blank">{{image['description']}}</a></td>
<td><div class="i-checks"><label><input type="radio" name="image" value="{{image['name']}}_{{p_user}}_public"></label></div></td> <td><div class="i-checks"><label><input type="radio" name="image" value="{{image['name']}}_{{p_user}}_public"></label></div></td>

View File

@ -51,27 +51,16 @@
<div class="modal-body"> <div class="modal-body">
<form action="/group/add/" method="POST" id="addGroupForm"> <form action="/group/add/" method="POST" id="addGroupForm">
<div class="form-group"> <div class="form-group">
<label>Group Name</label> <label>Name</label>
<input type = "text" placeholder="Enter GroupName" class="form-control" name="name" id="mymyname"> <input type="text" placeholder="Enter Name" class="form-control" name="groupname"/>
</div> </div>
<div class="form-group"> {% for quota in quotas %}
<label>CPU Quota</label> <div class="form-group">
<input type = "text" placeholder="Enter CPU Quota" class="form-control" name="cpu" id="myCpu" value="100000"> <label>{{ quota }}</label>
</div> <input type="text" placeholder="Enter {{ quota }}" class="form-control" name={{ quota }} />
<div class="form-group"> </div>
<label>Memory Quota</label> {% endfor %}
<input type="text" placeholder="Enter Memory Quota" class="form-control" name="memory" id="myMemory" value="2000">
</div>
<div class="form-group">
<label>Image Quantity</label>
<input type = "text" placeholder="Enter Image Quantity" class="form-control" name="image" id="myImage" value="10">
</div>
<div class="form-group">
<label>Life Cycle</label>
<input type = "text" placeholder="Enter Life Cycle" class="form-control" name="lifecycle" id="myLifecycle" value="24">
</div>
</form> </form>
</div> </div>
@ -82,59 +71,93 @@
</div> </div>
</div> </div>
</div> </div>
<table id="myGroupTable" class="table table-striped table-bordered"> <button type="button" class="btn btn-primary btn-sm" data-toggle="modal" data-target="#AddQuotaModal"><i class="fa fa-plus"></i> Add Quota</button>
<thead> <div class="modal inmodal" id="AddQuotaModal" tabindex="-1" role="dialog" aria-hidden="true">
<tr>
<th>Name</th>
<th>CPU</th>
<th>Memory</th>
<th>ImageQuantity</th>
<th>LifeCycle</th>
<th>Command</th>
</tr>
</thead>
<tbody>
</tbody>
<div class="modal inmodal" id="ModifyGroupModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content animated fadeIn"> <div class="modal-content animated fadeIn">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button> <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
<i class="fa fa-laptop modal-icon"></i> <i class="fa fa-laptop modal-icon"></i>
<h4 class="modal-title">Modify Group</h4> <h4 class="modal-title">Add Quota</h4>
<small class="font-bold">Modify a group in Docklet</small> <small class="font-bold">Add a quota to Docklet</small>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form action="/group/modify/" method="POST" id="modifyGroupForm">
<div class="form-group"> <form action="/quota/add/" method="POST" id="addQuotaForm">
<label>Group Name</label> <div class="form-group">
<input type = "text" placeholder="Enter Groupname" class="form-control" name="groupname" id="mGroupname" readonly="readonly"> <label>Name</label>
</div> <input type="text" placeholder="Enter Name" class="form-control" name="quotaname"/>
<div class="form-group"> </div>
<label>CPU Quota</label> <div class="form-group">
<input type = "text" placeholder="Enter CPU Quota" class="form-control" name="cpu" id="mCpu"> <label>Default Value</label>
</div> <input type="text" placeholder="Enter Default Value" class="form-control" name="default_value"/>
<div class="form-group"> </div>
<label>Memory Quota</label> </form>
<input type="text" placeholder="Enter Memory Quota" class="form-control" name="memory" id="mMemory">
</div>
<div class="form-group">
<label>Image Quantity</label>
<input type = "text" placeholder="Enter Image Quantity" class="form-control" name="image" id="mImage">
</div>
<div class="form-group">
<label>Life Cycle</label>
<input type = "text" placeholder="Enter Life Cycle" class="form-control" name="lifecycle" id="mLifecycle">
</div>
</form>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-white" data-dismiss="modal">Close</button> <button type="button" class="btn btn-white" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" onClick="javascript:sendModifyGroup();">Submit</button> <button type="button" class="btn btn-primary" onClick="javascript:sendAddQuota();">Submit</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<table id="myGroupTable" class="table table-striped table-bordered">
<thead>
<tr>
<th>Name</th>
{% for quota in quotas %}
<th> {{ quota }} </th>
{% endfor %}
<th>Command</th>
</tr>
</thead>
<tbody>
{% for group in groups %}
<tr>
<th>{{ group['name'] }}</th>
{% for quota in quotas %}
<th> {{ group['quotas'][quota] }} </th>
{% endfor %}
<th><a class="btn btn-xs btn-info" data-toggle="modal" data-target="#ModifyGroupModal_{{ group['name'] }}">Edit</a>&nbsp;
{% if group['name'] in [ "root", "primary", "admin", "fundation" ] %}
<a class="btn btn-xs btn-default" href="javascript:void(0)">Delete</a></th>
{% else %}
<a class="btn btn-xs btn-danger" href="/group/delete/{{group['name']}}">Delete</a></th>
{% endif %}
<div class="modal inmodal" id="ModifyGroupModal_{{ group['name'] }}" 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">&times;</span><span class="sr-only">Close</span></button>
<i class="fa fa-laptop modal-icon"></i>
<h4 class="modal-title">Modify Group</h4>
<small class="font-bold">Modify a group in Docklet</small>
</div>
<form action="/group/modify/{{group['name']}}/" method="POST" >
<div class="modal-body">
<div class="form-group">
<label>Name</label>
<input type="text" placeholder="Enter Name" class="form-control" name="groupname" readonly="true" value={{ group['name'] }} />
</div>
{% for quota in quotas %}
<div class="form-group">
<label> {{ quota }}</label>
<input type="text" placeholder="Enter {{ quota }}" class="form-control" name={{ quota }} value={{ group['quotas'][quota] }} />
</div>
{% endfor %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-white" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</div>
</div>
</tr>
{% endfor %}
</tbody>
</table> </table>
</div> </div>
</div> </div>
@ -149,30 +172,11 @@
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function() {
var gTable = $('#myGroupTable').dataTable({
"ajax": {
"url": "/group/detail/",
"type": "POST"
},
//"scrollX": true,
"columnDefs": [
{
"render": function ( data, type, row ) {
return '<a class="btn btn-xs btn-info" data-toggle="modal" data-target="#ModifyGroupModal" onClick="javascript:setFormGroup('+ "'" + row[0] + "'" + ');">' + 'Edit' + '</a>'
+ '&nbsp;' +'<a class="btn btn-xs btn-danger" href="/group/delete/' + row[0] +'">' + 'Delete' + '</a>';
},
"targets": 5
},
]
});
});
function sendAddGroup(){ function sendAddGroup(){
document.getElementById("addGroupForm").submit(); document.getElementById("addGroupForm").submit();
} }
function sendModifyGroup(){ function sendAddQuota(){
document.getElementById("modifyGroupForm").submit(); document.getElementById("addQuotaForm").submit();
} }
function setFormGroup(arg){ function setFormGroup(arg){
$.post("/group/query/", $.post("/group/query/",

View File

@ -68,7 +68,7 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="form-group"> <div class="form-group">
<form action="/workspace/scaleout/{{ clustername }}/" method="POST" id="scaleout"> <form action="/workspace/scaleout/{{ clustername }}/" method="POST" >
<table class="table table-striped table-bordered table-hover table-image"> <table class="table table-striped table-bordered table-hover table-image">
<thead> <thead>
<tr> <tr>
@ -81,14 +81,14 @@
<tbody> <tbody>
<tr> <tr>
<td>base</td> <td>base</td>
<td><div class="label label-outline-success">public</div></td> <td>public</td>
<td>docklet</td> <td>docklet</td>
<td><input type="radio" name="image" value="base_base_base" checked="checked"></td> <td><input type="radio" name="image" value="base_base_base" checked="checked"></td>
</tr> </tr>
{% for image in images['private'] %} {% for image in images['private'] %}
<tr> <tr>
<td>{{image['name']}}</td> <td>{{image['name']}}</td>
<td><div class="label label-outline-warning">private</div></td> <td>private</td>
<td>{{mysession['username']}}</td> <td>{{mysession['username']}}</td>
<td><input type="radio" name="image" value="{{image['name']}}_{{mysession['username']}}_private"></td> <td><input type="radio" name="image" value="{{image['name']}}_{{mysession['username']}}_private"></td>
</tr> </tr>
@ -97,7 +97,7 @@
{% for image in p_images %} {% for image in p_images %}
<tr> <tr>
<td>{{image['name']}}</td> <td>{{image['name']}}</td>
<td><div class="label label-outline-success">public</div></td> <td>public</td>
<td>{{p_user}}</td> <td>{{p_user}}</td>
<td><input type="radio" name="image" value="{{image['name']}}_{{p_user}}_public"></td> <td><input type="radio" name="image" value="{{image['name']}}_{{p_user}}_public"></td>
</tr> </tr>
@ -247,7 +247,7 @@
<tbody> <tbody>
<tr> <tr>
<td>base</td> <td>base</td>
<td><div class="label label-outline-success">public</div></td> <td>public</td>
<td>docklet</td> <td>docklet</td>
<td>2015-01-01 00:00:00</td> <td>2015-01-01 00:00:00</td>
<td>A Base Image For You</td> <td>A Base Image For You</td>
@ -257,18 +257,18 @@
{% for image in images['private'] %} {% for image in images['private'] %}
<tr> <tr>
<td>{{image['name']}}</td> <td>{{image['name']}}</td>
<td><div class="label label-outline-warning">{{"private"}}</div></td> <td>private</td>
<td>{{mysession['username']}}</td> <td>{{mysession['username']}}</td>
<td>{{image['time']}}</td> <td>{{image['time']}}</td>
<td><a href="/image/description/{{image['name']}}_{{mysession['username']}}_private/" target="_blank">{{image['description']}}</a></td> <td><a href="/image/description/{{image['name']}}_{{mysession['username']}}_private/" target="_blank">{{image['description']}}</a></td>
{% if image['isshared'] == 'false' %} {% if image['isshared'] == 'false' %}
<td><div class="label label-outline-default">unshared</div></td> <td>unshared</td>
<td> <td>
<a href="/image/share/{{ image['name'] }}/"><button type="button" class="btn btn-xs btn-success">share</button></a> <a href="/image/share/{{ image['name'] }}/"><button type="button" class="btn btn-xs btn-success">share</button></a>
<a href="/image/delete/{{ image['name'] }}/"><button type="button" class="btn btn-xs btn-danger">delete</button></a> <a href="/image/delete/{{ image['name'] }}/"><button type="button" class="btn btn-xs btn-danger">delete</button></a>
</td> </td>
{% else %} {% else %}
<td><div class="label label-outline-default">shared</div></td> <td>shared</td>
<td> <td>
<a href="/image/unshare/{{ image['name'] }}/"><button type="button" class="btn btn-xs btn-warning">unshare</button></a> <a href="/image/unshare/{{ image['name'] }}/"><button type="button" class="btn btn-xs btn-warning">unshare</button></a>
<a href="/image/delete/{{ image['name'] }}/"><button type="button" class="btn btn-xs btn-danger">delete</button></a> <a href="/image/delete/{{ image['name'] }}/"><button type="button" class="btn btn-xs btn-danger">delete</button></a>
@ -280,7 +280,7 @@
{% for image in p_images %} {% for image in p_images %}
<tr> <tr>
<td>{{image['name']}}</td> <td>{{image['name']}}</td>
<td><div class="label label-outline-success">{{"public"}}</div></td> <td>public</td>
<td>{{p_user}}</td> <td>{{p_user}}</td>
<td>{{image['time']}}</td> <td>{{image['time']}}</td>
<td><a href="/image/description/{{image['name']}}_{{p_user}}_public/" target="_blank">{{image['description']}}</a></td> <td><a href="/image/description/{{image['name']}}_{{p_user}}_public/" target="_blank">{{image['description']}}</a></td>

View File

@ -56,7 +56,7 @@
<a href="/go/{{ mysession['username'] }}/{{ cluster['name'] }}" target="_blank"><button type="button" class="btn btn-xs btn-success">&nbsp;&nbsp;&nbsp;Go&nbsp;&nbsp;&nbsp;</button></a> <a href="/go/{{ mysession['username'] }}/{{ cluster['name'] }}" target="_blank"><button type="button" class="btn btn-xs btn-success">&nbsp;&nbsp;&nbsp;Go&nbsp;&nbsp;&nbsp;</button></a>
</td> </td>
{% else %} {% else %}
<td><a href="/monitor/Node/"><div class="text-warning"><i class="fa fa-stop "></i> Stopped</div></a></td> <td><a href="/vclusters/"><div class="text-warning"><i class="fa fa-stop "></i> Stopped</div></a></td>
<td> <td>
<a href="/workspace/start/{{ cluster['name'] }}/"><button type="button" class="btn btn-xs btn-success"> &nbsp;Start&nbsp;</button></a> <a href="/workspace/start/{{ cluster['name'] }}/"><button type="button" class="btn btn-xs btn-success"> &nbsp;Start&nbsp;</button></a>
<a href="/workspace/delete/{{ cluster['name'] }}/"><button type="button" class="btn btn-xs btn-danger">Delete</button></a> <a href="/workspace/delete/{{ cluster['name'] }}/"><button type="button" class="btn btn-xs btn-danger">Delete</button></a>

View File

@ -20,7 +20,7 @@ from webViews.log import logger
from flask import Flask, request, session, render_template, redirect, send_from_directory, make_response, url_for, abort from flask import Flask, request, session, render_template, redirect, send_from_directory, make_response, url_for, abort
from webViews.dashboard import dashboardView from webViews.dashboard import dashboardView
from webViews.user.userlist import userlistView, useraddView, usermodifyView, groupaddView, groupdelView, userdataView, userqueryView from webViews.user.userlist import userlistView, useraddView, usermodifyView, userdataView, userqueryView
from webViews.user.userinfo import userinfoView from webViews.user.userinfo import userinfoView
from webViews.user.userActivate import userActivateView from webViews.user.userActivate import userActivateView
from webViews.user.grouplist import grouplistView, groupqueryView, groupdetailView, groupmodifyView from webViews.user.grouplist import grouplistView, groupqueryView, groupdetailView, groupmodifyView
@ -303,9 +303,9 @@ def groupdetail():
def groupquery(): def groupquery():
return groupqueryView.as_view() return groupqueryView.as_view()
@app.route("/group/modify/", methods=['POST']) @app.route("/group/modify/<groupname>/", methods=['POST'])
@administration_required @administration_required
def groupmodify(): def groupmodify(groupname):
return groupmodifyView.as_view() return groupmodifyView.as_view()
@app.route("/user/data/", methods=['GET', 'POST']) @app.route("/user/data/", methods=['GET', 'POST'])
@ -323,6 +323,11 @@ def useradd():
def usermodify(): def usermodify():
return usermodifyView.as_view() return usermodifyView.as_view()
@app.route("/quota/add/", methods=['POST'])
@administration_required
def quotaadd():
return quotaaddView.as_view()
@app.route("/group/add/", methods=['POST']) @app.route("/group/add/", methods=['POST'])
@administration_required @administration_required
def groupadd(): def groupadd():

View File

@ -1,14 +1,40 @@
from flask import session from flask import session, render_template, redirect, request
from webViews.view import normalView from webViews.view import normalView
from webViews.dockletrequest import dockletRequest from webViews.dockletrequest import dockletRequest
from webViews.dashboard import * from webViews.dashboard import *
import time, re import time, re, json
class adminView(normalView): class adminView(normalView):
template_path = "admin.html" template_path = "admin.html"
@classmethod @classmethod
def get(self): def get(self):
groups = dockletRequest.post('/user/groupNameList/')["groups"] result = dockletRequest.post('/user/groupList/')
return self.render(self.template_path, groups = groups) groups = result["groups"]
quotas = result["quotas"]
return self.render(self.template_path, groups = groups, quotas = quotas)
class groupaddView(normalView):
@classmethod
def post(self):
dockletRequest.post('/user/groupadd', request.form)
return redirect('/admin/')
class quotaaddView(normalView):
@classmethod
def post(self):
dockletRequest.post('/user/quotaadd', request.form)
return redirect('/admin/')
class groupdelView(normalView):
@classmethod
def post(self):
data = {
"name" : self.groupname,
}
dockletRequest.post('/user/groupdel', data)
return redirect('/admin/')
@classmethod
def get(self):
return self.post()

View File

@ -182,6 +182,7 @@ class detailClusterView(normalView):
class saveImageView(normalView): class saveImageView(normalView):
template_path = "saveconfirm.html" template_path = "saveconfirm.html"
success_path = "opsuccess.html" success_path = "opsuccess.html"
error_path = "error.html"
@classmethod @classmethod
def post(self): def post(self):
@ -201,7 +202,10 @@ class saveImageView(normalView):
#res.clustername = self.clustername #res.clustername = self.clustername
#return res.as_view() #return res.as_view()
else: else:
return self.render(self.template_path, containername = self.containername, clustername = self.clustername, image = self.imagename, user = session['username'], description = self.description) if result.get('reason') == "exists":
return self.render(self.template_path, containername = self.containername, clustername = self.clustername, image = self.imagename, user = session['username'], description = self.description)
else:
return self.render(self.error_path, message = result.get('message'))
else: else:
self.error() self.error()

View File

@ -49,21 +49,4 @@ class usermodifyView(normalView):
return self.render('user/mailservererror.html') return self.render('user/mailservererror.html')
return redirect('/user/list/') return redirect('/user/list/')
class groupaddView(normalView):
@classmethod
def post(self):
dockletRequest.post('/user/groupadd', request.form)
return redirect('/admin/')
class groupdelView(normalView):
@classmethod
def post(self):
data = {
"name" : self.groupname,
}
dockletRequest.post('/user/groupdel', data)
return redirect('/admin/')
@classmethod
def get(self):
return self.post()