Coverage for scripts / live_release_validation / checks / eks_capabilities.py: 100.00%

52 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-10-28 16:19 +0000

1"""Checks behind the ``eks-capabilities`` action. 

2 

3The opt-in EKS Capabilities (AWS-managed ACK and kro; see 

4``docs/EKS_CAPABILITIES.md``) are off in the shipped ``cdk.json``, and the 

5harness's preflight requires a clean worktree, so a run enables them the way 

6it enables optional schedulers: through run-scoped CDK context. This module 

7turns ``--eks-capabilities`` into the ``eks_capabilities_overrides`` JSON the 

8deploy carries and later resolves the same merged block to know what to 

9prove. 

10 

11What the action proves, per deployed Region: every enabled capability is 

12attached to the Region's cluster, ``ACTIVE`` and drift-free — read through 

13the same configured-vs-live merge ``gco stacks capabilities status`` uses 

14(``cli.eks_capabilities``), so the CLI's drift model and the harness agree. 

15What each capability then does in the cluster (a kro ResourceGraphDefinition 

16composing a Job, an ACK SQS queue) is the example harness's job 

17(``examples/kro-batch-job.yaml``, ``examples/ack-sqs-queue.yaml``). 

18""" 

19 

20from __future__ import annotations 

21 

22import json 

23from collections.abc import Mapping 

24from typing import Any 

25 

26from cli.eks_capabilities import build_status, describe_live_capabilities 

27from gco.eks_capabilities_config import ( 

28 EKS_CAPABILITY_TYPES, 

29 EksCapabilitiesConfigError, 

30 enabled_capability_types, 

31 merge_eks_capabilities_overrides, 

32 parse_eks_capabilities_overrides, 

33 validate_eks_capabilities_config, 

34) 

35 

36from ..models import RunContext 

37 

38 

39class EksCapabilitiesValidationError(RuntimeError): 

40 """The deployed capabilities do not match what the run configured.""" 

41 

42 

43# ─── run inputs -> eks_capabilities_overrides ──────────────────────────────── 

44 

45 

46def build_eks_capabilities_overrides( 

47 *, 

48 types: tuple[str, ...], 

49 extra: Mapping[str, Mapping[str, Any]] | None = None, 

50) -> dict[str, Any]: 

51 """Turn the run's capability selection into the ``eks_capabilities_overrides`` object. 

52 

53 Every named type is enabled for every Region the run deploys. ``extra`` 

54 carries per-type settings merged into that type's block (the example 

55 harness uses it to give ACK the managed policy its SQS example needs). 

56 Raises ``ValueError`` on an unknown type, or on ``extra`` for a type that 

57 is not selected. 

58 """ 

59 unknown = sorted(set(types) - set(EKS_CAPABILITY_TYPES)) 

60 if unknown: 

61 raise ValueError( 

62 "unknown EKS capability type(s): " 

63 + ", ".join(unknown) 

64 + "; valid: " 

65 + ", ".join(EKS_CAPABILITY_TYPES) 

66 ) 

67 extra = extra or {} 

68 stray = sorted(set(extra) - set(types)) 

69 if stray: 

70 raise ValueError( 

71 "capability settings for type(s) the run does not enable: " + ", ".join(stray) 

72 ) 

73 overrides: dict[str, Any] = {} 

74 for name in EKS_CAPABILITY_TYPES: 

75 if name in types: 

76 overrides[name] = {**dict(extra.get(name) or {}), "enabled": True} 

77 return overrides 

78 

79 

80def overrides_json(overrides: Mapping[str, Any]) -> str: 

81 """Canonical JSON for the ``--context`` value and the resume identity.""" 

82 return json.dumps(overrides, sort_keys=True, separators=(",", ":")) 

83 

84 

85# ─── effective configuration ───────────────────────────────────────────────── 

86 

87 

88def effective_eks_capabilities_config(ctx: RunContext) -> dict[str, Any]: 

89 """The block the run deployed with: cdk.json merged with the run's overrides.""" 

90 try: 

91 overrides = parse_eks_capabilities_overrides( 

92 getattr(ctx.settings, "eks_capabilities_overrides_json", "") or None 

93 ) 

94 raw = merge_eks_capabilities_overrides(ctx.cdk_context.get("eks_capabilities"), overrides) 

95 return validate_eks_capabilities_config(raw, ctx.deployment_regions) 

96 except EksCapabilitiesConfigError as exc: 

97 raise EksCapabilitiesValidationError(f"eks_capabilities is invalid: {exc}") from exc 

98 

99 

100def enabled_types_by_region( 

101 config: Mapping[str, Any], regions: tuple[str, ...] 

102) -> dict[str, list[str]]: 

103 """``{region: [types]}`` for the Regions where at least one type is on.""" 

104 result: dict[str, list[str]] = {} 

105 for region in regions: 

106 enabled = enabled_capability_types(config, region) 

107 if enabled: 

108 result[region] = enabled 

109 return result 

110 

111 

112# ─── AWS-side verification ─────────────────────────────────────────────────── 

113 

114 

115def verify_capabilities_attached( 

116 ctx: RunContext, 

117 region: str, 

118 config: Mapping[str, Any], 

119) -> dict[str, Any]: 

120 """Require every enabled type ACTIVE on the Region's cluster; return the CLI status document. 

121 

122 Uses ``cli.eks_capabilities.build_status`` so a failure here reads exactly 

123 like ``gco stacks capabilities status`` would report it. 

124 """ 

125 eks = ctx.session.client("eks", region_name=region) 

126 project_name = ctx.config.project_name 

127 cluster_name = f"{project_name}-{region}" 

128 cluster = eks.describe_cluster(name=cluster_name).get("cluster") or {} 

129 cluster_arn = str(cluster.get("arn") or "") 

130 if not cluster_arn: 

131 raise EksCapabilitiesValidationError(f"{region}: EKS returned no ARN for {cluster_name}") 

132 live = describe_live_capabilities(eks, cluster_name) 

133 status = build_status(region=region, project_name=project_name, config=config, live=live) 

134 problems = [f"{row['type']}: {row['drift']}" for row in status["capabilities"] if row["drift"]] 

135 if problems: 

136 raise EksCapabilitiesValidationError( 

137 f"{region}: capabilities drift from the run configuration: " + "; ".join(problems) 

138 ) 

139 status["cluster_arn"] = cluster_arn 

140 return status