Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/superlinter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ jobs:
VALIDATE_JSON_PRETTIER: false
VALIDATE_MARKDOWN_PRETTIER: false
VALIDATE_PYTHON_PYLINT: false
# ruff (I001) already enforces import sorting with a 120-char line
# length; isort's 88-char limit cannot fit the noqa'd star imports
# needed for the pytest conftest fixtures.
VALIDATE_PYTHON_ISORT: false
VALIDATE_SHELL_SHFMT: false
VALIDATE_YAML: false
VALIDATE_KUBERNETES_KUBECONFORM: false
Expand Down
2 changes: 2 additions & 0 deletions .trivyignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ AVD-KSV-0020 # Container 'apache' of Deployment 'hello-world' should set 'securi
AVD-KSV-0021 # Container 'apache' of Deployment 'hello-world' should set 'securityContext.runAsGroup' > 10000. Not needed on OCP
AVD-KSV-0014 # Readonly root filesystem does not work with httpd ubi images
AVD-KSV-0125 # Container apache in deployment hello-world (namespace: default) uses an image from an untrusted registry. registry.access.redhat.com is trusted
AVD-KSV-0113 # The k-orc credentials Role must read RHOSO config secrets and manage the ORC cloud-config secret in the openstack namespace; the service account is dedicated to the credentials Job
AVD-KSV-0013 # The pattern utility container is only published as :latest; the credentials Job is short-lived and CI-only


8 changes: 8 additions & 0 deletions tests/ci/conftest.py
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
import sys
from pathlib import Path

from validatedpatterns_tests.interop.conftest_openshift import *

# The k-orc feature tree uses a hyphenated directory name (matching the
# upstream project name), which is not importable as a Python package.
# Make its test module importable from tests/ci/test_standalone.py.
sys.path.insert(0, str(Path(__file__).parent / "k-orc"))
152 changes: 152 additions & 0 deletions tests/ci/k-orc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# k-orc: OpenStack Resource Controller integration

This directory deploys [ORC][orc] (OpenStack Resource Controller) on the
cluster and manages a small steady-state smoke stack in OpenStack through it:

- a **Flavor** (`m1.xsmall`: 1024 MiB RAM, 2 vCPUs, 15 GiB disk),
- a CirrOS **Image** (downloaded by ORC from download.cirros-cloud.net,
pinned by sha256),
- a **Network**, **Subnet**, and **Port**,
- a **Server** (VM) booting the managed image with the managed flavor on the
managed port.

The goal is twofold: exercise ORC end-to-end against a real RHOSO cloud, and
give the pattern CI meaningful assertions (see `test_k_orc.py`).

This is a CI-only feature: nothing outside `tests/ci/` is modified, and the
standard pattern chart does not deploy it.

[orc]: https://github.com/k-orc/openstack-resource-controller

## Layout

```text
k-orc/
applications/ # Argo CD Applications, applied by the CI tests
k-orc-crds.yaml # static: orc-crds chart (CRDs), wave -2
k-orc-operator.yaml # static: orc chart (controller), wave -1
k-orc-resources.yaml # template: git source filled in by the tests
resources/ # Source path of k-orc-resources (flat directory)
00-credentials-rbac.yaml # SA/Role/RoleBinding for the credentials Job
01-credentials-job.yaml # assembles the ORC credential Secret
10-flavor.yaml ... 15-server.yaml # ORC custom resources (wave 0)
test_k_orc.py # CI assertions (applies the Applications, then polls)
```

## How it is deployed

The CI tests (not the pattern chart) create the Argo CD Applications, in the
namespace of the Argo CD instance managing the pattern:

