Coverage for gco / enablement_overrides.py: 100.00%
29 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-09-14 22:07 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-09-14 22:07 +0000
1"""Run-scoped enablement overrides shared by the CLI and the recorders.
3GCO ships every optional add-on **off** in ``cdk.json`` because each one
4carries real recurring cost (an FSx for Lustre filesystem has a 1.2 TiB
5provisioned floor; Aurora Serverless v2 keeps a writer and a reader; Valkey
6Serverless bills storage and ECPUs). Two CDK context keys exist so a single
7run can force those features on *without rewriting the committed config*:
9``feature_enabled_overrides``
10 Infrastructure blocks whose top-level ``enabled`` flag may be forced on
11 (see ``gco.config.config_loader.parse_feature_enabled_overrides``).
13``helm_enabled_overrides``
14 ``helm`` block keys whose chart may be forced on (see
15 ``gco.stacks.regional_stack._parse_helm_enabled_overrides``).
17Both consumers live in modules that import ``aws_cdk``. The CLI must be able
18to validate ``--enable`` names and build the ``--context`` pairs *before* the
19CDK Python toolchain is known to be importable — ``StackManager._run_cdk``
20deliberately fails with an actionable message in that case rather than an
21``ImportError`` at startup. So the canonical name sets live here, in a module
22with no third-party imports, and ``tests/test_enablement_overrides.py`` pins
23them in lockstep with the two authoritative parsers.
25Overrides are one-way: they can only *enable*. A feature an operator turned
26off stays off unless it is named explicitly.
27"""
29from __future__ import annotations
31from collections.abc import Iterable
33#: CDK context key carrying forced-on infrastructure feature blocks.
34FEATURE_OVERRIDE_CONTEXT_KEY = "feature_enabled_overrides"
36#: CDK context key carrying forced-on Helm chart keys.
37HELM_OVERRIDE_CONTEXT_KEY = "helm_enabled_overrides"
39#: cdk.json blocks ``feature_enabled_overrides`` accepts. Lockstep with
40#: ``gco.config.config_loader.FEATURE_OVERRIDE_KEYS``.
41FEATURE_OVERRIDE_KEYS = frozenset({"aurora_pgvector", "valkey", "fsx_lustre", "vector_store"})
43#: cdk.json ``helm`` block keys ``helm_enabled_overrides`` accepts. Lockstep
44#: with ``gco.stacks.regional_stack._HELM_CHART_CONFIG_KEYS``.
45HELM_CHART_CONFIG_KEYS = frozenset(
46 {
47 "aws_load_balancer_controller",
48 "keda",
49 "aws_efa_device_plugin",
50 "aws_neuron_device_plugin",
51 "volcano",
52 "kuberay",
53 "cert_manager",
54 "slurm",
55 "yunikorn",
56 "kubeflow_trainer",
57 "kueue",
58 }
59)
62class EnablementOverrideError(ValueError):
63 """Raised when a requested override name is not a known feature or chart."""
66def split_override_names(raw: Iterable[str]) -> list[str]:
67 """Flatten repeated and comma-joined ``--enable`` values into bare names.
69 Accepts the two shapes a caller can produce interchangeably —
70 ``--enable valkey --enable slurm`` and ``--enable valkey,slurm`` — and
71 drops empty segments so a trailing comma is not an error. Order is
72 preserved for the caller's benefit; duplicates are left intact because
73 :func:`route_enablement_overrides` de-duplicates when it groups.
74 """
75 names: list[str] = []
76 for entry in raw:
77 for part in entry.split(","):
78 candidate = part.strip()
79 if candidate:
80 names.append(candidate)
81 return names
84def route_enablement_overrides(raw: Iterable[str]) -> dict[str, str]:
85 """Group requested names into the CDK ``--context`` pairs they belong to.
87 The two namespaces are disjoint, so each name routes unambiguously: a
88 caller says ``--enable fsx_lustre,slurm`` and gets both
89 ``feature_enabled_overrides=fsx_lustre`` and
90 ``helm_enabled_overrides=slurm``. Names are sorted so the resulting
91 context is byte-identical for any input ordering, which keeps a resumed
92 or re-recorded run's argv stable.
94 Returns an empty mapping when nothing was requested, so callers can pass
95 the result straight to ``StackManager.set_extra_cdk_context``.
97 Raises:
98 EnablementOverrideError: if any name is neither a known feature block
99 nor a known Helm chart key. Failing here — before any AWS call —
100 means a typo can never silently deploy without the feature the
101 operator asked for.
102 """
103 requested = set(split_override_names(raw))
104 unknown = sorted(requested - FEATURE_OVERRIDE_KEYS - HELM_CHART_CONFIG_KEYS)
105 if unknown:
106 valid = ", ".join(sorted(FEATURE_OVERRIDE_KEYS | HELM_CHART_CONFIG_KEYS))
107 raise EnablementOverrideError(
108 f"Unknown --enable name(s): {', '.join(unknown)}. Valid: {valid}"
109 )
111 context: dict[str, str] = {}
112 features = sorted(requested & FEATURE_OVERRIDE_KEYS)
113 charts = sorted(requested & HELM_CHART_CONFIG_KEYS)
114 if features:
115 context[FEATURE_OVERRIDE_CONTEXT_KEY] = ",".join(features)
116 if charts:
117 context[HELM_OVERRIDE_CONTEXT_KEY] = ",".join(charts)
118 return context