Skip to content

Latest commit

 

History

53 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AutoShift Console Plugin

A read-only OpenShift console dynamic plugin that adds an AutoShift section to the Fleet management perspective, surfacing what AutoShift configures across a fleet of clusters.

ACM's own console shows clusters, cluster sets and policy compliance. What it cannot show is why a cluster is configured the way it is — AutoShift resolves fleet defaults, cluster-set config and per-cluster overrides into a single rendered config, and that derivation is invisible. This plugin makes it legible.

Pages

Page Path What it answers
Fleet /autoshift/fleet What does this deployment configure, and which clusters need attention?
Cluster Sets /autoshift/cluster-sets What does each set turn on, who overrides it, and what reads it?
Clusters /autoshift/clusters Where did each setting come from?
Stacks /autoshift/stacks What is deployed, grouped by application stack?

The Clusters page carries the provenance drawer: for any setting, the layer chain

fleet default  →  cluster-set-config.<set>  →  managed-cluster-config.<cluster>  →  rendered-config
   gp3-csi            gp3-csi                      gp2-csi  ← wins                     gp2-csi

with superseded values struck through.

Every policy name in the UI — on a cluster's Compliance tab, and under a cluster set's Consumed by view — links to that policy's per-cluster results in ACM Governance (/multicloud/governance/policies/details/<namespace>/<name>/results). Both plugins live in the Fleet management perspective, so it is an in-app navigation rather than a page load.

Why there is no config or label drift view

AutoShift reconciles both continuously: cluster-labels is a mustonlyhave + enforce policy, and rendered-config is generated by a policy from the same ConfigMaps the plugin reads. Desired and actual are therefore equal except while a policy is mid-reconcile, and when they are not, the policy reports itself NonCompliant — which the Compliance tab already shows.

A client-side diff of the two could only ever surface that transient, or a discrepancy in this plugin's own re-implementation of the merge. model.live.spec.ts pins the invariant, so if enforcement semantics ever change the test fails rather than the UI quietly going wrong.

The one desired-vs-actual comparison the plugin does make is the OpenShift version: an upgrade takes hours, so that gap is real state rather than a race with a controller.

How it discovers data

Nothing about AutoShift's policy list is compiled into this plugin. The whole model is derived at runtime from objects on the hub, so a policy added to AutoShift appears here with no plugin rebuild and no version coupling to an AutoShift release:

What Source
AutoShift deployments ConfigMaps labelled autoshift.io/cluster-labels; namespace policies-<release>
Components, sync/health, version ArgoCD Applications labelled app: <release>-policies
Gating label per component Placement.spec.predicates[].requiredClusterSelector
Which components read a label the same predicates, inverted — note this is consumption, so gitlab appears under odf because it requires ODF, not because it provides it
Clusters per component PlacementDecision labelled cluster.open-cluster-management.io/placement
Policy ↔ Placement PlacementBinding
Compliance Policy.status.status[]
Config layers ConfigMaps labelled autoshift.io/cluster-default-configs, …/cluster-set-configs, …/cluster-configs
Resolved config ConfigMaps labelled autoshift.io/rendered-config-map
Actual labels, health, version ManagedCluster

There is no backend service. Every read goes through the console's Kubernetes proxy via useK8sWatchResource, so the viewer's own RBAC applies and no privileged service account exists. A user who cannot list ManagedCluster simply sees less.

Feature grouping (cluster sets)

Labels group into features using the cluster's own vocabulary — every Placement gating label plus every component name. A label joins the shortest known name that prefixes it, so cert-manager-ca and cert-manager-ingress-cert land under cert-manager, while node-feature-discovery and node-maintenance stay apart. Group names are never guessed from string prefixes; doing that produced overlapping junk groups (cert beside cert-manager).

A label matching no known name falls back to its leading token, absorbing same-token groups so acm-source sits with acm-observability rather than beside it.

Stack grouping (stacks page)

Only the names are editorial. Resolution order:

  1. ConfigMap/autoshift-console-catalog in the autoshift-console namespace — admin-editable in-cluster
  2. DEFAULT_STACKS in src/lib/catalog.ts, versioned with the plugin image
  3. anything unnamed classifies itself by the API groups its policies manage, so a new AutoShift policy lands somewhere sensible with no plugin rebuild
  4. only a component managing nothing but generic resources reaches Other

The page also offers By tier (stable / certified / community), read from each Application's policies/<tier>/<name> source path — fully derived, no catalog involved.

Thematic names cannot be derived: policy categories carry two distinct values across ~180 policies, component names leave most components as singletons, and namespaces are mostly the shared openshift-operators. That is why a curated list still exists at all.

To regroup without rebuilding:

apiVersion: v1
kind: ConfigMap
metadata:
  name: autoshift-console-catalog
  namespace: autoshift-console
data:
  stacks: |
    stacks:
      - id: ai
        name: AI & Accelerators
        components:
          - openshift-ai
          - gpu-operator

Development

Requires Node.js and a cluster login. The repo vendors Yarn 4, so no global install is needed.

The plugin is built once per OpenShift release (see ocp-targets.json), because the console supplies react, react-router and react-i18next as shared singletons and those versions change between releases — most sharply at 4.22, where the console moved React 17 to 18. A bundle built for the wrong release loads and then fails silently: the pod serves assets, the console skips the plugin, and every route 404s with nothing in any server-side log.

