Loading ci/README.md +4 −0 Changes for ci/README.md: 4 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -54,3 +54,7 @@ The downstream trigger disables inheritance of SDK default variables and passes only the explicit SDK artifact coordinates. Job-only paths such as TMPDIR must be established by the owning project. Candidate rc1 exposed this boundary issue and was not published; rc2 retains a new immutable tag instead of moving rc1. Packaged container chart checks render canonical CPU millicores and decimal MB requests, including omission and absence of invented limits. Provider regressions exercise the same mapping through activation and update. ci/verify.py +17 −5 Changes for ci/verify.py: 17 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -182,13 +182,23 @@ def charts(): chart = Path(openop_tfsdk.__file__).parent / "contract/adapters/charts/container" helm = helm_binary() image = "example.invalid/fixture@sha256:" + "a" * 64 for name, service_type, ports in [ ("none", "ClusterIP", []), ("internal", "ClusterIP", [{"name": "p80-tcp", "port": 80, "protocol": "TCP"}]), ("external", "NodePort", [{"name": "p80-tcp", "port": 80, "protocol": "TCP"}]), for name, service_type, ports, requests in [ ("none", "ClusterIP", [], {}), ("internal", "ClusterIP", [{"name": "p80-tcp", "port": 80, "protocol": "TCP"}], {}), ("external", "NodePort", [{"name": "p80-tcp", "port": 80, "protocol": "TCP"}], {}), ("requests", "ClusterIP", [], {"cpu": "250m", "memory": "257M"}), ]: values = OUT / f"chart-{name}.json" write_json(values, {"image": image, "serviceType": service_type, "ports": ports}) expected_resources = {"requests": requests} if requests else {} write_json( values, { "image": image, "serviceType": service_type, "ports": ports, "resources": expected_resources, }, ) run(helm, "lint", chart, "--strict", "-f", values) raw = subprocess.check_output( [ Loading @@ -208,6 +218,8 @@ def charts(): deployment = objects["Deployment"] spec = deployment["spec"]["template"]["spec"]["containers"][0] assert spec["image"] == image assert spec.get("resources", {}) == expected_resources assert "limits" not in spec.get("resources", {}) assert spec.get("ports", []) == [ {"name": p["name"], "containerPort": p["port"], "protocol": p["protocol"]} for p in ports Loading src/openop_tfsdk/contract/adapters/charts/container/templates/deployment.yaml +4 −0 Changes for src/openop_tfsdk/contract/adapters/charts/container/templates/deployment.yaml: 4 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -25,3 +25,7 @@ spec: protocol: {{ .protocol }} {{- end }} {{- end }} {{- with .Values.resources }} resources: {{- toYaml . | nindent 12 }} {{- end }} src/openop_tfsdk/contract/adapters/charts/container/values.yaml +2 −0 Changes for src/openop_tfsdk/contract/adapters/charts/container/values.yaml: 2 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -3,3 +3,5 @@ image: "" # Each port: {name, port, protocol}. ports: [] serviceType: ClusterIP # Kubernetes container resources (requests/limits). Empty when no compute intent. resources: {} src/openop_tfsdk/contract/adapters/kubernetes.py +17 −0 Changes for src/openop_tfsdk/contract/adapters/kubernetes.py: 17 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -99,10 +99,27 @@ def _chart_args(unit) -> list: raise ValidationError( "kubernetes container does not support mixed internal and external ports" ) compute = ( getattr(unit.resource_requirements, "compute", None) if unit.resource_requirements else None ) requests: dict[str, str] = {} if compute is not None: cpu_millicores = getattr(compute, "cpu_millicores", None) memory_mb = getattr(compute, "memory_mb", None) if cpu_millicores is not None and cpu_millicores < 0: raise ValidationError("container compute requests must be nonnegative") if memory_mb is not None and memory_mb < 0: raise ValidationError("container compute requests must be nonnegative") if cpu_millicores is not None and cpu_millicores > 0: requests["cpu"] = f"{cpu_millicores}m" if memory_mb is not None and memory_mb > 0: requests["memory"] = f"{memory_mb}M" resources = {"requests": requests} if requests else {} values = { "image": unit.artifact_ref, "ports": list(ports.values()), "serviceType": "NodePort" if external else "ClusterIP", "resources": resources, } return [CONTAINER_CHART] + [ arg for key, value in values.items() for arg in ("--set-json", f"{key}={json.dumps(value)}") Loading Loading
ci/README.md +4 −0 Changes for ci/README.md: 4 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -54,3 +54,7 @@ The downstream trigger disables inheritance of SDK default variables and passes only the explicit SDK artifact coordinates. Job-only paths such as TMPDIR must be established by the owning project. Candidate rc1 exposed this boundary issue and was not published; rc2 retains a new immutable tag instead of moving rc1. Packaged container chart checks render canonical CPU millicores and decimal MB requests, including omission and absence of invented limits. Provider regressions exercise the same mapping through activation and update.
ci/verify.py +17 −5 Changes for ci/verify.py: 17 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -182,13 +182,23 @@ def charts(): chart = Path(openop_tfsdk.__file__).parent / "contract/adapters/charts/container" helm = helm_binary() image = "example.invalid/fixture@sha256:" + "a" * 64 for name, service_type, ports in [ ("none", "ClusterIP", []), ("internal", "ClusterIP", [{"name": "p80-tcp", "port": 80, "protocol": "TCP"}]), ("external", "NodePort", [{"name": "p80-tcp", "port": 80, "protocol": "TCP"}]), for name, service_type, ports, requests in [ ("none", "ClusterIP", [], {}), ("internal", "ClusterIP", [{"name": "p80-tcp", "port": 80, "protocol": "TCP"}], {}), ("external", "NodePort", [{"name": "p80-tcp", "port": 80, "protocol": "TCP"}], {}), ("requests", "ClusterIP", [], {"cpu": "250m", "memory": "257M"}), ]: values = OUT / f"chart-{name}.json" write_json(values, {"image": image, "serviceType": service_type, "ports": ports}) expected_resources = {"requests": requests} if requests else {} write_json( values, { "image": image, "serviceType": service_type, "ports": ports, "resources": expected_resources, }, ) run(helm, "lint", chart, "--strict", "-f", values) raw = subprocess.check_output( [ Loading @@ -208,6 +218,8 @@ def charts(): deployment = objects["Deployment"] spec = deployment["spec"]["template"]["spec"]["containers"][0] assert spec["image"] == image assert spec.get("resources", {}) == expected_resources assert "limits" not in spec.get("resources", {}) assert spec.get("ports", []) == [ {"name": p["name"], "containerPort": p["port"], "protocol": p["protocol"]} for p in ports Loading
src/openop_tfsdk/contract/adapters/charts/container/templates/deployment.yaml +4 −0 Changes for src/openop_tfsdk/contract/adapters/charts/container/templates/deployment.yaml: 4 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -25,3 +25,7 @@ spec: protocol: {{ .protocol }} {{- end }} {{- end }} {{- with .Values.resources }} resources: {{- toYaml . | nindent 12 }} {{- end }}
src/openop_tfsdk/contract/adapters/charts/container/values.yaml +2 −0 Changes for src/openop_tfsdk/contract/adapters/charts/container/values.yaml: 2 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -3,3 +3,5 @@ image: "" # Each port: {name, port, protocol}. ports: [] serviceType: ClusterIP # Kubernetes container resources (requests/limits). Empty when no compute intent. resources: {}
src/openop_tfsdk/contract/adapters/kubernetes.py +17 −0 Changes for src/openop_tfsdk/contract/adapters/kubernetes.py: 17 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -99,10 +99,27 @@ def _chart_args(unit) -> list: raise ValidationError( "kubernetes container does not support mixed internal and external ports" ) compute = ( getattr(unit.resource_requirements, "compute", None) if unit.resource_requirements else None ) requests: dict[str, str] = {} if compute is not None: cpu_millicores = getattr(compute, "cpu_millicores", None) memory_mb = getattr(compute, "memory_mb", None) if cpu_millicores is not None and cpu_millicores < 0: raise ValidationError("container compute requests must be nonnegative") if memory_mb is not None and memory_mb < 0: raise ValidationError("container compute requests must be nonnegative") if cpu_millicores is not None and cpu_millicores > 0: requests["cpu"] = f"{cpu_millicores}m" if memory_mb is not None and memory_mb > 0: requests["memory"] = f"{memory_mb}M" resources = {"requests": requests} if requests else {} values = { "image": unit.artifact_ref, "ports": list(ports.values()), "serviceType": "NodePort" if external else "ClusterIP", "resources": resources, } return [CONTAINER_CHART] + [ arg for key, value in values.items() for arg in ("--set-json", f"{key}={json.dumps(value)}") Loading