mirror of
https://github.com/ComputerScienceHouse/proxstar.git
synced 2025-03-09 15:40:09 +00:00
add ability to change boot order, a lot more cleanup from conversion to classes
This commit is contained in:
parent
cefe605bb9
commit
64b8d3983e
7 changed files with 217 additions and 74 deletions
|
@ -13,7 +13,6 @@ from sqlalchemy.orm import sessionmaker
|
||||||
from flask_pyoidc.flask_pyoidc import OIDCAuthentication
|
from flask_pyoidc.flask_pyoidc import OIDCAuthentication
|
||||||
from flask import Flask, render_template, request, redirect, session, abort
|
from flask import Flask, render_template, request, redirect, session, abort
|
||||||
from proxstar.db import *
|
from proxstar.db import *
|
||||||
from proxstar.vm import VM
|
|
||||||
from proxstar.vnc import *
|
from proxstar.vnc import *
|
||||||
from proxstar.util import gen_password
|
from proxstar.util import gen_password
|
||||||
from proxstar.starrs import *
|
from proxstar.starrs import *
|
||||||
|
@ -64,6 +63,7 @@ starrs = psycopg2.connect(
|
||||||
app.config['STARRS_DB_NAME'], app.config['STARRS_DB_USER'],
|
app.config['STARRS_DB_NAME'], app.config['STARRS_DB_USER'],
|
||||||
app.config['STARRS_DB_HOST'], app.config['STARRS_DB_PASS']))
|
app.config['STARRS_DB_HOST'], app.config['STARRS_DB_PASS']))
|
||||||
|
|
||||||
|
from proxstar.vm import VM
|
||||||
from proxstar.user import User
|
from proxstar.user import User
|
||||||
from proxstar.tasks import generate_pool_cache_task, process_expiring_vms_task, cleanup_vnc_task, delete_vm_task, create_vm_task, setup_template_task
|
from proxstar.tasks import generate_pool_cache_task, process_expiring_vms_task, cleanup_vnc_task, delete_vm_task, create_vm_task, setup_template_task
|
||||||
|
|
||||||
|
@ -179,25 +179,11 @@ def vm_details(vmid):
|
||||||
proxmox = connect_proxmox()
|
proxmox = connect_proxmox()
|
||||||
if user.rtp or int(vmid) in user.allowed_vms:
|
if user.rtp or int(vmid) in user.allowed_vms:
|
||||||
vm = VM(vmid)
|
vm = VM(vmid)
|
||||||
vm_dict = vm.info
|
usage_check = user.check_usage(vm.cpu, vm.mem, 0)
|
||||||
vm_dict['vmid'] = vmid
|
|
||||||
vm_dict['config'] = vm.config
|
|
||||||
vm_dict['node'] = vm.node
|
|
||||||
vm_dict['disks'] = vm.get_disks()
|
|
||||||
vm_dict['iso'] = vm.get_iso()
|
|
||||||
vm_dict['interfaces'] = []
|
|
||||||
for interface in vm.get_interfaces():
|
|
||||||
vm_dict['interfaces'].append(
|
|
||||||
[interface[0],
|
|
||||||
get_ip_for_mac(starrs, interface[1])])
|
|
||||||
vm_dict['expire'] = get_vm_expire(
|
|
||||||
db, vmid, app.config['VM_EXPIRE_MONTHS']).strftime('%m/%d/%Y')
|
|
||||||
usage_check = user.check_usage(vm_dict['config']['cores'],
|
|
||||||
vm_dict['config']['memory'], 0)
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'vm_details.html',
|
'vm_details.html',
|
||||||
user=user,
|
user=user,
|
||||||
vm=vm_dict,
|
vm=vm,
|
||||||
usage=user.usage,
|
usage=user.usage,
|
||||||
limits=user.limits,
|
limits=user.limits,
|
||||||
usage_check=usage_check)
|
usage_check=usage_check)
|
||||||
|
@ -338,8 +324,9 @@ def vm_renew(vmid):
|
||||||
if user.rtp or int(vmid) in user.allowed_vms:
|
if user.rtp or int(vmid) in user.allowed_vms:
|
||||||
vm = VM(vmid)
|
vm = VM(vmid)
|
||||||
renew_vm_expire(db, vmid, app.config['VM_EXPIRE_MONTHS'])
|
renew_vm_expire(db, vmid, app.config['VM_EXPIRE_MONTHS'])
|
||||||
for interface in vm.get_interfaces():
|
for interface in vm.interfaces:
|
||||||
renew_ip(starrs, get_ip_for_mac(starrs, interface[1]))
|
if interface[2] != 'No IP':
|
||||||
|
renew_ip(starrs, interface[2])
|
||||||
return '', 200
|
return '', 200
|
||||||
else:
|
else:
|
||||||
return '', 403
|
return '', 403
|
||||||
|
@ -384,6 +371,22 @@ def delete(vmid):
|
||||||
return '', 403
|
return '', 403
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/vm/<string:vmid>/boot_order", methods=['POST'])
|
||||||
|
@auth.oidc_auth
|
||||||
|
def boot_order(vmid):
|
||||||
|
user = User(session['userinfo']['preferred_username'])
|
||||||
|
proxmox = connect_proxmox()
|
||||||
|
if user.rtp or int(vmid) in user.allowed_vms:
|
||||||
|
boot_order = []
|
||||||
|
for key, value in request.form.items():
|
||||||
|
boot_order.append(value)
|
||||||
|
vm = VM(vmid)
|
||||||
|
vm.set_boot_order(boot_order)
|
||||||
|
return '', 200
|
||||||
|
else:
|
||||||
|
return '', 403
|
||||||
|
|
||||||
|
|
||||||
@app.route("/vm/create", methods=['GET', 'POST'])
|
@app.route("/vm/create", methods=['GET', 'POST'])
|
||||||
@auth.oidc_auth
|
@auth.oidc_auth
|
||||||
def create():
|
def create():
|
||||||
|
@ -414,7 +417,10 @@ def create():
|
||||||
iso = "{}:iso/{}".format(app.config['PROXMOX_ISO_STORAGE'],
|
iso = "{}:iso/{}".format(app.config['PROXMOX_ISO_STORAGE'],
|
||||||
iso)
|
iso)
|
||||||
if not user.rtp:
|
if not user.rtp:
|
||||||
|
if template == 'none':
|
||||||
usage_check = user.check_usage(0, 0, disk)
|
usage_check = user.check_usage(0, 0, disk)
|
||||||
|
else:
|
||||||
|
usage_check = user.check_usage(cores, memory, disk)
|
||||||
username = user.name
|
username = user.name
|
||||||
else:
|
else:
|
||||||
usage_check = None
|
usage_check = None
|
||||||
|
|
|
@ -392,6 +392,8 @@ $("#create-vm").click(function(){
|
||||||
const template = document.getElementById('template').value;
|
const template = document.getElementById('template').value;
|
||||||
const iso = document.getElementById('iso').value;
|
const iso = document.getElementById('iso').value;
|
||||||
const user = document.getElementById('user');
|
const user = document.getElementById('user');
|
||||||
|
const max_cpu = $(this).data('max_cpu');
|
||||||
|
const max_mem = $(this).data('max_mem');
|
||||||
const max_disk = $(this).data('max_disk');
|
const max_disk = $(this).data('max_disk');
|
||||||
var disk = document.getElementById('disk').value;
|
var disk = document.getElementById('disk').value;
|
||||||
fetch(`/template/${template}/disk`, {
|
fetch(`/template/${template}/disk`, {
|
||||||
|
@ -407,6 +409,10 @@ $("#create-vm").click(function(){
|
||||||
if (name && disk) {
|
if (name && disk) {
|
||||||
if (disk > max_disk) {
|
if (disk > max_disk) {
|
||||||
swal("Uh oh...", `You do not have enough disk resources available! Please lower the VM disk size to ${max_disk}GB or lower.`, "error");
|
swal("Uh oh...", `You do not have enough disk resources available! Please lower the VM disk size to ${max_disk}GB or lower.`, "error");
|
||||||
|
} else if (template != 'none' && cores > max_cpu) {
|
||||||
|
swal("Uh oh...", `You do not have enough CPU resources available! Please lower the VM cores to ${max_cpu} or lower.`, "error");
|
||||||
|
} else if (template != 'none' && mem/1024 > max_mem) {
|
||||||
|
swal("Uh oh...", `You do not have enough memory resources available! Please lower the VM memory to ${max_mem}GB or lower.`, "error");
|
||||||
} else {
|
} else {
|
||||||
fetch(`/hostname/${name}`, {
|
fetch(`/hostname/${name}`, {
|
||||||
credentials: 'same-origin',
|
credentials: 'same-origin',
|
||||||
|
@ -942,3 +948,84 @@ $(".edit-template").click(function(){
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#edit-boot-order").click(function(){
|
||||||
|
const vmid = $(this).data('vmid');
|
||||||
|
const vmname = $(this).data('vmname');
|
||||||
|
const boot_order = $(this).data('boot_order');
|
||||||
|
var options = document.createElement('div');
|
||||||
|
for (i = 0; i < boot_order.length; i++) {
|
||||||
|
text = document.createElement('span');
|
||||||
|
text.innerHTML = `${i + 1}. `;
|
||||||
|
options.append(text);
|
||||||
|
var entry = document.createElement('select');
|
||||||
|
entry.setAttribute("id", `boot-order-${i + 1}`);
|
||||||
|
for (j = 0; j < boot_order.length; j++) {
|
||||||
|
entry.appendChild(new Option(boot_order[j], boot_order[j]));
|
||||||
|
}
|
||||||
|
entry.selectedIndex = i;
|
||||||
|
entry.setAttribute('style', 'width: 85px');
|
||||||
|
options.append(entry);
|
||||||
|
options.append(document.createElement('br'));
|
||||||
|
}
|
||||||
|
swal({
|
||||||
|
title: `Select the new boot order for ${vmname} (full shutdown required for settings to take effect):`,
|
||||||
|
content: options,
|
||||||
|
buttons: {
|
||||||
|
cancel: {
|
||||||
|
text: "Cancel",
|
||||||
|
visible: true,
|
||||||
|
closeModal: true,
|
||||||
|
},
|
||||||
|
confirm: {
|
||||||
|
text: "Submit",
|
||||||
|
closeModal: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((willChange) => {
|
||||||
|
if (willChange) {
|
||||||
|
var data = new FormData();
|
||||||
|
for (k = 0; k < boot_order.length; k++) {
|
||||||
|
e = document.getElementById(`boot-order-${k + 1}`);
|
||||||
|
data.append(`${k + 1}`, e.options[e.selectedIndex].value);
|
||||||
|
}
|
||||||
|
fetch(`/vm/${vmid}/boot_order`, {
|
||||||
|
credentials: 'same-origin',
|
||||||
|
method: 'post',
|
||||||
|
body: data
|
||||||
|
}).then((response) => {
|
||||||
|
return swal(`Now applying the new boot order to ${vmname}!`, {
|
||||||
|
icon: "success",
|
||||||
|
buttons: {
|
||||||
|
ok: {
|
||||||
|
text: "OK",
|
||||||
|
closeModal: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).then(() => {
|
||||||
|
window.location = `/vm/${vmid}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
if (err) {
|
||||||
|
swal("Uh oh...", `Unable to change the boot order for ${vmname}. Please try again later.`, "error");
|
||||||
|
} else {
|
||||||
|
swal.stopLoading();
|
||||||
|
swal.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('focus click', "[id^=boot-order-]", function() {
|
||||||
|
previous = $(this).val();
|
||||||
|
}).on('change', "[id^=boot-order-]", function() {
|
||||||
|
current = $(this).val();
|
||||||
|
id = $(this).attr("id");
|
||||||
|
$("[id^=boot-order-]").each(function() {
|
||||||
|
if ($(this).attr("id") != id && $(this).val() == current) {
|
||||||
|
$(this).val(previous);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -98,15 +98,13 @@ def process_expiring_vms_task():
|
||||||
expiring_vms = []
|
expiring_vms = []
|
||||||
vms = user.vms
|
vms = user.vms
|
||||||
for vm in vms:
|
for vm in vms:
|
||||||
vmid = vm['vmid']
|
vm = VM(vm['vmid'])
|
||||||
expire = get_vm_expire(db, vmid,
|
days = (vm.expire - datetime.date.today()).days
|
||||||
app.config['VM_EXPIRE_MONTHS'])
|
|
||||||
days = (expire - datetime.date.today()).days
|
|
||||||
if days in [10, 7, 3, 1, 0]:
|
if days in [10, 7, 3, 1, 0]:
|
||||||
name = VM(vmid).config['name']
|
name = vm.name
|
||||||
expiring_vms.append([name, days])
|
expiring_vms.append([vm.name, days])
|
||||||
if days == 0:
|
if days == 0:
|
||||||
VM(vmid).stop()
|
vm.stop()
|
||||||
if expiring_vms:
|
if expiring_vms:
|
||||||
send_vm_expire_email('com6056', expiring_vms)
|
send_vm_expire_email('com6056', expiring_vms)
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<button class="btn btn-success" id="create-vm" name="create" data-max_disk="{{ limits['disk'] - usage['disk'] }}">CREATE</button>
|
<button class="btn btn-success" id="create-vm" name="create" data-max_cpu="{{ limits['cpu'] - usage['cpu'] }}" data-max_mem="{{ limits['mem'] - usage['mem'] }}" data-max_disk="{{ limits['disk'] - usage['disk'] }}">CREATE</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -9,27 +9,27 @@
|
||||||
<h3 class="panel-title">Actions</h3>
|
<h3 class="panel-title">Actions</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{% if vm['qmpstatus'] == 'stopped' %}
|
{% if vm.qmpstatus == 'stopped' %}
|
||||||
{% if not usage_check %}
|
{% if not usage_check %}
|
||||||
<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" id="start-vm" name="start" data-vmid="{{ vm.id }}" data-vmname="{{ vm.name }}">START</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
Insufficient resources to start VM.
|
Insufficient resources to start VM.
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if vm['qmpstatus'] == 'suspended' or vm['qmpstatus'] == 'paused' %}
|
{% if vm.qmpstatus == 'suspended' or vm.qmpstatus == 'paused' %}
|
||||||
<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" id="resume-vm" name="resume" data-vmid="{{ vm.id }}" data-vmname="{{ vm.name }}">RESUME</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if vm['qmpstatus'] == 'running' or vm['qmpstatus'] == 'suspended' or vm['qmpstatus'] == 'paused' %}
|
{% if vm.qmpstatus == 'running' or vm.qmpstatus == 'suspended' or vm.qmpstatus == 'paused' %}
|
||||||
{% if vm['qmpstatus'] == 'running' %}
|
{% if vm.qmpstatus == 'running' %}
|
||||||
<button class="btn btn-success proxstar-actionbtn" id="console-vm" name="console" data-vmid="{{ vm['vmid'] }}" data-vmname="{{ vm['name'] }}">CONSOLE</button>
|
<button class="btn btn-success proxstar-actionbtn" id="console-vm" name="console" data-vmid="{{ vm.id }}" data-vmname="{{ vm.name }}">CONSOLE</button>
|
||||||
<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" id="suspend-vm" name="suspend" data-vmid="{{ vm.id }}" data-vmname="{{ vm.name }}">SUSPEND</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<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" id="shutdown-vm" name="shutdown" data-vmid="{{ vm.id }}" data-vmname="{{ vm.name }}">SHUTDOWN</button>
|
||||||
<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" id="stop-vm" name="stop" data-vmid="{{ vm.id }}" data-vmname="{{ vm.name }}">STOP</button>
|
||||||
<button class="btn btn-warning proxstar-actionbtn" id="reset-vm" name="reset" data-vmid="{{ vm['vmid'] }}" data-vmname="{{ vm['name'] }}">RESET</button>
|
<button class="btn btn-warning proxstar-actionbtn" id="reset-vm" name="reset" data-vmid="{{ vm.id }}" data-vmname="{{ vm.name }}">RESET</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if vm['qmpstatus'] == 'stopped' %}
|
{% if vm.qmpstatus == 'stopped' %}
|
||||||
<button class="btn btn-danger proxstar-actionbtn" id="delete-vm" name="delete" data-vmid="{{ vm['vmid'] }}" data-vmname="{{ vm['name'] }}">DELETE</button>
|
<button class="btn btn-danger proxstar-actionbtn" id="delete-vm" name="delete" data-vmid="{{ vm.id }}" data-vmname="{{ vm.name }}">DELETE</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
To delete VM, power it off.
|
To delete VM, power it off.
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -43,28 +43,35 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<ul class="nav nav-list">
|
<ul class="nav nav-list">
|
||||||
|
<li class="nav-header">Boot Order</li>
|
||||||
|
<li>
|
||||||
|
{{ vm.boot_order|join(', ') }}
|
||||||
|
<button class="btn btn-default proxstar-changebtn" id="edit-boot-order" data-vmid="{{ vm.id }}" data-vmname="{{ vm.name }}" data-boot_order="{{ vm.boot_order_json }}">
|
||||||
|
<span class="glyphicon glyphicon-cog"></span>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
<li class="nav-header">Interfaces</li>
|
<li class="nav-header">Interfaces</li>
|
||||||
{% for interface in vm['interfaces'] %}
|
{% for interface in vm.interfaces %}
|
||||||
<li>{{ interface[0] }}: {{ interface[1] }}</li>
|
<li>{{ interface[0] }}: {{ interface[2] }}</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<li class="nav-header">Disks</li>
|
<li class="nav-header">Disks</li>
|
||||||
{% for disk in vm['disks'] %}
|
{% for disk in vm.disks %}
|
||||||
<li>
|
<li>
|
||||||
{{ disk[0] }}: {{ disk[1] }}GB
|
{{ disk[0] }}: {{ disk[1] }}GB
|
||||||
<button class="btn btn-default proxstar-changebtn resize-disk" id="resize-disk" name="resize" data-vmid="{{ vm['vmid'] }}" data-disk="{{ disk[0] }}" data-usage="{{ usage['disk'] }}" data-limit="{{ limits['disk'] }}">
|
<button class="btn btn-default proxstar-changebtn resize-disk" id="resize-disk" name="resize" data-vmid="{{ vm.id }}" data-disk="{{ disk[0] }}" data-usage="{{ usage['disk'] }}" data-limit="{{ limits['disk'] }}">
|
||||||
<span class="glyphicon glyphicon-cog"></span>
|
<span class="glyphicon glyphicon-cog"></span>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<li class="nav-header">ISO</li>
|
<li class="nav-header">ISO</li>
|
||||||
<li>
|
<li>
|
||||||
{{ vm['iso'] }}
|
{{ vm.iso }}
|
||||||
{% if vm['iso'] != 'None' %}
|
{% if vm.iso != 'None' %}
|
||||||
<button class="btn btn-danger proxstar-ejectbtn" id="eject-iso" name="eject" data-vmid="{{ vm['vmid'] }}" data-iso="{{ vm['iso'] }}">
|
<button class="btn btn-danger proxstar-ejectbtn" id="eject-iso" name="eject" data-vmid="{{ vm.id }}" data-iso="{{ vm.iso }}">
|
||||||
<span class="glyphicon glyphicon-eject"></span>
|
<span class="glyphicon glyphicon-eject"></span>
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<button class="btn btn-default proxstar-changebtn" id="change-iso" name="change" data-vmid="{{ vm['vmid'] }}" data-iso="{{ vm['iso'] }}">
|
<button class="btn btn-default proxstar-changebtn" id="change-iso" name="change" data-vmid="{{ vm.id }}" data-iso="{{ vm.iso }}">
|
||||||
<span class="glyphicon glyphicon-cog"></span>
|
<span class="glyphicon glyphicon-cog"></span>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
@ -80,49 +87,49 @@
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<dl class="dl-horizontal">
|
<dl class="dl-horizontal">
|
||||||
<dt>Name</dt>
|
<dt>Name</dt>
|
||||||
<dd>{{ vm['name'] }}</dd>
|
<dd>{{ vm.name }}</dd>
|
||||||
<dt>DNS Name</dt>
|
<dt>DNS Name</dt>
|
||||||
<dd>{{ vm['name'] }}.csh.rit.edu</dd>
|
<dd>{{ vm.name }}.csh.rit.edu</dd>
|
||||||
<dt>ID</dt>
|
<dt>ID</dt>
|
||||||
<dd>{{ vm['vmid'] }}</dd>
|
<dd>{{ vm.id }}</dd>
|
||||||
<dt>Status</dt>
|
<dt>Status</dt>
|
||||||
<dd>{{ vm['qmpstatus'] }}</dd>
|
<dd>{{ vm.qmpstatus }}</dd>
|
||||||
<dt>Node</dt>
|
<dt>Node</dt>
|
||||||
<dd>{{ vm['node'] }}</dd>
|
<dd>{{ vm.node }}</dd>
|
||||||
<dt>Cores</dt>
|
<dt>Cores</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{{ vm['config']['cores'] * vm['config'].get('sockets', 1) }}
|
{{ vm.cpu }}
|
||||||
{% if vm['qmpstatus'] == 'running' or vm['qmpstatus'] == 'suspended' or vm['qmpstatus'] == 'paused' %}
|
{% if vm.qmpstatus == 'running' or vm.qmpstatus == 'suspended' or vm.qmpstatus == 'paused' %}
|
||||||
<button class="btn btn-default proxstar-changebtn" id="change-cores" data-vmid="{{ vm['vmid'] }}" data-usage="{{ usage['cpu'] - (vm['config']['cores'] * vm['config'].get('sockets', 1)) }}" data-limit="{{ limits['cpu'] }}">
|
<button class="btn btn-default proxstar-changebtn" id="change-cores" data-vmid="{{ vm.id }}" data-usage="{{ usage['cpu'] - vm.cpu }}" data-limit="{{ limits['cpu'] }}">
|
||||||
<span class="glyphicon glyphicon-cog"></span>
|
<span class="glyphicon glyphicon-cog"></span>
|
||||||
</button>
|
</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<button class="btn btn-default proxstar-changebtn" id="change-cores" data-vmid="{{ vm['vmid'] }}" data-usage=0 data-limit="{{ limits['cpu'] }}">
|
<button class="btn btn-default proxstar-changebtn" id="change-cores" data-vmid="{{ vm.id }}" data-usage=0 data-limit="{{ limits['cpu'] }}">
|
||||||
<span class="glyphicon glyphicon-cog"></span>
|
<span class="glyphicon glyphicon-cog"></span>
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</dd>
|
</dd>
|
||||||
<dt>Memory</dt>
|
<dt>Memory</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{% if vm['config']['memory'] < 1024 %}
|
{% if vm.mem < 1024 %}
|
||||||
{{ vm['config']['memory'] }}MB
|
{{ vm.mem }}MB
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ vm['config']['memory'] // 1024 }}GB
|
{{ vm.mem // 1024 }}GB
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if vm['qmpstatus'] == 'running' or vm['qmpstatus'] == 'suspended' or vm['qmpstatus'] == 'paused' %}
|
{% if vm.qmpstatus == 'running' or vm.qmpstatus == 'suspended' or vm.qmpstatus == 'paused' %}
|
||||||
<button class="btn btn-default proxstar-changebtn" id="change-mem" data-vmid="{{ vm['vmid'] }}" data-usage="{{ usage['mem'] - vm['config']['memory'] // 1024 }}" data-limit="{{ limits['mem'] }}">
|
<button class="btn btn-default proxstar-changebtn" id="change-mem" data-vmid="{{ vm.id }}" data-usage="{{ usage['mem'] - vm.config['memory'] // 1024 }}" data-limit="{{ limits['mem'] }}">
|
||||||
<span class="glyphicon glyphicon-cog"></span>
|
<span class="glyphicon glyphicon-cog"></span>
|
||||||
</button>
|
</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<button class="btn btn-default proxstar-changebtn" id="change-mem" data-vmid="{{ vm['vmid'] }}" data-usage=0 data-limit="{{ limits['mem'] }}">
|
<button class="btn btn-default proxstar-changebtn" id="change-mem" data-vmid="{{ vm.id }}" data-usage=0 data-limit="{{ limits['mem'] }}">
|
||||||
<span class="glyphicon glyphicon-cog"></span>
|
<span class="glyphicon glyphicon-cog"></span>
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</dd>
|
</dd>
|
||||||
<dt>Expiration</dt>
|
<dt>Expiration</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{{ vm['expire'] }}
|
{{ vm.expire.strftime('%m/%d/%Y') }}
|
||||||
<button class="btn btn-success proxstar-renewbtn" id="renew-vm" name="renew" data-vmid="{{ vm['vmid'] }}" data-vmname="{{ vm['name'] }}">
|
<button class="btn btn-success proxstar-renewbtn" id="renew-vm" name="renew" data-vmid="{{ vm.id }}" data-vmname="{{ vm.name }}">
|
||||||
<span class="glyphicon glyphicon-plus"></span>
|
<span class="glyphicon glyphicon-plus"></span>
|
||||||
</button>
|
</button>
|
||||||
</dd>
|
</dd>
|
||||||
|
|
|
@ -76,7 +76,7 @@ class User(object):
|
||||||
if vm.status == 'running' or vm.status == 'paused':
|
if vm.status == 'running' or vm.status == 'paused':
|
||||||
usage['cpu'] += int(vm.cpu * vm.config.get('sockets', 1))
|
usage['cpu'] += int(vm.cpu * vm.config.get('sockets', 1))
|
||||||
usage['mem'] += (int(vm.mem) / 1024)
|
usage['mem'] += (int(vm.mem) / 1024)
|
||||||
for disk in vm.get_disks():
|
for disk in vm.disks:
|
||||||
usage['disk'] += int(disk[1])
|
usage['disk'] += int(disk[1])
|
||||||
return usage
|
return usage
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
import time
|
import time
|
||||||
from proxstar.util import *
|
import json
|
||||||
|
from proxstar import db, starrs
|
||||||
|
from proxstar.db import get_vm_expire
|
||||||
|
from proxstar.util import lazy_property
|
||||||
|
from proxstar.starrs import get_ip_for_mac
|
||||||
from proxstar.proxmox import connect_proxmox, get_node_least_mem, get_free_vmid, get_vm_node
|
from proxstar.proxmox import connect_proxmox, get_node_least_mem, get_free_vmid, get_vm_node
|
||||||
|
from flask import current_app as app
|
||||||
|
|
||||||
|
|
||||||
class VM(object):
|
class VM(object):
|
||||||
|
@ -13,7 +18,7 @@ class VM(object):
|
||||||
|
|
||||||
@lazy_property
|
@lazy_property
|
||||||
def cpu(self):
|
def cpu(self):
|
||||||
return self.config['cores']
|
return self.config['cores'] * self.config.get('sockets', 1)
|
||||||
|
|
||||||
@lazy_property
|
@lazy_property
|
||||||
def mem(self):
|
def mem(self):
|
||||||
|
@ -40,7 +45,8 @@ class VM(object):
|
||||||
|
|
||||||
def set_cpu(self, cores):
|
def set_cpu(self, cores):
|
||||||
proxmox = connect_proxmox()
|
proxmox = connect_proxmox()
|
||||||
proxmox.nodes(self.node).qemu(self.id).config.put(cores=cores)
|
proxmox.nodes(self.node).qemu(self.id).config.put(
|
||||||
|
cores=cores, sockets=1)
|
||||||
|
|
||||||
def set_mem(self, mem):
|
def set_mem(self, mem):
|
||||||
proxmox = connect_proxmox()
|
proxmox = connect_proxmox()
|
||||||
|
@ -80,7 +86,39 @@ class VM(object):
|
||||||
proxmox = connect_proxmox()
|
proxmox = connect_proxmox()
|
||||||
return proxmox.nodes(self.node).qemu(self.id).config.get()
|
return proxmox.nodes(self.node).qemu(self.id).config.get()
|
||||||
|
|
||||||
def get_interfaces(self):
|
@lazy_property
|
||||||
|
def boot_order(self):
|
||||||
|
boot_order_lookup = {
|
||||||
|
'a': 'Floppy',
|
||||||
|
'c': 'Hard Disk',
|
||||||
|
'd': 'CD-ROM',
|
||||||
|
'n': 'Network'
|
||||||
|
}
|
||||||
|
raw_boot_order = self.config.get('boot', 'cdn')
|
||||||
|
boot_order = []
|
||||||
|
for i in range(0, len(raw_boot_order)):
|
||||||
|
boot_order.append(boot_order_lookup[raw_boot_order[i]])
|
||||||
|
return boot_order
|
||||||
|
|
||||||
|
@lazy_property
|
||||||
|
def boot_order_json(self):
|
||||||
|
return json.dumps(self.boot_order)
|
||||||
|
|
||||||
|
def set_boot_order(self, boot_order):
|
||||||
|
proxmox = connect_proxmox()
|
||||||
|
boot_order_lookup = {
|
||||||
|
'Floppy': 'a',
|
||||||
|
'Hard Disk': 'c',
|
||||||
|
'CD-ROM': 'd',
|
||||||
|
'Network': 'n'
|
||||||
|
}
|
||||||
|
raw_boot_order = ''
|
||||||
|
for i in range(0, len(boot_order)):
|
||||||
|
raw_boot_order += boot_order_lookup[boot_order[i]]
|
||||||
|
proxmox.nodes(self.node).qemu(self.id).config.put(boot=raw_boot_order)
|
||||||
|
|
||||||
|
@lazy_property
|
||||||
|
def interfaces(self):
|
||||||
interfaces = []
|
interfaces = []
|
||||||
for key, val in self.config.items():
|
for key, val in self.config.items():
|
||||||
if 'net' in key:
|
if 'net' in key:
|
||||||
|
@ -90,7 +128,8 @@ class VM(object):
|
||||||
mac = mac[0].split('=')[1]
|
mac = mac[0].split('=')[1]
|
||||||
else:
|
else:
|
||||||
mac = mac[1].split('=')[1]
|
mac = mac[1].split('=')[1]
|
||||||
interfaces.append([key, mac])
|
ip = get_ip_for_mac(starrs, mac)
|
||||||
|
interfaces.append([key, mac, ip])
|
||||||
interfaces = sorted(interfaces, key=lambda x: x[0])
|
interfaces = sorted(interfaces, key=lambda x: x[0])
|
||||||
return interfaces
|
return interfaces
|
||||||
|
|
||||||
|
@ -109,7 +148,8 @@ class VM(object):
|
||||||
disk_size = split.split('=')[1].rstrip('G')
|
disk_size = split.split('=')[1].rstrip('G')
|
||||||
return disk_size
|
return disk_size
|
||||||
|
|
||||||
def get_disks(self):
|
@lazy_property
|
||||||
|
def disks(self):
|
||||||
disks = []
|
disks = []
|
||||||
for key, val in self.config.items():
|
for key, val in self.config.items():
|
||||||
valid_disk_types = ['virtio', 'ide', 'sata', 'scsi']
|
valid_disk_types = ['virtio', 'ide', 'sata', 'scsi']
|
||||||
|
@ -123,7 +163,8 @@ class VM(object):
|
||||||
disks = sorted(disks, key=lambda x: x[0])
|
disks = sorted(disks, key=lambda x: x[0])
|
||||||
return disks
|
return disks
|
||||||
|
|
||||||
def get_iso(self):
|
@lazy_property
|
||||||
|
def iso(self):
|
||||||
if self.config.get('ide2'):
|
if self.config.get('ide2'):
|
||||||
if self.config['ide2'].split(',')[0] == 'none':
|
if self.config['ide2'].split(',')[0] == 'none':
|
||||||
iso = 'None'
|
iso = 'None'
|
||||||
|
@ -154,6 +195,10 @@ class VM(object):
|
||||||
proxmox.nodes(self.node).qemu(self.id).resize.put(
|
proxmox.nodes(self.node).qemu(self.id).resize.put(
|
||||||
disk=disk, size="+{}G".format(size))
|
disk=disk, size="+{}G".format(size))
|
||||||
|
|
||||||
|
@lazy_property
|
||||||
|
def expire(self):
|
||||||
|
return get_vm_expire(db, self.id, app.config['VM_EXPIRE_MONTHS'])
|
||||||
|
|
||||||
|
|
||||||
def create_vm(proxmox, user, name, cores, memory, disk, iso):
|
def create_vm(proxmox, user, name, cores, memory, disk, iso):
|
||||||
node = proxmox.nodes(get_node_least_mem(proxmox))
|
node = proxmox.nodes(get_node_least_mem(proxmox))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue