Multi Cluster View (OCM) logo

Backstage Multi Cluster View with OCM Plugin

Created by Red Hat

Multi Cluster View with OCM brings your fleet view from Open Cluster Management into Backstage. OCM runs a hub that knows about every managed Kubernetes cluster through MultiClusterHub and MultiCluster Engine. This plugin pulls those clusters into the Backstage catalog as resources, then shows live details on each cluster page. You see health, node state, Kubernetes and OpenShift versions, and available capacity. You also get direct links to the OpenShift console, the OCM console, and OpenShift Cluster Manager.

This fits teams that already use OpenShift or OCM to manage many clusters. Platform engineers get a single place to check fleet status inside the developer portal they already use. SREs can spot down clusters fast and jump to the right console with one click. Developers can understand where their services run by following catalog relations back to the clusters that host them. The plugin can surface all clusters on a dedicated page in Backstage, or show cluster info on each cluster resource page, so you can choose what suits your portal. The goal is simple. Put fleet awareness next to your services and docs so people do not switch tools or contexts to get work done.

Installation Instructions

These instructions apply to self-hosted Backstage only.

Install the backend package with the new backend system

  1. Add the backend package
Copy
yarn workspace backend add @backstage-community/plugin-ocm-backend
  1. Add OCM provider config

Use one of the two options below.

Direct hub config

Add an OCM provider entry to your app config. Use a ServiceAccount token from the hub. Use a valid Backstage entity name for the hub name.

Copy
# app-config.yaml
catalog:
  providers:
    ocm:
      env:
        name: your-hub-name
        url: https://hub-api.example.com
        serviceAccountToken: ${OCM_HUB_TOKEN}
        skipTLSVerify: false
        caData:

Bind to an existing Kubernetes cluster config

If your Kubernetes plugin already has the hub configured, reference it here. The cluster name must match.

Copy
# app-config.yaml
kubernetes:
  serviceLocatorMethod:
    type: multiTenant
  clusterLocatorMethods:
    - type: config
      clusters:
        - name: hub
          url: https://hub-api.example.com
          serviceAccountToken: ${OCM_HUB_TOKEN}
          skipTLSVerify: false
          caData:

catalog:
  providers:
    ocm:
      env:
        kubernetesPluginRef: hub
  1. Optional default owner for discovered clusters
Copy
# app-config.yaml
catalog:
  providers:
    ocm:
      env:
        owner: user:foo
  1. Optional schedule for refresh and timeout
Copy
# app-config.yaml
catalog:
  providers:
    ocm:
      env:
        schedule:
          frequency:
            minutes: 30
          timeout:
            minutes: 5
  1. Wire the backend modules

Add the OCM backend modules to the new backend system.

Copy
// packages/backend/src/index.ts
import { createBackend } from '@backstage/backend-defaults';
import {
  catalogModuleOCMEntityProvider
  , ocmPlugin
} from '@backstage-community/plugin-ocm-backend';

const backend = createBackend();

backend.add(catalogModuleOCMEntityProvider);
backend.add(ocmPlugin);

backend.start();

Set up access on the hub cluster

Create the ClusterRole on the hub. Then create a ServiceAccount and bind this role to it. Use the token from that ServiceAccount in your app config.

Copy
# apply on the hub cluster
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: backstage-ocm-plugin
rules:
  - apiGroups:
      - cluster.open-cluster-management.io
    resources:
      - managedclusters
    verbs:
      - get
      - watch
      - list
  - apiGroups:
      - internal.open-cluster-management.io
    resources:
      - managedclusterinfos
    verbs:
      - get
      - watch
      - list

Install the frontend package

  1. Add the frontend package
Copy
yarn workspace app add @backstage-community/plugin-ocm
  1. Add the OCM page route so people can reach it
Copy
// packages/app/src/App.tsx
import React from 'react';
import { Route } from 'react-router';
import { FlatRoutes } from '@backstage/core-app-api';
import { OcmPage } from '@backstage-community/plugin-ocm';
import { Logo } from './components/Root/Logo'; // use your logo

