Skip to content
Snippets Groups Projects
Commit 367306c0 authored by Vladimír Višňovský's avatar Vladimír Višňovský
Browse files

:Merge branch 'remodule-2' of gitlab.ics.muni.cz:467814/magic-pipeline-web into remodule-2

parents 4cad94e5 a1d9edf8
No related branches found
No related tags found
2 merge requests!8Development,!7Remodule (v1.0 -> v1.1)
import os
import requests
from __main__ import login_manager
sys.path.insert(1, "/app")
from user import User
sys.path.insert(1, "/app/pmcff")
from db import get_connection
# Flask-Login helper to retrieve a user from db
@login_manager.user_loader
def load_user(user_id):
connection = get_connection(DATABASE)
return User.get(connection, user_id)
def get_provider_cfg():
return requests.get(DISCOVERY_URL).json()
def remove_deployment(user_id):
os.system(f'kubectl delete -f /srv/{user_id}')
def get_response(code):
provider_cfg = get_provider_cfg()
token_endpoint = provider_cfg["token_endpoint"]
client_auth = requests.auth.HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET)
post_data = {"grant_type": "authorization_code",
"code": code,
"redirect_uri": REDIRECT_URI}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.post(token_endpoint,
auth=client_auth,
headers=headers,
data=post_data)
return response
#!/usr/bin/env python3
import json
import os
import sqlite3
import threading
import time
import logging
# Third-party libraries
from flask import Flask, redirect, request, url_for, render_template
from flask_login import (
LoginManager,
current_user,
login_required,
login_user,
logout_user,
)
from oauthlib.oauth2 import WebApplicationClient
from waitress import serve
import requests
import sys
# Internal imports
from db import (init_db_command, get_connection)
from user import User
sys.path.insert(1, "../app/pipeline")
from pipeline_run import run_container
##
# Configuration
# DO NOT FORGET TO EXPORT THOSE VARIABLES
##
CLIENT_ID = os.environ.get("CLIENT_ID", None)
CLIENT_SECRET = os.environ.get("CLIENT_SECRET", None)
DISCOVERY_URL = (
"https://login.elixir-czech.org/oidc/.well-known/openid-configuration"
)
REDIRECT_URI = (
"https://pmcvff-correction.cerit-sc.cz/login/callback"
)
# Database name present in current folder
DATABASE = '/var/lib/sqlite/sqlite_db'
# Flask setup
app = Flask(__name__)
app.secret_key = os.environ.get("SECRET_KEY") or os.urandom(24)
# User session management setup
login_manager = LoginManager()
login_manager.init_app(app)
###
# TEST USER
###
test_user = User(
id_="test123456", name="test_user", email="test_mail", dns_name=None, token=None
)
# Database setup
def initialize_db():
try:
init_db_command()
except sqlite3.OperationalError:
# Assume it's already been created
pass
# OAuth 2 client setup
client = WebApplicationClient(CLIENT_ID)
# Flask-Login helper to retrieve a user from db
@login_manager.user_loader
def load_user(user_id):
connection = get_connection(DATABASE)
return User.get(connection, user_id)
@app.route("/")
def index():
if current_user.is_authenticated:
return render_template('index_authorized.html',
user=current_user.name,
email=current_user.email,
dns_name=current_user.dns_name)
else:
return render_template('index_unauthorized.html')
def get_provider_cfg():
return requests.get(DISCOVERY_URL).json()
@app.route("/notebook")
def notebook():
if current_user.is_authenticated:
app.logger.info('%s %s opening notebook', current_user.id, current_user.name)
# Check if the service is running
if current_user.dns_name:
jupyter_notebook = f'https://{current_user.dns_name}/?token={current_user.token}'
try:
if requests.head(jupyter_notebook).status_code in [200, 405]:
app.logger.info('%s %s redirecting to existing notebook %s', current_user.id, current_user.name, jupyter_notebook)
return redirect(jupyter_notebook)
except requests.exceptions.ConnectionError:
app.logger.info('%s %s connection error to jupyter notebook %s', current_user.id, current_user.name, jupyter_notebook)
app.logger.info('%s %s allocating resources, dns name set (retry later)', current_user.id, current_user.name)
return '<p>Taking longer to allocate needed resources... Please try to open pipeline from main page again later</p>'
# Check if the pvc is deleted
pvcs = os.popen('kubectl get pvc').read()
user_pvc_name = f'pmcvff-correction-claim-{current_user.id}'
if user_pvc_name in pvcs:
app.logger.info('%s %s pvc still getting deleted %s', current_user.id, current_user.name, pvcs)
return '<p>Your personal storage is still getting deleted... Please try again later</p>'
# Run pipeline container
jupyter_notebook = run_container(current_user.id)
app.logger.info('%s %s running container', current_user.id, current_user.name)
# Periodicaly wait until the container is available or timeout
timeout_threshold = 5
while timeout_threshold >= 0:
time.sleep(4)
timeout_threshold -= 1
try:
response = requests.head(jupyter_notebook)
except requests.exceptions.ConnectionError:
app.logger.info('%s %s connection error in new noteboook', current_user.id, current_user.name)
continue
if response.status_code in [200, 405]:
app.logger.info('%s %s redirecting successfully to new notebook %s', current_user.id, current_user.name, jupyter_notebook)
return redirect(jupyter_notebook)
app.logger.info('%s %s still allocating resources for %s', current_user.id, current_user.name, jupyter_notebook)
return '<p>Taking longer to allocate needed resources... Please try to open pipeline from main page again later</p>'
return '<p>User not authorized to perform opening of notebook</p>'
@app.route("/delete")
def delete_notebook():
if current_user.is_authenticated:
connection = get_connection(DATABASE)
try:
User.remove_container(connection, current_user.dns_name)
app.logger.info('%s %s successfully removed container %s', current_user.id, current_user.name, current_user.dns_name)
except Exception as e:
app.logger.info('%s %s exception in delete container %s', current_user.id, current_user.name, e)
return redirect(url_for("index"))
threading.Thread(target=remove_deployment, args=[current_user.id]).start()
return redirect(url_for("index"))
return '<p>User not authorized to remove notebook</p>'
def remove_deployment(user_id):
os.system(f'kubectl delete -f /srv/{user_id}')
@app.route("/login")
def login():
# provider_cfg = get_provider_cfg()
# authorization_endpoint = provider_cfg["authorization_endpoint"]
# request_uri = client.prepare_request_uri(
# authorization_endpoint,
# redirect_uri=REDIRECT_URI,
# scope=["openid", "email", "profile"],
# )
return redirect(url_for("callback"))
@app.route("/login/callback")
def callback():
# code = request.args.get("code")
# token_response = get_response(code)
# if token_response.status_code == 400:
# return redirect(url_for("index"))
# client.parse_request_body_response(json.dumps(token_response.json()))
# provider_cfg = get_provider_cfg()
# userinfo_endpoint = provider_cfg["userinfo_endpoint"]
# uri, headers, body = client.add_token(userinfo_endpoint)
# userinfo_response = requests.get(uri, headers=headers, data=body)
# # Get user info
# unique_id = userinfo_response.json()["sub"].split('@')[0]
# users_email = userinfo_response.json()["email"]
# users_name = userinfo_response.json()["given_name"]
user = User(
id_=test_user.id, name=test_user.name, email=test_user.email, dns_name=test_user.dns_name, token=None
)
# Doesn't exist? Add it to the internal database.
connection = get_connection(DATABASE)
if not User.get(connection, test_user.id):
User.create(connection, test_user.id, test_user.name, test_user.email, test_user.dns_name, None)
# Begin user session by logging the user in
login_user(user)
app.logger.info('%s %s successfully logged in', user.id, user.name)
# Send user back to homepage as authorized
return redirect(url_for("index"))
def get_response(code):
provider_cfg = get_provider_cfg()
token_endpoint = provider_cfg["token_endpoint"]
client_auth = requests.auth.HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET)
post_data = {"grant_type": "authorization_code",
"code": code,
"redirect_uri": REDIRECT_URI}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.post(token_endpoint,
auth=client_auth,
headers=headers,
data=post_data)
return response
@app.route("/logout")
@login_required
def logout():
app.logger.info('%s %s logging out', current_user.id, current_user.name)
logout_user()
return redirect(url_for("index"))
if __name__ == "__main__":
init_db = threading.Thread(target=initialize_db).start()
logging.basicConfig(filename='debug.log',
level=logging.DEBUG,
format='%(asctime)s %(levelname)s %(name)s %(threadName)s : %(message)s')
# Run in production
serve(app, host='0.0.0.0', port=5000)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment