add ldap, check if active member, create user and give console perms, retry getting mac, better handling of rtp

This commit is contained in:
Jordan Rodgers 2018-01-19 03:01:10 -05:00
parent 8161d97f21
commit cc2033f2ca
11 changed files with 136 additions and 58 deletions

View file

@ -1,5 +0,0 @@
from websockify.websocket import *
from websockify.websocketproxy import *
server = WebSocketProxy(listen_port='10000', target_port='6000')
server.start_server()

99
app.py
View file

@ -4,6 +4,7 @@ import psycopg2
import subprocess import subprocess
from db import * from db import *
from starrs import * from starrs import *
from ldapdb import *
from proxmox import * from proxmox import *
from werkzeug.contrib.cache import SimpleCache from werkzeug.contrib.cache import SimpleCache
from flask_pyoidc.flask_pyoidc import OIDCAuthentication from flask_pyoidc.flask_pyoidc import OIDCAuthentication
@ -45,6 +46,10 @@ def list_vms(user=None):
else: else:
user = session['userinfo']['preferred_username'] user = session['userinfo']['preferred_username']
vms = get_vms_for_user(proxmox, user) vms = get_vms_for_user(proxmox, user)
if active:
vms = get_vms_for_user(proxmox, user)
else:
vms = 'INACTIVE'
return render_template( return render_template(
'list_vms.html', 'list_vms.html',
username=user, username=user,
@ -80,10 +85,10 @@ def hostname(name):
def vm_details(vmid): def vm_details(vmid):
user = session['userinfo']['preferred_username'] user = session['userinfo']['preferred_username']
rtp = 'rtp' in session['userinfo']['groups'] rtp = 'rtp' in session['userinfo']['groups']
active = 'active' in session['userinfo']['groups']
proxmox = connect_proxmox() proxmox = connect_proxmox()
starrs = connect_starrs() starrs = connect_starrs()
if int(vmid) in get_user_allowed_vms( if 'rtp' in session['userinfo']['groups'] or int(vmid) in get_user_allowed_vms(proxmox, user):
proxmox, user) or 'rtp' in session['userinfo']['groups']:
vm = get_vm(proxmox, vmid) vm = get_vm(proxmox, vmid)
vm['vmid'] = vmid vm['vmid'] = vmid
vm['config'] = get_vm_config(proxmox, vmid) vm['config'] = get_vm_config(proxmox, vmid)
@ -97,7 +102,7 @@ def vm_details(vmid):
get_ip_for_mac(starrs, interface[1])]) get_ip_for_mac(starrs, interface[1])])
vm['expire'] = get_vm_expire( vm['expire'] = get_vm_expire(
vmid, app.config['VM_EXPIRE_MONTHS']).strftime('%m/%d/%Y') vmid, app.config['VM_EXPIRE_MONTHS']).strftime('%m/%d/%Y')
usage = get_user_usage(proxmox, 'proxstar') usage = get_user_usage(proxmox, user)
limits = get_user_usage_limits(user) limits = get_user_usage_limits(user)
usage_check = check_user_usage(proxmox, user, vm['config']['cores'], usage_check = check_user_usage(proxmox, user, vm['config']['cores'],
vm['config']['memory'], 0) vm['config']['memory'], 0)
@ -105,6 +110,7 @@ def vm_details(vmid):
'vm_details.html', 'vm_details.html',
username=user, username=user,
rtp=rtp, rtp=rtp,
active=active,
vm=vm, vm=vm,
usage=usage, usage=usage,
limits=limits, limits=limits,
@ -243,48 +249,55 @@ def delete(vmid):
def create(): def create():
user = session['userinfo']['preferred_username'] user = session['userinfo']['preferred_username']
rtp = 'rtp' in session['userinfo']['groups'] rtp = 'rtp' in session['userinfo']['groups']
active = 'active' in session['userinfo']['groups']
proxmox = connect_proxmox() proxmox = connect_proxmox()
starrs = connect_starrs() starrs = connect_starrs()
if request.method == 'GET': if active:
usage = get_user_usage(proxmox, user) if request.method == 'GET':
limits = get_user_usage_limits(user) usage = get_user_usage(proxmox, user)
percents = get_user_usage_percent(proxmox, user, usage, limits) limits = get_user_usage_limits(user)
isos = get_isos(proxmox, app.config['PROXMOX_ISO_STORAGE']) percents = get_user_usage_percent(proxmox, user, usage, limits)
pools = get_pools(proxmox) isos = get_isos(proxmox, app.config['PROXMOX_ISO_STORAGE'])
return render_template( pools = get_pools(proxmox)
'create.html', return render_template(
username=user, 'create.html',
rtp=rtp, username=user,
usage=usage, rtp=rtp,
limits=limits, active=active,
percents=percents, usage=usage,
isos=isos, limits=limits,
pools=pools) percents=percents,
elif request.method == 'POST': isos=isos,
name = request.form['name'] pools=pools)
cores = request.form['cores'] elif request.method == 'POST':
memory = request.form['mem'] name = request.form['name']
disk = request.form['disk'] cores = request.form['cores']
iso = request.form['iso'] memory = request.form['mem']
if iso != 'none': disk = request.form['disk']
iso = "{}:iso/{}".format(app.config['PROXMOX_ISO_STORAGE'], iso) iso = request.form['iso']
if not rtp: if iso != 'none':
usage_check = check_user_usage(proxmox, user, 0, 0, disk) iso = "{}:iso/{}".format(app.config['PROXMOX_ISO_STORAGE'],
else: iso)
usage_check = None if not rtp:
user = request.form['user'] usage_check = check_user_usage(proxmox, user, 0, 0, disk)
if usage_check: else:
return usage_check usage_check = None
else: user = request.form['user']
valid, available = check_hostname(starrs, name) if usage_check:
if valid and available: return usage_check
vmid, mac = create_vm(proxmox, starrs, user, name, cores, else:
memory, disk, iso) valid, available = check_hostname(starrs, name)
register_starrs( if valid and available:
starrs, name, app.config['STARRS_USER'], mac, vmid, mac = create_vm(proxmox, starrs, user, name, cores,
get_next_ip(starrs, app.config['STARRS_IP_RANGE'])[0][0]) memory, disk, iso)
get_vm_expire(vmid, app.config['VM_EXPIRE_MONTHS']) register_starrs(
return vmid starrs, name, app.config['STARRS_USER'], mac,
get_next_ip(starrs,
app.config['STARRS_IP_RANGE'])[0][0])
get_vm_expire(vmid, app.config['VM_EXPIRE_MONTHS'])
return vmid
else:
return '', 403
@app.route('/limits/<string:user>', methods=['POST']) @app.route('/limits/<string:user>', methods=['POST'])

