convert all vm and user operations to objects, lazy load some attributes, clean up some unneeded code/imports, sort rtp view before displaying

This commit is contained in:
Jordan Rodgers 2018-02-28 03:12:18 -05:00
parent bea806e964
commit 06920e1216
11 changed files with 391 additions and 350 deletions

View file

@ -2,16 +2,17 @@ import os
import time
import psutil
import atexit
import psycopg2
import subprocess
from rq import Queue
from redis import Redis
from rq_scheduler import Scheduler
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from werkzeug.contrib.cache import SimpleCache
from flask_pyoidc.flask_pyoidc import OIDCAuthentication
from flask import Flask, render_template, request, redirect, send_from_directory, session
from flask import Flask, render_template, request, redirect, session
from proxstar.db import *
from proxstar.vm import VM
from proxstar.vnc import *
from proxstar.util import *
from proxstar.tasks import *
@ -48,8 +49,6 @@ while retry < 5:
retry += 1
time.sleep(2)
cache = SimpleCache()
redis_conn = Redis(app.config['REDIS_HOST'], app.config['REDIS_PORT'])
q = Queue(connection=redis_conn)
scheduler = Scheduler(connection=redis_conn)
@ -82,25 +81,27 @@ if 'cleanup_vnc' not in scheduler:
func=cleanup_vnc_task,
interval=3600)
from proxstar.user import User
@app.route("/")
@app.route("/user/<string:user_view>")
@auth.oidc_auth
def list_vms(user_view=None):
user = build_user_dict(session, db)
user = User(session['userinfo']['preferred_username'])
rtp_view = False
proxmox = connect_proxmox()
if user_view and not user['rtp']:
if user_view and not user.rtp:
return '', 403
elif user_view and user['rtp']:
vms = get_vms_for_user(proxmox, db, user_view)
elif user_view and user.rtp:
vms = User(user_view).vms
rtp_view = user_view
elif user['rtp']:
elif user.rtp:
vms = get_pool_cache(db)
rtp_view = True
else:
if user['active']:
vms = get_vms_for_user(proxmox, db, user['username'])
if user.active:
vms = user.vms
else:
vms = 'INACTIVE'
return render_template(
@ -130,35 +131,31 @@ def hostname(name):
@app.route("/vm/<string:vmid>")
@auth.oidc_auth
def vm_details(vmid):
user = build_user_dict(session, db)
user = User(session['userinfo']['preferred_username'])
proxmox = connect_proxmox()
if user['rtp'] or int(vmid) in get_user_allowed_vms(
proxmox, db, user['username']):
vm = get_vm(proxmox, vmid)
vm['vmid'] = vmid
vm['config'] = get_vm_config(proxmox, vmid)
vm['node'] = get_vm_node(proxmox, vmid)
vm['disks'] = get_vm_disks(proxmox, vmid, config=vm['config'])
vm['iso'] = get_vm_iso(proxmox, vmid, config=vm['config'])
vm['interfaces'] = []
for interface in get_vm_interfaces(
proxmox, vm['vmid'], config=vm['config']):
vm['interfaces'].append(
if user.rtp or int(vmid) in user.allowed_vms:
vm = VM(vmid)
vm_dict = vm.info
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['expire'] = get_vm_expire(
vm_dict['expire'] = get_vm_expire(
db, vmid, app.config['VM_EXPIRE_MONTHS']).strftime('%m/%d/%Y')
usage = get_user_usage(proxmox, db, user['username'])
limits = get_user_usage_limits(db, user['username'])
usage_check = check_user_usage(proxmox, db, user['username'],
vm['config']['cores'],
vm['config']['memory'], 0)
usage_check = user.check_usage(vm_dict['config']['cores'],
vm_dict['config']['memory'], 0)
return render_template(
'vm_details.html',
user=user,
vm=vm,
usage=usage,
limits=limits,
vm=vm_dict,
usage=user.usage,
limits=user.limits,
usage_check=usage_check)
else:
return '', 403
@ -167,18 +164,27 @@ def vm_details(vmid):
@app.route("/vm/<string:vmid>/power/<string:action>", methods=['POST'])
@auth.oidc_auth
def vm_power(vmid, action):
user = build_user_dict(session, db)
user = User(session['userinfo']['preferred_username'])
proxmox = connect_proxmox()
if user['rtp'] or int(vmid) in get_user_allowed_vms(
proxmox, db, user['username']):
if user.rtp or int(vmid) in user.allowed_vms:
vm = VM(vmid)
if action == 'start':
config = get_vm_config(proxmox, vmid)
usage_check = check_user_usage(proxmox, db, user['username'],
config['cores'], config['memory'],
config = vm.config
usage_check = user.check_usage(config['cores'], config['memory'],
0)
if usage_check:
return usage_check
change_vm_power(proxmox, vmid, action)
vm.start()
elif action == 'stop':
vm.stop()
elif action == 'shutdown':
vm.shutdown()
elif action == 'reset':
vm.reset()
elif action == 'suspend':
vm.suspend()
elif action == 'resume':
vm.resume()
return '', 200
else:
return '', 403
@ -187,13 +193,13 @@ def vm_power(vmid, action):
@app.route("/console/vm/<string:vmid>", methods=['POST'])
@auth.oidc_auth
def vm_console(vmid):
user = build_user_dict(session, db)
user = User(session['userinfo']['preferred_username'])
proxmox = connect_proxmox()
if user['rtp'] or int(vmid) in get_user_allowed_vms(
proxmox, db, user['username']):
if user.rtp or int(vmid) in user.allowed_vms:
vm = VM(vmid)
port = str(5900 + int(vmid))
token = add_vnc_target(port)
node = "{}.csh.rit.edu".format(get_vm_node(proxmox, vmid))
node = "{}.csh.rit.edu".format(vm.node)
tunnel = next((tunnel for tunnel in ssh_tunnels
if tunnel.local_bind_port == int(port)), None)
if tunnel:
@ -207,7 +213,7 @@ def vm_console(vmid):
node, vmid))
tunnel = start_ssh_tunnel(node, port)
ssh_tunnels.append(tunnel)
start_vm_vnc(proxmox, vmid, port)
vm.start_vnc(port)
else:
print("Tunnel already exists to {} for VM {}.".format(
node, vmid))
@ -215,7 +221,7 @@ def vm_console(vmid):
print("Creating SSH tunnel to {} for VM {}.".format(node, vmid))
tunnel = start_ssh_tunnel(node, port)
ssh_tunnels.append(tunnel)
start_vm_vnc(proxmox, vmid, port)
vm.start_vnc(port)
return token, 200
else:
return '', 403
@ -224,22 +230,19 @@ def vm_console(vmid):
@app.route("/vm/<string:vmid>/cpu/<int:cores>", methods=['POST'])
@auth.oidc_auth
def vm_cpu(vmid, cores):
user = build_user_dict(session, db)
user = User(session['userinfo']['preferred_username'])
proxmox = connect_proxmox()
if user['rtp'] or int(vmid) in get_user_allowed_vms(
proxmox, db, user['username']):
cur_cores = get_vm_config(proxmox, vmid)['cores']
if user.rtp or int(vmid) in user.allowed_vms:
vm = VM(vmid)
cur_cores = vm.cpu
if cores >= cur_cores:
status = get_vm(proxmox, vmid)['qmpstatus']
if status == 'running' or status == 'paused':
usage_check = check_user_usage(proxmox, db, user['username'],
cores - cur_cores, 0, 0)
if vm.qmpstatus == 'running' or vm.qmpstatus == 'paused':
usage_check = user.check_usage(cores - cur_cores, 0, 0)
else:
usage_check = check_user_usage(proxmox, db, user['username'],
cores, 0, 0)
usage_check = user.check_usage(cores, 0, 0)
if usage_check:
return usage_check
change_vm_cpu(proxmox, vmid, cores)
vm.set_cpu(cores)
return '', 200
else:
return '', 403
@ -248,22 +251,19 @@ def vm_cpu(vmid, cores):
@app.route("/vm/<string:vmid>/mem/<int:mem>", methods=['POST'])
@auth.oidc_auth
def vm_mem(vmid, mem):
user = build_user_dict(session, db)
user = User(session['userinfo']['preferred_username'])
proxmox = connect_proxmox()
if user['rtp'] or int(vmid) in get_user_allowed_vms(
proxmox, db, user['username']):
cur_mem = get_vm_config(proxmox, vmid)['memory'] // 1024
if user.rtp or int(vmid) in user.allowed_vms:
vm = VM(vmid)
cur_mem = vm.mem // 1024
if mem >= cur_mem:
status = get_vm(proxmox, vmid)['qmpstatus']
if status == 'running' or status == 'paused':
usage_check = check_user_usage(proxmox, db, user['username'],
0, mem - cur_mem, 0)
if vm.qmpstatus == 'running' or vm.qmpstatus == 'paused':
usage_check = user.check_usage(0, mem - cur_mem, 0)
else:
usage_check = check_user_usage(proxmox, db, user['username'],
0, mem, 0)
usage_check = user.check_usage(0, mem, 0)
if usage_check:
return usage_check
change_vm_mem(proxmox, vmid, mem * 1024)
vm.set_mem(mem * 1024)
return '', 200
else:
return '', 403
@ -272,15 +272,15 @@ def vm_mem(vmid, mem):
@app.route("/vm/<string:vmid>/disk/<string:disk>/<int:size>", methods=['POST'])
@auth.oidc_auth
def vm_disk(vmid, disk, size):
user = build_user_dict(session, db)
user = User(session['userinfo']['preferred_username'])
proxmox = connect_proxmox()
if user['rtp'] or int(vmid) in get_user_allowed_vms(
proxmox, db, user['username']):
cur_cores = get_vm_config(proxmox, vmid)['cores']
usage_check = check_user_usage(proxmox, db, user['username'], 0, 0, size)
if user.rtp or int(vmid) in user.allowed_vms:
vm = VM(vmid)
cur_cores = vm.cpu
usage_check = user.check_usage(0, 0, size)
if usage_check:
return usage_check
resize_vm_disk(proxmox, vmid, disk, size)
vm.resize_disk(disk, size)
return '', 200
else:
return '', 403
@ -289,12 +289,12 @@ def vm_disk(vmid, disk, size):
@app.route("/vm/<string:vmid>/renew", methods=['POST'])
@auth.oidc_auth
def vm_renew(vmid):
user = build_user_dict(session, db)
user = User(session['userinfo']['preferred_username'])
proxmox = connect_proxmox()
if user['rtp'] or int(vmid) in get_user_allowed_vms(
proxmox, db, user['username']):
if user.rtp or int(vmid) in user.allowed_vms:
vm = VM(vmid)
renew_vm_expire(db, vmid, app.config['VM_EXPIRE_MONTHS'])
for interface in get_vm_interfaces(proxmox, vmid):
for interface in vm.get_interfaces():
renew_ip(starrs, get_ip_for_mac(starrs, interface[1]))
return '', 200
else:
@ -304,10 +304,11 @@ def vm_renew(vmid):
@app.route("/vm/<string:vmid>/eject", methods=['POST'])
@auth.oidc_auth
def iso_eject(vmid):
user = build_user_dict(session, db)
user = User(session['userinfo']['preferred_username'])
proxmox = connect_proxmox()
if user['rtp'] or int(vmid) in get_user_allowed_vms(proxmox, db, user):
eject_vm_iso(proxmox, vmid)
if user.rtp or int(vmid) in user.allowed_vms:
vm = VM(vmid)
vm.eject_iso()
return '', 200
else:
return '', 403
@ -316,12 +317,12 @@ def iso_eject(vmid):
@app.route("/vm/<string:vmid>/mount/<string:iso>", methods=['POST'])
@auth.oidc_auth
def iso_mount(vmid, iso):
user = build_user_dict(session, db)
user = User(session['userinfo']['preferred_username'])
proxmox = connect_proxmox()
if user['rtp'] or int(vmid) in get_user_allowed_vms(
proxmox, db, user['username']):
if user.rtp or int(vmid) in user.allowed_vms:
iso = "{}:iso/{}".format(app.config['PROXMOX_ISO_STORAGE'], iso)
mount_vm_iso(proxmox, vmid, iso)
vm = VM(vmid)
vm.mount_iso(iso)
return '', 200
else:
return '', 403
@ -330,11 +331,9 @@ def iso_mount(vmid, iso):
@app.route("/vm/<string:vmid>/delete", methods=['POST'])
@auth.oidc_auth
def delete(vmid):
user = build_user_dict(session, db)
user = User(session['userinfo']['preferred_username'])
proxmox = connect_proxmox()
if user['rtp'] or int(vmid) in get_user_allowed_vms(
proxmox, db,
user['username']) or 'rtp' in session['userinfo']['groups']:
if user.rtp or int(vmid) in user.allowed_vms:
q.enqueue(delete_vm_task, vmid)
return '', 200
else:
@ -344,23 +343,19 @@ def delete(vmid):
@app.route("/vm/create", methods=['GET', 'POST'])
@auth.oidc_auth
def create():
user = build_user_dict(session, db)
user = User(session['userinfo']['preferred_username'])
proxmox = connect_proxmox()
if user['active']:
if user.active:
if request.method == 'GET':
usage = get_user_usage(proxmox, db, user['username'])
limits = get_user_usage_limits(db, user['username'])
percents = get_user_usage_percent(proxmox, user['username'], usage,
limits)
isos = get_isos(proxmox, app.config['PROXMOX_ISO_STORAGE'])
pools = get_pools(proxmox, db)
templates = get_templates(db)
return render_template(
'create.html',
user=user,
usage=usage,
limits=limits,
percents=percents,
usage=user.usage,
limits=user.limits,
percents=user.usage_percent,
isos=isos,
pools=pools,
templates=templates)
@ -374,12 +369,12 @@ def create():
if iso != 'none':
iso = "{}:iso/{}".format(app.config['PROXMOX_ISO_STORAGE'],
iso)
if not user['rtp']:
usage_check = check_user_usage(proxmox, db, user['username'],
0, 0, disk)
if not user.rtp:
usage_check = user.check_usage(0, 0, disk)
username = user.name
else:
usage_check = None
user['username'] = request.form['user']
username = request.form['user']
if usage_check:
return usage_check
else:
@ -388,7 +383,7 @@ def create():
if template == 'none':
q.enqueue(
create_vm_task,
user['username'],
username,
name,
cores,
memory,
@ -401,7 +396,7 @@ def create():
setup_template,
template,
name,
user['username'],
username,
password,
cores,
memory,
@ -440,8 +435,8 @@ def delete_user(user):
@app.route("/settings")
@auth.oidc_auth
def settings():
user = build_user_dict(session, db)
if user['rtp']:
user = User(session['userinfo']['preferred_username'])
if user.rtp:
templates = get_templates(db)
ignored_pools = get_ignored_pools(db)
allowed_users = get_allowed_users(db)

View file

@ -123,6 +123,7 @@ def get_pool_cache(db):
pool_dict['limits'] = pool.limits
pool_dict['percents'] = pool.percents
pools.append(pool_dict)
pools = sorted(pools, key=lambda x: x['user'])
return pools
@ -204,8 +205,9 @@ def delete_allowed_user(db, user):
def set_template_info(db, template_id, name, username, password, disk):
if db.query(exists().where(Template.id == template_id,)).scalar():
template = db.query(Template).filter(Template.id == template_id,).one()
if db.query(exists().where(Template.id == template_id, )).scalar():
template = db.query(Template).filter(Template.id == template_id,
).one()
template.name = name
template.username = username
if password:

View file

@ -19,8 +19,14 @@ def is_rtp(user):
def is_active(user):
ldap = connect_ldap()
rtp_group = ldap.get_group('active')
return rtp_group.check_member(ldap.get_member(user, uid=True))
active_group = ldap.get_group('active')
return active_group.check_member(ldap.get_member(user, uid=True))
def is_current_student(user):
ldap = connect_ldap()
current_student_group = ldap.get_group('current_student')
return current_student_group.check_member(ldap.get_member(user, uid=True))
def is_user(user):

View file

@ -21,21 +21,6 @@ def connect_proxmox():
raise
def get_vms_for_user(proxmox, db, user):
pools = get_pools(proxmox, db)
if user not in pools:
if is_user(user) and not is_rtp(user):
proxmox.pools.post(poolid=user, comment='Managed by Proxstar')
else:
return []
vms = proxmox.pools(user).get()['members']
for vm in vms:
if 'name' not in vm:
vms.remove(vm)
vms = sorted(vms, key=lambda k: k['name'])
return vms
def get_vms_for_rtp(proxmox, db):
pools = []
for pool in get_pools(proxmox, db):
@ -51,13 +36,6 @@ def get_vms_for_rtp(proxmox, db):
return pools
def get_user_allowed_vms(proxmox, db, user):
allowed_vms = []
for vm in get_vms_for_user(proxmox, db, user):
allowed_vms.append(vm['vmid'])
return allowed_vms
def get_node_least_mem(proxmox):
nodes = proxmox.nodes.get()
sorted_nodes = sorted(nodes, key=lambda x: x['mem'])
@ -74,129 +52,6 @@ def get_vm_node(proxmox, vmid):
return vm['node']
def get_vm(proxmox, vmid):
node = proxmox.nodes(get_vm_node(proxmox, vmid))
return node.qemu(vmid).status.current.get()
def get_vm_config(proxmox, vmid):
node = proxmox.nodes(get_vm_node(proxmox, vmid))
return node.qemu(vmid).config.get()
def get_vm_mac(proxmox, vmid, config=None, interface='net0'):
if not config:
config = get_vm_config(proxmox, vmid)
mac = config[interface].split(',')
if 'virtio' in mac[0]:
mac = mac[0].split('=')[1]
else:
mac = mac[1].split('=')[1]
return mac
def get_vm_interfaces(proxmox, vmid, config=None):
if not config:
config = get_vm_config(proxmox, vmid)
interfaces = []
for key, val in config.items():
if 'net' in key:
mac = config[key].split(',')
valid_int_types = ['virtio', 'e1000', 'rtl8139', 'vmxnet3']
if any(int_type in mac[0] for int_type in valid_int_types):
mac = mac[0].split('=')[1]
else:
mac = mac[1].split('=')[1]
interfaces.append([key, mac])
interfaces = sorted(interfaces, key=lambda x: x[0])
return interfaces
def get_vm_disk_size(proxmox, vmid, config=None, name='virtio0'):
if not config:
config = get_vm_config(proxmox, vmid)
disk_size = config[name].split(',')
for split in disk_size:
if 'size' in split:
disk_size = split.split('=')[1].rstrip('G')
return disk_size
def get_vm_disks(proxmox, vmid, config=None):
if not config:
config = get_vm_config(proxmox, vmid)
disks = []
for key, val in config.items():
valid_disk_types = ['virtio', 'ide', 'sata', 'scsi']
if any(disk_type in key for disk_type in valid_disk_types):
if 'scsihw' not in key and 'cdrom' not in val:
disk_size = val.split(',')
for split in disk_size:
if 'size' in split:
disk_size = split.split('=')[1].rstrip('G')
disks.append([key, disk_size])
disks = sorted(disks, key=lambda x: x[0])
return disks
def get_vm_iso(proxmox, vmid, config=None):
if not config:
config = get_vm_config(proxmox, vmid)
if config.get('ide2'):
if config['ide2'].split(',')[0] == 'none':
iso = 'None'
else:
iso = config['ide2'].split(',')[0].split('/')[1]
else:
iso = 'None'
return iso
def get_user_usage(proxmox, db, user):
usage = dict()
usage['cpu'] = 0
usage['mem'] = 0
usage['disk'] = 0
if is_rtp(user):
return usage
vms = get_vms_for_user(proxmox, db, user)
for vm in vms:
config = get_vm_config(proxmox, vm['vmid'])
if 'status' in vm:
if vm['status'] == 'running' or vm['status'] == 'paused':
usage['cpu'] += int(config['cores'] * config.get('sockets', 1))
usage['mem'] += (int(config['memory']) / 1024)
for disk in get_vm_disks(proxmox, vm['vmid'], config):
usage['disk'] += int(disk[1])
return usage
def check_user_usage(proxmox, db, user, vm_cpu, vm_mem, vm_disk):
limits = get_user_usage_limits(db, user)
cur_usage = get_user_usage(proxmox, db, user)
if int(cur_usage['cpu']) + int(vm_cpu) > int(limits['cpu']):
return 'exceeds_cpu_limit'
elif int(cur_usage['mem']) + (int(vm_mem) / 1024) > int(limits['mem']):
return 'exceeds_memory_limit'
elif int(cur_usage['disk']) + int(vm_disk) > int(limits['disk']):
return 'exceeds_disk_limit'
def get_user_usage_percent(proxmox, user, usage=None, limits=None):
percents = dict()
if not usage:
usage = get_user_usage(proxmox, db, user)
if not limits:
limits = get_user_usage_limits(user)
percents['cpu'] = round(usage['cpu'] / limits['cpu'] * 100)
percents['mem'] = round(usage['mem'] / limits['mem'] * 100)
percents['disk'] = round(usage['disk'] / limits['disk'] * 100)
for resource in percents:
if percents[resource] > 100:
percents[resource] = 100
return percents
def create_vm(proxmox, user, name, cores, memory, disk, iso):
node = proxmox.nodes(get_node_least_mem(proxmox))
vmid = get_free_vmid(proxmox)
@ -214,7 +69,7 @@ def create_vm(proxmox, user, name, cores, memory, disk, iso):
retry = 0
while retry < 5:
try:
mac = get_vm_mac(proxmox, vmid)
mac = VM(vmid).get_mac()
break
except:
retry += 1
@ -222,44 +77,6 @@ def create_vm(proxmox, user, name, cores, memory, disk, iso):
return vmid, mac
def delete_vm(proxmox, vmid):
node = proxmox.nodes(get_vm_node(proxmox, vmid))
node.qemu(vmid).delete()
def change_vm_power(proxmox, vmid, action):
node = proxmox.nodes(get_vm_node(proxmox, vmid))
if action == 'start':
node.qemu(vmid).status.start.post()
elif action == 'stop':
node.qemu(vmid).status.stop.post()
elif action == 'shutdown':
node.qemu(vmid).status.shutdown.post()
elif action == 'reset':
node.qemu(vmid).status.reset.post()
elif action == 'suspend':
node.qemu(vmid).status.suspend.post()
elif action == 'resume':
node.qemu(vmid).status.resume.post()
def change_vm_cpu(proxmox, vmid, cores):
node = proxmox.nodes(get_vm_node(proxmox, vmid))
node.qemu(vmid).config.put(cores=cores)
def change_vm_mem(proxmox, vmid, mem):
node = proxmox.nodes(get_vm_node(proxmox, vmid))
node.qemu(vmid).config.put(memory=mem)
def start_vm_vnc(proxmox, vmid, port):
node = proxmox.nodes(get_vm_node(proxmox, vmid))
port = str(int(port) - 5900)
node.qemu(vmid).monitor.post(
command="change vnc 127.0.0.1:{}".format(port))
def get_isos(proxmox, storage):
isos = []
for iso in proxmox.nodes('proxmox01').storage(storage).content.get():
@ -267,16 +84,6 @@ def get_isos(proxmox, storage):
return isos
def eject_vm_iso(proxmox, vmid):
node = proxmox.nodes(get_vm_node(proxmox, vmid))
node.qemu(vmid).config.post(ide2='none,media=cdrom')
def mount_vm_iso(proxmox, vmid, iso):
node = proxmox.nodes(get_vm_node(proxmox, vmid))
node.qemu(vmid).config.post(ide2="{},media=cdrom".format(iso))
def get_pools(proxmox, db):
ignored_pools = get_ignored_pools(db)
pools = []
@ -288,15 +95,6 @@ def get_pools(proxmox, db):
return pools
def delete_user_pool(proxmox, pool):
proxmox.pools(pool).delete()
users = proxmox.access.users.get()
if any(user['userid'] == "{}@csh.rit.edu".format(pool) for user in users):
if 'rtp' not in proxmox.access.users(
"{}@csh.rit.edu".format(pool)).get()['groups']:
proxmox.access.users("{}@csh.rit.edu".format(pool)).delete()
def clone_vm(proxmox, template_id, name, pool):
node = proxmox.nodes(get_vm_node(proxmox, template_id))
newid = get_free_vmid(proxmox)
@ -311,14 +109,9 @@ def clone_vm(proxmox, template_id, name, pool):
retry = 0
while retry < 60:
try:
mac = get_vm_mac(proxmox, newid)
mac = VM(newid).get_mac()
break
except:
retry += 1
time.sleep(3)
return newid, mac
def resize_vm_disk(proxmox, vmid, disk, size):
node = proxmox.nodes(get_vm_node(proxmox, vmid))
node.qemu(vmid).resize.put(disk=disk, size="+{}G".format(size))

View file

@ -1,7 +1,3 @@
import psycopg2
from flask import current_app as app
def get_next_ip(starrs, range_name):
c = starrs.cursor()
try:

View file

@ -1004,7 +1004,7 @@
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
.c100:hover {
/*.c100:hover {
cursor: default;
}
.c100:hover > span {
@ -1018,7 +1018,7 @@
left: 0.04em;
width: 0.92em;
height: 0.92em;
}
}*/
.c100.dark {
background-color: #777777;
}

View file

@ -1,10 +1,12 @@
import os
import requests
import paramiko
import psycopg2
from flask import Flask
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from proxstar.db import *
from proxstar.vm import VM
from proxstar.util import *
from proxstar.mail import *
from proxstar.starrs import *
@ -50,12 +52,11 @@ def create_vm_task(user, name, cores, memory, disk, iso):
def delete_vm_task(vmid):
with app.app_context():
proxmox = connect_proxmox()
db = connect_db()
starrs = connect_starrs()
vmname = get_vm_config(proxmox, vmid)['name']
delete_vm(proxmox, vmid)
delete_starrs(starrs, vmname)
vm = VM(vmid)
vm.delete()
delete_starrs(starrs, vm.name)
delete_vm_expire(db, vmid)
@ -67,9 +68,10 @@ def process_expired_vms_task():
print(expired_vms)
# for vmid in expired_vms:
# vmname = get_vm_config(proxmox, vmid)['name']
# vm = VM(vmid)
# delete_vm(proxmox, starrs, vmid)
# delete_starrs(starrs, vmname)
# delete_starrs(starrs, vm.name)
# delete_vm_expire(vmid)
@ -88,10 +90,10 @@ def process_expiring_vms_task():
app.config['VM_EXPIRE_MONTHS'])
days = (expire - datetime.date.today()).days
if days in [10, 7, 3, 1, 0]:
name = get_vm_config(proxmox, vmid)['name']
name = VM(vmid).config['name']
expiring_vms.append([name, days])
if days == 0:
change_vm_power(proxmox, vmid, 'stop')
VM(vmid).stop()
if expiring_vms:
send_vm_expire_email('com6056', expiring_vms)
@ -119,14 +121,15 @@ def setup_template(template_id, name, user, password, cores, memory):
register_starrs(starrs, name, app.config['STARRS_USER'], mac, ip)
get_vm_expire(db, vmid, app.config['VM_EXPIRE_MONTHS'])
print("[{}] Setting CPU and memory.".format(name))
change_vm_cpu(proxmox, vmid, cores)
change_vm_mem(proxmox, vmid, memory)
vm = VM(vmid)
vm.set_cpu(cores)
vm.set_mem(memory)
print(
"[{}] Waiting for STARRS to propogate before starting VM.".format(
name))
time.sleep(90)
print("[{}] Starting VM.".format(name))
change_vm_power(proxmox, vmid, 'start')
vm.start()
print("[{}] Waiting for VM to start before SSHing.".format(name))
time.sleep(20)
print("[{}] Creating SSH session.".format(name))

View file

@ -27,7 +27,7 @@
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
{% if user['active'] %}
{% if user.active %}
<li>
<a href="/">
<span class="glyphicon glyphicon-th-list"></span>
@ -40,7 +40,7 @@
Create VM
</a>
</li>
{% if user['rtp'] %}
{% if user.rtp %}
<li>
<a href="/settings">
<span class="glyphicon glyphicon-cog"></span>
@ -54,14 +54,14 @@
<li class="dropdown navbar-user">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-expanded="false">
<img src="https://profiles.csh.rit.edu/image/{{ user['username'] }}"
title="{{ user['username'] }}">
{{ user['username'] }}
<img src="https://profiles.csh.rit.edu/image/{{ user.name }}"
title="{{ user.name }}">
{{ user.name }}
<span class="caret"></span>
</a>
<ul class="dropdown-menu" role="menu">
<li>
<a href="https://profiles.csh.rit.edu/user/{{ user['username'] }}">
<a href="https://profiles.csh.rit.edu/user/{{ user.name }}">
<span class="glyphicon glyphicon-user"></span>
Profile
</a>

87
proxstar/user.py Normal file
View file

@ -0,0 +1,87 @@
from proxstar import db
from proxstar.db import *
from proxstar.util import *
from proxstar.proxmox import *
class User(object):
def __init__(self, username):
self.name = username
self.active = is_active(self.name) or is_current_student(
self.name) or self.name in get_allowed_users(db)
self.rtp = is_rtp(self.name)
self.limits = get_user_usage_limits(db, self.name)
@lazy_property
def vms(self):
proxmox = connect_proxmox()
pools = get_pools(proxmox, db)
if self.name not in pools:
if is_user(self.name) and not is_rtp(self.name):
proxmox.pools.post(
poolid=self.name, comment='Managed by Proxstar')
else:
return []
vms = proxmox.pools(self.name).get()['members']
for vm in vms:
if 'name' not in vm:
vms.remove(vm)
vms = sorted(vms, key=lambda k: k['name'])
return vms
@lazy_property
def allowed_vms(self):
allowed_vms = []
for vm in self.vms:
allowed_vms.append(vm['vmid'])
return allowed_vms
@lazy_property
def usage(self):
usage = dict()
usage['cpu'] = 0
usage['mem'] = 0
usage['disk'] = 0
if self.rtp:
return usage
vms = self.vms
for vm in vms:
if 'status' in vm:
vm = VM(vm['vmid'])
if vm.status == 'running' or vm.status == 'paused':
usage['cpu'] += int(vm.cpu * vm.config.get('sockets', 1))
usage['mem'] += (int(vm.mem) / 1024)
for disk in vm.get_disks():
usage['disk'] += int(disk[1])
return usage
@lazy_property
def usage_percent(self):
percents = dict()
percents['cpu'] = round(self.usage['cpu'] / self.limits['cpu'] * 100)
percents['mem'] = round(self.usage['mem'] / self.limits['mem'] * 100)
percents['disk'] = round(
self.usage['disk'] / self.limits['disk'] * 100)
for resource in percents:
if percents[resource] > 100:
percents[resource] = 100
return percents
def check_usage(self, cpu, mem, disk):
if int(self.usage['cpu']) + int(cpu) > int(self.limits['cpu']):
return 'exceeds_cpu_limit'
elif int(self.usage['mem']) + (int(mem) / 1024) > int(
self.limits['mem']):
return 'exceeds_memory_limit'
elif int(self.usage['disk']) + int(disk) > int(self.limits['disk']):
return 'exceeds_disk_limit'
def delete(self):
proxmox.pools(self.name).delete()
users = proxmox.access.users.get()
if any(user['userid'] == "{}@csh.rit.edu".format(self.name)
for user in users):
if 'rtp' not in proxmox.access.users("{}@csh.rit.edu".format(
self.name)).get()['groups']:
proxmox.access.users("{}@csh.rit.edu".format(
self.name)).delete()

View file

@ -11,11 +11,14 @@ def gen_password(
return ''.join(random.choice(charset) for x in range(length))
def build_user_dict(session, db):
user_dict = dict()
user_dict['username'] = session['userinfo']['preferred_username']
user_dict[
'active'] = 'active' in session['userinfo']['groups'] or 'current_student' in session['userinfo']['groups'] or user_dict['username'] in get_allowed_users(
db)
user_dict['rtp'] = 'rtp' in session['userinfo']['groups']
return user_dict
def lazy_property(fn):
# Decorator that makes a property lazy-evaluated (https://stevenloria.com/lazy-properties/)
attr_name = '_lazy_' + fn.__name__
@property
def _lazy_property(self):
if not hasattr(self, attr_name):
setattr(self, attr_name, fn(self))
return getattr(self, attr_name)
return _lazy_property

156
proxstar/vm.py Normal file
View file

@ -0,0 +1,156 @@
from proxstar.util import *
from proxstar.proxmox import *
class VM(object):
def __init__(self, vmid):
self.id = vmid
@lazy_property
def name(self):
return self.config['name']
@lazy_property
def cpu(self):
return self.config['cores']
@lazy_property
def mem(self):
return self.config['memory']
@lazy_property
def status(self):
return self.info['status']
@lazy_property
def qmpstatus(self):
return self.info['qmpstatus']
@lazy_property
def node(self):
proxmox = connect_proxmox()
for vm in proxmox.cluster.resources.get(type='vm'):
if vm['vmid'] == int(self.id):
return vm['node']
def delete(self):
proxmox = connect_proxmox()
proxmox.nodes(self.node).qemu(self.id).delete()
def set_cpu(self, cores):
proxmox = connect_proxmox()
proxmox.nodes(self.node).qemu(self.id).config.put(cores=cores)
self.cpu = cores
def set_mem(self, mem):
proxmox = connect_proxmox()
proxmox.nodes(self.node).qemu(self.id).config.put(memory=mem)
self.mem = mem
def start(self):
proxmox = connect_proxmox()
proxmox.nodes(self.node).qemu(self.id).status.start.post()
def stop(self):
proxmox = connect_proxmox()
proxmox.nodes(self.node).qemu(self.id).status.stop.post()
def shutdown(self):
proxmox = connect_proxmox()
proxmox.nodes(self.node).qemu(self.id).status.shutdown.post()
def reset(self):
proxmox = connect_proxmox()
proxmox.nodes(self.node).qemu(self.id).status.reset.post()
def suspend(self):
proxmox = connect_proxmox()
proxmox.nodes(self.node).qemu(self.id).status.suspend.post()
def resume(self):
proxmox = connect_proxmox()
proxmox.nodes(self.node).qemu(self.id).status.resume.post()
@lazy_property
def info(self):
proxmox = connect_proxmox()
return proxmox.nodes(self.node).qemu(self.id).status.current.get()
@lazy_property
def config(self):
proxmox = connect_proxmox()
return proxmox.nodes(self.node).qemu(self.id).config.get()
def get_interfaces(self):
interfaces = []
for key, val in self.config.items():
if 'net' in key:
mac = self.config[key].split(',')
valid_int_types = ['virtio', 'e1000', 'rtl8139', 'vmxnet3']
if any(int_type in mac[0] for int_type in valid_int_types):
mac = mac[0].split('=')[1]
else:
mac = mac[1].split('=')[1]
interfaces.append([key, mac])
interfaces = sorted(interfaces, key=lambda x: x[0])
return interfaces
def get_mac(self, interface='net0'):
mac = self.config[interface].split(',')
if 'virtio' in mac[0]:
mac = mac[0].split('=')[1]
else:
mac = mac[1].split('=')[1]
return mac
def get_disk_size(self, name='virtio0'):
disk_size = self.config[name].split(',')
for split in disk_size:
if 'size' in split:
disk_size = split.split('=')[1].rstrip('G')
return disk_size
def get_disks(self):
disks = []
for key, val in self.config.items():
valid_disk_types = ['virtio', 'ide', 'sata', 'scsi']
if any(disk_type in key for disk_type in valid_disk_types):
if 'scsihw' not in key and 'cdrom' not in val:
disk_size = val.split(',')
for split in disk_size:
if 'size' in split:
disk_size = split.split('=')[1].rstrip('G')
disks.append([key, disk_size])
disks = sorted(disks, key=lambda x: x[0])
return disks
def get_iso(self):
if self.config.get('ide2'):
if self.config['ide2'].split(',')[0] == 'none':
iso = 'None'
else:
iso = self.config['ide2'].split(',')[0].split('/')[1]
else:
iso = 'None'
return iso
def start_vnc(self, port):
proxmox = connect_proxmox()
port = str(int(port) - 5900)
proxmox.nodes(self.node).qemu(self.id).monitor.post(
command="change vnc 127.0.0.1:{}".format(port))
def eject_iso(self):
proxmox = connect_proxmox()
proxmox.nodes(self.node).qemu(
self.id).config.post(ide2='none,media=cdrom')
def mount_iso(self, iso):
proxmox = connect_proxmox()
proxmox.nodes(self.node).qemu(
self.id).config.post(ide2="{},media=cdrom".format(iso))
def resize_disk(self, disk, size):
proxmox = connect_proxmox()
proxmox.nodes(self.node).qemu(self.id).resize.put(
disk=disk, size="+{}G".format(size))