diff --git a/backend/app.py b/backend/app.py index 76dddf1ae99111eda75ab54f0c9a8d598ddd9e90..067d4e14b3cbf94dde567d2e8819cbc504255928 100644 --- a/backend/app.py +++ b/backend/app.py @@ -1,8 +1,9 @@ from flask import Flask, jsonify from flask_cors import CORS from flask_jwt_extended import JWTManager -from flask_migrate import Migrate +import flask_migrate from jsonschema.exceptions import ValidationError +from NamedAtomicLock import NamedAtomicLock from werkzeug.exceptions import BadRequest # These imports are required @@ -32,8 +33,11 @@ from helpers import ( unauthorized_error, ) +import cluster_config from config import * import logging +import migration_reset +import sys # Configure logging. from logging.config import dictConfig @@ -59,12 +63,41 @@ 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) + cors = CORS(app) -Migrate(app, db) -db.init_app(app) +db.init_app(app) -app.logger.setLevel(logging.INFO) +# We'll now perform some initialization routines. Because these have to be done +# once at startup, not for every gunicorn worker, we take a machine-wide lock +# for this. +init_lock = NamedAtomicLock('dashboard_init') +if init_lock.acquire(): + try: + with app.app_context(): + # We have reset the alembic migration history at Stackspin version 2.2. + # This checks whether we need to prepare the database to follow that + # change. + migration_reset.reset() + flask_migrate.Migrate(app, db) + try: + with app.app_context(): + flask_migrate.upgrade() + except Exception as e: + app.logger.info(f"upgrade failed: {type(e)}: {e}") + sys.exit(2) + + # 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(): + # Load the list of apps from a configmap and store any missing ones in the + # database. + cluster_config.populate_apps() + # Same for the list of oauthclients. + cluster_config.populate_oauthclients() + finally: + init_lock.release() 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..069c73751643f42af0619e65c7d6425d4802138d 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}>" @@ -303,6 +309,7 @@ class OAuthClientApp(db.Model): # pylint: disable=too-few-public-methods This mapping exists so that * you can have a different name for the OAuth client than for the app, and * you can have multiple OAuth clients that belong to the same app. + Also, some apps might have no OAuth client at all. """ __tablename__ = "oauthclient_app" diff --git a/backend/cluster_config.py b/backend/cluster_config.py new file mode 100644 index 0000000000000000000000000000000000000000..20ec9e98023dfd01b46a30492f74057aea1a1aed --- /dev/null +++ b/backend/cluster_config.py @@ -0,0 +1,83 @@ +from database import db +from areas.apps.models import App, OAuthClientApp +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() + +# Read in two configmaps from the cluster, which specify which oauthclients +# should be present in the database. +def populate_oauthclients(): + logging.info("cluster_config: populating oauthclients") + database_oauthclients = {} + for client in OAuthClientApp.query.all(): + id = client.oauthclient_id + database_oauthclients[id] = client + logging.info(f"database oauthclient: {id}") + _populate_oauthclients_from(database_oauthclients, "stackspin-oauthclients") + _populate_oauthclients_from(database_oauthclients, "stackspin-oauthclients-custom") + +# Read a list of oauthclients from a configmap. Check if they are already +# present in the database, and if not, add missing ones there. The value of the +# mapping is taken to be the slug of the app the oauthclient belongs to. +def _populate_oauthclients_from(database_oauthclients, configmap_name): + cm_oauthclients = k8s.get_kubernetes_config_map_data(configmap_name, "flux-system") + if cm_oauthclients is None: + logging.info(f"Could not find configmap '{configmap_name}' in namespace 'flux-system'; ignoring.") + else: + for client_id, client_app in cm_oauthclients.items(): + logging.info(f"configmap oauthclient: {client_id}") + if client_id in database_oauthclients: + logging.info(f" already present in database") + else: + logging.info(f" not present in database, adding!") + # Take the value of the configmap mapping (`client_app`) and + # interpret it as the slug of the app that this oauthclient + # belongs to. + app = App.query.filter_by(slug=client_app).first() + if not app: + logging.error(f" could not find app with slug {client_app}") + continue + new_client = OAuthClientApp(oauthclient_id=client_id, app_id=app.id) + logging.info(f" new oauth client: {new_client}") + db.session.add(new_client) + db.session.commit() diff --git a/backend/migration_reset.py b/backend/migration_reset.py new file mode 100644 index 0000000000000000000000000000000000000000..4f674c75ecff4e31ccf744818978580270e4ef48 --- /dev/null +++ b/backend/migration_reset.py @@ -0,0 +1,34 @@ +from sqlalchemy import exc + +from database import db +import logging + +# We "reset" the alembic version history for Stackspin 2.2, to clean up our old +# mess of database migrations a bit, and in particular to make the transition +# easier to moving the source of truth for some of the data (list of apps) out +# of the database and into configmaps. This function deals with older clusters +# that have to be led through this transition. To determine if we need to do +# anything, we look at the `alembic_version` value in the database. If it's a +# legacy version, we delete the table so the alembic migration will view the +# database as "empty" and perform all new migrations on it. The new initial +# migration will have to handle that case specially, by checking if any tables +# already exist, and not do anything in that case. +def reset(): + logging.info("Checking if alembic version needs to be reset.") + version = None + try: + result = db.session.execute("select version_num from alembic_version") + for row in result: + version = row[0] + except exc.ProgrammingError: + # We assume this means the alembic_version table doesn't exist, which + # is expected for new clusters. + pass + logging.info(f"alembic version: {version}") + legacy_versions = ["fc0892d07771", "3fa0c38ea1ac", "e08df0bef76f", "b514cca2d47b", "5f462d2d9d25", "27761560bbcb"] + if version in legacy_versions: + logging.info("This is an old version: resetting.") + db.session.execute("drop table alembic_version") + else: + logging.info("This is not a known legacy version: not resetting.") + diff --git a/backend/migrations/alembic.ini b/backend/migrations/alembic.ini index ec9d45c26a6bb54e833fd4e6ce2de29343894f4b..ef355cdd0bc77377516a78e5f891f20b8573b403 100644 --- a/backend/migrations/alembic.ini +++ b/backend/migrations/alembic.ini @@ -8,43 +8,3 @@ # the 'revision' command, regardless of autogenerate # revision_environment = false - -# Logging configuration -[loggers] -keys = root,sqlalchemy,alembic,flask_migrate - -[handlers] -keys = console - -[formatters] -keys = generic - -[logger_root] -level = WARN -handlers = console -qualname = - -[logger_sqlalchemy] -level = WARN -handlers = -qualname = sqlalchemy.engine - -[logger_alembic] -level = INFO -handlers = -qualname = alembic - -[logger_flask_migrate] -level = INFO -handlers = -qualname = flask_migrate - -[handler_console] -class = StreamHandler -args = (sys.stderr,) -level = NOTSET -formatter = generic - -[formatter_generic] -format = %(levelname)-5.5s [%(name)s] %(message)s -datefmt = %H:%M:%S diff --git a/backend/migrations/env.py b/backend/migrations/env.py index 68feded2a040005310d770ac7136b2e4ff8a6312..2a7628b80babbf6b5a2777efe7e02c5c115c391c 100644 --- a/backend/migrations/env.py +++ b/backend/migrations/env.py @@ -13,7 +13,9 @@ config = context.config # Interpret the config file for Python logging. # This line sets up loggers basically. -fileConfig(config.config_file_name) +# We commented this out, because we want to configure logging in the app +# itself, not here. +# fileConfig(config.config_file_name) logger = logging.getLogger('alembic.env') # add your model's MetaData object here diff --git a/backend/migrations/versions/27761560bbcb_.py b/backend/migrations/versions/27761560bbcb_.py deleted file mode 100644 index baa80e4969b00d9fcb03b6048d254703d6a07759..0000000000000000000000000000000000000000 --- a/backend/migrations/versions/27761560bbcb_.py +++ /dev/null @@ -1,46 +0,0 @@ -"""empty message - -Revision ID: 27761560bbcb -Revises: -Create Date: 2021-12-21 06:07:14.857940 - -""" -import sqlalchemy as sa -from alembic import op - -# revision identifiers, used by Alembic. -revision = "27761560bbcb" -down_revision = None -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.create_table( - "app", - sa.Column("id", sa.Integer(), nullable=False), - sa.Column("name", sa.String(length=64), nullable=True), - sa.Column("slug", sa.String(length=64), nullable=True), - sa.PrimaryKeyConstraint("id"), - sa.UniqueConstraint("slug"), - ) - op.create_table( - "app_role", - sa.Column("user_id", sa.String(length=64), nullable=False), - sa.Column("app_id", sa.Integer(), nullable=False), - sa.Column("role", sa.String(length=64), nullable=True), - sa.ForeignKeyConstraint( - ["app_id"], - ["app.id"], - ), - sa.PrimaryKeyConstraint("user_id", "app_id"), - ) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table("app_role") - op.drop_table("app") - # ### end Alembic commands ### diff --git a/backend/migrations/versions/3fa0c38ea1ac_add_velero_as_app.py b/backend/migrations/versions/3fa0c38ea1ac_add_velero_as_app.py deleted file mode 100644 index 5caae97d62acdabc750580389246cbc376162c35..0000000000000000000000000000000000000000 --- a/backend/migrations/versions/3fa0c38ea1ac_add_velero_as_app.py +++ /dev/null @@ -1,25 +0,0 @@ -"""add-velero-as-app - -Revision ID: 3fa0c38ea1ac -Revises: e08df0bef76f -Create Date: 2022-10-13 09:40:44.290319 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = '3fa0c38ea1ac' -down_revision = 'e08df0bef76f' -branch_labels = None -depends_on = None - - -def upgrade(): - # Add monitoring app - op.execute(f'INSERT IGNORE INTO app (`name`, `slug`) VALUES ("Velero","velero")') - - -def downgrade(): - pass diff --git a/backend/migrations/versions/5f462d2d9d25_convert_role_column_to_table.py b/backend/migrations/versions/5f462d2d9d25_convert_role_column_to_table.py deleted file mode 100644 index 53a8a1d5defc9223443200f79649c703e6b4025c..0000000000000000000000000000000000000000 --- a/backend/migrations/versions/5f462d2d9d25_convert_role_column_to_table.py +++ /dev/null @@ -1,48 +0,0 @@ -"""convert role column to table - -Revision ID: 5f462d2d9d25 -Revises: 27761560bbcb -Create Date: 2022-04-13 15:00:27.182898 - -""" -from alembic import op -import sqlalchemy as sa -from sqlalchemy.dialects import mysql - -# revision identifiers, used by Alembic. -revision = "5f462d2d9d25" -down_revision = "27761560bbcb" -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - role_table = op.create_table( - "role", - sa.Column("id", sa.Integer(), nullable=False), - sa.Column("name", sa.String(length=64), nullable=True), - sa.PrimaryKeyConstraint("id"), - ) - op.add_column("app_role", sa.Column("role_id", sa.Integer(), nullable=True)) - op.create_foreign_key(None, "app_role", "role", ["role_id"], ["id"]) - # ### end Alembic commands ### - - # Insert default role "admin" as ID 1 - op.execute(sa.insert(role_table).values(id=1,name="admin")) - # Set role_id 1 to all current "admin" users - op.execute("UPDATE app_role SET role_id = 1 WHERE role = 'admin'") - - # Drop old column - op.drop_column("app_role", "role") - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column( - "app_role", sa.Column("role", mysql.VARCHAR(length=64), nullable=True) - ) - op.drop_constraint(None, "app_role", type_="foreignkey") - op.drop_column("app_role", "role_id") - op.drop_table("role") - # ### end Alembic commands ### diff --git a/backend/migrations/versions/7d27395c892a_new_migration.py b/backend/migrations/versions/7d27395c892a_new_migration.py new file mode 100644 index 0000000000000000000000000000000000000000..94a1d844c0918712970147183025150a28ccd37c --- /dev/null +++ b/backend/migrations/versions/7d27395c892a_new_migration.py @@ -0,0 +1,72 @@ +"""Initial version after history reset: Create tables and fill the "role" one + +Revision ID: 7d27395c892a +Revises: +Create Date: 2023-01-18 14:48:23.996261 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import mysql +from sqlalchemy.engine.reflection import Inspector + +# revision identifiers, used by Alembic. +revision = '7d27395c892a' +down_revision = None +branch_labels = None +depends_on = None + +conn = op.get_bind() +inspector = Inspector.from_engine(conn) +tables = inspector.get_table_names() + +def upgrade(): + if "app" not in tables: + op.create_table( + "app", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("name", sa.String(length=64), nullable=False), + sa.Column("slug", sa.String(length=64), nullable=False), + sa.Column("external", sa.Boolean(), server_default='0', nullable=False), + sa.Column("url", sa.String(length=128), nullable=True), + sa.PrimaryKeyConstraint("id"), + sa.UniqueConstraint("slug"), + ) + + if "role" not in tables: + op.create_table( + "role", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("name", sa.String(length=64), nullable=True), + sa.PrimaryKeyConstraint("id") + ) + op.execute("INSERT INTO `role` (id, `name`) VALUES (1, 'admin')") + op.execute("INSERT INTO `role` (id, `name`) VALUES (2, 'user')") + op.execute("INSERT INTO `role` (id, `name`) VALUES (3, 'no access')") + + if "app_role" not in tables: + op.create_table( + "app_role", + sa.Column("user_id", sa.String(length=64), nullable=False), + sa.Column("app_id", sa.Integer(), nullable=False), + sa.Column("role_id", sa.Integer(), nullable=True), + sa.PrimaryKeyConstraint("user_id", "app_id"), + sa.ForeignKeyConstraint(["app_id"],["app.id"]), + sa.ForeignKeyConstraint(["role_id"],["role.id"]) + ) + + if "oauthclient_app" not in tables: + op.create_table('oauthclient_app', + sa.Column('oauthclient_id', mysql.VARCHAR(length=64), nullable=False), + sa.Column('app_id', mysql.INTEGER(display_width=11), autoincrement=False, nullable=False), + sa.PrimaryKeyConstraint('oauthclient_id'), + sa.ForeignKeyConstraint(['app_id'], ['app.id']), + mysql_default_charset='utf8mb3', + mysql_engine='InnoDB' + ) + +def downgrade(): + op.drop_table("oauthclient_app") + op.drop_table("app_role") + op.drop_table("role") + op.drop_table("app") \ No newline at end of file diff --git a/backend/migrations/versions/b514cca2d47b_add_user_role.py b/backend/migrations/versions/b514cca2d47b_add_user_role.py deleted file mode 100644 index 058694200fe0e2c1a9b6ca82abf9c023e5562b40..0000000000000000000000000000000000000000 --- a/backend/migrations/versions/b514cca2d47b_add_user_role.py +++ /dev/null @@ -1,76 +0,0 @@ -"""update apps and add 'user' and 'no access' role - -Revision ID: b514cca2d47b -Revises: 5f462d2d9d25 -Create Date: 2022-06-08 17:24:51.305129 - -""" -from alembic import op -import sqlalchemy as sa - -# revision identifiers, used by Alembic. -revision = 'b514cca2d47b' -down_revision = '5f462d2d9d25' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### end Alembic commands ### - - # Check and update app table in DB - apps = { - "dashboard": "Dashboard", - "wekan": "Wekan", - "wordpress": "WordPress", - "nextcloud": "Nextcloud", - "zulip": "Zulip" - } - # app table - app_table = sa.table('app', sa.column('id', sa.Integer), sa.column( - 'name', sa.String), sa.column('slug', sa.String)) - - existing_apps = op.get_bind().execute(app_table.select()).fetchall() - existing_app_slugs = [app['slug'] for app in existing_apps] - for app_slug in apps.keys(): - if app_slug in existing_app_slugs: - op.execute(f'UPDATE app SET `name` = "{apps.get(app_slug)}" WHERE slug = "{app_slug}"') - else: - op.execute(f'INSERT INTO app (`name`, slug) VALUES ("{apps.get(app_slug)}","{app_slug}")') - - # Fetch all apps including newly created - existing_apps = op.get_bind().execute(app_table.select()).fetchall() - # Insert role "user" as ID 2 - op.execute("INSERT INTO `role` (id, `name`) VALUES (2, 'user')") - # Insert role "no access" as ID 3 - op.execute("INSERT INTO `role` (id, `name`) VALUES (3, 'no access')") - # Set role_id 2 to all current "user" users which by have NULL role ID - op.execute("UPDATE app_role SET role_id = 2 WHERE role_id IS NULL") - - # Add 'no access' role for all users that don't have any roles for specific apps - app_roles_table = sa.table('app_role', sa.column('user_id', sa.String), sa.column( - 'app_id', sa.Integer), sa.column('role_id', sa.Integer)) - - app_ids = [app['id'] for app in existing_apps] - app_roles = op.get_bind().execute(app_roles_table.select()).fetchall() - user_ids = set([app_role['user_id'] for app_role in app_roles]) - - for user_id in user_ids: - existing_user_app_ids = [x['app_id'] for x in list(filter(lambda role: role['user_id'] == user_id, app_roles))] - missing_user_app_ids = [x for x in app_ids if x not in existing_user_app_ids] - - if len(missing_user_app_ids) > 0: - values = [{'user_id': user_id, 'app_id': app_id, 'role_id': 3} for app_id in missing_user_app_ids] - op.bulk_insert(app_roles_table, values) - - -def downgrade(): - # Revert all users role_id to NULL where role is 'user' - op.execute("UPDATE app_role SET role_id = NULL WHERE role_id = 2") - # Delete role 'user' from roles - op.execute("DELETE FROM `role` WHERE id = 2") - - # Delete all user app roles where role is 'no access' with role_id 3 - op.execute("DELETE FROM app_role WHERE role_id = 3") - # Delete role 'no access' from roles - op.execute("DELETE FROM `role` WHERE id = 3") diff --git a/backend/migrations/versions/e08df0bef76f_.py b/backend/migrations/versions/e08df0bef76f_.py deleted file mode 100644 index 005833fb12e38ce6241720a520f160316c53d251..0000000000000000000000000000000000000000 --- a/backend/migrations/versions/e08df0bef76f_.py +++ /dev/null @@ -1,33 +0,0 @@ -"""Add fields for external apps - -Revision ID: e08df0bef76f -Revises: b514cca2d47b -Create Date: 2022-09-23 16:38:06.557307 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'e08df0bef76f' -down_revision = 'b514cca2d47b' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('app', sa.Column('external', sa.Boolean(), server_default='0', nullable=False)) - op.add_column('app', sa.Column('url', sa.String(length=128), nullable=True)) - # ### end Alembic commands ### - - # Add monitoring app - op.execute(f'INSERT IGNORE INTO app (`name`, `slug`) VALUES ("Monitoring","monitoring")') - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('app', 'url') - op.drop_column('app', 'external') - # ### end Alembic commands ### diff --git a/backend/migrations/versions/fc0892d07771_add_oauthclient_app_table.py b/backend/migrations/versions/fc0892d07771_add_oauthclient_app_table.py deleted file mode 100644 index be0ddf02201f097547d2a69346aa1479dabd976c..0000000000000000000000000000000000000000 --- a/backend/migrations/versions/fc0892d07771_add_oauthclient_app_table.py +++ /dev/null @@ -1,39 +0,0 @@ -"""Add oauthclient_app table - -Revision ID: fc0892d07771 -Revises: 3fa0c38ea1ac -Create Date: 2022-11-02 09:52:09.510764 - -""" -from alembic import op -import sqlalchemy as sa -from sqlalchemy.dialects import mysql - -# revision identifiers, used by Alembic. -revision = 'fc0892d07771' -down_revision = '3fa0c38ea1ac' -branch_labels = None -depends_on = None - - -def upgrade(): - oauthclient_app_table = op.create_table('oauthclient_app', - sa.Column('oauthclient_id', mysql.VARCHAR(length=64), nullable=False), - sa.Column('app_id', mysql.INTEGER(display_width=11), autoincrement=False, nullable=False), - sa.ForeignKeyConstraint(['app_id'], ['app.id'], name='oauthclient_app_fk_app_id'), - sa.PrimaryKeyConstraint('oauthclient_id'), - mysql_default_charset='utf8mb3', - mysql_engine='InnoDB' - ) - values = [ - {"oauthclient_id": "dashboard" , "app_id": 1}, - {"oauthclient_id": "wekan" , "app_id": 2}, - {"oauthclient_id": "wordpress" , "app_id": 3}, - {"oauthclient_id": "nextcloud" , "app_id": 4}, - {"oauthclient_id": "zulip" , "app_id": 5}, - {"oauthclient_id": "kube-prometheus-stack", "app_id": 6}, - ] - op.bulk_insert(oauthclient_app_table, values) - -def downgrade(): - op.drop_table('oauthclient_app') diff --git a/backend/requirements.txt b/backend/requirements.txt index 44114da26d1c4a6e53eb3c564fc71b4ed00c32b0..fc2836ad096a8f50d217569cc0a9b8eccdc5db34 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -21,6 +21,7 @@ jinja2-base64-filters==0.1.4 kubernetes==24.2.0 MarkupSafe==2.1.1 mypy-extensions==0.4.3 +NamedAtomicLock==1.1.3 oauthlib==3.2.0 ory-kratos-client==0.11.0 ory-hydra-client==1.11.8 @@ -30,6 +31,7 @@ pycparser==2.21 PyJWT==2.3.0 pymysql==1.0.2 pyrsistent==0.18.1 +PyYAML==6.0 regex==2022.3.15 requests==2.27.1 requests-oauthlib==1.3.1 diff --git a/deployment/helmchart/templates/job-initialize-user.yaml b/deployment/helmchart/templates/job-initialize-user.yaml index 32910dbc7b17209e8a3a74fe59008c34e34aa247..4cf77350d3cbfbd3b2defeb9e3f732397d8ab95b 100644 --- a/deployment/helmchart/templates/job-initialize-user.yaml +++ b/deployment/helmchart/templates/job-initialize-user.yaml @@ -21,6 +21,7 @@ spec: component: dashboard spec: restartPolicy: Never + serviceAccountName: {{ include "dashboard.serviceAccountName" . }} containers: - name: {{ .Chart.Name }}-login-create-admin image: {{ template "backend.image" . }} diff --git a/deployment/helmchart/values.yaml b/deployment/helmchart/values.yaml index a7be717951b75c0be3a768e79973ad3692d43d11..35ae6d4fd479970e5c0a10d3c338706b66c7e915 100644 --- a/deployment/helmchart/values.yaml +++ b/deployment/helmchart/values.yaml @@ -68,7 +68,7 @@ dashboard: image: registry: open.greenhost.net:4567 repository: stackspin/dashboard/dashboard - tag: 0.5.2 + tag: 0.6.0 digest: "" ## Optionally specify an array of imagePullSecrets. ## Secrets must be manually created in the namespace. @@ -236,7 +236,7 @@ backend: image: registry: open.greenhost.net:4567 repository: stackspin/dashboard/dashboard-backend - tag: 0.5.2 + tag: 0.6.0 digest: "" ## Optionally specify an array of imagePullSecrets. ## Secrets must be manually created in the namespace. diff --git a/docker-compose.yml b/docker-compose.yml index c5c20e4f7abfb9fcdb8fd44f85ab102c4a555229..cfab7512f853d5cfd0b44e507548180deb883a99 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -57,7 +57,7 @@ services: - kube_port_mysql entrypoint: ["bash", "-c", "flask run --host $$(hostname -i)"] kube_port_kratos_admin: - image: bitnami/kubectl:1.25.5 + image: bitnami/kubectl:1.26.1 user: "${KUBECTL_UID}:${KUBECTL_GID}" expose: - 8000 @@ -65,7 +65,7 @@ services: - "$KUBECONFIG:/.kube/config" entrypoint: ["bash", "-c", "kubectl -n stackspin port-forward --address $$(hostname -i) service/kratos-admin 8000:80"] kube_port_hydra_admin: - image: bitnami/kubectl:1.25.5 + image: bitnami/kubectl:1.26.1 user: "${KUBECTL_UID}:${KUBECTL_GID}" expose: - 4445 @@ -73,7 +73,7 @@ services: - "$KUBECONFIG:/.kube/config" entrypoint: ["bash", "-c", "kubectl -n stackspin port-forward --address $$(hostname -i) service/hydra-admin 4445:4445"] kube_port_kratos_public: - image: bitnami/kubectl:1.25.5 + image: bitnami/kubectl:1.26.1 user: "${KUBECTL_UID}:${KUBECTL_GID}" ports: - "8080:8080" @@ -83,7 +83,7 @@ services: - "$KUBECONFIG:/.kube/config" entrypoint: ["bash", "-c", "kubectl -n stackspin port-forward --address 0.0.0.0 service/kratos-public 8080:80"] kube_port_mysql: - image: bitnami/kubectl:1.25.5 + image: bitnami/kubectl:1.26.1 user: "${KUBECTL_UID}:${KUBECTL_GID}" expose: - 3306