97 lines
4.7 KiB
SQL
97 lines
4.7 KiB
SQL
-- simple-cost-dashboard — schéma SQLite
|
|
--
|
|
-- Une "collection" = un relevé de coût pour un tenant sur une période donnée.
|
|
-- granularity='daily' -> alimenté par le cron (1 jour = 1 ligne)
|
|
-- granularity='monthly' -> alimenté par l'import historique (1 mois = 1 ligne),
|
|
-- utilisé pour les données antérieures à la mise en
|
|
-- place de la collecte journalière.
|
|
--
|
|
-- Le montant est figé en EUR au moment de la collecte (avec le taux utilisé),
|
|
-- pour que l'historique affiché ne bouge pas quand le taux de change évolue.
|
|
|
|
CREATE TABLE IF NOT EXISTS collections (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
provider TEXT NOT NULL CHECK(provider IN ('aws', 'azure')),
|
|
tenant_name TEXT NOT NULL,
|
|
granularity TEXT NOT NULL CHECK(granularity IN ('daily', 'monthly')),
|
|
period_start DATE NOT NULL, -- inclusif
|
|
period_end DATE NOT NULL, -- exclusif
|
|
collected_at TIMESTAMP NOT NULL,
|
|
status TEXT NOT NULL CHECK(status IN ('ok', 'error')),
|
|
error_message TEXT,
|
|
total_amount REAL, -- en EUR (figé)
|
|
currency TEXT, -- 'EUR'
|
|
original_total REAL, -- montant avant conversion
|
|
original_currency TEXT, -- devise de facturation d'origine
|
|
exchange_rate REAL, -- taux appliqué au moment de la collecte
|
|
UNIQUE(provider, tenant_name, granularity, period_start)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_collections_lookup
|
|
ON collections(provider, tenant_name, granularity, period_start);
|
|
|
|
CREATE TABLE IF NOT EXISTS service_costs (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
collection_id INTEGER NOT NULL REFERENCES collections(id) ON DELETE CASCADE,
|
|
service_name TEXT NOT NULL,
|
|
amount REAL NOT NULL -- en EUR (figé)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_service_costs_collection
|
|
ON service_costs(collection_id);
|
|
|
|
-- Détail par ressource (bucket S3, instance EC2, fonction Lambda, VM Azure...).
|
|
-- Cliché glissant sur les 14 derniers jours, réécrit à chaque collecte — pas
|
|
-- un historique jour par jour comme `collections` : AWS Cost Explorer ne
|
|
-- fournit le détail par ressource que sur cette fenêtre (limite dure de
|
|
-- l'API, indépendante de notre code), donc conserver plus d'historique
|
|
-- n'apporterait rien. Pour rester cohérent entre providers, Azure (qui n'a
|
|
-- pas cette limite) utilise la même fenêtre de 14 jours.
|
|
CREATE TABLE IF NOT EXISTS resource_costs (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
provider TEXT NOT NULL CHECK(provider IN ('aws', 'azure')),
|
|
tenant_name TEXT NOT NULL,
|
|
service_name TEXT NOT NULL,
|
|
resource_id TEXT NOT NULL, -- ARN AWS / resource ID Azure complet
|
|
resource_name TEXT NOT NULL, -- dernier segment, pour l'affichage
|
|
period_start DATE NOT NULL,
|
|
period_end DATE NOT NULL,
|
|
amount REAL NOT NULL, -- en EUR (figé), somme sur la fenêtre
|
|
UNIQUE(provider, tenant_name, service_name, resource_id)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_resource_costs_lookup
|
|
ON resource_costs(provider, tenant_name, service_name);
|
|
|
|
-- Statut de la collecte resource-level, séparé de `collections` : elle peut
|
|
-- échouer pour une raison différente (ex: "Resource IDs" non activé côté
|
|
-- AWS Cost Explorer) sans que la collecte quotidienne normale soit en cause.
|
|
CREATE TABLE IF NOT EXISTS resource_collection_status (
|
|
provider TEXT NOT NULL CHECK(provider IN ('aws', 'azure')),
|
|
tenant_name TEXT NOT NULL,
|
|
status TEXT NOT NULL CHECK(status IN ('ok', 'unavailable', 'error')),
|
|
message TEXT,
|
|
collected_at TIMESTAMP NOT NULL,
|
|
PRIMARY KEY (provider, tenant_name)
|
|
);
|
|
|
|
-- Historique des exécutions de tâches de collecte (page "Collecte" du
|
|
-- dashboard) : une ligne par lancement de collect.py (run_type='daily') ou
|
|
-- backfill_historical.py (run_type='backfill'). Le détail des tenants en
|
|
-- erreur n'est pas dupliqué ici : il se relit dans `collections`
|
|
-- (status='error') sur la fenêtre [started_at, finished_at] de l'exécution.
|
|
-- acknowledged_at reste NULL tant qu'une erreur n'a pas été acquittée
|
|
-- manuellement depuis le dashboard.
|
|
CREATE TABLE IF NOT EXISTS collection_runs (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
run_type TEXT NOT NULL CHECK(run_type IN ('daily', 'backfill')),
|
|
started_at TIMESTAMP NOT NULL,
|
|
finished_at TIMESTAMP,
|
|
tenants_ok INTEGER NOT NULL DEFAULT 0,
|
|
tenants_error INTEGER NOT NULL DEFAULT 0,
|
|
acknowledged_at TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_collection_runs_started
|
|
ON collection_runs(started_at);
|