Commit 28ca053b authored by Konstantinos Togias's avatar Konstantinos Togias
Browse files

Merge published SDK acceptance and platform lab prerequisites

parents 9a2075c8 6835ae8a
Loading
Loading
Loading
Loading
+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:
@@ -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:
@@ -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:
@@ -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
+53 −0
Changes for README.md: 53 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -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
```
+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
+7 −11
Changes for ansible/inventory/r2.example.yml: 7 added lines, 11 removed lines.
Original line number Diff line number Diff line
@@ -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:
+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
@@ -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:
@@ -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