diff --git a/backend/app.py b/backend/app.py index 9d5aec625a14e7cf570894c18eb0d5a2d665b205..8394a1fff033ab738fe5bfc01beee90624e1c1c7 100644 --- a/backend/app.py +++ b/backend/app.py @@ -32,6 +32,7 @@ from helpers import ( unauthorized_error, ) +import cluster_config from config import * import logging @@ -59,13 +60,17 @@ app.config["SECRET_KEY"] = SECRET_KEY app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_DATABASE_URI app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = SQLALCHEMY_TRACK_MODIFICATIONS +app.logger.setLevel(logging.INFO) +app.logger.info("Starting dashboard backend.") + cors = CORS(app) Migrate(app, db) db.init_app(app) - -app.logger.setLevel(logging.INFO) -app.logger.info("Starting dashboard backend.") +# We need this app context in order to talk the database, which is managed by +# flask-sqlalchemy, which assumes a flask app context. +with app.app_context(): + cluster_config.populate_apps() app.register_blueprint(api_v1) app.register_blueprint(web) diff --git a/backend/areas/apps/models.py b/backend/areas/apps/models.py index ef930501a9d8be66a5d27114531edd57477c2574..0f2b00eca24c11d58a20944bd670003a7d48ca93 100644 --- a/backend/areas/apps/models.py +++ b/backend/areas/apps/models.py @@ -30,6 +30,12 @@ class App(db.Model): # URL is stored in a configmap (see get_url) url = db.Column(String(length=128), unique=False) + def __init__(self, slug, name, external=False, url=None): + self.slug = slug + self.name = name + self.external = external + self.url = url + def __repr__(self): return f"{self.id} <{self.name}>" diff --git a/backend/cluster_config.py b/backend/cluster_config.py new file mode 100644 index 0000000000000000000000000000000000000000..1ea44e1b4c9daccd7afa76b67f94b230fea07ce3 --- /dev/null +++ b/backend/cluster_config.py @@ -0,0 +1,45 @@ +from database import db +from areas.apps.models import App +import helpers.kubernetes as k8s + +import logging +import yaml + +# Read in two configmaps from the cluster, which specify which apps should be +# present in the database. +def populate_apps(): + logging.info("cluster_config: populating apps") + database_apps = {} + for app in App.query.all(): + slug = app.slug + database_apps[slug] = app + logging.info(f"database app: {slug}") + _populate_apps_from(database_apps, "stackspin-apps") + _populate_apps_from(database_apps, "stackspin-apps-custom") + +# Read a list of apps from a configmap. Check if they are already present in +# the database, and if not, add missing ones there. Properties `name`, +# `external` and `url` can be specified in yaml format in the configmap value +# contents. +def _populate_apps_from(database_apps, configmap_name): + cm_apps = k8s.get_kubernetes_config_map_data(configmap_name, "flux-system") + if cm_apps is None: + logging.info(f"Could not find configmap '{configmap_name}' in namespace 'flux-system'; ignoring.") + else: + for app_slug, app_data in cm_apps.items(): + logging.info(f"configmap app: {app_slug}") + if app_slug in database_apps: + logging.info(f" already present in database") + else: + logging.info(f" not present in database, adding!") + data = yaml.safe_load(app_data) + name = data["name"] + logging.info(f" name: {name}") + external = data.get("external", False) + logging.info(f" type external: {type(external)}") + logging.info(f" external: {external}") + url = data.get("url", None) + logging.info(f" url: {url}") + new_app = App(slug=app_slug, name=name, external=external, url=url) + db.session.add(new_app) + db.session.commit() diff --git a/backend/requirements.txt b/backend/requirements.txt index eae5bd291b0e1fc6c0733dd3fc9ca23eb52145d1..9a625388d2d0c32464e1a046104c2f90065d0371 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -25,6 +25,7 @@ platformdirs==2.5.1 pycparser==2.21 PyJWT==2.3.0 pyrsistent==0.18.1 +PyYAML==6.0 regex==2022.3.15 requests==2.27.1 requests-oauthlib==1.3.1