This commit is contained in:
Will Nilges 2022-07-10 18:06:03 -04:00
parent 1134939d3c
commit 98d1408693
4 changed files with 54 additions and 13 deletions

View file

@ -17,6 +17,13 @@ It is available to house members at [proxstar.csh.rit.edu](https://proxstar.csh.
1. [Fork](https://help.github.com/en/articles/fork-a-repo) this repository
- Optionally create a new [git branch](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell) if your change is more than a small tweak (`git checkout -b BRANCH-NAME-HERE`)
2. Create a Virtualenv to do your work in.
```
mkdir venv
python3.8 -m venv venv
source venv/bin/activate
```
3. Make your changes locally, commit, and push to your fork
- If you want to test locally, you should copy `config.py` to `config_local.py`, and talk to an RTP about filling in secrets.
- Lint and format your local changes with `pylint proxstar` and `black proxstar`

View file

@ -13,7 +13,17 @@ from redis import Redis
from rq_scheduler import Scheduler
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from flask import Flask, render_template, request, redirect, session, abort, url_for, jsonify, Response
from flask import (
Flask,
render_template,
request,
redirect,
session,
abort,
url_for,
jsonify,
Response,
)
import sentry_sdk
from sentry_sdk.integrations.flask import FlaskIntegration
from sentry_sdk.integrations.rq import RqIntegration
@ -135,6 +145,7 @@ if 'cleanup_vnc' not in scheduler:
interval=3600,
)
def add_rq_dashboard_auth(blueprint):
@blueprint.before_request
@auth.oidc_auth
@ -159,6 +170,7 @@ def forbidden(e):
user = User(session['userinfo']['preferred_username'])
return render_template('403.html', user=user, e=e), 403
@app.route('/')
@app.route('/user/<string:user_view>')
@auth.oidc_auth
@ -287,15 +299,23 @@ def vm_console(vmid):
if user.rtp or int(vmid) in user.allowed_vms:
# import pdb; pdb.set_trace()
vm = VM(vmid)
vnc_ticket, vnc_port = open_vnc_session(vmid, vm.node, app.config['PROXMOX_USER'], app.config['PROXMOX_PASS'])
vnc_ticket, vnc_port = open_vnc_session(
vmid, vm.node, app.config['PROXMOX_USER'], app.config['PROXMOX_PASS']
)
node = f'{vm.node}.csh.rit.edu'
token = add_vnc_target(node, vnc_port)
# return {'host' : node, 'port' : vnc_port, 'token' : token, 'password' : vnc_ticket}, 200
return {'host' : app.config['VNC_HOST'], 'port' : 8081, 'token' : token, 'password' : vnc_ticket}, 200
return {
'host': app.config['VNC_HOST'],
'port': 8081,
'token': token,
'password': vnc_ticket,
}, 200
else:
return '', 403
@app.route('/vm/<string:vmid>/cpu/<int:cores>', methods=['POST'])
@auth.oidc_auth
def vm_cpu(vmid, cores):

View file

@ -272,19 +272,28 @@ class VM:
# )
def configure_vnc_in_vm_config(self, ssh_user, ssh_pass):
""" Sets the vm up for VNC. Enables it to open a socket on localhost
"""Sets the vm up for VNC. Enables it to open a socket on localhost
with a pre-determined password, which proxstar can then proxy to a noVNC
instance.
instance.
"""
# proxmox = connect_proxmox()
config = f'args: -object secret,id=secvnc{self.id},data={self.id} -vnc 127.0.0.1:{int(self.id)+5900},password-secret=secvnc{self.id}'
path = f'/etc/pve/local/qemu-server/{self.id}.conf'
with paramiko.SSHClient() as ssh:
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(self.node, port=22, username=ssh_user, key_filename='proxmox_ssh_key', passphrase=ssh_pass)
ssh.exec_command(f"if grep -- '{config}' {path}; then echo identical config found; else sed -i /dev/null '/-vnc/d' {path}") #YOLO
ssh.exec_command(f"if grep -- '-vnc' {path}; then echo found config; else echo {config} >> {path}; fi")
ssh.connect(
self.node,
port=22,
username=ssh_user,
key_filename='proxmox_ssh_key',
passphrase=ssh_pass,
)
ssh.exec_command(
f"if grep -- '{config}' {path}; then echo identical config found; else sed -i /dev/null '/-vnc/d' {path}"
) # YOLO
ssh.exec_command(
f"if grep -- '-vnc' {path}; then echo found config; else echo {config} >> {path}; fi"
)
@retry(wait=wait_fixed(2), stop=stop_after_attempt(5))
def eject_iso(self):

View file

@ -37,6 +37,7 @@ def get_vnc_targets():
target_file.close()
return targets
def add_vnc_target(node, port):
# TODO (willnilges): This doesn't throw an error if the target file is wrong.
# TODO (willnilges): This will duplicate targets
@ -52,6 +53,7 @@ def add_vnc_target(node, port):
target_file.close()
return token
def delete_vnc_target(node, port):
targets = get_vnc_targets()
target = next((target for target in targets if target['host'] == f'{node}:{port}'), None)
@ -62,8 +64,9 @@ def delete_vnc_target(node, port):
target_file.write(f"{target['token']}: {target['host']}\n")
target_file.close()
def open_vnc_session(vmid, node, proxmox_user, proxmox_pass):
""" Pings the Proxmox API to request a VNC Proxy connection. Authenticates
"""Pings the Proxmox API to request a VNC Proxy connection. Authenticates
against the API using a Uname/Pass, gets a few tokens back, then uses those
tokens to open the VNC Proxy. Use these to connect to the VM's host with
websockify proxy.
@ -91,17 +94,18 @@ def open_vnc_session(vmid, node, proxmox_user, proxmox_pass):
timeout=5,
params=proxy_params,
headers={"CSRFPreventionToken": csrf_prevention_token},
cookies={"PVEAuthCookie": ticket}
cookies={"PVEAuthCookie": ticket},
).json()["data"]
return urllib.parse.quote_plus(vncproxy_response_data['ticket']), vncproxy_response_data['port']
def start_ssh_tunnel(node, port):
"""Forwards a port on a node
to the proxstar container
"""
port = int(port)
server = SSHTunnelForwarder(
node,
ssh_username=app.config['PROXMOX_SSH_USER'],
@ -113,6 +117,7 @@ def start_ssh_tunnel(node, port):
server.start()
return server
def stop_ssh_tunnel(vmid, ssh_tunnels):
# Tear down the SSH tunnel and VNC target entry for a given VM
port = 5900 + int(vmid)