authentik.blueprints.migrations.0001_initial
1# Generated by Django 4.0.6 on 2022-07-31 17:35 2import uuid 3from glob import glob 4from pathlib import Path 5 6import django.contrib.postgres.fields 7from dacite.core import from_dict 8from django.apps.registry import Apps 9from django.db import migrations, models 10from django.db.backends.base.schema import BaseDatabaseSchemaEditor 11from yaml import load 12 13from authentik.blueprints.v1.labels import LABEL_AUTHENTIK_SYSTEM 14from authentik.lib.config import CONFIG 15 16 17def check_blueprint_v1_file(BlueprintInstance: type, db_alias, path: Path): 18 """Check if blueprint should be imported""" 19 from authentik.blueprints.models import BlueprintInstanceStatus 20 from authentik.blueprints.v1.common import BlueprintLoader, BlueprintMetadata 21 from authentik.blueprints.v1.labels import LABEL_AUTHENTIK_INSTANTIATE 22 23 with open(path, "r", encoding="utf-8") as blueprint_file: 24 raw_blueprint = load(blueprint_file.read(), BlueprintLoader) 25 if not raw_blueprint: 26 return 27 metadata = raw_blueprint.get("metadata", None) 28 version = raw_blueprint.get("version", 1) 29 if version != 1: 30 return 31 blueprint_file.seek(0) 32 instance = BlueprintInstance.objects.using(db_alias).filter(path=path).first() 33 rel_path = path.relative_to(Path(CONFIG.get("blueprints_dir"))) 34 meta = None 35 if metadata: 36 meta = from_dict(BlueprintMetadata, metadata) 37 if meta.labels.get(LABEL_AUTHENTIK_INSTANTIATE, "").lower() == "false": 38 return 39 if not instance: 40 BlueprintInstance.objects.using(db_alias).create( 41 name=meta.name if meta else str(rel_path), 42 path=str(rel_path), 43 context={}, 44 status=BlueprintInstanceStatus.UNKNOWN, 45 enabled=True, 46 managed_models=[], 47 last_applied_hash="", 48 metadata=metadata or {}, 49 ) 50 51 52def migration_blueprint_import(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): 53 BlueprintInstance = apps.get_model("authentik_blueprints", "BlueprintInstance") 54 Flow = apps.get_model("authentik_flows", "Flow") 55 56 db_alias = schema_editor.connection.alias 57 for file in glob(f"{CONFIG.get('blueprints_dir')}/**/*.yaml", recursive=True): 58 check_blueprint_v1_file(BlueprintInstance, db_alias, Path(file)) 59 60 for blueprint in BlueprintInstance.objects.using(db_alias).all(): 61 # If we already have flows (and we should always run before flow migrations) 62 # then this is an existing install and we want to disable all blueprints 63 if Flow.objects.using(db_alias).all().exists(): 64 blueprint.enabled = False 65 # System blueprints are always enabled 66 if blueprint.metadata.get("labels", {}).get(LABEL_AUTHENTIK_SYSTEM, "").lower() == "true": 67 blueprint.enabled = True 68 blueprint.save() 69 70 71class Migration(migrations.Migration): 72 initial = True 73 74 dependencies = [("authentik_flows", "0001_initial")] 75 76 operations = [ 77 migrations.CreateModel( 78 name="BlueprintInstance", 79 fields=[ 80 ("created", models.DateTimeField(auto_now_add=True)), 81 ("last_updated", models.DateTimeField(auto_now=True)), 82 ( 83 "managed", 84 models.TextField( 85 default=None, 86 help_text=( 87 "Objects which are managed by authentik. These objects are created and" 88 " updated automatically. This is flag only indicates that an object can" 89 " be overwritten by migrations. You can still modify the objects via" 90 " the API, but expect changes to be overwritten in a later update." 91 ), 92 null=True, 93 unique=True, 94 verbose_name="Managed by authentik", 95 ), 96 ), 97 ( 98 "instance_uuid", 99 models.UUIDField( 100 default=uuid.uuid4, editable=False, primary_key=True, serialize=False 101 ), 102 ), 103 ("name", models.TextField()), 104 ("metadata", models.JSONField(default=dict)), 105 ("path", models.TextField()), 106 ("context", models.JSONField(default=dict)), 107 ("last_applied", models.DateTimeField(auto_now=True)), 108 ("last_applied_hash", models.TextField()), 109 ( 110 "status", 111 models.TextField( 112 choices=[ 113 ("successful", "Successful"), 114 ("warning", "Warning"), 115 ("error", "Error"), 116 ("orphaned", "Orphaned"), 117 ("unknown", "Unknown"), 118 ], 119 default="unknown", 120 ), 121 ), 122 ("enabled", models.BooleanField(default=True)), 123 ( 124 "managed_models", 125 django.contrib.postgres.fields.ArrayField( 126 base_field=models.TextField(), default=list, size=None 127 ), 128 ), 129 ], 130 options={ 131 "verbose_name": "Blueprint Instance", 132 "verbose_name_plural": "Blueprint Instances", 133 "unique_together": {("name", "path")}, 134 }, 135 ), 136 migrations.RunPython(migration_blueprint_import), 137 ]
def
check_blueprint_v1_file(BlueprintInstance: type, db_alias, path: pathlib.Path):
18def check_blueprint_v1_file(BlueprintInstance: type, db_alias, path: Path): 19 """Check if blueprint should be imported""" 20 from authentik.blueprints.models import BlueprintInstanceStatus 21 from authentik.blueprints.v1.common import BlueprintLoader, BlueprintMetadata 22 from authentik.blueprints.v1.labels import LABEL_AUTHENTIK_INSTANTIATE 23 24 with open(path, "r", encoding="utf-8") as blueprint_file: 25 raw_blueprint = load(blueprint_file.read(), BlueprintLoader) 26 if not raw_blueprint: 27 return 28 metadata = raw_blueprint.get("metadata", None) 29 version = raw_blueprint.get("version", 1) 30 if version != 1: 31 return 32 blueprint_file.seek(0) 33 instance = BlueprintInstance.objects.using(db_alias).filter(path=path).first() 34 rel_path = path.relative_to(Path(CONFIG.get("blueprints_dir"))) 35 meta = None 36 if metadata: 37 meta = from_dict(BlueprintMetadata, metadata) 38 if meta.labels.get(LABEL_AUTHENTIK_INSTANTIATE, "").lower() == "false": 39 return 40 if not instance: 41 BlueprintInstance.objects.using(db_alias).create( 42 name=meta.name if meta else str(rel_path), 43 path=str(rel_path), 44 context={}, 45 status=BlueprintInstanceStatus.UNKNOWN, 46 enabled=True, 47 managed_models=[], 48 last_applied_hash="", 49 metadata=metadata or {}, 50 )
Check if blueprint should be imported
def
migration_blueprint_import( apps: django.apps.registry.Apps, schema_editor: django.db.backends.base.schema.BaseDatabaseSchemaEditor):
53def migration_blueprint_import(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): 54 BlueprintInstance = apps.get_model("authentik_blueprints", "BlueprintInstance") 55 Flow = apps.get_model("authentik_flows", "Flow") 56 57 db_alias = schema_editor.connection.alias 58 for file in glob(f"{CONFIG.get('blueprints_dir')}/**/*.yaml", recursive=True): 59 check_blueprint_v1_file(BlueprintInstance, db_alias, Path(file)) 60 61 for blueprint in BlueprintInstance.objects.using(db_alias).all(): 62 # If we already have flows (and we should always run before flow migrations) 63 # then this is an existing install and we want to disable all blueprints 64 if Flow.objects.using(db_alias).all().exists(): 65 blueprint.enabled = False 66 # System blueprints are always enabled 67 if blueprint.metadata.get("labels", {}).get(LABEL_AUTHENTIK_SYSTEM, "").lower() == "true": 68 blueprint.enabled = True 69 blueprint.save()
class
Migration(django.db.migrations.migration.Migration):
72class Migration(migrations.Migration): 73 initial = True 74 75 dependencies = [("authentik_flows", "0001_initial")] 76 77 operations = [ 78 migrations.CreateModel( 79 name="BlueprintInstance", 80 fields=[ 81 ("created", models.DateTimeField(auto_now_add=True)), 82 ("last_updated", models.DateTimeField(auto_now=True)), 83 ( 84 "managed", 85 models.TextField( 86 default=None, 87 help_text=( 88 "Objects which are managed by authentik. These objects are created and" 89 " updated automatically. This is flag only indicates that an object can" 90 " be overwritten by migrations. You can still modify the objects via" 91 " the API, but expect changes to be overwritten in a later update." 92 ), 93 null=True, 94 unique=True, 95 verbose_name="Managed by authentik", 96 ), 97 ), 98 ( 99 "instance_uuid", 100 models.UUIDField( 101 default=uuid.uuid4, editable=False, primary_key=True, serialize=False 102 ), 103 ), 104 ("name", models.TextField()), 105 ("metadata", models.JSONField(default=dict)), 106 ("path", models.TextField()), 107 ("context", models.JSONField(default=dict)), 108 ("last_applied", models.DateTimeField(auto_now=True)), 109 ("last_applied_hash", models.TextField()), 110 ( 111 "status", 112 models.TextField( 113 choices=[ 114 ("successful", "Successful"), 115 ("warning", "Warning"), 116 ("error", "Error"), 117 ("orphaned", "Orphaned"), 118 ("unknown", "Unknown"), 119 ], 120 default="unknown", 121 ), 122 ), 123 ("enabled", models.BooleanField(default=True)), 124 ( 125 "managed_models", 126 django.contrib.postgres.fields.ArrayField( 127 base_field=models.TextField(), default=list, size=None 128 ), 129 ), 130 ], 131 options={ 132 "verbose_name": "Blueprint Instance", 133 "verbose_name_plural": "Blueprint Instances", 134 "unique_together": {("name", "path")}, 135 }, 136 ), 137 migrations.RunPython(migration_blueprint_import), 138 ]
The base class for all migrations.
Migration files will import this from django.db.migrations.Migration and subclass it as a class called Migration. It will have one or more of the following attributes:
- operations: A list of Operation instances, probably from django.db.migrations.operations
- dependencies: A list of tuples of (app_path, migration_name)
- run_before: A list of tuples of (app_path, migration_name)
- replaces: A list of migration_names
Note that all migrations come out of migrations and into the Loader or Graph as instances, having been initialized with their app label and name.
operations =
[<CreateModel name='BlueprintInstance', fields=[('created', <django.db.models.fields.DateTimeField>), ('last_updated', <django.db.models.fields.DateTimeField>), ('managed', <django.db.models.fields.TextField>), ('instance_uuid', <django.db.models.fields.UUIDField>), ('name', <django.db.models.fields.TextField>), ('metadata', <django.db.models.fields.json.JSONField>), ('path', <django.db.models.fields.TextField>), ('context', <django.db.models.fields.json.JSONField>), ('last_applied', <django.db.models.fields.DateTimeField>), ('last_applied_hash', <django.db.models.fields.TextField>), ('status', <django.db.models.fields.TextField>), ('enabled', <django.db.models.fields.BooleanField>), ('managed_models', <django.contrib.postgres.fields.array.ArrayField>)], options={'verbose_name': 'Blueprint Instance', 'verbose_name_plural': 'Blueprint Instances', 'unique_together': {('name', 'path')}}>, <RunPython <function migration_blueprint_import>>]