mirror of
https://github.com/ComputerScienceHouse/proxstar.git
synced 2025-02-14 22:11:51 +00:00
add proper confirmations, add resource usage indicators, add authorization check, change routes to be more consistent
This commit is contained in:
parent
16974eec39
commit
a2278f59db
10 changed files with 1451 additions and 89 deletions
66
app.py
66
app.py
|
@ -37,34 +37,52 @@ def list_vms():
|
||||||
|
|
||||||
@app.route("/vm/<string:vmid>")
|
@app.route("/vm/<string:vmid>")
|
||||||
def vm_details(vmid):
|
def vm_details(vmid):
|
||||||
vm = get_vm(proxmox, vmid)
|
if int(vmid) in get_user_allowed_vms(proxmox, user):
|
||||||
vm['vmid'] = vmid
|
vm = get_vm(proxmox, vmid)
|
||||||
vm['config'] = get_vm_config(proxmox, vmid)
|
vm['vmid'] = vmid
|
||||||
vm['disks'] = get_vm_disks(proxmox, vmid, config=vm['config'])
|
vm['config'] = get_vm_config(proxmox, vmid)
|
||||||
vm['interfaces'] = get_vm_interfaces(
|
vm['disks'] = get_vm_disks(proxmox, vmid, config=vm['config'])
|
||||||
proxmox, vm['vmid'], config=vm['config'])
|
vm['interfaces'] = get_vm_interfaces(
|
||||||
return render_template('vm_details.html', username='com6056', vm=vm)
|
proxmox, vm['vmid'], config=vm['config'])
|
||||||
|
return render_template('vm_details.html', username='com6056', vm=vm)
|
||||||
|
else:
|
||||||
|
return '', 403
|
||||||
|
|
||||||
|
|
||||||
@app.route("/vm_status/<string:vmid>", methods=['POST'])
|
@app.route("/vm/<string:vmid>/power/<string:action>", methods=['POST'])
|
||||||
def vm_status(vmid):
|
def vm_power(vmid, action):
|
||||||
action = request.form['action']
|
if int(vmid) in get_user_allowed_vms(proxmox, user):
|
||||||
change_vm_status(proxmox, vmid, action)
|
change_vm_power(proxmox, vmid, action)
|
||||||
return redirect("/proxstar/vm/{}".format(vmid))
|
return '', 200
|
||||||
|
else:
|
||||||
|
return '', 403
|
||||||
|
|
||||||
|
|
||||||
@app.route("/create", methods=['GET', 'POST'])
|
@app.route("/vm/<string:vmid>/delete", methods=['POST'])
|
||||||
|
def delete(vmid):
|
||||||
|
if int(vmid) in get_user_allowed_vms(proxmox, user):
|
||||||
|
vmname = get_vm_config(proxmox, vmid)['name']
|
||||||
|
delete_vm(proxmox, starrs, vmid)
|
||||||
|
delete_starrs(starrs, vmname)
|
||||||
|
return '', 200
|
||||||
|
else:
|
||||||
|
return '', 403
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/vm/create", methods=['GET', 'POST'])
|
||||||
def create():
|
def create():
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
usage = get_user_usage(proxmox, 'proxstar')
|
usage = get_user_usage(proxmox, 'proxstar')
|
||||||
limits = get_user_usage_limits(user)
|
limits = get_user_usage_limits(user)
|
||||||
full_limits = check_user_limit(proxmox, user, usage, limits)
|
full_limits = check_user_limit(proxmox, user, usage, limits)
|
||||||
|
percents = get_user_usage_percent(proxmox, usage, limits)
|
||||||
return render_template(
|
return render_template(
|
||||||
'create.html',
|
'create.html',
|
||||||
username='com6056',
|
username='com6056',
|
||||||
usage=usage,
|
usage=usage,
|
||||||
limits=limits,
|
limits=limits,
|
||||||
full_limits=full_limits)
|
full_limits=full_limits,
|
||||||
|
percents=percents)
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
name = request.form['name']
|
name = request.form['name']
|
||||||
cores = request.form['cores']
|
cores = request.form['cores']
|
||||||
|
@ -82,28 +100,10 @@ def create():
|
||||||
return redirect("/proxstar/vm/{}".format(vmid))
|
return redirect("/proxstar/vm/{}".format(vmid))
|
||||||
|
|
||||||
|
|
||||||
@app.route("/delete", methods=['POST'])
|
|
||||||
def delete():
|
|
||||||
vmid = request.form['delete']
|
|
||||||
vmname = get_vm_config(proxmox, vmid)['name']
|
|
||||||
return render_template(
|
|
||||||
'confirm_delete.html', username='com6056', vmid=vmid, vmname=vmname)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/confirm_delete", methods=['POST'])
|
|
||||||
def confirm_delete():
|
|
||||||
vmid = request.form['delete']
|
|
||||||
vmname = get_vm_config(proxmox, vmid)['name']
|
|
||||||
delete_vm(proxmox, starrs, vmid)
|
|
||||||
delete_starrs(starrs, vmname)
|
|
||||||
time.sleep(3)
|
|
||||||
return redirect("/proxstar")
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/novnc/<path:path>')
|
@app.route('/novnc/<path:path>')
|
||||||
def send_novnc(path):
|
def send_novnc(path):
|
||||||
return send_from_directory('static/novnc-pve/novnc', path)
|
return send_from_directory('static/novnc-pve/novnc', path)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run()
|
app.run(debug=True)
|
||||||
|
|
32
proxmox.py
32
proxmox.py
|
@ -16,6 +16,13 @@ def get_vms_for_user(proxmox, user):
|
||||||
return proxmox.pools(user).get()['members']
|
return proxmox.pools(user).get()['members']
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_allowed_vms(proxmox, user):
|
||||||
|
allowed_vms = []
|
||||||
|
for vm in get_vms_for_user(proxmox, user):
|
||||||
|
allowed_vms.append(vm['vmid'])
|
||||||
|
return allowed_vms
|
||||||
|
|
||||||
|
|
||||||
def get_node_least_mem(proxmox):
|
def get_node_least_mem(proxmox):
|
||||||
nodes = proxmox.nodes.get()
|
nodes = proxmox.nodes.get()
|
||||||
sorted_nodes = sorted(nodes, key=lambda x: x['mem'])
|
sorted_nodes = sorted(nodes, key=lambda x: x['mem'])
|
||||||
|
@ -115,11 +122,12 @@ def get_user_usage(proxmox, user):
|
||||||
vms = get_vms_for_user(proxmox, user)
|
vms = get_vms_for_user(proxmox, user)
|
||||||
for vm in vms:
|
for vm in vms:
|
||||||
config = get_vm_config(proxmox, vm['vmid'])
|
config = get_vm_config(proxmox, vm['vmid'])
|
||||||
if vm['status'] == 'running' or vm['status'] == 'paused':
|
if 'status' in vm:
|
||||||
usage['cpu'] += int(config['cores'] * config.get('sockets', 1))
|
if vm['status'] == 'running' or vm['status'] == 'paused':
|
||||||
usage['mem'] += (int(config['memory']) // 1024)
|
usage['cpu'] += int(config['cores'] * config.get('sockets', 1))
|
||||||
for disk in get_vm_disks(proxmox, vm['vmid'], config):
|
usage['mem'] += (int(config['memory']) // 1024)
|
||||||
usage['disk'] += int(disk[1][:-1])
|
for disk in get_vm_disks(proxmox, vm['vmid'], config):
|
||||||
|
usage['disk'] += int(disk[1][:-1])
|
||||||
return usage
|
return usage
|
||||||
|
|
||||||
|
|
||||||
|
@ -149,6 +157,18 @@ def check_user_usage(proxmox, user, vm_cpu, vm_mem, vm_disk):
|
||||||
return 'Exceeds disk limit!'
|
return 'Exceeds disk limit!'
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_usage_percent(proxmox, usage=None, limits=None):
|
||||||
|
percents = dict()
|
||||||
|
if not usage:
|
||||||
|
usage = get_user_usage(proxmox, user)
|
||||||
|
if not limits:
|
||||||
|
limits = get_user_usage_limits(user)
|
||||||
|
percents['cpu'] = round(int(usage['cpu']) / int(limits['cpu']) * 100)
|
||||||
|
percents['mem'] = round(int(usage['mem']) / int(limits['mem']) * 100)
|
||||||
|
percents['disk'] = round(int(usage['disk']) / int(limits['disk']) * 100)
|
||||||
|
return percents
|
||||||
|
|
||||||
|
|
||||||
def create_vm(proxmox, starrs, user, name, cores, memory, disk):
|
def create_vm(proxmox, starrs, user, name, cores, memory, disk):
|
||||||
node = proxmox.nodes(get_node_least_mem(proxmox))
|
node = proxmox.nodes(get_node_least_mem(proxmox))
|
||||||
vmid = get_free_vmid(proxmox)
|
vmid = get_free_vmid(proxmox)
|
||||||
|
@ -171,7 +191,7 @@ def delete_vm(proxmox, starrs, vmid):
|
||||||
node.qemu(vmid).delete()
|
node.qemu(vmid).delete()
|
||||||
|
|
||||||
|
|
||||||
def change_vm_status(proxmox, vmid, action):
|
def change_vm_power(proxmox, vmid, action):
|
||||||
node = proxmox.nodes(get_vm_node(proxmox, vmid))
|
node = proxmox.nodes(get_vm_node(proxmox, vmid))
|
||||||
if action == 'start':
|
if action == 'start':
|
||||||
node.qemu(vmid).status.start.post()
|
node.qemu(vmid).status.start.post()
|
||||||
|
|
1065
static/css/circle.css
Normal file
1065
static/css/circle.css
Normal file
File diff suppressed because it is too large
Load diff
|
@ -65,3 +65,8 @@ table, th, td {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.resource-usage {
|
||||||
|
width: 50%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
238
static/js/script.js
Normal file
238
static/js/script.js
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
$("#delete-vm").click(function(){
|
||||||
|
const vmname = $(this).data('vmname')
|
||||||
|
swal({
|
||||||
|
title: `Are you sure you want to delete ${vmname}?`,
|
||||||
|
icon: "warning",
|
||||||
|
buttons: {
|
||||||
|
cancel: true,
|
||||||
|
delete: {
|
||||||
|
text: "Delete",
|
||||||
|
closeModal: false,
|
||||||
|
className: "swal-button--danger",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dangerMode: true,
|
||||||
|
})
|
||||||
|
.then((willDelete) => {
|
||||||
|
if (willDelete) {
|
||||||
|
const vmid = $(this).data('vmid')
|
||||||
|
fetch(`/proxstar/vm/${vmid}/delete`, {
|
||||||
|
credentials: 'same-origin',
|
||||||
|
method: 'post'
|
||||||
|
}).then((response) => {
|
||||||
|
return swal(`${vmname} has been deleted!`, {
|
||||||
|
icon: "success",
|
||||||
|
});
|
||||||
|
}).then(() => {
|
||||||
|
window.location = "/proxstar";
|
||||||
|
}).catch(err => {
|
||||||
|
if (err) {
|
||||||
|
swal("Uh oh...", `Unable to delete ${vmname}. Please try again later.`, "error");
|
||||||
|
} else {
|
||||||
|
swal.stopLoading();
|
||||||
|
swal.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#stop-vm").click(function(){
|
||||||
|
const vmname = $(this).data('vmname')
|
||||||
|
swal({
|
||||||
|
title: `Are you sure you want to stop ${vmname}?`,
|
||||||
|
icon: "warning",
|
||||||
|
buttons: {
|
||||||
|
cancel: true,
|
||||||
|
delete: {
|
||||||
|
text: "Stop",
|
||||||
|
closeModal: false,
|
||||||
|
className: "swal-button--danger",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dangerMode: true,
|
||||||
|
})
|
||||||
|
.then((willDelete) => {
|
||||||
|
if (willDelete) {
|
||||||
|
const vmid = $(this).data('vmid')
|
||||||
|
fetch(`/proxstar/vm/${vmid}/power/stop`, {
|
||||||
|
credentials: 'same-origin',
|
||||||
|
method: 'post'
|
||||||
|
}).then((response) => {
|
||||||
|
return swal(`${vmname} is now stopping!`, {
|
||||||
|
icon: "success",
|
||||||
|
});
|
||||||
|
}).then(() => {
|
||||||
|
window.location = `/proxstar/vm/${vmid}`;
|
||||||
|
}).catch(err => {
|
||||||
|
if (err) {
|
||||||
|
swal("Uh oh...", `Unable to stop ${vmname}. Please try again later.`, "error");
|
||||||
|
} else {
|
||||||
|
swal.stopLoading();
|
||||||
|
swal.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#reset-vm").click(function(){
|
||||||
|
const vmname = $(this).data('vmname')
|
||||||
|
swal({
|
||||||
|
title: `Are you sure you want to reset ${vmname}?`,
|
||||||
|
icon: "warning",
|
||||||
|
buttons: {
|
||||||
|
cancel: true,
|
||||||
|
delete: {
|
||||||
|
text: "Reset",
|
||||||
|
closeModal: false,
|
||||||
|
className: "swal-button--danger",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dangerMode: true,
|
||||||
|
})
|
||||||
|
.then((willDelete) => {
|
||||||
|
if (willDelete) {
|
||||||
|
const vmid = $(this).data('vmid')
|
||||||
|
fetch(`/proxstar/vm/${vmid}/power/reset`, {
|
||||||
|
credentials: 'same-origin',
|
||||||
|
method: 'post'
|
||||||
|
}).then((response) => {
|
||||||
|
return swal(`${vmname} is now resetting!`, {
|
||||||
|
icon: "success",
|
||||||
|
});
|
||||||
|
}).then(() => {
|
||||||
|
window.location = `/proxstar/vm/${vmid}`;
|
||||||
|
}).catch(err => {
|
||||||
|
if (err) {
|
||||||
|
swal("Uh oh...", `Unable to reset ${vmname}. Please try again later.`, "error");
|
||||||
|
} else {
|
||||||
|
swal.stopLoading();
|
||||||
|
swal.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#shutdown-vm").click(function(){
|
||||||
|
const vmname = $(this).data('vmname')
|
||||||
|
swal({
|
||||||
|
title: `Are you sure you want to shutdown ${vmname}?`,
|
||||||
|
icon: "warning",
|
||||||
|
buttons: {
|
||||||
|
cancel: true,
|
||||||
|
delete: {
|
||||||
|
text: "Shutdown",
|
||||||
|
closeModal: false,
|
||||||
|
className: "swal-button--danger",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dangerMode: true,
|
||||||
|
})
|
||||||
|
.then((willDelete) => {
|
||||||
|
if (willDelete) {
|
||||||
|
const vmid = $(this).data('vmid')
|
||||||
|
fetch(`/proxstar/vm/${vmid}/power/shutdown`, {
|
||||||
|
credentials: 'same-origin',
|
||||||
|
method: 'post'
|
||||||
|
}).then((response) => {
|
||||||
|
return swal(`${vmname} is now shutting down!`, {
|
||||||
|
icon: "success",
|
||||||
|
});
|
||||||
|
}).then(() => {
|
||||||
|
window.location = `/proxstar/vm/${vmid}`;
|
||||||
|
}).catch(err => {
|
||||||
|
if (err) {
|
||||||
|
swal("Uh oh...", `Unable to shutdown ${vmname}. Please try again later.`, "error");
|
||||||
|
} else {
|
||||||
|
swal.stopLoading();
|
||||||
|
swal.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#suspend-vm").click(function(){
|
||||||
|
const vmname = $(this).data('vmname')
|
||||||
|
swal({
|
||||||
|
title: `Are you sure you want to suspend ${vmname}?`,
|
||||||
|
icon: "warning",
|
||||||
|
buttons: {
|
||||||
|
cancel: true,
|
||||||
|
delete: {
|
||||||
|
text: "Suspend",
|
||||||
|
closeModal: false,
|
||||||
|
className: "swal-button--danger",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dangerMode: true,
|
||||||
|
})
|
||||||
|
.then((willDelete) => {
|
||||||
|
if (willDelete) {
|
||||||
|
const vmid = $(this).data('vmid')
|
||||||
|
fetch(`/proxstar/vm/${vmid}/power/suspend`, {
|
||||||
|
credentials: 'same-origin',
|
||||||
|
method: 'post'
|
||||||
|
}).then((response) => {
|
||||||
|
return swal(`${vmname} is now suspending!`, {
|
||||||
|
icon: "success",
|
||||||
|
});
|
||||||
|
}).then(() => {
|
||||||
|
window.location = `/proxstar/vm/${vmid}`;
|
||||||
|
}).catch(err => {
|
||||||
|
if (err) {
|
||||||
|
swal("Uh oh...", `Unable to suspend ${vmname}. Please try again later.`, "error");
|
||||||
|
} else {
|
||||||
|
swal.stopLoading();
|
||||||
|
swal.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#start-vm").click(function(){
|
||||||
|
const vmname = $(this).data('vmname')
|
||||||
|
const vmid = $(this).data('vmid')
|
||||||
|
fetch(`/proxstar/vm/${vmid}/power/start`, {
|
||||||
|
credentials: 'same-origin',
|
||||||
|
method: 'post'
|
||||||
|
}).then((response) => {
|
||||||
|
return swal(`${vmname} is now starting!`, {
|
||||||
|
icon: "success",
|
||||||
|
});
|
||||||
|
}).then(() => {
|
||||||
|
window.location = `/proxstar/vm/${vmid}`;
|
||||||
|
}).catch(err => {
|
||||||
|
if (err) {
|
||||||
|
swal("Uh oh...", `Unable to start ${vmname}. Please try again later.`, "error");
|
||||||
|
} else {
|
||||||
|
swal.stopLoading();
|
||||||
|
swal.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#resume-vm").click(function(){
|
||||||
|
const vmname = $(this).data('vmname')
|
||||||
|
const vmid = $(this).data('vmid')
|
||||||
|
fetch(`/proxstar/vm/${vmid}/power/resume`, {
|
||||||
|
credentials: 'same-origin',
|
||||||
|
method: 'post'
|
||||||
|
}).then((response) => {
|
||||||
|
return swal(`${vmname} is now resuming!`, {
|
||||||
|
icon: "success",
|
||||||
|
});
|
||||||
|
}).then(() => {
|
||||||
|
window.location = `/proxstar/vm/${vmid}`;
|
||||||
|
}).catch(err => {
|
||||||
|
if (err) {
|
||||||
|
swal("Uh oh...", `Unable to resume ${vmname}. Please try again later.`, "error");
|
||||||
|
} else {
|
||||||
|
swal.stopLoading();
|
||||||
|
swal.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -7,9 +7,8 @@
|
||||||
<meta name="theme-color" content="#B0197E">
|
<meta name="theme-color" content="#B0197E">
|
||||||
<link rel="stylesheet" href="/proxstar/static/css/csh-material-bootstrap/dist/css/csh-material-bootstrap.css">
|
<link rel="stylesheet" href="/proxstar/static/css/csh-material-bootstrap/dist/css/csh-material-bootstrap.css">
|
||||||
<link rel="stylesheet" href="/proxstar/static/css/styles.css">
|
<link rel="stylesheet" href="/proxstar/static/css/styles.css">
|
||||||
|
<link rel="stylesheet" href="/proxstar/static/css/circle.css">
|
||||||
<link rel="manifest" href="/static/manifest.json">
|
<link rel="manifest" href="/static/manifest.json">
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
|
|
||||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% block nav %}
|
{% block nav %}
|
||||||
|
@ -34,7 +33,7 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/proxstar/create">
|
<a href="/proxstar/vm/create">
|
||||||
<span class="glyphicon glyphicon-plus-sign"></span>
|
<span class="glyphicon glyphicon-plus-sign"></span>
|
||||||
Create VM
|
Create VM
|
||||||
</a>
|
</a>
|
||||||
|
@ -90,6 +89,10 @@
|
||||||
<a class="footer-version" href="https://github.com/com6056/proxstar/tree/{{config["GIT_REVISION"]}}">Proxstar ({{config["GIT_REVISION"]}})</a>
|
<a class="footer-version" href="https://github.com/com6056/proxstar/tree/{{config["GIT_REVISION"]}}">Proxstar ({{config["GIT_REVISION"]}})</a>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
|
||||||
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
|
||||||
|
<script src="/proxstar/static/js/script.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% block body %}
|
|
||||||
|
|
||||||
Are you sure you want to delete "{{ vmname }}"?
|
|
||||||
|
|
||||||
<form action="/proxstar/confirm_delete" method="post">
|
|
||||||
<button type="submit" name="delete" value="{{ vmid }}">CONFIRM</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -11,11 +11,9 @@
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{% if full_limits %}
|
{% if full_limits %}
|
||||||
<p>You have reached your limit for the following resources:</p>
|
<p>You have reached your limit for the following resources:</p>
|
||||||
<ul>
|
|
||||||
{% for limit in full_limits %}
|
{% for limit in full_limits %}
|
||||||
<li>{{ limit }}</li>
|
<p><strong>{{ limit }}</strong></p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
|
||||||
<p>Before you can create any more VMs, you must first either power off (CPU/Memory) or delete (Disk) existing VMs until you have enough resources available.</p>
|
<p>Before you can create any more VMs, you must first either power off (CPU/Memory) or delete (Disk) existing VMs until you have enough resources available.</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<form action="create" method="post">
|
<form action="create" method="post">
|
||||||
|
@ -55,9 +53,56 @@
|
||||||
<h3 class="panel-title">Current Usage</h3>
|
<h3 class="panel-title">Current Usage</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<p>CPU: {{ usage['cpu'] }}/{{ limits['cpu'] }} Cores</p>
|
<div class="resource-usage">
|
||||||
<p>Memory: {{ usage['mem'] }}/{{ limits['mem'] }} GB</p>
|
<div>
|
||||||
<p>Disk: {{ usage['disk'] }}/{{ limits['disk'] }} GB</p>
|
CPU Cores
|
||||||
|
{% if percents['cpu'] <= 50 %}
|
||||||
|
<div class="c100 p{{ percents['cpu'] }} green">
|
||||||
|
{% elif percents['cpu'] <= 75 %}
|
||||||
|
<div class="c100 p{{ percents['cpu'] }} blue">
|
||||||
|
{% else %}
|
||||||
|
<div class="c100 p{{ percents['cpu'] }} orange">
|
||||||
|
{% endif %}
|
||||||
|
<span>{{ usage['cpu'] }}/{{ limits['cpu'] }}</span>
|
||||||
|
<div class="slice">
|
||||||
|
<div class="bar"></div>
|
||||||
|
<div class="fill"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Memory (GB)
|
||||||
|
{% if percents['mem'] <= 50 %}
|
||||||
|
<div class="c100 p{{ percents['mem'] }} green">
|
||||||
|
{% elif percents['mem'] <= 75 %}
|
||||||
|
<div class="c100 p{{ percents['mem'] }} blue">
|
||||||
|
{% else %}
|
||||||
|
<div class="c100 p{{ percents['mem'] }} orange">
|
||||||
|
{% endif %}
|
||||||
|
<span>{{ usage['mem'] }}/{{ limits['mem'] }}</span>
|
||||||
|
<div class="slice">
|
||||||
|
<div class="bar"></div>
|
||||||
|
<div class="fill"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Disk (GB)
|
||||||
|
{% if percents['disk'] <= 50 %}
|
||||||
|
<div class="c100 p{{ percents['disk'] }} green">
|
||||||
|
{% elif percents['disk'] <= 75 %}
|
||||||
|
<div class="c100 p{{ percents['disk'] }} blue">
|
||||||
|
{% else %}
|
||||||
|
<div class="c100 p{{ percents['disk'] }} orange">
|
||||||
|
{% endif %}
|
||||||
|
<span>{{ usage['disk'] }}/{{ limits['disk'] }}</span>
|
||||||
|
<div class="slice">
|
||||||
|
<div class="bar"></div>
|
||||||
|
<div class="fill"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,18 +3,28 @@
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% for vm in vms %}
|
{% if not vms %}
|
||||||
<div class="col-md-3 col-sm-4 col-xs-6">
|
<div class="col-md-12 col-sm-12">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<a href="/proxstar/vm/{{ vm['vmid'] }}">
|
<p>It looks like you don't have any VMs! If you want to create a VM, click <a href="/proxstar/vm/create">here</a>.</p>
|
||||||
<p>{{ vm['name'] }}</p>
|
|
||||||
</a>
|
|
||||||
<p>Status: {{ vm['status'] }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
</div>
|
||||||
|
{% else %}
|
||||||
|
{% for vm in vms %}
|
||||||
|
<div class="col-md-3 col-sm-4 col-xs-6">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<a href="/proxstar/vm/{{ vm['vmid'] }}">
|
||||||
|
<p>{{ vm['name'] }}</p>
|
||||||
|
</a>
|
||||||
|
<p>Status: {{ vm['status'] }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -10,34 +10,20 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{% if vm['qmpstatus'] == 'stopped' %}
|
{% if vm['qmpstatus'] == 'stopped' %}
|
||||||
<form action="/proxstar/vm_status/{{ vm['vmid'] }}" method="post">
|
<button class="btn btn-success proxstar-actionbtn" id="start-vm" name="start" data-vmid="{{ vm['vmid'] }}" data-vmname="{{ vm['name'] }}">START</button>
|
||||||
<button class="btn btn-success proxstar-actionbtn" type="submit" name="action" value="start">START</button>
|
<button class="btn btn-danger proxstar-actionbtn" id="delete-vm" name="delete" data-vmid="{{ vm['vmid'] }}" data-vmname="{{ vm['name'] }}">DELETE</button>
|
||||||
</form>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if vm['qmpstatus'] == 'paused' %}
|
{% if vm['qmpstatus'] == 'paused' %}
|
||||||
<form action="/proxstar/vm_status/{{ vm['vmid'] }}" method="post">
|
<button class="btn btn-success proxstar-actionbtn" id="resume-vm" name="resume" data-vmid="{{ vm['vmid'] }}" data-vmname="{{ vm['name'] }}">RESUME</button>
|
||||||
<button class="btn btn-success proxstar-actionbtn" type="submit" name="action" value="resume">RESUME</button>
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if vm['qmpstatus'] == 'running' or vm['qmpstatus'] == 'paused' %}
|
{% if vm['qmpstatus'] == 'running' or vm['qmpstatus'] == 'paused' %}
|
||||||
<form action="/proxstar/vm_status/{{ vm['vmid'] }}" method="post">
|
<button class="btn btn-info proxstar-actionbtn" id="shutdown-vm" name="shutdown" data-vmid="{{ vm['vmid'] }}" data-vmname="{{ vm['name'] }}">SHUTDOWN</button>
|
||||||
<button class="btn btn-info proxstar-actionbtn" type="submit" name="action" value="shutdown">SHUTDOWN</button>
|
|
||||||
</form>
|
|
||||||
{% if vm['qmpstatus'] == 'running' %}
|
{% if vm['qmpstatus'] == 'running' %}
|
||||||
<form action="/proxstar/vm_status/{{ vm['vmid'] }}" method="post">
|
<button class="btn btn-info proxstar-actionbtn" id="suspend-vm" name="suspend" data-vmid="{{ vm['vmid'] }}" data-vmname="{{ vm['name'] }}">SUSPEND</button>
|
||||||
<button class="btn btn-info proxstar-actionbtn" type="submit" name="action" value="suspend">SUSPEND</button>
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<form action="/proxstar/vm_status/{{ vm['vmid'] }}" method="post">
|
<button class="btn btn-warning proxstar-actionbtn" id="stop-vm" name="stop" data-vmid="{{ vm['vmid'] }}" data-vmname="{{ vm['name'] }}">STOP</button>
|
||||||
<button class="btn btn-warning proxstar-actionbtn" type="submit" name="action" value="stop">STOP</button>
|
<button class="btn btn-warning proxstar-actionbtn" id="reset-vm" name="reset" data-vmid="{{ vm['vmid'] }}" data-vmname="{{ vm['name'] }}">RESET</button>
|
||||||
</form>
|
|
||||||
<form action="/proxstar/vm_status/{{ vm['vmid'] }}" method="post">
|
|
||||||
<button class="btn btn-warning proxstar-actionbtn" type="submit" name="action" value="reset">RESET</button>
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<form action="/proxstar/delete" method="post">
|
|
||||||
<button class="btn btn-danger proxstar-actionbtn" type="submit" name="delete" value="{{ vm['vmid'] }}">DELETE</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue