mirror of
https://github.com/ComputerScienceHouse/proxstar.git
synced 2025-02-14 22:11:51 +00:00
add ldap, check if active member, create user and give console perms, retry getting mac, better handling of rtp
This commit is contained in:
parent
8161d97f21
commit
cc2033f2ca
11 changed files with 136 additions and 58 deletions
5
agent.py
5
agent.py
|
@ -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
99
app.py
|
@ -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'])
|
||||||
|
|
|
@ -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
7
db.py
|
@ -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
24
ldapdb.py
Normal 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))
|
25
proxmox.py
25
proxmox.py
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,3 +4,4 @@ proxmoxer
|
||||||
psycopg2
|
psycopg2
|
||||||
sqlalchemy
|
sqlalchemy
|
||||||
python-dateutil
|
python-dateutil
|
||||||
|
csh_ldap
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue