def test_write_infra(self): infra = Infrastructures("sqlite:///tmp/creds.db") infra.write_infra("infid", {"name": "infra_name"}) res = infra.get_infra("infid") self.assertEquals(res, {"name": "infra_name"}) infra.write_infra("infid", {"state": "infra_state"}) res = infra.get_infra("infid") self.assertEquals(res, {"name": "infra_name", "state": "infra_state"})
def test_get_infra(self): infra = Infrastructures("sqlite:///tmp/creds.db") res = infra._get_inf_db() str_data = '{"name": "infra_name"}' res.execute("replace into infrastructures (infid, data) values (%s, %s)", ("infid", str_data)) res.close() res = infra.get_infra("infid") self.assertEquals(res, {'name': 'infra_name'})
def test_delete_infra(self): infra = Infrastructures("sqlite:///tmp/creds.db") infra.delete_infra("infid") res = infra.get_infra("infid") self.assertEquals(res, {})
def create_app(oidc_blueprint=None): app = Flask(__name__) app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_port=1, x_prefix=1) app.secret_key = "8210f566-4981-11ea-92d1-f079596e599b" app.config.from_json('config.json') settings = Settings(app.config) cred = Credentials(settings.db_url) infra = Infrastructures(settings.db_url) toscaTemplates = utils.loadToscaTemplates(settings.toscaDir) toscaInfo = utils.extractToscaInfo(settings.toscaDir, settings.toscaParamsDir, toscaTemplates) app.jinja_env.filters['tojson_pretty'] = utils.to_pretty_json app.logger.debug("TOSCA INFO: " + json.dumps(toscaInfo)) loglevel = app.config.get("LOG_LEVEL") if app.config.get( "LOG_LEVEL") else "INFO" numeric_level = getattr(logging, loglevel.upper(), None) if not isinstance(numeric_level, int): raise ValueError('Invalid log level: %s' % loglevel) logging.basicConfig(level=numeric_level) oidc_base_url = app.config['OIDC_BASE_URL'] oidc_token_url = oidc_base_url + '/token' oidc_refresh_url = oidc_base_url + '/token' oidc_authorization_url = oidc_base_url + '/authorize' if not oidc_blueprint: oidc_blueprint = OAuth2ConsumerBlueprint( "oidc", __name__, client_id=app.config['OIDC_CLIENT_ID'], client_secret=app.config['OIDC_CLIENT_SECRET'], scope=app.config['OIDC_SCOPES'], base_url=oidc_base_url, token_url=oidc_token_url, auto_refresh_url=oidc_refresh_url, authorization_url=oidc_authorization_url, redirect_to='home') app.register_blueprint(oidc_blueprint, url_prefix="/login") @app.before_request def before_request_checks(): if 'external_links' not in session: session['external_links'] = settings.external_links g.analytics_tag = settings.analytics_tag g.settings = settings def authorized_with_valid_token(f): @wraps(f) def decorated_function(*args, **kwargs): try: if not oidc_blueprint.session.authorized or 'username' not in session: return redirect(url_for('login')) if oidc_blueprint.session.token['expires_in'] < 20: app.logger.debug("Force refresh token") oidc_blueprint.session.get('/userinfo') except (InvalidTokenError, TokenExpiredError): flash("Token expired.", 'warning') return redirect(url_for('login')) return f(*args, **kwargs) return decorated_function @app.route('/settings') @authorized_with_valid_token def show_settings(): return render_template('settings.html', oidc_url=settings.oidcUrl, im_url=settings.imUrl) @app.route('/login') def login(): session.clear() return render_template('home.html', oidc_name=settings.oidcName) @app.route('/') def home(): if not oidc_blueprint.session.authorized: return redirect(url_for('login')) try: account_info = oidc_blueprint.session.get( urlparse(settings.oidcUrl)[2] + "/userinfo") except (InvalidTokenError, TokenExpiredError): flash("Token expired.", 'warning') return redirect(url_for('login')) if account_info.ok: account_info_json = account_info.json() session["vos"] = None if 'eduperson_entitlement' in account_info_json: session["vos"] = utils.getUserVOs( account_info_json['eduperson_entitlement']) if settings.oidcGroups: user_groups = [] if 'groups' in account_info_json: user_groups = account_info_json['groups'] elif 'eduperson_entitlement' in account_info_json: user_groups = account_info_json['eduperson_entitlement'] if not set(settings.oidcGroups).issubset(user_groups): app.logger.debug( "No match on group membership. User group membership: " + json.dumps(user_groups)) message = Markup( 'You need to be a member of the following groups: {0}. <br>' ' Please, visit <a href="{1}">{1}</a> and apply for the requested ' 'membership.'.format(json.dumps(settings.oidcGroups), settings.oidcUrl)) raise Forbidden(description=message) session['userid'] = account_info_json['sub'] if 'name' in account_info_json: session['username'] = account_info_json['name'] else: session['username'] = "" if 'given_name' in account_info_json: session['username'] = account_info_json['given_name'] if 'family_name' in account_info_json: session[ 'username'] += " " + account_info_json['family_name'] if session['username'] == "": session['username'] = account_info_json['sub'] if 'email' in account_info_json: session['gravatar'] = utils.avatar(account_info_json['email'], 26) else: session['gravatar'] = utils.avatar(account_info_json['sub'], 26) return render_template('portfolio.html', templates=toscaInfo) else: flash("Error getting User info: \n" + account_info.text, 'error') return render_template('home.html', oidc_name=settings.oidcName) @app.route('/vminfo/<infid>/<vmid>') @authorized_with_valid_token def showvminfo(infid=None, vmid=None): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) headers = {"Authorization": auth_data, "Accept": "application/json"} url = "%s/infrastructures/%s/vms/%s" % (settings.imUrl, infid, vmid) response = requests.get(url, headers=headers) vminfo = {} state = "" nets = "" deployment = "" if not response.ok: flash("Error retrieving VM info: \n" + response.text, 'error') else: app.logger.debug("VM Info: %s" % response.text) vminfo = utils.format_json_radl(response.json()["radl"]) if "cpu.arch" in vminfo: del vminfo["cpu.arch"] if "state" in vminfo: state = vminfo["state"] del vminfo["state"] if "provider.type" in vminfo: deployment = vminfo["provider.type"] del vminfo["provider.type"] if "provider.host" in vminfo: if "provider.port" in vminfo: deployment += ": %s:%s" % (vminfo["provider.host"], vminfo["provider.port"]) del vminfo["provider.port"] else: deployment += ": " + vminfo["provider.host"] del vminfo["provider.host"] cont = 0 while "net_interface.%s.ip" % cont in vminfo: if cont > 0: nets += Markup('<br/>') nets += Markup('<i class="fa fa-network-wired"></i>') nets += " %s: %s" % (cont, vminfo["net_interface.%s.ip" % cont]) del vminfo["net_interface.%s.ip" % cont] cont += 1 cont = 0 while "net_interface.%s.connection" % cont in vminfo: del vminfo["net_interface.%s.connection" % cont] cont += 1 for elem in vminfo: if elem.endswith("size") and isinstance(vminfo[elem], int): vminfo[elem] = "%d GB" % (vminfo[elem] / 1073741824) return render_template('vminfo.html', infid=infid, vmid=vmid, vminfo=vminfo, state=state, nets=nets, deployment=deployment) @app.route('/managevm/<op>/<infid>/<vmid>') @authorized_with_valid_token def managevm(op=None, infid=None, vmid=None): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) headers = {"Authorization": auth_data, "Accept": "application/json"} op = op.lower() if op in ["stop", "start", "reboot"]: url = "%s/infrastructures/%s/vms/%s/%s" % (settings.imUrl, infid, vmid, op) response = requests.put(url, headers=headers) elif op == "terminate": url = "%s/infrastructures/%s/vms/%s" % (settings.imUrl, infid, vmid) response = requests.delete(url, headers=headers) else: flash("Error: invalid operation: %s." % op, 'error') return redirect(url_for('showinfrastructures')) if response.ok: flash("Operation '%s' successfully made on VM ID: %s" % (op, vmid), 'info') else: flash( "Error making %s op on VM %s: \n%s" % (op, vmid, response.text), 'error') if op == "terminate": return redirect(url_for('showinfrastructures')) else: return redirect(url_for('showvminfo', infid=infid, vmid=vmid)) @app.route('/infrastructures') @authorized_with_valid_token def showinfrastructures(): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) headers = {"Authorization": auth_data, "Accept": "application/json"} url = "%s/infrastructures" % settings.imUrl response = requests.get(url, headers=headers) infrastructures = {} if not response.ok: flash("Error retrieving infrastructure list: \n" + response.text, 'error') else: app.logger.debug("Infrastructures: %s" % response.text) state_res = response.json() if "uri-list" in state_res: inf_id_list = [elem["uri"] for elem in state_res["uri-list"]] else: inf_id_list = [] for inf_id in inf_id_list: url = "%s/state" % inf_id response = requests.get(url, headers=headers) if not response.ok: flash( "Error retrieving infrastructure %s state: \n%s" % (inf_id, response.text), 'warning') else: inf_state = response.json() infrastructures[os.path.basename( inf_id)] = inf_state['state'] try: infra_name = infra.get_infra( os.path.basename(inf_id))["name"] except Exception: infra_name = "" infrastructures[os.path.basename( inf_id)]['name'] = infra_name return render_template('infrastructures.html', infrastructures=infrastructures) @app.route('/reconfigure/<infid>') @authorized_with_valid_token def infreconfigure(infid=None): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) headers = {"Authorization": auth_data} url = "%s/infrastructures/%s/reconfigure" % (settings.imUrl, infid) response = requests.put(url, headers=headers) if response.ok: flash("Infrastructure successfuly reconfigured.", "info") else: flash("Error reconfiguring Infrastructure: \n" + response.text, "error") return redirect(url_for('showinfrastructures')) @app.route('/template/<infid>') @authorized_with_valid_token def template(infid=None): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) headers = {"Authorization": auth_data} url = "%s/infrastructures/%s/tosca" % (settings.imUrl, infid) response = requests.get(url, headers=headers) if not response.ok: flash("Error getting template: \n" + response.text, "error") template = "" else: template = response.text return render_template('deptemplate.html', template=template) @app.route('/log/<infid>') @authorized_with_valid_token def inflog(infid=None): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) headers = {"Authorization": auth_data} url = "%s/infrastructures/%s/contmsg" % (settings.imUrl, infid) response = requests.get(url, headers=headers, verify=False) if not response.ok: log = "Not found" else: log = response.text return render_template('inflog.html', log=log) @app.route('/vmlog/<infid>/<vmid>') @authorized_with_valid_token def vmlog(infid=None, vmid=None): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) headers = {"Authorization": auth_data} url = "%s/infrastructures/%s/vms/%s/contmsg" % (settings.imUrl, infid, vmid) response = requests.get(url, headers=headers, verify=False) if not response.ok: log = "Not found" else: log = response.text return render_template('inflog.html', log=log, vmid=vmid) @app.route('/outputs/<infid>') @authorized_with_valid_token def infoutputs(infid=None): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) headers = {"Authorization": auth_data} url = "%s/infrastructures/%s/outputs" % (settings.imUrl, infid) response = requests.get(url, headers=headers, verify=False) if not response.ok: outputs = {} else: outputs = response.json()["outputs"] for elem in outputs: if isinstance(outputs[elem], str) and (outputs[elem].startswith('http://') or outputs[elem].startswith('https://')): outputs[elem] = Markup( "<a href='%s' target='_blank'>%s</a>" % (outputs[elem], outputs[elem])) return render_template('outputs.html', infid=infid, outputs=outputs) @app.route('/delete/<infid>/<force>') @authorized_with_valid_token def infdel(infid=None, force=0): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) headers = {"Authorization": auth_data} url = "%s/infrastructures/%s?async=1" % (settings.imUrl, infid) if force: url += "&force=1" response = requests.delete(url, headers=headers) if not response.ok: flash("Error deleting infrastructure: " + response.text, "error") else: flash("Infrastructure '%s' successfuly deleted." % infid, "info") try: infra.delete_infra(infid) except Exception as ex: flash("Error deleting infrastructure name: %s" + str(ex), "warning") return redirect(url_for('showinfrastructures')) @app.route('/configure') @authorized_with_valid_token def configure(): selected_tosca = request.args['selected_tosca'] app.logger.debug("Template: " + json.dumps(toscaInfo[selected_tosca])) vos = utils.getStaticVOs() vos.extend(appdb.get_vo_list()) vos = list(set(vos)) if "vos" in session and session["vos"]: vos = [vo for vo in vos if vo in session["vos"]] return render_template('createdep.html', template=toscaInfo[selected_tosca], selectedTemplate=selected_tosca, vos=vos) @app.route('/sites/<vo>') def getsites(vo=None): res = "" appdb_sites = appdb.get_sites(vo) for site_name, site in appdb_sites.items(): if site["state"]: site["state"] = " (WARNING: %s state!)" % site["state"] res += '<option name="selectedSite" value=%s>%s%s</option>' % ( site_name, site_name, site["state"]) for site_name, _ in utils.getStaticSites(vo).items(): # avoid site duplication if site_name not in appdb_sites: res += '<option name="selectedSite" value=%s>%s</option>' % ( site_name, site_name) return res @app.route('/images/<site>/<vo>') @authorized_with_valid_token def getimages(site=None, vo=None): res = "" local = request.args.get('local', None) if local: access_token = oidc_blueprint.session.token['access_token'] for image_name, image_id in utils.get_site_images( site, vo, access_token, cred, session["userid"]): res += '<option name="selectedSiteImage" value=%s>%s</option>' % ( image_id, image_name) else: site_id = utils.getCachedSiteList()[site]['id'] for image in appdb.get_images(site_id, vo): res += '<option name="selectedImage" value=%s>%s</option>' % ( image, image) return res @app.route('/usage/<site>/<vo>') @authorized_with_valid_token def getusage(site=None, vo=None): try: access_token = oidc_blueprint.session.token['access_token'] quotas_dict = utils.get_site_usage(site, vo, access_token, cred, session["userid"]) return json.dumps(quotas_dict) except Exception as ex: return "Error loading site quotas: %s!" % str(ex), 400 def add_image_to_template(template, image): # Add the image to all compute nodes for node in list( template['topology_template']['node_templates'].values()): if node["type"] == "tosca.nodes.indigo.Compute": node["capabilities"]["os"]["properties"]["image"] = image app.logger.debug(yaml.dump(template, default_flow_style=False)) return template def add_auth_to_template(template, auth_data): # Add the auth_data ElasticCluster node for node in list( template['topology_template']['node_templates'].values()): if node["type"] == "tosca.nodes.ec3.ElasticCluster": if "properties" not in node: node["properties"] = {} node["properties"]["im_auth"] = auth_data app.logger.debug(yaml.dump(template, default_flow_style=False)) return template def set_inputs_to_template(template, inputs): # Add the image to all compute nodes for name, value in template['topology_template']['inputs'].items(): if name in inputs: if value["type"] == "integer": value["default"] = int(inputs[name]) elif value["type"] == "float": value["default"] = float(inputs[name]) elif value["type"] == "boolean": if inputs[name].lower() in ['yes', 'true', '1']: value["default"] = True else: value["default"] = False # Special case for ports, convert a comma separated list of ints # to a PortSpec map elif value["type"] == "map" and name == "ports": ports = inputs[name].split(",") ports_value = {} for port in ports: # Should we also open UDP? ports_value["port_%s" % port] = { "protocol": "tcp", "source": int(port) } value["default"] = ports_value else: value["default"] = inputs[name] app.logger.debug(yaml.dump(template, default_flow_style=False)) return template @app.route('/submit', methods=['POST']) @authorized_with_valid_token def createdep(): form_data = request.form.to_dict() vo = form_data['extra_opts.selectedVO'] site = form_data['extra_opts.selectedSite'] access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"], vo, site) app.logger.debug("Form data: " + json.dumps(request.form.to_dict())) with io.open(settings.toscaDir + request.args.get('template')) as stream: template = yaml.full_load(stream) if form_data['extra_opts.selectedImage'] != "": image = "appdb://%s/%s?%s" % ( form_data['extra_opts.selectedSite'], form_data['extra_opts.selectedImage'], form_data['extra_opts.selectedVO']) elif form_data['extra_opts.selectedSiteImage'] != "": site_url = utils.get_ost_image_url( form_data['extra_opts.selectedSite']) image = "ost://%s/%s" % ( site_url, form_data['extra_opts.selectedSiteImage']) else: flash("No correct image selected.", "error") return redirect(url_for('showinfrastructures')) template = add_image_to_template(template, image) template = add_auth_to_template(template, auth_data) inputs = { k: v for (k, v) in form_data.items() if not k.startswith("extra_opts.") } app.logger.debug("Parameters: " + json.dumps(inputs)) template = set_inputs_to_template(template, inputs) payload = yaml.dump(template, default_flow_style=False, sort_keys=False) headers = {"Authorization": auth_data, "Content-Type": "text/yaml"} url = "%s/infrastructures?async=1" % settings.imUrl response = requests.post(url, headers=headers, data=payload) if not response.ok: flash("Error creating infrastrucrure: \n" + response.text, "error") else: try: inf_id = os.path.basename(response.text) infra.write_infra(inf_id, {"name": form_data['infra_name']}) except Exception as ex: flash("Error storing Infrastructure name: %s" % str(ex), "warning") return redirect(url_for('showinfrastructures')) @app.route('/manage_creds') @authorized_with_valid_token def manage_creds(): sites = {} try: sites = utils.getCachedSiteList() except Exception as e: flash("Error retrieving sites list: \n" + str(e), 'warning') return render_template('service_creds.html', sites=sites) @app.route('/write_creds', methods=['GET', 'POST']) @authorized_with_valid_token def write_creds(): serviceid = request.args.get('service_id', "") servicename = request.args.get('service_name', "") app.logger.debug("service_id={}".format(serviceid)) if request.method == 'GET': res = {} projects = {} try: res = cred.get_cred(servicename, session["userid"]) projects = utils.getCachedProjectIDs(serviceid) app.logger.debug("projects={}".format(projects)) if session["vos"]: filter_projects = {} for vo, project in projects.items(): if vo in session["vos"]: filter_projects[vo] = project projects = filter_projects except Exception as ex: flash("Error reading credentials %s!" % ex, 'error') return render_template('modal_creds.html', service_creds=res, service_id=serviceid, service_name=servicename, projects=projects) else: app.logger.debug("Form data: " + json.dumps(request.form.to_dict())) creds = request.form.to_dict() try: cred.write_creds(servicename, session["userid"], creds) flash("Credentials successfully written!", 'info') except Exception as ex: flash("Error writing credentials %s!" % ex, 'error') return redirect(url_for('manage_creds')) @app.route('/delete_creds') @authorized_with_valid_token def delete_creds(): serviceid = request.args.get('service_id', "") try: cred.delete_cred(serviceid, session["userid"]) flash("Credentials successfully deleted!", 'info') except Exception as ex: flash("Error deleting credentials %s!" % ex, 'error') return redirect(url_for('manage_creds')) @app.route('/addresourcesform/<infid>') @authorized_with_valid_token def addresourcesform(infid=None): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) headers = {"Authorization": auth_data, "Accept": "text/plain"} url = "%s/infrastructures/%s/radl" % (settings.imUrl, infid) response = requests.get(url, headers=headers) if response.ok: systems = [] try: radl = radl_parse.parse_radl(response.text) systems = radl.systems except Exception as ex: flash("Error parsing RADL: \n%s" % str(ex), 'error') return render_template('addresource.html', infid=infid, systems=systems) else: flash("Error getting RADL: \n%s" % (response.text), 'error') return redirect(url_for('showinfrastructures')) @app.route('/addresources/<infid>', methods=['POST']) @authorized_with_valid_token def addresources(infid=None): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) headers = {"Authorization": auth_data, "Accept": "text/plain"} form_data = request.form.to_dict() url = "%s/infrastructures/%s/radl" % (settings.imUrl, infid) response = requests.get(url, headers=headers) if response.ok: radl = None try: radl = radl_parse.parse_radl(response.text) radl.deploys = [] for system in radl.systems: if "%s_num" % system.name in form_data: vm_num = int(form_data["%s_num" % system.name]) if vm_num > 0: radl.deploys.append(deploy(system.name, vm_num)) except Exception as ex: flash( "Error parsing RADL: \n%s\n%s" % (str(ex), response.text), 'error') if radl: headers = { "Authorization": auth_data, "Accept": "application/json" } url = "%s/infrastructures/%s" % (settings.imUrl, infid) response = requests.post(url, headers=headers, data=str(radl)) if response.ok: num = len(response.json()["uri-list"]) flash("%d nodes added successfully" % num, 'info') else: flash("Error adding nodesL: \n%s" % (response.text), 'error') return redirect(url_for('showinfrastructures')) else: flash("Error getting RADL: \n%s" % (response.text), 'error') return redirect(url_for('showinfrastructures')) @app.route('/logout') def logout(): session.clear() oidc_blueprint.session.get("/logout") return redirect(url_for('login')) @app.errorhandler(403) def forbidden(error): return render_template('error_pages/403.html', message=error.description) @app.errorhandler(404) def page_not_found(error): app.logger.error('Page not found: %s', (request.path)) return render_template('error_pages/404.html'), 404 @app.errorhandler(500) def internal_server_error(error): app.logger.error('Server Error: %s', (error)) return render_template( 'error_pages/500.html', support_email=app.config.get('SUPPORT_EMAIL')), 500 return app
def create_app(oidc_blueprint=None): app = Flask(__name__) app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_port=1, x_prefix=1) app.secret_key = "8210f566-4981-11ea-92d1-f079596e599b" app.config.from_json('config.json') settings = Settings(app.config) if 'CREDS_KEY' in os.environ: key = os.environ['CREDS_KEY'] else: key = None CSRFProtect(app) cred = Credentials(settings.db_url, key) infra = Infrastructures(settings.db_url) im = InfrastructureManager(settings.imUrl) # To Reload internally the site cache scheduler = APScheduler() scheduler.api_enabled = False scheduler.init_app(app) scheduler.start() toscaTemplates = utils.loadToscaTemplates(settings.toscaDir) toscaInfo = utils.extractToscaInfo(settings.toscaDir, settings.toscaParamsDir, toscaTemplates) app.jinja_env.filters['tojson_pretty'] = utils.to_pretty_json app.logger.debug("TOSCA INFO: " + json.dumps(toscaInfo)) loglevel = app.config.get("LOG_LEVEL") if app.config.get( "LOG_LEVEL") else "INFO" numeric_level = getattr(logging, loglevel.upper(), None) if not isinstance(numeric_level, int): raise ValueError('Invalid log level: %s' % loglevel) logging.basicConfig(level=numeric_level) oidc_base_url = app.config['OIDC_BASE_URL'] oidc_token_url = oidc_base_url + '/token' oidc_refresh_url = oidc_base_url + '/token' oidc_authorization_url = oidc_base_url + '/authorize' if not oidc_blueprint: oidc_blueprint = OAuth2ConsumerBlueprint( "oidc", __name__, client_id=app.config['OIDC_CLIENT_ID'], client_secret=app.config['OIDC_CLIENT_SECRET'], scope=app.config['OIDC_SCOPES'], base_url=oidc_base_url, token_url=oidc_token_url, auto_refresh_url=oidc_refresh_url, authorization_url=oidc_authorization_url, redirect_to='home') app.register_blueprint(oidc_blueprint, url_prefix="/login") @app.before_request def before_request_checks(): if 'external_links' not in session: session['external_links'] = settings.external_links g.analytics_tag = settings.analytics_tag g.settings = settings def authorized_with_valid_token(f): @wraps(f) def decorated_function(*args, **kwargs): if settings.debug_oidc_token: oidc_blueprint.session.token = { 'access_token': settings.debug_oidc_token } else: try: if not oidc_blueprint.session.authorized or 'username' not in session: return redirect(url_for('login')) if oidc_blueprint.session.token['expires_in'] < 20: app.logger.debug("Force refresh token") oidc_blueprint.session.get('/userinfo') except (InvalidTokenError, TokenExpiredError): flash("Token expired.", 'warning') return redirect(url_for('login')) return f(*args, **kwargs) return decorated_function @app.route('/settings') @authorized_with_valid_token def show_settings(): imUrl = "%s (v. %s)" % (settings.imUrl, im.get_version()) return render_template('settings.html', oidc_url=settings.oidcUrl, im_url=imUrl) @app.route('/login') def login(): session.clear() return render_template('home.html', oidc_name=settings.oidcName) @app.route('/') def home(): if settings.debug_oidc_token: session["vos"] = None session['userid'] = "userid" session['username'] = "******" session['gravatar'] = "" return render_template('portfolio.html', templates=toscaInfo) else: if not oidc_blueprint.session.authorized: return redirect(url_for('login')) try: account_info = oidc_blueprint.session.get( urlparse(settings.oidcUrl)[2] + "/userinfo") except (InvalidTokenError, TokenExpiredError): flash("Token expired.", 'warning') return redirect(url_for('login')) if account_info.ok: account_info_json = account_info.json() session["vos"] = None if 'eduperson_entitlement' in account_info_json: session["vos"] = utils.getUserVOs( account_info_json['eduperson_entitlement']) if settings.oidcGroups: user_groups = [] if 'groups' in account_info_json: user_groups = account_info_json['groups'] elif 'eduperson_entitlement' in account_info_json: user_groups = account_info_json[ 'eduperson_entitlement'] if not set(settings.oidcGroups).issubset(user_groups): app.logger.debug( "No match on group membership. User group membership: " + json.dumps(user_groups)) message = Markup( 'You need to be a member of the following groups: {0}. <br>' ' Please, visit <a href="{1}">{1}</a> and apply for the requested ' 'membership.'.format( json.dumps(settings.oidcGroups), settings.oidcUrl)) raise Forbidden(description=message) session['userid'] = account_info_json['sub'] if 'name' in account_info_json: session['username'] = account_info_json['name'] else: session['username'] = "" if 'given_name' in account_info_json: session['username'] = account_info_json['given_name'] if 'family_name' in account_info_json: session['username'] += " " + account_info_json[ 'family_name'] if session['username'] == "": session['username'] = account_info_json['sub'] if 'email' in account_info_json: session['gravatar'] = utils.avatar( account_info_json['email'], 26) else: session['gravatar'] = utils.avatar( account_info_json['sub'], 26) return render_template('portfolio.html', templates=toscaInfo) else: flash("Error getting User info: \n" + account_info.text, 'error') return render_template('home.html', oidc_name=settings.oidcName) @app.route('/vminfo') @authorized_with_valid_token def showvminfo(): access_token = oidc_blueprint.session.token['access_token'] vmid = request.args['vmId'] infid = request.args['infId'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) try: response = im.get_vm_info(infid, vmid, auth_data) except Exception as ex: flash("Error: %s." % ex, 'error') vminfo = {} state = "" nets = "" disks = "" deployment = "" if not response.ok: flash("Error retrieving VM info: \n" + response.text, 'error') else: app.logger.debug("VM Info: %s" % response.text) radl_json = response.json()["radl"] outports = utils.get_out_ports(radl_json) vminfo = utils.format_json_radl(radl_json) if "cpu.arch" in vminfo: del vminfo["cpu.arch"] if "state" in vminfo: state = vminfo["state"] del vminfo["state"] if "provider.type" in vminfo: deployment = vminfo["provider.type"] del vminfo["provider.type"] if "provider.host" in vminfo: if "provider.port" in vminfo: deployment += ": %s:%s" % (vminfo["provider.host"], vminfo["provider.port"]) del vminfo["provider.port"] else: deployment += ": " + vminfo["provider.host"] del vminfo["provider.host"] if "disk.0.os.name" in vminfo: del vminfo["disk.0.os.name"] cont = 0 while "net_interface.%s.connection" % cont in vminfo: if "net_interface.%s.ip" % cont in vminfo: if cont > 0: nets += Markup('<br/>') nets += Markup('<i class="fa fa-network-wired"></i>') nets += Markup( ' <span class="badge badge-secondary">%s</span>' % cont) nets += ": %s" % vminfo["net_interface.%s.ip" % cont] del vminfo["net_interface.%s.ip" % cont] if "net_interface.%s.dns_name" % cont in vminfo: nets += " (%s)" % vminfo["net_interface.%s.dns_name" % cont] del vminfo["net_interface.%s.dns_name" % cont] cont += 1 cont = 0 while "net_interface.%s.connection" % cont in vminfo: del vminfo["net_interface.%s.connection" % cont] cont += 1 for elem in vminfo: if elem.endswith("size") and isinstance(vminfo[elem], int): vminfo[elem] = "%d GB" % (vminfo[elem] / 1073741824) cont = 0 while "disk.%s.size" % cont in vminfo or "disk.%s.image.url" % cont in vminfo: if cont > 0: disks += Markup('<br/>') disks += Markup( '<i class="fa fa-database"></i> <span class="badge badge-secondary">' '%s</span><br/>' % cont) prop_map = { "size": "Size", "image.url": "URL", "device": "Device", "mount_path": "Mount Path", "fstype": "F.S. type", "os.flavour": "O.S. Flavor", "os.version": "O.S. Version" } for name, label in prop_map.items(): prop = "disk.%s.%s" % (cont, name) if prop in vminfo: disks += Markup(' ') disks += "- %s: %s" % (label, vminfo[prop]) disks += Markup('<br/>') del vminfo[prop] cont += 1 str_outports = "" for port in outports: str_outports += Markup( '<i class="fas fa-project-diagram"></i> <span class="badge ' 'badge-secondary">%s</span>' % port.get_remote_port()) if not port.is_range(): if port.get_remote_port() != port.get_local_port(): str_outports += Markup( ' <i class="fas fa-long-arrow-alt-right">' '</i> <span class="badge badge-secondary">%s</span>' % port.get_local_port()) else: str_outports += Markup( ' : </i> <span class="badge badge-secondary">%s</span>' % port.get_local_port()) str_outports += Markup('<br/>') return render_template('vminfo.html', infid=infid, vmid=vmid, vminfo=vminfo, outports=str_outports, state=state, nets=nets, deployment=deployment, disks=disks) @app.route('/managevm/<op>/<infid>/<vmid>', methods=['POST']) @authorized_with_valid_token def managevm(op=None, infid=None, vmid=None): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) try: if op == "reconfigure": response = im.reconfigure_inf(infid, auth_data, [vmid]) if op == "resize": form_data = request.form.to_dict() cpu = int(form_data['cpu']) memory = int(form_data['memory']) system_name = form_data['system_name'] radl = "system %s (cpu.count >= %d and memory.size >= %dg)" % ( system_name, cpu, memory) response = im.resize_vm(infid, vmid, radl, auth_data) else: response = im.manage_vm(op, infid, vmid, auth_data) except Exception as ex: flash("Error: %s." % ex, 'error') return redirect(url_for('showinfrastructures')) if response.ok: flash("Operation '%s' successfully made on VM ID: %s" % (op, vmid), 'info') else: flash( "Error making %s op on VM %s: \n%s" % (op, vmid, response.text), 'error') if op == "terminate": return redirect(url_for('showinfrastructures')) else: return redirect(url_for('showvminfo', infId=infid, vmId=vmid)) @app.route('/infrastructures') @authorized_with_valid_token def showinfrastructures(): access_token = oidc_blueprint.session.token['access_token'] reload_infid = None if 'reload' in request.args: reload_infid = request.args['reload'] auth_data = "type = InfrastructureManager; token = %s" % access_token inf_list = [] try: inf_list = im.get_inf_list(auth_data) except Exception as ex: flash("Error: %s." % ex, 'error') infrastructures = {} for inf_id in inf_list: infrastructures[inf_id] = {} try: infra_data = infra.get_infra(inf_id) except Exception: infra_data = {} infrastructures[inf_id] = {'name': '', 'state': {}} if 'name' in infra_data: infrastructures[inf_id]['name'] = infra_data["name"] if 'state' in infra_data: infrastructures[inf_id]['state'] = infra_data["state"] return render_template('infrastructures.html', infrastructures=infrastructures, reload=reload_infid) @app.route('/infrastructures/state') @authorized_with_valid_token def infrastructure_state(): access_token = oidc_blueprint.session.token['access_token'] infid = request.args['infid'] if not infid: return {"state": "error", "vm_states": {}} auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) try: state = im.get_inf_state(infid, auth_data) try: infra.write_infra(infid, {"state": state}) except Exception as ex: app.logger.error("Error saving infrastructure state: %s" % ex) return state except Exception: return {"state": "error", "vm_states": {}} @app.route('/template/<infid>') @authorized_with_valid_token def template(infid=None): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) template = "" try: response = im.get_inf_property(infid, 'tosca', auth_data) if not response.ok: raise Exception(response.text) template = response.text except Exception as ex: flash("Error getting template: \n%s" % ex, "error") return render_template('deptemplate.html', template=template) def add_colors(log): """Add color in error messages in logs.""" res = "" lines = log.split('\n') for n, line in enumerate(lines): if "ERROR executing task" in line or ( "fatal: " in line and "...ignoring" not in lines[n + 1]): res += Markup( '<span class="bg-danger text-white">%s</span><br>' % line) else: res += Markup("%s<br>" % line) return res @app.route('/log/<infid>') @authorized_with_valid_token def inflog(infid=None): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) log = "Not found" try: response = im.get_inf_property(infid, 'contmsg', auth_data) if not response.ok: raise Exception(response.text) log = add_colors(response.text) except Exception as ex: flash("Error: %s." % ex, 'error') return render_template('inflog.html', log=log) @app.route('/vmlog/<infid>/<vmid>') @authorized_with_valid_token def vmlog(infid=None, vmid=None): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) log = "Not found" try: response = im.get_vm_contmsg(infid, vmid, auth_data) if not response.ok: raise Exception(response.text) log = add_colors(response.text) except Exception as ex: flash("Error: %s." % ex, 'error') return render_template('inflog.html', log=log, vmid=vmid) @app.route('/outputs/<infid>') @authorized_with_valid_token def infoutputs(infid=None): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) outputs = {} try: response = im.get_inf_property(infid, 'outputs', auth_data) if not response.ok: raise Exception(response.text) outputs = response.json()["outputs"] for elem in outputs: if isinstance(outputs[elem], str) and (outputs[elem].startswith('http://') or outputs[elem].startswith('https://')): outputs[elem] = Markup( "<a href='%s' target='_blank'>%s</a>" % (outputs[elem], outputs[elem])) except Exception as ex: flash("Error: %s." % ex, 'error') return render_template('outputs.html', infid=infid, outputs=outputs) @app.route('/configure') @authorized_with_valid_token def configure(): selected_tosca = request.args['selected_tosca'] app.logger.debug("Template: " + json.dumps(toscaInfo[selected_tosca])) creds = cred.get_creds(session['userid'], 1) return render_template('createdep.html', template=toscaInfo[selected_tosca], selectedTemplate=selected_tosca, creds=creds) @app.route('/vos') def getvos(): res = "" vos = utils.getStaticVOs() vos.extend(appdb.get_vo_list()) vos = list(set(vos)) if "vos" in session and session["vos"]: vos = [vo for vo in vos if vo in session["vos"]] for vo in vos: res += '<option name="selectedVO" value=%s>%s</option>' % (vo, vo) return res @app.route('/sites/<vo>') def getsites(vo=None): res = "" static_sites = utils.getStaticSites(vo) for site_name, site in static_sites.items(): res += '<option name="selectedSite" value=%s>%s</option>' % ( site['url'], site_name) appdb_sites = appdb.get_sites(vo) for site_name, site in appdb_sites.items(): # avoid site duplication if site_name not in static_sites: if site["state"]: site["state"] = " (WARNING: %s state!)" % site["state"] res += '<option name="selectedSite" value=%s>%s%s</option>' % ( site['url'], site_name, site["state"]) return res @app.route('/images/<cred_id>') @authorized_with_valid_token def getimages(cred_id=None): res = "" local = request.args.get('local', None) if local: access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"], cred_id) try: response = im.get_cloud_images(cred_id, auth_data) if not response.ok: raise Exception(response.text) for image in response.json()["images"]: res += '<option name="selectedSiteImage" value=%s>%s</option>' % ( image['uri'], image['name']) except Exception as ex: res += '<option name="selectedSiteImage" value=%s>%s</option>' % ( ex, ex) else: site, _, vo = utils.get_site_info(cred_id, cred, session["userid"]) for image_name, image_id in appdb.get_images(site['id'], vo): res += '<option name="selectedImage" value=%s>%s</option>' % ( image_id, image_name) return res @app.route('/usage/<cred_id>') @authorized_with_valid_token def getusage(cred_id=None): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"], cred_id) try: response = im.get_cloud_quotas(cred_id, auth_data) if not response.ok: raise Exception(response.text) return json.dumps(response.json()["quotas"]) except Exception as ex: return "Error loading site quotas: %s!" % str(ex), 400 def add_image_to_template(template, image): # Add the image to all compute nodes for node in list( template['topology_template']['node_templates'].values()): if node["type"] == "tosca.nodes.indigo.Compute": node["capabilities"]["os"]["properties"]["image"] = image app.logger.debug(yaml.dump(template, default_flow_style=False)) return template def add_auth_to_template(template, auth_data): # Add the auth_data ElasticCluster node for node in list( template['topology_template']['node_templates'].values()): if node["type"] == "tosca.nodes.ec3.ElasticCluster": if "properties" not in node: node["properties"] = {} node["properties"]["im_auth"] = auth_data app.logger.debug(yaml.dump(template, default_flow_style=False)) return template def add_record_name_to_template(template, replace_name): # Add a random name in the DNS record name for node in list( template['topology_template']['node_templates'].values()): if node["type"] == "tosca.nodes.ec3.DNSRegistry": node["properties"]["record_name"] = node["properties"][ "record_name"].replace("*", replace_name) return template def set_inputs_to_template(template, inputs): # Add the image to all compute nodes for name, value in template['topology_template']['inputs'].items(): if name in inputs: if value["type"] == "integer": value["default"] = int(inputs[name]) elif value["type"] == "float": value["default"] = float(inputs[name]) elif value["type"] == "boolean": if inputs[name].lower() in ['yes', 'true', '1']: value["default"] = True else: value["default"] = False # Special case for ports, convert a comma separated list of ints # to a PortSpec map elif value["type"] == "map" and name == "ports": ports = inputs[name].split(",") ports_value = {} for port in ports: # Should we also open UDP? ports_value["port_%s" % port] = { "protocol": "tcp", "source": int(port) } value["default"] = ports_value else: value["default"] = inputs[name] app.logger.debug(yaml.dump(template, default_flow_style=False)) return template @app.route('/submit', methods=['POST']) @authorized_with_valid_token def createdep(): form_data = request.form.to_dict() app.logger.debug("Form data: " + json.dumps(request.form.to_dict())) cred_id = form_data['extra_opts.selectedCred'] cred_data = cred.get_cred(cred_id, session["userid"]) access_token = oidc_blueprint.session.token['access_token'] image = None if cred_data['type'] in [ 'fedcloud', 'OpenStack', 'OpenNebula', 'Linode', 'Orange', 'GCE' ]: if form_data['extra_opts.selectedImage'] != "": site, _, vo = utils.get_site_info(cred_id, cred, session["userid"]) image = "appdb://%s/%s?%s" % ( site['name'], form_data['extra_opts.selectedImage'], vo) elif form_data['extra_opts.selectedSiteImage'] != "": image = form_data['extra_opts.selectedSiteImage'] else: image_id = form_data['extra_opts.imageID'] protocol_map = { 'EC2': 'aws', 'Kubernetes': 'docker', 'Azure': 'azr' } image = "%s://%s" % (protocol_map.get(cred_data['type']), image_id) if not image: flash("No correct image specified.", "error") return redirect(url_for('showinfrastructures')) auth_data = utils.getUserAuthData(access_token, cred, session["userid"], cred_id) with io.open(settings.toscaDir + request.args.get('template')) as stream: template = yaml.full_load(stream) template = add_image_to_template(template, image) template = add_image_to_template(template, image) template = add_auth_to_template(template, auth_data) # Specially added for OSCAR clusters template = add_record_name_to_template(template, utils.generate_random_name()) inputs = { k: v for (k, v) in form_data.items() if not k.startswith("extra_opts.") } app.logger.debug("Parameters: " + json.dumps(inputs)) template = set_inputs_to_template(template, inputs) payload = yaml.dump(template, default_flow_style=False, sort_keys=False) try: response = im.create_inf(payload, auth_data) if not response.ok: raise Exception(response.text) try: inf_id = os.path.basename(response.text) infra.write_infra( inf_id, { "name": form_data['infra_name'], "state": { "state": "pending", "vm_states": {} } }) except Exception as ex: flash("Error storing Infrastructure name: %s" % str(ex), "warning") except Exception as ex: flash("Error creating infrastrucrure: \n%s." % ex, 'error') return redirect(url_for('showinfrastructures')) @app.route('/manage_creds') @authorized_with_valid_token def manage_creds(): creds = {} try: creds = cred.get_creds(session["userid"]) except Exception as e: flash("Error retrieving credentials: \n" + str(e), 'warning') return render_template('service_creds.html', creds=creds) @app.route('/write_creds', methods=['GET', 'POST']) @authorized_with_valid_token def write_creds(): cred_id = request.args.get('cred_id', "") cred_type = request.args.get('cred_type', "") app.logger.debug("service_id={}".format(cred_id)) if request.method == 'GET': res = {} try: if cred_id: res = cred.get_cred(cred_id, session["userid"]) cred_type = res['type'] except Exception as ex: flash("Error reading credentials %s!" % ex, 'error') return render_template('modal_creds.html', creds=res, cred_id=cred_id, cred_type=cred_type) else: app.logger.debug("Form data: " + json.dumps(request.form.to_dict())) creds = request.form.to_dict() if 'cred_id' in creds: cred_id = creds['cred_id'] del creds['cred_id'] if 'password' in request.files: if request.files['password'].filename != "": creds['password'] = request.files['password'].read( ).decode() try: if 'password' in creds and creds['password'] in [None, '']: del creds['password'] if 'csrf_token' in creds: del creds['csrf_token'] cred.write_creds(creds["id"], session["userid"], creds, cred_id in [None, '']) flash("Credentials successfully written!", 'info') except db.IntegrityError: flash("Error writing credentials: Duplicated Credential ID!", 'error') except Exception as ex: flash("Error writing credentials: %s!" % ex, 'error') return redirect(url_for('manage_creds')) @app.route('/delete_creds') @authorized_with_valid_token def delete_creds(): cred_id = request.args.get('cred_id', "") try: cred.delete_cred(cred_id, session["userid"]) flash("Credentials successfully deleted!", 'info') except Exception as ex: flash("Error deleting credentials %s!" % ex, 'error') return redirect(url_for('manage_creds')) @app.route('/enable_creds') @authorized_with_valid_token def enable_creds(): cred_id = request.args.get('cred_id', "") enable = request.args.get('enable', 0) try: cred.enable_cred(cred_id, session["userid"], enable) except Exception as ex: flash("Error updating credentials %s!" % ex, 'error') return redirect(url_for('manage_creds')) @app.route('/addresourcesform/<infid>') @authorized_with_valid_token def addresourcesform(infid=None): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) try: response = im.get_inf_property(infid, 'radl', auth_data) if not response.ok: raise Exception(response.text) systems = [] try: radl = radl_parse.parse_radl(response.text) systems = radl.systems except Exception as ex: flash("Error parsing RADL: \n%s" % str(ex), 'error') return render_template('addresource.html', infid=infid, systems=systems) except Exception as ex: flash("Error getting RADL: \n%s" % ex, 'error') return redirect(url_for('showinfrastructures')) @app.route('/addresources/<infid>', methods=['POST']) @authorized_with_valid_token def addresources(infid=None): access_token = oidc_blueprint.session.token['access_token'] form_data = request.form.to_dict() auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) try: response = im.get_inf_property(infid, 'radl', auth_data) except Exception as ex: flash("Error: %s." % ex, 'error') if response.ok: radl = None try: radl = radl_parse.parse_radl(response.text) radl.deploys = [] for system in radl.systems: sys_dep = deploy(system.name, 0) if "%s_num" % system.name in form_data: vm_num = int(form_data["%s_num" % system.name]) if vm_num > 0: sys_dep.vm_number = vm_num radl.deploys.append(sys_dep) except Exception as ex: flash( "Error parsing RADL: \n%s\n%s" % (str(ex), response.text), 'error') if radl: try: response = im.addresource_inf(infid, str(radl), auth_data) if not response.ok: raise Exception(response.text) num = len(response.json()["uri-list"]) flash("%d nodes added successfully" % num, 'info') except Exception as ex: flash("Error adding nodes: \n%s\n%s" % (ex, response.text), 'error') return redirect(url_for('showinfrastructures')) else: flash("Error getting RADL: \n%s" % (response.text), 'error') return redirect(url_for('showinfrastructures')) @app.route('/manage_inf/<infid>/<op>', methods=['POST']) @authorized_with_valid_token def manage_inf(infid=None, op=None): access_token = oidc_blueprint.session.token['access_token'] auth_data = utils.getUserAuthData(access_token, cred, session["userid"]) reload = None try: if op in ["start", "stop"]: response = im.manage_inf(op, infid, auth_data) if not response.ok: raise Exception(response.text) flash( "Operation '%s' successfully made on Infrastructure ID: %s" % (op, infid), 'info') reload = infid elif op == "delete": form_data = request.form.to_dict() force = False if 'force' in form_data and form_data['force'] != "0": force = True # Specially added for OSCAR clusters success, msg = utils.delete_dns_record(infid, im, auth_data) if not success: app.logger.error('Error deleting DNS record: %s', (msg)) response = im.delete_inf(infid, force, auth_data) if not response.ok: raise Exception(response.text) flash("Infrastructure '%s' successfuly deleted." % infid, "info") try: infra_data = infra.get_infra(infid) infra_data["state"]["state"] = "deleting" infra.write_infra(infid, infra_data) scheduler.add_job('delete_infra_%s' % infid, delete_infra, trigger='interval', seconds=60, args=(infid, )) except Exception as dex: app.logger.error( 'Error setting infra state to deleting.: %s', (dex)) elif op == "reconfigure": response = im.reconfigure_inf(infid, auth_data) if not response.ok: raise Exception(response.text) flash("Reconfiguration process successfuly started.", "info") except Exception as ex: flash("Error in '%s' operation: %s." % (op, ex), 'error') return redirect(url_for('showinfrastructures', reload=reload)) @app.route('/logout') def logout(): session.clear() oidc_blueprint.session.get("/logout") return redirect(url_for('login')) @app.errorhandler(403) def forbidden(error): return render_template('error_pages/403.html', message=error.description) @app.errorhandler(404) def page_not_found(error): app.logger.error('Page not found: %s', (request.path)) return render_template('error_pages/404.html'), 404 @app.errorhandler(500) def internal_server_error(error): app.logger.error('Server Error: %s', (error)) return render_template( 'error_pages/500.html', support_email=app.config.get('SUPPORT_EMAIL')), 500 # Reload internally the site cache @scheduler.task('interval', id='reload_sites', seconds=5) def reload_sites(): scheduler.modify_job('reload_sites', trigger='interval', seconds=settings.appdb_cache_timeout - 30) with app.app_context(): app.logger.debug('Reload Site List.') g.settings = settings utils.getCachedSiteList(True) def delete_infra(infid): infra.delete_infra(infid) scheduler.delete_job('delete_infra_%s' % infid) return app