View file

@ -29,3 +29,7 @@ STARRS_DB_USER = ''
STARRS_DB_PASS = '' STARRS_DB_PASS = ''
STARRS_USER = 'proxstar' STARRS_USER = 'proxstar'
STARRS_IP_RANGE = '' STARRS_IP_RANGE = ''
# LDAP
LDAP_BIND_DN = ''
LDAP_BIND_PW = ''

7
db.py
View file

@ -1,6 +1,7 @@
from sqlalchemy import create_engine, exists from sqlalchemy import create_engine, exists
from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import sessionmaker
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from ldapdb import *
import datetime import datetime
from db_init import VM_Expiration, Usage_Limit, Base from db_init import VM_Expiration, Usage_Limit, Base
@ -58,7 +59,11 @@ def get_expired_vms():
def get_user_usage_limits(user): def get_user_usage_limits(user):
limits = dict() limits = dict()
if session.query(exists().where(Usage_Limit.id == user)).scalar(): if is_rtp(user):
limits['cpu'] = 1000
limits['mem'] = 1000
limits['disk'] = 100000
elif session.query(exists().where(Usage_Limit.id == user)).scalar():
limits['cpu'] = session.query(Usage_Limit).filter( limits['cpu'] = session.query(Usage_Limit).filter(
Usage_Limit.id == user).one().cpu Usage_Limit.id == user).one().cpu
limits['mem'] = session.query(Usage_Limit).filter( limits['mem'] = session.query(Usage_Limit).filter(

24
ldapdb.py Normal file
View file

@ -0,0 +1,24 @@
from csh_ldap import CSHLDAP
from flask import current_app as app
def connect_ldap():
try:
ldap = CSHLDAP(app.config['LDAP_BIND_DN'],
app.config['LDAP_BIND_PW'])
except:
print("Unable to connect to LDAP.")
raise
return ldap
def is_rtp(user):
ldap = connect_ldap()
rtp_group = ldap.get_group('rtp')
return rtp_group.check_member(ldap.get_member(user, uid=True))
def is_active(ldap, user):
ldap = connect_ldap()
rtp_group = ldap.get_group('active')
return rtp_group.check_member(ldap.get_member(user, uid=True))

View file

@ -3,6 +3,7 @@ from functools import lru_cache
from proxmoxer import ProxmoxAPI from proxmoxer import ProxmoxAPI
from flask import current_app as app from flask import current_app as app
from db import * from db import *
from ldapdb import *
def connect_proxmox(): def connect_proxmox():
@ -18,10 +19,20 @@ def connect_proxmox():
return proxmox return proxmox
def create_user(proxmox, user):
if not is_rtp(user):
proxmox.pools.post(poolid=user, comment='Managed by Proxstar')
users = proxmox.access.users.get()
username = "{}@csh.rit.edu".format(user)
proxmox.access.users.post(userid=username)
proxmox.access.acl.put(
path="/pool/{}".format(user), roles='PVEVMConsole', users=username)
def get_vms_for_user(proxmox, user): def get_vms_for_user(proxmox, user):
pools = get_pools(proxmox) pools = get_pools(proxmox)
if user not in pools: if user not in pools:
proxmox.pools.post(poolid=user, comment='Managed by Proxstar') create_user(proxmox, user)
vms = proxmox.pools(user).get()['members'] vms = proxmox.pools(user).get()['members']
for vm in vms: for vm in vms:
if 'name' not in vm: if 'name' not in vm:
@ -152,6 +163,8 @@ def get_user_usage(proxmox, user):
usage['cpu'] = 0 usage['cpu'] = 0
usage['mem'] = 0 usage['mem'] = 0
usage['disk'] = 0 usage['disk'] = 0
if is_rtp(user):
return usage
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'])
@ -204,8 +217,14 @@ def create_vm(proxmox, starrs, user, name, cores, memory, disk, iso):
net0='virtio,bridge=vmbr0', net0='virtio,bridge=vmbr0',
pool=user, pool=user,
description='Managed by Proxstar') description='Managed by Proxstar')
time.sleep(3) retry = 0
mac = get_vm_mac(proxmox, vmid) while retry < 5:
try:
mac = get_vm_mac(proxmox, vmid)
break
except:
retry += 1
time.sleep(3)
return vmid, mac return vmid, mac

