diff --git a/migrate_teams_pct_workflow.sql b/migrate_teams_pct_workflow.sql new file mode 100644 index 0000000..40c6d0c --- /dev/null +++ b/migrate_teams_pct_workflow.sql @@ -0,0 +1,126 @@ +-- Migration : architecture intervention complète (Teams + PCT + workflow) +-- - teams_channels (canaux Teams configurés) +-- - server_clusters (groupes avec ordre de redémarrage) +-- - contacts enrichis (teams_upn, phone, is_pct_member) +-- - applications enrichies (teams_channel_id, pct_required, pct_email override) +-- - servers enrichis (FK contacts, teams, pct, snap policy, hooks pre/post, +-- cluster + cluster_order) +-- - patch_planning_import_rows enrichis (workflow intervention complet) +-- Idempotent — exécutable plusieurs fois. + +-- ─── 1) Nouvelles tables ────────────────────────────────────── + +CREATE TABLE IF NOT EXISTS public.teams_channels ( + id SERIAL PRIMARY KEY, + name text NOT NULL, + webhook_url text NOT NULL, + description text, + is_active boolean NOT NULL DEFAULT true, + is_default boolean NOT NULL DEFAULT false, + created_at timestamptz NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS public.server_clusters ( + id SERIAL PRIMARY KEY, + name text NOT NULL UNIQUE, + description text, + reboot_strategy text NOT NULL DEFAULT 'sequential', + -- sequential | parallel + is_active boolean NOT NULL DEFAULT true, + created_at timestamptz NOT NULL DEFAULT now() +); + +-- ─── 2) Enrichir contacts ───────────────────────────────────── + +ALTER TABLE public.contacts + ADD COLUMN IF NOT EXISTS teams_upn text, + ADD COLUMN IF NOT EXISTS phone text, + ADD COLUMN IF NOT EXISTS is_pct_member boolean DEFAULT false; + +-- ─── 3) Enrichir applications ──────────────────────────────── + +ALTER TABLE public.applications + ADD COLUMN IF NOT EXISTS teams_channel_id integer REFERENCES public.teams_channels(id) ON DELETE SET NULL, + ADD COLUMN IF NOT EXISTS pct_required boolean DEFAULT false, + ADD COLUMN IF NOT EXISTS pct_email text; + -- pct_email : override si différent du défaut global (pct.reims@sanef.com) + +-- ─── 4) Enrichir servers ───────────────────────────────────── + +ALTER TABLE public.servers + ADD COLUMN IF NOT EXISTS responsable_domaine_contact_id integer REFERENCES public.contacts(id) ON DELETE SET NULL, + ADD COLUMN IF NOT EXISTS referent_technique_contact_id integer REFERENCES public.contacts(id) ON DELETE SET NULL, + ADD COLUMN IF NOT EXISTS valideur_ra_contact_id integer REFERENCES public.contacts(id) ON DELETE SET NULL, + ADD COLUMN IF NOT EXISTS teams_channel_id integer REFERENCES public.teams_channels(id) ON DELETE SET NULL, + ADD COLUMN IF NOT EXISTS pct_required boolean DEFAULT false, + ADD COLUMN IF NOT EXISTS requires_snapshot boolean DEFAULT true, + ADD COLUMN IF NOT EXISTS snap_can_be_skipped boolean DEFAULT false, + ADD COLUMN IF NOT EXISTS pre_patch_cmd text, + ADD COLUMN IF NOT EXISTS post_patch_cmd text, + ADD COLUMN IF NOT EXISTS cluster_id integer REFERENCES public.server_clusters(id) ON DELETE SET NULL, + ADD COLUMN IF NOT EXISTS cluster_order integer; + +-- Backfill : physiques → requires_snapshot=false (snap vCenter pas applicable) +UPDATE public.servers + SET requires_snapshot = false + WHERE LOWER(COALESCE(machine_type::text, '')) LIKE '%physic%'; + +-- ─── 5) Enrichir patch_planning_import_rows (workflow intervention) ─ + +ALTER TABLE public.patch_planning_import_rows + ADD COLUMN IF NOT EXISTS intervention_started_at timestamptz, + ADD COLUMN IF NOT EXISTS intervention_finished_at timestamptz, + ADD COLUMN IF NOT EXISTS validated_at timestamptz, + ADD COLUMN IF NOT EXISTS validated_by_contact_id integer REFERENCES public.contacts(id) ON DELETE SET NULL, + ADD COLUMN IF NOT EXISTS validation_status text, + -- 'ok' | 'ko' | 'en_attente' | NULL + ADD COLUMN IF NOT EXISTS validation_note text, + ADD COLUMN IF NOT EXISTS snap_skipped boolean DEFAULT false, + ADD COLUMN IF NOT EXISTS snap_skip_reason text, + ADD COLUMN IF NOT EXISTS patch_forced boolean DEFAULT false, + ADD COLUMN IF NOT EXISTS patch_forced_reason text, + ADD COLUMN IF NOT EXISTS teams_reminder_sent_at timestamptz, + ADD COLUMN IF NOT EXISTS teams_start_sent_at timestamptz, + ADD COLUMN IF NOT EXISTS teams_end_sent_at timestamptz, + ADD COLUMN IF NOT EXISTS pct_mail_sent_at timestamptz, + ADD COLUMN IF NOT EXISTS rollback_done_at timestamptz, + ADD COLUMN IF NOT EXISTS rollback_method text; + -- rollback_method : 'yum_undo' | 'snapshot_restore' | 'commvault' | 'manual' + +-- ─── 6) Index ───────────────────────────────────────────────── + +CREATE INDEX IF NOT EXISTS idx_pp_rows_validation_status + ON public.patch_planning_import_rows(validation_status) + WHERE validation_status IS NOT NULL; + +CREATE INDEX IF NOT EXISTS idx_pp_rows_intervention_started + ON public.patch_planning_import_rows(intervention_started_at) + WHERE intervention_started_at IS NOT NULL; + +CREATE INDEX IF NOT EXISTS idx_servers_cluster + ON public.servers(cluster_id, cluster_order) + WHERE cluster_id IS NOT NULL; + +CREATE INDEX IF NOT EXISTS idx_servers_resp_domaine + ON public.servers(responsable_domaine_contact_id) + WHERE responsable_domaine_contact_id IS NOT NULL; + +CREATE INDEX IF NOT EXISTS idx_servers_referent + ON public.servers(referent_technique_contact_id) + WHERE referent_technique_contact_id IS NOT NULL; + +CREATE INDEX IF NOT EXISTS idx_servers_valideur + ON public.servers(valideur_ra_contact_id) + WHERE valideur_ra_contact_id IS NOT NULL; + +-- ─── 7) GRANT pour le user applicatif ───────────────────────── + +GRANT SELECT, INSERT, UPDATE, DELETE ON public.teams_channels TO patchcenter; +GRANT SELECT, INSERT, UPDATE, DELETE ON public.server_clusters TO patchcenter; +GRANT USAGE, SELECT ON SEQUENCE public.teams_channels_id_seq TO patchcenter; +GRANT USAGE, SELECT ON SEQUENCE public.server_clusters_id_seq TO patchcenter; + +-- ─── Note ───────────────────────────────────────────────────── +-- Le mail PCT global ('pct.reims@sanef.com') sera configuré via l'UI +-- Settings (M5) car app_secrets utilise un chiffrement Fernet — on ne peut +-- pas l'INSERT en clair via SQL.