Commit f18bb13c authored by Dimitrios Gogos's avatar Dimitrios Gogos
Browse files

Merge branch 'develop' into 'main'

Release 2.0.0: deployment automation and E2E validation

See merge request !12
parents f5901b6a fa68f343
Loading
Loading
Loading
Loading
Loading
+214 −2
Changes for .gitlab-ci.yml: 214 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:
  - lint
  - test
  - report

variables:
  ANSIBLE_CONFIG: ansible/ansible.cfg
@@ -23,6 +32,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 +52,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,7 +86,194 @@ 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/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

platform-smoke-checks:
  stage: test
  image: python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1
  cache: []
  variables:
    TMPDIR: "$CI_PROJECT_DIR/.cache/smoke-tests"
    PYTHONDONTWRITEBYTECODE: "1"
  script:
    - mkdir -p "$TMPDIR"
    - pip install -r ci/requirements-smoke.txt
    - python -m pytest --confcutdir=ansible/tests/unit -q -p no:cacheprovider ansible/tests/unit --basetemp="$TMPDIR/pytest"
    - python -m pytest --collect-only -q -p no:cacheprovider ansible/tests/r2_e2e

# Read-only opt-in check of an already deployed platform, through its public URLs.
platform-smoke:
  stage: test
  image: python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1
  cache: []
  timeout: 10 minutes
  variables:
    TMPDIR: "$CI_PROJECT_DIR/.cache/smoke-install"
    PYTHONDONTWRITEBYTECODE: "1"
  rules:
    - if: '$RUN_PLATFORM_SMOKE == "1" && $CI_COMMIT_REF_PROTECTED == "true"'
    - when: never
  script:
    - mkdir -p "$TMPDIR"
    - pip install -r ci/requirements-smoke.txt
    - python ci/platform_smoke.py --inventory "$OOP_SMOKE_INVENTORY"
  artifacts:
    when: always
    paths:
      - .cache/platform-smoke/result.json
    reports:
      junit: .cache/platform-smoke/junit.xml
    expire_in: 1 week

# Disposable core platform: create -> existing deploy -> existing health -> delete.
# Requires a trusted DinD-capable runner with shared TLS client certificates.
platform-lab:
  stage: test
  image: docker:29.5.1-cli@sha256:b40b3737eb3bf588d25bb856d3564dd3f9fdb32ac2fc19ebe85cc58d761692a5
  services:
    - name: docker:29.5.1-dind@sha256:eed377f3ce14afda560e742c5b3ae446df1ce00a16e1beab2ac6c78c1477fe85
      alias: docker
      variables:
        HEALTHCHECK_TCP_PORT: "2376"
  cache: []
  timeout: 40 minutes
  variables:
    OOP_LAB_REPORT_DIR: .cache/platform-lab/container
    FF_NETWORK_PER_BUILD: "true"
    DOCKER_HOST: tcp://docker:2376
    DOCKER_TLS_CERTDIR: /certs
    DOCKER_TLS_VERIFY: "1"
    DOCKER_CERT_PATH: /certs/client
  rules:
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH == "test/platform-application-checkpoints" || $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == "test/platform-application-checkpoints"'
      when: on_success
      allow_failure: false
      variables:
        OOP_LAB_PROFILE: ci/lab/profile.release-2.0.json
        OOP_LAB_REFRESH_CANDIDATE: "1"
    - if: '$CI_COMMIT_BRANCH == "test/platform-lab"'
      when: manual
      allow_failure: false
    - if: '$RUN_PLATFORM_LAB == "1" && $CI_COMMIT_REF_PROTECTED == "true"'
    - when: never
  before_script:
    - apk add --no-cache python3
  script:
    - sh ci/run_platform_lab.sh "${OOP_LAB_PROFILE:-ci/lab/profile.health.json}" "$OOP_LAB_REPORT_DIR"
  artifacts:
    when: always
    paths:
      - $OOP_LAB_REPORT_DIR/result.json
      - $OOP_LAB_REPORT_DIR/junit.xml
      - $OOP_LAB_REPORT_DIR/chart.json
      - $OOP_LAB_REPORT_DIR/candidate.json
      - $OOP_LAB_REPORT_DIR/feature-matrix.json
      - $OOP_LAB_REPORT_DIR/feature-matrix.md
      - $OOP_LAB_REPORT_DIR/wrapper-junit.xml
      - $OOP_LAB_REPORT_DIR/pods.txt
      - $OOP_LAB_REPORT_DIR/events.txt
      - $OOP_LAB_REPORT_DIR/health/result.json
      - $OOP_LAB_REPORT_DIR/health/junit.xml
      - $OOP_LAB_REPORT_DIR/health/acceptance/
    reports:
      junit:
        - $OOP_LAB_REPORT_DIR/junit.xml
        - $OOP_LAB_REPORT_DIR/wrapper-junit.xml
    expire_in: 90 days