View file

@ -4,3 +4,4 @@ proxmoxer
psycopg2 psycopg2
sqlalchemy sqlalchemy
python-dateutil python-dateutil
csh_ldap

View file

@ -27,6 +27,7 @@
</div> </div>
<div id="navbar" class="navbar-collapse collapse"> <div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
{% if active %}
<li> <li>
<a href="/"> <a href="/">
<span class="glyphicon glyphicon-th-list"></span> <span class="glyphicon glyphicon-th-list"></span>
@ -39,6 +40,7 @@
Create VM Create VM
</a> </a>
</li> </li>
{% endif %}
</ul> </ul>
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
<li class="dropdown navbar-user"> <li class="dropdown navbar-user">

View file

@ -3,7 +3,11 @@
<div class="container"> <div class="container">
<div class="row"> <div class="row">
{% if rtp %}
<div class="col-md-12 col-sm-12">
{% else %}
<div class="col-md-9 col-sm-12"> <div class="col-md-9 col-sm-12">
{% endif %}
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h3 class="panel-title">Create VM</h3> <h3 class="panel-title">Create VM</h3>
@ -13,11 +17,11 @@
<p>Before you can create any more VMs, you must first delete existing VMs until you have enough disk resources available.</p> <p>Before you can create any more VMs, you must first delete existing VMs until you have enough disk resources available.</p>
{% else %} {% else %}
<div class="form-group"> <div class="form-group">
<label for="name">VM Name</label> <label for="name" class="pull-left">VM Name</label>
<input type="text" name="name" id="name" class="form-control"> <input type="text" name="name" id="name" class="form-control">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="cores">Cores</label> <label for="cores" class="pull-left">Cores</label>
<select name="cores" id="cores" class="form-control"> <select name="cores" id="cores" class="form-control">
{% for i in range(1, limits['cpu'] + 1) %} {% for i in range(1, limits['cpu'] + 1) %}
<option value="{{ i }}">{{ i }}</option> <option value="{{ i }}">{{ i }}</option>
@ -25,7 +29,7 @@
</select> </select>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="mem">Memory</label> <label for="mem" class="pull-left">Memory</label>
<select name="mem" id="mem" class="form-control"> <select name="mem" id="mem" class="form-control">
<option value="512">512MB</option> <option value="512">512MB</option>
{% for i in range(1, limits['mem'] + 1) %} {% for i in range(1, limits['mem'] + 1) %}
@ -34,11 +38,11 @@
</select> </select>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="disk">Disk (GB)</label> <label for="disk" class="pull-left">Disk (GB)</label>
<input type="number" name="disk" id="disk" class="form-control" min="1" max="{{ limits['disk'] - usage['disk'] }}"> <input type="number" name="disk" id="disk" class="form-control" min="1" max="{{ limits['disk'] - usage['disk'] }}">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="iso">ISO</label> <label for="iso" class="pull-left">ISO</label>
<select name="iso" id="iso" class="form-control"> <select name="iso" id="iso" class="form-control">
<option value="none"></option> <option value="none"></option>
{% for iso in isos %} {% for iso in isos %}
@ -48,7 +52,7 @@
</div> </div>
{% if rtp %} {% if rtp %}
<div class="form-group"> <div class="form-group">
<label for="user">User</label> <label for="user" class="pull-left">User</label>
<select name="user" id="user" class="form-control"> <select name="user" id="user" class="form-control">
{% for pool in pools %} {% for pool in pools %}
<option value="{{ pool }}">{{ pool }}</option> <option value="{{ pool }}">{{ pool }}</option>
@ -61,6 +65,7 @@
</div> </div>
</div> </div>
</div> </div>
{% if not rtp %}
<div class="col-md-3 col-sm-12"> <div class="col-md-3 col-sm-12">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
@ -120,6 +125,7 @@
</div> </div>
</div> </div>
</div> </div>
{% endif %}
</div> </div>
</div> </div>

