316 lines
12 KiB
PL/PgSQL
316 lines
12 KiB
PL/PgSQL
-- Migration: Add Pack Runtime Environments
|
|
-- Description: Adds support for per-pack isolated runtime environments with installer metadata
|
|
-- Version: 20260203000002
|
|
|
|
-- ============================================================================
|
|
-- PART 1: Add installer metadata to runtime table
|
|
-- ============================================================================
|
|
|
|
-- Add installers field to runtime table for environment setup instructions
|
|
ALTER TABLE runtime ADD COLUMN IF NOT EXISTS installers JSONB DEFAULT '[]'::jsonb;
|
|
|
|
COMMENT ON COLUMN runtime.installers IS 'Array of installer actions to create pack-specific runtime environments. Each installer defines commands to set up isolated environments (e.g., Python venv, npm install).
|
|
|
|
Structure:
|
|
{
|
|
"installers": [
|
|
{
|
|
"name": "create_environment",
|
|
"description": "Create isolated runtime environment",
|
|
"command": "python3",
|
|
"args": ["-m", "venv", "{env_path}"],
|
|
"cwd": "{pack_path}",
|
|
"env": {},
|
|
"order": 1
|
|
},
|
|
{
|
|
"name": "install_dependencies",
|
|
"description": "Install pack dependencies",
|
|
"command": "{env_path}/bin/pip",
|
|
"args": ["install", "-r", "{pack_path}/requirements.txt"],
|
|
"cwd": "{pack_path}",
|
|
"env": {},
|
|
"order": 2,
|
|
"optional": false
|
|
}
|
|
]
|
|
}
|
|
|
|
Template variables:
|
|
{env_path} - Full path to environment directory (e.g., /opt/attune/packenvs/mypack/python)
|
|
{pack_path} - Full path to pack directory (e.g., /opt/attune/packs/mypack)
|
|
{pack_ref} - Pack reference (e.g., mycompany.monitoring)
|
|
{runtime_ref} - Runtime reference (e.g., core.python)
|
|
{runtime_name} - Runtime name (e.g., Python)
|
|
';
|
|
|
|
-- ============================================================================
|
|
-- PART 2: Create pack_environment table
|
|
-- ============================================================================
|
|
|
|
-- Pack environment table
|
|
CREATE TABLE IF NOT EXISTS pack_environment (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
pack BIGINT NOT NULL REFERENCES pack(id) ON DELETE CASCADE,
|
|
pack_ref TEXT NOT NULL,
|
|
runtime BIGINT NOT NULL REFERENCES runtime(id) ON DELETE CASCADE,
|
|
runtime_ref TEXT NOT NULL,
|
|
env_path TEXT NOT NULL,
|
|
status pack_environment_status_enum NOT NULL DEFAULT 'pending',
|
|
installed_at TIMESTAMPTZ,
|
|
last_verified TIMESTAMPTZ,
|
|
install_log TEXT,
|
|
install_error TEXT,
|
|
metadata JSONB DEFAULT '{}'::jsonb,
|
|
created TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
UNIQUE(pack, runtime)
|
|
);
|
|
|
|
-- Indexes
|
|
CREATE INDEX IF NOT EXISTS idx_pack_environment_pack ON pack_environment(pack);
|
|
CREATE INDEX IF NOT EXISTS idx_pack_environment_runtime ON pack_environment(runtime);
|
|
CREATE INDEX IF NOT EXISTS idx_pack_environment_status ON pack_environment(status);
|
|
CREATE INDEX IF NOT EXISTS idx_pack_environment_pack_ref ON pack_environment(pack_ref);
|
|
CREATE INDEX IF NOT EXISTS idx_pack_environment_runtime_ref ON pack_environment(runtime_ref);
|
|
CREATE INDEX IF NOT EXISTS idx_pack_environment_pack_runtime ON pack_environment(pack, runtime);
|
|
|
|
-- Trigger for updated timestamp
|
|
CREATE TRIGGER update_pack_environment_updated
|
|
BEFORE UPDATE ON pack_environment
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION update_updated_column();
|
|
|
|
-- Comments
|
|
COMMENT ON TABLE pack_environment IS 'Tracks pack-specific runtime environments for dependency isolation';
|
|
COMMENT ON COLUMN pack_environment.pack IS 'Pack that owns this environment';
|
|
COMMENT ON COLUMN pack_environment.pack_ref IS 'Pack reference for quick lookup';
|
|
COMMENT ON COLUMN pack_environment.runtime IS 'Runtime used for this environment';
|
|
COMMENT ON COLUMN pack_environment.runtime_ref IS 'Runtime reference for quick lookup';
|
|
COMMENT ON COLUMN pack_environment.env_path IS 'Filesystem path to the environment directory (e.g., /opt/attune/packenvs/mypack/python)';
|
|
COMMENT ON COLUMN pack_environment.status IS 'Current installation status';
|
|
COMMENT ON COLUMN pack_environment.installed_at IS 'When the environment was successfully installed';
|
|
COMMENT ON COLUMN pack_environment.last_verified IS 'Last time the environment was verified as working';
|
|
COMMENT ON COLUMN pack_environment.install_log IS 'Installation output logs';
|
|
COMMENT ON COLUMN pack_environment.install_error IS 'Error message if installation failed';
|
|
COMMENT ON COLUMN pack_environment.metadata IS 'Additional metadata (installed packages, versions, etc.)';
|
|
|
|
-- ============================================================================
|
|
-- PART 3: Update existing runtimes with installer metadata
|
|
-- ============================================================================
|
|
|
|
-- Python runtime installers
|
|
UPDATE runtime
|
|
SET installers = jsonb_build_object(
|
|
'base_path_template', '/opt/attune/packenvs/{pack_ref}/{runtime_name_lower}',
|
|
'installers', jsonb_build_array(
|
|
jsonb_build_object(
|
|
'name', 'create_venv',
|
|
'description', 'Create Python virtual environment',
|
|
'command', 'python3',
|
|
'args', jsonb_build_array('-m', 'venv', '{env_path}'),
|
|
'cwd', '{pack_path}',
|
|
'env', jsonb_build_object(),
|
|
'order', 1,
|
|
'optional', false
|
|
),
|
|
jsonb_build_object(
|
|
'name', 'upgrade_pip',
|
|
'description', 'Upgrade pip to latest version',
|
|
'command', '{env_path}/bin/pip',
|
|
'args', jsonb_build_array('install', '--upgrade', 'pip'),
|
|
'cwd', '{pack_path}',
|
|
'env', jsonb_build_object(),
|
|
'order', 2,
|
|
'optional', true
|
|
),
|
|
jsonb_build_object(
|
|
'name', 'install_requirements',
|
|
'description', 'Install pack Python dependencies',
|
|
'command', '{env_path}/bin/pip',
|
|
'args', jsonb_build_array('install', '-r', '{pack_path}/requirements.txt'),
|
|
'cwd', '{pack_path}',
|
|
'env', jsonb_build_object(),
|
|
'order', 3,
|
|
'optional', false,
|
|
'condition', jsonb_build_object(
|
|
'file_exists', '{pack_path}/requirements.txt'
|
|
)
|
|
)
|
|
),
|
|
'executable_templates', jsonb_build_object(
|
|
'python', '{env_path}/bin/python',
|
|
'pip', '{env_path}/bin/pip'
|
|
)
|
|
)
|
|
WHERE ref = 'core.python';
|
|
|
|
-- Node.js runtime installers
|
|
UPDATE runtime
|
|
SET installers = jsonb_build_object(
|
|
'base_path_template', '/opt/attune/packenvs/{pack_ref}/{runtime_name_lower}',
|
|
'installers', jsonb_build_array(
|
|
jsonb_build_object(
|
|
'name', 'npm_install',
|
|
'description', 'Install Node.js dependencies',
|
|
'command', 'npm',
|
|
'args', jsonb_build_array('install', '--prefix', '{env_path}'),
|
|
'cwd', '{pack_path}',
|
|
'env', jsonb_build_object(
|
|
'NODE_PATH', '{env_path}/node_modules'
|
|
),
|
|
'order', 1,
|
|
'optional', false,
|
|
'condition', jsonb_build_object(
|
|
'file_exists', '{pack_path}/package.json'
|
|
)
|
|
)
|
|
),
|
|
'executable_templates', jsonb_build_object(
|
|
'node', 'node',
|
|
'npm', 'npm'
|
|
),
|
|
'env_vars', jsonb_build_object(
|
|
'NODE_PATH', '{env_path}/node_modules'
|
|
)
|
|
)
|
|
WHERE ref = 'core.nodejs';
|
|
|
|
-- Shell runtime (no environment needed, uses system shell)
|
|
UPDATE runtime
|
|
SET installers = jsonb_build_object(
|
|
'base_path_template', '/opt/attune/packenvs/{pack_ref}/{runtime_name_lower}',
|
|
'installers', jsonb_build_array(),
|
|
'executable_templates', jsonb_build_object(
|
|
'sh', 'sh',
|
|
'bash', 'bash'
|
|
),
|
|
'requires_environment', false
|
|
)
|
|
WHERE ref = 'core.shell';
|
|
|
|
-- Native runtime (no environment needed, binaries are standalone)
|
|
UPDATE runtime
|
|
SET installers = jsonb_build_object(
|
|
'base_path_template', '/opt/attune/packenvs/{pack_ref}/{runtime_name_lower}',
|
|
'installers', jsonb_build_array(),
|
|
'executable_templates', jsonb_build_object(),
|
|
'requires_environment', false
|
|
)
|
|
WHERE ref = 'core.native';
|
|
|
|
-- Built-in sensor runtime (internal, no environment)
|
|
UPDATE runtime
|
|
SET installers = jsonb_build_object(
|
|
'installers', jsonb_build_array(),
|
|
'requires_environment', false
|
|
)
|
|
WHERE ref = 'core.sensor.builtin';
|
|
|
|
-- ============================================================================
|
|
-- PART 4: Add helper functions
|
|
-- ============================================================================
|
|
|
|
-- Function to get environment path for a pack/runtime combination
|
|
CREATE OR REPLACE FUNCTION get_pack_environment_path(p_pack_ref TEXT, p_runtime_ref TEXT)
|
|
RETURNS TEXT AS $$
|
|
DECLARE
|
|
v_runtime_name TEXT;
|
|
v_base_template TEXT;
|
|
v_result TEXT;
|
|
BEGIN
|
|
-- Get runtime name and base path template
|
|
SELECT
|
|
LOWER(name),
|
|
installers->>'base_path_template'
|
|
INTO v_runtime_name, v_base_template
|
|
FROM runtime
|
|
WHERE ref = p_runtime_ref;
|
|
|
|
IF v_base_template IS NULL THEN
|
|
v_base_template := '/opt/attune/packenvs/{pack_ref}/{runtime_name_lower}';
|
|
END IF;
|
|
|
|
-- Replace template variables
|
|
v_result := v_base_template;
|
|
v_result := REPLACE(v_result, '{pack_ref}', p_pack_ref);
|
|
v_result := REPLACE(v_result, '{runtime_ref}', p_runtime_ref);
|
|
v_result := REPLACE(v_result, '{runtime_name_lower}', v_runtime_name);
|
|
|
|
RETURN v_result;
|
|
END;
|
|
$$ LANGUAGE plpgsql IMMUTABLE;
|
|
|
|
COMMENT ON FUNCTION get_pack_environment_path IS 'Calculate the filesystem path for a pack runtime environment';
|
|
|
|
-- Function to check if a runtime requires an environment
|
|
CREATE OR REPLACE FUNCTION runtime_requires_environment(p_runtime_ref TEXT)
|
|
RETURNS BOOLEAN AS $$
|
|
DECLARE
|
|
v_requires BOOLEAN;
|
|
BEGIN
|
|
SELECT COALESCE((installers->>'requires_environment')::boolean, true)
|
|
INTO v_requires
|
|
FROM runtime
|
|
WHERE ref = p_runtime_ref;
|
|
|
|
RETURN COALESCE(v_requires, false);
|
|
END;
|
|
$$ LANGUAGE plpgsql STABLE;
|
|
|
|
COMMENT ON FUNCTION runtime_requires_environment IS 'Check if a runtime needs a pack-specific environment';
|
|
|
|
-- ============================================================================
|
|
-- PART 5: Create view for environment status
|
|
-- ============================================================================
|
|
|
|
CREATE OR REPLACE VIEW v_pack_environment_status AS
|
|
SELECT
|
|
pe.id,
|
|
pe.pack,
|
|
p.ref AS pack_ref,
|
|
p.label AS pack_name,
|
|
pe.runtime,
|
|
r.ref AS runtime_ref,
|
|
r.name AS runtime_name,
|
|
pe.env_path,
|
|
pe.status,
|
|
pe.installed_at,
|
|
pe.last_verified,
|
|
CASE
|
|
WHEN pe.status = 'ready' AND pe.last_verified < NOW() - INTERVAL '7 days' THEN true
|
|
ELSE false
|
|
END AS needs_verification,
|
|
CASE
|
|
WHEN pe.status = 'ready' THEN 'healthy'
|
|
WHEN pe.status = 'failed' THEN 'unhealthy'
|
|
WHEN pe.status IN ('pending', 'installing') THEN 'provisioning'
|
|
WHEN pe.status = 'outdated' THEN 'needs_update'
|
|
ELSE 'unknown'
|
|
END AS health_status,
|
|
pe.install_error,
|
|
pe.created,
|
|
pe.updated
|
|
FROM pack_environment pe
|
|
JOIN pack p ON pe.pack = p.id
|
|
JOIN runtime r ON pe.runtime = r.id;
|
|
|
|
COMMENT ON VIEW v_pack_environment_status IS 'Consolidated view of pack environment status with health indicators';
|
|
|
|
-- ============================================================================
|
|
-- SUMMARY
|
|
-- ============================================================================
|
|
|
|
-- Display summary of changes
|
|
DO $$
|
|
BEGIN
|
|
RAISE NOTICE 'Pack environment system migration complete.';
|
|
RAISE NOTICE '';
|
|
RAISE NOTICE 'New table: pack_environment (tracks installed environments)';
|
|
RAISE NOTICE 'New column: runtime.installers (environment setup instructions)';
|
|
RAISE NOTICE 'New functions: get_pack_environment_path, runtime_requires_environment';
|
|
RAISE NOTICE 'New view: v_pack_environment_status';
|
|
RAISE NOTICE '';
|
|
RAISE NOTICE 'Environment paths will be: /opt/attune/packenvs/{pack_ref}/{runtime}';
|
|
END $$;
|