1. `test_k_orc.py` reads every manifest in `applications/` and applies it
(create or idempotent patch). Static manifests (`k-orc-crds`,
`k-orc-operator`: OCI Helm chart sources) are applied as-is. The
generated one (`k-orc-resources`) gets its Git source filled in:
`VP_KORC_REPOURL` / `VP_KORC_TARGET_REVISION` environment variables,
then the local Git checkout (origin remote and current branch), then the
deployed parent Application's source.
2. `k-orc-crds` and `k-orc-operator` sync the official ORC Helm charts from
quay.io into `orc-system` (CRDs first, then the controller).
3. `k-orc-resources` syncs `resources/` into the `openstack` namespace.
Until the ORC CRDs are established, Argo CD rejects its sync plan
("one or more synchronization tasks are not valid"); the Application's
sync retries (limit 20, exponential backoff) make it converge once the
CRDs are in place. Within that Application, sync waves order the
credentials RBAC (-2), the credentials Job (-1) and the ORC custom
resources (0).

The Applications and everything they deploy are steady-state: they are left
running after the CI run, and re-applying is idempotent. To remove the whole
feature, delete the three Applications (their finalizer cascade removes the
CRDs, the controller, the ORC resources and, through ORC, the OpenStack
resources themselves).

Applications carrying the `validatedpatterns.io/ci-feature: k-orc` label are
excluded from the pattern inventory assertions in `test_standalone.py`,
since they are created by the CI rather than by the pattern chart.

## Version pinning

Both Helm charts (`orc-crds` and `orc`) are pinned to the same version in
`applications/`. Bump both together. `3.0.0-pre1` was the only published
chart tag at the time this was written; prefer a stable release once one is
available.

## OpenStack credentials

ORC resources reference `spec.cloudCredentialsRef` pointing at the
`orc-cloud-config` Secret in the `openstack` namespace. That Secret is
assembled by the `k-orc-credentials` Job from RHOSO's own configuration:

- `openstack-config` ConfigMap: `clouds.yaml` (cloud `default`, without the
password),
- `openstack-config-secret` Secret: `cloudrc` (carries `OS_PASSWORD`),
- `combined-ca-bundle` Secret: the TLS CA bundle (exposed to ORC as the
optional `cacert` key).

The password is only ever handled in memory inside the Job; it is never
printed, logged, or committed. If the RHOSO admin password is rotated,
delete the completed `k-orc-credentials` Job object: the next Argo sync
re-runs it and refreshes the Secret. The same applies after editing the Job
manifest itself (Jobs are immutable).

The credential account is the RHOSO admin (`clouds.yaml` entry `default`).
Creating flavors requires elevated OpenStack permissions; if the deployment
uses a restricted account, the `k-orc-flavor` object will report a terminal
`InvalidConfiguration`/`UnrecoverableError` condition.

## Configuration knobs

- **Subnet CIDR**: `192.168.150.0/24` by default, in
`resources/13-subnet.yaml`. Change it there if it overlaps existing
networks. `cidr` is immutable on the Subnet object: after changing it,
delete the `k-orc-subnet`, `k-orc-port` and `k-orc-server` objects and let
Argo re-create them.
- **Image**: pinned to CirrOS 0.6.3 (URL + sha256) in
`resources/11-image.yaml`. Bump both together using the published
`SHA256SUMS`.
- **Flavor**: `m1.xsmall`, 1024 MiB / 2 vCPUs / 15 GiB in
`resources/10-flavor.yaml`.

## Pruning

Pruning is intentionally disabled (`Prune=false`) on all three Applications:
GitOps changes to the manifests do not delete OpenStack resources, and
neither CRDs nor the controller are removed on manifest removal. Deleting
the Applications is the supported way to remove everything (see above).

## Namespaces

- `orc-system`: ORC controller (created by the chart applications).
- `openstack`: ORC custom resources, the credentials Job and its Secret.
- The Argo CD namespace hosting the Applications is discovered at runtime
from the deployed pattern Applications; the manifests' hardcoded
`namespace: vp-gitops` is only a documented default that the tests
override.

## Running the tests