View file

@ -20,6 +20,14 @@
</div> </div>
</div> </div>
</div> </div>
{% elif vms == 'INACTIVE' %}
<div class="col-md-12 col-sm-12">
<div class="panel panel-default">
<div class="panel-body">
<p>Only active members have access to create Proxmox VMs. If you believe this is an error, please contact an RTP.</p>
</div>
</div>
</div>
{% elif rtp_view != True %} {% elif rtp_view != True %}
{% for vm in vms %} {% for vm in vms %}
<div class="col-md-3 col-sm-4 col-xs-6"> <div class="col-md-3 col-sm-4 col-xs-6">

View file

@ -21,6 +21,7 @@
{% endif %} {% endif %}
{% if vm['qmpstatus'] == 'running' or vm['qmpstatus'] == 'paused' %} {% if vm['qmpstatus'] == 'running' or vm['qmpstatus'] == 'paused' %}
{% if vm['qmpstatus'] == 'running' %} {% if vm['qmpstatus'] == 'running' %}
<a href="https://proxmox01.csh.rit.edu/#v1:0:=qemu%2F{{ vm['vmid'] }}:4::::8::" target="_blank">Open VM Console</a>
<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['vmid'] }}" 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['vmid'] }}" data-vmname="{{ vm['name'] }}">SHUTDOWN</button>