From cc2033f2ca392dac29ae5bc64cf549d31a3142a6 Mon Sep 17 00:00:00 2001 From: Jordan Rodgers Date: Fri, 19 Jan 2018 03:01:10 -0500 Subject: [PATCH] add ldap, check if active member, create user and give console perms, retry getting mac, better handling of rtp --- agent.py | 5 -- app.py | 99 ++++++++++++++++++++++----------------- config.sample.py | 4 ++ db.py | 7 ++- ldapdb.py | 24 ++++++++++ proxmox.py | 25 ++++++++-- requirements.txt | 1 + templates/base.html | 2 + templates/create.html | 18 ++++--- templates/list_vms.html | 8 ++++ templates/vm_details.html | 1 + 11 files changed, 136 insertions(+), 58 deletions(-) delete mode 100644 agent.py create mode 100644 ldapdb.py diff --git a/agent.py b/agent.py deleted file mode 100644 index 181d3df..0000000 --- a/agent.py +++ /dev/null @@ -1,5 +0,0 @@ -from websockify.websocket import * -from websockify.websocketproxy import * - -server = WebSocketProxy(listen_port='10000', target_port='6000') -server.start_server() diff --git a/app.py b/app.py index a47c3aa..b9a6e58 100644 --- a/app.py +++ b/app.py @@ -4,6 +4,7 @@ import psycopg2 import subprocess from db import * from starrs import * +from ldapdb import * from proxmox import * from werkzeug.contrib.cache import SimpleCache from flask_pyoidc.flask_pyoidc import OIDCAuthentication @@ -45,6 +46,10 @@ def list_vms(user=None): else: user = session['userinfo']['preferred_username'] vms = get_vms_for_user(proxmox, user) + if active: + vms = get_vms_for_user(proxmox, user) + else: + vms = 'INACTIVE' return render_template( 'list_vms.html', username=user, @@ -80,10 +85,10 @@ def hostname(name): def vm_details(vmid): user = session['userinfo']['preferred_username'] rtp = 'rtp' in session['userinfo']['groups'] + active = 'active' in session['userinfo']['groups'] proxmox = connect_proxmox() starrs = connect_starrs() - if int(vmid) in get_user_allowed_vms( - proxmox, user) or 'rtp' in session['userinfo']['groups']: + if 'rtp' in session['userinfo']['groups'] or int(vmid) in get_user_allowed_vms(proxmox, user): vm = get_vm(proxmox, vmid) vm['vmid'] = vmid vm['config'] = get_vm_config(proxmox, vmid) @@ -97,7 +102,7 @@ def vm_details(vmid): get_ip_for_mac(starrs, interface[1])]) vm['expire'] = get_vm_expire( 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) usage_check = check_user_usage(proxmox, user, vm['config']['cores'], vm['config']['memory'], 0) @@ -105,6 +110,7 @@ def vm_details(vmid): 'vm_details.html', username=user, rtp=rtp, + active=active, vm=vm, usage=usage, limits=limits, @@ -243,48 +249,55 @@ def delete(vmid): def create(): user = session['userinfo']['preferred_username'] rtp = 'rtp' in session['userinfo']['groups'] + active = 'active' in session['userinfo']['groups'] proxmox = connect_proxmox() starrs = connect_starrs() - if request.method == 'GET': - usage = get_user_usage(proxmox, user) - limits = get_user_usage_limits(user) - percents = get_user_usage_percent(proxmox, user, usage, limits) - isos = get_isos(proxmox, app.config['PROXMOX_ISO_STORAGE']) - pools = get_pools(proxmox) - return render_template( - 'create.html', - username=user, - rtp=rtp, - usage=usage, - limits=limits, - percents=percents, - isos=isos, - pools=pools) - elif request.method == 'POST': - name = request.form['name'] - cores = request.form['cores'] - memory = request.form['mem'] - disk = request.form['disk'] - iso = request.form['iso'] - if iso != 'none': - iso = "{}:iso/{}".format(app.config['PROXMOX_ISO_STORAGE'], iso) - if not rtp: - usage_check = check_user_usage(proxmox, user, 0, 0, disk) - else: - usage_check = None - user = request.form['user'] - if usage_check: - return usage_check - else: - valid, available = check_hostname(starrs, name) - if valid and available: - vmid, mac = create_vm(proxmox, starrs, user, name, cores, - memory, disk, iso) - register_starrs( - 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 + if active: + if request.method == 'GET': + usage = get_user_usage(proxmox, user) + limits = get_user_usage_limits(user) + percents = get_user_usage_percent(proxmox, user, usage, limits) + isos = get_isos(proxmox, app.config['PROXMOX_ISO_STORAGE']) + pools = get_pools(proxmox) + return render_template( + 'create.html', + username=user, + rtp=rtp, + active=active, + usage=usage, + limits=limits, + percents=percents, + isos=isos, + pools=pools) + elif request.method == 'POST': + name = request.form['name'] + cores = request.form['cores'] + memory = request.form['mem'] + disk = request.form['disk'] + iso = request.form['iso'] + if iso != 'none': + iso = "{}:iso/{}".format(app.config['PROXMOX_ISO_STORAGE'], + iso) + if not rtp: + usage_check = check_user_usage(proxmox, user, 0, 0, disk) + else: + usage_check = None + user = request.form['user'] + if usage_check: + return usage_check + else: + valid, available = check_hostname(starrs, name) + if valid and available: + vmid, mac = create_vm(proxmox, starrs, user, name, cores, + memory, disk, iso) + register_starrs( + 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/', methods=['POST']) diff --git a/config.sample.py b/config.sample.py index 248fd5d..0c7b045 100644 --- a/config.sample.py +++ b/config.sample.py @@ -29,3 +29,7 @@ STARRS_DB_USER = '' STARRS_DB_PASS = '' STARRS_USER = 'proxstar' STARRS_IP_RANGE = '' + +# LDAP +LDAP_BIND_DN = '' +LDAP_BIND_PW = '' diff --git a/db.py b/db.py index cfe178e..a855d10 100644 --- a/db.py +++ b/db.py @@ -1,6 +1,7 @@ from sqlalchemy import create_engine, exists from sqlalchemy.orm import sessionmaker from dateutil.relativedelta import relativedelta +from ldapdb import * import datetime from db_init import VM_Expiration, Usage_Limit, Base @@ -58,7 +59,11 @@ def get_expired_vms(): def get_user_usage_limits(user): 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( Usage_Limit.id == user).one().cpu limits['mem'] = session.query(Usage_Limit).filter( diff --git a/ldapdb.py b/ldapdb.py new file mode 100644 index 0000000..a31a43c --- /dev/null +++ b/ldapdb.py @@ -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)) diff --git a/proxmox.py b/proxmox.py index 3484cb8..4142ea8 100644 --- a/proxmox.py +++ b/proxmox.py @@ -3,6 +3,7 @@ from functools import lru_cache from proxmoxer import ProxmoxAPI from flask import current_app as app from db import * +from ldapdb import * def connect_proxmox(): @@ -18,10 +19,20 @@ def connect_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): pools = get_pools(proxmox) if user not in pools: - proxmox.pools.post(poolid=user, comment='Managed by Proxstar') + create_user(proxmox, user) vms = proxmox.pools(user).get()['members'] for vm in vms: if 'name' not in vm: @@ -152,6 +163,8 @@ def get_user_usage(proxmox, user): usage['cpu'] = 0 usage['mem'] = 0 usage['disk'] = 0 + if is_rtp(user): + return usage vms = get_vms_for_user(proxmox, user) for vm in vms: 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', pool=user, description='Managed by Proxstar') - time.sleep(3) - mac = get_vm_mac(proxmox, vmid) + retry = 0 + while retry < 5: + try: + mac = get_vm_mac(proxmox, vmid) + break + except: + retry += 1 + time.sleep(3) return vmid, mac diff --git a/requirements.txt b/requirements.txt index 24f3ca5..47029c1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,4 @@ proxmoxer psycopg2 sqlalchemy python-dateutil +csh_ldap diff --git a/templates/base.html b/templates/base.html index 9bde71c..90ff5da 100644 --- a/templates/base.html +++ b/templates/base.html @@ -27,6 +27,7 @@ + {% elif vms == 'INACTIVE' %} +
+
+
+

Only active members have access to create Proxmox VMs. If you believe this is an error, please contact an RTP.

+
+
+
{% elif rtp_view != True %} {% for vm in vms %}
diff --git a/templates/vm_details.html b/templates/vm_details.html index 9267a83..2627dba 100644 --- a/templates/vm_details.html +++ b/templates/vm_details.html @@ -21,6 +21,7 @@ {% endif %} {% if vm['qmpstatus'] == 'running' or vm['qmpstatus'] == 'paused' %} {% if vm['qmpstatus'] == 'running' %} + Open VM Console {% endif %}