From 87190de93411fb525ee39db9555489065aba27e1 Mon Sep 17 00:00:00 2001 From: slashburygin Date: Wed, 22 Jul 2026 23:39:49 +0300 Subject: [PATCH] squash migrations --- Makefile | 2 +- exordos/images/bootstrap.sh | 1 + exordos/images/install.sh | 1 + migrations/0000-init-compute-tables-0234eb.py | 139 -- migrations/0000-init-config-tables-9a7b58.py | 42 - .../0000-init-discovery-tables-907a68.py | 42 - .../0000-init-elements-tables-fe8bdb.py | 42 - migrations/0000-init-iam-tables-9c9153.py | 443 ----- ...-init-values-and-profiles-tables-0a61dc.py | 42 - migrations/0000-squashed-current-7f2e4a.py | 1536 +++++++++++++++++ migrations/0001-init-all-tables-f47bad.py | 47 - migrations/0002-add-volumes-tables-a6972c.py | 114 -- migrations/0003-Organization-Roles-4b584d.py | 139 -- migrations/0004-fix_typoes-31d9b2.py | 64 - .../0005-add-organization-info-4fac91.py | 55 - migrations/0006-add-gc-organization-678510.py | 63 - migrations/0007-add-default-roles-73f4c4.py | 86 - migrations/0008-add-iam-permissions-d81bba.py | 169 -- .../0009-node-builder-entities-0d8f66.py | 127 -- migrations/0010-image-for-machine-31471a.py | 56 - .../0011-add-surname-and-phone-ea974b.py | 54 - migrations/0012-compute-permissions-aac851.py | 123 -- migrations/0013-add-ttl-to-token-2b8e3e.py | 51 - migrations/0014-network-ipam-067981.py | 209 --- ...0015-add-email-confirmation-info-8b38d3.py | 62 - ...permissions-to-all-iam-resources-3b82c6.py | 199 --- migrations/0017-init-configs-c3bbc6.py | 186 -- migrations/0018-add-elements-76bca4.py | 248 --- migrations/0019-init-dns-40a307.py | 135 -- migrations/0020-init-secret-a643b1.py | 97 -- migrations/0021-dns-permissions-7adac7.py | 127 -- migrations/0022-secret-certs-d340e8.py | 90 - migrations/0023-nullable_fio-c9cb3a.py | 53 - ..._confirmation_code_made_at-added-435e66.py | 45 - migrations/0025-secret-ssh-keys-ad3fad.py | 73 - ...ase-insensitive-users-name-index-41f4b9.py | 49 - ...mail-lowercase-unique-constraint-98a7bb.py | 49 - ...0028-add-api-version-to-manifest-8de907.py | 63 - migrations/0029-sdk-0-7-0-migration-c2c52a.py | 79 - migrations/0030-compute-node-sets-b1869c.py | 130 -- .../0031-node-set-permissions-2de46e.py | 102 -- .../0032-project-id-dns-records-1ca60d.py | 70 - migrations/0033-em-ua-status-check-5be89c.py | 133 -- ...-add-export-adn-import-resources-a12854.py | 108 -- migrations/0035-dummy-placement-e6d5dc.py | 181 -- migrations/0036-init-services-741b72.py | 114 -- migrations/0037-manifest-indexes-815825.py | 94 - migrations/0038-init-lb-e88603.py | 126 -- migrations/0039-add-oidc-structures-e5d2a8.py | 196 --- migrations/0040-secret-rsa-keys-2f3c1a.py | 71 - .../0041-remove-idp-clientid-secret-18d7c4.py | 83 - .../0042-compute-ua-integration-4bd866.py | 456 ----- migrations/0043-add-user-source-4f5e1f.py | 58 - migrations/0044-add-lb-ext-source-ca08ef.py | 57 - migrations/0045-add-security-rules-7c2f6d.py | 74 - migrations/0046-init-vs-f5aaa2.py | 149 -- migrations/0047-sdk-1-3-0-migration-33fdc9.py | 55 - migrations/0048-iam-nonce-optional-c6e9f6.py | 58 - .../0049-lb-add-proxy-protocol-from-ef8f58.py | 57 - migrations/0050-subnet-source-6c071d.py | 58 - migrations/0051-sdk-1-5-0-migration-eea262.py | 55 - .../0052-iam-user-custom-props-bc80b5.py | 57 - ...3-lb-node-secret-set-permissions-11c9a8.py | 129 -- .../0054-iam-idp-callback-kind-3a6c1b.py | 90 - migrations/0055-iam-user-type-8d7f2a.py | 132 -- .../0056-iam-user-create-perm-3e0dc5.py | 83 - ...oject-id-requirements-to-element-3bc138.py | 61 - ...users-target-to-actual-resources-a1b2c3.py | 83 - ...dns-sync-to-ecosystem-secret-len-a7b3c1.py | 74 - .../0060-openapi-spec_e-m-link-02ef0a.py | 74 - ...1-rename-rule-verifier-to-action-a3b4c5.py | 57 - .../0062-convert-varchar-to-jsonb-4d5e6f.py | 107 -- ...spec-connection-uri-unique-index-eb26ec.py | 59 - migrations/0064-init-repo-tables-645142.py | 111 -- ...gistration-client-auto-provision-b7f2d9.py | 69 - ...pools-driver-spec-kind-migration-138d02.py | 104 -- migrations/0067-init-border-ec37b4.py | 124 -- ...8-fix-resource-status-hash-check-437c89.py | 108 -- migrations/0069-add-quota-tables-f8778e.py | 68 - migrations/MANUAL-boot-network-40b1ae.py | 170 -- migrations/MANUAL-computeV2-e26427.py | 339 ---- migrations/MANUAL-fix-usernames-6b042b.py | 51 - 82 files changed, 1539 insertions(+), 8298 deletions(-) delete mode 100644 migrations/0000-init-compute-tables-0234eb.py delete mode 100644 migrations/0000-init-config-tables-9a7b58.py delete mode 100644 migrations/0000-init-discovery-tables-907a68.py delete mode 100644 migrations/0000-init-elements-tables-fe8bdb.py delete mode 100644 migrations/0000-init-iam-tables-9c9153.py delete mode 100644 migrations/0000-init-values-and-profiles-tables-0a61dc.py create mode 100644 migrations/0000-squashed-current-7f2e4a.py delete mode 100644 migrations/0001-init-all-tables-f47bad.py delete mode 100644 migrations/0002-add-volumes-tables-a6972c.py delete mode 100644 migrations/0003-Organization-Roles-4b584d.py delete mode 100644 migrations/0004-fix_typoes-31d9b2.py delete mode 100644 migrations/0005-add-organization-info-4fac91.py delete mode 100644 migrations/0006-add-gc-organization-678510.py delete mode 100644 migrations/0007-add-default-roles-73f4c4.py delete mode 100644 migrations/0008-add-iam-permissions-d81bba.py delete mode 100644 migrations/0009-node-builder-entities-0d8f66.py delete mode 100644 migrations/0010-image-for-machine-31471a.py delete mode 100644 migrations/0011-add-surname-and-phone-ea974b.py delete mode 100644 migrations/0012-compute-permissions-aac851.py delete mode 100644 migrations/0013-add-ttl-to-token-2b8e3e.py delete mode 100644 migrations/0014-network-ipam-067981.py delete mode 100644 migrations/0015-add-email-confirmation-info-8b38d3.py delete mode 100644 migrations/0016-add-permissions-to-all-iam-resources-3b82c6.py delete mode 100644 migrations/0017-init-configs-c3bbc6.py delete mode 100644 migrations/0018-add-elements-76bca4.py delete mode 100644 migrations/0019-init-dns-40a307.py delete mode 100644 migrations/0020-init-secret-a643b1.py delete mode 100644 migrations/0021-dns-permissions-7adac7.py delete mode 100644 migrations/0022-secret-certs-d340e8.py delete mode 100644 migrations/0023-nullable_fio-c9cb3a.py delete mode 100644 migrations/0024-user_confirmation_code_made_at-added-435e66.py delete mode 100644 migrations/0025-secret-ssh-keys-ad3fad.py delete mode 100644 migrations/0026-case-insensitive-users-name-index-41f4b9.py delete mode 100644 migrations/0027-email-lowercase-unique-constraint-98a7bb.py delete mode 100644 migrations/0028-add-api-version-to-manifest-8de907.py delete mode 100644 migrations/0029-sdk-0-7-0-migration-c2c52a.py delete mode 100644 migrations/0030-compute-node-sets-b1869c.py delete mode 100644 migrations/0031-node-set-permissions-2de46e.py delete mode 100644 migrations/0032-project-id-dns-records-1ca60d.py delete mode 100644 migrations/0033-em-ua-status-check-5be89c.py delete mode 100644 migrations/0034-add-export-adn-import-resources-a12854.py delete mode 100644 migrations/0035-dummy-placement-e6d5dc.py delete mode 100644 migrations/0036-init-services-741b72.py delete mode 100644 migrations/0037-manifest-indexes-815825.py delete mode 100644 migrations/0038-init-lb-e88603.py delete mode 100644 migrations/0039-add-oidc-structures-e5d2a8.py delete mode 100644 migrations/0040-secret-rsa-keys-2f3c1a.py delete mode 100644 migrations/0041-remove-idp-clientid-secret-18d7c4.py delete mode 100644 migrations/0042-compute-ua-integration-4bd866.py delete mode 100644 migrations/0043-add-user-source-4f5e1f.py delete mode 100644 migrations/0044-add-lb-ext-source-ca08ef.py delete mode 100644 migrations/0045-add-security-rules-7c2f6d.py delete mode 100644 migrations/0046-init-vs-f5aaa2.py delete mode 100644 migrations/0047-sdk-1-3-0-migration-33fdc9.py delete mode 100644 migrations/0048-iam-nonce-optional-c6e9f6.py delete mode 100644 migrations/0049-lb-add-proxy-protocol-from-ef8f58.py delete mode 100644 migrations/0050-subnet-source-6c071d.py delete mode 100644 migrations/0051-sdk-1-5-0-migration-eea262.py delete mode 100644 migrations/0052-iam-user-custom-props-bc80b5.py delete mode 100644 migrations/0053-lb-node-secret-set-permissions-11c9a8.py delete mode 100644 migrations/0054-iam-idp-callback-kind-3a6c1b.py delete mode 100644 migrations/0055-iam-user-type-8d7f2a.py delete mode 100644 migrations/0056-iam-user-create-perm-3e0dc5.py delete mode 100644 migrations/0057-add-project-id-requirements-to-element-3bc138.py delete mode 100644 migrations/0058-copy-iam-users-target-to-actual-resources-a1b2c3.py delete mode 100644 migrations/0059-dns-sync-to-ecosystem-secret-len-a7b3c1.py delete mode 100644 migrations/0060-openapi-spec_e-m-link-02ef0a.py delete mode 100644 migrations/0061-rename-rule-verifier-to-action-a3b4c5.py delete mode 100644 migrations/0062-convert-varchar-to-jsonb-4d5e6f.py delete mode 100644 migrations/0063-add-driver-spec-connection-uri-unique-index-eb26ec.py delete mode 100644 migrations/0064-init-repo-tables-645142.py delete mode 100644 migrations/0065-registration-client-auto-provision-b7f2d9.py delete mode 100644 migrations/0066-machine-pools-driver-spec-kind-migration-138d02.py delete mode 100644 migrations/0067-init-border-ec37b4.py delete mode 100644 migrations/0068-fix-resource-status-hash-check-437c89.py delete mode 100644 migrations/0069-add-quota-tables-f8778e.py delete mode 100644 migrations/MANUAL-boot-network-40b1ae.py delete mode 100644 migrations/MANUAL-computeV2-e26427.py delete mode 100644 migrations/MANUAL-fix-usernames-6b042b.py diff --git a/Makefile b/Makefile index 4f0fa744..f55e8092 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ bootstrap: exordos bootstrap -i output -f -m core --admin-password admin --cidr 10.20.0.0/22 delete_core: - exordos realms d local + exordos realms d exordos-core add_ssh_keys: exordos secret ssh_keys add --current-realm --target_public_key $(SSH_KEY) diff --git a/exordos/images/bootstrap.sh b/exordos/images/bootstrap.sh index acbd349a..1d7eeea1 100755 --- a/exordos/images/bootstrap.sh +++ b/exordos/images/bootstrap.sh @@ -154,6 +154,7 @@ log "Apply migrations" source "$VENV_PATH/bin/activate" # TODO(akremenetsky): Database configuration parameters should be taken # from persistent configuration file. +ra-apply-migration --config-dir "$GC_CFG_DIR/" --path "$GC_PATH/.venv/lib/python3.14/site-packages/gcl_sdk/migrations" ra-apply-migration --config-dir "$GC_CFG_DIR/" --path "$GC_PATH/migrations" # --- Meta file migrations --- diff --git a/exordos/images/install.sh b/exordos/images/install.sh index c96a9f11..cae8e455 100644 --- a/exordos/images/install.sh +++ b/exordos/images/install.sh @@ -231,6 +231,7 @@ sudo cp "$GC_PATH/etc/exordos_universal_agent/logging.yaml" /etc/exordos_univers # 1) The bootstrap script will transfer the data to the data disk # 2) It's speed up the first run since the migrations are already applied. # 3) It's allows to debug the migrations at build time. +OS_DB__CONNECTION_URL="postgresql://$GC_PG_USER:$GC_PG_PASS@127.0.0.1:5432/$GC_PG_DB" ra-apply-migration --path "$GC_PATH/.venv/lib/python3.14/site-packages/gcl_sdk/migrations" OS_DB__CONNECTION_URL="postgresql://$GC_PG_USER:$GC_PG_PASS@127.0.0.1:5432/$GC_PG_DB" ra-apply-migration --path "$GC_PATH/migrations" deactivate diff --git a/migrations/0000-init-compute-tables-0234eb.py b/migrations/0000-init-compute-tables-0234eb.py deleted file mode 100644 index cb43f844..00000000 --- a/migrations/0000-init-compute-tables-0234eb.py +++ /dev/null @@ -1,139 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = [ - "0000-root-d34de1.py", - ] - - @property - def migration_id(self): - return "0234eb6a-82b1-49b8-b266-2d0a7b4deac9" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - sql_expressions = [ - # TABLES - """ - CREATE TABLE IF NOT EXISTS machine_agents ( - uuid UUID NOT NULL PRIMARY KEY, - name varchar(255) NOT NULL, - description varchar(255) NOT NULL, - status VARCHAR(32) NOT NULL CHECK (status IN ('ACTIVE', 'DISABLED')) - ); - """, - """ - CREATE TABLE IF NOT EXISTS machine_pools ( - uuid UUID NOT NULL PRIMARY KEY, - name varchar(255) NOT NULL, - description varchar(255) NOT NULL, - driver_spec varchar(512) NOT NULL, - agent UUID references machine_agents(uuid) ON DELETE SET NULL, - machine_type VARCHAR(2) NOT NULL CHECK (machine_type IN ('VM', 'HW')), - status VARCHAR(32) NOT NULL CHECK (status IN ('ACTIVE', 'DISABLED', 'MAINTENANCE')) - ); - """, - """ - CREATE TABLE IF NOT EXISTS nodes ( - uuid UUID NOT NULL PRIMARY KEY, - project_id UUID NOT NULL, - name varchar(255) NOT NULL, - description varchar(255) NOT NULL, - cores integer NOT NULL, - ram integer NOT NULL, - image varchar(255) NOT NULL, - node_type VARCHAR(2) NOT NULL CHECK (node_type IN ('VM', 'HW')), - status VARCHAR(32) NOT NULL CHECK (status IN ('NEW', 'SCHEDULED', 'IN_PROGRESS', 'STARTED', 'ACTIVE', 'ERROR')), - created_at timestamp NOT NULL DEFAULT current_timestamp, - updated_at timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE TABLE IF NOT EXISTS machines ( - uuid UUID NOT NULL PRIMARY KEY, - project_id UUID NOT NULL, - name varchar(255) NOT NULL, - description varchar(255) NOT NULL, - cores integer NOT NULL, - ram integer NOT NULL, - node UUID references nodes(uuid) ON DELETE CASCADE, - machine_type VARCHAR(2) NOT NULL CHECK (machine_type IN ('VM', 'HW')), - boot VARCHAR(8) NOT NULL CHECK (boot IN ('hd0', 'hd1', 'hd2', 'hd3', 'cdrom', 'network')), - pool UUID references machine_pools(uuid) ON DELETE SET NULL, - firmware_uuid UUID NULL DEFAULT NULL, - status VARCHAR(32) NOT NULL CHECK (status IN ('NEW', 'SCHEDULED', 'IN_PROGRESS', 'STARTED', 'ACTIVE', 'IDLE', 'ERROR')), - created_at timestamp NOT NULL DEFAULT current_timestamp, - updated_at timestamp NOT NULL DEFAULT current_timestamp - ); - """, - # VIEWS - """ - CREATE OR REPLACE VIEW unscheduled_nodes AS - SELECT - nodes.uuid, - nodes.project_id, - nodes.name, - nodes.description, - nodes.cores, - nodes.ram, - nodes.image, - nodes.node_type, - nodes.status, - nodes.created_at, - nodes.updated_at - FROM nodes LEFT JOIN machines ON - nodes.uuid = machines.node WHERE machines.uuid is NULL; - """, - """ - CREATE OR REPLACE VIEW netboots AS - SELECT - machines.firmware_uuid as uuid, - machines.boot as boot - FROM machines; - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - def downgrade(self, session): - tables = [ - "machines", - "nodes", - "machine_pools", - "machine_agents", - ] - views = [ - "unscheduled_nodes", - "netboots", - ] - - for view_name in views: - self._delete_view_if_exists(session, view_name) - - for table_name in tables: - self._delete_table_if_exists(session, table_name) - - -migration_step = MigrationStep() diff --git a/migrations/0000-init-config-tables-9a7b58.py b/migrations/0000-init-config-tables-9a7b58.py deleted file mode 100644 index aa22eef3..00000000 --- a/migrations/0000-init-config-tables-9a7b58.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = [ - "0000-root-d34de1.py", - ] - - @property - def migration_id(self): - return "9a7b58bd-c55c-49ef-aebd-238f2007b212" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - pass - - def downgrade(self, session): - pass - - -migration_step = MigrationStep() diff --git a/migrations/0000-init-discovery-tables-907a68.py b/migrations/0000-init-discovery-tables-907a68.py deleted file mode 100644 index abac7fe8..00000000 --- a/migrations/0000-init-discovery-tables-907a68.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = [ - "0000-root-d34de1.py", - ] - - @property - def migration_id(self): - return "907a684b-5992-466f-a33f-3ec6f755d98c" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - pass - - def downgrade(self, session): - pass - - -migration_step = MigrationStep() diff --git a/migrations/0000-init-elements-tables-fe8bdb.py b/migrations/0000-init-elements-tables-fe8bdb.py deleted file mode 100644 index 4168b89d..00000000 --- a/migrations/0000-init-elements-tables-fe8bdb.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = [ - "0000-root-d34de1.py", - ] - - @property - def migration_id(self): - return "fe8bdb9c-a2a8-41dc-b30b-1cf5902427cd" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - pass - - def downgrade(self, session): - pass - - -migration_step = MigrationStep() diff --git a/migrations/0000-init-iam-tables-9c9153.py b/migrations/0000-init-iam-tables-9c9153.py deleted file mode 100644 index a8e791fe..00000000 --- a/migrations/0000-init-iam-tables-9c9153.py +++ /dev/null @@ -1,443 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import base64 -import hashlib -import os - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = [ - "0000-root-d34de1.py", - ] - self._global_salt = os.getenv( - "GLOBAL_SALT", - "FOy/2kwwdn0ig1QOq7cestqe", - ) - self._default_client_secret = os.getenv( - "DEFAULT_CLIENT_SECRET", - "GenesisCoreSecret", - ) - self._admin_password = os.getenv( - "ADMIN_PASSWORD", - "admin", - ) - - @property - def migration_id(self): - return "9c9153e3-e187-4420-bf4d-d0e4dbf489d3" - - @property - def is_manual(self): - return False - - def _generate_hash(cls, secret, secret_salt, global_salt): - - raw_secret_salt = base64.b64decode(secret_salt) - raw_global_salt = base64.b64decode(global_salt) - - hashed = hashlib.pbkdf2_hmac( - "sha512", - secret.encode("utf-8"), - raw_secret_salt + raw_global_salt, - 251685, # count of iterations - ) - - return hashed.hex() - - def _get_admin_secret(self): - return self._generate_hash( - secret=self._admin_password, - secret_salt=self._global_salt, - global_salt=self._global_salt, - ) - - def _get_client_secret(self): - return None - - def upgrade(self, session): - default_admin_salt = "d4JJ9QYuEEJxHCFja9FZskG4" - default_admin_secret = self._generate_hash( - secret=self._admin_password, - secret_salt=default_admin_salt, - global_salt=self._global_salt, - ) - default_client_secret = self._generate_hash( - secret=self._default_client_secret, - secret_salt=default_admin_salt, - global_salt=self._global_salt, - ) - - expressions = [ - # Users - """ - CREATE TABLE IF NOT EXISTS "iam_users" ( - "uuid" UUID PRIMARY KEY, - status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' - CHECK (status IN ('ACTIVE')), - "name" VARCHAR(256) NOT NULL, - "description" VARCHAR(256) NOT NULL, - "first_name" VARCHAR(128) NOT NULL, - "last_name" VARCHAR(128) NOT NULL, - "email" VARCHAR(128) NOT NULL, - "secret_hash" CHAR(128) NOT NULL, - "salt" CHAR(24) NOT NULL, - "otp_secret" VARCHAR(128) DEFAULT '', - "otp_enabled" BOOLEAN DEFAULT FALSE, - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - """, - """ - CREATE UNIQUE INDEX "iam_users_name_idx" ON "iam_users" ( - "name" - ); - """, - """ - CREATE UNIQUE INDEX "iam_users_email_idx" ON "iam_users" ( - "email" - ); - """, - f""" - INSERT INTO "iam_users" ( - "uuid", "name", "description", "first_name", "last_name", - "email", "secret_hash", "salt" - ) VALUES ( - '00000000-0000-0000-0000-000000000000', - 'admin', - 'System administrator', - 'Admin', - 'User', - 'admin@example.com', - '{default_admin_secret}', - '{default_admin_salt}' - ); - """, - # Organizations - """ - CREATE TABLE IF NOT EXISTS "iam_organizations" ( - "uuid" UUID PRIMARY KEY, - status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' - CHECK (status IN ('ACTIVE')), - "name" VARCHAR(128) NOT NULL, - "description" VARCHAR(256) DEFAULT '', - "owner" UUID NOT NULL REFERENCES "iam_users" ("uuid") - ON DELETE RESTRICT - ON UPDATE RESTRICT, - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - """, - """ - CREATE INDEX "iam_organizations_name_idx" ON - "iam_organizations" ("name"); - """, - """ - INSERT INTO "iam_organizations" ( - "uuid", "name", "description", "owner" - ) VALUES ( - '00000000-0000-0000-0000-000000000000', - 'admin', 'Admin Organization', - '00000000-0000-0000-0000-000000000000' - ); - """, - # Projects - """ - CREATE TABLE IF NOT EXISTS "iam_projects" ( - "uuid" UUID PRIMARY KEY, - status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' - CHECK ( - status IN ( - 'NEW', - 'IN_PROGRESS', - 'ACTIVE', - 'DELETING' - ) - ), - "name" VARCHAR(128) NOT NULL, - "description" VARCHAR(256) DEFAULT '', - "organization" UUID NOT NULL REFERENCES - "iam_organizations" ("uuid"), - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - """, - """ - CREATE INDEX "iam_projects_name_idx" ON "iam_projects" - ("name"); - """, - """ - CREATE INDEX "iam_projects_organization_idx" ON - "iam_projects" ("organization"); - """, - """ - INSERT INTO "iam_projects" ( - "uuid", "name", description, organization - ) VALUES ( - '00000000-0000-0000-0000-000000000000', - 'admin', 'Admin Project', - '00000000-0000-0000-0000-000000000000' - ); - """, - # Roles - """ - CREATE TABLE IF NOT EXISTS "iam_roles" ( - "uuid" UUID PRIMARY KEY, - status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' - CHECK (status IN ('ACTIVE')), - "name" VARCHAR(128) NOT NULL, - "description" VARCHAR(256) DEFAULT '', - "project_id" UUID DEFAULT NULL, - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - """, - """ - CREATE INDEX "iam_roles_name_idx" ON "iam_roles" ("name"); - """, - """ - INSERT INTO "iam_roles" ( - "uuid", "name", "description" - ) VALUES ( - '00000000-0000-0000-0000-000000000000', - 'admin', 'Admin Role' - ); - """, - # Permissions - """ - CREATE TABLE IF NOT EXISTS "iam_permissions" ( - "uuid" UUID PRIMARY KEY, - status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' - CHECK (status IN ('ACTIVE')), - "name" VARCHAR(256) NOT NULL, - "description" VARCHAR(256) DEFAULT '', - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - """, - """ - CREATE UNIQUE INDEX "iam_permissions_name_idx" ON - "iam_permissions" ("name"); - """, - """ - INSERT INTO "iam_permissions" ( - "uuid", "name", "description" - ) VALUES ( - '00000000-0000-0000-0000-000000000000', - '*.*.*', 'Allow All' - ); - """, - # Bindings - """ - CREATE TABLE IF NOT EXISTS "iam_binding_permissions" ( - "uuid" UUID PRIMARY KEY, - status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' - CHECK (status IN ('ACTIVE')), - "project_id" UUID DEFAULT NULL, - "role" UUID NOT NULL REFERENCES "iam_roles" ("uuid"), - "permission" UUID NOT NULL REFERENCES - "iam_permissions" ("uuid"), - "description" VARCHAR(256) DEFAULT '', - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - """, - """ - CREATE INDEX "iam_binding_permissions_role_permission_idx" ON - "iam_binding_permissions" ("role", "permission"); - """, - """ - INSERT INTO "iam_binding_permissions" ( - "uuid", "role", "permission" - ) VALUES ( - '00000000-0000-0000-0000-000000000000', - '00000000-0000-0000-0000-000000000000', - '00000000-0000-0000-0000-000000000000' - ); - """, - """ - CREATE TABLE IF NOT EXISTS "iam_binding_roles" ( - "uuid" UUID PRIMARY KEY, - status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' - CHECK (status IN ('ACTIVE')), - "user" UUID NOT NULL REFERENCES "iam_users" ("uuid"), - "role" UUID NOT NULL REFERENCES "iam_roles" ("uuid"), - "project" UUID DEFAULT NULL REFERENCES - "iam_projects" ("uuid"), - "description" VARCHAR(256) DEFAULT '', - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - """, - """ - CREATE INDEX "iam_binding_roles_user_idx" ON - "iam_binding_roles" ("user"); - """, - """ - CREATE INDEX "iam_binding_roles_role_idx" ON - "iam_binding_roles" ("role"); - """, - """ - CREATE INDEX "iam_binding_roles_project_idx" ON - "iam_binding_roles" ("project"); - """, - """ - INSERT INTO "iam_binding_roles" ( - "uuid", "user", "role", "description" - ) VALUES ( - '00000000-0000-0000-0000-000000000000', - '00000000-0000-0000-0000-000000000000', - '00000000-0000-0000-0000-000000000000', - 'Super Administrator' - ); - """, - # IDP - """ - CREATE TABLE IF NOT EXISTS "iam_idp" ( - "uuid" UUID PRIMARY KEY, - status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' - CHECK (status IN ('ACTIVE')), - "name" VARCHAR(256) NOT NULL, - "project_id" UUID DEFAULT NULL, - "description" VARCHAR(256) DEFAULT '', - "client_id" VARCHAR(64) NOT NULL, - "secret_hash" CHAR(128) NOT NULL, - "salt" CHAR(24) NOT NULL, - "scope" VARCHAR(64) DEFAULT 'openid', - "well_known_endpoint" VARCHAR(256) NOT NULL, - "redirect_uri_template" VARCHAR(256) NOT NULL, - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - """, - """ - CREATE UNIQUE INDEX "iam_idp_id_idx" ON "iam_idp" ( - "client_id" - ) - """, - # Clients - """ - CREATE TABLE IF NOT EXISTS "iam_clients" ( - "uuid" UUID PRIMARY KEY, - status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' - CHECK (status IN ('ACTIVE')), - "name" VARCHAR(256) NOT NULL, - "project_id" UUID DEFAULT NULL, - "description" VARCHAR(256) DEFAULT '', - "client_id" VARCHAR(64) NOT NULL, - "secret_hash" CHAR(128) NOT NULL, - "salt" CHAR(24) NOT NULL, - "redirect_url" VARCHAR(256) NOT NULL, - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - """, - """ - CREATE UNIQUE INDEX "iam_client_id_idx" ON "iam_clients" ( - "client_id" - )""", - f""" - INSERT INTO "iam_clients" ( - "uuid", "name", "description", "client_id", - "secret_hash", "salt", "redirect_url" - ) VALUES( - '00000000-0000-0000-0000-000000000000', - 'GenesisCoreClient', - 'Exordos Core OIDC Client', - 'GenesisCoreClientId', - '{default_client_secret}', - '{default_admin_salt}', - 'http://127.0.0.1:11010/v1/' - ); - """, - # Tokens - """ - CREATE TABLE IF NOT EXISTS "iam_tokens" ( - "uuid" UUID PRIMARY KEY, - "user" UUID NOT NULL REFERENCES "iam_users" ("uuid") - ON DELETE CASCADE - ON UPDATE CASCADE, - "project" UUID DEFAULT NULL REFERENCES "iam_projects" - ("uuid") - ON DELETE CASCADE - ON UPDATE CASCADE, - "experation_at" TIMESTAMP(6) NOT NULL, - "refresh_token_uuid" UUID NOT NULL, - "refresh_experation_at" TIMESTAMP(6) NOT NULL, - "issuer" VARCHAR(256) DEFAULT NULL, - "audience" VARCHAR(256) DEFAULT 'account', - "typ" VARCHAR(64) DEFAULT 'Bearer', - "scope" VARCHAR(128) NOT NULL, - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - """, - """ - CREATE OR REPLACE VIEW "iam_permissions_fast_view" AS - SELECT - "t1"."uuid" AS "uuid", - "t1"."uuid" AS "permission", - "t4"."uuid" AS "user", - "t3"."uuid" AS "role", - "t3"."project" as "project" - FROM - "iam_permissions" AS "t1" - LEFT JOIN - "iam_binding_permissions" AS "t2" - ON ("t2"."permission" = "t1"."uuid") - LEFT JOIN - "iam_binding_roles" AS "t3" - ON ("t3"."role" = "t2"."role") - LEFT JOIN - "iam_users" AS "t4" - ON ("t4"."uuid" = "t3"."user"); - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - tables = [ - "iam_tokens", - "iam_clients", - "iam_idp", - "iam_binding_roles", - "iam_binding_permissions", - "iam_permissions", - "iam_roles", - "iam_users", - "iam_projects", - "iam_organizations", - ] - - views = [ - "iam_permissions_fast_view", - ] - - for view in views: - self._delete_view_if_exists(session, view) - - for table in tables: - self._delete_table_if_exists(session, table) - # session.execute(f'DROP TABLE IF EXISTS "{table}" CASCADE;') - - -migration_step = MigrationStep() diff --git a/migrations/0000-init-values-and-profiles-tables-0a61dc.py b/migrations/0000-init-values-and-profiles-tables-0a61dc.py deleted file mode 100644 index 22485aa3..00000000 --- a/migrations/0000-init-values-and-profiles-tables-0a61dc.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = [ - "0000-root-d34de1.py", - ] - - @property - def migration_id(self): - return "0a61dc29-924d-4870-8b6b-0637230efb10" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - pass - - def downgrade(self, session): - pass - - -migration_step = MigrationStep() diff --git a/migrations/0000-squashed-current-7f2e4a.py b/migrations/0000-squashed-current-7f2e4a.py new file mode 100644 index 00000000..0b7fcced --- /dev/null +++ b/migrations/0000-squashed-current-7f2e4a.py @@ -0,0 +1,1536 @@ +# Copyright 2026 Genesis Corporation. +# +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import base64 +import hashlib +import logging +import os +import uuid as _uuid + +from restalchemy.storage.sql import migrations + +LOG = logging.getLogger(__name__) + +# --------------------------------------------------------------------------- +# UUID helpers used for deterministic permission/project UUIDs +# --------------------------------------------------------------------------- + +_NS_UUID_DFD0 = _uuid.UUID("dfd0c604-607f-4260-981f-374f88435ea0") +_NS_UUID_A6C4 = _uuid.UUID("a6c4c7a8-b1d2-4e8f-9a3c-1d7e4f5a9b0c") + + +def _u(name: str) -> str: + return str(_uuid.uuid5(_NS_UUID_DFD0, name)) + + +def _generate_uuid_a6c4(name): + return str(_uuid.uuid5(_NS_UUID_A6C4, name)) + + +def _generate_hash(secret, secret_salt, global_salt): + raw_secret_salt = base64.b64decode(secret_salt) + raw_global_salt = base64.b64decode(global_salt) + hashed = hashlib.pbkdf2_hmac( + "sha512", + secret.encode("utf-8"), + raw_secret_salt + raw_global_salt, + 251685, + ) + return hashed.hex() + + +# --------------------------------------------------------------------------- +# Bootstrap data UUID constants +# --------------------------------------------------------------------------- + +EXORDOS_CORE_ORGANIZATION_ID = "11111111-1111-1111-1111-111111111111" +EXORDOS_CORE_ORGANIZATION_NAME = "Genesis Corporation" +EXORDOS_CORE_ORGANIZATION_DESCRIPTION = ( + "The organization serves as the central platform for all services" + " and elements developed by Genesis Corporation." +) +DEFAULT_IAM_CLIENT_UUID = "00000000-0000-0000-0000-000000000000" +NEWCOMER_ROLE_UUID = "726f6c65-0000-0000-0000-000000000001" +OWNER_ROLE_UUID = "726f6c65-0000-0000-0000-000000000002" +NEWCOMER_ROLE_NAME = "newcomer" +NEWCOMER_ROLE_DESCRIPTION = ( + "Default role for newly registered users. Provides basic system access" + " and onboarding capabilities." +) +OWNER_ROLE_NAME = "owner" +OWNER_ROLE_DESCRIPTION = ( + "Project ownership role. Grants full administrative privileges" + " within a specific project. Automatically assigned during project" + " creation process." +) +IAM_PROJECT_UUID = _generate_uuid_a6c4("GenesisCore-IAM-Project") +COMPUTE_PROJECT_UUID = _u("GenesisCore-Compute-Project") +DNS_PROJECT_UUID = _u("GenesisCore-Dns-Project") + +# --------------------------------------------------------------------------- +# Permission name constants and UUID mappings +# --------------------------------------------------------------------------- + +USER_LIST = "iam.user.list" +USER_READ_ALL = "iam.user.read_all" +USER_WRITE_ALL = "iam.user.write_all" +USER_DELETE_ALL = "iam.user.delete_all" +USER_DELETE = "iam.user.delete" +ORG_CREATE = "iam.organization.create" +ORG_READ_ALL = "iam.organization.read_all" +ORG_WRITE_ALL = "iam.organization.write_all" +ORG_DELETE = "iam.organization.delete" +ORG_DELETE_ALL = "iam.organization.delete_all" + +PERMISSION_PROJECT_LIST_ALL = "iam.project.list_all" +PERMISSION_PROJECT_READ_ALL = "iam.project.read_all" +PERMISSION_PROJECT_WRITE_ALL = "iam.project.write_all" +PERMISSION_PROJECT_DELETE_ALL = "iam.project.delete_all" +PERMISSION_PERMISSION_CREATE = "iam.permission.create" +PERMISSION_PERMISSION_READ = "iam.permission.read" +PERMISSION_PERMISSION_UPDATE = "iam.permission.update" +PERMISSION_PERMISSION_DELETE = "iam.permission.delete" +PERMISSION_PERMISSION_BINDING_CREATE = "iam.permission_binding.create" +PERMISSION_PERMISSION_BINDING_READ = "iam.permission_binding.read" +PERMISSION_PERMISSION_BINDING_UPDATE = "iam.permission_binding.update" +PERMISSION_PERMISSION_BINDING_DELETE = "iam.permission_binding.delete" +PERMISSION_ROLE_CREATE = "iam.role.create" +PERMISSION_ROLE_READ = "iam.role.read" +PERMISSION_ROLE_UPDATE = "iam.role.write" +PERMISSION_ROLE_DELETE = "iam.role.delete" +PERMISSION_ROLE_BINDING_CREATE = "iam.role_binding.create" +PERMISSION_ROLE_BINDING_READ = "iam.role_binding.read" +PERMISSION_ROLE_BINDING_UPDATE = "iam.role_binding.update" +PERMISSION_ROLE_BINDING_DELETE = "iam.role_binding.delete" +PERMISSION_IAM_CLIENT_CREATE = "iam.iam_client.create" +PERMISSION_IAM_CLIENT_READ_ALL = "iam.iam_client.read_all" +PERMISSION_IAM_CLIENT_UPDATE = "iam.iam_client.update" +PERMISSION_IAM_CLIENT_DELETE = "iam.iam_client.delete" + +PERMISSION_UUIDS = { + USER_LIST: _generate_uuid_a6c4(USER_LIST), + USER_READ_ALL: _generate_uuid_a6c4(USER_READ_ALL), + USER_WRITE_ALL: _generate_uuid_a6c4(USER_WRITE_ALL), + USER_DELETE_ALL: _generate_uuid_a6c4(USER_DELETE_ALL), + USER_DELETE: _generate_uuid_a6c4(USER_DELETE), + ORG_CREATE: _generate_uuid_a6c4(ORG_CREATE), + ORG_READ_ALL: _generate_uuid_a6c4(ORG_READ_ALL), + ORG_WRITE_ALL: _generate_uuid_a6c4(ORG_WRITE_ALL), + ORG_DELETE: _generate_uuid_a6c4(ORG_DELETE), + ORG_DELETE_ALL: _generate_uuid_a6c4(ORG_DELETE_ALL), + PERMISSION_PROJECT_LIST_ALL: _generate_uuid_a6c4(PERMISSION_PROJECT_LIST_ALL), + PERMISSION_PROJECT_READ_ALL: _generate_uuid_a6c4(PERMISSION_PROJECT_READ_ALL), + PERMISSION_PROJECT_WRITE_ALL: _generate_uuid_a6c4(PERMISSION_PROJECT_WRITE_ALL), + PERMISSION_PROJECT_DELETE_ALL: _generate_uuid_a6c4(PERMISSION_PROJECT_DELETE_ALL), + PERMISSION_PERMISSION_CREATE: _generate_uuid_a6c4(PERMISSION_PERMISSION_CREATE), + PERMISSION_PERMISSION_READ: _generate_uuid_a6c4(PERMISSION_PERMISSION_READ), + PERMISSION_PERMISSION_UPDATE: _generate_uuid_a6c4(PERMISSION_PERMISSION_UPDATE), + PERMISSION_PERMISSION_DELETE: _generate_uuid_a6c4(PERMISSION_PERMISSION_DELETE), + PERMISSION_PERMISSION_BINDING_CREATE: _generate_uuid_a6c4( + PERMISSION_PERMISSION_BINDING_CREATE + ), + PERMISSION_PERMISSION_BINDING_READ: _generate_uuid_a6c4( + PERMISSION_PERMISSION_BINDING_READ + ), + PERMISSION_PERMISSION_BINDING_UPDATE: _generate_uuid_a6c4( + PERMISSION_PERMISSION_BINDING_UPDATE + ), + PERMISSION_PERMISSION_BINDING_DELETE: _generate_uuid_a6c4( + PERMISSION_PERMISSION_BINDING_DELETE + ), + PERMISSION_ROLE_CREATE: _generate_uuid_a6c4(PERMISSION_ROLE_CREATE), + PERMISSION_ROLE_READ: _generate_uuid_a6c4(PERMISSION_ROLE_READ), + PERMISSION_ROLE_UPDATE: _generate_uuid_a6c4(PERMISSION_ROLE_UPDATE), + PERMISSION_ROLE_DELETE: _generate_uuid_a6c4(PERMISSION_ROLE_DELETE), + PERMISSION_ROLE_BINDING_CREATE: _generate_uuid_a6c4(PERMISSION_ROLE_BINDING_CREATE), + PERMISSION_ROLE_BINDING_READ: _generate_uuid_a6c4(PERMISSION_ROLE_BINDING_READ), + PERMISSION_ROLE_BINDING_UPDATE: _generate_uuid_a6c4(PERMISSION_ROLE_BINDING_UPDATE), + PERMISSION_ROLE_BINDING_DELETE: _generate_uuid_a6c4(PERMISSION_ROLE_BINDING_DELETE), + PERMISSION_IAM_CLIENT_CREATE: _generate_uuid_a6c4(PERMISSION_IAM_CLIENT_CREATE), + PERMISSION_IAM_CLIENT_READ_ALL: _generate_uuid_a6c4(PERMISSION_IAM_CLIENT_READ_ALL), + PERMISSION_IAM_CLIENT_UPDATE: _generate_uuid_a6c4(PERMISSION_IAM_CLIENT_UPDATE), + PERMISSION_IAM_CLIENT_DELETE: _generate_uuid_a6c4(PERMISSION_IAM_CLIENT_DELETE), +} + +COMPUTE_NODE_DEF_PERMISSIONS = ( + ("compute.node.read", "List and read own nodes"), + ("compute.node.create", "Create own nodes"), + ("compute.node.update", "Update own nodes"), + ("compute.node.delete", "Delete own nodes"), +) + +COMPUTE_NODE_SET_DEF_PERMISSIONS = ( + ("compute.node_set.read", "List and read own node sets"), + ("compute.node_set.create", "Create own node sets"), + ("compute.node_set.update", "Update own node sets"), + ("compute.node_set.delete", "Delete own node sets"), +) + +DNS_NODE_DEF_PERMISSIONS = ( + ("dns.domain.read", "List and read own domains"), + ("dns.domain.create", "Create own domains"), + ("dns.domain.update", "Update own domains"), + ("dns.domain.delete", "Delete own domains"), + ("dns.record.read", "List and read own records"), + ("dns.record.create", "Create own records"), + ("dns.record.update", "Update own records"), + ("dns.record.delete", "Delete own records"), +) + +NETWORK_LB_PERMISSIONS = ( + ("network.lb.read", "List and read load balancers"), + ("network.lb.create", "Create load balancers"), + ("network.lb.update", "Update load balancers"), + ("network.lb.delete", "Delete load balancers"), + ("network.lb_vhost.read", "List and read LB virtual hosts"), + ("network.lb_vhost.create", "Create LB virtual hosts"), + ("network.lb_vhost.update", "Update LB virtual hosts"), + ("network.lb_vhost.delete", "Delete LB virtual hosts"), + ("network.lb_vhost_route.read", "List and read LB vhost routes"), + ("network.lb_vhost_route.create", "Create LB vhost routes"), + ("network.lb_vhost_route.update", "Update LB vhost routes"), + ("network.lb_vhost_route.delete", "Delete LB vhost routes"), + ("network.lb_backendpool.read", "List and read LB backend pools"), + ("network.lb_backendpool.create", "Create LB backend pools"), + ("network.lb_backendpool.update", "Update LB backend pools"), + ("network.lb_backendpool.delete", "Delete LB backend pools"), + ("compute.node.get_private_key", "Get node(s) agent private key"), + ("compute.node_set.get_private_key", "Get node(s) agent private key"), + ("config.config.read", "List and read configs"), + ("config.config.create", "Create configs"), + ("config.config.update", "Update configs"), + ("config.config.delete", "Delete configs"), + ("em.service.read", "List and read services"), + ("em.service.create", "Create services"), + ("em.service.update", "Update services"), + ("em.service.delete", "Delete services"), +) + +SERVICE_TOKEN_PERMISSIONS = ( + ("iam.service_token.create", "Create service account tokens"), +) + +IAM_USER_PERMISSIONS = (("iam.user.create", "Create IAM users"),) + +REPO_PERMISSIONS = ( + ("repo.repository.read", "List and read repositories"), + ("repo.repository.create", "Create repositories"), + ("repo.repository.update", "Update repositories"), + ("repo.repository.delete", "Delete repositories"), + ("repo.repository.refresh", "Refresh repositories"), + ("repo.repository.upload", "Upload elements to repositories"), + ("repo.element.read", "List and read repository elements"), + ("repo.element.delete", "Delete repository elements"), + ("repo.element.install", "Install repository elements"), + ("repo.element.uninstall", "Uninstall repository elements"), + ("repo.element.upgrade", "Upgrade repository elements"), + ("repo.element.edit", "Edit repository elements"), +) + + +def _constraint_exists(session, constraint_name): + result = session.execute( + f"""SELECT 1 FROM pg_catalog.pg_constraint + WHERE conname = '{constraint_name}'""", + None, + ) + return result is not None and result.rowcount > 0 + + +def _index_exists(session, index_name): + result = session.execute( + f"""SELECT 1 FROM pg_catalog.pg_indexes + WHERE indexname = '{index_name}'""", + None, + ) + return result is not None and result.rowcount > 0 + + +SCHEMA_STATEMENTS = ( + "CREATE TYPE public.enum_agent_status AS ENUM (\n 'NEW',\n 'ACTIVE',\n 'ERROR',\n 'DISABLED'\n)", + "CREATE TYPE public.enum_config_status AS ENUM (\n 'NEW',\n 'IN_PROGRESS',\n 'ACTIVE',\n 'ERROR'\n)", + "CREATE TYPE public.enum_secret_status AS ENUM (\n 'NEW',\n 'IN_PROGRESS',\n 'ACTIVE',\n 'ERROR'\n)", + "CREATE TYPE public.enum_service_status AS ENUM (\n 'NEW',\n 'IN_PROGRESS',\n 'ACTIVE',\n 'ERROR'\n)", + "CREATE TYPE public.enum_service_target_status AS ENUM (\n 'enabled',\n 'disabled'\n)", + "CREATE TYPE public.user_type_enum AS ENUM (\n 'user',\n 'service'\n)", + "CREATE SEQUENCE IF NOT EXISTS public.dns_domain_id_seq\n START WITH 1\n INCREMENT BY 1\n NO MINVALUE\n NO MAXVALUE\n CACHE 1", + "CREATE SEQUENCE IF NOT EXISTS public.dns_domainmetadata_id_seq\n AS integer\n START WITH 1\n INCREMENT BY 1\n NO MINVALUE\n NO MAXVALUE\n CACHE 1", + "CREATE TABLE public.compute_net_interfaces (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n machine uuid,\n ipv4 character varying(15) DEFAULT NULL::character varying,\n mask character varying(15) DEFAULT NULL::character varying,\n mac character varying(17) DEFAULT NULL::character varying,\n mtu integer DEFAULT 1500,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL\n)", + "CREATE TABLE public.compute_ports (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n project_id uuid NOT NULL,\n subnet uuid,\n node uuid,\n machine uuid,\n interface character varying(32) DEFAULT NULL::character varying,\n target_ipv4 character varying(15) DEFAULT NULL::character varying,\n target_mask character varying(15) DEFAULT NULL::character varying,\n ipv4 character varying(15) DEFAULT NULL::character varying,\n mask character varying(15) DEFAULT NULL::character varying,\n mac character varying(17) DEFAULT NULL::character varying,\n status character varying(32) NOT NULL,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n source character varying(128) DEFAULT NULL::character varying,\n CONSTRAINT compute_ports_status_check CHECK (((status)::text = ANY ((ARRAY['NEW'::character varying, 'IN_PROGRESS'::character varying, 'ACTIVE'::character varying, 'ERROR'::character varying])::text[])))\n)", + "CREATE TABLE public.machines (\n uuid uuid NOT NULL,\n project_id uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n cores integer NOT NULL,\n ram integer NOT NULL,\n node uuid,\n machine_type character varying(2) NOT NULL,\n boot character varying(8) NOT NULL,\n pool uuid,\n firmware_uuid uuid,\n status character varying(32) NOT NULL,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n image character varying(255) DEFAULT NULL::character varying,\n block_devices jsonb DEFAULT '{}'::jsonb,\n CONSTRAINT machines_boot_check CHECK (((boot)::text = ANY ((ARRAY['hd0'::character varying, 'hd1'::character varying, 'hd2'::character varying, 'hd3'::character varying, 'cdrom'::character varying, 'network'::character varying])::text[]))),\n CONSTRAINT machines_machine_type_check CHECK (((machine_type)::text = ANY ((ARRAY['VM'::character varying, 'HW'::character varying])::text[]))),\n CONSTRAINT machines_status_check CHECK (((status)::text = ANY ((ARRAY['NEW'::character varying, 'SCHEDULED'::character varying, 'IN_PROGRESS'::character varying, 'STARTED'::character varying, 'ACTIVE'::character varying, 'IDLE'::character varying, 'ERROR'::character varying])::text[])))\n)", + "CREATE TABLE public.nodes (\n uuid uuid NOT NULL,\n project_id uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n cores integer NOT NULL,\n ram integer NOT NULL,\n node_type character varying(2) NOT NULL,\n status character varying(32) NOT NULL,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n default_network character varying(255) DEFAULT NULL::character varying,\n node_set uuid,\n placement_policies uuid[] DEFAULT '{}'::uuid[] NOT NULL,\n disk_spec jsonb,\n hostname character varying(256) DEFAULT NULL::character varying,\n CONSTRAINT nodes_node_type_check CHECK (((node_type)::text = ANY ((ARRAY['VM'::character varying, 'HW'::character varying])::text[]))),\n CONSTRAINT nodes_status_check CHECK (((status)::text = ANY ((ARRAY['NEW'::character varying, 'SCHEDULED'::character varying, 'IN_PROGRESS'::character varying, 'STARTED'::character varying, 'ACTIVE'::character varying, 'ERROR'::character varying])::text[])))\n)", + "CREATE TABLE public.compute_machine_volumes (\n uuid uuid NOT NULL,\n project_id uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n node_volume uuid,\n pool uuid,\n machine uuid,\n size integer NOT NULL,\n boot boolean DEFAULT true NOT NULL,\n index integer DEFAULT 4096 NOT NULL,\n label character varying(256),\n image character varying(256) DEFAULT NULL::character varying,\n device_type character varying(64) DEFAULT ''::character varying NOT NULL,\n status character varying(32) DEFAULT 'NEW'::character varying NOT NULL,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n CONSTRAINT compute_machine_volumes_status_check CHECK (((status)::text = ANY ((ARRAY['NEW'::character varying, 'IN_PROGRESS'::character varying, 'ACTIVE'::character varying, 'ERROR'::character varying])::text[])))\n)", + "CREATE TABLE public.compute_networks (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n project_id uuid NOT NULL,\n driver_spec jsonb DEFAULT '{}'::jsonb NOT NULL,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL\n)", + "CREATE TABLE public.compute_placement_domains (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL\n)", + "CREATE TABLE public.compute_placement_policies (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n project_id uuid NOT NULL,\n domain uuid,\n zone uuid,\n kind character varying(64) NOT NULL,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL\n)", + "CREATE TABLE public.compute_placement_policy_allocations (\n uuid uuid NOT NULL,\n node uuid,\n policy uuid,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL\n)", + "CREATE TABLE public.compute_placement_zones (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n domain uuid,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL\n)", + "CREATE TABLE public.compute_sets (\n uuid uuid NOT NULL,\n project_id uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n cores integer NOT NULL,\n ram integer NOT NULL,\n replicas integer NOT NULL,\n node_type character varying(2) NOT NULL,\n set_type character varying(32) NOT NULL,\n status character varying(32) NOT NULL,\n nodes jsonb NOT NULL,\n default_network jsonb NOT NULL,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n disk_spec jsonb,\n CONSTRAINT compute_sets_node_type_check CHECK (((node_type)::text = ANY ((ARRAY['VM'::character varying, 'HW'::character varying])::text[]))),\n CONSTRAINT compute_sets_set_type_check CHECK (((set_type)::text = 'SET'::text)),\n CONSTRAINT compute_sets_status_check CHECK (((status)::text = ANY ((ARRAY['NEW'::character varying, 'SCHEDULED'::character varying, 'IN_PROGRESS'::character varying, 'STARTED'::character varying, 'ACTIVE'::character varying, 'ERROR'::character varying])::text[])))\n)", + "CREATE TABLE public.compute_subnets (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n project_id uuid NOT NULL,\n network uuid,\n cidr character varying(18) NOT NULL,\n ip_range character varying(31) DEFAULT NULL::character varying,\n dhcp boolean DEFAULT true,\n dns_servers character varying(512) DEFAULT '{}'::character varying NOT NULL,\n routers character varying(512) DEFAULT '{}'::character varying NOT NULL,\n next_server character varying(256) DEFAULT '127.0.0.1'::character varying,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n ip_discovery_range character varying(31) DEFAULT NULL::character varying\n)", + "CREATE TABLE public.node_volumes (\n uuid uuid NOT NULL,\n project_id uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n node uuid,\n size integer NOT NULL,\n boot boolean DEFAULT true NOT NULL,\n label character varying(127),\n device_type character varying(64) NOT NULL,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n status character varying(32) DEFAULT 'NEW'::character varying NOT NULL,\n index integer DEFAULT 4096,\n pool uuid,\n image character varying(256) DEFAULT NULL::character varying,\n CONSTRAINT node_volumes_status_check CHECK (((status)::text = ANY ((ARRAY['NEW'::character varying, 'IN_PROGRESS'::character varying, 'ACTIVE'::character varying, 'ERROR'::character varying])::text[])))\n)", + "CREATE TABLE public.config_configs (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n project_id uuid NOT NULL,\n status public.enum_config_status DEFAULT 'NEW'::public.enum_config_status NOT NULL,\n path character varying(255) NOT NULL,\n target jsonb NOT NULL,\n body jsonb NOT NULL,\n on_change jsonb NOT NULL,\n mode character(4) NOT NULL,\n owner character varying(128) NOT NULL,\n \"group\" character varying(128) NOT NULL,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL\n)", + "CREATE TABLE public.dns_domainmetadata (\n id integer NOT NULL,\n domain_id integer,\n kind character varying(32),\n content text\n)", + "CREATE TABLE public.dns_domains (\n uuid uuid NOT NULL,\n id integer DEFAULT nextval('public.dns_domain_id_seq'::regclass),\n name character varying(255) NOT NULL,\n master character varying(128) DEFAULT NULL::character varying,\n last_check integer,\n type text DEFAULT 'NATIVE'::text NOT NULL,\n notified_serial bigint,\n account character varying(40) DEFAULT NULL::character varying,\n options text,\n catalog text,\n project_id uuid NOT NULL,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n sync_to_ecosystem boolean DEFAULT false NOT NULL,\n CONSTRAINT c_lowercase_name CHECK (((name)::text = lower((name)::text)))\n)", + "CREATE TABLE public.dns_records (\n uuid uuid NOT NULL,\n domain_id integer,\n name character varying(255) DEFAULT NULL::character varying,\n type character varying(10) DEFAULT NULL::character varying,\n content character varying(65535) DEFAULT NULL::character varying,\n ttl integer,\n prio integer,\n disabled boolean DEFAULT false,\n ordername character varying(255),\n auth boolean DEFAULT true,\n domain uuid NOT NULL,\n record jsonb NOT NULL,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n project_id uuid NOT NULL,\n CONSTRAINT dns_records_name_check CHECK (((name)::text = lower((name)::text)))\n)", + "CREATE TABLE public.em_elements (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) DEFAULT ''::character varying NOT NULL,\n status character varying(20) DEFAULT 'NEW'::character varying NOT NULL,\n version character varying(64) NOT NULL,\n install_type character varying(20) DEFAULT 'MANUAL'::character varying NOT NULL,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n api_version character varying(16) DEFAULT NULL::character varying,\n profile uuid,\n project_id uuid,\n requirements jsonb DEFAULT '{}'::jsonb NOT NULL,\n manifest uuid,\n CONSTRAINT em_elements_install_type_check CHECK (((install_type)::text = ANY ((ARRAY['MANUAL'::character varying, 'AUTO_AS_DEPENDENCY'::character varying])::text[]))),\n CONSTRAINT em_elements_status_check CHECK (((status)::text = ANY ((ARRAY['NEW'::character varying, 'IN_PROGRESS'::character varying, 'ACTIVE'::character varying])::text[])))\n)", + "CREATE TABLE public.em_exports (\n uuid uuid NOT NULL,\n element uuid NOT NULL,\n name character varying(255) NOT NULL,\n kind character varying(20) DEFAULT 'resource'::character varying NOT NULL,\n link character varying(255) NOT NULL,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n CONSTRAINT em_exports_kind_check CHECK (((kind)::text = 'resource'::text))\n)", + "CREATE TABLE public.em_imports (\n uuid uuid NOT NULL,\n element uuid NOT NULL,\n from_element uuid NOT NULL,\n from_resource uuid NOT NULL,\n name character varying(255) NOT NULL,\n kind character varying(20) DEFAULT 'resource'::character varying NOT NULL,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n CONSTRAINT em_imports_kind_check CHECK (((kind)::text = 'resource'::text))\n)", + "CREATE TABLE public.em_resources (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n element uuid NOT NULL,\n status character varying(20) DEFAULT 'NEW'::character varying NOT NULL,\n resource_link_prefix character varying(256) NOT NULL,\n value jsonb DEFAULT '{}'::jsonb NOT NULL,\n target_resource uuid,\n actual_resource uuid,\n full_hash character varying(256) DEFAULT ''::character varying NOT NULL,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n CONSTRAINT em_resources_status_check CHECK (((status)::text = ANY ((ARRAY['NEW'::character varying, 'IN_PROGRESS'::character varying, 'ACTIVE'::character varying])::text[])))\n)", + "CREATE TABLE public.em_manifests (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) DEFAULT ''::character varying NOT NULL,\n status character varying(20) DEFAULT 'NEW'::character varying NOT NULL,\n version character varying(64) NOT NULL,\n schema_version integer DEFAULT 1 NOT NULL,\n project_id uuid NOT NULL,\n requirements jsonb DEFAULT '{}'::jsonb NOT NULL,\n resources jsonb DEFAULT '{}'::jsonb NOT NULL,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n api_version character varying(16) DEFAULT NULL::character varying,\n exports jsonb DEFAULT '{}'::jsonb NOT NULL,\n imports jsonb DEFAULT '{}'::jsonb NOT NULL,\n openapi_spec text,\n CONSTRAINT em_manifests_status_check CHECK (((status)::text = 'ACTIVE'::text))\n)", + "CREATE TABLE public.em_services (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n project_id uuid NOT NULL,\n status public.enum_service_status DEFAULT 'NEW'::public.enum_service_status NOT NULL,\n target_status public.enum_service_target_status DEFAULT 'enabled'::public.enum_service_target_status NOT NULL,\n path character varying(255) NOT NULL,\n target jsonb NOT NULL,\n service_type jsonb NOT NULL,\n before jsonb[],\n after jsonb[],\n \"user\" character varying(255) NOT NULL,\n \"group\" character varying(255),\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL\n)", + "CREATE TABLE public.gcl_sdk_audit_logs (\n uuid uuid NOT NULL,\n object_uuid uuid NOT NULL,\n object_type character varying(64) NOT NULL,\n user_uuid uuid,\n action character varying(64) NOT NULL,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL\n)", + "CREATE TABLE public.gcl_sdk_events (\n uuid uuid NOT NULL,\n status character varying(20) DEFAULT 'NEW'::character varying NOT NULL,\n event_type jsonb NOT NULL,\n event_data jsonb NOT NULL,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n CONSTRAINT gcl_sdk_events_status_check CHECK (((status)::text = ANY ((ARRAY['NEW'::character varying, 'IN_PROGRESS'::character varying, 'ERROR'::character varying, 'ACTIVE'::character varying])::text[])))\n)", + "CREATE TABLE public.iam_binding_permissions (\n uuid uuid NOT NULL,\n status character varying(20) DEFAULT 'ACTIVE'::character varying NOT NULL,\n project_id uuid,\n role uuid NOT NULL,\n permission uuid NOT NULL,\n description character varying(256) DEFAULT ''::character varying,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n CONSTRAINT iam_binding_permissions_status_check CHECK (((status)::text = 'ACTIVE'::text))\n)", + "CREATE TABLE public.iam_binding_roles (\n uuid uuid NOT NULL,\n status character varying(20) DEFAULT 'ACTIVE'::character varying NOT NULL,\n \"user\" uuid NOT NULL,\n role uuid NOT NULL,\n project uuid,\n description character varying(256) DEFAULT ''::character varying,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n CONSTRAINT iam_binding_roles_status_check CHECK (((status)::text = 'ACTIVE'::text))\n)", + 'CREATE TABLE public.iam_clients (\n uuid uuid NOT NULL,\n status character varying(20) DEFAULT \'ACTIVE\'::character varying NOT NULL,\n name character varying(256) NOT NULL,\n project_id uuid,\n description character varying(256) DEFAULT \'\'::character varying,\n client_id character varying(64) NOT NULL,\n secret_hash character(128) NOT NULL,\n salt character(24) NOT NULL,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n signature_algorithm jsonb DEFAULT \'{"kind": "HS256", "secret_uuid": "00000000-0000-0000-0000-000000000001", "previous_secret_uuid": null}\'::jsonb NOT NULL,\n registration_auto_provision boolean DEFAULT true NOT NULL,\n CONSTRAINT iam_clients_status_check CHECK (((status)::text = \'ACTIVE\'::text))\n)', + "CREATE TABLE public.iam_idp (\n uuid uuid NOT NULL,\n status character varying(20) DEFAULT 'ACTIVE'::character varying NOT NULL,\n name character varying(256) NOT NULL,\n project_id uuid,\n description character varying(256) DEFAULT ''::character varying,\n scope character varying(64) DEFAULT 'openid'::character varying,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n iam_client uuid,\n nonce_required boolean DEFAULT true NOT NULL,\n callback jsonb DEFAULT '{\"kind\": \"callback_uri\", \"callback\": \"\"}'::jsonb NOT NULL,\n CONSTRAINT iam_idp_status_check CHECK (((status)::text = 'ACTIVE'::text))\n)", + "CREATE TABLE public.iam_idp_authorization_info (\n uuid uuid NOT NULL,\n idp uuid NOT NULL,\n state character varying(256) NOT NULL,\n response_type character varying(20) DEFAULT 'code'::character varying NOT NULL,\n nonce character varying(256) NOT NULL,\n scope character varying(256) NOT NULL,\n expiration_time_at timestamp(6) without time zone NOT NULL,\n token uuid,\n code uuid NOT NULL,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n redirect_uri character varying(256) DEFAULT ''::character varying NOT NULL,\n CONSTRAINT iam_idp_authorization_info_response_type_check CHECK (((response_type)::text = 'code'::text))\n)", + "CREATE TABLE public.iam_organization_members (\n uuid uuid NOT NULL,\n organization uuid NOT NULL,\n \"user\" uuid NOT NULL,\n role character varying(20) DEFAULT 'MEMBER'::character varying NOT NULL,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n CONSTRAINT iam_organization_members_role_check CHECK (((role)::text = ANY ((ARRAY['OWNER'::character varying, 'MEMBER'::character varying])::text[])))\n)", + "CREATE TABLE public.iam_organizations (\n uuid uuid NOT NULL,\n status character varying(20) DEFAULT 'ACTIVE'::character varying NOT NULL,\n name character varying(128) NOT NULL,\n description character varying(256) DEFAULT ''::character varying,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n info character varying(2048) DEFAULT '{}'::character varying,\n CONSTRAINT iam_organizations_status_check CHECK (((status)::text = 'ACTIVE'::text))\n)", + "CREATE TABLE public.iam_permissions (\n uuid uuid NOT NULL,\n status character varying(20) DEFAULT 'ACTIVE'::character varying NOT NULL,\n name character varying(256) NOT NULL,\n description character varying(256) DEFAULT ''::character varying,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n CONSTRAINT iam_permissions_status_check CHECK (((status)::text = 'ACTIVE'::text))\n)", + "CREATE TABLE public.iam_users (\n uuid uuid NOT NULL,\n status character varying(20) DEFAULT 'ACTIVE'::character varying NOT NULL,\n name character varying(256) NOT NULL,\n description character varying(256) NOT NULL,\n first_name character varying(128),\n last_name character varying(128),\n email character varying(128) NOT NULL,\n secret_hash character(128) NOT NULL,\n salt character(24) NOT NULL,\n otp_secret character varying(128) DEFAULT ''::character varying,\n otp_enabled boolean DEFAULT false,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n surname character varying(128) DEFAULT ''::character varying NOT NULL,\n phone character varying(15),\n email_verified boolean DEFAULT false NOT NULL,\n confirmation_code uuid,\n confirmation_code_made_at timestamp without time zone,\n user_source jsonb DEFAULT '{\"kind\": \"IAM\"}'::jsonb NOT NULL,\n custom_props jsonb,\n type public.user_type_enum DEFAULT 'user'::public.user_type_enum NOT NULL,\n registration_client uuid,\n CONSTRAINT iam_users_status_check CHECK (((status)::text = 'ACTIVE'::text))\n)", + "CREATE TABLE public.iam_projects (\n uuid uuid NOT NULL,\n status character varying(20) DEFAULT 'ACTIVE'::character varying NOT NULL,\n name character varying(128) NOT NULL,\n description character varying(256) DEFAULT ''::character varying,\n organization uuid NOT NULL,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n CONSTRAINT iam_projects_status_check CHECK (((status)::text = ANY ((ARRAY['NEW'::character varying, 'IN_PROGRESS'::character varying, 'ACTIVE'::character varying, 'DELETING'::character varying])::text[])))\n)", + "CREATE TABLE public.iam_roles (\n uuid uuid NOT NULL,\n status character varying(20) DEFAULT 'ACTIVE'::character varying NOT NULL,\n name character varying(128) NOT NULL,\n description character varying(256) DEFAULT ''::character varying,\n project_id uuid,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n CONSTRAINT iam_roles_status_check CHECK (((status)::text = 'ACTIVE'::text))\n)", + "CREATE TABLE public.iam_tokens (\n uuid uuid NOT NULL,\n \"user\" uuid NOT NULL,\n project uuid,\n expiration_at timestamp(6) without time zone CONSTRAINT iam_tokens_experation_at_not_null NOT NULL,\n refresh_token_uuid uuid NOT NULL,\n refresh_expiration_at timestamp(6) without time zone CONSTRAINT iam_tokens_refresh_experation_at_not_null NOT NULL,\n issuer character varying(256) DEFAULT NULL::character varying,\n audience character varying(256) DEFAULT 'account'::character varying,\n typ character varying(64) DEFAULT 'Bearer'::character varying,\n scope character varying(128) NOT NULL,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n expiration_delta double precision DEFAULT 900.0 NOT NULL,\n refresh_expiration_delta double precision DEFAULT 86400.0 NOT NULL,\n nonce character varying(256) DEFAULT NULL::character varying,\n iam_client uuid NOT NULL\n)", + "CREATE TABLE public.machine_pools (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n driver_spec jsonb NOT NULL,\n machine_type character varying(2) NOT NULL,\n status character varying(32) NOT NULL,\n avail_cores integer DEFAULT 0 NOT NULL,\n avail_ram integer DEFAULT 0 NOT NULL,\n all_cores integer DEFAULT 0 NOT NULL,\n all_ram integer DEFAULT 0 NOT NULL,\n storage_pools jsonb[] DEFAULT '{}'::jsonb[],\n builder uuid,\n agent uuid,\n cores_ratio double precision DEFAULT 1.0 NOT NULL,\n ram_ratio double precision DEFAULT 1.0 NOT NULL,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n CONSTRAINT machine_pools_machine_type_check CHECK (((machine_type)::text = ANY ((ARRAY['VM'::character varying, 'HW'::character varying])::text[]))),\n CONSTRAINT machine_pools_status_check CHECK (((status)::text = ANY ((ARRAY['ACTIVE'::character varying, 'DISABLED'::character varying, 'MAINTENANCE'::character varying, 'IN_PROGRESS'::character varying])::text[])))\n)", + "CREATE TABLE public.n_builders (\n uuid uuid NOT NULL,\n status character varying(32) NOT NULL,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n CONSTRAINT n_builders_status_check CHECK (((status)::text = ANY ((ARRAY['ACTIVE'::character varying, 'DISABLED'::character varying])::text[])))\n)", + "CREATE TABLE public.n_machine_pool_reservations (\n uuid uuid NOT NULL,\n cores integer NOT NULL,\n ram integer NOT NULL,\n pool uuid,\n machine uuid,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL\n)", + "CREATE TABLE public.net_border (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description text,\n project_id uuid NOT NULL,\n status character varying(64) DEFAULT 'NEW'::character varying NOT NULL,\n created_at timestamp without time zone NOT NULL,\n updated_at timestamp without time zone NOT NULL,\n node uuid,\n snat_rules jsonb[] DEFAULT '{}'::jsonb[] NOT NULL,\n forwards jsonb[] DEFAULT '{}'::jsonb[] NOT NULL,\n type jsonb DEFAULT '{\"kind\": \"core_agent\"}'::jsonb NOT NULL,\n ipsv4 character varying(15)[] DEFAULT '{}'::character varying[] NOT NULL\n)", + "CREATE TABLE public.net_lb (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description text,\n project_id uuid NOT NULL,\n status character varying(64) DEFAULT 'NEW'::character varying NOT NULL,\n ipsv4 character varying(15)[],\n type jsonb NOT NULL,\n created_at timestamp without time zone NOT NULL,\n updated_at timestamp without time zone NOT NULL\n)", + "CREATE TABLE public.net_lb_backendpools (\n uuid uuid NOT NULL,\n name character varying(64) NOT NULL,\n status character varying(64) DEFAULT 'NEW'::character varying NOT NULL,\n description text,\n project_id uuid NOT NULL,\n created_at timestamp without time zone NOT NULL,\n updated_at timestamp without time zone NOT NULL,\n endpoints jsonb[] NOT NULL,\n balance character varying(32) NOT NULL,\n parent uuid NOT NULL\n)", + "CREATE TABLE public.net_lb_vhosts (\n uuid uuid NOT NULL,\n name character varying(64) NOT NULL,\n enabled boolean DEFAULT true NOT NULL,\n status character varying(64) DEFAULT 'NEW'::character varying NOT NULL,\n description text,\n project_id uuid NOT NULL,\n created_at timestamp without time zone NOT NULL,\n updated_at timestamp without time zone NOT NULL,\n protocol character varying(10) NOT NULL,\n port integer NOT NULL,\n domains character varying(255)[],\n cert jsonb,\n parent uuid NOT NULL,\n external_sources jsonb[] DEFAULT '{}'::jsonb[] NOT NULL,\n proxy_protocol_from character varying(18)\n)", + "CREATE TABLE public.net_lb_vhosts_routes (\n uuid uuid NOT NULL,\n name character varying(64) NOT NULL,\n enabled boolean DEFAULT true NOT NULL,\n status character varying(64) DEFAULT 'NEW'::character varying NOT NULL,\n description text,\n project_id uuid NOT NULL,\n created_at timestamp without time zone NOT NULL,\n updated_at timestamp without time zone NOT NULL,\n condition jsonb,\n parent uuid NOT NULL\n)", + "CREATE TABLE public.repo_artifacts (\n uuid uuid NOT NULL,\n project_id uuid NOT NULL,\n element uuid NOT NULL,\n urn character varying(2048) NOT NULL,\n uri character varying(2048) NOT NULL\n)", + "CREATE TABLE public.repo_element_deps_bindings (\n uuid uuid NOT NULL,\n element uuid NOT NULL,\n depends_on uuid NOT NULL\n)", + "CREATE TABLE public.repo_elements (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description text DEFAULT ''::text NOT NULL,\n project_id uuid NOT NULL,\n repository uuid NOT NULL,\n version character varying(255) NOT NULL,\n status character varying(32) DEFAULT 'NEW'::character varying NOT NULL,\n installation_state character varying(32) DEFAULT 'UNINSTALLED'::character varying NOT NULL,\n manifest jsonb DEFAULT '{}'::jsonb,\n specification jsonb DEFAULT '{}'::jsonb,\n inventory jsonb DEFAULT '{}'::jsonb,\n element uuid,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL\n)", + "CREATE TABLE public.repo_repositories (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description text DEFAULT ''::text NOT NULL,\n project_id uuid NOT NULL,\n status character varying(32) DEFAULT 'NEW'::character varying NOT NULL,\n priority integer DEFAULT 2048 NOT NULL,\n refresh_rate integer DEFAULT 3600 NOT NULL,\n sync_mode character varying(32) DEFAULT 'copy'::character varying NOT NULL,\n driver_spec jsonb,\n next_refresh timestamp(6) without time zone DEFAULT now() NOT NULL,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL\n)", + "CREATE TABLE public.secret_certificates (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n project_id uuid NOT NULL,\n status character varying(32) NOT NULL,\n constructor jsonb NOT NULL,\n method jsonb NOT NULL,\n email character varying(254) NOT NULL,\n domains character varying(1024) NOT NULL,\n key text,\n cert text,\n expiration_at timestamp without time zone,\n expiration_threshold integer NOT NULL,\n overcome_threshold boolean DEFAULT false,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n CONSTRAINT secret_certificates_status_check CHECK (((status)::text = ANY ((ARRAY['NEW'::character varying, 'IN_PROGRESS'::character varying, 'ACTIVE'::character varying, 'ERROR'::character varying])::text[])))\n)", + "CREATE TABLE public.secret_passwords (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n project_id uuid NOT NULL,\n status public.enum_secret_status DEFAULT 'NEW'::public.enum_secret_status NOT NULL,\n constructor jsonb NOT NULL,\n value character varying(512) DEFAULT NULL::character varying,\n method character varying(64) NOT NULL,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n default_length integer DEFAULT 32 NOT NULL\n)", + "CREATE TABLE public.secret_rsa_keys (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n project_id uuid NOT NULL,\n status character varying(32) NOT NULL,\n constructor jsonb NOT NULL,\n private_key text NOT NULL,\n public_key text NOT NULL,\n bitness integer DEFAULT 2048 NOT NULL,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n CONSTRAINT secret_rsa_keys_bitness_check CHECK ((bitness = ANY (ARRAY[2048, 3072, 4096]))),\n CONSTRAINT secret_rsa_keys_status_check CHECK (((status)::text = ANY ((ARRAY['NEW'::character varying, 'IN_PROGRESS'::character varying, 'ACTIVE'::character varying, 'ERROR'::character varying])::text[])))\n)", + "CREATE TABLE public.secret_ssh_keys (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n project_id uuid NOT NULL,\n status character varying(32) NOT NULL,\n constructor jsonb NOT NULL,\n target jsonb NOT NULL,\n \"user\" character varying(64) NOT NULL,\n authorized_keys character varying(256) NOT NULL,\n target_public_key text,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n CONSTRAINT secret_ssh_keys_status_check CHECK (((status)::text = ANY ((ARRAY['NEW'::character varying, 'IN_PROGRESS'::character varying, 'ACTIVE'::character varying, 'ERROR'::character varying])::text[])))\n)", + "CREATE TABLE public.security_rules (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) DEFAULT ''::character varying NOT NULL,\n project_id uuid,\n condition jsonb NOT NULL,\n action jsonb CONSTRAINT security_rules_verifier_not_null NOT NULL,\n operator character varying(8) DEFAULT 'OR'::character varying NOT NULL,\n status character varying(20) DEFAULT 'ACTIVE'::character varying NOT NULL,\n created_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n updated_at timestamp(6) without time zone DEFAULT now() NOT NULL,\n CONSTRAINT security_rules_operator_check CHECK (((operator)::text = ANY ((ARRAY['OR'::character varying, 'AND'::character varying])::text[]))),\n CONSTRAINT security_rules_status_check CHECK (((status)::text = 'ACTIVE'::text))\n)", + "CREATE TABLE public.storage_certs (\n uuid uuid NOT NULL,\n status character varying(32) NOT NULL,\n pkey character varying(10240) NOT NULL,\n fullchain character varying(10240) NOT NULL,\n csr character varying(10240) NOT NULL,\n expiration_at timestamp without time zone NOT NULL,\n meta jsonb NOT NULL,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n CONSTRAINT storage_certs_status_check CHECK (((status)::text = ANY ((ARRAY['NEW'::character varying, 'IN_PROGRESS'::character varying, 'ACTIVE'::character varying, 'ERROR'::character varying])::text[])))\n)", + "CREATE TABLE public.storage_passwords (\n uuid uuid NOT NULL,\n status public.enum_secret_status DEFAULT 'NEW'::public.enum_secret_status NOT NULL,\n value character varying(512) NOT NULL,\n meta jsonb NOT NULL,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL\n)", + "CREATE TABLE public.vs_profiles (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n project_id uuid NOT NULL,\n status character varying(32) NOT NULL,\n profile_type character varying(32) NOT NULL,\n active boolean DEFAULT false,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n CONSTRAINT vs_profiles_profile_type_check CHECK (((profile_type)::text = ANY ((ARRAY['GLOBAL'::character varying, 'ELEMENT'::character varying])::text[]))),\n CONSTRAINT vs_profiles_status_check CHECK (((status)::text = ANY ((ARRAY['NEW'::character varying, 'IN_PROGRESS'::character varying, 'ACTIVE'::character varying, 'ERROR'::character varying])::text[])))\n)", + "CREATE TABLE public.vs_values (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n project_id uuid NOT NULL,\n status character varying(32) NOT NULL,\n value jsonb,\n read_only boolean DEFAULT false,\n manual_selected boolean DEFAULT false,\n variable uuid,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n CONSTRAINT vs_values_status_check CHECK (((status)::text = ANY ((ARRAY['NEW'::character varying, 'IN_PROGRESS'::character varying, 'ACTIVE'::character varying, 'ERROR'::character varying])::text[])))\n)", + "CREATE TABLE public.vs_variables (\n uuid uuid NOT NULL,\n name character varying(255) NOT NULL,\n description character varying(255) NOT NULL,\n project_id uuid NOT NULL,\n status character varying(32) NOT NULL,\n setter jsonb NOT NULL,\n value jsonb,\n created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,\n CONSTRAINT vs_variables_status_check CHECK (((status)::text = ANY ((ARRAY['NEW'::character varying, 'IN_PROGRESS'::character varying, 'ACTIVE'::character varying, 'ERROR'::character varying])::text[])))\n)", + 'CREATE TABLE IF NOT EXISTS quota_limits (\n uuid UUID NOT NULL PRIMARY KEY,\n project_id UUID NOT NULL,\n resource_name VARCHAR(255) NOT NULL,\n field_name VARCHAR(255) NOT NULL DEFAULT \'\',\n "limit" INTEGER NOT NULL,\n "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(),\n "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW()\n)', + "ALTER TABLE ONLY public.dns_domainmetadata ALTER COLUMN id SET DEFAULT nextval('public.dns_domainmetadata_id_seq'::regclass)", + "ALTER TABLE ONLY public.compute_machine_volumes\n ADD CONSTRAINT compute_machine_volumes_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.compute_net_interfaces\n ADD CONSTRAINT compute_net_interfaces_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.compute_networks\n ADD CONSTRAINT compute_networks_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.compute_placement_domains\n ADD CONSTRAINT compute_placement_domains_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.compute_placement_policies\n ADD CONSTRAINT compute_placement_policies_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.compute_placement_policy_allocations\n ADD CONSTRAINT compute_placement_policy_allocations_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.compute_placement_zones\n ADD CONSTRAINT compute_placement_zones_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.compute_ports\n ADD CONSTRAINT compute_ports_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.compute_sets\n ADD CONSTRAINT compute_sets_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.compute_subnets\n ADD CONSTRAINT compute_subnets_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.config_configs\n ADD CONSTRAINT config_configs_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.dns_domainmetadata\n ADD CONSTRAINT dns_domainmetadata_pkey PRIMARY KEY (id)", + "ALTER TABLE ONLY public.dns_domains\n ADD CONSTRAINT dns_domains_id_key UNIQUE (id)", + "ALTER TABLE ONLY public.dns_domains\n ADD CONSTRAINT dns_domains_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.dns_records\n ADD CONSTRAINT dns_records_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.em_elements\n ADD CONSTRAINT em_elements_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.em_elements\n ADD CONSTRAINT em_elements_unique_name UNIQUE (name)", + "ALTER TABLE ONLY public.em_exports\n ADD CONSTRAINT em_exports_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.em_exports\n ADD CONSTRAINT em_exports_unique_name UNIQUE (element, name)", + "ALTER TABLE ONLY public.em_imports\n ADD CONSTRAINT em_imports_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.em_imports\n ADD CONSTRAINT em_imports_unique_name UNIQUE (element, name)", + "ALTER TABLE ONLY public.em_manifests\n ADD CONSTRAINT em_manifests_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.em_resources\n ADD CONSTRAINT em_resources_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.em_services\n ADD CONSTRAINT em_services_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.gcl_sdk_audit_logs\n ADD CONSTRAINT gcl_sdk_audit_logs_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.gcl_sdk_events\n ADD CONSTRAINT gcl_sdk_events_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.iam_binding_permissions\n ADD CONSTRAINT iam_binding_permissions_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.iam_binding_roles\n ADD CONSTRAINT iam_binding_roles_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.iam_clients\n ADD CONSTRAINT iam_clients_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.iam_idp_authorization_info\n ADD CONSTRAINT iam_idp_authorization_info_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.iam_idp\n ADD CONSTRAINT iam_idp_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.iam_organization_members\n ADD CONSTRAINT iam_organization_members_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.iam_organizations\n ADD CONSTRAINT iam_organizations_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.iam_permissions\n ADD CONSTRAINT iam_permissions_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.iam_projects\n ADD CONSTRAINT iam_projects_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.iam_roles\n ADD CONSTRAINT iam_roles_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.iam_tokens\n ADD CONSTRAINT iam_tokens_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.iam_users\n ADD CONSTRAINT iam_users_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.machine_pools\n ADD CONSTRAINT machine_pools_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.machines\n ADD CONSTRAINT machines_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.n_builders\n ADD CONSTRAINT n_builders_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.n_machine_pool_reservations\n ADD CONSTRAINT n_machine_pool_reservations_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.net_border\n ADD CONSTRAINT net_border_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.net_lb_backendpools\n ADD CONSTRAINT net_lb_backendpools_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.net_lb\n ADD CONSTRAINT net_lb_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.net_lb_vhosts\n ADD CONSTRAINT net_lb_vhosts_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.net_lb_vhosts_routes\n ADD CONSTRAINT net_lb_vhosts_routes_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.node_volumes\n ADD CONSTRAINT node_volumes_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.nodes\n ADD CONSTRAINT nodes_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.ra_migrations\n ADD CONSTRAINT ra_migrations_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.repo_artifacts\n ADD CONSTRAINT repo_artifacts_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.repo_element_deps_bindings\n ADD CONSTRAINT repo_element_deps_bindings_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.repo_elements\n ADD CONSTRAINT repo_elements_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.repo_repositories\n ADD CONSTRAINT repo_repositories_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.secret_certificates\n ADD CONSTRAINT secret_certificates_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.secret_passwords\n ADD CONSTRAINT secret_passwords_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.secret_rsa_keys\n ADD CONSTRAINT secret_rsa_keys_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.secret_ssh_keys\n ADD CONSTRAINT secret_ssh_keys_pkey PRIMARY KEY (uuid)", + 'ALTER TABLE ONLY public.secret_ssh_keys\n ADD CONSTRAINT secret_ssh_keys_user_target_target_public_key_key UNIQUE ("user", target, target_public_key)', + "ALTER TABLE ONLY public.security_rules\n ADD CONSTRAINT security_rules_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.storage_certs\n ADD CONSTRAINT storage_certs_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.storage_passwords\n ADD CONSTRAINT storage_passwords_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.em_elements\n ADD CONSTRAINT unique_em_elements_name_version_idx UNIQUE (name, version)", + 'ALTER TABLE ONLY public.iam_organization_members\n ADD CONSTRAINT uq_organization_user UNIQUE (organization, "user")', + "ALTER TABLE ONLY public.vs_profiles\n ADD CONSTRAINT vs_profiles_name_key UNIQUE (name)", + "ALTER TABLE ONLY public.vs_profiles\n ADD CONSTRAINT vs_profiles_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.vs_values\n ADD CONSTRAINT vs_values_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.vs_variables\n ADD CONSTRAINT vs_variables_pkey PRIMARY KEY (uuid)", + "ALTER TABLE ONLY public.compute_machine_volumes\n ADD CONSTRAINT compute_machine_volumes_machine_fkey FOREIGN KEY (machine) REFERENCES public.machines(uuid) ON DELETE SET NULL", + "ALTER TABLE ONLY public.compute_machine_volumes\n ADD CONSTRAINT compute_machine_volumes_node_volume_fkey FOREIGN KEY (node_volume) REFERENCES public.node_volumes(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.compute_machine_volumes\n ADD CONSTRAINT compute_machine_volumes_pool_fkey FOREIGN KEY (pool) REFERENCES public.machine_pools(uuid) ON DELETE SET NULL", + "ALTER TABLE ONLY public.compute_net_interfaces\n ADD CONSTRAINT compute_net_interfaces_machine_fkey FOREIGN KEY (machine) REFERENCES public.machines(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.compute_placement_policies\n ADD CONSTRAINT compute_placement_policies_domain_fkey FOREIGN KEY (domain) REFERENCES public.compute_placement_domains(uuid) ON DELETE RESTRICT", + "ALTER TABLE ONLY public.compute_placement_policies\n ADD CONSTRAINT compute_placement_policies_zone_fkey FOREIGN KEY (zone) REFERENCES public.compute_placement_zones(uuid) ON DELETE RESTRICT", + "ALTER TABLE ONLY public.compute_placement_policy_allocations\n ADD CONSTRAINT compute_placement_policy_allocations_node_fkey FOREIGN KEY (node) REFERENCES public.nodes(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.compute_placement_policy_allocations\n ADD CONSTRAINT compute_placement_policy_allocations_policy_fkey FOREIGN KEY (policy) REFERENCES public.compute_placement_policies(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.compute_placement_zones\n ADD CONSTRAINT compute_placement_zones_domain_fkey FOREIGN KEY (domain) REFERENCES public.compute_placement_domains(uuid) ON DELETE RESTRICT", + "ALTER TABLE ONLY public.compute_ports\n ADD CONSTRAINT compute_ports_machine_fkey FOREIGN KEY (machine) REFERENCES public.machines(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.compute_ports\n ADD CONSTRAINT compute_ports_node_fkey FOREIGN KEY (node) REFERENCES public.nodes(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.compute_ports\n ADD CONSTRAINT compute_ports_subnet_fkey FOREIGN KEY (subnet) REFERENCES public.compute_subnets(uuid) ON DELETE RESTRICT", + "ALTER TABLE ONLY public.compute_subnets\n ADD CONSTRAINT compute_subnets_network_fkey FOREIGN KEY (network) REFERENCES public.compute_networks(uuid) ON DELETE RESTRICT", + "ALTER TABLE ONLY public.dns_domainmetadata\n ADD CONSTRAINT dns_domainmetadata_domain_id_fkey FOREIGN KEY (domain_id) REFERENCES public.dns_domains(id) ON DELETE CASCADE", + "ALTER TABLE ONLY public.dns_records\n ADD CONSTRAINT dns_records_domain_fkey FOREIGN KEY (domain) REFERENCES public.dns_domains(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.dns_records\n ADD CONSTRAINT dns_records_domain_id_fkey FOREIGN KEY (domain_id) REFERENCES public.dns_domains(id) ON DELETE RESTRICT", + "ALTER TABLE ONLY public.em_elements\n ADD CONSTRAINT em_elements_manifest_fkey FOREIGN KEY (manifest) REFERENCES public.em_manifests(uuid) ON DELETE RESTRICT", + "ALTER TABLE ONLY public.em_elements\n ADD CONSTRAINT em_elements_profile_fkey FOREIGN KEY (profile) REFERENCES public.vs_profiles(uuid) ON DELETE RESTRICT", + "ALTER TABLE ONLY public.em_exports\n ADD CONSTRAINT em_exports_element_fkey FOREIGN KEY (element) REFERENCES public.em_elements(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.em_imports\n ADD CONSTRAINT em_imports_element_fkey FOREIGN KEY (element) REFERENCES public.em_elements(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.em_imports\n ADD CONSTRAINT em_imports_from_element_fkey FOREIGN KEY (from_element) REFERENCES public.em_elements(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.em_imports\n ADD CONSTRAINT em_imports_from_resource_fkey FOREIGN KEY (from_resource) REFERENCES public.em_resources(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.em_resources\n ADD CONSTRAINT em_resources_actual_resource_fkey FOREIGN KEY (actual_resource) REFERENCES public.ua_actual_resources(res_uuid) ON DELETE SET NULL", + "ALTER TABLE ONLY public.em_resources\n ADD CONSTRAINT em_resources_element_fkey FOREIGN KEY (element) REFERENCES public.em_elements(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.em_resources\n ADD CONSTRAINT em_resources_target_resource_fkey FOREIGN KEY (target_resource) REFERENCES public.ua_target_resources(res_uuid)", + "ALTER TABLE ONLY public.iam_binding_permissions\n ADD CONSTRAINT iam_binding_permissions_permission_fkey FOREIGN KEY (permission) REFERENCES public.iam_permissions(uuid)", + "ALTER TABLE ONLY public.iam_binding_permissions\n ADD CONSTRAINT iam_binding_permissions_role_fkey FOREIGN KEY (role) REFERENCES public.iam_roles(uuid)", + "ALTER TABLE ONLY public.iam_binding_roles\n ADD CONSTRAINT iam_binding_roles_project_fkey FOREIGN KEY (project) REFERENCES public.iam_projects(uuid)", + "ALTER TABLE ONLY public.iam_binding_roles\n ADD CONSTRAINT iam_binding_roles_role_fkey FOREIGN KEY (role) REFERENCES public.iam_roles(uuid)", + 'ALTER TABLE ONLY public.iam_binding_roles\n ADD CONSTRAINT iam_binding_roles_user_fkey FOREIGN KEY ("user") REFERENCES public.iam_users(uuid)', + "ALTER TABLE ONLY public.iam_idp_authorization_info\n ADD CONSTRAINT iam_idp_authorization_info_idp_fkey FOREIGN KEY (idp) REFERENCES public.iam_idp(uuid)", + "ALTER TABLE ONLY public.iam_idp_authorization_info\n ADD CONSTRAINT iam_idp_authorization_info_token_fkey FOREIGN KEY (token) REFERENCES public.iam_tokens(uuid)", + "ALTER TABLE ONLY public.iam_idp\n ADD CONSTRAINT iam_idp_iam_client_fkey FOREIGN KEY (iam_client) REFERENCES public.iam_clients(uuid) ON UPDATE RESTRICT ON DELETE RESTRICT", + "ALTER TABLE ONLY public.iam_organization_members\n ADD CONSTRAINT iam_organization_members_organization_fkey FOREIGN KEY (organization) REFERENCES public.iam_organizations(uuid) ON UPDATE CASCADE ON DELETE CASCADE", + 'ALTER TABLE ONLY public.iam_organization_members\n ADD CONSTRAINT iam_organization_members_user_fkey FOREIGN KEY ("user") REFERENCES public.iam_users(uuid) ON UPDATE CASCADE ON DELETE CASCADE', + "ALTER TABLE ONLY public.iam_projects\n ADD CONSTRAINT iam_projects_organization_fkey FOREIGN KEY (organization) REFERENCES public.iam_organizations(uuid)", + "ALTER TABLE ONLY public.iam_tokens\n ADD CONSTRAINT iam_tokens_iam_client_fkey FOREIGN KEY (iam_client) REFERENCES public.iam_clients(uuid) ON UPDATE CASCADE ON DELETE CASCADE", + "ALTER TABLE ONLY public.iam_tokens\n ADD CONSTRAINT iam_tokens_project_fkey FOREIGN KEY (project) REFERENCES public.iam_projects(uuid) ON UPDATE CASCADE ON DELETE CASCADE", + 'ALTER TABLE ONLY public.iam_tokens\n ADD CONSTRAINT iam_tokens_user_fkey FOREIGN KEY ("user") REFERENCES public.iam_users(uuid) ON UPDATE CASCADE ON DELETE CASCADE', + "ALTER TABLE ONLY public.iam_users\n ADD CONSTRAINT iam_users_registration_client_fkey FOREIGN KEY (registration_client) REFERENCES public.iam_clients(uuid) ON DELETE SET NULL", + "ALTER TABLE ONLY public.machines\n ADD CONSTRAINT machines_node_fkey FOREIGN KEY (node) REFERENCES public.nodes(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.machines\n ADD CONSTRAINT machines_pool_fkey FOREIGN KEY (pool) REFERENCES public.machine_pools(uuid) ON DELETE SET NULL", + "ALTER TABLE ONLY public.n_machine_pool_reservations\n ADD CONSTRAINT n_machine_pool_reservations_machine_fkey FOREIGN KEY (machine) REFERENCES public.machines(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.n_machine_pool_reservations\n ADD CONSTRAINT n_machine_pool_reservations_pool_fkey FOREIGN KEY (pool) REFERENCES public.machine_pools(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.net_lb_backendpools\n ADD CONSTRAINT net_lb_backendpools_parent_fkey FOREIGN KEY (parent) REFERENCES public.net_lb(uuid)", + "ALTER TABLE ONLY public.net_lb_vhosts\n ADD CONSTRAINT net_lb_vhosts_parent_fkey FOREIGN KEY (parent) REFERENCES public.net_lb(uuid)", + "ALTER TABLE ONLY public.net_lb_vhosts_routes\n ADD CONSTRAINT net_lb_vhosts_routes_parent_fkey FOREIGN KEY (parent) REFERENCES public.net_lb_vhosts(uuid)", + "ALTER TABLE ONLY public.node_volumes\n ADD CONSTRAINT node_volumes_node_fkey FOREIGN KEY (node) REFERENCES public.nodes(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.node_volumes\n ADD CONSTRAINT node_volumes_pool_fkey FOREIGN KEY (pool) REFERENCES public.machine_pools(uuid) ON DELETE SET NULL", + "ALTER TABLE ONLY public.nodes\n ADD CONSTRAINT nodes_node_set_fkey FOREIGN KEY (node_set) REFERENCES public.compute_sets(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.repo_artifacts\n ADD CONSTRAINT repo_artifacts_element_fkey FOREIGN KEY (element) REFERENCES public.repo_elements(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.repo_element_deps_bindings\n ADD CONSTRAINT repo_element_deps_bindings_depends_on_fkey FOREIGN KEY (depends_on) REFERENCES public.repo_elements(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.repo_element_deps_bindings\n ADD CONSTRAINT repo_element_deps_bindings_element_fkey FOREIGN KEY (element) REFERENCES public.repo_elements(uuid) ON DELETE CASCADE", + "ALTER TABLE ONLY public.repo_elements\n ADD CONSTRAINT repo_elements_element_fkey FOREIGN KEY (element) REFERENCES public.em_elements(uuid) ON DELETE SET NULL", + "ALTER TABLE ONLY public.repo_elements\n ADD CONSTRAINT repo_elements_repository_fkey FOREIGN KEY (repository) REFERENCES public.repo_repositories(uuid) ON DELETE RESTRICT", + "ALTER TABLE ONLY public.vs_values\n ADD CONSTRAINT vs_values_variable_fkey FOREIGN KEY (variable) REFERENCES public.vs_variables(uuid) ON DELETE SET NULL", + "CREATE OR REPLACE VIEW public.compute_hw_nodes_without_ports AS\n SELECT nodes.uuid,\n nodes.uuid AS node,\n machines.uuid AS machine,\n compute_net_interfaces.uuid AS iface\n FROM (((public.nodes\n LEFT JOIN public.machines ON ((nodes.uuid = machines.node)))\n LEFT JOIN public.compute_net_interfaces ON ((compute_net_interfaces.machine = machines.uuid)))\n LEFT JOIN public.compute_ports ON ((compute_ports.node = nodes.uuid)))\n WHERE (((nodes.node_type)::text = 'HW'::text) AND (machines.uuid IS NOT NULL) AND (compute_net_interfaces.ipv4 IS NOT NULL) AND (compute_ports.uuid IS NULL))", + "CREATE OR REPLACE VIEW public.compute_nodes_without_ports AS\n SELECT nodes.uuid,\n nodes.project_id,\n nodes.name,\n nodes.description,\n nodes.cores,\n nodes.ram,\n nodes.node_type,\n nodes.status,\n nodes.created_at,\n nodes.updated_at,\n nodes.default_network,\n nodes.node_set,\n nodes.placement_policies,\n nodes.disk_spec,\n nodes.hostname\n FROM (public.nodes\n LEFT JOIN public.compute_ports ports ON ((nodes.uuid = ports.node)))\n WHERE (ports.uuid IS NULL)", + "CREATE OR REPLACE VIEW public.compute_unscheduled_volumes AS\n SELECT node_volumes.uuid,\n node_volumes.uuid AS volume\n FROM (public.node_volumes\n LEFT JOIN public.compute_machine_volumes ON ((node_volumes.uuid = compute_machine_volumes.node_volume)))\n WHERE (compute_machine_volumes.uuid IS NULL)", + "CREATE OR REPLACE VIEW public.domainmetadata AS\n SELECT id,\n domain_id,\n kind,\n content\n FROM public.dns_domainmetadata", + "CREATE OR REPLACE VIEW public.domains AS\n SELECT id,\n name,\n master,\n last_check,\n type,\n notified_serial,\n account,\n options,\n catalog\n FROM public.dns_domains", + """CREATE OR REPLACE VIEW public.em_incorrect_resource_statuses_view AS +SELECT + er.uuid, + er.status AS current_status, + ( + CASE + WHEN utr.hash IS NULL THEN uar.status + WHEN uar.status = 'ACTIVE' AND utr.hash = uar.hash THEN 'ACTIVE' + WHEN uar.status IS NULL THEN NULL + ELSE 'IN_PROGRESS' + END + )::varchar(32) AS actual_status +FROM public.em_resources er +LEFT JOIN ( + SELECT uuid, hash + FROM public.ua_target_resources + WHERE kind LIKE 'em_%' +) utr ON er.uuid = utr.uuid +LEFT JOIN ( + SELECT uuid, status, hash + FROM public.ua_actual_resources + WHERE kind LIKE 'em_%' +) uar ON er.uuid = uar.uuid +WHERE er.status IS DISTINCT FROM ( + CASE + WHEN utr.hash IS NULL THEN uar.status + WHEN uar.status = 'ACTIVE' AND utr.hash = uar.hash THEN 'ACTIVE' + WHEN uar.status IS NULL THEN NULL + ELSE 'IN_PROGRESS' + END +)::varchar(32)""", + "CREATE OR REPLACE VIEW public.em_incorrect_statuses_view AS\n WITH em_incorrect_resource_statuses AS (\n WITH tmp AS (\n SELECT em_resources.element,\n bool_or(((em_resources.status)::text = 'IN_PROGRESS'::text)) AS has_in_progress,\n bool_and(((em_resources.status)::text = 'ACTIVE'::text)) AS all_active,\n bool_and(((em_resources.status)::text = 'NEW'::text)) AS all_new,\n count(*) AS resources_count\n FROM public.em_resources\n GROUP BY em_resources.element\n )\n SELECT e.uuid,\n e.name,\n e.status AS api_status,\n CASE\n WHEN (tmp.resources_count IS NULL) THEN 'ACTIVE'::text\n WHEN tmp.has_in_progress THEN 'IN_PROGRESS'::text\n WHEN tmp.all_active THEN 'ACTIVE'::text\n WHEN tmp.all_new THEN 'NEW'::text\n ELSE 'IN_PROGRESS'::text\n END AS actual_status\n FROM (public.em_elements e\n LEFT JOIN tmp tmp ON ((e.uuid = tmp.element)))\n )\n SELECT uuid,\n name,\n api_status,\n actual_status\n FROM em_incorrect_resource_statuses eis\n WHERE ((api_status)::text <> actual_status)", + "CREATE OR REPLACE VIEW public.em_outdated_resources_view AS\n SELECT COALESCE(er.uuid, utr.uuid) AS uuid,\n er.uuid AS em_resource,\n utr.res_uuid AS target_resource\n FROM (public.em_resources er\n FULL JOIN ( SELECT ua_target_resources.uuid,\n ua_target_resources.res_uuid,\n ua_target_resources.updated_at,\n ua_target_resources.tracked_at\n FROM public.ua_target_resources\n WHERE ((ua_target_resources.kind)::text ~~ 'em_%'::text)) utr ON ((er.uuid = utr.uuid)))\n WHERE ((er.uuid IS NULL) OR (utr.uuid IS NULL) OR (er.updated_at <> utr.tracked_at))", + 'CREATE OR REPLACE VIEW public.iam_permissions_fast_view AS\n SELECT t1.uuid,\n t1.uuid AS permission,\n t4.uuid AS "user",\n t3.uuid AS role,\n t3.project\n FROM (((public.iam_permissions t1\n LEFT JOIN public.iam_binding_permissions t2 ON ((t2.permission = t1.uuid)))\n LEFT JOIN public.iam_binding_roles t3 ON ((t3.role = t2.role)))\n LEFT JOIN public.iam_users t4 ON ((t4.uuid = t3."user")))', + "CREATE OR REPLACE VIEW public.netboots AS\n SELECT firmware_uuid AS uuid,\n boot\n FROM public.machines", + "CREATE OR REPLACE VIEW public.records AS\n SELECT domain_id,\n name,\n type,\n content,\n ttl,\n prio,\n disabled,\n ordername,\n auth\n FROM public.dns_records", + "CREATE OR REPLACE VIEW public.unscheduled_nodes AS\n SELECT nodes.uuid,\n nodes.uuid AS node\n FROM (public.nodes\n LEFT JOIN public.machines ON ((nodes.uuid = machines.node)))\n WHERE (machines.uuid IS NULL)", +) +VIEWS = ( + "compute_hw_nodes_without_ports", + "compute_nodes_without_ports", + "compute_unscheduled_volumes", + "domainmetadata", + "domains", + "em_incorrect_resource_statuses_view", + "em_incorrect_statuses_view", + "em_outdated_resources_view", + "iam_permissions_fast_view", + "netboots", + "records", + "unscheduled_nodes", +) +TABLES = ( + "compute_net_interfaces", + "compute_ports", + "machines", + "nodes", + "compute_machine_volumes", + "compute_networks", + "compute_placement_domains", + "compute_placement_policies", + "compute_placement_policy_allocations", + "compute_placement_zones", + "compute_sets", + "compute_subnets", + "node_volumes", + "config_configs", + "dns_domainmetadata", + "dns_domains", + "dns_records", + "em_elements", + "em_exports", + "em_imports", + "em_resources", + "em_manifests", + "em_services", + "gcl_sdk_audit_logs", + "gcl_sdk_events", + "iam_binding_permissions", + "iam_binding_roles", + "iam_clients", + "iam_idp", + "iam_idp_authorization_info", + "iam_organization_members", + "iam_organizations", + "iam_permissions", + "iam_users", + "iam_projects", + "iam_roles", + "iam_tokens", + "machine_pools", + "n_builders", + "n_machine_pool_reservations", + "net_border", + "net_lb", + "net_lb_backendpools", + "net_lb_vhosts", + "net_lb_vhosts_routes", + "repo_artifacts", + "repo_element_deps_bindings", + "repo_elements", + "repo_repositories", + "secret_certificates", + "secret_passwords", + "secret_rsa_keys", + "secret_ssh_keys", + "security_rules", + "storage_certs", + "storage_passwords", + "vs_profiles", + "vs_values", + "vs_variables", + "quota_limits", +) +SEQUENCES = ( + "dns_domain_id_seq", + "dns_domainmetadata_id_seq", +) +TYPES = ( + "enum_agent_status", + "enum_config_status", + "enum_secret_status", + "enum_service_status", + "enum_service_target_status", + "user_type_enum", +) + + +INDEX_STATEMENTS = ( + "CREATE UNIQUE INDEX IF NOT EXISTS compute_net_interfaces_mac_machine_id_idx ON public.compute_net_interfaces USING btree (mac, machine)", + "CREATE INDEX IF NOT EXISTS compute_net_interfaces_machine_id_idx ON public.compute_net_interfaces USING btree (machine)", + "CREATE INDEX IF NOT EXISTS compute_networks_project_id_idx ON public.compute_networks USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS machines_project_id_idx ON public.machines USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS nodes_project_id_idx ON public.nodes USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS node_volumes_project_id_idx ON public.node_volumes USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS compute_placement_policies_domain_idx ON public.compute_placement_policies USING btree (domain)", + "CREATE INDEX IF NOT EXISTS compute_placement_policies_project_id_idx ON public.compute_placement_policies USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS compute_placement_policies_zone_idx ON public.compute_placement_policies USING btree (zone)", + "CREATE INDEX IF NOT EXISTS compute_placement_policy_allocations_node_idx ON public.compute_placement_policy_allocations USING btree (node)", + "CREATE INDEX IF NOT EXISTS compute_placement_policy_allocations_policy_idx ON public.compute_placement_policy_allocations USING btree (policy)", + "CREATE INDEX IF NOT EXISTS compute_placement_zones_domain_idx ON public.compute_placement_zones USING btree (domain)", + "CREATE UNIQUE INDEX IF NOT EXISTS compute_ports_mac_subnet_id_idx ON public.compute_ports USING btree (mac, subnet)", + "CREATE INDEX IF NOT EXISTS compute_ports_node_id_idx ON public.compute_ports USING btree (node)", + "CREATE INDEX IF NOT EXISTS compute_ports_project_id_idx ON public.compute_ports USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS compute_ports_subnet_id_idx ON public.compute_ports USING btree (subnet)", + "CREATE UNIQUE INDEX IF NOT EXISTS compute_ports_target_ipv4_subnet_id_idx ON public.compute_ports USING btree (target_ipv4, subnet)", + "CREATE INDEX IF NOT EXISTS compute_sets_project_id_idx ON public.compute_sets USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS compute_subnets_network_id_idx ON public.compute_subnets USING btree (network)", + "CREATE INDEX IF NOT EXISTS compute_subnets_project_id_idx ON public.compute_subnets USING btree (project_id)", + "CREATE UNIQUE INDEX IF NOT EXISTS config_configs_path_target_id_idx ON public.config_configs USING btree (path, target)", + "CREATE UNIQUE INDEX IF NOT EXISTS quota_limits_project_resource_field_name_idx ON quota_limits (project_id, resource_name, field_name)", + "CREATE INDEX IF NOT EXISTS config_configs_project_id_idx ON public.config_configs USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS dns_domainmetadata_domain_id_idx ON public.dns_domainmetadata USING btree (domain_id)", + "CREATE INDEX IF NOT EXISTS dns_domains_catalog_idx ON public.dns_domains USING btree (catalog)", + "CREATE UNIQUE INDEX IF NOT EXISTS dns_domains_id_idx ON public.dns_domains USING btree (id)", + "CREATE UNIQUE INDEX IF NOT EXISTS dns_domains_name_idx ON public.dns_domains USING btree (name)", + "CREATE INDEX IF NOT EXISTS dns_domains_project_id_name_idx ON public.dns_domains USING btree (project_id, name)", + "CREATE INDEX IF NOT EXISTS dns_records_project_id_idx ON public.dns_records USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS dns_records_updated_at_idx ON public.dns_records USING btree (updated_at)", + "CREATE INDEX IF NOT EXISTS domain_id ON public.dns_records USING btree (domain_id)", + "CREATE INDEX IF NOT EXISTS em_exports_element_idx ON public.em_exports USING btree (element)", + "CREATE INDEX IF NOT EXISTS em_imports_element_idx ON public.em_imports USING btree (element)", + "CREATE INDEX IF NOT EXISTS em_resources_element_idx ON public.em_resources USING btree (element)", + "CREATE UNIQUE INDEX IF NOT EXISTS em_services_path_target_id_idx ON public.em_services USING btree (path, target)", + "CREATE INDEX IF NOT EXISTS em_services_project_id_idx ON public.em_services USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS em_elements_project_id_idx ON public.em_elements USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS em_manifests_project_id_idx ON public.em_manifests USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS gcl_sdk_audit_logs_object_type_action_idx ON public.gcl_sdk_audit_logs USING btree (object_type, action)", + "CREATE INDEX IF NOT EXISTS iam_binding_permissions_role_permission_idx ON public.iam_binding_permissions USING btree (role, permission)", + "CREATE INDEX IF NOT EXISTS iam_binding_permissions_project_id_idx ON public.iam_binding_permissions USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS iam_binding_roles_project_idx ON public.iam_binding_roles USING btree (project)", + "CREATE INDEX IF NOT EXISTS iam_binding_roles_role_idx ON public.iam_binding_roles USING btree (role)", + 'CREATE INDEX IF NOT EXISTS iam_binding_roles_user_idx ON public.iam_binding_roles USING btree ("user")', + "CREATE UNIQUE INDEX IF NOT EXISTS iam_client_id_idx ON public.iam_clients USING btree (client_id)", + "CREATE INDEX IF NOT EXISTS iam_clients_project_id_idx ON public.iam_clients USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS iam_idp_project_id_idx ON public.iam_idp USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS iam_organizations_name_idx ON public.iam_organizations USING btree (name)", + "CREATE UNIQUE INDEX IF NOT EXISTS iam_permissions_name_idx ON public.iam_permissions USING btree (name)", + "CREATE INDEX IF NOT EXISTS iam_projects_name_idx ON public.iam_projects USING btree (name)", + "CREATE INDEX IF NOT EXISTS iam_projects_organization_idx ON public.iam_projects USING btree (organization)", + "CREATE INDEX IF NOT EXISTS iam_roles_name_idx ON public.iam_roles USING btree (name)", + "CREATE INDEX IF NOT EXISTS iam_roles_project_id_idx ON public.iam_roles USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS iam_tokens_iam_client_idx ON public.iam_tokens USING btree (iam_client)", + "CREATE UNIQUE INDEX IF NOT EXISTS iam_users_email_lower_idx ON public.iam_users USING btree (lower((email)::text))", + "CREATE UNIQUE INDEX IF NOT EXISTS iam_users_name_lower_idx ON public.iam_users USING btree (lower((name)::text))", + "CREATE INDEX IF NOT EXISTS idx_compute_machine_volumes_machine ON public.compute_machine_volumes USING btree (machine)", + "CREATE INDEX IF NOT EXISTS idx_compute_machine_volumes_node_volume ON public.compute_machine_volumes USING btree (node_volume)", + "CREATE INDEX IF NOT EXISTS idx_compute_machine_volumes_pool ON public.compute_machine_volumes USING btree (pool)", + "CREATE INDEX IF NOT EXISTS idx_compute_machine_volumes_project_id ON public.compute_machine_volumes USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS nametype_index ON public.dns_records USING btree (name, type)", + "CREATE INDEX IF NOT EXISTS net_border_project_id_name_idx ON public.net_border USING btree (project_id, name)", + "CREATE INDEX IF NOT EXISTS net_lb_backendpools_parent_name_idx ON public.net_lb_backendpools USING btree (parent, name)", + "CREATE INDEX IF NOT EXISTS net_lb_backendpools_project_id_idx ON public.net_lb_backendpools USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS net_lb_project_id_name_idx ON public.net_lb USING btree (project_id, name)", + "CREATE INDEX IF NOT EXISTS net_lb_vhosts_parent_name_idx ON public.net_lb_vhosts USING btree (parent, name)", + "CREATE INDEX IF NOT EXISTS net_lb_vhosts_parent_port_domains_idx ON public.net_lb_vhosts USING btree (parent, port, domains)", + "CREATE INDEX IF NOT EXISTS net_lb_vhosts_project_id_idx ON public.net_lb_vhosts USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS net_lb_vhosts_routes_parent_name_idx ON public.net_lb_vhosts_routes USING btree (parent, name)", + "CREATE INDEX IF NOT EXISTS net_lb_vhosts_routes_project_id_idx ON public.net_lb_vhosts_routes USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS rec_name_index ON public.dns_records USING btree (name)", + "CREATE INDEX IF NOT EXISTS recordorder ON public.dns_records USING btree (domain_id, ordername text_pattern_ops)", + "CREATE INDEX IF NOT EXISTS repo_artifacts_element_idx ON public.repo_artifacts USING btree (element)", + "CREATE UNIQUE INDEX IF NOT EXISTS repo_artifacts_element_urn_idx ON public.repo_artifacts USING btree (element, urn)", + "CREATE INDEX IF NOT EXISTS repo_artifacts_project_id_idx ON public.repo_artifacts USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS repo_element_deps_bindings_depends_on_idx ON public.repo_element_deps_bindings USING btree (depends_on)", + "CREATE UNIQUE INDEX IF NOT EXISTS repo_element_deps_bindings_element_depends_on_idx ON public.repo_element_deps_bindings USING btree (element, depends_on)", + "CREATE INDEX IF NOT EXISTS repo_element_deps_bindings_element_idx ON public.repo_element_deps_bindings USING btree (element)", + "CREATE INDEX IF NOT EXISTS repo_elements_installation_state_idx ON public.repo_elements USING btree (installation_state)", + "CREATE INDEX IF NOT EXISTS repo_elements_name_idx ON public.repo_elements USING btree (name)", + "CREATE INDEX IF NOT EXISTS repo_elements_name_installation_state_idx ON public.repo_elements USING btree (name, installation_state)", + "CREATE INDEX IF NOT EXISTS repo_elements_project_id_idx ON public.repo_elements USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS repo_elements_repository_idx ON public.repo_elements USING btree (repository)", + "CREATE UNIQUE INDEX IF NOT EXISTS repo_elements_repository_name_version_idx ON public.repo_elements USING btree (repository, name, version)", + "CREATE INDEX IF NOT EXISTS repo_elements_status_idx ON public.repo_elements USING btree (status)", + "CREATE UNIQUE INDEX IF NOT EXISTS repo_repositories_driver_spec_idx ON public.repo_repositories USING btree (driver_spec)", + "CREATE INDEX IF NOT EXISTS repo_repositories_project_id_idx ON public.repo_repositories USING btree (project_id)", + "CREATE UNIQUE INDEX IF NOT EXISTS repo_repositories_project_id_name_idx ON public.repo_repositories USING btree (project_id, name)", + "CREATE INDEX IF NOT EXISTS repo_repositories_status_idx ON public.repo_repositories USING btree (status)", + "CREATE INDEX IF NOT EXISTS secret_certificates_project_id_idx ON public.secret_certificates USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS secret_passwords_project_id_idx ON public.secret_passwords USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS secret_rsa_keys_project_id_idx ON public.secret_rsa_keys USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS secret_ssh_keys_project_id_idx ON public.secret_ssh_keys USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS security_rules_name_idx ON public.security_rules USING btree (name)", + "CREATE INDEX IF NOT EXISTS security_rules_project_id_idx ON public.security_rules USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS vs_profiles_profile_type_idx ON public.vs_profiles USING btree (profile_type)", + "CREATE INDEX IF NOT EXISTS vs_profiles_project_id_idx ON public.vs_profiles USING btree (project_id)", + "CREATE UNIQUE INDEX IF NOT EXISTS vs_values_one_manual_selected_per_variable ON public.vs_values USING btree (variable) WHERE (manual_selected = true)", + "CREATE INDEX IF NOT EXISTS vs_values_project_id_idx ON public.vs_values USING btree (project_id)", + "CREATE INDEX IF NOT EXISTS vs_variables_project_id_idx ON public.vs_variables USING btree (project_id)", +) + + +class MigrationStep(migrations.AbstractMigrationStep): + def __init__(self): + self._depends = ["0000-root-d34de1.py"] + + @property + def migration_id(self): + return "7f2e4a90-3c6d-45ed-9da3-e1f8b2a7c619" + + @property + def is_manual(self): + return False + + def upgrade(self, session): + for statement in SCHEMA_STATEMENTS + INDEX_STATEMENTS: + if statement.startswith("CREATE TYPE public."): + type_name = statement.split()[2].removeprefix("public.") + existing_type = session.execute( + f"SELECT 1 FROM pg_catalog.pg_type WHERE typname = '{type_name}'", + None, + ) + if existing_type.rowcount: + continue + if statement.startswith("CREATE TABLE public."): + table_name = statement.split()[2].removeprefix("public.") + existing_table = session.execute( + f"SELECT to_regclass('public.{table_name}')", None + ) + if existing_table.fetchone()["to_regclass"] is not None: + continue + if "ADD CONSTRAINT" in statement: + table_name = statement.split()[3].removeprefix("public.") + constraint_name = statement.split("ADD CONSTRAINT ", 1)[1].split()[0] + existing_constraint = session.execute( + "SELECT 1 FROM pg_catalog.pg_constraint AS pg_constraint " + "JOIN pg_catalog.pg_class AS pg_class " + "ON pg_class.oid = pg_constraint.conrelid " + f"WHERE pg_constraint.conname = '{constraint_name}' " + f"AND pg_class.relname = '{table_name}'", + None, + ) + if existing_constraint.rowcount: + continue + session.execute(statement, None) + self._upgrade_data(session) + + def downgrade(self, session): + for view in VIEWS: + session.execute(f"DROP VIEW IF EXISTS public.{view} CASCADE", None) + for table in TABLES: + session.execute(f"DROP TABLE IF EXISTS public.{table} CASCADE", None) + for sequence in SEQUENCES: + session.execute(f"DROP SEQUENCE IF EXISTS public.{sequence} CASCADE", None) + for type_name in TYPES: + if type_name != "enum_agent_status": + session.execute(f"DROP TYPE IF EXISTS public.{type_name} CASCADE", None) + + def _upgrade_data(self, session): + self._upgrade_bootstrap_admin_data(session) + self._upgrade_default_org_and_roles(session) + self._upgrade_iam_core(session) + self._upgrade_compute(session) + self._upgrade_iam_resource_permissions(session) + self._upgrade_dns(session) + self._upgrade_compute_node_set(session) + self._upgrade_org_members(session) + self._upgrade_secret_password(session) + self._upgrade_network_lb(session) + self._upgrade_service_token(session) + self._upgrade_iam_user_create(session) + self._upgrade_repo_permissions(session) + self._upgrade_border_permissions(session) + + def _downgrade_data(self, session): + self._downgrade_border_permissions(session) + self._downgrade_repo_permissions(session) + self._downgrade_iam_user_create(session) + self._downgrade_service_token(session) + self._downgrade_network_lb(session) + self._downgrade_secret_password(session) + self._downgrade_org_members(session) + self._downgrade_compute_node_set(session) + self._downgrade_dns(session) + self._downgrade_iam_resource_permissions(session) + self._downgrade_compute(session) + self._downgrade_iam_core(session) + self._downgrade_default_org_and_roles(session) + self._downgrade_bootstrap_admin_data(session) + + # ------------------------------------------------------------------ + # Bootstrap admin data + # ------------------------------------------------------------------ + + def _upgrade_bootstrap_admin_data(self, session): + default_admin_salt = "d4JJ9QYuEEJxHCFja9FZskG4" + default_client_secret = os.getenv("DEFAULT_CLIENT_SECRET", "GenesisCoreSecret") + global_salt = os.getenv("GLOBAL_SALT", "FOy/2kwwdn0ig1QOq7cestqe") + default_admin_secret = _generate_hash( + secret=os.getenv("ADMIN_PASSWORD", "admin"), + secret_salt=default_admin_salt, + global_salt=global_salt, + ) + default_client_secret_hash = _generate_hash( + secret=default_client_secret, + secret_salt=default_admin_salt, + global_salt=global_salt, + ) + statements = [ + # Admin user + f"""INSERT INTO "iam_users" ( + "uuid", "name", "description", "first_name", "last_name", + "email", "secret_hash", "salt" + ) VALUES ( + '00000000-0000-0000-0000-000000000000', + 'admin', + 'System administrator', + 'Admin', + 'User', + 'admin@example.com', + '{default_admin_secret}', + '{default_admin_salt}' + ) ON CONFLICT (uuid) DO NOTHING;""", + # Admin organization + """INSERT INTO "iam_organizations" ( + "uuid", "name", "description" + ) VALUES ( + '00000000-0000-0000-0000-000000000000', + 'admin', 'Admin Organization' + ) ON CONFLICT (uuid) DO NOTHING;""", + # Admin project + """INSERT INTO "iam_projects" ( + "uuid", "name", description, organization + ) VALUES ( + '00000000-0000-0000-0000-000000000000', + 'admin', 'Admin Project', + '00000000-0000-0000-0000-000000000000' + ) ON CONFLICT (uuid) DO NOTHING;""", + # Admin role + """INSERT INTO "iam_roles" ( + "uuid", "name", "description" + ) VALUES ( + '00000000-0000-0000-0000-000000000000', + 'admin', 'Admin Role' + ) ON CONFLICT (uuid) DO NOTHING;""", + # Wildcard permission + """INSERT INTO "iam_permissions" ( + "uuid", "name", "description" + ) VALUES ( + '00000000-0000-0000-0000-000000000000', + '*.*.*', 'Allow All' + ) ON CONFLICT (uuid) DO NOTHING;""", + # Admin binding permission + """INSERT INTO "iam_binding_permissions" ( + "uuid", "role", "permission" + ) VALUES ( + '00000000-0000-0000-0000-000000000000', + '00000000-0000-0000-0000-000000000000', + '00000000-0000-0000-0000-000000000000' + ) ON CONFLICT (uuid) DO NOTHING;""", + # Admin role binding + """INSERT INTO "iam_binding_roles" ( + "uuid", "user", "role", "description" + ) VALUES ( + '00000000-0000-0000-0000-000000000000', + '00000000-0000-0000-0000-000000000000', + '00000000-0000-0000-0000-000000000000', + 'Super Administrator' + ) ON CONFLICT (uuid) DO NOTHING;""", + # Default IAM client + f"""INSERT INTO "iam_clients" ( + "uuid", "name", "description", "client_id", + "secret_hash", "salt" + ) VALUES( + '{DEFAULT_IAM_CLIENT_UUID}', + 'GenesisCoreClient', + 'Exordos Core OIDC Client', + 'GenesisCoreClientId', + '{default_client_secret_hash}', + '{default_admin_salt}' + ) ON CONFLICT (uuid) DO NOTHING;""", + ] + for stmt in statements: + session.execute(stmt) + + def _downgrade_bootstrap_admin_data(self, session): + statements = [ + # Delete all binding permissions for bindings referencing admin + "DELETE FROM iam_binding_permissions WHERE role IN (SELECT uuid FROM iam_binding_roles WHERE \"user\" = '00000000-0000-0000-0000-000000000000');", + # Delete ALL role bindings referencing admin user (catches test-created ones) + "DELETE FROM iam_binding_roles WHERE \"user\" = '00000000-0000-0000-0000-000000000000';", + # Bootstrap data cleanup + # f"DELETE FROM iam_clients WHERE uuid = '{DEFAULT_IAM_CLIENT_UUID}';", + "DELETE FROM iam_binding_permissions WHERE uuid = '00000000-0000-0000-0000-000000000000';", + "DELETE FROM iam_permissions WHERE uuid = '00000000-0000-0000-0000-000000000000';", + "DELETE FROM iam_roles WHERE uuid = '00000000-0000-0000-0000-000000000000';", + "DELETE FROM iam_projects WHERE uuid = '00000000-0000-0000-0000-000000000000';", + "DELETE FROM iam_organizations WHERE uuid = '00000000-0000-0000-0000-000000000000';", + "DELETE FROM iam_users WHERE uuid = '00000000-0000-0000-0000-000000000000';", + ] + for stmt in statements: + session.execute(stmt) + + # ------------------------------------------------------------------ + # Default organisation and roles (Genesis Corporation, newcomer, owner) + # ------------------------------------------------------------------ + + def _upgrade_default_org_and_roles(self, session): + statements = [ + f"""INSERT INTO "iam_organizations" ( + "uuid", "name", "description" + ) VALUES ( + '{EXORDOS_CORE_ORGANIZATION_ID}', + '{EXORDOS_CORE_ORGANIZATION_NAME}', + '{EXORDOS_CORE_ORGANIZATION_DESCRIPTION}' + ) ON CONFLICT (uuid) DO NOTHING;""", + f"""INSERT INTO "iam_roles" ( + "uuid", "name", "description", "project_id" + ) VALUES ( + '{NEWCOMER_ROLE_UUID}', + '{NEWCOMER_ROLE_NAME}', + '{NEWCOMER_ROLE_DESCRIPTION}', + NULL + ) ON CONFLICT (uuid) DO NOTHING;""", + f"""INSERT INTO "iam_roles" ( + "uuid", "name", "description", "project_id" + ) VALUES ( + '{OWNER_ROLE_UUID}', + '{OWNER_ROLE_NAME}', + '{OWNER_ROLE_DESCRIPTION}', + NULL + ) ON CONFLICT (uuid) DO NOTHING;""", + ] + for stmt in statements: + session.execute(stmt) + + def _downgrade_default_org_and_roles(self, session): + statements = [ + f"DELETE FROM iam_binding_permissions WHERE role = '{NEWCOMER_ROLE_UUID}';", + f"DELETE FROM iam_binding_permissions WHERE role = '{OWNER_ROLE_UUID}';", + f"DELETE FROM iam_binding_roles WHERE role = '{NEWCOMER_ROLE_UUID}';", + f"DELETE FROM iam_binding_roles WHERE role = '{OWNER_ROLE_UUID}';", + f"DELETE FROM iam_roles WHERE uuid = '{NEWCOMER_ROLE_UUID}';", + f"DELETE FROM iam_roles WHERE uuid = '{OWNER_ROLE_UUID}';", + f"DELETE FROM iam_organizations WHERE uuid = '{EXORDOS_CORE_ORGANIZATION_ID}';", + ] + for stmt in statements: + session.execute(stmt) + + # ------------------------------------------------------------------ + # Core IAM permissions, project, and newcomer bindings (m0008) + # ------------------------------------------------------------------ + + def _upgrade_iam_core(self, session): + iam_permissions = [ + (USER_LIST, "Allows listing users in the system"), + (USER_READ_ALL, "Allows reading all user profiles"), + (USER_WRITE_ALL, "Allows modifying any user`s data"), + (USER_DELETE_ALL, "Allows deleting any user account"), + (USER_DELETE, "Allows users to delete their own account"), + (ORG_CREATE, "Allows creating new organizations"), + (ORG_READ_ALL, "Allows viewing all organization details"), + (ORG_WRITE_ALL, "Allows modifying any organization`s data"), + (ORG_DELETE, "Allows deleting own organization"), + (ORG_DELETE_ALL, "Allows deleting any organization"), + ] + for name, description in iam_permissions: + session.execute(f""" + INSERT INTO iam_permissions ( + uuid, name, description + ) VALUES ( + '{PERMISSION_UUIDS[name]}', + '{name}', + '{description}' + ) ON CONFLICT (uuid) DO NOTHING; + """) + session.execute(f""" + INSERT INTO iam_projects ( + uuid, name, description, organization + ) VALUES ( + '{IAM_PROJECT_UUID}', + 'iam-core', + 'Identity and Access Management Core Project', + '{EXORDOS_CORE_ORGANIZATION_ID}' + ) ON CONFLICT (uuid) DO NOTHING; + """) + for perm_name in [USER_DELETE, ORG_CREATE, ORG_DELETE]: + session.execute(f""" + INSERT INTO iam_binding_permissions ( + uuid, role, permission, project_id + ) VALUES ( + gen_random_uuid(), + '{NEWCOMER_ROLE_UUID}', + '{PERMISSION_UUIDS[perm_name]}', + '{IAM_PROJECT_UUID}' + ); + """) + + def _downgrade_iam_core(self, session): + for permission_uuid in PERMISSION_UUIDS.values(): + session.execute(f""" + DELETE FROM iam_binding_permissions + WHERE permission = '{permission_uuid}'; + """) + session.execute(f""" + DELETE FROM iam_projects + WHERE uuid = '{IAM_PROJECT_UUID}'; + """) + for permission_uuid in PERMISSION_UUIDS.values(): + session.execute(f""" + DELETE FROM iam_permissions + WHERE uuid = '{permission_uuid}'; + """) + + # ------------------------------------------------------------------ + # Compute permissions, project, and owner bindings (m0012) + # ------------------------------------------------------------------ + + def _upgrade_compute(self, session): + for name, description in COMPUTE_NODE_DEF_PERMISSIONS: + session.execute(f""" + INSERT INTO iam_permissions ( + uuid, name, description + ) VALUES ( + '{_u(name)}', + '{name}', + '{description}' + ) ON CONFLICT (uuid) DO NOTHING; + """) + session.execute(f""" + INSERT INTO iam_projects ( + uuid, name, description, organization + ) VALUES ( + '{COMPUTE_PROJECT_UUID}', + 'compute-core', + 'Compute and Baremetal Core Project', + '{EXORDOS_CORE_ORGANIZATION_ID}' + ) ON CONFLICT (uuid) DO NOTHING; + """) + for name, _ in COMPUTE_NODE_DEF_PERMISSIONS: + session.execute(f""" + INSERT INTO iam_binding_permissions ( + uuid, role, permission, project_id + ) VALUES ( + gen_random_uuid(), + '{OWNER_ROLE_UUID}', + '{_u(name)}', + '{COMPUTE_PROJECT_UUID}' + ); + """) + + def _downgrade_compute(self, session): + for name, _ in COMPUTE_NODE_DEF_PERMISSIONS: + session.execute(f""" + DELETE FROM iam_binding_permissions + WHERE permission = '{_u(name)}'; + """) + session.execute(f""" + DELETE FROM iam_projects + WHERE uuid = '{COMPUTE_PROJECT_UUID}'; + """) + for name, _ in COMPUTE_NODE_DEF_PERMISSIONS: + session.execute(f""" + DELETE FROM iam_permissions + WHERE uuid = '{_u(name)}'; + """) + + # ------------------------------------------------------------------ + # Full IAM resource permissions (m0016) + # ------------------------------------------------------------------ + + def _upgrade_iam_resource_permissions(self, session): + iam_resource_permissions = [ + (PERMISSION_PROJECT_LIST_ALL, "Allows listing projects in the system"), + (PERMISSION_PROJECT_READ_ALL, "Allows reading all project details"), + (PERMISSION_PROJECT_WRITE_ALL, "Allows modifying any project`s data"), + (PERMISSION_PROJECT_DELETE_ALL, "Allows deleting any project"), + (PERMISSION_PERMISSION_CREATE, "Allows creating new permissions"), + (PERMISSION_PERMISSION_READ, "Allows reading permissions"), + (PERMISSION_PERMISSION_UPDATE, "Allows updating existing permissions"), + (PERMISSION_PERMISSION_DELETE, "Allows deleting permissions"), + ( + PERMISSION_PERMISSION_BINDING_CREATE, + "Allows creating permission bindings", + ), + (PERMISSION_PERMISSION_BINDING_READ, "Allows reading permission bindings"), + ( + PERMISSION_PERMISSION_BINDING_UPDATE, + "Allows updating permission bindings", + ), + ( + PERMISSION_PERMISSION_BINDING_DELETE, + "Allows deleting permission bindings", + ), + (PERMISSION_ROLE_CREATE, "Allows creating new roles"), + (PERMISSION_ROLE_READ, "Allows reading roles"), + (PERMISSION_ROLE_UPDATE, "Allows updating existing roles"), + (PERMISSION_ROLE_DELETE, "Allows deleting roles"), + (PERMISSION_ROLE_BINDING_CREATE, "Allows creating role bindings"), + (PERMISSION_ROLE_BINDING_READ, "Allows reading role bindings"), + (PERMISSION_ROLE_BINDING_UPDATE, "Allows updating role bindings"), + (PERMISSION_ROLE_BINDING_DELETE, "Allows deleting role bindings"), + (PERMISSION_IAM_CLIENT_CREATE, "Allows creating IAM clients"), + (PERMISSION_IAM_CLIENT_READ_ALL, "Allows reading all IAM clients"), + (PERMISSION_IAM_CLIENT_UPDATE, "Allows updating IAM clients"), + (PERMISSION_IAM_CLIENT_DELETE, "Allows deleting IAM clients"), + ] + for name, description in iam_resource_permissions: + session.execute(f""" + INSERT INTO iam_permissions ( + uuid, name, description + ) VALUES ( + '{PERMISSION_UUIDS[name]}', + '{name}', + '{description}' + ) ON CONFLICT (uuid) DO NOTHING; + """) + + def _downgrade_iam_resource_permissions(self, session): + iam_resource_permission_names = [ + PERMISSION_PROJECT_LIST_ALL, + PERMISSION_PROJECT_READ_ALL, + PERMISSION_PROJECT_WRITE_ALL, + PERMISSION_PROJECT_DELETE_ALL, + PERMISSION_PERMISSION_CREATE, + PERMISSION_PERMISSION_READ, + PERMISSION_PERMISSION_UPDATE, + PERMISSION_PERMISSION_DELETE, + PERMISSION_PERMISSION_BINDING_CREATE, + PERMISSION_PERMISSION_BINDING_READ, + PERMISSION_PERMISSION_BINDING_UPDATE, + PERMISSION_PERMISSION_BINDING_DELETE, + PERMISSION_ROLE_CREATE, + PERMISSION_ROLE_READ, + PERMISSION_ROLE_UPDATE, + PERMISSION_ROLE_DELETE, + PERMISSION_ROLE_BINDING_CREATE, + PERMISSION_ROLE_BINDING_READ, + PERMISSION_ROLE_BINDING_UPDATE, + PERMISSION_ROLE_BINDING_DELETE, + PERMISSION_IAM_CLIENT_CREATE, + PERMISSION_IAM_CLIENT_READ_ALL, + PERMISSION_IAM_CLIENT_UPDATE, + PERMISSION_IAM_CLIENT_DELETE, + ] + for name in iam_resource_permission_names: + session.execute(f""" + DELETE FROM iam_binding_permissions + WHERE permission = '{PERMISSION_UUIDS[name]}'; + """) + for name in iam_resource_permission_names: + session.execute(f""" + DELETE FROM iam_permissions + WHERE uuid = '{PERMISSION_UUIDS[name]}'; + """) + + # ------------------------------------------------------------------ + # DNS permissions, project, and owner bindings (m0021) + # ------------------------------------------------------------------ + + def _upgrade_dns(self, session): + for name, description in DNS_NODE_DEF_PERMISSIONS: + session.execute(f""" + INSERT INTO iam_permissions ( + uuid, name, description + ) VALUES ( + '{_u(name)}', + '{name}', + '{description}' + ) ON CONFLICT (uuid) DO NOTHING; + """) + session.execute(f""" + INSERT INTO iam_projects ( + uuid, name, description, organization + ) VALUES ( + '{DNS_PROJECT_UUID}', + 'dns-core', + 'Dns Core Project', + '{EXORDOS_CORE_ORGANIZATION_ID}' + ) ON CONFLICT (uuid) DO NOTHING; + """) + for name, _ in DNS_NODE_DEF_PERMISSIONS: + session.execute(f""" + INSERT INTO iam_binding_permissions ( + uuid, role, permission, project_id + ) VALUES ( + gen_random_uuid(), + '{OWNER_ROLE_UUID}', + '{_u(name)}', + '{DNS_PROJECT_UUID}' + ); + """) + + def _downgrade_dns(self, session): + for name, _ in DNS_NODE_DEF_PERMISSIONS: + session.execute(f""" + DELETE FROM iam_binding_permissions + WHERE permission = '{_u(name)}'; + """) + session.execute(f""" + DELETE FROM iam_projects + WHERE uuid = '{DNS_PROJECT_UUID}'; + """) + for name, _ in DNS_NODE_DEF_PERMISSIONS: + session.execute(f""" + DELETE FROM iam_permissions + WHERE uuid = '{_u(name)}'; + """) + + # ------------------------------------------------------------------ + # Compute node set permissions and bindings (m0031) + # ------------------------------------------------------------------ + + def _upgrade_compute_node_set(self, session): + for name, description in COMPUTE_NODE_SET_DEF_PERMISSIONS: + session.execute(f""" + INSERT INTO iam_permissions ( + uuid, name, description + ) VALUES ( + '{_u(name)}', + '{name}', + '{description}' + ) ON CONFLICT (uuid) DO NOTHING; + """) + for name, _ in COMPUTE_NODE_SET_DEF_PERMISSIONS: + session.execute(f""" + INSERT INTO iam_binding_permissions ( + uuid, role, permission, project_id + ) VALUES ( + '{_u("binding." + name)}', + '{OWNER_ROLE_UUID}', + '{_u(name)}', + '{COMPUTE_PROJECT_UUID}' + ) ON CONFLICT (uuid) DO NOTHING; + """) + + def _downgrade_compute_node_set(self, session): + for name, _ in COMPUTE_NODE_SET_DEF_PERMISSIONS: + session.execute(f""" + DELETE FROM iam_binding_permissions + WHERE permission = '{_u(name)}'; + """) + for name, _ in COMPUTE_NODE_SET_DEF_PERMISSIONS: + session.execute(f""" + DELETE FROM iam_permissions + WHERE uuid = '{_u(name)}'; + """) + + # ------------------------------------------------------------------ + # Organization member for admin user (m0003) + # ------------------------------------------------------------------ + + def _upgrade_org_members(self, session): + session.execute(""" + INSERT INTO "iam_organization_members" ( + "uuid", + "organization", + "user", + "role", + "created_at", + "updated_at" + ) + SELECT + gen_random_uuid(), + o."uuid", + '00000000-0000-0000-0000-000000000000', + 'OWNER', + o."created_at", + o."updated_at" + FROM "iam_organizations" o + ON CONFLICT ("organization", "user") DO NOTHING; + """) + + def _downgrade_org_members(self, session): + session.execute(""" + DELETE FROM "iam_organization_members" + WHERE "user" = '00000000-0000-0000-0000-000000000000'; + """) + + # ------------------------------------------------------------------ + # Default HS256 secret password (m0039) + # ------------------------------------------------------------------ + + def _upgrade_secret_password(self, session): + session.execute(""" + INSERT INTO "secret_passwords" ( + "uuid", + "name", + "description", + "project_id", + "constructor", + "method", + "value", + "status" + ) VALUES ( + '00000000-0000-0000-0000-000000000001', + 'iam-client-hs256-secret', + 'Default HS256 secret for IAM clients', + '00000000-0000-0000-0000-000000000000', + '{"kind": "plain"}'::jsonb, + 'MANUAL', + 'secret', + 'ACTIVE' + ) ON CONFLICT ("uuid") DO NOTHING; + """) + session.execute( + """ + UPDATE "iam_tokens" + SET "iam_client" = %s + WHERE "iam_client" IS NULL; + """, + (DEFAULT_IAM_CLIENT_UUID,), + ) + + def _downgrade_secret_password(self, session): + session.execute(""" + DELETE FROM "secret_passwords" + WHERE "uuid" = '00000000-0000-0000-0000-000000000001'; + """) + + # ------------------------------------------------------------------ + # Network LB permissions and bindings (m0053) + # ------------------------------------------------------------------ + + def _upgrade_network_lb(self, session): + for name, description in NETWORK_LB_PERMISSIONS: + session.execute(f""" + INSERT INTO iam_permissions ( + uuid, name, description + ) VALUES ( + '{_u(name)}', + '{name}', + '{description}' + ) ON CONFLICT (uuid) DO NOTHING; + """) + for name, _ in NETWORK_LB_PERMISSIONS: + session.execute(f""" + INSERT INTO iam_binding_permissions ( + uuid, role, permission, project_id + ) VALUES ( + '{_u("binding." + name)}', + '{OWNER_ROLE_UUID}', + '{_u(name)}', + '{COMPUTE_PROJECT_UUID}' + ) ON CONFLICT (uuid) DO NOTHING; + """) + + def _downgrade_network_lb(self, session): + for name, _ in NETWORK_LB_PERMISSIONS: + session.execute(f""" + DELETE FROM iam_binding_permissions + WHERE permission = '{_u(name)}'; + """) + for name, _ in NETWORK_LB_PERMISSIONS: + session.execute(f""" + DELETE FROM iam_permissions + WHERE uuid = '{_u(name)}'; + """) + + # ------------------------------------------------------------------ + # Service token permission and binding (m0055) + # ------------------------------------------------------------------ + + def _upgrade_service_token(self, session): + for name, description in SERVICE_TOKEN_PERMISSIONS: + session.execute(f""" + INSERT INTO iam_permissions ( + uuid, name, description + ) VALUES ( + '{_u(name)}', + '{name}', + '{description}' + ) ON CONFLICT (uuid) DO NOTHING; + """) + for name, _ in SERVICE_TOKEN_PERMISSIONS: + session.execute(f""" + INSERT INTO iam_binding_permissions ( + uuid, role, permission, project_id + ) VALUES ( + gen_random_uuid(), + '{OWNER_ROLE_UUID}', + '{_u(name)}', + NULL + ); + """) + + def _downgrade_service_token(self, session): + for name, _ in SERVICE_TOKEN_PERMISSIONS: + session.execute(f""" + DELETE FROM iam_binding_permissions + WHERE permission = '{_u(name)}'; + """) + for name, _ in SERVICE_TOKEN_PERMISSIONS: + session.execute(f""" + DELETE FROM iam_permissions + WHERE uuid = '{_u(name)}'; + """) + + # ------------------------------------------------------------------ + # IAM user create permission (m0056) + # ------------------------------------------------------------------ + + def _upgrade_iam_user_create(self, session): + for name, description in IAM_USER_PERMISSIONS: + session.execute(f""" + INSERT INTO iam_permissions ( + uuid, name, description + ) VALUES ( + '{_u(name)}', + '{name}', + '{description}' + ) ON CONFLICT (uuid) DO NOTHING; + """) + + def _downgrade_iam_user_create(self, session): + for name, _ in IAM_USER_PERMISSIONS: + session.execute(f""" + DELETE FROM iam_binding_permissions + WHERE permission = '{_u(name)}'; + """) + for name, _ in IAM_USER_PERMISSIONS: + session.execute(f""" + DELETE FROM iam_permissions + WHERE uuid = '{_u(name)}'; + """) + + def _upgrade_repo_permissions(self, session): + for name, description in REPO_PERMISSIONS: + session.execute( + f""" + INSERT INTO iam_permissions (uuid, name, description) + VALUES ('{_u(name)}', '{name}', '{description}') + ON CONFLICT (uuid) DO NOTHING; + """, + None, + ) + session.execute( + f""" + INSERT INTO iam_binding_permissions (uuid, role, permission, project_id) + VALUES ( + '{_u("binding." + name)}', '{OWNER_ROLE_UUID}', + '{_u(name)}', '{COMPUTE_PROJECT_UUID}' + ) ON CONFLICT (uuid) DO NOTHING; + """, + None, + ) + + def _downgrade_repo_permissions(self, session): + for name, _ in REPO_PERMISSIONS: + session.execute( + f"DELETE FROM iam_binding_permissions WHERE permission = '{_u(name)}'", + None, + ) + session.execute( + f"DELETE FROM iam_permissions WHERE uuid = '{_u(name)}'", None + ) + + def _upgrade_actual_resources(self, session): + expressions = [ + """ + INSERT INTO ua_actual_resources ( + uuid, + kind, + res_uuid, + value, + status, + node, + hash, + full_hash, + created_at, + updated_at + ) + SELECT + uuid, + kind, + res_uuid, + value, + status, + node, + hash, + full_hash, + created_at, + updated_at + FROM ua_target_resources + WHERE kind = 'em_core_iam_users' + ON CONFLICT (res_uuid) DO NOTHING; + """, + ] + + for expression in expressions: + session.execute(expression) + + def _downgrade_actual_resources(self, session): + expressions = [ + """ + DELETE FROM ua_actual_resources + WHERE kind = 'em_core_iam_users'; + """, + ] + + for expression in expressions: + session.execute(expression) + + def _upgrade_border_permissions(self, session): + permissions = ( + ("network.border.read", "List and read borders (NAT gateways)"), + ("network.border.create", "Create borders (NAT gateways)"), + ("network.border.update", "Update borders (NAT gateways)"), + ("network.border.delete", "Delete borders (NAT gateways)"), + ) + for name, description in permissions: + session.execute( + f""" + INSERT INTO iam_permissions (uuid, name, description) + VALUES ('{_u(name)}', '{name}', '{description}') + ON CONFLICT (uuid) DO NOTHING; + """, + None, + ) + session.execute( + f""" + INSERT INTO iam_binding_permissions (uuid, role, permission, project_id) + VALUES ('{_u("binding." + name)}', '{OWNER_ROLE_UUID}', + '{_u(name)}', '{COMPUTE_PROJECT_UUID}') + ON CONFLICT (uuid) DO NOTHING; + """, + None, + ) + + def _downgrade_border_permissions(self, session): + for name in ( + "network.border.read", + "network.border.create", + "network.border.update", + "network.border.delete", + ): + session.execute( + f"DELETE FROM iam_binding_permissions WHERE permission = '{_u(name)}'", + None, + ) + session.execute( + f"DELETE FROM iam_permissions WHERE uuid = '{_u(name)}'", None + ) + + +migration_step = MigrationStep() diff --git a/migrations/0001-init-all-tables-f47bad.py b/migrations/0001-init-all-tables-f47bad.py deleted file mode 100644 index 89c990df..00000000 --- a/migrations/0001-init-all-tables-f47bad.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = [ - "0000-init-iam-tables-9c9153.py", - "0000-init-discovery-tables-907a68.py", - "0000-init-values-and-profiles-tables-0a61dc.py", - "0000-init-config-tables-9a7b58.py", - "0000-init-elements-tables-fe8bdb.py", - "0000-init-compute-tables-0234eb.py", - ] - - @property - def migration_id(self): - return "f47bad9c-ff07-47bc-9112-9b4761c318d6" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - pass - - def downgrade(self, session): - pass - - -migration_step = MigrationStep() diff --git a/migrations/0002-add-volumes-tables-a6972c.py b/migrations/0002-add-volumes-tables-a6972c.py deleted file mode 100644 index 4dd1db6f..00000000 --- a/migrations/0002-add-volumes-tables-a6972c.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - -from exordos_core.compute import constants as nc - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0001-init-all-tables-f47bad.py"] - - @property - def migration_id(self): - return "a6972cd6-1cca-43a5-b8f7-47ead0af3eb9" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - sql_expressions = [ - # TABLES - f""" - ALTER TABLE nodes - ADD IF NOT EXISTS root_disk_size INTEGER NULL DEFAULT {nc.DEF_ROOT_DISK_SIZE}; - """, - """ - CREATE TABLE IF NOT EXISTS node_volumes ( - uuid UUID NOT NULL PRIMARY KEY, - project_id UUID NOT NULL, - name varchar(255) NOT NULL, - description varchar(255) NOT NULL, - node UUID references nodes(uuid) ON DELETE CASCADE, - size integer NOT NULL, - boot bool NOT NULL DEFAULT true, - label varchar(127) NULL, - device_type VARCHAR(16) NOT NULL CHECK (device_type IN ('QCOW2')), - created_at timestamp NOT NULL DEFAULT current_timestamp, - updated_at timestamp NOT NULL DEFAULT current_timestamp - ); - """, - # VIEWS - """ - CREATE OR REPLACE VIEW unscheduled_nodes AS - SELECT - nodes.uuid, - nodes.project_id, - nodes.name, - nodes.description, - nodes.cores, - nodes.ram, - nodes.image, - nodes.node_type, - nodes.status, - nodes.created_at, - nodes.updated_at, - nodes.root_disk_size - FROM nodes LEFT JOIN machines ON - nodes.uuid = machines.node WHERE machines.uuid is NULL; - """, - """ - CREATE OR REPLACE VIEW machine_volumes AS - SELECT - node_volumes.uuid, - node_volumes.project_id, - node_volumes.name, - node_volumes.description, - node_volumes.node, - node_volumes.size, - node_volumes.boot, - node_volumes.label, - node_volumes.device_type, - machines.uuid as machine, - node_volumes.created_at, - node_volumes.updated_at - FROM node_volumes LEFT JOIN machines ON - node_volumes.node = machines.node; - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - def downgrade(self, session): - tables = [ - "node_volumes", - ] - views = [ - "machine_volumes", - ] - - for view_name in views: - self._delete_view_if_exists(session, view_name) - - for table_name in tables: - self._delete_table_if_exists(session, table_name) - - -migration_step = MigrationStep() diff --git a/migrations/0003-Organization-Roles-4b584d.py b/migrations/0003-Organization-Roles-4b584d.py deleted file mode 100644 index c22c5b9c..00000000 --- a/migrations/0003-Organization-Roles-4b584d.py +++ /dev/null @@ -1,139 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0002-add-volumes-tables-a6972c.py"] - - @property - def migration_id(self): - return "4b584d08-3345-44f3-8f90-b3caafc7a206" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - CREATE TABLE IF NOT EXISTS "iam_organization_members" ( - "uuid" UUID PRIMARY KEY, - "organization" UUID NOT NULL REFERENCES - "iam_organizations" ("uuid") - ON DELETE CASCADE - ON UPDATE CASCADE, - "user" UUID NOT NULL REFERENCES "iam_users" ("uuid") - ON DELETE CASCADE - ON UPDATE CASCADE, - "role" VARCHAR(20) NOT NULL DEFAULT 'MEMBER' - CHECK (role IN ('OWNER', 'MEMBER')), - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - CONSTRAINT uq_organization_user UNIQUE ( - "organization", "user" - ) - ); - """, - """ - INSERT INTO "iam_organization_members" ( - "uuid", - "organization", - "user", - "role", - "created_at", - "updated_at" - ) - SELECT - gen_random_uuid(), - o."uuid", - o."owner", - 'OWNER', - o."created_at", - o."updated_at" - FROM "iam_organizations" o; - """, - """ - ALTER TABLE "iam_organizations" DROP COLUMN "owner"; - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """ - ALTER TABLE "iam_organizations" - ADD COLUMN "owner" UUID; - """, - """ - UPDATE - "iam_organizations" o - SET "owner" = ( - SELECT m."user" - FROM "iam_organization_members" m - WHERE - m."organization" = o."uuid" - AND m."role" = 'OWNER' - LIMIT 1 - ); - """, - # Organizations without an owner member (e.g. the owner user was - # deleted) cannot be represented in the old schema, where owner - # is NOT NULL. Fall back to any member, then to the oldest user. - """ - UPDATE - "iam_organizations" o - SET "owner" = ( - SELECT m."user" - FROM "iam_organization_members" m - WHERE m."organization" = o."uuid" - LIMIT 1 - ) - WHERE o."owner" IS NULL; - """, - """ - UPDATE - "iam_organizations" o - SET "owner" = ( - SELECT u."uuid" - FROM "iam_users" u - ORDER BY u."created_at" - LIMIT 1 - ) - WHERE o."owner" IS NULL; - """, - """ - ALTER TABLE "iam_organizations" - ALTER COLUMN "owner" SET NOT NULL; - """, - ] - - for expression in expressions: - session.execute(expression) - - drop_tables = [ - "iam_organization_members", - ] - - for table in drop_tables: - self._delete_table_if_exists(session, table) - - -migration_step = MigrationStep() diff --git a/migrations/0004-fix_typoes-31d9b2.py b/migrations/0004-fix_typoes-31d9b2.py deleted file mode 100644 index 76d623f3..00000000 --- a/migrations/0004-fix_typoes-31d9b2.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0003-Organization-Roles-4b584d.py"] - - @property - def migration_id(self): - return "31d9b221-7af4-4bef-b769-c793e4eb1da0" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """\ - ALTER TABLE iam_tokens - RENAME COLUMN experation_at TO expiration_at; - """, - """\ - ALTER TABLE iam_tokens - RENAME COLUMN refresh_experation_at TO refresh_expiration_at; - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """\ - ALTER TABLE iam_tokens - RENAME COLUMN expiration_at TO experation_at; - """, - """\ - ALTER TABLE iam_tokens - RENAME COLUMN refresh_expiration_at TO refresh_experation_at; - """, - ] - - for expression in expressions: - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0005-add-organization-info-4fac91.py b/migrations/0005-add-organization-info-4fac91.py deleted file mode 100644 index d24c03a2..00000000 --- a/migrations/0005-add-organization-info-4fac91.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0004-fix_typoes-31d9b2.py"] - - @property - def migration_id(self): - return "4fac917a-1229-4428-a535-bed607dbf558" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - ALTER TABLE "iam_organizations" - ADD COLUMN "info" VARCHAR(2048) DEFAULT '{}'; - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """ - ALTER TABLE "iam_organizations" - DROP COLUMN "info"; - """, - ] - - for expression in expressions: - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0006-add-gc-organization-678510.py b/migrations/0006-add-gc-organization-678510.py deleted file mode 100644 index c4d4e6bc..00000000 --- a/migrations/0006-add-gc-organization-678510.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2025 Genesis Corporation -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - -# NOTE(efrolov): copy-pasted from constants. Migration should have the -# same values for autonomous working. -# Exordos Core Organization and Project Information -EXORDOS_CORE_ORGANIZATION_ID = "11111111-1111-1111-1111-111111111111" -EXORDOS_CORE_ORGANIZATION_NAME = "Genesis Corporation" -EXORDOS_CORE_ORGANIZATION_DESCRIPTION = ( - "The organization serves as the central platform for all services" - " and elements developed by Genesis Corporation." -) - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0005-add-organization-info-4fac91.py"] - - @property - def migration_id(self): - return "678510e9-1e83-4270-9cfc-ce5c5d09f960" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - insert_query = f""" - INSERT INTO "iam_organizations" ( - "uuid", "name", "description" - ) VALUES ( - '{EXORDOS_CORE_ORGANIZATION_ID}', - '{EXORDOS_CORE_ORGANIZATION_NAME}', - '{EXORDOS_CORE_ORGANIZATION_DESCRIPTION}' - ); - """ - session.execute(insert_query) - - def downgrade(self, session): - delete_query = f""" - DELETE FROM "iam_organizations" - WHERE "uuid" = '{EXORDOS_CORE_ORGANIZATION_ID}'; - """ - session.execute(delete_query) - - -migration_step = MigrationStep() diff --git a/migrations/0007-add-default-roles-73f4c4.py b/migrations/0007-add-default-roles-73f4c4.py deleted file mode 100644 index 0f086bea..00000000 --- a/migrations/0007-add-default-roles-73f4c4.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - -NEWCOMER_ROLE_UUID = "726f6c65-0000-0000-0000-000000000001" -NEWCOMER_ROLE_NAME = "newcomer" -NEWCOMER_ROLE_DESCRIPTION = ( - "Default role for newly registered users. Provides basic system access " - "and onboarding capabilities." -) - -OWNER_ROLE_UUID = "726f6c65-0000-0000-0000-000000000002" -OWNER_ROLE_NAME = "owner" -OWNER_ROLE_DESCRIPTION = ( - "Project ownership role. Grants full administrative privileges " - "within a specific project. Automatically assigned during project " - "creation process." -) - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0006-add-gc-organization-678510.py"] - - @property - def migration_id(self): - return "73f4c423-b617-4269-b9f2-6115050c8b6c" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - insert_queries = [ - f""" - INSERT INTO "iam_roles" ( - "uuid", "name", "description", "project_id" - ) VALUES ( - '{NEWCOMER_ROLE_UUID}', - '{NEWCOMER_ROLE_NAME}', - '{NEWCOMER_ROLE_DESCRIPTION}', - NULL - ); - """, - f""" - INSERT INTO "iam_roles" ( - "uuid", "name", "description", "project_id" - ) VALUES ( - '{OWNER_ROLE_UUID}', - '{OWNER_ROLE_NAME}', - '{OWNER_ROLE_DESCRIPTION}', - NULL - ); - """, - ] - - for query in insert_queries: - session.execute(query) - - def downgrade(self, session): - delete_queries = [ - f"DELETE FROM iam_binding_roles WHERE role = '{NEWCOMER_ROLE_UUID}';", - f"DELETE FROM iam_binding_roles WHERE role = '{OWNER_ROLE_UUID}';", - f"DELETE FROM iam_roles WHERE uuid = '{NEWCOMER_ROLE_UUID}';", - f"DELETE FROM iam_roles WHERE uuid = '{OWNER_ROLE_UUID}';", - ] - - for query in delete_queries: - session.execute(query) - - -migration_step = MigrationStep() diff --git a/migrations/0008-add-iam-permissions-d81bba.py b/migrations/0008-add-iam-permissions-d81bba.py deleted file mode 100644 index 79c8140d..00000000 --- a/migrations/0008-add-iam-permissions-d81bba.py +++ /dev/null @@ -1,169 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from restalchemy.storage.sql import migrations - -USER_LIST = "iam.user.list" -USER_READ_ALL = "iam.user.read_all" -USER_WRITE_ALL = "iam.user.write_all" -USER_DELETE_ALL = "iam.user.delete_all" -USER_DELETE = "iam.user.delete" - -ORG_CREATE = "iam.organization.create" -ORG_READ_ALL = "iam.organization.read_all" -ORG_WRITE_ALL = "iam.organization.write_all" -ORG_DELETE = "iam.organization.delete" -ORG_DELETE_ALL = "iam.organization.delete_all" - - -NAMESPACE_UUID = uuid.UUID("a6c4c7a8-b1d2-4e8f-9a3c-1d7e4f5a9b0c") - - -def generate_uuid(name): - return str(uuid.uuid5(NAMESPACE_UUID, name)) - - -PERMISSION_UUIDS = { - USER_LIST: generate_uuid(USER_LIST), - USER_READ_ALL: generate_uuid(USER_READ_ALL), - USER_WRITE_ALL: generate_uuid(USER_WRITE_ALL), - USER_DELETE_ALL: generate_uuid(USER_DELETE_ALL), - USER_DELETE: generate_uuid(USER_DELETE), - ORG_CREATE: generate_uuid(ORG_CREATE), - ORG_READ_ALL: generate_uuid(ORG_READ_ALL), - ORG_WRITE_ALL: generate_uuid(ORG_WRITE_ALL), - ORG_DELETE: generate_uuid(ORG_DELETE), - ORG_DELETE_ALL: generate_uuid(ORG_DELETE_ALL), -} - -EXORDOS_CORE_ORG_UUID = "11111111-1111-1111-1111-111111111111" -NEWCOMER_ROLE_UUID = "726f6c65-0000-0000-0000-000000000001" - -IAM_PROJECT_UUID = generate_uuid("GenesisCore-IAM-Project") - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0007-add-default-roles-73f4c4.py"] - - @property - def migration_id(self): - return "d81bba1e-eec5-44ba-b4f3-7a95e34bf1f7" - - @property - def is_manual(self): - return False - - def _create_permissions(self, session): - permissions = [ - # User permissions - (USER_LIST, "Allows listing users in the system"), - (USER_READ_ALL, "Allows reading all user profiles"), - (USER_WRITE_ALL, "Allows modifying any user`s data"), - (USER_DELETE_ALL, "Allows deleting any user account"), - ( - USER_DELETE, - "Allows users to delete their own account", - ), - # Organization permissions - (ORG_CREATE, "Allows creating new organizations"), - ( - ORG_READ_ALL, - "Allows viewing all organization details", - ), - ( - ORG_WRITE_ALL, - "Allows modifying any organization`s data", - ), - (ORG_DELETE, "Allows deleting own organization"), - (ORG_DELETE_ALL, "Allows deleting any organization"), - ] - - for name, description in permissions: - session.execute(f""" - INSERT INTO iam_permissions ( - uuid, name, description - ) VALUES ( - '{PERMISSION_UUIDS[name]}', - '{name}', - '{description}' - ) - ON CONFLICT (uuid) DO NOTHING; - """) - - def _create_iam_project(self, session): - session.execute(f""" - INSERT INTO iam_projects ( - uuid, name, description, organization - ) VALUES ( - '{IAM_PROJECT_UUID}', - 'iam-core', - 'Identity and Access Management Core Project', - '{EXORDOS_CORE_ORG_UUID}' - ) - ON CONFLICT (uuid) DO NOTHING; - """) - - def _create_bindings(self, session): - bind_permissions = [USER_DELETE, ORG_CREATE, ORG_DELETE] - - for perm_name in bind_permissions: - session.execute(f""" - INSERT INTO iam_binding_permissions ( - uuid, role, permission, project_id - ) VALUES ( - gen_random_uuid(), - '{NEWCOMER_ROLE_UUID}', - '{PERMISSION_UUIDS[perm_name]}', - '{IAM_PROJECT_UUID}' - ); - """) - - def upgrade(self, session): - self._create_permissions(session) - self._create_iam_project(session) - self._create_bindings(session) - - def _delete_bindings(self, session): - for permission_uuid in PERMISSION_UUIDS.values(): - session.execute(f""" - DELETE FROM iam_binding_permissions - WHERE - permission = '{permission_uuid}'; - """) - - def _delete_iam_project(self, session): - session.execute(f""" - DELETE FROM iam_projects - WHERE uuid = '{IAM_PROJECT_UUID}'; - """) - - def _delete_permissions(self, session): - for permission_uuid in PERMISSION_UUIDS.values(): - session.execute(f""" - DELETE FROM iam_permissions - WHERE uuid = '{permission_uuid}'; - """) - - def downgrade(self, session): - self._delete_bindings(session) - self._delete_iam_project(session) - self._delete_permissions(session) - - -migration_step = MigrationStep() diff --git a/migrations/0009-node-builder-entities-0d8f66.py b/migrations/0009-node-builder-entities-0d8f66.py deleted file mode 100644 index 60315880..00000000 --- a/migrations/0009-node-builder-entities-0d8f66.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0008-add-iam-permissions-d81bba.py"] - - @property - def migration_id(self): - return "0d8f66c9-ecb7-4821-92af-2d7adc931616" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - sql_expressions = [ - # TABLES - """ - CREATE TABLE IF NOT EXISTS n_builders ( - uuid UUID NOT NULL PRIMARY KEY, - status VARCHAR(32) NOT NULL CHECK (status IN ('ACTIVE', 'DISABLED')), - created_at timestamp NOT NULL DEFAULT current_timestamp, - updated_at timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE TABLE IF NOT EXISTS n_machine_pool_reservations ( - uuid UUID NOT NULL PRIMARY KEY, - cores integer NOT NULL, - ram integer NOT NULL, - pool UUID references machine_pools(uuid) ON DELETE CASCADE, - machine UUID references machines(uuid) ON DELETE CASCADE, - created_at timestamp NOT NULL DEFAULT current_timestamp, - updated_at timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - ALTER TABLE machines - ADD IF NOT EXISTS builder UUID references n_builders(uuid) ON DELETE SET NULL; - """, - """ - ALTER TABLE machines - ADD IF NOT EXISTS build_status VARCHAR(32) NOT NULL CHECK (build_status IN ('IN_BUILD', 'READY')) DEFAULT 'READY'; - """, - """ - ALTER TABLE machine_pools - ADD IF NOT EXISTS avail_cores integer NOT NULL DEFAULT 0; - """, - """ - ALTER TABLE machine_pools - ADD IF NOT EXISTS avail_ram integer NOT NULL DEFAULT 0; - """, - """ - ALTER TABLE machine_pools - ADD IF NOT EXISTS all_cores integer NOT NULL DEFAULT 0; - """, - """ - ALTER TABLE machine_pools - ADD IF NOT EXISTS all_ram integer NOT NULL DEFAULT 0; - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - def downgrade(self, session): - sql_expressions = [ - """ - ALTER TABLE machines - DROP COLUMN IF EXISTS builder; - """, - """ - ALTER TABLE machines - DROP COLUMN IF EXISTS build_status; - """, - """ - ALTER TABLE machine_pools - DROP COLUMN IF EXISTS avail_cores; - """, - """ - ALTER TABLE machine_pools - DROP COLUMN IF EXISTS avail_ram; - """, - """ - ALTER TABLE machine_pools - DROP COLUMN IF EXISTS all_cores; - """, - """ - ALTER TABLE machine_pools - DROP COLUMN IF EXISTS all_ram; - """, - ] - tables = [ - "n_builders", - "n_machine_pool_reservations", - ] - views = [] - - for expr in sql_expressions: - session.execute(expr, None) - - for view_name in views: - self._delete_view_if_exists(session, view_name) - - for table_name in tables: - self._delete_table_if_exists(session, table_name) - - -migration_step = MigrationStep() diff --git a/migrations/0010-image-for-machine-31471a.py b/migrations/0010-image-for-machine-31471a.py deleted file mode 100644 index 208b4f65..00000000 --- a/migrations/0010-image-for-machine-31471a.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0009-node-builder-entities-0d8f66.py"] - - @property - def migration_id(self): - return "31471a63-e61d-4fa6-8bec-bb555e0f38c3" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - sql_expressions = [ - """ - ALTER TABLE machines - ADD IF NOT EXISTS image varchar(255) NULL DEFAULT NULL; - """ - ] - - for expr in sql_expressions: - session.execute(expr, None) - - def downgrade(self, session): - sql_expressions = [ - """ - ALTER TABLE machines - DROP COLUMN IF EXISTS image; - """ - ] - - for expr in sql_expressions: - session.execute(expr, None) - - -migration_step = MigrationStep() diff --git a/migrations/0011-add-surname-and-phone-ea974b.py b/migrations/0011-add-surname-and-phone-ea974b.py deleted file mode 100644 index f1783aa8..00000000 --- a/migrations/0011-add-surname-and-phone-ea974b.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0010-image-for-machine-31471a.py"] - - @property - def migration_id(self): - return "ea974b0f-e5d0-4e17-8543-3770eca8df85" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - session.execute(""" - ALTER TABLE "iam_users" - ADD COLUMN surname VARCHAR(128) NOT NULL DEFAULT '' - """) - session.execute(""" - ALTER TABLE "iam_users" - ADD COLUMN phone VARCHAR(15) - """) - - def downgrade(self, session): - session.execute(""" - ALTER TABLE "iam_users" - DROP COLUMN surname - """) - session.execute(""" - ALTER TABLE "iam_users" - DROP COLUMN phone - """) - - -migration_step = MigrationStep() diff --git a/migrations/0012-compute-permissions-aac851.py b/migrations/0012-compute-permissions-aac851.py deleted file mode 100644 index 1c3da45e..00000000 --- a/migrations/0012-compute-permissions-aac851.py +++ /dev/null @@ -1,123 +0,0 @@ -# Copyright 2025 Genesis Corporation. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid as sys_uuid - -from restalchemy.storage.sql import migrations - -NS_UUID = sys_uuid.UUID("dfd0c604-607f-4260-981f-374f88435ea0") -EXORDOS_CORE_ORG_UUID = "11111111-1111-1111-1111-111111111111" -OWNER_ROLE_UUID = "726f6c65-0000-0000-0000-000000000002" - -COMPUTE_NODE_DEF_PERMISSIONS = ( - ("compute.node.read", "List and read own nodes"), - ("compute.node.create", "Create own nodes"), - ("compute.node.update", "Update own nodes"), - ("compute.node.delete", "Delete own nodes"), -) - - -def _u(name: str) -> str: - return str(sys_uuid.uuid5(NS_UUID, name)) - - -COMPUTE_PROJECT_UUID = _u("GenesisCore-Compute-Project") - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0011-add-surname-and-phone-ea974b.py"] - - @property - def migration_id(self): - return "aac8510e-9a0d-4db5-9a94-7bc8abff40e1" - - @property - def is_manual(self): - return False - - def _create_permissions(self, session): - for name, description in COMPUTE_NODE_DEF_PERMISSIONS: - session.execute(f""" - INSERT INTO iam_permissions ( - uuid, name, description - ) VALUES ( - '{_u(name)}', - '{name}', - '{description}' - ) - ON CONFLICT (uuid) DO NOTHING; - """) - - def _create_project(self, session): - session.execute(f""" - INSERT INTO iam_projects ( - uuid, name, description, organization - ) VALUES ( - '{COMPUTE_PROJECT_UUID}', - 'compute-core', - 'Comptue and Baremetal Core Project', - '{EXORDOS_CORE_ORG_UUID}' - ) - ON CONFLICT (uuid) DO NOTHING; - """) - - def _create_bindings(self, session): - for name, _ in COMPUTE_NODE_DEF_PERMISSIONS: - session.execute(f""" - INSERT INTO iam_binding_permissions ( - uuid, role, permission, project_id - ) VALUES ( - gen_random_uuid(), - '{OWNER_ROLE_UUID}', - '{_u(name)}', - '{COMPUTE_PROJECT_UUID}' - ); - """) - - def upgrade(self, session): - self._create_permissions(session) - self._create_project(session) - self._create_bindings(session) - - def _delete_bindings(self, session): - for name, _ in COMPUTE_NODE_DEF_PERMISSIONS: - session.execute(f""" - DELETE FROM iam_binding_permissions - WHERE - permission = '{_u(name)}'; - """) - - def _delete_project(self, session): - session.execute(f""" - DELETE FROM iam_projects - WHERE uuid = '{COMPUTE_PROJECT_UUID}'; - """) - - def _delete_permissions(self, session): - for name, _ in COMPUTE_NODE_DEF_PERMISSIONS: - session.execute(f""" - DELETE FROM iam_permissions - WHERE uuid = '{_u(name)}'; - """) - - def downgrade(self, session): - self._delete_bindings(session) - self._delete_project(session) - self._delete_permissions(session) - - -migration_step = MigrationStep() diff --git a/migrations/0013-add-ttl-to-token-2b8e3e.py b/migrations/0013-add-ttl-to-token-2b8e3e.py deleted file mode 100644 index f9a2366f..00000000 --- a/migrations/0013-add-ttl-to-token-2b8e3e.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0012-compute-permissions-aac851.py"] - - @property - def migration_id(self): - return "2b8e3e4d-6164-42ee-b0fe-3fd4d2c6dc81" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - session.execute(""" - ALTER TABLE "iam_tokens" - ADD COLUMN expiration_delta FLOAT NOT NULL - DEFAULT 900.0; - """) - session.execute(""" - ALTER TABLE "iam_tokens" - ADD COLUMN refresh_expiration_delta FLOAT NOT NULL - DEFAULT 86400.0; - """) - - def downgrade(self, session): - session.execute('ALTER TABLE "iam_tokens" DROP COLUMN expiration_delta;') - session.execute( - 'ALTER TABLE "iam_tokens" DROP COLUMN refresh_expiration_delta;' - ) - - -migration_step = MigrationStep() diff --git a/migrations/0014-network-ipam-067981.py b/migrations/0014-network-ipam-067981.py deleted file mode 100644 index 8bc09c79..00000000 --- a/migrations/0014-network-ipam-067981.py +++ /dev/null @@ -1,209 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0013-add-ttl-to-token-2b8e3e.py"] - - @property - def migration_id(self): - return "067981fb-487e-4ec7-8141-b84569af759b" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - sql_expressions = [ - # TABLES - """ - CREATE TABLE IF NOT EXISTS compute_networks ( - uuid UUID NOT NULL PRIMARY KEY, - name varchar(255) NOT NULL, - description varchar(255) NOT NULL, - project_id UUID NOT NULL, - driver_spec varchar(512) NOT NULL DEFAULT '{}', - created_at timestamp NOT NULL DEFAULT current_timestamp, - updated_at timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE INDEX IF NOT EXISTS compute_networks_project_id_idx - ON compute_networks (project_id); - """, - """ - CREATE TABLE IF NOT EXISTS compute_subnets ( - uuid UUID NOT NULL PRIMARY KEY, - name varchar(255) NOT NULL, - description varchar(255) NOT NULL, - project_id UUID NOT NULL, - network UUID references compute_networks(uuid) ON DELETE RESTRICT, - cidr varchar(18) NOT NULL, - ip_range varchar(31) NULL DEFAULT NULL, - dhcp boolean DEFAULT true, - dns_servers varchar(512) NOT NULL DEFAULT '{}', - routers varchar(512) NOT NULL DEFAULT '{}', - next_server varchar(256) NULL DEFAULT '127.0.0.1', - created_at timestamp NOT NULL DEFAULT current_timestamp, - updated_at timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE INDEX IF NOT EXISTS compute_subnets_project_id_idx - ON compute_subnets (project_id); - """, - """ - CREATE INDEX IF NOT EXISTS compute_subnets_network_id_idx - ON compute_subnets (network); - """, - """ - CREATE TABLE IF NOT EXISTS compute_ports ( - uuid UUID NOT NULL PRIMARY KEY, - name varchar(255) NOT NULL, - description varchar(255) NOT NULL, - project_id UUID NOT NULL, - subnet UUID references compute_subnets(uuid) ON DELETE RESTRICT, - node UUID references nodes(uuid) ON DELETE CASCADE, - machine UUID references machines(uuid) ON DELETE CASCADE, - interface varchar(32) NULL DEFAULT NULL, - target_ipv4 varchar(15) NULL DEFAULT NULL, - target_mask varchar(15) NULL DEFAULT NULL, - ipv4 varchar(15) NULL DEFAULT NULL, - mask varchar(15) NULL DEFAULT NULL, - mac varchar(17) NULL DEFAULT NULL, - status VARCHAR(32) NOT NULL CHECK (status IN ('NEW', 'IN_PROGRESS', 'ACTIVE', 'ERROR')), - created_at timestamp NOT NULL DEFAULT current_timestamp, - updated_at timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE INDEX IF NOT EXISTS compute_ports_project_id_idx - ON compute_ports (project_id); - """, - """ - CREATE INDEX IF NOT EXISTS compute_ports_subnet_id_idx - ON compute_ports (subnet); - """, - """ - CREATE INDEX IF NOT EXISTS compute_ports_node_id_idx - ON compute_ports (node); - """, - """ - CREATE UNIQUE INDEX IF NOT EXISTS compute_ports_target_ipv4_subnet_id_idx - ON compute_ports (target_ipv4, subnet); - """, - """ - CREATE UNIQUE INDEX IF NOT EXISTS compute_ports_mac_subnet_id_idx - ON compute_ports (mac, subnet); - """, - """ - ALTER TABLE nodes - ADD IF NOT EXISTS default_network varchar(255) NULL DEFAULT NULL; - """, - # VIEWS - """ - CREATE OR REPLACE VIEW unscheduled_nodes AS - SELECT - nodes.uuid, - nodes.project_id, - nodes.name, - nodes.description, - nodes.cores, - nodes.ram, - nodes.image, - nodes.node_type, - nodes.status, - nodes.created_at, - nodes.updated_at, - nodes.root_disk_size, - nodes.default_network - FROM nodes LEFT JOIN machines ON - nodes.uuid = machines.node WHERE machines.uuid is NULL; - """, - """ - CREATE OR REPLACE VIEW compute_nodes_without_ports AS - SELECT - nodes.uuid, - nodes.project_id, - nodes.name, - nodes.description, - nodes.cores, - nodes.ram, - nodes.image, - nodes.node_type, - nodes.status, - nodes.created_at, - nodes.updated_at, - nodes.root_disk_size, - nodes.default_network - FROM nodes LEFT JOIN compute_ports as ports ON - nodes.uuid = ports.node WHERE ports.uuid is NULL; - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - def downgrade(self, session): - sql_expressions = [ - """ - DROP VIEW IF EXISTS unscheduled_nodes; - """, - """ - CREATE OR REPLACE VIEW unscheduled_nodes AS - SELECT - nodes.uuid, - nodes.project_id, - nodes.name, - nodes.description, - nodes.cores, - nodes.ram, - nodes.image, - nodes.node_type, - nodes.status, - nodes.created_at, - nodes.updated_at, - nodes.root_disk_size - FROM nodes LEFT JOIN machines ON - nodes.uuid = machines.node WHERE machines.uuid is NULL; - """, - """ - ALTER TABLE nodes - DROP COLUMN IF EXISTS default_network; - """, - ] - tables = [ - "compute_ports", - "compute_subnets", - "compute_networks", - ] - views = ["compute_nodes_without_ports"] - - for view_name in views: - self._delete_view_if_exists(session, view_name) - - for expr in sql_expressions: - session.execute(expr, None) - - for table_name in tables: - self._delete_table_if_exists(session, table_name) - - -migration_step = MigrationStep() diff --git a/migrations/0015-add-email-confirmation-info-8b38d3.py b/migrations/0015-add-email-confirmation-info-8b38d3.py deleted file mode 100644 index f607af1d..00000000 --- a/migrations/0015-add-email-confirmation-info-8b38d3.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0014-network-ipam-067981.py"] - - @property - def migration_id(self): - return "8b38d350-ccf2-4af5-b2e1-0573b19ee363" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - sql_expressions = [ - """ - ALTER TABLE "iam_users" - ADD IF NOT EXISTS "email_verified" BOOLEAN NOT NULL - DEFAULT FALSE, - ADD IF NOT EXISTS "confirmation_code" UUID NULL - DEFAULT NULL; - """, - ] - - for expr in sql_expressions: - session.execute(expr) - - def downgrade(self, session): - sql_expressions = [ - """ - ALTER TABLE "iam_users" DROP COLUMN IF EXISTS - email_verified; - """, - """ - ALTER TABLE "iam_users" DROP COLUMN IF EXISTS - confirmation_code; - """, - ] - - for expr in sql_expressions: - session.execute(expr) - - -migration_step = MigrationStep() diff --git a/migrations/0016-add-permissions-to-all-iam-resources-3b82c6.py b/migrations/0016-add-permissions-to-all-iam-resources-3b82c6.py deleted file mode 100644 index ea7914a6..00000000 --- a/migrations/0016-add-permissions-to-all-iam-resources-3b82c6.py +++ /dev/null @@ -1,199 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from restalchemy.storage.sql import migrations - -PERMISSION_PROJECT_LIST_ALL = "iam.project.list_all" -PERMISSION_PROJECT_READ_ALL = "iam.project.read_all" -PERMISSION_PROJECT_WRITE_ALL = "iam.project.write_all" -PERMISSION_PROJECT_DELETE_ALL = "iam.project.delete_all" - -PERMISSION_PERMISSION_CREATE = "iam.permission.create" -PERMISSION_PERMISSION_READ = "iam.permission.read" -PERMISSION_PERMISSION_UPDATE = "iam.permission.update" -PERMISSION_PERMISSION_DELETE = "iam.permission.delete" - - -PERMISSION_PERMISSION_BINDING_CREATE = "iam.permission_binding.create" -PERMISSION_PERMISSION_BINDING_READ = "iam.permission_binding.read" -PERMISSION_PERMISSION_BINDING_UPDATE = "iam.permission_binding.update" -PERMISSION_PERMISSION_BINDING_DELETE = "iam.permission_binding.delete" - - -PERMISSION_ROLE_CREATE = "iam.role.create" -PERMISSION_ROLE_READ = "iam.role.read" -PERMISSION_ROLE_UPDATE = "iam.role.write" -PERMISSION_ROLE_DELETE = "iam.role.delete" - - -PERMISSION_ROLE_BINDING_CREATE = "iam.role_binding.create" -PERMISSION_ROLE_BINDING_READ = "iam.role_binding.read" -PERMISSION_ROLE_BINDING_UPDATE = "iam.role_binding.update" -PERMISSION_ROLE_BINDING_DELETE = "iam.role_binding.delete" - - -PERMISSION_IAM_CLIENT_CREATE = "iam.iam_client.create" -PERMISSION_IAM_CLIENT_READ_ALL = "iam.iam_client.read_all" -PERMISSION_IAM_CLIENT_UPDATE = "iam.iam_client.update" -PERMISSION_IAM_CLIENT_DELETE = "iam.iam_client.delete" - - -NAMESPACE_UUID = uuid.UUID("a6c4c7a8-b1d2-4e8f-9a3c-1d7e4f5a9b0c") - - -def generate_uuid(name): - return str(uuid.uuid5(NAMESPACE_UUID, name)) - - -PERMISSION_UUIDS = { - PERMISSION_PROJECT_LIST_ALL: generate_uuid(PERMISSION_PROJECT_LIST_ALL), - PERMISSION_PROJECT_READ_ALL: generate_uuid(PERMISSION_PROJECT_READ_ALL), - PERMISSION_PROJECT_WRITE_ALL: generate_uuid(PERMISSION_PROJECT_WRITE_ALL), - PERMISSION_PROJECT_DELETE_ALL: generate_uuid(PERMISSION_PROJECT_DELETE_ALL), - PERMISSION_PERMISSION_CREATE: generate_uuid(PERMISSION_PERMISSION_CREATE), - PERMISSION_PERMISSION_READ: generate_uuid(PERMISSION_PERMISSION_READ), - PERMISSION_PERMISSION_UPDATE: generate_uuid(PERMISSION_PERMISSION_UPDATE), - PERMISSION_PERMISSION_DELETE: generate_uuid(PERMISSION_PERMISSION_DELETE), - PERMISSION_PERMISSION_BINDING_CREATE: generate_uuid( - PERMISSION_PERMISSION_BINDING_CREATE - ), - PERMISSION_PERMISSION_BINDING_READ: generate_uuid( - PERMISSION_PERMISSION_BINDING_READ - ), - PERMISSION_PERMISSION_BINDING_UPDATE: generate_uuid( - PERMISSION_PERMISSION_BINDING_UPDATE - ), - PERMISSION_PERMISSION_BINDING_DELETE: generate_uuid( - PERMISSION_PERMISSION_BINDING_DELETE - ), - PERMISSION_ROLE_CREATE: generate_uuid(PERMISSION_ROLE_CREATE), - PERMISSION_ROLE_READ: generate_uuid(PERMISSION_ROLE_READ), - PERMISSION_ROLE_UPDATE: generate_uuid(PERMISSION_ROLE_UPDATE), - PERMISSION_ROLE_DELETE: generate_uuid(PERMISSION_ROLE_DELETE), - PERMISSION_ROLE_BINDING_CREATE: generate_uuid(PERMISSION_ROLE_BINDING_CREATE), - PERMISSION_ROLE_BINDING_READ: generate_uuid(PERMISSION_ROLE_BINDING_READ), - PERMISSION_ROLE_BINDING_UPDATE: generate_uuid(PERMISSION_ROLE_BINDING_UPDATE), - PERMISSION_ROLE_BINDING_DELETE: generate_uuid(PERMISSION_ROLE_BINDING_DELETE), - PERMISSION_IAM_CLIENT_CREATE: generate_uuid(PERMISSION_IAM_CLIENT_CREATE), - PERMISSION_IAM_CLIENT_READ_ALL: generate_uuid(PERMISSION_IAM_CLIENT_READ_ALL), - PERMISSION_IAM_CLIENT_UPDATE: generate_uuid(PERMISSION_IAM_CLIENT_UPDATE), - PERMISSION_IAM_CLIENT_DELETE: generate_uuid(PERMISSION_IAM_CLIENT_DELETE), -} - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0015-add-email-confirmation-info-8b38d3.py"] - - @property - def migration_id(self): - return "3b82c606-7f77-49ff-8bbf-d04112569117" - - def _create_permissions(self, session): - permissions = [ - # User permissions - ( - PERMISSION_PROJECT_LIST_ALL, - "Allows listing projects in the system", - ), - ( - PERMISSION_PROJECT_READ_ALL, - "Allows reading all project details", - ), - ( - PERMISSION_PROJECT_WRITE_ALL, - "Allows modifying any project`s data", - ), - (PERMISSION_PROJECT_DELETE_ALL, "Allows deleting any project"), - (PERMISSION_PERMISSION_CREATE, "Allows creating new permissions"), - (PERMISSION_PERMISSION_READ, "Allows reading permissions"), - ( - PERMISSION_PERMISSION_UPDATE, - "Allows updating existing permissions", - ), - (PERMISSION_PERMISSION_DELETE, "Allows deleting permissions"), - ( - PERMISSION_PERMISSION_BINDING_CREATE, - "Allows creating permission bindings", - ), - ( - PERMISSION_PERMISSION_BINDING_READ, - "Allows reading permission bindings", - ), - ( - PERMISSION_PERMISSION_BINDING_UPDATE, - "Allows updating permission bindings", - ), - ( - PERMISSION_PERMISSION_BINDING_DELETE, - "Allows deleting permission bindings", - ), - (PERMISSION_ROLE_CREATE, "Allows creating new roles"), - (PERMISSION_ROLE_READ, "Allows reading roles"), - (PERMISSION_ROLE_UPDATE, "Allows updating existing roles"), - (PERMISSION_ROLE_DELETE, "Allows deleting roles"), - (PERMISSION_ROLE_BINDING_CREATE, "Allows creating role bindings"), - (PERMISSION_ROLE_BINDING_READ, "Allows reading role bindings"), - (PERMISSION_ROLE_BINDING_UPDATE, "Allows updating role bindings"), - (PERMISSION_ROLE_BINDING_DELETE, "Allows deleting role bindings"), - (PERMISSION_IAM_CLIENT_CREATE, "Allows creating IAM clients"), - (PERMISSION_IAM_CLIENT_READ_ALL, "Allows reading all IAM clients"), - (PERMISSION_IAM_CLIENT_UPDATE, "Allows updating IAM clients"), - (PERMISSION_IAM_CLIENT_DELETE, "Allows deleting IAM clients"), - ] - - for name, description in permissions: - session.execute(f""" - INSERT INTO iam_permissions ( - uuid, name, description - ) VALUES ( - '{PERMISSION_UUIDS[name]}', - '{name}', - '{description}' - ) - ON CONFLICT (uuid) DO NOTHING; - """) - - @property - def is_manual(self): - return False - - def upgrade(self, session): - self._create_permissions(session) - - def _delete_permission_bindings(self, session): - for permission_uuid in PERMISSION_UUIDS.values(): - session.execute(f""" - DELETE FROM iam_binding_permissions - WHERE permission = '{permission_uuid}'; - """) - - def _delete_permissions(self, session): - for permission_uuid in PERMISSION_UUIDS.values(): - session.execute(f""" - DELETE FROM iam_permissions - WHERE uuid = '{permission_uuid}'; - """) - - def downgrade(self, session): - self._delete_permission_bindings(session) - self._delete_permissions(session) - - -migration_step = MigrationStep() diff --git a/migrations/0017-init-configs-c3bbc6.py b/migrations/0017-init-configs-c3bbc6.py deleted file mode 100644 index 79832a2e..00000000 --- a/migrations/0017-init-configs-c3bbc6.py +++ /dev/null @@ -1,186 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0016-add-permissions-to-all-iam-resources-3b82c6.py"] - - @property - def migration_id(self): - return "c3bbc6b2-bc9a-4436-9496-515b3b701220" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - sql_expressions = [ - # TABLES - """ - ALTER TABLE compute_subnets - ADD IF NOT EXISTS ip_discovery_range varchar(31) NULL DEFAULT NULL; - """, - """ - CREATE TABLE IF NOT EXISTS compute_net_interfaces ( - uuid UUID NOT NULL PRIMARY KEY, - name varchar(255) NOT NULL, - description varchar(255) NOT NULL, - machine UUID references machines(uuid) ON DELETE CASCADE, - ipv4 varchar(15) NULL DEFAULT NULL, - mask varchar(15) NULL DEFAULT NULL, - mac varchar(17) NULL DEFAULT NULL, - mtu integer DEFAULT 1500, - created_at timestamp NOT NULL DEFAULT current_timestamp, - updated_at timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE INDEX IF NOT EXISTS compute_net_interfaces_machine_id_idx - ON compute_net_interfaces (machine); - """, - """ - CREATE UNIQUE INDEX IF NOT EXISTS compute_net_interfaces_mac_machine_id_idx - ON compute_net_interfaces (mac, machine); - """, - """ - DROP TYPE IF EXISTS enum_config_status; - CREATE TYPE "enum_config_status" AS ENUM ( - 'NEW', - 'IN_PROGRESS', - 'ACTIVE', - 'ERROR' - ); - """, - """ - CREATE TABLE IF NOT EXISTS config_configs ( - "uuid" UUID NOT NULL PRIMARY KEY, - "name" varchar(255) NOT NULL, - "description" varchar(255) NOT NULL, - "project_id" UUID NOT NULL, - "status" enum_config_status NOT NULL DEFAULT 'NEW', - "path" varchar(255) NOT NULL, - "target" JSONB NOT NULL, - "body" JSONB NOT NULL, - "on_change" JSONB NOT NULL, - "mode" char(4) NOT NULL, - "owner" varchar(128) NOT NULL, - "group" varchar(128) NOT NULL, - "created_at" timestamp NOT NULL DEFAULT current_timestamp, - "updated_at" timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE INDEX IF NOT EXISTS config_configs_project_id_idx - ON config_configs (project_id); - """, - """ - CREATE UNIQUE INDEX IF NOT EXISTS config_configs_path_target_id_idx - ON config_configs (path, target); - """, - # Views - """ - DROP VIEW IF EXISTS unscheduled_nodes; - """, - """ - CREATE OR REPLACE VIEW unscheduled_nodes AS - SELECT - nodes.uuid as uuid, - nodes.uuid as node - FROM nodes LEFT JOIN machines ON - nodes.uuid = machines.node WHERE machines.uuid is NULL; - """, - """ - CREATE OR REPLACE VIEW compute_hw_nodes_without_ports AS - SELECT - nodes.uuid as uuid, - nodes.uuid as node, - machines.uuid as machine, - compute_net_interfaces.uuid as iface - FROM nodes LEFT JOIN machines ON - nodes.uuid = machines.node - LEFT JOIN compute_net_interfaces ON - compute_net_interfaces.machine = machines.uuid - LEFT JOIN compute_ports ON - compute_ports.node = nodes.uuid - WHERE nodes.node_type = 'HW' AND machines.uuid is not NULL AND compute_net_interfaces.ipv4 is not NULL AND compute_ports.uuid is NULL; - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - def downgrade(self, session): - sql_expressions = [ - """ - ALTER TABLE compute_subnets - DROP COLUMN IF EXISTS ip_discovery_range; - """, - """ - DROP VIEW IF EXISTS unscheduled_nodes; - """, - """ - CREATE OR REPLACE VIEW unscheduled_nodes AS - SELECT - nodes.uuid, - nodes.project_id, - nodes.name, - nodes.description, - nodes.cores, - nodes.ram, - nodes.image, - nodes.node_type, - nodes.status, - nodes.created_at, - nodes.updated_at, - nodes.root_disk_size, - nodes.default_network - FROM nodes LEFT JOIN machines ON - nodes.uuid = machines.node WHERE machines.uuid is NULL; - """, - ] - - sql_types = [ - """ - DROP TYPE IF EXISTS enum_config_status; - """, - ] - - tables = [ - "config_configs", - "compute_net_interfaces", - ] - views = [ - "compute_hw_nodes_without_ports", - ] - - for view_name in views: - self._delete_view_if_exists(session, view_name) - - for expr in sql_expressions: - session.execute(expr, None) - - for table_name in tables: - self._delete_table_if_exists(session, table_name) - - for expr in sql_types: - session.execute(expr, None) - - -migration_step = MigrationStep() diff --git a/migrations/0018-add-elements-76bca4.py b/migrations/0018-add-elements-76bca4.py deleted file mode 100644 index e6eb203d..00000000 --- a/migrations/0018-add-elements-76bca4.py +++ /dev/null @@ -1,248 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import os - -from gcl_sdk import migrations as sdk_migrations -from restalchemy.storage.sql import migrations - -SDK_MIGRATION_FILE_NAME = "0001-universal-agent-391c09.py" - - -LOG = logging.getLogger(__name__) - - -class MigrationEngine(migrations.MigrationEngine): - def apply_migration(self, migration_name, session): - filename = self.get_file_name(migration_name) - self._init_migration_table(session) - migrations = self._load_migration_controllers(session) - - migration = migrations[filename] - if migration.is_applied(): - LOG.warning("Migration '%s' is already applied", migration.name) - else: - LOG.info("Applying migration '%s'", migration.name) - migrations[filename].apply(session, migrations) - - def rollback_migration(self, migration_name, session): - filename = self.get_file_name(migration_name) - self._init_migration_table(session) - migrations = self._load_migration_controllers(session) - migration = migrations[filename] - if not migration.is_applied(): - LOG.warning("Migration '%s' is not applied", migration.name) - else: - LOG.info("Rolling back migration '%s'", migration.name) - migrations[filename].rollback(session, migrations) - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0017-init-configs-c3bbc6.py"] - - @property - def migration_id(self): - return "76bca4a1-46ab-495e-b956-99bdab62d7c5" - - @property - def is_manual(self): - return False - - def _get_migration_engine(self): - sdk_migration_path = os.path.dirname(sdk_migrations.__file__) - return MigrationEngine(migrations_path=sdk_migration_path) - - def upgrade(self, session): - expressions = [ - """ - CREATE TABLE IF NOT EXISTS "em_manifests" ( - "uuid" UUID PRIMARY KEY, - "name" VARCHAR(255) NOT NULL, - "description" VARCHAR(255) NOT NULL DEFAULT '', - "status" VARCHAR(20) NOT NULL DEFAULT 'NEW' - CHECK ( - status IN ( - 'ACTIVE' - ) - ), - "version" VARCHAR(64) NOT NULL, - "schema_version" INTEGER NOT NULL DEFAULT 1, - "project_id" UUID NOT NULL, - "requirements" JSONB NOT NULL DEFAULT '{}', - "resources" JSONB NOT NULL DEFAULT '{}', - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - """, - """ - CREATE TABLE IF NOT EXISTS "em_elements" ( - "uuid" UUID PRIMARY KEY, - "name" VARCHAR(255) NOT NULL, - "description" VARCHAR(255) NOT NULL DEFAULT '', - "status" VARCHAR(20) NOT NULL DEFAULT 'NEW' - CHECK ( - status IN ( - 'NEW', - 'IN_PROGRESS', - 'ACTIVE' - ) - ), - "version" VARCHAR(64) NOT NULL, - "install_type" VARCHAR(20) NOT NULL DEFAULT 'MANUAL' - CHECK ( - install_type IN ( - 'MANUAL', - 'AUTO_AS_DEPENDENCY' - ) - ), - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - CONSTRAINT unique_em_elements_name_version_idx UNIQUE ( - name, version - ) - ); - """, - """ - CREATE TABLE IF NOT EXISTS "em_resources" ( - "uuid" UUID PRIMARY KEY, - "name" VARCHAR(255) NOT NULL, - "element" UUID NOT NULL REFERENCES em_elements("uuid") - ON DELETE CASCADE, - "status" VARCHAR(20) NOT NULL DEFAULT 'NEW' - CHECK ( - status IN ( - 'NEW', - 'IN_PROGRESS', - 'ACTIVE' - ) - ), - "resource_link_prefix" VARCHAR(256) NOT NULL, - "value" JSONB NOT NULL DEFAULT '{}', - "target_resource" UUID DEFAULT NULL REFERENCES - ua_target_resources("res_uuid"), - "actual_resource" UUID DEFAULT NULL REFERENCES - ua_actual_resources("res_uuid"), - "full_hash" VARCHAR(256) NOT NULL DEFAULT '', - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - """, - """ - CREATE OR REPLACE VIEW "em_incorrect_statuses_view" AS - WITH "em_incorrect_resource_statuses" AS ( - WITH "tmp" AS ( - SELECT - "element", - BOOL_OR("status" = 'IN_PROGRESS') AS - "has_in_progress", - BOOL_AND("status" = 'ACTIVE') AS "all_active", - BOOL_AND("status" = 'NEW') AS "all_new", - COUNT(*) AS "resources_count" - FROM "em_resources" - GROUP BY "element" - ) - SELECT - "e"."uuid" "uuid", - "e"."name" "name", - "e"."status" "api_status", - CASE - WHEN "tmp"."resources_count" IS NULL THEN 'ACTIVE' - WHEN "tmp"."has_in_progress" THEN 'IN_PROGRESS' - WHEN "tmp"."all_active" THEN 'ACTIVE' - WHEN "tmp"."all_new" THEN 'NEW' - ELSE 'IN_PROGRESS' - END AS "actual_status" - FROM "em_elements" "e" - LEFT JOIN "tmp" "tmp" ON "e"."uuid" = "tmp"."element" - ) - SELECT * FROM "em_incorrect_resource_statuses" "eis" - WHERE "eis"."api_status" != "eis"."actual_status"; - """, - """ - CREATE OR REPLACE VIEW "em_outdated_resources_view" AS - SELECT - COALESCE("er"."uuid", "utr"."uuid") AS "uuid", - "er"."uuid" AS "em_resource", - "utr"."res_uuid" AS "target_resource" - FROM "em_resources" "er" - FULL OUTER JOIN ( - SELECT - "uuid", - "res_uuid", - "updated_at", - "tracked_at" - FROM "ua_target_resources" - WHERE "kind" like 'em_core_%' - ) AS "utr" - on "er"."uuid" = "utr"."uuid" - WHERE - "er"."uuid" IS NULL - OR "utr"."uuid" IS NULL - OR "er"."updated_at" <> "utr"."tracked_at"; - """, - """ - CREATE OR REPLACE VIEW "em_incorrect_resource_statuses_view" AS - SELECT - "er"."uuid" AS "uuid", - "er"."status" AS "current_status", - "uar"."status" AS "actual_status" - FROM - "em_resources" "er" - LEFT JOIN ( - SELECT - "uuid", - "status" - FROM "ua_actual_resources" - WHERE "kind" like 'em_core_%' - ) AS "uar" - ON - "er"."uuid" = "uar"."uuid" - WHERE - "er"."status" <> "uar"."status"; - """, - ] - - migration_engine = self._get_migration_engine() - migration_engine.apply_migration(SDK_MIGRATION_FILE_NAME, session) - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - tables = [ - "em_manifests", - "em_elements", - "em_resources", - ] - views = [ - "em_incorrect_statuses_view", - "em_incorrect_resource_statuses_view", - "em_outdated_resources_view", - ] - - for view in reversed(views): - self._delete_view_if_exists(session, view) - - for table in reversed(tables): - self._delete_table_if_exists(session, table) - - migration_engine = self._get_migration_engine() - migration_engine.rollback_migration(SDK_MIGRATION_FILE_NAME, session) - - -migration_step = MigrationStep() diff --git a/migrations/0019-init-dns-40a307.py b/migrations/0019-init-dns-40a307.py deleted file mode 100644 index a5eed3a2..00000000 --- a/migrations/0019-init-dns-40a307.py +++ /dev/null @@ -1,135 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0018-add-elements-76bca4.py"] - - @property - def migration_id(self): - return "40a307b3-fdcc-46d8-bc81-1e2a53ac59e4" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ -CREATE SEQUENCE IF NOT EXISTS dns_domain_id_seq; - """, - """ -CREATE TABLE dns_domains ( - uuid UUID PRIMARY KEY, - id INT UNIQUE DEFAULT nextval('dns_domain_id_seq'), - name VARCHAR(255) NOT NULL, - master VARCHAR(128) DEFAULT NULL, - last_check INT DEFAULT NULL, - type TEXT NOT NULL DEFAULT 'NATIVE', - notified_serial BIGINT DEFAULT NULL, - account VARCHAR(40) DEFAULT NULL, - options TEXT DEFAULT NULL, - catalog TEXT DEFAULT NULL, - CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))), - -- our (plus uuid) - project_id UUID NOT NULL, - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() -); - -CREATE UNIQUE INDEX ON dns_domains(id); -CREATE UNIQUE INDEX ON dns_domains(name); -CREATE INDEX ON dns_domains(catalog); -CREATE INDEX on dns_domains(project_id, name); - """, - """ -CREATE TABLE dns_domainmetadata ( - id SERIAL PRIMARY KEY, - domain_id INT REFERENCES dns_domains(id) ON DELETE CASCADE, - kind VARCHAR(32), - content TEXT -); - -CREATE INDEX ON dns_domainmetadata(domain_id); - """, - """ -CREATE TABLE dns_records ( - uuid UUID PRIMARY KEY, - domain_id INT DEFAULT NULL REFERENCES dns_domains(id) ON DELETE RESTRICT, - name VARCHAR(255) DEFAULT NULL CHECK (((name)::TEXT = LOWER((name)::TEXT))), - type VARCHAR(10) DEFAULT NULL, - content VARCHAR(65535) DEFAULT NULL, - ttl INT DEFAULT NULL, - prio INT DEFAULT NULL, - disabled BOOL DEFAULT 'f', - ordername VARCHAR(255), - auth BOOL DEFAULT 't', - -- our (plus uuid) - domain UUID NOT NULL REFERENCES dns_domains(uuid) ON DELETE CASCADE, - "record" JSONB NOT NULL, - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() -); - -CREATE INDEX rec_name_index ON dns_records(name); -CREATE INDEX nametype_index ON dns_records(name,type); -CREATE INDEX domain_id ON dns_records(domain_id); -CREATE INDEX recordorder ON dns_records (domain_id, ordername text_pattern_ops); - """, - """ -CREATE VIEW domains AS -SELECT id, name, master, last_check, type, notified_serial, account, options, catalog FROM dns_domains; - """, - """ -CREATE VIEW records AS -SELECT domain_id, name, type, content, ttl, prio, disabled, ordername, auth FROM dns_records; - """, - """ -CREATE VIEW domainmetadata AS -SELECT id, domain_id, kind, content FROM dns_domainmetadata; - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - views = [ - "domains", - "records", - "domainmetadata", - ] - - tables = [ - "dns_records", - "dns_domainmetadata", - "dns_domains", - ] - - for view in views: - self._delete_view_if_exists(session, view) - - for table in tables: - self._delete_table_if_exists(session, table) - - session.execute("DROP SEQUENCE IF EXISTS dns_domain_id_seq;") - - -migration_step = MigrationStep() diff --git a/migrations/0020-init-secret-a643b1.py b/migrations/0020-init-secret-a643b1.py deleted file mode 100644 index f5dc46ac..00000000 --- a/migrations/0020-init-secret-a643b1.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0019-init-dns-40a307.py"] - - @property - def migration_id(self): - return "a643b104-f95d-47cd-aaa8-55a1a0104ba6" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - sql_expressions = [ - # TABLES - """ - DROP TYPE IF EXISTS enum_secret_status; - CREATE TYPE "enum_secret_status" AS ENUM ( - 'NEW', - 'IN_PROGRESS', - 'ACTIVE', - 'ERROR' - ); - """, - """ - CREATE TABLE IF NOT EXISTS secret_passwords ( - "uuid" UUID NOT NULL PRIMARY KEY, - "name" varchar(255) NOT NULL, - "description" varchar(255) NOT NULL, - "project_id" UUID NOT NULL, - "status" enum_secret_status NOT NULL DEFAULT 'NEW', - "constructor" JSONB NOT NULL, - "value" varchar(512) NULL DEFAULT NULL, - "method" varchar(64) NOT NULL, - "created_at" timestamp NOT NULL DEFAULT current_timestamp, - "updated_at" timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE INDEX IF NOT EXISTS secret_passwords_project_id_idx - ON secret_passwords (project_id); - """, - """ - CREATE TABLE IF NOT EXISTS storage_passwords ( - "uuid" UUID NOT NULL PRIMARY KEY, - "status" enum_secret_status NOT NULL DEFAULT 'NEW', - "value" varchar(512) NOT NULL, - "meta" JSONB NOT NULL, - "created_at" timestamp NOT NULL DEFAULT current_timestamp, - "updated_at" timestamp NOT NULL DEFAULT current_timestamp - ); - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - def downgrade(self, session): - sql_types = [ - """ - DROP TYPE IF EXISTS enum_secret_status; - """, - ] - - tables = [ - "storage_passwords", - "secret_passwords", - ] - - for table_name in tables: - self._delete_table_if_exists(session, table_name) - - for expr in sql_types: - session.execute(expr, None) - - -migration_step = MigrationStep() diff --git a/migrations/0021-dns-permissions-7adac7.py b/migrations/0021-dns-permissions-7adac7.py deleted file mode 100644 index ae1eb51e..00000000 --- a/migrations/0021-dns-permissions-7adac7.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright 2025 Genesis Corporation. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid as sys_uuid - -from restalchemy.storage.sql import migrations - -NS_UUID = sys_uuid.UUID("dfd0c604-607f-4260-981f-374f88435ea0") -EXORDOS_CORE_ORG_UUID = "11111111-1111-1111-1111-111111111111" -OWNER_ROLE_UUID = "726f6c65-0000-0000-0000-000000000002" - -DNS_NODE_DEF_PERMISSIONS = ( - ("dns.domain.read", "List and read own domains"), - ("dns.domain.create", "Create own domains"), - ("dns.domain.update", "Update own domains"), - ("dns.domain.delete", "Delete own domains"), - ("dns.record.read", "List and read own records"), - ("dns.record.create", "Create own records"), - ("dns.record.update", "Update own records"), - ("dns.record.delete", "Delete own records"), -) - - -def _u(name: str) -> str: - return str(sys_uuid.uuid5(NS_UUID, name)) - - -DNS_PROJECT_UUID = _u("GenesisCore-Dns-Project") - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0020-init-secret-a643b1.py"] - - @property - def migration_id(self): - return "7adac7d0-3d20-4c09-a6f5-f90f4442a5d4" - - @property - def is_manual(self): - return False - - def _create_permissions(self, session): - for name, description in DNS_NODE_DEF_PERMISSIONS: - session.execute(f""" - INSERT INTO iam_permissions ( - uuid, name, description - ) VALUES ( - '{_u(name)}', - '{name}', - '{description}' - ) - ON CONFLICT (uuid) DO NOTHING; - """) - - def _create_project(self, session): - session.execute(f""" - INSERT INTO iam_projects ( - uuid, name, description, organization - ) VALUES ( - '{DNS_PROJECT_UUID}', - 'dns-core', - 'Dns Core Project', - '{EXORDOS_CORE_ORG_UUID}' - ) - ON CONFLICT (uuid) DO NOTHING; - """) - - def _create_bindings(self, session): - for name, _ in DNS_NODE_DEF_PERMISSIONS: - session.execute(f""" - INSERT INTO iam_binding_permissions ( - uuid, role, permission, project_id - ) VALUES ( - gen_random_uuid(), - '{OWNER_ROLE_UUID}', - '{_u(name)}', - '{DNS_PROJECT_UUID}' - ); - """) - - def upgrade(self, session): - self._create_permissions(session) - self._create_project(session) - self._create_bindings(session) - - def _delete_bindings(self, session): - for name, _ in DNS_NODE_DEF_PERMISSIONS: - session.execute(f""" - DELETE FROM iam_binding_permissions - WHERE - permission = '{_u(name)}'; - """) - - def _delete_project(self, session): - session.execute(f""" - DELETE FROM iam_projects - WHERE uuid = '{DNS_PROJECT_UUID}'; - """) - - def _delete_permissions(self, session): - for name, _ in DNS_NODE_DEF_PERMISSIONS: - session.execute(f""" - DELETE FROM iam_permissions - WHERE uuid = '{_u(name)}'; - """) - - def downgrade(self, session): - self._delete_bindings(session) - self._delete_project(session) - self._delete_permissions(session) - - -migration_step = MigrationStep() diff --git a/migrations/0022-secret-certs-d340e8.py b/migrations/0022-secret-certs-d340e8.py deleted file mode 100644 index 685fc66c..00000000 --- a/migrations/0022-secret-certs-d340e8.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0021-dns-permissions-7adac7.py"] - - @property - def migration_id(self): - return "d340e85d-c244-43c9-8844-f509179a69fb" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - sql_expressions = [ - # TABLES - """ - CREATE TABLE IF NOT EXISTS secret_certificates ( - "uuid" UUID NOT NULL PRIMARY KEY, - "name" varchar(255) NOT NULL, - "description" varchar(255) NOT NULL, - "project_id" UUID NOT NULL, - "status" VARCHAR(32) NOT NULL CHECK - (status IN ('NEW', 'IN_PROGRESS', 'ACTIVE', 'ERROR')), - "constructor" JSONB NOT NULL, - "method" JSONB NOT NULL, - "email" varchar(254) NOT NULL, - "domains" varchar(1024) NOT NULL, - "key" TEXT NULL DEFAULT NULL, - "cert" TEXT NULL DEFAULT NULL, - "expiration_at" timestamp NULL DEFAULT NULL, - "expiration_threshold" integer NOT NULL, - "overcome_threshold" boolean DEFAULT false, - "created_at" timestamp NOT NULL DEFAULT current_timestamp, - "updated_at" timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE INDEX IF NOT EXISTS secret_certificates_project_id_idx - ON secret_certificates (project_id); - """, - """ - CREATE TABLE IF NOT EXISTS storage_certs ( - "uuid" UUID NOT NULL PRIMARY KEY, - "status" VARCHAR(32) NOT NULL CHECK - (status IN ('NEW', 'IN_PROGRESS', 'ACTIVE', 'ERROR')), - "pkey" varchar(10240) NOT NULL, - "fullchain" varchar(10240) NOT NULL, - "csr" varchar(10240) NOT NULL, - "expiration_at" timestamp NOT NULL, - "meta" JSONB NOT NULL, - "created_at" timestamp NOT NULL DEFAULT current_timestamp, - "updated_at" timestamp NOT NULL DEFAULT current_timestamp - ); - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - def downgrade(self, session): - tables = [ - "storage_certs", - "secret_certificates", - ] - - for table_name in tables: - self._delete_table_if_exists(session, table_name) - - -migration_step = MigrationStep() diff --git a/migrations/0023-nullable_fio-c9cb3a.py b/migrations/0023-nullable_fio-c9cb3a.py deleted file mode 100644 index 6fbea285..00000000 --- a/migrations/0023-nullable_fio-c9cb3a.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0022-secret-certs-d340e8.py"] - - @property - def migration_id(self): - return "c9cb3a7d-28c9-4f8e-ba52-c2fd5f7c18a9" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expression = """ - ALTER TABLE iam_users - ALTER COLUMN first_name DROP NOT NULL, - ALTER COLUMN last_name DROP NOT NULL; - """ - session.execute(expression) - - def downgrade(self, session): - expression = """ - BEGIN; - UPDATE iam_users SET first_name = '' WHERE first_name IS NULL; - UPDATE iam_users SET last_name = '' WHERE last_name IS NULL; - ALTER TABLE iam_users - ALTER COLUMN first_name SET NOT NULL, - ALTER COLUMN last_name SET NOT NULL; - COMMIT; - """ - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0024-user_confirmation_code_made_at-added-435e66.py b/migrations/0024-user_confirmation_code_made_at-added-435e66.py deleted file mode 100644 index 0374dc3b..00000000 --- a/migrations/0024-user_confirmation_code_made_at-added-435e66.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0023-nullable_fio-c9cb3a.py"] - - @property - def migration_id(self): - return "435e66ec-1fa8-4394-bc43-c7aaf54d0e78" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - session.execute(""" - ALTER TABLE iam_users - ADD COLUMN confirmation_code_made_at TIMESTAMP NULL DEFAULT NULL; - """) - - def downgrade(self, session): - session.execute(""" - ALTER TABLE iam_users - DROP COLUMN confirmation_code_made_at; - """) - - -migration_step = MigrationStep() diff --git a/migrations/0025-secret-ssh-keys-ad3fad.py b/migrations/0025-secret-ssh-keys-ad3fad.py deleted file mode 100644 index 2e0436e4..00000000 --- a/migrations/0025-secret-ssh-keys-ad3fad.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - # self._depends = ["MANUAL-fix-usernames-6b042b.py"] - self._depends = ["0024-user_confirmation_code_made_at-added-435e66.py"] - - @property - def migration_id(self): - return "ad3fadc1-b50c-4378-a570-86db321616d6" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - sql_expressions = [ - # TABLES - """ - CREATE TABLE IF NOT EXISTS secret_ssh_keys ( - "uuid" UUID NOT NULL PRIMARY KEY, - "name" varchar(255) NOT NULL, - "description" varchar(255) NOT NULL, - "project_id" UUID NOT NULL, - "status" VARCHAR(32) NOT NULL CHECK - (status IN ('NEW', 'IN_PROGRESS', 'ACTIVE', 'ERROR')), - "constructor" JSONB NOT NULL, - "target" JSONB NOT NULL, - "user" varchar(64) NOT NULL, - "authorized_keys" varchar(256) NOT NULL, - "target_public_key" TEXT NULL DEFAULT NULL, - "created_at" timestamp NOT NULL DEFAULT current_timestamp, - "updated_at" timestamp NOT NULL DEFAULT current_timestamp, - UNIQUE ("user", "target", "target_public_key") - ); - """, - """ - CREATE INDEX IF NOT EXISTS secret_ssh_keys_project_id_idx - ON secret_ssh_keys (project_id); - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - def downgrade(self, session): - tables = [ - "secret_ssh_keys", - ] - - for table_name in tables: - self._delete_table_if_exists(session, table_name) - - -migration_step = MigrationStep() diff --git a/migrations/0026-case-insensitive-users-name-index-41f4b9.py b/migrations/0026-case-insensitive-users-name-index-41f4b9.py deleted file mode 100644 index 0005c2c0..00000000 --- a/migrations/0026-case-insensitive-users-name-index-41f4b9.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0025-secret-ssh-keys-ad3fad.py"] - - @property - def migration_id(self): - return "41f4b995-d237-4b89-bec9-046a50de8d27" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expression = """ - DROP INDEX IF EXISTS iam_users_name_idx; - CREATE UNIQUE INDEX IF NOT EXISTS iam_users_name_lower_idx ON iam_users ( - LOWER(name) - ); - """ - session.execute(expression) - - def downgrade(self, session): - expression = """ - DROP INDEX IF EXISTS iam_users_name_lower_idx; - CREATE UNIQUE INDEX IF NOT EXISTS iam_users_name_idx ON iam_users (name); - """ - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0027-email-lowercase-unique-constraint-98a7bb.py b/migrations/0027-email-lowercase-unique-constraint-98a7bb.py deleted file mode 100644 index ced8f260..00000000 --- a/migrations/0027-email-lowercase-unique-constraint-98a7bb.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0026-case-insensitive-users-name-index-41f4b9.py"] - - @property - def migration_id(self): - return "98a7bbb6-9b39-4d58-9e10-b64914790fbb" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expression = """ - DROP INDEX IF EXISTS iam_users_email_idx; - CREATE UNIQUE INDEX iam_users_email_lower_idx ON iam_users ( - LOWER(email) - ); - """ - session.execute(expression) - - def downgrade(self, session): - expression = """ - DROP INDEX IF EXISTS iam_users_email_lower_idx; - CREATE UNIQUE INDEX iam_users_email_idx ON iam_users (email); - """ - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0028-add-api-version-to-manifest-8de907.py b/migrations/0028-add-api-version-to-manifest-8de907.py deleted file mode 100644 index c0060805..00000000 --- a/migrations/0028-add-api-version-to-manifest-8de907.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0027-email-lowercase-unique-constraint-98a7bb.py"] - - @property - def migration_id(self): - return "8de907a2-768c-4285-aa82-de0eba3d01db" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - ALTER TABLE "em_manifests" - ADD COLUMN IF NOT EXISTS "api_version" VARCHAR(16) - DEFAULT NULL; - """, - """ - ALTER TABLE "em_elements" - ADD COLUMN IF NOT EXISTS "api_version" VARCHAR(16) - DEFAULT NULL; - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """ - ALTER TABLE "em_manifests" DROP COLUMN IF EXISTS "api_version"; - """, - """ - ALTER TABLE "em_elements" DROP COLUMN IF EXISTS "api_version"; - """, - ] - - for expression in expressions: - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0029-sdk-0-7-0-migration-c2c52a.py b/migrations/0029-sdk-0-7-0-migration-c2c52a.py deleted file mode 100644 index 9aad583e..00000000 --- a/migrations/0029-sdk-0-7-0-migration-c2c52a.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import os - -from gcl_sdk import migrations as sdk_migrations -from restalchemy.storage.sql import migrations - -SDK_MIGRATION_FILE_NAME = "0003-ua-addtional-hashes-6e9ca8" - - -LOG = logging.getLogger(__name__) - - -class MigrationEngine(migrations.MigrationEngine): - def apply_migration(self, migration_name, session): - filename = self.get_file_name(migration_name) - self._init_migration_table(session) - migrations = self._load_migration_controllers(session) - - migration = migrations[filename] - if migration.is_applied(): - LOG.warning("Migration '%s' is already applied", migration.name) - else: - LOG.info("Applying migration '%s'", migration.name) - migrations[filename].apply(session, migrations) - - def rollback_migration(self, migration_name, session): - filename = self.get_file_name(migration_name) - self._init_migration_table(session) - migrations = self._load_migration_controllers(session) - migration = migrations[filename] - if not migration.is_applied(): - LOG.warning("Migration '%s' is not applied", migration.name) - else: - LOG.info("Rolling back migration '%s'", migration.name) - migrations[filename].rollback(session, migrations) - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0028-add-api-version-to-manifest-8de907.py"] - - @property - def migration_id(self): - return "c2c52a97-b1c2-44d1-a57f-1add51f219c2" - - @property - def is_manual(self): - return False - - def _get_migration_engine(self): - sdk_migration_path = os.path.dirname(sdk_migrations.__file__) - return MigrationEngine(migrations_path=sdk_migration_path) - - def upgrade(self, session): - migration_engine = self._get_migration_engine() - migration_engine.apply_migration(SDK_MIGRATION_FILE_NAME, session) - - def downgrade(self, session): - migration_engine = self._get_migration_engine() - migration_engine.rollback_migration(SDK_MIGRATION_FILE_NAME, session) - - -migration_step = MigrationStep() diff --git a/migrations/0030-compute-node-sets-b1869c.py b/migrations/0030-compute-node-sets-b1869c.py deleted file mode 100644 index 6025f4ed..00000000 --- a/migrations/0030-compute-node-sets-b1869c.py +++ /dev/null @@ -1,130 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0029-sdk-0-7-0-migration-c2c52a.py"] - - @property - def migration_id(self): - return "b1869cc2-82c0-42e8-a6a9-df07105c3df5" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - sql_expressions = [ - # TABLES - """ - CREATE TABLE IF NOT EXISTS compute_sets ( - "uuid" UUID NOT NULL PRIMARY KEY, - "project_id" UUID NOT NULL, - "name" varchar(255) NOT NULL, - "description" varchar(255) NOT NULL, - "cores" integer NOT NULL, - "ram" integer NOT NULL, - "root_disk_size" integer NOT NULL, - "replicas" integer NOT NULL, - "image" varchar(255) NOT NULL, - "node_type" VARCHAR(2) NOT NULL CHECK (node_type IN ('VM', 'HW')), - "set_type" VARCHAR(32) NOT NULL CHECK (set_type IN ('SET')), - "status" VARCHAR(32) NOT NULL CHECK (status IN ('NEW', 'SCHEDULED', 'IN_PROGRESS', 'STARTED', 'ACTIVE', 'ERROR')), - "nodes" JSONB NOT NULL, - "default_network" JSONB NOT NULL, - "created_at" timestamp NOT NULL DEFAULT current_timestamp, - "updated_at" timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE INDEX IF NOT EXISTS compute_sets_project_id_idx - ON compute_sets (project_id); - """, - """ - ALTER TABLE nodes - ADD IF NOT EXISTS node_set UUID references compute_sets(uuid) ON DELETE CASCADE; - """, - # VIEWS - """ - CREATE OR REPLACE VIEW compute_nodes_without_ports AS - SELECT - nodes.uuid, - nodes.project_id, - nodes.name, - nodes.description, - nodes.cores, - nodes.ram, - nodes.image, - nodes.node_type, - nodes.status, - nodes.created_at, - nodes.updated_at, - nodes.root_disk_size, - nodes.default_network, - nodes.node_set - FROM nodes LEFT JOIN compute_ports as ports ON - nodes.uuid = ports.node WHERE ports.uuid is NULL; - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - def downgrade(self, session): - sql_expressions = [ - """ - DROP VIEW IF EXISTS compute_nodes_without_ports; - """, - """ - CREATE OR REPLACE VIEW compute_nodes_without_ports AS - SELECT - nodes.uuid, - nodes.project_id, - nodes.name, - nodes.description, - nodes.cores, - nodes.ram, - nodes.image, - nodes.node_type, - nodes.status, - nodes.created_at, - nodes.updated_at, - nodes.root_disk_size, - nodes.default_network - FROM nodes LEFT JOIN compute_ports as ports ON - nodes.uuid = ports.node WHERE ports.uuid is NULL; - """, - """ - ALTER TABLE nodes - DROP COLUMN IF EXISTS node_set; - """, - ] - tables = [ - "compute_sets", - ] - - for expr in sql_expressions: - session.execute(expr, None) - - for table_name in tables: - self._delete_table_if_exists(session, table_name) - - -migration_step = MigrationStep() diff --git a/migrations/0031-node-set-permissions-2de46e.py b/migrations/0031-node-set-permissions-2de46e.py deleted file mode 100644 index 2df2b38c..00000000 --- a/migrations/0031-node-set-permissions-2de46e.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright 2025 Genesis Corporation. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid as sys_uuid - -from restalchemy.storage.sql import migrations - -NS_UUID = sys_uuid.UUID("dfd0c604-607f-4260-981f-374f88435ea0") -EXORDOS_CORE_ORG_UUID = "11111111-1111-1111-1111-111111111111" -OWNER_ROLE_UUID = "726f6c65-0000-0000-0000-000000000002" - -COMPUTE_NODE_DEF_PERMISSIONS = ( - ("compute.node_set.read", "List and read own node sets"), - ("compute.node_set.create", "Create own node sets"), - ("compute.node_set.update", "Update own node sets"), - ("compute.node_set.delete", "Delete own node sets"), -) - - -def _u(name: str) -> str: - return str(sys_uuid.uuid5(NS_UUID, name)) - - -COMPUTE_PROJECT_UUID = _u("GenesisCore-Compute-Project") - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0030-compute-node-sets-b1869c.py"] - - @property - def migration_id(self): - return "2de46e49-a793-4854-b311-a406f10f1289" - - @property - def is_manual(self): - return False - - def _create_permissions(self, session): - for name, description in COMPUTE_NODE_DEF_PERMISSIONS: - session.execute(f""" - INSERT INTO iam_permissions ( - uuid, name, description - ) VALUES ( - '{_u(name)}', - '{name}', - '{description}' - ) - ON CONFLICT (uuid) DO NOTHING; - """) - - def _create_bindings(self, session): - for name, _ in COMPUTE_NODE_DEF_PERMISSIONS: - session.execute(f""" - INSERT INTO iam_binding_permissions ( - uuid, role, permission, project_id - ) VALUES ( - '{_u("binding." + name)}', - '{OWNER_ROLE_UUID}', - '{_u(name)}', - '{COMPUTE_PROJECT_UUID}' - ); - """) - - def upgrade(self, session): - self._create_permissions(session) - self._create_bindings(session) - - def _delete_bindings(self, session): - for name, _ in COMPUTE_NODE_DEF_PERMISSIONS: - session.execute(f""" - DELETE FROM iam_binding_permissions - WHERE - permission = '{_u(name)}'; - """) - - def _delete_permissions(self, session): - for name, _ in COMPUTE_NODE_DEF_PERMISSIONS: - session.execute(f""" - DELETE FROM iam_permissions - WHERE uuid = '{_u(name)}'; - """) - - def downgrade(self, session): - self._delete_bindings(session) - self._delete_permissions(session) - - -migration_step = MigrationStep() diff --git a/migrations/0032-project-id-dns-records-1ca60d.py b/migrations/0032-project-id-dns-records-1ca60d.py deleted file mode 100644 index 55b9362e..00000000 --- a/migrations/0032-project-id-dns-records-1ca60d.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = ["0031-node-set-permissions-2de46e.py"] - - @property - def migration_id(self): - return "1ca60d51-f2d1-49d5-b0ed-273d76492d6d" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - ALTER TABLE dns_records ADD COLUMN IF NOT EXISTS project_id UUID; - - UPDATE dns_records dr - SET project_id = dd.project_id - FROM dns_domains dd - WHERE dr.domain = dd.uuid - AND dr.project_id IS NULL; - - ALTER TABLE dns_records ALTER COLUMN project_id SET NOT NULL; - """, - """ - CREATE INDEX IF NOT EXISTS dns_records_project_id_idx - ON dns_records (project_id); - """, - ] - - for expression in expressions: - session.execute(expression, None) - - def downgrade(self, session): - - expressions = [ - """ - DROP INDEX IF EXISTS dns_records_project_id_idx; - """, - """ - ALTER TABLE dns_records DROP COLUMN IF EXISTS project_id; - """, - ] - - for expression in expressions: - session.execute(expression, None) - - -migration_step = MigrationStep() diff --git a/migrations/0033-em-ua-status-check-5be89c.py b/migrations/0033-em-ua-status-check-5be89c.py deleted file mode 100644 index e05fcd83..00000000 --- a/migrations/0033-em-ua-status-check-5be89c.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = ["0032-project-id-dns-records-1ca60d.py"] - - @property - def migration_id(self): - return "5be89c1f-77e1-4054-ab9f-e4d961e9dda8" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - CREATE OR REPLACE VIEW "em_outdated_resources_view" AS - SELECT - COALESCE("er"."uuid", "utr"."uuid") AS "uuid", - "er"."uuid" AS "em_resource", - "utr"."res_uuid" AS "target_resource" - FROM "em_resources" "er" - FULL OUTER JOIN ( - SELECT - "uuid", - "res_uuid", - "updated_at", - "tracked_at" - FROM "ua_target_resources" - WHERE "kind" like 'em_%' - ) AS "utr" - on "er"."uuid" = "utr"."uuid" - WHERE - "er"."uuid" IS NULL - OR "utr"."uuid" IS NULL - OR "er"."updated_at" <> "utr"."tracked_at"; - """, - """ - CREATE OR REPLACE VIEW "em_incorrect_resource_statuses_view" AS - SELECT - "er"."uuid" AS "uuid", - "er"."status" AS "current_status", - "uar"."status" AS "actual_status" - FROM - "em_resources" "er" - LEFT JOIN ( - SELECT - "uuid", - "status" - FROM "ua_actual_resources" - WHERE "kind" like 'em_%' - ) AS "uar" - ON - "er"."uuid" = "uar"."uuid" - WHERE - "er"."status" <> "uar"."status"; - """, - ] - - for expression in expressions: - session.execute(expression, None) - - def downgrade(self, session): - - expressions = [ - """ - CREATE OR REPLACE VIEW "em_outdated_resources_view" AS - SELECT - COALESCE("er"."uuid", "utr"."uuid") AS "uuid", - "er"."uuid" AS "em_resource", - "utr"."res_uuid" AS "target_resource" - FROM "em_resources" "er" - FULL OUTER JOIN ( - SELECT - "uuid", - "res_uuid", - "updated_at", - "tracked_at" - FROM "ua_target_resources" - WHERE "kind" like 'em_core_%' - ) AS "utr" - on "er"."uuid" = "utr"."uuid" - WHERE - "er"."uuid" IS NULL - OR "utr"."uuid" IS NULL - OR "er"."updated_at" <> "utr"."tracked_at"; - """, - """ - CREATE OR REPLACE VIEW "em_incorrect_resource_statuses_view" AS - SELECT - "er"."uuid" AS "uuid", - "er"."status" AS "current_status", - "uar"."status" AS "actual_status" - FROM - "em_resources" "er" - LEFT JOIN ( - SELECT - "uuid", - "status" - FROM "ua_actual_resources" - WHERE "kind" like 'em_core_%' - ) AS "uar" - ON - "er"."uuid" = "uar"."uuid" - WHERE - "er"."status" <> "uar"."status"; - """, - ] - - for expression in expressions: - session.execute(expression, None) - - -migration_step = MigrationStep() diff --git a/migrations/0034-add-export-adn-import-resources-a12854.py b/migrations/0034-add-export-adn-import-resources-a12854.py deleted file mode 100644 index 6bdbdace..00000000 --- a/migrations/0034-add-export-adn-import-resources-a12854.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = ["0033-em-ua-status-check-5be89c.py"] - - @property - def migration_id(self): - return "a12854ea-14af-4d9c-b8a8-a7925263eacf" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - ALTER TABLE - em_manifests - ADD COLUMN IF NOT EXISTS - exports JSONB NOT NULL DEFAULT '{}'; - """, - """ - ALTER TABLE - em_manifests - ADD COLUMN IF NOT EXISTS - imports JSONB NOT NULL DEFAULT '{}'; - """, - """ - CREATE TABLE IF NOT EXISTS "em_exports" ( - "uuid" UUID PRIMARY KEY, - "element" UUID NOT NULL REFERENCES em_elements("uuid") - ON DELETE CASCADE, - "name" VARCHAR(255) NOT NULL, - "kind" VARCHAR(20) NOT NULL DEFAULT 'resource' - CHECK ( - kind IN ( - 'resource' - ) - ), - "link" VARCHAR(255) NOT NULL, - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - """, - """ - CREATE TABLE IF NOT EXISTS "em_imports" ( - "uuid" UUID PRIMARY KEY, - "element" UUID NOT NULL REFERENCES em_elements("uuid") - ON DELETE CASCADE, - "from_element" UUID NOT NULL REFERENCES em_elements("uuid") - ON DELETE CASCADE, - "from_resource" UUID NOT NULL REFERENCES - em_resources("uuid") - ON DELETE CASCADE, - "name" VARCHAR(255) NOT NULL, - "kind" VARCHAR(20) NOT NULL DEFAULT 'resource' - CHECK ( - kind IN ( - 'resource' - ) - ), - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """ - ALTER TABLE em_manifests DROP COLUMN IF EXISTS - exports; - """, - """ - ALTER TABLE em_manifests DROP COLUMN IF EXISTS - imports; - """, - ] - - for expression in expressions: - session.execute(expression) - - self._delete_table_if_exists(session, "em_imports") - self._delete_table_if_exists(session, "em_exports") - - -migration_step = MigrationStep() diff --git a/migrations/0035-dummy-placement-e6d5dc.py b/migrations/0035-dummy-placement-e6d5dc.py deleted file mode 100644 index 4e285546..00000000 --- a/migrations/0035-dummy-placement-e6d5dc.py +++ /dev/null @@ -1,181 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = ["0034-add-export-adn-import-resources-a12854.py"] - - @property - def migration_id(self): - return "e6d5dcbb-ba98-4f86-8f06-6292eb5ac1a1" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - CREATE TABLE IF NOT EXISTS compute_placement_domains ( - uuid UUID NOT NULL PRIMARY KEY, - name varchar(255) NOT NULL, - description varchar(255) NOT NULL, - created_at timestamp NOT NULL DEFAULT current_timestamp, - updated_at timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE TABLE IF NOT EXISTS compute_placement_zones ( - uuid UUID NOT NULL PRIMARY KEY, - name varchar(255) NOT NULL, - description varchar(255) NOT NULL, - domain UUID references compute_placement_domains(uuid) ON DELETE RESTRICT, - created_at timestamp NOT NULL DEFAULT current_timestamp, - updated_at timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE INDEX IF NOT EXISTS compute_placement_zones_domain_idx - ON compute_placement_zones (domain); - """, - """ - CREATE TABLE IF NOT EXISTS compute_placement_policies ( - uuid UUID NOT NULL PRIMARY KEY, - name varchar(255) NOT NULL, - description varchar(255) NOT NULL, - project_id UUID NOT NULL, - domain UUID references compute_placement_domains(uuid) ON DELETE RESTRICT, - zone UUID references compute_placement_zones(uuid) ON DELETE RESTRICT, - kind VARCHAR(64) NOT NULL, - created_at timestamp NOT NULL DEFAULT current_timestamp, - updated_at timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE INDEX IF NOT EXISTS compute_placement_policies_project_id_idx - ON compute_placement_policies (project_id); - """, - """ - CREATE INDEX IF NOT EXISTS compute_placement_policies_domain_idx - ON compute_placement_policies (domain); - """, - """ - CREATE INDEX IF NOT EXISTS compute_placement_policies_zone_idx - ON compute_placement_policies (zone); - """, - """ - CREATE TABLE IF NOT EXISTS compute_placement_policy_allocations ( - uuid UUID NOT NULL PRIMARY KEY, - node UUID references nodes(uuid) ON DELETE CASCADE, - policy UUID references compute_placement_policies(uuid) ON DELETE CASCADE, - created_at timestamp NOT NULL DEFAULT current_timestamp, - updated_at timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE INDEX IF NOT EXISTS compute_placement_policy_allocations_node_idx - ON compute_placement_policy_allocations (node); - """, - """ - CREATE INDEX IF NOT EXISTS compute_placement_policy_allocations_policy_idx - ON compute_placement_policy_allocations (policy); - """, - """ - ALTER TABLE nodes - ADD COLUMN IF NOT EXISTS placement_policies UUID[] NOT NULL DEFAULT '{}'; - """, - # View - """ - DROP VIEW IF EXISTS compute_nodes_without_ports; - """, - """ - CREATE OR REPLACE VIEW compute_nodes_without_ports AS - SELECT - nodes.uuid, - nodes.project_id, - nodes.name, - nodes.description, - nodes.cores, - nodes.ram, - nodes.image, - nodes.node_type, - nodes.status, - nodes.created_at, - nodes.updated_at, - nodes.root_disk_size, - nodes.default_network, - nodes.node_set, - nodes.placement_policies - FROM nodes LEFT JOIN compute_ports as ports ON - nodes.uuid = ports.node WHERE ports.uuid is NULL; - """, - ] - - for expression in expressions: - session.execute(expression, None) - - def downgrade(self, session): - expressions = [ - # View - """ - DROP VIEW IF EXISTS compute_nodes_without_ports; - """, - """ - CREATE OR REPLACE VIEW compute_nodes_without_ports AS - SELECT - nodes.uuid, - nodes.project_id, - nodes.name, - nodes.description, - nodes.cores, - nodes.ram, - nodes.image, - nodes.node_type, - nodes.status, - nodes.created_at, - nodes.updated_at, - nodes.root_disk_size, - nodes.default_network, - nodes.node_set - FROM nodes LEFT JOIN compute_ports as ports ON - nodes.uuid = ports.node WHERE ports.uuid is NULL; - """, - """ - ALTER TABLE nodes - DROP COLUMN IF EXISTS placement_policies; - """, - """ - DROP TABLE IF EXISTS compute_placement_policy_allocations; - """, - """ - DROP TABLE IF EXISTS compute_placement_policies; - """, - """ - DROP TABLE IF EXISTS compute_placement_zones; - """, - """ - DROP TABLE IF EXISTS compute_placement_domains; - """, - ] - - for expression in expressions: - session.execute(expression, None) - - -migration_step = MigrationStep() diff --git a/migrations/0036-init-services-741b72.py b/migrations/0036-init-services-741b72.py deleted file mode 100644 index 1cd6c64d..00000000 --- a/migrations/0036-init-services-741b72.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = ["0035-dummy-placement-e6d5dc.py"] - - @property - def migration_id(self): - return "741b7266-19e8-448b-9463-1c55ec174e28" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - sql_expressions = [ - # TABLES - """ - DROP TYPE IF EXISTS enum_service_status; - CREATE TYPE "enum_service_status" AS ENUM ( - 'NEW', - 'IN_PROGRESS', - 'ACTIVE', - 'ERROR' - ); - """, - """ - DROP TYPE IF EXISTS enum_service_target_status; - CREATE TYPE "enum_service_target_status" AS ENUM ( - 'enabled', - 'disabled' - ); - """, - """ - CREATE TABLE IF NOT EXISTS em_services ( - "uuid" UUID NOT NULL PRIMARY KEY, - "name" varchar(255) NOT NULL, - "description" varchar(255) NOT NULL, - "project_id" UUID NOT NULL, - "status" enum_service_status NOT NULL DEFAULT 'NEW', - "target_status" enum_service_target_status NOT NULL DEFAULT 'enabled', - "path" varchar(255) NOT NULL, - "target" JSONB NOT NULL, - "service_type" JSONB NOT NULL, - "before" JSONB[], - "after" JSONB[], - "user" varchar(255) NOT NULL, - "group" varchar(255), - "created_at" timestamp NOT NULL DEFAULT current_timestamp, - "updated_at" timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE INDEX IF NOT EXISTS em_services_project_id_idx - ON em_services (project_id); - """, - """ - CREATE UNIQUE INDEX IF NOT EXISTS em_services_path_target_id_idx - ON em_services (path, target); - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - def downgrade(self, session): - sql_expressions = [] - - sql_types = [ - """ - DROP TYPE IF EXISTS enum_service_status; - """, - """ - DROP TYPE IF EXISTS enum_service_target_status; - """, - ] - - tables = [ - "em_services", - ] - views = [] - - for view_name in views: - self._delete_view_if_exists(session, view_name) - - for expr in sql_expressions: - session.execute(expr, None) - - for table_name in tables: - self._delete_table_if_exists(session, table_name) - - for expr in sql_types: - session.execute(expr, None) - - -migration_step = MigrationStep() diff --git a/migrations/0037-manifest-indexes-815825.py b/migrations/0037-manifest-indexes-815825.py deleted file mode 100644 index c6831374..00000000 --- a/migrations/0037-manifest-indexes-815825.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = ["0036-init-services-741b72.py"] - - @property - def migration_id(self): - return "815825d7-4864-4a0d-badc-2b186925771d" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - CREATE INDEX IF NOT EXISTS em_imports_element_idx - ON em_imports (element); - """, - """ - ALTER TABLE em_imports - ADD CONSTRAINT em_imports_unique_name UNIQUE (element, name); - """, - """ - CREATE INDEX IF NOT EXISTS em_exports_element_idx - ON em_exports (element); - """, - """ - ALTER TABLE em_exports - ADD CONSTRAINT em_exports_unique_name UNIQUE (element, name); - """, - """ - CREATE INDEX IF NOT EXISTS em_resources_element_idx - ON em_resources (element); - """, - """ - ALTER TABLE em_elements - ADD CONSTRAINT em_elements_unique_name UNIQUE (name); - """, - ] - - for expression in expressions: - session.execute(expression, None) - - def downgrade(self, session): - - expressions = [ - """ - DROP INDEX IF EXISTS em_imports_element_idx; - """, - """ - ALTER TABLE em_imports - DROP CONSTRAINT em_imports_unique_name; - """, - """ - DROP INDEX IF EXISTS em_exports_element_idx; - """, - """ - ALTER TABLE em_exports - DROP CONSTRAINT em_exports_unique_name; - """, - """ - DROP INDEX IF EXISTS em_resources_element_idx; - """, - """ - ALTER TABLE em_elements - DROP CONSTRAINT em_elements_unique_name; - """, - ] - - for expression in expressions: - session.execute(expression, None) - - -migration_step = MigrationStep() diff --git a/migrations/0038-init-lb-e88603.py b/migrations/0038-init-lb-e88603.py deleted file mode 100644 index bd45ecbc..00000000 --- a/migrations/0038-init-lb-e88603.py +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = ["0037-manifest-indexes-815825.py"] - - @property - def migration_id(self): - return "e8860362-cba3-4fa9-b6ec-9395ddec13c3" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """\ -CREATE TABLE net_lb ( - uuid UUID PRIMARY KEY, - name VARCHAR(255) NOT NULL, - description TEXT, - project_id UUID NOT NULL, - status VARCHAR(64) NOT NULL DEFAULT 'NEW', - "ipsv4" varchar(15) ARRAY, - type JSONB NOT NULL, - created_at TIMESTAMP NOT NULL, - updated_at TIMESTAMP NOT NULL -); - -CREATE INDEX ON net_lb(project_id, name); -""", - """\ -CREATE TABLE net_lb_vhosts ( - uuid UUID PRIMARY KEY, - name VARCHAR(64) NOT NULL, - enabled BOOLEAN NOT NULL DEFAULT TRUE, - status VARCHAR(64) NOT NULL DEFAULT 'NEW', - description TEXT, - project_id UUID NOT NULL, - created_at TIMESTAMP NOT NULL, - updated_at TIMESTAMP NOT NULL, - protocol VARCHAR(10) NOT NULL, - port INT NOT NULL, - domains VARCHAR(255) ARRAY, - cert JSONB, - parent UUID NOT NULL, - FOREIGN KEY (parent) REFERENCES net_lb(uuid) -); - -CREATE INDEX ON net_lb_vhosts(project_id); -CREATE INDEX ON net_lb_vhosts(parent, name); -CREATE INDEX ON net_lb_vhosts(parent, port, domains); -""", - """\ -CREATE TABLE net_lb_vhosts_routes ( - uuid UUID PRIMARY KEY, - name VARCHAR(64) NOT NULL, - enabled BOOLEAN NOT NULL DEFAULT TRUE, - status VARCHAR(64) NOT NULL DEFAULT 'NEW', - description TEXT, - project_id UUID NOT NULL, - created_at TIMESTAMP NOT NULL, - updated_at TIMESTAMP NOT NULL, - condition JSONB, - parent UUID NOT NULL, - FOREIGN KEY (parent) REFERENCES net_lb_vhosts(uuid) -); - -CREATE INDEX ON net_lb_vhosts_routes(project_id); -CREATE INDEX ON net_lb_vhosts_routes(parent, name); -""", - """\ -CREATE TABLE net_lb_backendpools ( - uuid UUID PRIMARY KEY, - name VARCHAR(64) NOT NULL, - status VARCHAR(64) NOT NULL DEFAULT 'NEW', - description TEXT, - project_id UUID NOT NULL, - created_at TIMESTAMP NOT NULL, - updated_at TIMESTAMP NOT NULL, - endpoints JSONB[] NOT NULL, - balance VARCHAR(32) NOT NULL, - parent UUID NOT NULL, - FOREIGN KEY (parent) REFERENCES net_lb(uuid) -); - -CREATE INDEX ON net_lb_backendpools(project_id); -CREATE INDEX ON net_lb_backendpools(parent, name); -""", - ] - - for expression in expressions: - session.execute(expression, None) - - def downgrade(self, session): - - tables = [ - "net_lb_backendpools", - "net_lb_vhosts_routes", - "net_lb_vhosts", - "net_lb", - ] - - for table in tables: - self._delete_table_if_exists(session, table) - - -migration_step = MigrationStep() diff --git a/migrations/0039-add-oidc-structures-e5d2a8.py b/migrations/0039-add-oidc-structures-e5d2a8.py deleted file mode 100644 index 9e5e0154..00000000 --- a/migrations/0039-add-oidc-structures-e5d2a8.py +++ /dev/null @@ -1,196 +0,0 @@ -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - -_DEFAULT_IAM_CLIENT_UUID = "00000000-0000-0000-0000-000000000000" - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = [ - "0038-init-lb-e88603.py", - ] - - @property - def migration_id(self): - return "e5d2a8e0-6c4a-4a0e-9f0d-3c4b2a1d9e50" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - ALTER TABLE iam_idp - RENAME COLUMN redirect_uri_template TO callback_uri; - """, - """ - ALTER TABLE iam_idp - DROP COLUMN IF EXISTS well_known_endpoint; - """, - """ - ALTER TABLE "iam_idp" - ADD COLUMN IF NOT EXISTS "iam_client" UUID - REFERENCES "iam_clients" ("uuid") - ON DELETE RESTRICT - ON UPDATE RESTRICT; - """, - """ - CREATE TABLE IF NOT EXISTS "iam_idp_authorization_info" ( - "uuid" UUID PRIMARY KEY, - "idp" UUID NOT NULL REFERENCES "iam_idp" ("uuid"), - "state" VARCHAR(256) NOT NULL, - "response_type" VARCHAR(20) NOT NULL DEFAULT 'code' - CHECK ( - response_type IN ('code') - ), - "nonce" VARCHAR(256) NOT NULL, - "scope" VARCHAR(256) NOT NULL, - "expiration_time_at" TIMESTAMP(6) NOT NULL, - "token" UUID DEFAULT NULL REFERENCES "iam_tokens" ("uuid"), - "code" UUID NOT NULL, - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - """, - """ - ALTER TABLE "iam_tokens" - ADD COLUMN IF NOT EXISTS "nonce" VARCHAR(256) DEFAULT NULL; - """, - """ - ALTER TABLE "iam_clients" - ADD COLUMN IF NOT EXISTS "signature_algorithm" JSONB - NOT NULL DEFAULT - '{"kind": "HS256", "secret_uuid": "00000000-0000-0000-0000-000000000001", "previous_secret_uuid": null}'::jsonb; - """, - """ - ALTER TABLE "iam_clients" - DROP COLUMN IF EXISTS "redirect_url"; - """, - """ - UPDATE "iam_clients" - SET "salt" = 'd4JJ9QYuEEJxHCFja9FZskG4' - WHERE "salt" = '5fOuZXeIn5e5TJlo9Pv5T219'; --fix incorrect default salt - """, - """ - ALTER TABLE "iam_tokens" - ADD COLUMN IF NOT EXISTS "iam_client" UUID - REFERENCES "iam_clients" ("uuid") - ON DELETE CASCADE - ON UPDATE CASCADE; - """, - ] - - for expression in expressions: - session.execute(expression) - - session.execute(""" - INSERT INTO "secret_passwords" ( - "uuid", - "name", - "description", - "project_id", - "constructor", - "method", - "value", - "status" - ) VALUES ( - '00000000-0000-0000-0000-000000000001', - 'iam-client-hs256-secret', - 'Default HS256 secret for IAM clients', - '00000000-0000-0000-0000-000000000000', - '{"kind": "plain"}'::jsonb, - 'MANUAL', - 'secret', - 'ACTIVE' - ) ON CONFLICT ("uuid") DO NOTHING; - """) - - session.execute( - """ - UPDATE "iam_tokens" - SET "iam_client" = %s - WHERE "iam_client" IS NULL; - """, - (_DEFAULT_IAM_CLIENT_UUID,), - ) - - expressions = [ - """ - ALTER TABLE "iam_tokens" - ALTER COLUMN "iam_client" SET NOT NULL; - """, - """ - CREATE INDEX IF NOT EXISTS "iam_tokens_iam_client_idx" - ON "iam_tokens" ("iam_client"); - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """ - DROP INDEX IF EXISTS "iam_tokens_iam_client_idx"; - """, - """ - ALTER TABLE "iam_tokens" - DROP COLUMN IF EXISTS "iam_client"; - """, - """ - ALTER TABLE "iam_clients" - ADD COLUMN IF NOT EXISTS "redirect_url" VARCHAR(256) - NOT NULL DEFAULT 'http://127.0.0.1:11010/v1/'; - """, - """ - ALTER TABLE "iam_clients" - DROP COLUMN IF EXISTS "signature_algorithm"; - """, - """ - ALTER TABLE "iam_tokens" - DROP COLUMN IF EXISTS "nonce"; - """, - """ - ALTER TABLE "iam_idp" - DROP COLUMN IF EXISTS "iam_client"; - """, - ] - - for expression in expressions: - session.execute(expression) - - self._delete_table_if_exists(session, "iam_idp_authorization_info") - - expressions = [ - """ - ALTER TABLE iam_idp - ADD COLUMN IF NOT EXISTS well_known_endpoint VARCHAR(256) - NOT NULL DEFAULT ''; - """, - """ - ALTER TABLE iam_idp - RENAME COLUMN callback_uri TO redirect_uri_template; - """, - ] - - for expression in expressions: - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0040-secret-rsa-keys-2f3c1a.py b/migrations/0040-secret-rsa-keys-2f3c1a.py deleted file mode 100644 index e9eca5e8..00000000 --- a/migrations/0040-secret-rsa-keys-2f3c1a.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = [ - "0039-add-oidc-structures-e5d2a8.py", - ] - - @property - def migration_id(self): - return "2f3c1a0e-6dbe-4f55-8c5f-2d7b56c2f2c1" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - sql_expressions = [ - """ - CREATE TABLE IF NOT EXISTS secret_rsa_keys ( - "uuid" UUID NOT NULL PRIMARY KEY, - "name" varchar(255) NOT NULL, - "description" varchar(255) NOT NULL, - "project_id" UUID NOT NULL, - "status" VARCHAR(32) NOT NULL CHECK - (status IN ('NEW', 'IN_PROGRESS', 'ACTIVE', 'ERROR')), - "constructor" JSONB NOT NULL, - "private_key" TEXT NOT NULL, - "public_key" TEXT NOT NULL, - "bitness" INTEGER NOT NULL DEFAULT 2048 CHECK - (bitness IN (2048, 3072, 4096)), - "created_at" timestamp NOT NULL DEFAULT current_timestamp, - "updated_at" timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE INDEX IF NOT EXISTS secret_rsa_keys_project_id_idx - ON secret_rsa_keys (project_id); - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - def downgrade(self, session): - tables = [ - "secret_rsa_keys", - ] - - for table_name in tables: - self._delete_table_if_exists(session, table_name) - - -migration_step = MigrationStep() diff --git a/migrations/0041-remove-idp-clientid-secret-18d7c4.py b/migrations/0041-remove-idp-clientid-secret-18d7c4.py deleted file mode 100644 index d8be2999..00000000 --- a/migrations/0041-remove-idp-clientid-secret-18d7c4.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = [ - "0040-secret-rsa-keys-2f3c1a.py", - ] - - @property - def migration_id(self): - return "18d7c4a6-9ee0-4b1a-8fa2-9a0a1f9cfbcb" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - DROP INDEX IF EXISTS "iam_idp_id_idx"; - """, - """ - ALTER TABLE "iam_idp" - DROP COLUMN IF EXISTS "client_id"; - """, - """ - ALTER TABLE "iam_idp" - DROP COLUMN IF EXISTS "secret_hash"; - """, - """ - ALTER TABLE "iam_idp" - DROP COLUMN IF EXISTS "salt"; - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """ - ALTER TABLE "iam_idp" - ADD COLUMN IF NOT EXISTS "client_id" VARCHAR(64) - NOT NULL DEFAULT ''; - """, - """ - ALTER TABLE "iam_idp" - ADD COLUMN IF NOT EXISTS "secret_hash" CHAR(128) - NOT NULL DEFAULT ''; - """, - """ - ALTER TABLE "iam_idp" - ADD COLUMN IF NOT EXISTS "salt" CHAR(24) - NOT NULL DEFAULT ''; - """, - """ - CREATE UNIQUE INDEX IF NOT EXISTS "iam_idp_id_idx" - ON "iam_idp" ("client_id"); - """, - ] - - for expression in expressions: - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0042-compute-ua-integration-4bd866.py b/migrations/0042-compute-ua-integration-4bd866.py deleted file mode 100644 index af38784c..00000000 --- a/migrations/0042-compute-ua-integration-4bd866.py +++ /dev/null @@ -1,456 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = ["0041-remove-idp-clientid-secret-18d7c4.py"] - - @property - def migration_id(self): - return "4bd86653-6413-4c4d-9a44-7df58b0acb90" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - DROP VIEW IF EXISTS compute_nodes_without_ports; - """, - """ - DROP VIEW IF EXISTS machine_volumes; - """, - """ - -- Add disk_spec column to nodes table - ALTER TABLE nodes - ADD COLUMN IF NOT EXISTS disk_spec JSONB; - - -- Fill disk_spec for existing records - UPDATE nodes - SET disk_spec = jsonb_build_object( - 'kind', 'root_disk', - 'size', root_disk_size, - 'image', image - ); - - -- Drop old columns - ALTER TABLE nodes DROP COLUMN root_disk_size; - ALTER TABLE nodes DROP COLUMN image; - """, - """ - ALTER TABLE nodes - ADD IF NOT EXISTS hostname VARCHAR(256) NULL DEFAULT NULL; - """, - """ - ALTER TABLE compute_sets - ADD COLUMN IF NOT EXISTS disk_spec JSONB; - - -- Fill disk_spec for existing records - UPDATE compute_sets - SET disk_spec = jsonb_build_object( - 'kind', 'root_disk', - 'size', root_disk_size, - 'image', image - ); - - -- Drop old columns - ALTER TABLE compute_sets DROP COLUMN root_disk_size; - ALTER TABLE compute_sets DROP COLUMN image; - """, - """ - ALTER TABLE machines - DROP COLUMN IF EXISTS builder; - """, - """ - ALTER TABLE machines - DROP COLUMN IF EXISTS build_status; - """, - """ - ALTER TABLE machines - ALTER COLUMN image DROP NOT NULL, - ALTER COLUMN image SET DEFAULT NULL; - """, - """ - ALTER TABLE machines - ADD COLUMN IF NOT EXISTS block_devices JSONB DEFAULT '{}'; - """, - """ - ALTER TABLE node_volumes - ADD IF NOT EXISTS status VARCHAR(32) NOT NULL - CHECK (status IN ('NEW', 'IN_PROGRESS', 'ACTIVE', 'ERROR')) DEFAULT 'NEW'; - """, - """ - ALTER TABLE node_volumes - ALTER COLUMN device_type TYPE VARCHAR(64); - """, - """ - ALTER TABLE node_volumes - ADD IF NOT EXISTS index INTEGER DEFAULT 4096; - """, - """ - ALTER TABLE node_volumes - ADD IF NOT EXISTS pool UUID references machine_pools(uuid) ON DELETE SET NULL; - """, - """ - ALTER TABLE node_volumes DROP CONSTRAINT node_volumes_device_type_check; - """, - """ - ALTER TABLE node_volumes - ADD IF NOT EXISTS image VARCHAR(256) NULL DEFAULT NULL; - - -- Fill image from disk_spec - UPDATE node_volumes nv - SET image = ( - SELECT n.disk_spec->>'image' - FROM nodes n - WHERE n.uuid = nv.node - AND n.disk_spec IS NOT NULL - AND jsonb_typeof(n.disk_spec) = 'object' - AND n.disk_spec ? 'image' - ) - WHERE node IS NOT NULL; - - UPDATE node_volumes SET index=0; - UPDATE node_volumes SET device_type=''; - """, - """ - CREATE TABLE IF NOT EXISTS compute_machine_volumes ( - uuid UUID NOT NULL PRIMARY KEY, - project_id UUID NOT NULL, - name varchar(255) NOT NULL, - description varchar(255) NOT NULL, - node_volume UUID references node_volumes(uuid) ON DELETE CASCADE, - pool UUID references machine_pools(uuid) ON DELETE SET NULL, - machine UUID references machines(uuid) ON DELETE SET NULL, - size integer NOT NULL, - boot bool NOT NULL DEFAULT true, - index INTEGER NOT NULL DEFAULT 4096, - label varchar(256) NULL, - image VARCHAR(256) NULL DEFAULT NULL, - device_type VARCHAR(64) NOT NULL DEFAULT '', - status VARCHAR(32) NOT NULL - CHECK (status IN ( - 'NEW', 'IN_PROGRESS', 'ACTIVE', 'ERROR') - ) DEFAULT 'NEW', - created_at timestamp NOT NULL DEFAULT current_timestamp, - updated_at timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE INDEX IF NOT EXISTS idx_compute_machine_volumes_project_id - ON compute_machine_volumes (project_id); - """, - """ - CREATE INDEX IF NOT EXISTS idx_compute_machine_volumes_node_volume - ON compute_machine_volumes (node_volume); - """, - """ - CREATE INDEX IF NOT EXISTS idx_compute_machine_volumes_pool - ON compute_machine_volumes (pool); - """, - """ - CREATE INDEX IF NOT EXISTS idx_compute_machine_volumes_machine - ON compute_machine_volumes (machine); - """, - # Explicitly drop `agent` column to avoid any migration problem - """ - ALTER TABLE machine_pools - DROP COLUMN IF EXISTS agent; - """, - """ - ALTER TABLE machine_pools - ADD IF NOT EXISTS storage_pools JSONB[] DEFAULT '{}'; - """, - """ - ALTER TABLE machine_pools - ADD IF NOT EXISTS builder UUID DEFAULT NULL; - """, - """ - ALTER TABLE machine_pools - ADD IF NOT EXISTS agent UUID DEFAULT NULL; - """, - """ - ALTER TABLE machine_pools - ADD IF NOT EXISTS cores_ratio FLOAT NOT NULL DEFAULT 1.0; - """, - """ - ALTER TABLE machine_pools - ADD IF NOT EXISTS ram_ratio FLOAT NOT NULL DEFAULT 1.0; - """, - """ - ALTER TABLE machine_pools - ADD IF NOT EXISTS created_at timestamp NOT NULL DEFAULT current_timestamp; - """, - """ - ALTER TABLE machine_pools - ADD IF NOT EXISTS updated_at timestamp NOT NULL DEFAULT current_timestamp; - """, - """ - ALTER TABLE machine_pools - DROP CONSTRAINT IF EXISTS machine_pools_status_check; - """, - """ - ALTER TABLE machine_pools - ADD CONSTRAINT machine_pools_status_check - CHECK (status IN ('ACTIVE', 'DISABLED', 'MAINTENANCE', 'IN_PROGRESS')); - """, - """ - DROP TABLE IF EXISTS machine_agents; - """, - """ - CREATE OR REPLACE VIEW compute_nodes_without_ports AS - SELECT - nodes.uuid, - nodes.project_id, - nodes.name, - nodes.description, - nodes.cores, - nodes.ram, - nodes.node_type, - nodes.status, - nodes.created_at, - nodes.updated_at, - nodes.default_network, - nodes.node_set, - nodes.placement_policies, - nodes.disk_spec, - nodes.hostname - FROM nodes LEFT JOIN compute_ports as ports ON - nodes.uuid = ports.node WHERE ports.uuid is NULL; - """, - """ - CREATE OR REPLACE VIEW compute_unscheduled_volumes AS - SELECT - node_volumes.uuid as uuid, - node_volumes.uuid as volume - FROM node_volumes LEFT JOIN compute_machine_volumes ON - node_volumes.uuid = compute_machine_volumes.node_volume - WHERE compute_machine_volumes.uuid is NULL; - """, - """ - --- EM cannot restrict UA to delete actual resource - --- if they aren't present on DP. - ALTER TABLE em_resources - DROP CONSTRAINT em_resources_actual_resource_fkey; - ALTER TABLE em_resources - ADD CONSTRAINT em_resources_actual_resource_fkey - FOREIGN KEY (actual_resource) - REFERENCES ua_actual_resources (res_uuid) - ON DELETE SET NULL; - """, - ] - - for expression in expressions: - session.execute(expression, None) - - def downgrade(self, session): - - expressions = [ - """ - DROP VIEW IF EXISTS compute_unscheduled_volumes; - """, - """ - DROP VIEW IF EXISTS compute_nodes_without_ports; - """, - """ - DROP TABLE IF EXISTS compute_machine_volumes; - """, - """ - ALTER TABLE em_resources - DROP CONSTRAINT em_resources_actual_resource_fkey; - ALTER TABLE em_resources - ADD CONSTRAINT em_resources_actual_resource_fkey - FOREIGN KEY (actual_resource) - REFERENCES ua_actual_resources (res_uuid); - """, - """ - CREATE TABLE IF NOT EXISTS machine_agents ( - uuid UUID NOT NULL PRIMARY KEY, - name varchar(255) NOT NULL, - description varchar(255) NOT NULL, - status VARCHAR(32) NOT NULL CHECK (status IN ('ACTIVE', 'DISABLED')) - ); - """, - """ - ALTER TABLE machine_pools - DROP CONSTRAINT IF EXISTS machine_pools_status_check; - """, - """ - ALTER TABLE machine_pools - ADD CONSTRAINT machine_pools_status_check - CHECK (status IN ('ACTIVE', 'DISABLED', 'MAINTENANCE')); - """, - """ - ALTER TABLE machine_pools - DROP COLUMN IF EXISTS created_at; - """, - """ - ALTER TABLE machine_pools - DROP COLUMN IF EXISTS updated_at; - """, - """ - ALTER TABLE machine_pools - DROP COLUMN IF EXISTS builder; - """, - """ - ALTER TABLE machine_pools - DROP COLUMN IF EXISTS storage_pools; - """, - """ - ALTER TABLE machine_pools - DROP COLUMN IF EXISTS cores_ratio; - """, - """ - ALTER TABLE machine_pools - DROP COLUMN IF EXISTS ram_ratio; - """, - """ - ALTER TABLE machine_pools - ADD IF NOT EXISTS agent UUID references machine_agents(uuid) ON DELETE SET NULL; - """, - """ - ALTER TABLE node_volumes - ALTER COLUMN device_type TYPE VARCHAR(16); - ALTER TABLE node_volumes - ALTER COLUMN device_type SET NOT NULL; - """, - """ - ALTER TABLE node_volumes - DROP COLUMN IF EXISTS status; - """, - """ - ALTER TABLE node_volumes - DROP COLUMN IF EXISTS image; - """, - """ - ALTER TABLE node_volumes - DROP COLUMN IF EXISTS pool; - """, - """ - ALTER TABLE node_volumes - DROP COLUMN IF EXISTS index; - """, - """ - ALTER TABLE machines - ADD IF NOT EXISTS builder UUID references n_builders(uuid) - ON DELETE SET NULL; - """, - """ - ALTER TABLE machines - ADD IF NOT EXISTS build_status VARCHAR(32) NOT NULL - CHECK (build_status IN ('IN_BUILD', 'READY')) DEFAULT 'READY'; - """, - """ - ALTER TABLE machines - DROP COLUMN IF EXISTS block_devices; - """, - """ - ALTER TABLE compute_sets ADD COLUMN IF NOT EXISTS root_disk_size integer; - ALTER TABLE compute_sets ADD COLUMN IF NOT EXISTS image varchar(255); - - UPDATE compute_sets - SET - root_disk_size = (disk_spec->>'size')::integer, - image = disk_spec->>'image' - WHERE disk_spec IS NOT NULL - AND disk_spec->>'kind' = 'root_disk'; - - UPDATE compute_sets - SET - root_disk_size = COALESCE(root_disk_size, 0), - image = COALESCE(image, '') - WHERE root_disk_size IS NULL OR image IS NULL; - - ALTER TABLE compute_sets ALTER COLUMN image SET NOT NULL; - - ALTER TABLE compute_sets DROP COLUMN disk_spec; - """, - """ - ALTER TABLE nodes ADD COLUMN IF NOT EXISTS root_disk_size integer; - ALTER TABLE nodes ADD COLUMN IF NOT EXISTS image varchar(255); - - UPDATE nodes - SET - root_disk_size = (disk_spec->>'size')::integer, - image = disk_spec->>'image' - WHERE disk_spec IS NOT NULL - AND disk_spec->>'kind' = 'root_disk'; - - UPDATE nodes - SET - root_disk_size = COALESCE(root_disk_size, 0), - image = COALESCE(image, '') - WHERE root_disk_size IS NULL OR image IS NULL; - - ALTER TABLE nodes ALTER COLUMN image SET NOT NULL; - - ALTER TABLE nodes DROP COLUMN disk_spec; - """, - """ - ALTER TABLE nodes - DROP COLUMN IF EXISTS hostname; - """, - """ - CREATE OR REPLACE VIEW compute_nodes_without_ports AS - SELECT - nodes.uuid, - nodes.project_id, - nodes.name, - nodes.description, - nodes.cores, - nodes.ram, - nodes.image, - nodes.node_type, - nodes.status, - nodes.created_at, - nodes.updated_at, - nodes.root_disk_size, - nodes.default_network, - nodes.node_set, - nodes.placement_policies - FROM nodes LEFT JOIN compute_ports as ports ON - nodes.uuid = ports.node WHERE ports.uuid is NULL; - """, - """ - CREATE OR REPLACE VIEW machine_volumes AS - SELECT - node_volumes.uuid, - node_volumes.project_id, - node_volumes.name, - node_volumes.description, - node_volumes.node, - node_volumes.size, - node_volumes.boot, - node_volumes.label, - node_volumes.device_type, - machines.uuid as machine, - node_volumes.created_at, - node_volumes.updated_at - FROM node_volumes LEFT JOIN machines ON - node_volumes.node = machines.node; - """, - ] - - for expression in expressions: - session.execute(expression, None) - - -migration_step = MigrationStep() diff --git a/migrations/0043-add-user-source-4f5e1f.py b/migrations/0043-add-user-source-4f5e1f.py deleted file mode 100644 index bba442fb..00000000 --- a/migrations/0043-add-user-source-4f5e1f.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = [ - "0042-compute-ua-integration-4bd866.py", - ] - - @property - def migration_id(self): - return "4f5e1f94-0f37-4c24-8c37-522ce3c6c5c6" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - ALTER TABLE "iam_users" - ADD COLUMN IF NOT EXISTS "user_source" JSONB - NOT NULL DEFAULT '{"kind": "IAM"}'::jsonb; - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """ - ALTER TABLE "iam_users" - DROP COLUMN IF EXISTS "user_source"; - """, - ] - - for expression in expressions: - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0044-add-lb-ext-source-ca08ef.py b/migrations/0044-add-lb-ext-source-ca08ef.py deleted file mode 100644 index eee7b592..00000000 --- a/migrations/0044-add-lb-ext-source-ca08ef.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2025 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = [ - "0043-add-user-source-4f5e1f.py", - ] - - @property - def migration_id(self): - return "ca08ef4a-f781-4b85-82ce-9a69602f1434" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - ALTER TABLE "net_lb_vhosts" - ADD COLUMN IF NOT EXISTS "external_sources" JSONB[] NOT NULL DEFAULT '{}'; - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """ - ALTER TABLE "net_lb_vhosts" - DROP COLUMN IF EXISTS "external_sources"; - """, - ] - - for expression in expressions: - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0045-add-security-rules-7c2f6d.py b/migrations/0045-add-security-rules-7c2f6d.py deleted file mode 100644 index 8d84e8e0..00000000 --- a/migrations/0045-add-security-rules-7c2f6d.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2026 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = [ - "0044-add-lb-ext-source-ca08ef.py", - ] - - @property - def migration_id(self): - return "7c2f6d9d-9a28-4d2b-93d6-0e4f7c2a0a56" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - CREATE TABLE IF NOT EXISTS "security_rules" ( - "uuid" UUID PRIMARY KEY, - "name" VARCHAR(255) NOT NULL, - "description" VARCHAR(255) NOT NULL DEFAULT '', - "project_id" UUID NULL, - "condition" JSONB NOT NULL, - "verifier" JSONB NOT NULL, - "operator" VARCHAR(8) NOT NULL DEFAULT 'OR' - CHECK ("operator" IN ('OR', 'AND')), - "status" VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' - CHECK ("status" IN ('ACTIVE')), - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - """, - """ - CREATE INDEX IF NOT EXISTS "security_rules_name_idx" ON - "security_rules" ("name"); - """, - """ - CREATE INDEX IF NOT EXISTS "security_rules_project_id_idx" ON - "security_rules" ("project_id"); - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - tables = [ - "security_rules", - ] - - for table in tables: - self._delete_table_if_exists(session, table) - - -migration_step = MigrationStep() diff --git a/migrations/0046-init-vs-f5aaa2.py b/migrations/0046-init-vs-f5aaa2.py deleted file mode 100644 index da8ca3c7..00000000 --- a/migrations/0046-init-vs-f5aaa2.py +++ /dev/null @@ -1,149 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation -# Copyright 2026 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = ["0045-add-security-rules-7c2f6d.py"] - - @property - def migration_id(self): - return "f5aaa29d-2f90-445f-b7d1-74f36b06a6d5" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - sql_expressions = [ - """ - CREATE TABLE IF NOT EXISTS vs_profiles ( - "uuid" UUID NOT NULL PRIMARY KEY, - "name" varchar(255) NOT NULL, - "description" varchar(255) NOT NULL, - "project_id" UUID NOT NULL, - "status" VARCHAR(32) NOT NULL CHECK ( - status IN ( - 'NEW', 'IN_PROGRESS', 'ACTIVE', 'ERROR' - ) - ), - "profile_type" VARCHAR(32) NOT NULL CHECK ( - profile_type IN ( - 'GLOBAL', 'ELEMENT' - ) - ), - "active" BOOL DEFAULT 'f', - "created_at" timestamp NOT NULL DEFAULT current_timestamp, - "updated_at" timestamp NOT NULL DEFAULT current_timestamp, - UNIQUE (name) - ); - """, - """ - CREATE INDEX IF NOT EXISTS vs_profiles_project_id_idx - ON vs_profiles (project_id); - """, - """ - CREATE INDEX IF NOT EXISTS vs_profiles_profile_type_idx - ON vs_profiles (profile_type); - """, - """ - CREATE TABLE IF NOT EXISTS vs_variables ( - "uuid" UUID NOT NULL PRIMARY KEY, - "name" varchar(255) NOT NULL, - "description" varchar(255) NOT NULL, - "project_id" UUID NOT NULL, - "status" VARCHAR(32) NOT NULL CHECK ( - status IN ( - 'NEW', 'IN_PROGRESS', 'ACTIVE', 'ERROR' - ) - ), - "setter" JSONB NOT NULL, - "value" JSONB NULL DEFAULT NULL, - "created_at" timestamp NOT NULL DEFAULT current_timestamp, - "updated_at" timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE INDEX IF NOT EXISTS vs_variables_project_id_idx - ON vs_variables (project_id); - """, - """ - CREATE TABLE IF NOT EXISTS vs_values ( - "uuid" UUID NOT NULL PRIMARY KEY, - "name" varchar(255) NOT NULL, - "description" varchar(255) NOT NULL, - "project_id" UUID NOT NULL, - "status" VARCHAR(32) NOT NULL CHECK ( - status IN ( - 'NEW', 'IN_PROGRESS', 'ACTIVE', 'ERROR' - ) - ), - "value" JSONB NULL DEFAULT NULL, - "read_only" BOOL DEFAULT 'f', - "manual_selected" BOOL DEFAULT 'f', - "variable" UUID NULL DEFAULT NULL REFERENCES vs_variables("uuid") ON DELETE SET NULL, - "created_at" timestamp NOT NULL DEFAULT current_timestamp, - "updated_at" timestamp NOT NULL DEFAULT current_timestamp - ); - """, - """ - CREATE UNIQUE INDEX vs_values_one_manual_selected_per_variable - ON vs_values (variable) - WHERE manual_selected = true; - """, - """ - CREATE INDEX IF NOT EXISTS vs_values_project_id_idx - ON vs_values (project_id); - """, - """ - ALTER TABLE em_elements - ADD COLUMN IF NOT EXISTS profile UUID NULL DEFAULT NULL REFERENCES vs_profiles("uuid") ON DELETE RESTRICT; - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - def downgrade(self, session): - sql_expressions = [ - """ - ALTER TABLE em_elements - DROP COLUMN IF EXISTS profile; - """, - ] - - tables = [ - "vs_values", - "vs_variables", - "vs_profiles", - ] - views = [] - - for view_name in views: - self._delete_view_if_exists(session, view_name) - - for expr in sql_expressions: - session.execute(expr, None) - - for table_name in tables: - self._delete_table_if_exists(session, table_name) - - -migration_step = MigrationStep() diff --git a/migrations/0047-sdk-1-3-0-migration-33fdc9.py b/migrations/0047-sdk-1-3-0-migration-33fdc9.py deleted file mode 100644 index 367b1934..00000000 --- a/migrations/0047-sdk-1-3-0-migration-33fdc9.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import os - -from gcl_sdk import migrations as sdk_migrations -from gcl_sdk.common import utils as sdk_utils -from restalchemy.storage.sql import migrations - -SDK_MIGRATION_FILE_NAME = "0004-ua-resources-relations-e9a811" - - -LOG = logging.getLogger(__name__) - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = ["0046-init-vs-f5aaa2.py"] - - @property - def migration_id(self): - return "33fdc9db-9557-4674-a6b7-8040a1908fc4" - - @property - def is_manual(self): - return False - - def _get_migration_engine(self): - sdk_migration_path = os.path.dirname(sdk_migrations.__file__) - return sdk_utils.MigrationEngine(migrations_path=sdk_migration_path) - - def upgrade(self, session): - migration_engine = self._get_migration_engine() - migration_engine.apply_migration(SDK_MIGRATION_FILE_NAME, session) - - def downgrade(self, session): - migration_engine = self._get_migration_engine() - migration_engine.rollback_migration(SDK_MIGRATION_FILE_NAME, session) - - -migration_step = MigrationStep() diff --git a/migrations/0048-iam-nonce-optional-c6e9f6.py b/migrations/0048-iam-nonce-optional-c6e9f6.py deleted file mode 100644 index 2c1b72b7..00000000 --- a/migrations/0048-iam-nonce-optional-c6e9f6.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2026 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = [ - "0047-sdk-1-3-0-migration-33fdc9.py", - ] - - @property - def migration_id(self): - return "c6e9f66a-086c-4e09-bcbd-80a2a4a6db14" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - ALTER TABLE "iam_idp" - ADD COLUMN IF NOT EXISTS "nonce_required" BOOLEAN - NOT NULL DEFAULT TRUE; - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """ - ALTER TABLE "iam_idp" - DROP COLUMN IF EXISTS "nonce_required"; - """, - ] - - for expression in expressions: - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0049-lb-add-proxy-protocol-from-ef8f58.py b/migrations/0049-lb-add-proxy-protocol-from-ef8f58.py deleted file mode 100644 index 9640ebd5..00000000 --- a/migrations/0049-lb-add-proxy-protocol-from-ef8f58.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2026 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = [ - "0048-iam-nonce-optional-c6e9f6.py", - ] - - @property - def migration_id(self): - return "ef8f58c7-1279-49db-9824-1e0aab090c0b" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - ALTER TABLE "net_lb_vhosts" - ADD COLUMN IF NOT EXISTS "proxy_protocol_from" VARCHAR(18); - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """ - ALTER TABLE "net_lb_vhosts" - DROP COLUMN IF EXISTS "proxy_protocol_from"; - """, - ] - - for expression in expressions: - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0050-subnet-source-6c071d.py b/migrations/0050-subnet-source-6c071d.py deleted file mode 100644 index 60341f48..00000000 --- a/migrations/0050-subnet-source-6c071d.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2026 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = [ - "0049-lb-add-proxy-protocol-from-ef8f58.py", - ] - - @property - def migration_id(self): - return "6c071d83-8fdf-45f3-90aa-cfde1898d3f7" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - ALTER TABLE "compute_ports" - ADD COLUMN IF NOT EXISTS "source" VARCHAR(128) NULL - DEFAULT NULL; - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """ - ALTER TABLE "compute_ports" - DROP COLUMN IF EXISTS "source"; - """, - ] - - for expression in expressions: - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0051-sdk-1-5-0-migration-eea262.py b/migrations/0051-sdk-1-5-0-migration-eea262.py deleted file mode 100644 index 0fb73f08..00000000 --- a/migrations/0051-sdk-1-5-0-migration-eea262.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import os - -from gcl_sdk import migrations as sdk_migrations -from gcl_sdk.common import utils as sdk_utils -from restalchemy.storage.sql import migrations - -SDK_MIGRATION_FILE_NAME = "0005-ua-api-encryption-keys-2f8d3a" - - -LOG = logging.getLogger(__name__) - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = ["0050-subnet-source-6c071d.py"] - - @property - def migration_id(self): - return "eea262b3-ec9f-4547-964b-5801857fd5ee" - - @property - def is_manual(self): - return False - - def _get_migration_engine(self): - sdk_migration_path = os.path.dirname(sdk_migrations.__file__) - return sdk_utils.MigrationEngine(migrations_path=sdk_migration_path) - - def upgrade(self, session): - migration_engine = self._get_migration_engine() - migration_engine.apply_migration(SDK_MIGRATION_FILE_NAME, session) - - def downgrade(self, session): - migration_engine = self._get_migration_engine() - migration_engine.rollback_migration(SDK_MIGRATION_FILE_NAME, session) - - -migration_step = MigrationStep() diff --git a/migrations/0052-iam-user-custom-props-bc80b5.py b/migrations/0052-iam-user-custom-props-bc80b5.py deleted file mode 100644 index f689a246..00000000 --- a/migrations/0052-iam-user-custom-props-bc80b5.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2026 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = [ - "0051-sdk-1-5-0-migration-eea262.py", - ] - - @property - def migration_id(self): - return "bc80b5db-ee1e-490c-8b17-6b80fc096475" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - ALTER TABLE "iam_users" - ADD COLUMN IF NOT EXISTS "custom_props" JSONB NULL DEFAULT NULL; - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """ - ALTER TABLE "iam_users" - DROP COLUMN IF EXISTS "custom_props"; - """, - ] - - for expression in expressions: - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0053-lb-node-secret-set-permissions-11c9a8.py b/migrations/0053-lb-node-secret-set-permissions-11c9a8.py deleted file mode 100644 index 09eb17a6..00000000 --- a/migrations/0053-lb-node-secret-set-permissions-11c9a8.py +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright 2025 Genesis Corporation. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid as sys_uuid - -from restalchemy.storage.sql import migrations - -NS_UUID = sys_uuid.UUID("dfd0c604-607f-4260-981f-374f88435ea0") -EXORDOS_CORE_ORG_UUID = "11111111-1111-1111-1111-111111111111" -OWNER_ROLE_UUID = "726f6c65-0000-0000-0000-000000000002" - -# Network LB permissions -NETWORK_LB_PERMISSIONS = ( - # Network - ("network.lb.read", "List and read load balancers"), - ("network.lb.create", "Create load balancers"), - ("network.lb.update", "Update load balancers"), - ("network.lb.delete", "Delete load balancers"), - ("network.lb_vhost.read", "List and read LB virtual hosts"), - ("network.lb_vhost.create", "Create LB virtual hosts"), - ("network.lb_vhost.update", "Update LB virtual hosts"), - ("network.lb_vhost.delete", "Delete LB virtual hosts"), - ("network.lb_vhost_route.read", "List and read LB vhost routes"), - ("network.lb_vhost_route.create", "Create LB vhost routes"), - ("network.lb_vhost_route.update", "Update LB vhost routes"), - ("network.lb_vhost_route.delete", "Delete LB vhost routes"), - ("network.lb_backendpool.read", "List and read LB backend pools"), - ("network.lb_backendpool.create", "Create LB backend pools"), - ("network.lb_backendpool.update", "Update LB backend pools"), - ("network.lb_backendpool.delete", "Delete LB backend pools"), - # Compute - ("compute.node.get_private_key", "Get node(s) agent private key"), - ("compute.node_set.get_private_key", "Get node(s) agent private key"), - # Config - ("config.config.read", "List and read configs"), - ("config.config.create", "Create configs"), - ("config.config.update", "Update configs"), - ("config.config.delete", "Delete configs"), - # Services - ("em.service.read", "List and read services"), - ("em.service.create", "Create services"), - ("em.service.update", "Update services"), - ("em.service.delete", "Delete services"), -) - - -def _u(name: str) -> str: - return str(sys_uuid.uuid5(NS_UUID, name)) - - -COMPUTE_PROJECT_UUID = _u("GenesisCore-Compute-Project") - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0052-iam-user-custom-props-bc80b5.py"] - - @property - def migration_id(self): - return "11c9a8bc-cc22-42d1-a8f8-cbfa21707fce" - - @property - def is_manual(self): - return False - - def _create_permissions(self, session): - for name, description in NETWORK_LB_PERMISSIONS: - session.execute(f""" - INSERT INTO iam_permissions ( - uuid, name, description - ) VALUES ( - '{_u(name)}', - '{name}', - '{description}' - ) - ON CONFLICT (uuid) DO NOTHING; - """) - - def _create_bindings(self, session): - for name, _ in NETWORK_LB_PERMISSIONS: - session.execute(f""" - INSERT INTO iam_binding_permissions ( - uuid, role, permission, project_id - ) VALUES ( - '{_u("binding." + name)}', - '{OWNER_ROLE_UUID}', - '{_u(name)}', - '{COMPUTE_PROJECT_UUID}' - ); - """) - - def upgrade(self, session): - self._create_permissions(session) - self._create_bindings(session) - - def _delete_bindings(self, session): - for name, _ in NETWORK_LB_PERMISSIONS: - session.execute(f""" - DELETE FROM iam_binding_permissions - WHERE - permission = '{_u(name)}'; - """) - - def _delete_permissions(self, session): - for name, _ in NETWORK_LB_PERMISSIONS: - session.execute(f""" - DELETE FROM iam_permissions - WHERE uuid = '{_u(name)}'; - """) - - def downgrade(self, session): - self._delete_bindings(session) - self._delete_permissions(session) - - -migration_step = MigrationStep() diff --git a/migrations/0054-iam-idp-callback-kind-3a6c1b.py b/migrations/0054-iam-idp-callback-kind-3a6c1b.py deleted file mode 100644 index 943c2703..00000000 --- a/migrations/0054-iam-idp-callback-kind-3a6c1b.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright 2026 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = [ - "0053-lb-node-secret-set-permissions-11c9a8.py", - ] - - @property - def migration_id(self): - return "3a6c1b7a-20a0-4d3b-8896-d183f5eb2e6b" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - ALTER TABLE "iam_idp" - ADD COLUMN IF NOT EXISTS "callback" JSONB - NOT NULL DEFAULT '{"kind": "callback_uri", "callback": ""}'::jsonb; - """, - """ - UPDATE "iam_idp" - SET "callback" = jsonb_build_object( - 'kind', 'callback_uri', - 'callback', COALESCE("callback_uri", '') - ); - """, - """ - ALTER TABLE "iam_idp" - DROP COLUMN IF EXISTS "callback_uri"; - """, - """ - DELETE FROM "iam_idp_authorization_info"; - """, - """ - ALTER TABLE "iam_idp_authorization_info" - ADD COLUMN IF NOT EXISTS "redirect_uri" VARCHAR(256) - NOT NULL DEFAULT ''; - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """ - ALTER TABLE "iam_idp" - ADD COLUMN IF NOT EXISTS "callback_uri" VARCHAR(256) - NOT NULL DEFAULT ''; - """, - """ - UPDATE "iam_idp" - SET "callback_uri" = COALESCE("callback"->>'callback', ''); - """, - """ - ALTER TABLE "iam_idp" - DROP COLUMN IF EXISTS "callback"; - """, - """ - ALTER TABLE "iam_idp_authorization_info" - DROP COLUMN IF EXISTS "redirect_uri"; - """, - ] - - for expression in expressions: - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0055-iam-user-type-8d7f2a.py b/migrations/0055-iam-user-type-8d7f2a.py deleted file mode 100644 index 681e6e42..00000000 --- a/migrations/0055-iam-user-type-8d7f2a.py +++ /dev/null @@ -1,132 +0,0 @@ -# Copyright 2026 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid as sys_uuid - -from restalchemy.storage.sql import migrations - -NS_UUID = sys_uuid.UUID("dfd0c604-607f-4260-981f-374f88435ea0") -EXORDOS_CORE_ORG_UUID = "11111111-1111-1111-1111-111111111111" -OWNER_ROLE_UUID = "726f6c65-0000-0000-0000-000000000002" - -SERVICE_TOKEN_PERMISSIONS = ( - ("iam.service_token.create", "Create service account tokens"), -) - - -def _u(name: str) -> str: - return str(sys_uuid.uuid5(NS_UUID, name)) - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = [ - "0054-iam-idp-callback-kind-3a6c1b.py", - ] - - @property - def migration_id(self): - return "8d7f2a9b-4c5d-4e8f-9a1b-2c3d4e5f6a7b" - - @property - def is_manual(self): - return False - - def _create_permissions(self, session): - for name, description in SERVICE_TOKEN_PERMISSIONS: - session.execute(f""" - INSERT INTO iam_permissions ( - uuid, name, description - ) VALUES ( - '{_u(name)}', - '{name}', - '{description}' - ) - ON CONFLICT (uuid) DO NOTHING; - """) - - def _create_bindings(self, session): - for name, _ in SERVICE_TOKEN_PERMISSIONS: - session.execute(f""" - INSERT INTO iam_binding_permissions ( - uuid, role, permission, project_id - ) VALUES ( - gen_random_uuid(), - '{OWNER_ROLE_UUID}', - '{_u(name)}', - NULL - ); - """) - - def upgrade(self, session): - # Create user type enum and column - expressions = [ - """ - DO $$ BEGIN - CREATE TYPE user_type_enum AS ENUM ('user', 'service'); - EXCEPTION - WHEN duplicate_object THEN null; - END $$; - """, - """ - ALTER TABLE "iam_users" - ADD COLUMN IF NOT EXISTS "type" user_type_enum NOT NULL DEFAULT 'user'; - """, - ] - - for expression in expressions: - session.execute(expression) - - # Create service token permissions and bindings - self._create_permissions(session) - self._create_bindings(session) - - def _delete_bindings(self, session): - for name, _ in SERVICE_TOKEN_PERMISSIONS: - session.execute(f""" - DELETE FROM iam_binding_permissions - WHERE - permission = '{_u(name)}'; - """) - - def _delete_permissions(self, session): - for name, _ in SERVICE_TOKEN_PERMISSIONS: - session.execute(f""" - DELETE FROM iam_permissions - WHERE uuid = '{_u(name)}'; - """) - - def downgrade(self, session): - # Delete service token permissions and bindings first - self._delete_bindings(session) - self._delete_permissions(session) - - # Then drop user type column and enum - expressions = [ - """ - ALTER TABLE "iam_users" - DROP COLUMN IF EXISTS "type"; - """, - """ - DROP TYPE IF EXISTS user_type_enum; - """, - ] - - for expression in expressions: - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0056-iam-user-create-perm-3e0dc5.py b/migrations/0056-iam-user-create-perm-3e0dc5.py deleted file mode 100644 index 08b3d848..00000000 --- a/migrations/0056-iam-user-create-perm-3e0dc5.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2025 Genesis Corporation. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid as sys_uuid - -from restalchemy.storage.sql import migrations - -NS_UUID = sys_uuid.UUID("dfd0c604-607f-4260-981f-374f88435ea0") - -# IAM user permissions -IAM_USER_PERMISSIONS = (("iam.user.create", "Create IAM users"),) - - -def _u(name: str) -> str: - return str(sys_uuid.uuid5(NS_UUID, name)) - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0055-iam-user-type-8d7f2a.py"] - - @property - def migration_id(self): - return "3e0dc5dd-1d40-444c-ae03-4817da87b0bc" - - @property - def is_manual(self): - return False - - def _create_permissions(self, session): - for name, description in IAM_USER_PERMISSIONS: - session.execute(f""" - INSERT INTO iam_permissions ( - uuid, name, description - ) VALUES ( - '{_u(name)}', - '{name}', - '{description}' - ) - ON CONFLICT (uuid) DO NOTHING; - """) - - def upgrade(self, session): - self._create_permissions(session) - - def _delete_bindings(self, session): - for name, _ in IAM_USER_PERMISSIONS: - session.execute(f""" - DELETE FROM iam_binding_permissions - WHERE permission = '{_u(name)}'; - """) - - def _delete_permissions(self, session): - for name, _ in IAM_USER_PERMISSIONS: - session.execute(f""" - DELETE FROM iam_permissions - WHERE uuid = '{_u(name)}'; - """) - - def downgrade(self, session): - self._delete_bindings(session) - self._delete_permissions(session) - for name, _ in IAM_USER_PERMISSIONS: - session.execute(f""" - DELETE FROM iam_permissions - WHERE uuid = '{_u(name)}'; - """) - - -migration_step = MigrationStep() diff --git a/migrations/0057-add-project-id-requirements-to-element-3bc138.py b/migrations/0057-add-project-id-requirements-to-element-3bc138.py deleted file mode 100644 index 7ea17195..00000000 --- a/migrations/0057-add-project-id-requirements-to-element-3bc138.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = ["0056-iam-user-create-perm-3e0dc5.py"] - - @property - def migration_id(self): - return "3bc13835-4fe9-4f04-b394-60a0748d4ea1" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - ALTER TABLE "em_elements" - ADD COLUMN IF NOT EXISTS "project_id" UUID DEFAULT NULL; - """, - """ - ALTER TABLE "em_elements" - ADD COLUMN IF NOT EXISTS "requirements" JSONB NOT NULL DEFAULT '{}'; - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """ - ALTER TABLE "em_elements" DROP COLUMN IF EXISTS "project_id"; - """, - """ - ALTER TABLE "em_elements" DROP COLUMN IF EXISTS "requirements"; - """, - ] - - for expression in expressions: - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0058-copy-iam-users-target-to-actual-resources-a1b2c3.py b/migrations/0058-copy-iam-users-target-to-actual-resources-a1b2c3.py deleted file mode 100644 index 6ab7ef0b..00000000 --- a/migrations/0058-copy-iam-users-target-to-actual-resources-a1b2c3.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2026 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = ["0057-add-project-id-requirements-to-element-3bc138.py"] - - @property - def migration_id(self): - return "a1b2c3d4-e5f6-7890-abcd-ef1234567890" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - INSERT INTO ua_actual_resources ( - uuid, - kind, - res_uuid, - value, - status, - node, - hash, - full_hash, - created_at, - updated_at - ) - SELECT - uuid, - kind, - res_uuid, - value, - status, - node, - hash, - full_hash, - created_at, - updated_at - FROM ua_target_resources - WHERE kind = 'em_core_iam_users' - ON CONFLICT (res_uuid) DO NOTHING; - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """ - DELETE FROM ua_actual_resources - WHERE res_uuid IN ( - SELECT res_uuid - FROM ua_target_resources - WHERE kind = 'em_core_iam_users' - ); - """, - ] - - for expression in expressions: - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0059-dns-sync-to-ecosystem-secret-len-a7b3c1.py b/migrations/0059-dns-sync-to-ecosystem-secret-len-a7b3c1.py deleted file mode 100644 index 48047912..00000000 --- a/migrations/0059-dns-sync-to-ecosystem-secret-len-a7b3c1.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2026 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = [ - "0058-copy-iam-users-target-to-actual-resources-a1b2c3.py", - ] - - @property - def migration_id(self): - return "a7b3c1d2-5e4f-4a3b-9c8d-7e6f5a4b3c2d" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - ALTER TABLE "dns_domains" - ADD COLUMN IF NOT EXISTS "sync_to_ecosystem" - BOOLEAN NOT NULL DEFAULT FALSE; - """, - """ - CREATE INDEX IF NOT EXISTS dns_records_updated_at_idx - ON dns_records (updated_at); - """, - """ - ALTER TABLE "secret_passwords" - ADD COLUMN IF NOT EXISTS "default_length" - INTEGER NOT NULL DEFAULT 32; - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """ - DROP INDEX IF EXISTS dns_records_updated_at_idx; - """, - """ - ALTER TABLE "secret_passwords" - DROP COLUMN IF EXISTS "default_length"; - """, - """ - ALTER TABLE "dns_domains" - DROP COLUMN IF EXISTS "sync_to_ecosystem"; - """, - ] - - for expression in expressions: - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0060-openapi-spec_e-m-link-02ef0a.py b/migrations/0060-openapi-spec_e-m-link-02ef0a.py deleted file mode 100644 index 5457d74d..00000000 --- a/migrations/0060-openapi-spec_e-m-link-02ef0a.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = ["0059-dns-sync-to-ecosystem-secret-len-a7b3c1.py"] - - @property - def migration_id(self): - return "02ef0abb-c4ab-4d7b-86a6-e8f847df64d4" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - ALTER TABLE - em_manifests - ADD COLUMN IF NOT EXISTS - openapi_spec TEXT NULL DEFAULT NULL; - """, - """ - ALTER TABLE - em_elements - ADD COLUMN IF NOT EXISTS - manifest UUID NULL DEFAULT NULL references em_manifests(uuid) ON DELETE RESTRICT; - """, - """ - UPDATE em_elements - SET manifest = em_manifests.uuid - FROM em_manifests - WHERE em_elements.uuid = em_manifests.uuid - AND em_elements.manifest IS NULL; - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """ - ALTER TABLE em_manifests DROP COLUMN IF EXISTS - openapi_spec; - """, - """ - ALTER TABLE em_elements DROP COLUMN IF EXISTS - manifest; - """, - ] - - for expression in expressions: - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0061-rename-rule-verifier-to-action-a3b4c5.py b/migrations/0061-rename-rule-verifier-to-action-a3b4c5.py deleted file mode 100644 index 2ff06171..00000000 --- a/migrations/0061-rename-rule-verifier-to-action-a3b4c5.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2026 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = [ - "0060-openapi-spec_e-m-link-02ef0a.py", - ] - - @property - def migration_id(self): - return "a3b4c5d6-7e8f-4a9b-8c0d-1e2f3a4b5c6d" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - expressions = [ - """ - ALTER TABLE "security_rules" - RENAME COLUMN "verifier" TO "action"; - """, - ] - - for expression in expressions: - session.execute(expression) - - def downgrade(self, session): - expressions = [ - """ - ALTER TABLE "security_rules" - RENAME COLUMN "action" TO "verifier"; - """, - ] - - for expression in expressions: - session.execute(expression) - - -migration_step = MigrationStep() diff --git a/migrations/0062-convert-varchar-to-jsonb-4d5e6f.py b/migrations/0062-convert-varchar-to-jsonb-4d5e6f.py deleted file mode 100644 index 2a98c95c..00000000 --- a/migrations/0062-convert-varchar-to-jsonb-4d5e6f.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2026 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging - -from restalchemy.storage.sql import migrations - -LOG = logging.getLogger(__name__) - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0061-rename-rule-verifier-to-action-a3b4c5.py"] - - @property - def migration_id(self): - return "4d5e6f78-9abc-def0-1234-56789abcdef0" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - # Remove defaults before changing column type - drop_default_expressions = [ - "ALTER TABLE compute_networks ALTER COLUMN driver_spec DROP DEFAULT;", - ] - - for expr in drop_default_expressions: - session.execute(expr, None) - - # Convert varchar columns to jsonb - sql_expressions = [ - """ - ALTER TABLE compute_networks - ALTER COLUMN driver_spec TYPE jsonb - USING driver_spec::jsonb; - """, - """ - ALTER TABLE machine_pools - ALTER COLUMN driver_spec TYPE jsonb - USING driver_spec::jsonb; - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - # Set new defaults for jsonb columns - default_expressions = [ - "ALTER TABLE compute_networks ALTER COLUMN driver_spec SET DEFAULT '{}'::jsonb;", - "ALTER TABLE machine_pools ALTER COLUMN driver_spec SET DEFAULT '{}'::jsonb;", - ] - - for expr in default_expressions: - session.execute(expr, None) - - def downgrade(self, session): - # Remove defaults before changing column type - drop_default_expressions = [ - "ALTER TABLE compute_networks ALTER COLUMN driver_spec DROP DEFAULT;", - ] - - for expr in drop_default_expressions: - session.execute(expr, None) - - # Convert jsonb columns to varchar - sql_expressions = [ - """ - ALTER TABLE compute_networks - ALTER COLUMN driver_spec TYPE varchar(512) - USING driver_spec::varchar(512); - """, - """ - ALTER TABLE machine_pools - ALTER COLUMN driver_spec TYPE varchar(512) - USING driver_spec::varchar(512); - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - # Set defaults for varchar columns - default_expressions = [ - "ALTER TABLE compute_networks ALTER COLUMN driver_spec SET DEFAULT '{}';", - ] - - for expr in default_expressions: - session.execute(expr, None) - - -migration_step = MigrationStep() diff --git a/migrations/0063-add-driver-spec-connection-uri-unique-index-eb26ec.py b/migrations/0063-add-driver-spec-connection-uri-unique-index-eb26ec.py deleted file mode 100644 index 6fe81ed0..00000000 --- a/migrations/0063-add-driver-spec-connection-uri-unique-index-eb26ec.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2026 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging - -from restalchemy.storage.sql import migrations - -LOG = logging.getLogger(__name__) - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0062-convert-varchar-to-jsonb-4d5e6f.py"] - - @property - def migration_id(self): - return "eb26ecbc-ab9e-427d-af94-b11247589ec0" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - sql_expressions = [ - """ - CREATE UNIQUE INDEX IF NOT EXISTS machine_pools_driver_spec_connection_uri_idx - ON machine_pools ((driver_spec->>'connection_uri')); - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - def downgrade(self, session): - sql_expressions = [ - """ - DROP INDEX IF EXISTS machine_pools_driver_spec_connection_uri_idx; - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - -migration_step = MigrationStep() diff --git a/migrations/0064-init-repo-tables-645142.py b/migrations/0064-init-repo-tables-645142.py deleted file mode 100644 index c54e576f..00000000 --- a/migrations/0064-init-repo-tables-645142.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright 2026 Genesis Corporation. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0063-add-driver-spec-connection-uri-unique-index-eb26ec.py"] - - @property - def migration_id(self): - return "6451425f-18b1-49c4-b5f8-94702141e880" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - session.execute( - """ - CREATE TABLE repo_repositories ( - uuid UUID PRIMARY KEY, - name VARCHAR(255) NOT NULL, - description TEXT NOT NULL DEFAULT '', - project_id UUID NOT NULL, - status VARCHAR(32) NOT NULL DEFAULT 'NEW', - priority INT NOT NULL DEFAULT 2048, - refresh_rate INT NOT NULL DEFAULT 3600, - sync_mode VARCHAR(32) NOT NULL DEFAULT 'copy', - driver_spec JSONB, - next_refresh TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - - CREATE INDEX ON repo_repositories(project_id); - CREATE INDEX ON repo_repositories(status); - CREATE UNIQUE INDEX ON repo_repositories(project_id, name); - CREATE UNIQUE INDEX ON repo_repositories(driver_spec); - - CREATE TABLE repo_elements ( - uuid UUID PRIMARY KEY, - name VARCHAR(255) NOT NULL, - description TEXT NOT NULL DEFAULT '', - project_id UUID NOT NULL, - repository UUID NOT NULL REFERENCES repo_repositories(uuid) ON DELETE RESTRICT, - version VARCHAR(255) NOT NULL, - status VARCHAR(32) NOT NULL DEFAULT 'NEW', - installation_state VARCHAR(32) NOT NULL DEFAULT 'UNINSTALLED', - manifest JSONB DEFAULT '{}', - specification JSONB DEFAULT '{}', - inventory JSONB DEFAULT '{}', - element UUID REFERENCES em_elements(uuid) ON DELETE SET NULL, - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - - CREATE INDEX ON repo_elements(project_id); - CREATE INDEX ON repo_elements(repository); - CREATE INDEX ON repo_elements(status); - CREATE INDEX ON repo_elements(name); - CREATE INDEX ON repo_elements(installation_state); - CREATE INDEX ON repo_elements(name, installation_state); - CREATE UNIQUE INDEX ON repo_elements(repository, name, version); - - CREATE TABLE repo_artifacts ( - uuid UUID PRIMARY KEY, - project_id UUID NOT NULL, - element UUID NOT NULL REFERENCES repo_elements(uuid) ON DELETE CASCADE, - urn VARCHAR(2048) NOT NULL, - uri VARCHAR(2048) NOT NULL - ); - - CREATE INDEX ON repo_artifacts(project_id); - CREATE INDEX ON repo_artifacts(element); - CREATE UNIQUE INDEX ON repo_artifacts(element, urn); - - CREATE TABLE repo_element_deps_bindings ( - uuid UUID PRIMARY KEY, - element UUID NOT NULL REFERENCES repo_elements(uuid) ON DELETE CASCADE, - depends_on UUID NOT NULL REFERENCES repo_elements(uuid) ON DELETE CASCADE - ); - - CREATE INDEX ON repo_element_deps_bindings(element); - CREATE INDEX ON repo_element_deps_bindings(depends_on); - CREATE UNIQUE INDEX ON repo_element_deps_bindings(element, depends_on); - """ - ) - - def downgrade(self, session): - self._delete_table_if_exists(session, "repo_element_deps_bindings") - self._delete_table_if_exists(session, "repo_artifacts") - self._delete_table_if_exists(session, "repo_elements") - self._delete_table_if_exists(session, "repo_repositories") - - -migration_step = MigrationStep() diff --git a/migrations/0065-registration-client-auto-provision-b7f2d9.py b/migrations/0065-registration-client-auto-provision-b7f2d9.py deleted file mode 100644 index 4aef3b1c..00000000 --- a/migrations/0065-registration-client-auto-provision-b7f2d9.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2026 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging - -from restalchemy.storage.sql import migrations - -LOG = logging.getLogger(__name__) - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0064-init-repo-tables-645142.py"] - - @property - def migration_id(self): - return "3c9d1f47-52ab-4e0e-9a86-7d02b64c1e58" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - sql_expressions = [ - """ - ALTER TABLE "iam_clients" - ADD COLUMN IF NOT EXISTS "registration_auto_provision" - BOOLEAN NOT NULL DEFAULT TRUE; - """, - """ - ALTER TABLE "iam_users" - ADD COLUMN IF NOT EXISTS "registration_client" UUID DEFAULT NULL - REFERENCES "iam_clients" ("uuid") ON DELETE SET NULL; - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - def downgrade(self, session): - sql_expressions = [ - """ - ALTER TABLE "iam_users" - DROP COLUMN IF EXISTS "registration_client"; - """, - """ - ALTER TABLE "iam_clients" - DROP COLUMN IF EXISTS "registration_auto_provision"; - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - -migration_step = MigrationStep() diff --git a/migrations/0066-machine-pools-driver-spec-kind-migration-138d02.py b/migrations/0066-machine-pools-driver-spec-kind-migration-138d02.py deleted file mode 100644 index 0695555d..00000000 --- a/migrations/0066-machine-pools-driver-spec-kind-migration-138d02.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2026 Genesis Corporation -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging - -from restalchemy.storage.sql import migrations - -LOG = logging.getLogger(__name__) - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = [ - "0065-registration-client-auto-provision-b7f2d9.py", - ] - - @property - def migration_id(self): - return "138d02f4-c3db-45cc-ba81-f3153c211731" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - # Rename "driver" key to "kind" in machine_pools.driver_spec JSONB - # column. Migrate empty '{}' specs to dummy spec since driver_spec - # is now a required field. - sql_expressions = [ - """ - UPDATE machine_pools - SET driver_spec = jsonb_set( - driver_spec - 'driver', - '{kind}', - driver_spec->'driver' - ), - updated_at = current_timestamp - WHERE driver_spec ? 'driver'; - """, - """ - ALTER TABLE machine_pools ALTER COLUMN driver_spec DROP DEFAULT; - """, - """ - UPDATE machine_pools - SET driver_spec = '{"kind": "dummy"}'::jsonb, - updated_at = current_timestamp - WHERE driver_spec = '{}'::jsonb; - """, - # Drop the unique index on connection_uri since - # exordos_local_hyper pools may share the same connection_uri. - """ - DROP INDEX IF EXISTS machine_pools_driver_spec_connection_uri_idx; - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - def downgrade(self, session): - sql_expressions = [ - """ - UPDATE machine_pools - SET driver_spec = jsonb_set( - driver_spec - 'kind', - '{driver}', - driver_spec->'kind' - ), - updated_at = current_timestamp - WHERE driver_spec ? 'kind'; - """, - """ - ALTER TABLE machine_pools - ALTER COLUMN driver_spec SET DEFAULT '{}'::jsonb; - """, - """ - UPDATE machine_pools - SET driver_spec = '{}'::jsonb, - updated_at = current_timestamp - WHERE driver_spec = '{"kind": "dummy"}'::jsonb; - """, - """ - CREATE UNIQUE INDEX IF NOT EXISTS machine_pools_driver_spec_connection_uri_idx - ON machine_pools ((driver_spec->>'connection_uri')); - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - -migration_step = MigrationStep() diff --git a/migrations/0067-init-border-ec37b4.py b/migrations/0067-init-border-ec37b4.py deleted file mode 100644 index 8115a34b..00000000 --- a/migrations/0067-init-border-ec37b4.py +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright 2026 Genesis Corporation. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid as sys_uuid - -from restalchemy.storage.sql import migrations - -# Same namespace/role/project as 0053 (network.lb permissions): border is -# the second network resource driven by project owners (and, via manifest -# bindings, by the ecosystem's service user for managed realms). -NS_UUID = sys_uuid.UUID("dfd0c604-607f-4260-981f-374f88435ea0") -OWNER_ROLE_UUID = "726f6c65-0000-0000-0000-000000000002" - -BORDER_PERMISSIONS = ( - ("network.border.read", "List and read borders (NAT gateways)"), - ("network.border.create", "Create borders (NAT gateways)"), - ("network.border.update", "Update borders (NAT gateways)"), - ("network.border.delete", "Delete borders (NAT gateways)"), -) - - -def _u(name: str) -> str: - return str(sys_uuid.uuid5(NS_UUID, name)) - - -COMPUTE_PROJECT_UUID = _u("GenesisCore-Compute-Project") - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = ["0066-machine-pools-driver-spec-kind-migration-138d02.py"] - - @property - def migration_id(self): - return "ec37b4c7-5218-40af-a8cb-c00e78c16809" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - # A border is machine-managed and reconciled as one flat resource: - # SNAT/DNAT rules are carried inline (restalchemy `types.List()` - # maps to a postgres jsonb[] array, like net_lb.external_sources). - # `type` is the deployment shape, calque of net_lb.type: core_agent - # (default, core node's agent) or core (dedicated VM); an explicitly - # pinned `node` keeps winning over `type`. `ipsv4` are the public - # IPv4s of a `core` border VM (like net_lb.ipsv4); NOT NULL + - # default: a NULL breaks TypedList restore on pre-existing rows. - expressions = [ - """\ -CREATE TABLE net_border ( - uuid UUID PRIMARY KEY, - name VARCHAR(255) NOT NULL, - description TEXT, - project_id UUID NOT NULL, - status VARCHAR(64) NOT NULL DEFAULT 'NEW', - created_at TIMESTAMP NOT NULL, - updated_at TIMESTAMP NOT NULL, - node UUID, - snat_rules JSONB[] NOT NULL DEFAULT '{}', - forwards JSONB[] NOT NULL DEFAULT '{}', - type JSONB NOT NULL DEFAULT '{"kind": "core_agent"}', - ipsv4 varchar(15)[] NOT NULL DEFAULT '{}' -); - -CREATE INDEX ON net_border(project_id, name); -""", - ] - - for expression in expressions: - session.execute(expression, None) - - for name, description in BORDER_PERMISSIONS: - session.execute(f""" - INSERT INTO iam_permissions ( - uuid, name, description - ) VALUES ( - '{_u(name)}', - '{name}', - '{description}' - ) - ON CONFLICT (uuid) DO NOTHING; - """) - session.execute(f""" - INSERT INTO iam_binding_permissions ( - uuid, role, permission, project_id - ) VALUES ( - '{_u("binding." + name)}', - '{OWNER_ROLE_UUID}', - '{_u(name)}', - '{COMPUTE_PROJECT_UUID}' - ) - ON CONFLICT (uuid) DO NOTHING; - """) - - def downgrade(self, session): - for name, _ in BORDER_PERMISSIONS: - session.execute(f""" - DELETE FROM iam_binding_permissions - WHERE permission = '{_u(name)}'; - """) - session.execute(f""" - DELETE FROM iam_permissions - WHERE uuid = '{_u(name)}'; - """) - - self._delete_table_if_exists(session, "net_border") - - -migration_step = MigrationStep() diff --git a/migrations/0068-fix-resource-status-hash-check-437c89.py b/migrations/0068-fix-resource-status-hash-check-437c89.py deleted file mode 100644 index 41f7f4cb..00000000 --- a/migrations/0068-fix-resource-status-hash-check-437c89.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright 2026 Genesis Corporation. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = [ - "0067-init-border-ec37b4.py", - ] - - @property - def migration_id(self): - return "437c8950-3580-406a-aaae-48f9aeac42c2" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - session.execute( - """ - CREATE OR REPLACE VIEW "em_incorrect_resource_statuses_view" AS - SELECT - "er"."uuid" AS "uuid", - "er"."status" AS "current_status", - ( - CASE - WHEN "utr"."hash" IS NULL THEN "uar"."status" - WHEN "uar"."status" = 'ACTIVE' - AND "utr"."hash" = "uar"."hash" THEN 'ACTIVE' - WHEN "uar"."status" IS NULL THEN NULL - ELSE 'IN_PROGRESS' - END - )::varchar(32) AS "actual_status" - FROM - "em_resources" "er" - LEFT JOIN ( - SELECT - "uuid", - "hash" - FROM "ua_target_resources" - WHERE "kind" LIKE 'em_%' - ) AS "utr" - ON "er"."uuid" = "utr"."uuid" - LEFT JOIN ( - SELECT - "uuid", - "status", - "hash" - FROM "ua_actual_resources" - WHERE "kind" LIKE 'em_%' - ) AS "uar" - ON "er"."uuid" = "uar"."uuid" - WHERE - "er"."status" IS DISTINCT FROM ( - CASE - WHEN "utr"."hash" IS NULL THEN "uar"."status" - WHEN "uar"."status" = 'ACTIVE' - AND "utr"."hash" = "uar"."hash" THEN 'ACTIVE' - WHEN "uar"."status" IS NULL THEN NULL - ELSE 'IN_PROGRESS' - END - )::varchar(32); - """, - None, - ) - - def downgrade(self, session): - session.execute( - """ - CREATE OR REPLACE VIEW "em_incorrect_resource_statuses_view" AS - SELECT - "er"."uuid" AS "uuid", - "er"."status" AS "current_status", - "uar"."status" AS "actual_status" - FROM - "em_resources" "er" - LEFT JOIN ( - SELECT - "uuid", - "status" - FROM "ua_actual_resources" - WHERE "kind" LIKE 'em_%' - ) AS "uar" - ON "er"."uuid" = "uar"."uuid" - WHERE - "er"."status" IS DISTINCT FROM "uar"."status"; - """, - None, - ) - - -migration_step = MigrationStep() diff --git a/migrations/0069-add-quota-tables-f8778e.py b/migrations/0069-add-quota-tables-f8778e.py deleted file mode 100644 index 4d99f52d..00000000 --- a/migrations/0069-add-quota-tables-f8778e.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2026 Genesis Corporation. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging - -from restalchemy.storage.sql import migrations - -LOG = logging.getLogger(__name__) - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = ["0068-fix-resource-status-hash-check-437c89.py"] - - @property - def migration_id(self): - return "f8778ebb-ce15-4b72-9860-305b84f3f7ae" - - @property - def is_manual(self): - return False - - def upgrade(self, session): - sql_expressions = [ - # quota_limits - """ - CREATE TABLE IF NOT EXISTS quota_limits ( - uuid UUID NOT NULL PRIMARY KEY, - project_id UUID NOT NULL, - resource_name VARCHAR(255) NOT NULL, - field_name VARCHAR(255) NOT NULL DEFAULT '', - "limit" INTEGER NOT NULL, - "created_at" TIMESTAMP(6) NOT NULL DEFAULT NOW(), - "updated_at" TIMESTAMP(6) NOT NULL DEFAULT NOW() - ); - """, - """ - CREATE UNIQUE INDEX IF NOT EXISTS quota_limits_project_resource_field_name_idx - ON quota_limits (project_id, resource_name, field_name); - """, - ] - - for expr in sql_expressions: - session.execute(expr, None) - - def downgrade(self, session): - tables = [ - "quota_limits", - ] - - for table_name in tables: - self._delete_table_if_exists(session, table_name) - - -migration_step = MigrationStep() diff --git a/migrations/MANUAL-boot-network-40b1ae.py b/migrations/MANUAL-boot-network-40b1ae.py deleted file mode 100644 index 13c84b2e..00000000 --- a/migrations/MANUAL-boot-network-40b1ae.py +++ /dev/null @@ -1,170 +0,0 @@ -# Copyright 2026 Genesis Corporation. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = ["0051-sdk-1-5-0-migration-eea262.py"] - - @property - def migration_id(self): - return "40b1aeb9-bbe0-4bd9-90fe-adecab5b719b" - - @property - def is_manual(self): - return True - - def upgrade(self, session): - expressions = [ - """ - DO $$ - DECLARE - subnets_count integer; - first_subnet record; - BEGIN - SELECT COUNT(*) INTO subnets_count FROM compute_subnets; - - IF subnets_count < 2 THEN - IF subnets_count = 0 THEN - RETURN; - END IF; - - SELECT * INTO first_subnet - FROM compute_subnets - ORDER BY created_at ASC, uuid ASC - LIMIT 1; - - UPDATE compute_subnets - SET - name = 'br0', - next_server = NULL - WHERE uuid = first_subnet.uuid; - - INSERT INTO compute_subnets ( - uuid, - name, - description, - project_id, - network, - cidr, - ip_range, - dhcp, - dns_servers, - routers, - next_server, - ip_discovery_range - ) VALUES ( - gen_random_uuid(), - 'br1', - '', - '00000000-0000-0000-0000-000000000000'::uuid, - first_subnet.network, - '10.100.0.0/22', - NULL, - true, - '["10.20.0.0"]', - '[{"to":"0.0.0.0/0","via":"10.100.0.2"}]', - '10.100.0.2', - '10.100.0.10-10.100.0.254' - ); - END IF; - END $$; - """, - """ - UPDATE ua_target_resources - SET value = jsonb_set( - value, - '{port_info,source}', - '"br0"'::jsonb, - true - ) - WHERE kind = 'pool_machine' - AND (value ? 'port_info') - AND jsonb_typeof(value->'port_info') = 'object' - AND NOT ((value->'port_info') ? 'source'); - """, - """ - UPDATE ua_target_resources - SET value = jsonb_set( - value, - '{boot}', - '"hd0"'::jsonb, - true - ) - WHERE kind = 'pool_machine' - AND (value ? 'boot') - AND value->>'boot' <> 'hd0'; - """, - """ - UPDATE ua_target_resources - SET value = jsonb_set( - value, - '{port_info}', - (value->'port_info') - 'uuid' - 'subnet', - true - ) - WHERE kind = 'pool_machine' - AND (value ? 'port_info') - AND jsonb_typeof(value->'port_info') = 'object' - AND ( - (value->'port_info') ? 'uuid' - OR (value->'port_info') ? 'subnet' - ); - """, - """ - INSERT INTO ua_node_encryption_keys ( - uuid, - private_key, - encryption_disabled_until - ) - SELECT - nodes.uuid, - encode( - decode( - md5(random()::text || clock_timestamp()::text || nodes.uuid::text) - || md5(clock_timestamp()::text || random()::text || nodes.uuid::text), - 'hex' - ), - 'base64' - ), - '2028-12-31 23:59:59'::timestamp - FROM nodes - ON CONFLICT (uuid) DO NOTHING; - """, - """ - UPDATE compute_ports - SET source = 'br0'; - """, - """ - UPDATE machines - SET updated_at = current_timestamp; - """, - ] - - for expression in expressions: - session.execute(expression, None) - - def downgrade(self, session): - - expressions = [] - - for expression in expressions: - session.execute(expression, None) - - -migration_step = MigrationStep() diff --git a/migrations/MANUAL-computeV2-e26427.py b/migrations/MANUAL-computeV2-e26427.py deleted file mode 100644 index 18ae4f87..00000000 --- a/migrations/MANUAL-computeV2-e26427.py +++ /dev/null @@ -1,339 +0,0 @@ -# Copyright 2016 Eugene Frolov -# Copyright 2025 Genesis Corporation. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstractMigrationStep): - def __init__(self): - self._depends = ["0042-compute-ua-integration-4bd866.py"] - - @property - def migration_id(self): - return "e26427e5-b510-49d1-a178-22ada1e8ce51" - - @property - def is_manual(self): - return True - - def upgrade(self, session): - expressions = [ - """ - -- Temporary delete machine pools of type HW. They are not used. - DELETE FROM machine_pools - WHERE machine_type = 'HW'; - """, - """ - -- Put volumes to hidden project if they belong to EM project - -- Only for migration from legacy schema - UPDATE node_volumes SET project_id='12345670-6f3a-402e-acf8-0319d53eab58'::uuid - WHERE project_id='12345678-c625-4fee-81d5-f691897b8142'::uuid; - """, - """ - -- Insert data from node_volumes to compute_machine_volumes - INSERT INTO compute_machine_volumes ( - uuid, - project_id, - name, - description, - node_volume, - pool, - machine, - size, - boot, - index, - label, - image, - device_type, - status, - created_at, - updated_at - ) - SELECT - nv.uuid, - nv.project_id, - nv.uuid::varchar(255) as name, - nv.description, - nv.uuid as node_volume, - m.pool as pool, - m.uuid as machine, - nv.size, - nv.boot, - nv.index, - nv.label, - nv.image, - nv.device_type, - nv.status, - nv.created_at, - nv.updated_at - FROM node_volumes nv - LEFT JOIN machines m ON m.node = nv.node; - """, - # Explicitly update the `updated_at` column to initialize - # updating UA target resource format. - """ - UPDATE compute_sets - SET updated_at = current_timestamp; - """, - # Manual migration - """ - -- [node_set] Migration for adding disk_spec structure to JSONB field value - DO $$ - DECLARE - rec RECORD; - new_value JSONB; - BEGIN - FOR rec IN SELECT res_uuid, value, kind FROM ua_target_resources WHERE kind='node_set' - LOOP - -- Create new JSONB value - new_value := jsonb_build_object( - 'ram', rec.value->'ram', - 'name', rec.value->>'name', - 'uuid', rec.value->>'uuid', - 'cores', rec.value->'cores', - 'replicas', rec.value->'replicas', - 'set_type', rec.value->>'set_type', - 'node_type', rec.value->>'node_type', - 'project_id', rec.value->>'project_id', - 'disk_spec', jsonb_build_object( - 'kind', 'root_disk', - 'size', rec.value->'root_disk_size', - 'image', rec.value->>'image' - ) - ); - - -- Update record - UPDATE ua_target_resources - SET value = new_value - WHERE res_uuid = rec.res_uuid; - END LOOP; - END $$; - """, - """ - -- [em_core_compute_sets] Migration for adding disk_spec structure to JSONB field value - DO $$ - DECLARE - rec RECORD; - new_value JSONB; - BEGIN - FOR rec IN SELECT res_uuid, value, kind FROM ua_target_resources WHERE kind='em_core_compute_sets' - LOOP - -- Create new JSONB value - new_value := jsonb_build_object( - 'ram', rec.value->'ram', - 'name', rec.value->>'name', - 'uuid', rec.value->>'uuid', - 'cores', rec.value->'cores', - 'replicas', rec.value->'replicas', - 'project_id', rec.value->>'project_id', - 'disk_spec', jsonb_build_object( - 'kind', 'root_disk', - 'size', rec.value->'root_disk_size', - 'image', rec.value->>'image' - ) - ); - - -- Update record - UPDATE ua_target_resources - SET value = new_value - WHERE res_uuid = rec.res_uuid; - END LOOP; - END $$; - """, - """ - -- [set_agent_node] Migration for adding disk_spec structure to JSONB field value - DO $$ - DECLARE - rec RECORD; - new_value JSONB; - BEGIN - FOR rec IN SELECT res_uuid, value, kind FROM ua_target_resources WHERE kind='set_agent_node' - LOOP - -- Create new JSONB value - new_value := jsonb_build_object( - 'ram', rec.value->'ram', - 'name', rec.value->>'name', - 'uuid', rec.value->>'uuid', - 'cores', rec.value->'cores', - 'node_type', rec.value->>'node_type', - 'project_id', rec.value->>'project_id', - 'placement_policies', rec.value->'placement_policies', - 'disk_spec', jsonb_build_object( - 'kind', 'root_disk', - 'size', rec.value->'root_disk_size', - 'image', rec.value->>'image' - ) - ); - - -- Update record - UPDATE ua_target_resources - SET value = new_value - WHERE res_uuid = rec.res_uuid; - END LOOP; - END $$; - """, - """ - -- [em_core_compute_nodes] Migration for adding disk_spec structure to JSONB field value - DO $$ - DECLARE - rec RECORD; - new_value JSONB; - BEGIN - FOR rec IN SELECT res_uuid, value, kind FROM ua_target_resources WHERE kind='em_core_compute_nodes' - LOOP - -- Create new JSONB value - new_value := jsonb_build_object( - 'ram', rec.value->'ram', - 'name', rec.value->>'name', - 'uuid', rec.value->>'uuid', - 'cores', rec.value->'cores', - 'project_id', rec.value->>'project_id', - 'disk_spec', jsonb_build_object( - 'kind', 'root_disk', - 'size', rec.value->'root_disk_size', - 'image', rec.value->>'image' - ) - ); - - -- Update record - UPDATE ua_target_resources - SET value = new_value - WHERE res_uuid = rec.res_uuid; - END LOOP; - END $$; - """, - """ - DELETE FROM ua_actual_resources WHERE - kind='em_core_compute_nodes' OR - kind='em_core_compute_sets' OR - kind='set_agent_node' OR - kind='node_set' OR - kind='target_node_set'; - """, - """ - UPDATE nodes - SET hostname = REPLACE(name, '_', '-') - WHERE hostname IS NULL OR hostname = ''; - """, - """ - -- [$core.compute.nodes] Migration for adding disk_spec structure to JSONB field value - DO $$ - DECLARE - rec RECORD; - new_value JSONB; - BEGIN - FOR rec IN SELECT uuid, value, resource_link_prefix FROM em_resources WHERE resource_link_prefix='$core.compute.nodes' - LOOP - -- Create new JSONB value - new_value := jsonb_build_object( - 'ram', rec.value->'ram', - 'name', rec.value->>'name', - 'uuid', rec.uuid, - 'cores', rec.value->'cores', - 'project_id', rec.value->>'project_id', - 'disk_spec', jsonb_build_object( - 'kind', 'root_disk', - 'size', rec.value->'root_disk_size', - 'image', rec.value->>'image' - ) - ); - - -- Update record - UPDATE em_resources - SET value = new_value - WHERE uuid = rec.uuid; - END LOOP; - END $$; - """, - """ - -- [$core.compute.sets] Migration for adding disk_spec structure to JSONB field value - DO $$ - DECLARE - rec RECORD; - new_value JSONB; - BEGIN - FOR rec IN SELECT uuid, value, resource_link_prefix FROM em_resources WHERE resource_link_prefix='$core.compute.sets' - LOOP - -- Create new JSONB value - new_value := jsonb_build_object( - 'ram', rec.value->'ram', - 'name', rec.value->>'name', - 'uuid', rec.uuid, - 'cores', rec.value->'cores', - 'project_id', rec.value->>'project_id', - 'replicas', rec.value->'replicas', - 'disk_spec', jsonb_build_object( - 'kind', 'root_disk', - 'size', rec.value->'root_disk_size', - 'image', rec.value->>'image' - ) - ); - - -- Update record - UPDATE em_resources - SET value = new_value - WHERE uuid = rec.uuid; - END LOOP; - END $$; - """, - """ - -- [target_node_set] Migration for adding disk_spec structure to JSONB field value - DO $$ - DECLARE - rec RECORD; - new_value JSONB; - BEGIN - FOR rec IN SELECT res_uuid, value, kind FROM ua_target_resources WHERE kind='target_node_set' - LOOP - -- Create new JSONB value - new_value := jsonb_build_object( - 'ram', rec.value->'ram', - 'name', rec.value->>'name', - 'uuid', rec.value->>'uuid', - 'cores', rec.value->'cores', - 'replicas', rec.value->'replicas', - 'node_type', rec.value->>'node_type', - 'set_type', rec.value->>'set_type', - 'project_id', rec.value->>'project_id', - 'disk_spec', jsonb_build_object( - 'kind', 'root_disk', - 'size', rec.value->'root_disk_size', - 'image', rec.value->>'image' - ) - ); - - -- Update record - UPDATE ua_target_resources - SET value = new_value - WHERE res_uuid = rec.res_uuid; - END LOOP; - END $$; - """, - ] - - for expression in expressions: - session.execute(expression, None) - - def downgrade(self, session): - - expressions = [] - - for expression in expressions: - session.execute(expression, None) - - -migration_step = MigrationStep() diff --git a/migrations/MANUAL-fix-usernames-6b042b.py b/migrations/MANUAL-fix-usernames-6b042b.py deleted file mode 100644 index 508ba6d1..00000000 --- a/migrations/MANUAL-fix-usernames-6b042b.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2016 Eugene Frolov -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from restalchemy.storage.sql import migrations - - -class MigrationStep(migrations.AbstarctMigrationStep): - def __init__(self): - self._depends = ["0023-nullable_fio-c9cb3a.py"] - - @property - def migration_id(self): - return "6b042b1d-df57-4553-a031-8ae74ffab015" - - @property - def is_manual(self): - return True - - def upgrade(self, session): - expression = """ - UPDATE iam_users - SET - name = REPLACE(name, '@', '.at.') - WHERE name LIKE '%@%'; - """ - session.execute(expression) - - def downgrade(self, session): - expression = """ - UPDATE iam_users - SET - name = REPLACE(name, '.at.', '@') - WHERE name LIKE '%.at.%'; - """ - session.execute(expression) - - -migration_step = MigrationStep()