Loading .gitlab-ci.yml +84 −2 Changes for .gitlab-ci.yml: 84 added lines, 2 removed lines. Original line number Diff line number Diff line workflow: rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - if: '$CI_PIPELINE_SOURCE == "push" && ($CI_COMMIT_BRANCH == "master" || $CI_COMMIT_BRANCH == "main")' - if: '$CI_PIPELINE_SOURCE == "push" && $CI_OPEN_MERGE_REQUESTS' when: never - when: always image: python:3.12-slim stages: Loading @@ -23,6 +31,10 @@ cache: - ansible-galaxy collection install -r ansible/requirements.yml secret-scan: rules: - if: '$RUN_SDK_ACCEPTANCE == "1"' when: never - when: on_success stage: lint image: alpine:latest before_script: Loading @@ -39,18 +51,30 @@ secret-scan: fi yamllint: rules: - if: '$RUN_SDK_ACCEPTANCE == "1"' when: never - when: on_success stage: lint extends: .ansible_setup script: - yamllint . ansible-lint: rules: - if: '$RUN_SDK_ACCEPTANCE == "1"' when: never - when: on_success stage: lint extends: .ansible_setup script: - ansible-lint -c .ansible-lint ansible/playbooks ansible/roles ansible/role-template - ansible-lint -c .ansible-lint ansible/playbooks ansible/roles ansible/role-template ansible/tests/test_platform_bootstrap.yml syntax-check: rules: - if: '$RUN_SDK_ACCEPTANCE == "1"' when: never - when: on_success stage: test extends: .ansible_setup script: Loading @@ -61,11 +85,69 @@ syntax-check: ansible-playbook -i inventory/r2.example.yml --syntax-check "$playbook" done - ANSIBLE_ROLES_PATH=roles ansible-playbook -i localhost, tests/test_platform_bootstrap.yml python-smoke: rules: - if: '$RUN_SDK_ACCEPTANCE == "1"' when: never - when: on_success stage: test script: - python3 -m py_compile ansible/roles/oop-platform/files/fm_partners.py ansible/tests/r2_e2e/*.py ci/*.py - python3 -m py_compile ansible/roles/oop-platform/files/fm_partners.py ansible/roles/oop-platform/files/tfsdk_bootstrap.py ansible/tests/r2_e2e/*.py ci/*.py - sh -n ci/run_platform_lab.sh - python3 -m unittest discover -s ansible/tests -p test_tfsdk_bootstrap.py # Pure gate/observation checks; no inventory, cluster access or deployment secrets. sdk-acceptance-checks: rules: - if: '$RUN_SDK_ACCEPTANCE == "1"' when: never - when: on_success stage: test variables: TMPDIR: "$CI_PROJECT_DIR/.cache/sdk-tmp" PYTHONDONTWRITEBYTECODE: "1" script: - mkdir -p "$TMPDIR" - pip install pytest==8.3.2 requests==2.33.0 - python -m pytest --confcutdir=ansible/tests/unit -q -p no:cacheprovider ansible/tests/unit/test_sdk_acceptance.py - python -m pytest --collect-only -q -p no:cacheprovider ansible/tests/r2_e2e # Explicit live mode leaves all default component tests and deployment jobs alone. sdk-live-acceptance: stage: test image: python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1 tags: [sdk-lab] interruptible: false timeout: 30 minutes resource_group: dedicated-sdk-lab environment: name: sdk-acceptance action: verify cache: [] variables: TMPDIR: "$CI_PROJECT_DIR/.cache/sdk-tmp" PYTHONDONTWRITEBYTECODE: "1" rules: - if: '$RUN_SDK_ACCEPTANCE == "1" && $CI_COMMIT_REF_PROTECTED == "true"' - when: never before_script: - mkdir -p "$TMPDIR" - pip install pytest==8.3.2 requests==2.33.0 - python ci/install_kubectl.py - export PATH="$CI_PROJECT_DIR/.cache/bin:$PATH" - kubectl version --client script: - python ci/sdk_live.py artifacts: when: always paths: - .cache/sdk-live/qualification.json - .cache/sdk-e2e/*/run.json reports: junit: .cache/sdk-live/junit.xml expire_in: 90 days platform-smoke-checks: stage: test Loading README.md +53 −0 Changes for README.md: 53 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -39,3 +39,56 @@ Sergio Giménez <sergio.gimenez@i2cat.net> ## License Apache 2.0. See `LICENSE` and `NOTICE` for attribution requirements. ## Single SRM / TF-SDK bootstrap The existing `oop-platform` role accepts `oop_platform_bootstrap` as one operator declaration. It emits the complete bootstrap and matching read-only credential mounts through the Release 2 chart: ```yaml oop_platform_bootstrap: version: openop.srm.bootstrap/v1 control_paths: - ref: athens adapter_type: kubernetes kubeconfig_secret: name: athens-credentials key: config infrastructure: kube_context: athens namespace: applications - ref: local-workloads adapter_type: kubernetes infrastructure: in_cluster: true namespace: applications zones: [] # Add the real declared topology and bindings. ``` For in-cluster workloads, configure the existing `workloads.namespaces` RBAC setting explicitly. Declaring a control path does not grant permissions. Create the referenced Secrets in the SRM namespace through the existing operator credential process. The role never reads their values or implements a secret resolver. It derives file paths from refs, keeping each control path separate, and strips deployment-only Secret metadata from emitted bootstrap. The SDK identity is derived by SRM from each ref, not repeated in infrastructure. The deployment controller's kubeconfig remains separate from SDK credentials. Remove `controlPaths` from extra chart values. When using `oop_platform_bootstrap`, also remove manually supplied `topology` and `controlPathCredentials`; competing sources fail before deployment. Existing empty defaults preserve health-only deployments. The paired chart provides `/var/run/openop-tfsdk` for private execution files. Use matching SDK 2.0.0rc3, SRM and chart revisions; upgrade or roll back the set together. Bootstrap generation is not a backend-health or credential-validity check. Offline producer tests run in the existing Python CI job. The real-role check also runs locally and in the existing syntax-check job, without cluster access: ```sh python -m unittest discover -s ansible/tests -p test_tfsdk_bootstrap.py ANSIBLE_ROLES_PATH=ansible/roles ansible-playbook -i localhost, ansible/tests/test_platform_bootstrap.yml ``` ansible/inventory/r2-sdk-lab.example.yml 0 → 100644 +63 −0 Changes for ansible/inventory/r2-sdk-lab.example.yml: 63 added lines, 0 removed lines. Original line number Diff line number Diff line --- # Separate, single-operator lab. Copy to r2-sdk-lab.local.yml and fill the pins. # No production inventory, federation, shared workload namespace or floating SDK install. all: children: oop_platform_operators: hosts: sdk_lab: ansible_connection: local ansible_python_interpreter: "{{ ansible_playbook_python }}" oop_platform_kubeconfig: ~/.kube/oop-sdk-lab.yaml oop_platform_kube_context: oop-sdk-lab oop_platform_namespace: oop-e2e-platform oop_platform_public_host: sdk-lab.example.test oop_platform_federation_id: sdk-lab oop_platform_country_code: GR oop_platform_mcc: "202" oop_platform_mncs: ["01"] oop_platform_federation_clients: [] oop_platform_portal_enabled: false oop_platform_chart_version: 04a5b7b2fd50ea2b2a321966ca6437a369cdadbf oop_platform_fm_image_tag: REPLACE_WITH_REVIEWED_FM_TAG oop_platform_oeg_image_tag: REPLACE_WITH_REVIEWED_OEG_TAG oop_platform_srm_image_tag: REPLACE_WITH_REVIEWED_SRM_TAG e2e_temp_dir: "{{ playbook_dir }}/../../../.cache/sdk-e2e-tmp" oop_platform_bootstrap: version: openop.srm.bootstrap/v1 platform_instance_id: sdk-lab control_paths: - ref: sdk-lab-k8s adapter_family: compute adapter_type: kubernetes adapter_contract_version: v1 infrastructure: namespace: oop-e2e-workloads in_cluster: true endpoint_host: sdk-lab.example.test zones: - ref: sdk-lab-zone name: SDK lab kind: resource state: active domains: - ref: sdk-lab-compute name: SDK lab compute kind: compute state: active capabilities: - ref: sdk-lab-workload name: SDK lab workload kind: workload state: active control_path_bindings: - ref: sdk-lab-workload-binding control_path_ref: sdk-lab-k8s is_default: true state: active oop_platform_extra_values: srm: srmcontroller: workloads: namespaces: - oop-e2e-workloads ansible/inventory/r2.example.yml +7 −11 Changes for ansible/inventory/r2.example.yml: 7 added lines, 11 removed lines. Original line number Diff line number Diff line Loading @@ -71,29 +71,25 @@ all: srmcontroller: workloads: namespaces: [oop-apps] controlPaths: - control_path_ref: k8s-local adapter: kubernetes config: namespace: oop-apps topology: | oop_platform_bootstrap: version: openop.srm.bootstrap/v1 platform_instance_id: {{ oop_platform_federation_id }} platform_instance_id: "{{ oop_platform_federation_id }}" control_paths: - ref: k8s-local adapter_family: compute adapter_type: kubernetes adapter_contract_version: v1 infrastructure: in_cluster: true namespace: oop-apps zones: - ref: {{ oop_platform_federation_id }}-zone name: {{ srm_zone_name }} - ref: "{{ oop_platform_federation_id }}-zone" name: "{{ srm_zone_name }}" kind: resource state: active domains: - ref: {{ oop_platform_federation_id }}-compute name: {{ srm_zone_name }} compute - ref: "{{ oop_platform_federation_id }}-compute" name: "{{ srm_zone_name }} compute" kind: compute state: active capabilities: Loading ansible/playbooks/scenarios/r2_existing_cluster/README.md +21 −32 Changes for ansible/playbooks/scenarios/r2_existing_cluster/README.md: 21 added lines, 32 removed lines. Original line number Diff line number Diff line Loading @@ -210,44 +210,37 @@ declaration Today the only implementation reads a file; a live source could replace it later without changing SRM. The chart's `srm.srmcontroller.topology` and `controlPaths` are empty by default. Helm's kind environment fills them in for you; on any other cluster the role leaves them empty. SRM then logs `bootstrap_topology_not_configured` and has no zones, so OEG lists nothing to deploy to, and any agreement in `federate.yml` fails with `no zone named ... in SRM`. The chart's bootstrap is empty by default. The role accepts one `oop_platform_bootstrap` declaration and generates the complete topology file and any credential mount metadata. With empty defaults, SRM logs `bootstrap_topology_not_configured` and exposes no zones. Give each operator its zone through `oop_platform_extra_values`. The example below declares one zone whose apps SRM deploys with Helm into namespace `oop-apps` of the operator's own cluster; the test environment runs this setup: For a local workload path, declare the connection explicitly and keep the existing namespace/RBAC setting: ```yaml oop_platform_extra_values: srm: srmcontroller: workloads: namespaces: [oop-apps] # created, with a Role for SRM's ServiceAccount controlPaths: - control_path_ref: k8s-local adapter: kubernetes config: namespace: oop-apps topology: | namespaces: [oop-apps] oop_platform_bootstrap: version: openop.srm.bootstrap/v1 platform_instance_id: {{ oop_platform_federation_id }} platform_instance_id: "{{ oop_platform_federation_id }}" control_paths: - ref: k8s-local adapter_family: compute adapter_type: kubernetes adapter_contract_version: v1 infrastructure: in_cluster: true namespace: oop-apps zones: - ref: {{ oop_platform_federation_id }}-zone name: {{ srm_zone_name }} - ref: "{{ oop_platform_federation_id }}-zone" name: "{{ srm_zone_name }}" kind: resource state: active domains: - ref: {{ oop_platform_federation_id }}-compute name: {{ srm_zone_name }} compute - ref: "{{ oop_platform_federation_id }}-compute" name: "{{ srm_zone_name }} compute" kind: compute state: active capabilities: Loading @@ -259,17 +252,13 @@ oop_platform_extra_values: - {ref: deploy-workload-via-k8s-local, control_path_ref: k8s-local, is_default: true, state: active} ``` `srm_zone_name` is a host variable (`Barcelona`, `Paris`, ...): the name users see, and the name agreements refer to. The zone declares one capability, `workload`, because that's all TF-SDK's `kubernetes` adapter serves: it installs, updates, removes and reads Helm releases and containers. It can't report free resources, so a `query_available_resources` capability bound to it gets no actions, and placement never uses it; SRM keeps no capacity of its own either ([ADR-0002](https://labs.etsi.org/rep/oop/architecture/-/blob/develop/decisions/0002-no-stored-capacity.md)). The adapter only reads `namespace` from its config and runs `helm` as SRM's own ServiceAccount, so it deploys into the cluster SRM runs in, in the namespaces listed under `workloads.namespaces`. `srm_zone_name` is the host variable used in public zone names and agreements. The Kubernetes adapter serves workload lifecycle operations; it does not report free capacity. SRM retains topology/placement responsibility. For remote clusters, see the repository README's `kubeconfig_secret` declaration. Remove legacy `controlPaths` and manually duplicated topology/mount values when using the generated declaration. Configure workload RBAC separately; declaring a control path does not grant permissions. ## Step 2: federate the operators Loading Loading
.gitlab-ci.yml +84 −2 Changes for .gitlab-ci.yml: 84 added lines, 2 removed lines. Original line number Diff line number Diff line workflow: rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - if: '$CI_PIPELINE_SOURCE == "push" && ($CI_COMMIT_BRANCH == "master" || $CI_COMMIT_BRANCH == "main")' - if: '$CI_PIPELINE_SOURCE == "push" && $CI_OPEN_MERGE_REQUESTS' when: never - when: always image: python:3.12-slim stages: Loading @@ -23,6 +31,10 @@ cache: - ansible-galaxy collection install -r ansible/requirements.yml secret-scan: rules: - if: '$RUN_SDK_ACCEPTANCE == "1"' when: never - when: on_success stage: lint image: alpine:latest before_script: Loading @@ -39,18 +51,30 @@ secret-scan: fi yamllint: rules: - if: '$RUN_SDK_ACCEPTANCE == "1"' when: never - when: on_success stage: lint extends: .ansible_setup script: - yamllint . ansible-lint: rules: - if: '$RUN_SDK_ACCEPTANCE == "1"' when: never - when: on_success stage: lint extends: .ansible_setup script: - ansible-lint -c .ansible-lint ansible/playbooks ansible/roles ansible/role-template - ansible-lint -c .ansible-lint ansible/playbooks ansible/roles ansible/role-template ansible/tests/test_platform_bootstrap.yml syntax-check: rules: - if: '$RUN_SDK_ACCEPTANCE == "1"' when: never - when: on_success stage: test extends: .ansible_setup script: Loading @@ -61,11 +85,69 @@ syntax-check: ansible-playbook -i inventory/r2.example.yml --syntax-check "$playbook" done - ANSIBLE_ROLES_PATH=roles ansible-playbook -i localhost, tests/test_platform_bootstrap.yml python-smoke: rules: - if: '$RUN_SDK_ACCEPTANCE == "1"' when: never - when: on_success stage: test script: - python3 -m py_compile ansible/roles/oop-platform/files/fm_partners.py ansible/tests/r2_e2e/*.py ci/*.py - python3 -m py_compile ansible/roles/oop-platform/files/fm_partners.py ansible/roles/oop-platform/files/tfsdk_bootstrap.py ansible/tests/r2_e2e/*.py ci/*.py - sh -n ci/run_platform_lab.sh - python3 -m unittest discover -s ansible/tests -p test_tfsdk_bootstrap.py # Pure gate/observation checks; no inventory, cluster access or deployment secrets. sdk-acceptance-checks: rules: - if: '$RUN_SDK_ACCEPTANCE == "1"' when: never - when: on_success stage: test variables: TMPDIR: "$CI_PROJECT_DIR/.cache/sdk-tmp" PYTHONDONTWRITEBYTECODE: "1" script: - mkdir -p "$TMPDIR" - pip install pytest==8.3.2 requests==2.33.0 - python -m pytest --confcutdir=ansible/tests/unit -q -p no:cacheprovider ansible/tests/unit/test_sdk_acceptance.py - python -m pytest --collect-only -q -p no:cacheprovider ansible/tests/r2_e2e # Explicit live mode leaves all default component tests and deployment jobs alone. sdk-live-acceptance: stage: test image: python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1 tags: [sdk-lab] interruptible: false timeout: 30 minutes resource_group: dedicated-sdk-lab environment: name: sdk-acceptance action: verify cache: [] variables: TMPDIR: "$CI_PROJECT_DIR/.cache/sdk-tmp" PYTHONDONTWRITEBYTECODE: "1" rules: - if: '$RUN_SDK_ACCEPTANCE == "1" && $CI_COMMIT_REF_PROTECTED == "true"' - when: never before_script: - mkdir -p "$TMPDIR" - pip install pytest==8.3.2 requests==2.33.0 - python ci/install_kubectl.py - export PATH="$CI_PROJECT_DIR/.cache/bin:$PATH" - kubectl version --client script: - python ci/sdk_live.py artifacts: when: always paths: - .cache/sdk-live/qualification.json - .cache/sdk-e2e/*/run.json reports: junit: .cache/sdk-live/junit.xml expire_in: 90 days platform-smoke-checks: stage: test Loading
README.md +53 −0 Changes for README.md: 53 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -39,3 +39,56 @@ Sergio Giménez <sergio.gimenez@i2cat.net> ## License Apache 2.0. See `LICENSE` and `NOTICE` for attribution requirements. ## Single SRM / TF-SDK bootstrap The existing `oop-platform` role accepts `oop_platform_bootstrap` as one operator declaration. It emits the complete bootstrap and matching read-only credential mounts through the Release 2 chart: ```yaml oop_platform_bootstrap: version: openop.srm.bootstrap/v1 control_paths: - ref: athens adapter_type: kubernetes kubeconfig_secret: name: athens-credentials key: config infrastructure: kube_context: athens namespace: applications - ref: local-workloads adapter_type: kubernetes infrastructure: in_cluster: true namespace: applications zones: [] # Add the real declared topology and bindings. ``` For in-cluster workloads, configure the existing `workloads.namespaces` RBAC setting explicitly. Declaring a control path does not grant permissions. Create the referenced Secrets in the SRM namespace through the existing operator credential process. The role never reads their values or implements a secret resolver. It derives file paths from refs, keeping each control path separate, and strips deployment-only Secret metadata from emitted bootstrap. The SDK identity is derived by SRM from each ref, not repeated in infrastructure. The deployment controller's kubeconfig remains separate from SDK credentials. Remove `controlPaths` from extra chart values. When using `oop_platform_bootstrap`, also remove manually supplied `topology` and `controlPathCredentials`; competing sources fail before deployment. Existing empty defaults preserve health-only deployments. The paired chart provides `/var/run/openop-tfsdk` for private execution files. Use matching SDK 2.0.0rc3, SRM and chart revisions; upgrade or roll back the set together. Bootstrap generation is not a backend-health or credential-validity check. Offline producer tests run in the existing Python CI job. The real-role check also runs locally and in the existing syntax-check job, without cluster access: ```sh python -m unittest discover -s ansible/tests -p test_tfsdk_bootstrap.py ANSIBLE_ROLES_PATH=ansible/roles ansible-playbook -i localhost, ansible/tests/test_platform_bootstrap.yml ```
ansible/inventory/r2-sdk-lab.example.yml 0 → 100644 +63 −0 Changes for ansible/inventory/r2-sdk-lab.example.yml: 63 added lines, 0 removed lines. Original line number Diff line number Diff line --- # Separate, single-operator lab. Copy to r2-sdk-lab.local.yml and fill the pins. # No production inventory, federation, shared workload namespace or floating SDK install. all: children: oop_platform_operators: hosts: sdk_lab: ansible_connection: local ansible_python_interpreter: "{{ ansible_playbook_python }}" oop_platform_kubeconfig: ~/.kube/oop-sdk-lab.yaml oop_platform_kube_context: oop-sdk-lab oop_platform_namespace: oop-e2e-platform oop_platform_public_host: sdk-lab.example.test oop_platform_federation_id: sdk-lab oop_platform_country_code: GR oop_platform_mcc: "202" oop_platform_mncs: ["01"] oop_platform_federation_clients: [] oop_platform_portal_enabled: false oop_platform_chart_version: 04a5b7b2fd50ea2b2a321966ca6437a369cdadbf oop_platform_fm_image_tag: REPLACE_WITH_REVIEWED_FM_TAG oop_platform_oeg_image_tag: REPLACE_WITH_REVIEWED_OEG_TAG oop_platform_srm_image_tag: REPLACE_WITH_REVIEWED_SRM_TAG e2e_temp_dir: "{{ playbook_dir }}/../../../.cache/sdk-e2e-tmp" oop_platform_bootstrap: version: openop.srm.bootstrap/v1 platform_instance_id: sdk-lab control_paths: - ref: sdk-lab-k8s adapter_family: compute adapter_type: kubernetes adapter_contract_version: v1 infrastructure: namespace: oop-e2e-workloads in_cluster: true endpoint_host: sdk-lab.example.test zones: - ref: sdk-lab-zone name: SDK lab kind: resource state: active domains: - ref: sdk-lab-compute name: SDK lab compute kind: compute state: active capabilities: - ref: sdk-lab-workload name: SDK lab workload kind: workload state: active control_path_bindings: - ref: sdk-lab-workload-binding control_path_ref: sdk-lab-k8s is_default: true state: active oop_platform_extra_values: srm: srmcontroller: workloads: namespaces: - oop-e2e-workloads
ansible/inventory/r2.example.yml +7 −11 Changes for ansible/inventory/r2.example.yml: 7 added lines, 11 removed lines. Original line number Diff line number Diff line Loading @@ -71,29 +71,25 @@ all: srmcontroller: workloads: namespaces: [oop-apps] controlPaths: - control_path_ref: k8s-local adapter: kubernetes config: namespace: oop-apps topology: | oop_platform_bootstrap: version: openop.srm.bootstrap/v1 platform_instance_id: {{ oop_platform_federation_id }} platform_instance_id: "{{ oop_platform_federation_id }}" control_paths: - ref: k8s-local adapter_family: compute adapter_type: kubernetes adapter_contract_version: v1 infrastructure: in_cluster: true namespace: oop-apps zones: - ref: {{ oop_platform_federation_id }}-zone name: {{ srm_zone_name }} - ref: "{{ oop_platform_federation_id }}-zone" name: "{{ srm_zone_name }}" kind: resource state: active domains: - ref: {{ oop_platform_federation_id }}-compute name: {{ srm_zone_name }} compute - ref: "{{ oop_platform_federation_id }}-compute" name: "{{ srm_zone_name }} compute" kind: compute state: active capabilities: Loading
ansible/playbooks/scenarios/r2_existing_cluster/README.md +21 −32 Changes for ansible/playbooks/scenarios/r2_existing_cluster/README.md: 21 added lines, 32 removed lines. Original line number Diff line number Diff line Loading @@ -210,44 +210,37 @@ declaration Today the only implementation reads a file; a live source could replace it later without changing SRM. The chart's `srm.srmcontroller.topology` and `controlPaths` are empty by default. Helm's kind environment fills them in for you; on any other cluster the role leaves them empty. SRM then logs `bootstrap_topology_not_configured` and has no zones, so OEG lists nothing to deploy to, and any agreement in `federate.yml` fails with `no zone named ... in SRM`. The chart's bootstrap is empty by default. The role accepts one `oop_platform_bootstrap` declaration and generates the complete topology file and any credential mount metadata. With empty defaults, SRM logs `bootstrap_topology_not_configured` and exposes no zones. Give each operator its zone through `oop_platform_extra_values`. The example below declares one zone whose apps SRM deploys with Helm into namespace `oop-apps` of the operator's own cluster; the test environment runs this setup: For a local workload path, declare the connection explicitly and keep the existing namespace/RBAC setting: ```yaml oop_platform_extra_values: srm: srmcontroller: workloads: namespaces: [oop-apps] # created, with a Role for SRM's ServiceAccount controlPaths: - control_path_ref: k8s-local adapter: kubernetes config: namespace: oop-apps topology: | namespaces: [oop-apps] oop_platform_bootstrap: version: openop.srm.bootstrap/v1 platform_instance_id: {{ oop_platform_federation_id }} platform_instance_id: "{{ oop_platform_federation_id }}" control_paths: - ref: k8s-local adapter_family: compute adapter_type: kubernetes adapter_contract_version: v1 infrastructure: in_cluster: true namespace: oop-apps zones: - ref: {{ oop_platform_federation_id }}-zone name: {{ srm_zone_name }} - ref: "{{ oop_platform_federation_id }}-zone" name: "{{ srm_zone_name }}" kind: resource state: active domains: - ref: {{ oop_platform_federation_id }}-compute name: {{ srm_zone_name }} compute - ref: "{{ oop_platform_federation_id }}-compute" name: "{{ srm_zone_name }} compute" kind: compute state: active capabilities: Loading @@ -259,17 +252,13 @@ oop_platform_extra_values: - {ref: deploy-workload-via-k8s-local, control_path_ref: k8s-local, is_default: true, state: active} ``` `srm_zone_name` is a host variable (`Barcelona`, `Paris`, ...): the name users see, and the name agreements refer to. The zone declares one capability, `workload`, because that's all TF-SDK's `kubernetes` adapter serves: it installs, updates, removes and reads Helm releases and containers. It can't report free resources, so a `query_available_resources` capability bound to it gets no actions, and placement never uses it; SRM keeps no capacity of its own either ([ADR-0002](https://labs.etsi.org/rep/oop/architecture/-/blob/develop/decisions/0002-no-stored-capacity.md)). The adapter only reads `namespace` from its config and runs `helm` as SRM's own ServiceAccount, so it deploys into the cluster SRM runs in, in the namespaces listed under `workloads.namespaces`. `srm_zone_name` is the host variable used in public zone names and agreements. The Kubernetes adapter serves workload lifecycle operations; it does not report free capacity. SRM retains topology/placement responsibility. For remote clusters, see the repository README's `kubeconfig_secret` declaration. Remove legacy `controlPaths` and manually duplicated topology/mount values when using the generated declaration. Configure workload RBAC separately; declaring a control path does not grant permissions. ## Step 2: federate the operators Loading