Pick a target before installing — it rewrites the shared-module pins and the declared pluginAPI range in package.json:

./scripts/set-ocp-target.sh 4.22
node .yarn/releases/yarn-4.17.1.cjs install --immutable
node .yarn/releases/yarn-4.17.1.cjs start        # plugin dev server on :9001

oc login <your-autoshift-hub>
node .yarn/releases/yarn-4.17.1.cjs start-console # console container on :9000, pinned to 4.22

Open http://localhost:9000/autoshift. window.SERVER_FLAGS.consolePlugins should list autoshift-console.

The plugin only has data on a cluster running an AutoShift instance. Elsewhere it renders an empty state explaining why rather than a blank page.

node .yarn/releases/yarn-4.17.1.cjs lint    # eslint + stylelint, mandatory before commit
node .yarn/releases/yarn-4.17.1.cjs test    # jest unit tests
node .yarn/releases/yarn-4.17.1.cjs build   # production bundle
node .yarn/releases/yarn-4.17.1.cjs i18n    # re-extract locales after changing strings

yarn.lock is committed, so Dependabot maintains it and CI's --immutable install means something. That holds only while there is one target: two targets need two pinned dependency trees, and Dependabot updates package.json + yarn.lock and nothing else, so a second lockfile would silently go stale and fail every build. ocp-targets.json records the choice that has to be made if 4.23 is added.

src/ocp-targets.spec.ts is what stops that being silent. Add a second target and it fails in yarn test naming the constraint, instead of surfacing later as an unexplained lockfile-drift error inside yarn install --immutable. It does not make multi-target work — it makes breaking the single-target assumption loud. Satisfying it means a lockfile per target and npm updates switched off in .github/dependabot.yml, refreshed by hand on each bump.

Unit tests cover the analytical core — provenance derivation, label merge, catalog resolution — in src/lib/*.spec.ts. That logic mirrors AutoShift's own merge semantics, so it is the part most worth pinning down.

Deployment

Production deployment is handled by AutoShift itself, via the community policy policies/community/autoshift-console/ in the autoshiftv2 repo. Enable it with:

hubClusterSets:
  hub:
    config:
      autoshiftConsole:
        image: 'quay.io/autoshift/autoshift-console-plugin:latest'
        replicas: 2
    labels:
      autoshift-console: 'true'

For a standalone install (local testing, or a cluster not managed by AutoShift), the generic Helm chart under charts/openshift-console-plugin still works:

podman build -t quay.io/autoshift/autoshift-console-plugin:latest .   # --platform=linux/amd64 on Apple Silicon
podman push quay.io/autoshift/autoshift-console-plugin:latest

helm upgrade -i autoshift-console charts/openshift-console-plugin \
  -n autoshift-console --create-namespace \
  --set plugin.image=quay.io/autoshift/autoshift-console-plugin:latest

CI and image security

Workflow Trigger What it does
ci.yaml PR / push to main gitleaks, lint, unit tests, build, then builds the image and fails on fixable HIGH/CRITICAL (image and filesystem). Pushes nothing.
release.yaml tag v*.*.* Builds, scans as a gate, generates an SPDX SBOM, pushes to Quay, then cosign-signs and attests by digest. Scanning happens before registry login, so a failing scan cannot publish.
scheduled-rebuild.yaml Mondays 06:00 UTC Rebuilds the latest release tag's source against freshly resolved UBI base digests, scans, publishes <tag>-<date> and latest, signs. A second job scans the already-published image (including unfixed CVEs) and opens or closes a tracking issue.

Base images are pinned by digest so a scan describes exactly what ships; Dependabot moves the pin, and the weekly rebuild overrides it via --build-arg to pick up Red Hat's patched bases without waiting for a commit.

On "zero vulnerabilities": the gate enforces zero fixable HIGH/CRITICAL, and the image currently meets it — a local scan of the full build reported 0 fixable at every severity.

It does carry a standing tail of unfixed CVEs inherited from the UBI base (17 HIGH, 327 MEDIUM, 403 LOW at the time of writing), none of which have an upstream fix yet. Those cannot be actioned by rebuilding, so they do not gate and do not open an issue; the weekly job reports them as a summary table instead. A CVE disclosed after release moves the count without anything changing, so the real measure is time-to-patch, which the weekly rebuild bounds to seven days.

The base carries far more packages than a static file server needs (the image is ~339 MB). A minimal base would cut the raw count sharply at the cost of leaving Red Hat's patch stream, which is why it has not been done.

ubi9/nodejs-22 and ubi9/nginx-126 are official Red Hat UBI images (vendor: Red Hat, Inc.). That is not the same as Red Hat Certified — certification is a Partner Connect process for the resulting image, not a property inherited from the base.

Build args are named PLUGIN_VERSION / PLUGIN_REVISION: podman/buildah silently clobbers a build arg called VERSION (verified on 5.4.1), which made the image label claim a version it was not built at.

Scope

Read-only by design. No writes, no GitOps PR write-back, no values simulator, and no Thanos/ACM Observability metrics — the plugin depends on nothing beyond the Kubernetes API.

Actual installed operator CSVs are not shown: they are not available on the hub. Channel and version columns are labelled as desired, sourced from the <component>-channel / <component>-version labels.

License

Apache 2.0. Custom console plugin code is not supported by Red Hat — only Cooperative community support is available.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages