add ability to change boot order, a lot more cleanup from conversion to classes

This commit is contained in:
Jordan Rodgers 2018-03-18 22:18:20 -04:00
parent cefe605bb9
commit 64b8d3983e
7 changed files with 217 additions and 74 deletions

View file

@ -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

View file

@ -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);
}
});
});

View file

@ -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)

View file

@ -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>

View file

@ -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>

View file

@ -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

View file

@ -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))