`test_k_orc.py` is collected through `tests/ci/test_standalone.py` (the
`k-orc` directory name is not a valid Python package name, so
`tests/ci/conftest.py` puts it on `sys.path` and `test_standalone.py`
star-imports it). Run as usual:

```bash
VP_HUBCONFIG=<kubeconfig> ./pattern.sh make run-ci-tests
```

Environment knobs: `VP_KORC_TEST_TIMEOUT` (default 900s),
`VP_KORC_POLL_INTERVAL` (default 5s), `VP_KORC_REPOURL` /
`VP_KORC_TARGET_REVISION` (override the k-orc-resources source). The first
deployment can take a few minutes (chart pulls, controller start, image
download, VM build), hence the larger default timeout compared to the rest
of the suite.

The tests apply the Applications and then assert:

- `k-orc-crds`, `k-orc-operator` and `k-orc-resources` applications are
Synced and Healthy,
- the ORC CRDs are installed and the controller Deployment is Available,
- every smoke stack object is `Available=True` / `Progressing=False` with a
populated `status.id`, failing fast on terminal error reasons,
- the server boots from the managed image and the port has a fixed IP.
48 changes: 48 additions & 0 deletions tests/ci/k-orc/applications/k-orc-crds.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
# Installs the ORC Custom Resource Definitions from the official ORC Helm
# chart published on quay.io.
#
# This Application is created by the "k-orc" application rendered by the
# rhoso-gitops chart (see charts/all/rhoso-gitops/values.yaml). It must run
# before the controller (k-orc-operator.yaml) and before any ORC custom
# resources are applied.
#
# Pruning is intentionally disabled: CRDs are cluster-scoped and deleting
# them would delete every ORC custom resource in the cluster.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: k-orc-crds
# The namespace must match the Argo CD instance watching Applications.
namespace: vp-gitops
labels:
# Identifies applications owned by CI features. The pattern inventory
# test excludes applications with this label.
validatedpatterns.io/ci-feature: k-orc
annotations:
argocd.argoproj.io/sync-wave: "-2"
finalizers:
- resources-finalizer.argocd.argoproj.io/background
spec:
project: default
source:
# Helm OCI chart: <registry>/<chart path> is split between repoURL/chart.
repoURL: quay.io
chart: orc/helm/orc-crds
# Keep in sync with k-orc-operator.yaml. Both charts must use the same
# released version.
targetRevision: 3.0.0-pre1
destination:
server: https://kubernetes.default.svc
namespace: orc-system
syncPolicy:
automated: {}
retry:
limit: 20
backoff:
duration: 30s
factor: 2
maxDuration: 5m
syncOptions:
- Prune=false
- CreateNamespace=true
57 changes: 57 additions & 0 deletions tests/ci/k-orc/applications/k-orc-operator.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
# Deploys the ORC controller from the official ORC Helm chart published on
# quay.io.
#
# This Application is created by the "k-orc" application rendered by the
# rhoso-gitops chart (see charts/all/rhoso-gitops/values.yaml). It runs after
# the CRDs (k-orc-crds.yaml) and before any ORC custom resources are applied.
#
# Pruning is intentionally disabled: GitOps removal of manifests must not
# delete the controller or its resources.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: k-orc-operator
# The namespace must match the Argo CD instance watching Applications.
namespace: vp-gitops
labels:
# Identifies applications owned by CI features. The pattern inventory
# test excludes applications with this label.
validatedpatterns.io/ci-feature: k-orc
annotations:
argocd.argoproj.io/sync-wave: "-1"
finalizers:
- resources-finalizer.argocd.argoproj.io/background
spec:
project: default
source:
# Helm OCI chart: <registry>/<chart path> is split between repoURL/chart.
repoURL: quay.io
chart: orc/helm/orc
# Keep in sync with k-orc-crds.yaml. Both charts must use the same
# released version.
targetRevision: 3.0.0-pre1
helm:
values: |
# Do not use the upstream default priority class: it is reserved for
# system components on OpenShift. Drop the chart's fixed runAsUser/
# runAsGroup as well: OpenShift restricted-v2 SCCs require UIDs from
# the namespace's allocated range (the pod keeps runAsNonRoot).
priorityClassName: ""
containerSecurityContext:
runAsUser: null
runAsGroup: null
destination:
server: https://kubernetes.default.svc
namespace: orc-system
syncPolicy:
automated: {}
retry:
limit: 20
backoff:
duration: 30s
factor: 2
maxDuration: 5m
syncOptions:
- Prune=false
- CreateNamespace=true
49 changes: 49 additions & 0 deletions tests/ci/k-orc/applications/k-orc-resources.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
# Template for the k-orc-resources Argo CD Application, applied by the CI
# tests (tests/ci/k-orc/test_k_orc.py).
#
# The CI tests fill in spec.source.repoURL and spec.source.targetRevision
# (deployment-specific: the pattern's own repository and branch) and create
# this Application in the namespace of the Argo CD instance managing the
# pattern. Its source path (tests/ci/k-orc/resources) holds the credentials
# Job/RBAC and the ORC custom resources.
#
# Until the ORC CRDs are established (k-orc-crds.yaml), Argo CD rejects this
# Application's sync plan ("one or more synchronization tasks are not valid");
# the sync retries below make it converge once the CRDs are in place.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: k-orc-resources
# Overwritten by the CI tests with the discovered Argo CD namespace.
namespace: vp-gitops
labels:
# Identifies applications owned by CI features. The pattern inventory
# test excludes applications with this label.
validatedpatterns.io/ci-feature: k-orc
finalizers:
- resources-finalizer.argocd.argoproj.io/background
spec:
project: default
source:
# Filled in by the CI tests.
repoURL: ""
path: tests/ci/k-orc/resources
targetRevision: ""
destination:
server: https://kubernetes.default.svc
namespace: openstack
syncPolicy:
automated: {}
retry:
# Until the ORC CRDs are established the sync plan is rejected; short
# retries cover that window, and exhaust quickly enough that a new
# revision (or a re-created Application) re-triggers a fresh sync
# promptly.
limit: 12
backoff:
duration: 10s
factor: 2
maxDuration: 1m
syncOptions:
- Prune=false
58 changes: 58 additions & 0 deletions tests/ci/k-orc/resources/00-credentials-rbac.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
# RBAC for the k-orc credentials Job. The Job reads the RHOSO
# openstack-config ConfigMap (clouds.yaml without the password), the
# openstack-config-secret Secret (cloudrc, which carries OS_PASSWORD) and the
# combined-ca-bundle Secret (CA bundle), and writes the assembled ORC
# credential Secret orc-cloud-config.
#
# Applied by the "k-orc" Argo CD application, sync wave -2 (before the
# credentials Job).
apiVersion: v1
kind: ServiceAccount
metadata:
name: k-orc-credentials
namespace: openstack
annotations:
argocd.argoproj.io/sync-wave: "-2"
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: k-orc-credentials
namespace: openstack
annotations:
argocd.argoproj.io/sync-wave: "-2"
rules:
- apiGroups: [""]
resources: [configmaps]
resourceNames: [openstack-config]
verbs: [get]
- apiGroups: [""]
resources: [secrets]
resourceNames: [openstack-config-secret, combined-ca-bundle]
verbs: [get]
- apiGroups: [""]
resources: [secrets]
resourceNames: [orc-cloud-config]
verbs: [get, patch, update]
# Create cannot be restricted by resourceName; the service account is
# dedicated to this Job and can only create secrets in this namespace.
- apiGroups: [""]
resources: [secrets]
verbs: [create]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: k-orc-credentials
namespace: openstack
annotations:
argocd.argoproj.io/sync-wave: "-2"
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: k-orc-credentials
subjects:
- kind: ServiceAccount
name: k-orc-credentials
namespace: openstack
Loading
Loading