# Same lab and lifecycle, using a chart archive instead of a container manifest.
platform-lab-helm:
  extends: platform-lab
  variables:
    OOP_LAB_PACKAGE_TYPE: HELM
    OOP_LAB_REPORT_DIR: .cache/platform-lab/helm
  rules:
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH == "test/platform-application-checkpoints" || $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == "test/platform-application-checkpoints"'
      variables:
        OOP_LAB_PROFILE: ci/lab/profile.release-2.0.json
        OOP_LAB_REFRESH_CANDIDATE: "1"
    - if: '$RUN_PLATFORM_HELM_LAB == "1" && $CI_COMMIT_REF_PROTECTED == "true"'
    - when: never

# Actual provider compatibility, extending the same container application lab.
platform-lab-network:
  extends: platform-lab
  variables:
    OOP_LAB_NETWORK_PROVIDER: EURECOM
    OOP_LAB_REPORT_DIR: .cache/platform-lab/network
  rules:
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH == "test/platform-application-checkpoints" || $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == "test/platform-application-checkpoints"'
      variables:
        OOP_LAB_PROFILE: ci/lab/profile.release-2.0.json
        OOP_LAB_REFRESH_CANDIDATE: "1"
    - if: '$RUN_PLATFORM_NETWORK_LAB == "1" && $CI_COMMIT_REF_PROTECTED == "true"'
    - when: never

# Consolidation consumes real job artifacts; it adds no approval or input form.
release-feature-report:
  stage: report
  image: python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1
  cache: []
  when: always
  needs:
    - {job: platform-lab, artifacts: true, optional: true}
    - {job: platform-lab-helm, artifacts: true, optional: true}
    - {job: platform-lab-network, artifacts: true, optional: true}
  rules:
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH == "test/platform-application-checkpoints" || $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == "test/platform-application-checkpoints"'
    - when: never
  script:
    - python ci/merge_feature_reports.py .cache/platform-lab .cache/release-features
  artifacts:
    when: always
    expose_as: Observed release features
    paths:
      - .cache/release-features/feature-matrix.md
      - .cache/release-features/feature-matrix.json
    expire_in: 90 days

# 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:
    - python3 -m py_compile ansible/roles/oop-platform/files/fm_partners.py ansible/tests/r2_e2e/*.py
    - 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
+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
```
+62 −0
Changes for ansible/inventory/r2-sdk-lab.example.yml: 62 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: 52a7b0d942af88d004a0781e365b0a6db7c66e2c
          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:
              workloads:
                namespaces:
                  - oop-e2e-workloads
+13 −0
Changes for ansible/inventory/r2-smoke.example.yml: 13 added lines, 0 removed lines.
Original line number Diff line number Diff line
---
# HTTP-only view of an already deployed platform. Copy to r2-smoke.local.yml.
# Public URLs must be reachable from the machine/container running the command.
# No SSH credentials, kubeconfig or application image is needed for this scenario.
all:
  children:
    oop_platform_operators:
      hosts:
        local_lab:
          oop_platform_public_host: 127.0.0.1
          oop_platform_scheme: http
          oop_platform_oeg_node_port: 32263
          oop_platform_fm_node_port: 30989
+9 −14
Changes for ansible/inventory/r2.example.yml: 9 added lines, 14 removed lines.
Original line number Diff line number Diff line
@@ -42,8 +42,8 @@ all:
        # No Release 2 portal image is published yet: build one, or turn the portal off.
        oop_platform_portal_enabled: false
        # The Release 2 charts are on this branch until oop/deploy/helm!15 merges;
        # helm develop still has the Release 1 (MongoDB) charts.
        oop_platform_chart_version: refactor/helm-2.0
        # Pin the reviewed Release 2 chart, including single-bootstrap mounts.
        oop_platform_chart_version: 52a7b0d942af88d004a0781e365b0a6db7c66e2c
        # Plain HTTP between the operators: test networks only.
        oop_platform_allow_insecure_partner_endpoints: true

@@ -68,32 +68,27 @@ all:
        # deployed by Helm into namespace oop-apps of the operator's own cluster.
        oop_platform_extra_values:
          srm:
            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