export const routes = (
  <FlatRoutes>
    {/* other routes */}
    <Route path="/ocm" element={<OcmPage logo={<Logo />} />} />
  </FlatRoutes>
);
  1. Add a sidebar link
Copy
// packages/app/src/components/Root/Root.tsx
import React, { PropsWithChildren } from 'react';
import { SidebarPage, Sidebar, SidebarGroup, SidebarItem } from '@backstage/core-components';
import MenuIcon from '@material-ui/icons/Menu';
import { OcmIcon } from '@backstage-community/plugin-ocm';

export const Root = ({ children }: PropsWithChildren<{}>) => (
  <SidebarPage>
    <Sidebar>
      <SidebarGroup label="Menu" icon={<MenuIcon />}>
        {/* other items */}
        <SidebarItem icon={OcmIcon} to="ocm" text="Clusters" />
      </SidebarGroup>
    </Sidebar>
    {children}
  </SidebarPage>
);
  1. Show cluster info on Resource entity pages

Add the context provider and cards to the Resource entity page. These appear for entities of kind Resource with spec.type set to kubernetes-cluster.

Copy
// packages/app/src/components/catalog/EntityPage.tsx
import React from 'react';
import Grid from '@material-ui/core/Grid';
import { Entity } from '@backstage/catalog-model';
import { EntityLayout, EntitySwitch, isKind } from '@backstage/plugin-catalog';
import {
  ClusterAvailableResourceCard,
  ClusterContextProvider,
  ClusterInfoCard,
} from '@backstage-community/plugin-ocm';

const isType = (types: string | string[]) => (entity: Entity) => {
  if (!entity?.spec?.type) return false;
  return typeof types === 'string'
    ? entity?.spec?.type === types
    : types.includes(entity.spec.type as string);
};

export const resourcePage = (
  <EntityLayout>
    <EntityLayout.Route path="/status" title="status">
      <EntitySwitch>
        <EntitySwitch.Case if={isType('kubernetes-cluster')}>
          <ClusterContextProvider>
            <Grid container direction="column" xs={6}>
              <Grid item>
                <ClusterInfoCard />
              </Grid>
              <Grid item>
                <ClusterAvailableResourceCard />
              </Grid>
            </Grid>
          </ClusterContextProvider>
        </EntitySwitch.Case>
      </EntitySwitch>
    </EntityLayout.Route>
  </EntityLayout>
);

export const entityPage = (
  <EntitySwitch>
    {/* other cases */}
    <EntitySwitch.Case if={isKind('resource')} children={resourcePage} />
  </EntitySwitch>
);

Optional permission policy for RBAC plugin

Add these to your external policy file if you use the RBAC framework.

Copy
p, role:default/rbac_admin, ocm.entity.read, read, allow
p, role:default/rbac_admin, ocm.cluster.read, read, allow

Old backend system

This plugin ships modules for the new backend system. Legacy backend code is not provided here. If your app still uses the old backend system, migrate the backend to the new system before adding this plugin.

Changelog

This changelog is produced from commits made to the Multi Cluster View (OCM) plugin since 7 months ago, and based on the code located here. It may not contain information about all commits. Releases and version bumps are intentionally omitted. This changelog is generated by AI.

Breaking changes

No breaking changes

Maintenance

  • Remove product theme from the dev app #4799 merged 2 months ago
  • Remove support and lifecycle keywords from plugin metadata #4302 merged 3 months ago
  • Remove unused dependencies in the OCM plugin #3440 merged 6 months ago
  • Remove direct prettier config from plugins #3672 merged 6 months ago
  • Clean up vendor and Janus references in package files #3476 merged 6 months ago
  • Reduce knip false positives by using workspace config #3018 merged 7 months ago
  • Remove prettier from plugin devDependencies since it exists at the workspace level #3012 merged 7 months ago

Set up Backstage in minutes with Roadie