Initial commit: stateful OpenStack API laboratory simulator.

Ship Keystone auth, multi-service handlers (Yoga→Dalmatian), Compose/Helm
packaging, API contract packs, and pytest/Pulumi coverage labs.
This commit is contained in:
2026-07-18 04:26:48 +03:00
commit 6033967e6a
509 changed files with 464404 additions and 0 deletions
+60
View File
@@ -0,0 +1,60 @@
CREATE TABLE contract_snapshots (
checksum text PRIMARY KEY,
source_version text NOT NULL,
document jsonb NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE nodes (
id uuid PRIMARY KEY,
name text NOT NULL UNIQUE,
status text NOT NULL CHECK (status IN ('online', 'offline'))
);
CREATE TABLE resources (
id uuid PRIMARY KEY,
node_id uuid NOT NULL REFERENCES nodes(id) ON DELETE RESTRICT,
kind text NOT NULL,
external_id text NOT NULL,
state jsonb NOT NULL DEFAULT '{}'::jsonb,
UNIQUE (kind, external_id)
);
CREATE INDEX resources_node_id_idx ON resources(node_id);
CREATE TABLE principals (
id uuid PRIMARY KEY,
name text NOT NULL UNIQUE,
password_hash text
);
CREATE TABLE roles (
name text PRIMARY KEY,
privileges text[] NOT NULL DEFAULT '{}'
);
CREATE TABLE acl_entries (
principal_id uuid NOT NULL REFERENCES principals(id) ON DELETE CASCADE,
role_name text NOT NULL REFERENCES roles(name) ON DELETE RESTRICT,
path text NOT NULL,
propagate boolean NOT NULL DEFAULT true,
PRIMARY KEY (principal_id, role_name, path)
);
CREATE TABLE tasks (
id uuid PRIMARY KEY,
upid text NOT NULL UNIQUE,
status text NOT NULL,
payload jsonb NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX tasks_status_created_idx ON tasks(status, created_at);
CREATE TABLE scenarios (
id uuid PRIMARY KEY,
name text NOT NULL UNIQUE,
definition jsonb NOT NULL,
enabled boolean NOT NULL DEFAULT true
);
CREATE TABLE audit_events (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
occurred_at timestamptz NOT NULL DEFAULT now(),
principal text,
action text NOT NULL,
target text,
details jsonb NOT NULL DEFAULT '{}'::jsonb
);
CREATE INDEX audit_events_occurred_idx ON audit_events(occurred_at);
@@ -0,0 +1,16 @@
CREATE TABLE realms (
name text PRIMARY KEY,
kind text NOT NULL CHECK (kind IN ('pam', 'pve', 'openid', 'ldap'))
);
INSERT INTO realms(name, kind) VALUES ('pam', 'pam'), ('pve', 'pve');
ALTER TABLE principals ADD COLUMN realm_name text REFERENCES realms(name) ON DELETE RESTRICT;
CREATE TABLE api_tokens (
principal_id uuid NOT NULL REFERENCES principals(id) ON DELETE CASCADE,
token_id text NOT NULL,
secret_hash text NOT NULL,
privileges text[] NOT NULL DEFAULT '{}',
expires_at timestamptz,
PRIMARY KEY (principal_id, token_id),
CHECK (secret_hash LIKE 'scrypt$%')
);
CREATE INDEX api_tokens_expires_idx ON api_tokens(expires_at) WHERE expires_at IS NOT NULL;
+32
View File
@@ -0,0 +1,32 @@
ALTER TABLE tasks
ADD COLUMN task_type text NOT NULL DEFAULT 'generic',
ADD COLUMN progress integer NOT NULL DEFAULT 0 CHECK (progress BETWEEN 0 AND 100),
ADD COLUMN result jsonb,
ADD COLUMN error text,
ADD COLUMN worker_id text,
ADD COLUMN lease_expires_at timestamptz,
ADD COLUMN cancel_requested boolean NOT NULL DEFAULT false,
ADD COLUMN idempotency_key text UNIQUE,
ADD COLUMN attempt integer NOT NULL DEFAULT 0,
ADD CONSTRAINT tasks_status_check CHECK (status IN ('queued', 'running', 'success', 'error', 'cancelled'));
CREATE INDEX tasks_claim_idx ON tasks(status, lease_expires_at, created_at);
CREATE TABLE resource_locks (
resource_key text PRIMARY KEY,
task_id uuid NOT NULL UNIQUE REFERENCES tasks(id) ON DELETE CASCADE,
acquired_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE task_logs (
task_id uuid NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
sequence bigint GENERATED ALWAYS AS IDENTITY,
created_at timestamptz NOT NULL DEFAULT now(),
message text NOT NULL,
PRIMARY KEY (task_id, sequence)
);
CREATE TABLE task_events (
task_id uuid NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
sequence bigint GENERATED ALWAYS AS IDENTITY,
created_at timestamptz NOT NULL DEFAULT now(),
kind text NOT NULL,
data jsonb NOT NULL DEFAULT '{}'::jsonb,
PRIMARY KEY (task_id, sequence)
);
+204
View File
@@ -0,0 +1,204 @@
CREATE TABLE clusters (
id uuid PRIMARY KEY,
external_id text NOT NULL UNIQUE,
name text NOT NULL,
version integer NOT NULL DEFAULT 1,
metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
INSERT INTO clusters(id, external_id, name)
VALUES ('dc760c47-d8d7-57e6-9404-f0c6f2395d8f', 'default', 'pve-simulator');
ALTER TABLE nodes
ADD COLUMN cluster_id uuid NOT NULL DEFAULT 'dc760c47-d8d7-57e6-9404-f0c6f2395d8f'
REFERENCES clusters(id) ON DELETE CASCADE,
ADD COLUMN version integer NOT NULL DEFAULT 1,
ADD COLUMN metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
ADD COLUMN created_at timestamptz NOT NULL DEFAULT now(),
ADD COLUMN updated_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE resources
ADD COLUMN cluster_id uuid NOT NULL DEFAULT 'dc760c47-d8d7-57e6-9404-f0c6f2395d8f'
REFERENCES clusters(id) ON DELETE CASCADE,
ADD COLUMN version integer NOT NULL DEFAULT 1,
ADD COLUMN metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
ADD COLUMN created_at timestamptz NOT NULL DEFAULT now(),
ADD COLUMN updated_at timestamptz NOT NULL DEFAULT now();
CREATE UNIQUE INDEX resources_cluster_vmid_idx
ON resources(cluster_id, external_id) WHERE kind IN ('qemu', 'lxc');
CREATE TABLE virtual_machines (
resource_id uuid PRIMARY KEY REFERENCES resources(id) ON DELETE CASCADE,
cluster_id uuid NOT NULL REFERENCES clusters(id) ON DELETE CASCADE,
vmid integer NOT NULL CHECK (vmid BETWEEN 100 AND 999999999),
config jsonb NOT NULL DEFAULT '{}'::jsonb,
lock text,
template boolean NOT NULL DEFAULT false,
UNIQUE (cluster_id, vmid)
);
CREATE TABLE containers (
resource_id uuid PRIMARY KEY REFERENCES resources(id) ON DELETE CASCADE,
cluster_id uuid NOT NULL REFERENCES clusters(id) ON DELETE CASCADE,
vmid integer NOT NULL CHECK (vmid BETWEEN 100 AND 999999999),
config jsonb NOT NULL DEFAULT '{}'::jsonb,
lock text,
template boolean NOT NULL DEFAULT false,
UNIQUE (cluster_id, vmid)
);
CREATE TABLE vm_disks (
id uuid PRIMARY KEY,
resource_id uuid NOT NULL REFERENCES resources(id) ON DELETE CASCADE,
device text NOT NULL,
storage_id text NOT NULL,
size_bytes bigint NOT NULL CHECK (size_bytes >= 0),
metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
UNIQUE (resource_id, device)
);
CREATE TABLE vm_network_interfaces (
id uuid PRIMARY KEY,
resource_id uuid NOT NULL REFERENCES resources(id) ON DELETE CASCADE,
device text NOT NULL,
config jsonb NOT NULL DEFAULT '{}'::jsonb,
UNIQUE (resource_id, device)
);
CREATE TABLE storages (
resource_id uuid PRIMARY KEY REFERENCES resources(id) ON DELETE CASCADE,
cluster_id uuid NOT NULL REFERENCES clusters(id) ON DELETE CASCADE,
storage_id text NOT NULL,
storage_type text NOT NULL,
shared boolean NOT NULL DEFAULT false,
capacity_bytes bigint CHECK (capacity_bytes >= 0),
used_bytes bigint CHECK (used_bytes >= 0),
config jsonb NOT NULL DEFAULT '{}'::jsonb,
UNIQUE (cluster_id, storage_id)
);
CREATE TABLE storage_contents (
id uuid PRIMARY KEY,
storage_resource_id uuid NOT NULL REFERENCES storages(resource_id) ON DELETE CASCADE,
volume_id text NOT NULL,
content_type text NOT NULL,
size_bytes bigint NOT NULL DEFAULT 0 CHECK (size_bytes >= 0),
metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
created_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (storage_resource_id, volume_id)
);
CREATE TABLE snapshots (
id uuid PRIMARY KEY,
resource_id uuid NOT NULL REFERENCES resources(id) ON DELETE CASCADE,
name text NOT NULL,
parent_name text,
description text,
state jsonb NOT NULL DEFAULT '{}'::jsonb,
created_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (resource_id, name)
);
CREATE TABLE backups (
id uuid PRIMARY KEY,
resource_id uuid REFERENCES resources(id) ON DELETE SET NULL,
storage_resource_id uuid NOT NULL REFERENCES storages(resource_id) ON DELETE CASCADE,
volume_id text NOT NULL,
size_bytes bigint NOT NULL DEFAULT 0 CHECK (size_bytes >= 0),
metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
created_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (storage_resource_id, volume_id)
);
CREATE TABLE pools (
id uuid PRIMARY KEY,
cluster_id uuid NOT NULL REFERENCES clusters(id) ON DELETE CASCADE,
pool_id text NOT NULL,
comment text,
metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
UNIQUE (cluster_id, pool_id)
);
CREATE TABLE pool_members (
pool_id uuid NOT NULL REFERENCES pools(id) ON DELETE CASCADE,
resource_id uuid NOT NULL REFERENCES resources(id) ON DELETE CASCADE,
PRIMARY KEY (pool_id, resource_id)
);
CREATE TABLE identity_groups (
id uuid PRIMARY KEY,
group_id text NOT NULL UNIQUE,
comment text,
metadata jsonb NOT NULL DEFAULT '{}'::jsonb
);
CREATE TABLE identity_group_members (
group_id uuid NOT NULL REFERENCES identity_groups(id) ON DELETE CASCADE,
principal_id uuid NOT NULL REFERENCES principals(id) ON DELETE CASCADE,
PRIMARY KEY (group_id, principal_id)
);
CREATE TABLE auth_tickets (
id uuid PRIMARY KEY,
principal_id uuid NOT NULL REFERENCES principals(id) ON DELETE CASCADE,
ticket_hash text NOT NULL UNIQUE,
issued_at timestamptz NOT NULL,
expires_at timestamptz NOT NULL,
revoked_at timestamptz
);
CREATE INDEX auth_tickets_expiry_idx ON auth_tickets(expires_at) WHERE revoked_at IS NULL;
CREATE TABLE contract_paths (
snapshot_checksum text NOT NULL REFERENCES contract_snapshots(checksum) ON DELETE CASCADE,
path text NOT NULL,
document jsonb NOT NULL,
PRIMARY KEY (snapshot_checksum, path)
);
CREATE TABLE contract_methods (
snapshot_checksum text NOT NULL,
path text NOT NULL,
verb text NOT NULL,
fingerprint text NOT NULL,
document jsonb NOT NULL,
PRIMARY KEY (snapshot_checksum, path, verb),
FOREIGN KEY (snapshot_checksum, path)
REFERENCES contract_paths(snapshot_checksum, path) ON DELETE CASCADE
);
CREATE TABLE contract_parameters (
snapshot_checksum text NOT NULL,
path text NOT NULL,
verb text NOT NULL,
name text NOT NULL,
location text NOT NULL,
document jsonb NOT NULL,
PRIMARY KEY (snapshot_checksum, path, verb, name, location),
FOREIGN KEY (snapshot_checksum, path, verb)
REFERENCES contract_methods(snapshot_checksum, path, verb) ON DELETE CASCADE
);
CREATE TABLE contract_schema_fragments (
id uuid PRIMARY KEY,
snapshot_checksum text NOT NULL REFERENCES contract_snapshots(checksum) ON DELETE CASCADE,
fingerprint text NOT NULL,
document jsonb NOT NULL,
UNIQUE (snapshot_checksum, fingerprint)
);
CREATE TABLE observed_contracts (
id uuid PRIMARY KEY,
source_version text NOT NULL,
method_fingerprint text NOT NULL,
observation jsonb NOT NULL,
observed_at timestamptz NOT NULL,
UNIQUE (source_version, method_fingerprint, observed_at)
);
CREATE TABLE scenario_rules (
id uuid PRIMARY KEY,
scenario_id uuid NOT NULL REFERENCES scenarios(id) ON DELETE CASCADE,
priority integer NOT NULL DEFAULT 0,
matcher jsonb NOT NULL,
action jsonb NOT NULL,
enabled boolean NOT NULL DEFAULT true
);
CREATE INDEX scenario_rules_scenario_priority_idx ON scenario_rules(scenario_id, priority DESC);
CREATE TABLE fault_injections (
id uuid PRIMARY KEY,
scenario_id uuid REFERENCES scenarios(id) ON DELETE CASCADE,
fault_type text NOT NULL,
matcher jsonb NOT NULL,
parameters jsonb NOT NULL DEFAULT '{}'::jsonb,
active_from timestamptz,
active_until timestamptz,
enabled boolean NOT NULL DEFAULT true
);
@@ -0,0 +1,6 @@
INSERT INTO realms(name, kind) VALUES ('test', 'pve') ON CONFLICT (name) DO NOTHING;
ALTER TABLE api_tokens
ADD COLUMN comment text,
ADD COLUMN privilege_separation boolean NOT NULL DEFAULT true,
ADD COLUMN created_at timestamptz NOT NULL DEFAULT now(),
ADD COLUMN updated_at timestamptz NOT NULL DEFAULT now();
+9
View File
@@ -0,0 +1,9 @@
CREATE TABLE group_acl_entries (
group_id uuid NOT NULL REFERENCES identity_groups(id) ON DELETE CASCADE,
role_name text NOT NULL REFERENCES roles(name) ON DELETE RESTRICT,
path text NOT NULL,
propagate boolean NOT NULL DEFAULT true,
PRIMARY KEY (group_id, role_name, path)
);
CREATE INDEX identity_group_members_principal_idx
ON identity_group_members(principal_id, group_id);
+17
View File
@@ -0,0 +1,17 @@
ALTER TABLE realms DROP CONSTRAINT IF EXISTS realms_kind_check;
ALTER TABLE realms
ADD CONSTRAINT realms_kind_check
CHECK (kind IN ('pam', 'pve', 'openid', 'ldap', 'ad'));
ALTER TABLE realms
ADD COLUMN IF NOT EXISTS config jsonb NOT NULL DEFAULT '{}'::jsonb;
UPDATE realms
SET config = config || jsonb_build_object(
'comment',
CASE name
WHEN 'pam' THEN 'Linux PAM standard authentication'
WHEN 'pve' THEN 'Proxmox VE authentication server'
ELSE COALESCE(config->>'comment', '')
END
)
WHERE name IN ('pam', 'pve')
AND COALESCE(config->>'comment', '') = '';
+23
View File
@@ -0,0 +1,23 @@
CREATE TABLE tfa_entries (
principal_id uuid NOT NULL REFERENCES principals(id) ON DELETE CASCADE,
entry_id text NOT NULL,
tfa_type text NOT NULL CHECK (tfa_type IN ('totp', 'u2f', 'webauthn', 'recovery', 'yubico')),
description text,
enable boolean NOT NULL DEFAULT true,
created_at timestamptz NOT NULL DEFAULT now(),
secret text,
metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
PRIMARY KEY (principal_id, entry_id)
);
CREATE INDEX tfa_entries_principal_idx ON tfa_entries(principal_id);
ALTER TABLE principals
ADD COLUMN IF NOT EXISTS tfa_locked_until timestamptz,
ADD COLUMN IF NOT EXISTS totp_locked boolean NOT NULL DEFAULT false;
CREATE TABLE openid_pending (
state text PRIMARY KEY,
realm text NOT NULL REFERENCES realms(name) ON DELETE CASCADE,
redirect_url text NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);
+137
View File
@@ -0,0 +1,137 @@
-- OpenStack identity + core IaaS tables (iteration 2).
CREATE TABLE IF NOT EXISTS os_domains (
id uuid PRIMARY KEY,
name text NOT NULL UNIQUE,
description text NOT NULL DEFAULT '',
enabled boolean NOT NULL DEFAULT true
);
CREATE TABLE IF NOT EXISTS os_projects (
id uuid PRIMARY KEY,
domain_id uuid NOT NULL REFERENCES os_domains(id) ON DELETE CASCADE,
name text NOT NULL,
description text NOT NULL DEFAULT '',
enabled boolean NOT NULL DEFAULT true,
UNIQUE (domain_id, name)
);
CREATE TABLE IF NOT EXISTS os_users (
id uuid PRIMARY KEY,
domain_id uuid NOT NULL REFERENCES os_domains(id) ON DELETE CASCADE,
name text NOT NULL,
password_hash text NOT NULL,
enabled boolean NOT NULL DEFAULT true,
UNIQUE (domain_id, name)
);
CREATE TABLE IF NOT EXISTS os_roles (
id uuid PRIMARY KEY,
name text NOT NULL UNIQUE
);
CREATE TABLE IF NOT EXISTS os_role_assignments (
id uuid PRIMARY KEY,
role_id uuid NOT NULL REFERENCES os_roles(id) ON DELETE CASCADE,
user_id uuid NOT NULL REFERENCES os_users(id) ON DELETE CASCADE,
project_id uuid NOT NULL REFERENCES os_projects(id) ON DELETE CASCADE,
UNIQUE (role_id, user_id, project_id)
);
CREATE TABLE IF NOT EXISTS os_tokens (
id text PRIMARY KEY,
user_id uuid NOT NULL REFERENCES os_users(id) ON DELETE CASCADE,
project_id uuid REFERENCES os_projects(id) ON DELETE CASCADE,
expires_at timestamptz NOT NULL,
issued_at timestamptz NOT NULL DEFAULT now(),
revoked boolean NOT NULL DEFAULT false
);
CREATE INDEX IF NOT EXISTS os_tokens_user_idx ON os_tokens(user_id);
CREATE INDEX IF NOT EXISTS os_tokens_expires_idx ON os_tokens(expires_at);
CREATE TABLE IF NOT EXISTS os_flavors (
id text PRIMARY KEY,
name text NOT NULL UNIQUE,
vcpus integer NOT NULL,
ram integer NOT NULL,
disk integer NOT NULL,
is_public boolean NOT NULL DEFAULT true
);
CREATE TABLE IF NOT EXISTS os_images (
id uuid PRIMARY KEY,
name text NOT NULL,
status text NOT NULL DEFAULT 'active',
visibility text NOT NULL DEFAULT 'public',
size bigint NOT NULL DEFAULT 0,
disk_format text NOT NULL DEFAULT 'qcow2',
container_format text NOT NULL DEFAULT 'bare',
owner_project_id uuid REFERENCES os_projects(id) ON DELETE SET NULL,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS os_networks (
id uuid PRIMARY KEY,
project_id uuid NOT NULL REFERENCES os_projects(id) ON DELETE CASCADE,
name text NOT NULL,
status text NOT NULL DEFAULT 'ACTIVE',
shared boolean NOT NULL DEFAULT false,
admin_state_up boolean NOT NULL DEFAULT true,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS os_subnets (
id uuid PRIMARY KEY,
network_id uuid NOT NULL REFERENCES os_networks(id) ON DELETE CASCADE,
project_id uuid NOT NULL REFERENCES os_projects(id) ON DELETE CASCADE,
name text NOT NULL DEFAULT '',
cidr text NOT NULL,
ip_version integer NOT NULL DEFAULT 4,
gateway_ip text,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS os_ports (
id uuid PRIMARY KEY,
network_id uuid NOT NULL REFERENCES os_networks(id) ON DELETE CASCADE,
project_id uuid NOT NULL REFERENCES os_projects(id) ON DELETE CASCADE,
name text NOT NULL DEFAULT '',
status text NOT NULL DEFAULT 'ACTIVE',
mac_address text NOT NULL,
device_id text NOT NULL DEFAULT '',
device_owner text NOT NULL DEFAULT '',
fixed_ips jsonb NOT NULL DEFAULT '[]'::jsonb,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS os_volumes (
id uuid PRIMARY KEY,
project_id uuid NOT NULL REFERENCES os_projects(id) ON DELETE CASCADE,
name text NOT NULL DEFAULT '',
status text NOT NULL DEFAULT 'available',
size integer NOT NULL,
volume_type text NOT NULL DEFAULT 'lvmdriver-1',
bootable boolean NOT NULL DEFAULT false,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS os_servers (
id uuid PRIMARY KEY,
project_id uuid NOT NULL REFERENCES os_projects(id) ON DELETE CASCADE,
user_id uuid NOT NULL REFERENCES os_users(id) ON DELETE CASCADE,
name text NOT NULL,
status text NOT NULL DEFAULT 'ACTIVE',
flavor_id text NOT NULL REFERENCES os_flavors(id),
image_id uuid REFERENCES os_images(id) ON DELETE SET NULL,
addresses jsonb NOT NULL DEFAULT '{}'::jsonb,
metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS os_servers_project_idx ON os_servers(project_id);
CREATE INDEX IF NOT EXISTS os_networks_project_idx ON os_networks(project_id);
CREATE INDEX IF NOT EXISTS os_volumes_project_idx ON os_volumes(project_id);
@@ -0,0 +1,142 @@
-- Generic OpenStack object store + service-specific extras for full lab surface.
CREATE TABLE IF NOT EXISTS os_api_objects (
id uuid PRIMARY KEY,
service text NOT NULL,
resource_type text NOT NULL,
project_id uuid REFERENCES os_projects(id) ON DELETE CASCADE,
name text NOT NULL DEFAULT '',
status text NOT NULL DEFAULT 'ACTIVE',
data jsonb NOT NULL DEFAULT '{}'::jsonb,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS os_api_objects_lookup_idx
ON os_api_objects(service, resource_type, project_id);
CREATE INDEX IF NOT EXISTS os_api_objects_name_idx
ON os_api_objects(service, resource_type, name);
CREATE TABLE IF NOT EXISTS os_keypairs (
name text NOT NULL,
user_id uuid NOT NULL REFERENCES os_users(id) ON DELETE CASCADE,
fingerprint text NOT NULL,
public_key text NOT NULL,
type text NOT NULL DEFAULT 'ssh',
created_at timestamptz NOT NULL DEFAULT now(),
PRIMARY KEY (user_id, name)
);
CREATE TABLE IF NOT EXISTS os_security_groups (
id uuid PRIMARY KEY,
project_id uuid NOT NULL REFERENCES os_projects(id) ON DELETE CASCADE,
name text NOT NULL,
description text NOT NULL DEFAULT '',
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS os_security_group_rules (
id uuid PRIMARY KEY,
security_group_id uuid NOT NULL REFERENCES os_security_groups(id) ON DELETE CASCADE,
project_id uuid NOT NULL REFERENCES os_projects(id) ON DELETE CASCADE,
direction text NOT NULL DEFAULT 'ingress',
ethertype text NOT NULL DEFAULT 'IPv4',
protocol text,
port_range_min integer,
port_range_max integer,
remote_ip_prefix text,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS os_routers (
id uuid PRIMARY KEY,
project_id uuid NOT NULL REFERENCES os_projects(id) ON DELETE CASCADE,
name text NOT NULL,
status text NOT NULL DEFAULT 'ACTIVE',
admin_state_up boolean NOT NULL DEFAULT true,
external_gateway_info jsonb,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS os_floating_ips (
id uuid PRIMARY KEY,
project_id uuid NOT NULL REFERENCES os_projects(id) ON DELETE CASCADE,
floating_ip_address text NOT NULL,
floating_network_id uuid,
port_id uuid,
fixed_ip_address text,
router_id uuid,
status text NOT NULL DEFAULT 'DOWN',
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS os_server_groups (
id uuid PRIMARY KEY,
project_id uuid NOT NULL REFERENCES os_projects(id) ON DELETE CASCADE,
name text NOT NULL,
policies jsonb NOT NULL DEFAULT '[]'::jsonb,
members jsonb NOT NULL DEFAULT '[]'::jsonb,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS os_stacks (
id uuid PRIMARY KEY,
project_id uuid NOT NULL REFERENCES os_projects(id) ON DELETE CASCADE,
stack_name text NOT NULL,
stack_status text NOT NULL DEFAULT 'CREATE_COMPLETE',
description text NOT NULL DEFAULT '',
template jsonb NOT NULL DEFAULT '{}'::jsonb,
parameters jsonb NOT NULL DEFAULT '{}'::jsonb,
outputs jsonb NOT NULL DEFAULT '[]'::jsonb,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS os_swift_objects (
id uuid PRIMARY KEY,
account text NOT NULL,
container text NOT NULL,
name text NOT NULL,
content_type text NOT NULL DEFAULT 'application/octet-stream',
bytes integer NOT NULL DEFAULT 0,
body bytea,
meta jsonb NOT NULL DEFAULT '{}'::jsonb,
created_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (account, container, name)
);
CREATE TABLE IF NOT EXISTS os_swift_containers (
account text NOT NULL,
name text NOT NULL,
meta jsonb NOT NULL DEFAULT '{}'::jsonb,
created_at timestamptz NOT NULL DEFAULT now(),
PRIMARY KEY (account, name)
);
CREATE TABLE IF NOT EXISTS os_nodes (
id uuid PRIMARY KEY,
name text NOT NULL UNIQUE,
driver text NOT NULL DEFAULT 'ipmi',
provision_state text NOT NULL DEFAULT 'available',
power_state text NOT NULL DEFAULT 'power on',
resource_class text NOT NULL DEFAULT 'baremetal',
properties jsonb NOT NULL DEFAULT '{}'::jsonb,
driver_info jsonb NOT NULL DEFAULT '{}'::jsonb,
ports jsonb NOT NULL DEFAULT '[]'::jsonb,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS os_loadbalancers (
id uuid PRIMARY KEY,
project_id uuid NOT NULL REFERENCES os_projects(id) ON DELETE CASCADE,
name text NOT NULL,
description text NOT NULL DEFAULT '',
vip_address text,
vip_subnet_id uuid,
provisioning_status text NOT NULL DEFAULT 'ACTIVE',
operating_status text NOT NULL DEFAULT 'ONLINE',
listeners jsonb NOT NULL DEFAULT '[]'::jsonb,
pools jsonb NOT NULL DEFAULT '[]'::jsonb,
created_at timestamptz NOT NULL DEFAULT now()
);
@@ -0,0 +1,56 @@
-- Topology tables for demo cloud + marker for loaded profile.
CREATE TABLE IF NOT EXISTS os_availability_zones (
name text PRIMARY KEY,
zone_state jsonb NOT NULL DEFAULT '{"available": true}'::jsonb
);
CREATE TABLE IF NOT EXISTS os_hypervisors (
id integer PRIMARY KEY,
hypervisor_hostname text NOT NULL UNIQUE,
state text NOT NULL DEFAULT 'up',
status text NOT NULL DEFAULT 'enabled',
hypervisor_type text NOT NULL DEFAULT 'QEMU',
hypervisor_version integer NOT NULL DEFAULT 201000,
host_ip text,
vcpus integer NOT NULL DEFAULT 64,
vcpus_used integer NOT NULL DEFAULT 0,
memory_mb integer NOT NULL DEFAULT 262144,
memory_mb_used integer NOT NULL DEFAULT 0,
local_gb integer NOT NULL DEFAULT 2000,
local_gb_used integer NOT NULL DEFAULT 0,
running_vms integer NOT NULL DEFAULT 0,
service_host text,
availability_zone text REFERENCES os_availability_zones(name),
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS os_aggregates (
id integer PRIMARY KEY,
name text NOT NULL UNIQUE,
availability_zone text,
hosts jsonb NOT NULL DEFAULT '[]'::jsonb,
metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS os_compute_services (
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
"binary" text NOT NULL,
host text NOT NULL,
zone text,
status text NOT NULL DEFAULT 'enabled',
state text NOT NULL DEFAULT 'up',
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS os_demo_meta (
key text PRIMARY KEY,
value text NOT NULL,
updated_at timestamptz NOT NULL DEFAULT now()
);
-- Extra columns for richer server/volume demo metadata (idempotent).
ALTER TABLE os_servers ADD COLUMN IF NOT EXISTS availability_zone text;
ALTER TABLE os_servers ADD COLUMN IF NOT EXISTS host text;
ALTER TABLE os_volumes ADD COLUMN IF NOT EXISTS description text NOT NULL DEFAULT '';