Skip to content

Conversation

mboersma
Copy link

@mboersma mboersma commented Jun 10, 2025

NOTE: This is still a work in progress. There are a few issues to address before it should merge.

Adds a headlamp plugin for rendering Cluster API objects in the Sidebar and Map.

capi-plugin
capi-plugin-2

Fixes kubernetes-sigs/cluster-api#12305

TODO:

  • The Detail views for all objects are generic, but should show more specific information.
  • The on-hover "Glance" tooltips in the Map should show more info, like basic k8s objects do.
  • There should be some basic tests.
  • Column spacing in list views could use some attention
  • The Cluster detail view should have a "Get kubeconfig" action button, and the downloaded kubeconfig should show up in Headlamp's "Clusters" list (see Headlamp.setCluster())
  • The MachinePool spec needs the template fields to be added.
  • The typescript defs for CAPI resources are not all complete and need reviewing.
  • The ClusterDetail view causes an error when its route is registered.
  • Time fields in List views should be formatted as kubectl -o table does, e.g. "2d5h".
  • The Sidebar needs a black-and-white "turtles" icon for CAPI.
  • All CAPI types are using the "turtles" icon, but they should have their own icons.
  • "Controlled by" field in Detail views should be a link to the owning object (see Pods for example)

Wishlist:

  • Should be able to render infra ref provider-specific objects in the tree, or other bootstrap components
  • Could elevate "Ready" condition to main detail view
  • There should be storybook tests for all components. (Currently not working--see comments below.)
  • The plugin should support the upcoming v1beta2 version of Cluster API resources.
  • KubeadmControlPlane and MachineDeployment|Set|Pool should have the ScaleButton and act like k8s Deployment/ReplicaSet (see Allow plugins to register as scalable resources kubernetes-sigs/headlamp#3536)
  • The Map filter menu should have multiple sources so it expands and can toggle all CAPI CRDs individually

Questions:
I don't know if this should be an official plugin or live in a separate repo. Any advice here is welcome.

@mboersma
Copy link
Author

/cc @willie-yao

@joaquimrocha
Copy link
Contributor

@mboersma , I am happy to have it as an official plugin.
Here is a turtle icon you may use: https://icon-sets.iconify.design/mdi/?icon-filter=turtle

We may also be able to early-merge it into a capi-plugin branch, so it continues being worked on without depending just on your branch. WDYT?

@mboersma mboersma changed the title Add Cluster API plugin [WIP] Add Cluster API plugin Jun 12, 2025
@mboersma
Copy link
Author

@joaquimrocha thanks for the info and the icon!

If it's ok to leave this as a work-in-progress for a few days, I think we can fix most of the known issues and then see if a capi-plugin branch would help with collaboration.

@mboersma mboersma force-pushed the cluster-api branch 3 times, most recently from 73d6515 to 87f84f5 Compare June 13, 2025 23:48
@mboersma mboersma force-pushed the cluster-api branch 2 times, most recently from 4e8c517 to f349a61 Compare June 17, 2025 23:22
@illume
Copy link
Contributor

illume commented Jun 18, 2025

For stories there's a problem with the current headlamp-plugin.

We have storybooks working in a headlamp-plugin alpha release, but there's still some bugs.

cd cluster-api
npx @kinvolk/headlamp-plugin upgrade --headlamp-plugin-version=0.13.0-alpha.5
diff --git a/cluster-api/src/index.tsx b/cluster-api/src/index.tsx
index a36d967..7eada7f 100644
--- a/cluster-api/src/index.tsx
+++ b/cluster-api/src/index.tsx
@@ -70,7 +70,7 @@ function registerClusterApiResource(config: ResourceRegistrationConfig) {
     path: `/cluster-api/${path}/${hasNamespace ? ':namespace/:name' : ':name'}`,
     sidebar: name,
     name: name.slice(0, -1), // Remove 's' from plural form
-    component: DetailComponent,
+    component: () => <DetailComponent />,
   });

   // Register list route
@@ -78,7 +78,7 @@ function registerClusterApiResource(config: ResourceRegistrationConfig) {
     path: `/cluster-api/${path}`,
     sidebar: name,
     name,
-    component: ListComponent,
+    component: () => <ListComponent />,
   });

   // Register icon for the resource kind   

One issue with the headlamp-plugin alpha is that it has issues with this import path when running the storybook.

diff --git a/cluster-api/src/resources/kubeadmcontrolplane.ts b/cluster-api/src/resources/kubeadmcontrolplane.ts
index 867af16..59ef79b 100644
--- a/cluster-api/src/resources/kubeadmcontrolplane.ts
+++ b/cluster-api/src/resources/kubeadmcontrolplane.ts
@@ -1,4 +1,4 @@
-import { KubeObject, KubeObjectInterface, Time } from '@kinvolk/headlamp-plugin/lib/k8s/cluster';
+import { KubeObject, KubeObjectInterface, Time } from '@kinvolk/headlamp-plugin/lib/lib/k8s/cluster';
 import { Condition, ObjectMeta, ReadinessGate } from './common';
 import { KubeadmConfigSpec } from './kubeadmconfig';

Autogenerated a storybook story:
src/components/kubeadmcontrolplanes/Glance.stories.tsx

import { Meta, StoryObj } from '@storybook/react';
import { KubeadmControlPlane } from '../../resources/kubeadmcontrolplane';
import { KubeadmControlPlaneGlance } from './Glance';

const meta: Meta<typeof KubeadmControlPlaneGlance> = {
  title: 'Components/KubeadmControlPlanes/Glance',
  component: KubeadmControlPlaneGlance,
  parameters: {
    layout: 'centered',
  },
};

export default meta;
type Story = StoryObj<typeof KubeadmControlPlaneGlance>;

export const Default: Story = {
  args: {
    node: {
      kubeObject: {
        kind: KubeadmControlPlane.kind,
        spec: {
          replicas: 3,
        },
        status: {
          readyReplicas: 2,
        },
      },
    },
  },
};

export const AllReplicasReady: Story = {
  args: {
    node: {
      kubeObject: {
        kind: KubeadmControlPlane.kind,
        spec: {
          replicas: 3,
        },
        status: {
          readyReplicas: 3,
        },
      },
    },
  },
};

export const NoReplicasReady: Story = {
  args: {
    node: {
      kubeObject: {
        kind: KubeadmControlPlane.kind,
        spec: {
          replicas: 3,
        },
        status: {
          readyReplicas: 0,
        },
      },
    },
  },
};

export const InvalidNodeKind: Story = {
  args: {
    node: {
      kubeObject: {
        kind: 'SomeOtherKind',
      },
    },
  },
};

Then you can see the storybook in here:
npm run storybook

Note, I didn't run the plugin with the headlamp-plugin alpha release. The npm run build, and npm run tsc run without error though. Let me know if you have any issues?

@illume
Copy link
Contributor

illume commented Jun 18, 2025

Sorry, I had the wrong line here:

npx @kinvolk/headlamp-plugin upgrade --headlamp-plugin-version=0.13.0-alpha.2

Should have been:

npx @kinvolk/headlamp-plugin upgrade --headlamp-plugin-version=0.13.0-alpha.5

@mboersma
Copy link
Author

Thanks @illume! I made the changes you suggested. Two problems:

  • npm run storybook won't compile without the change from lib/ to lib/lib/, but that change seems to break the plugin in general
  • When npm run storybook loads, it shows the Glance stories but won't render with this error:
ReferenceError: Cannot access 'KubeObject' before initialization
    at makeKubeObject (http://localhost:6007/vendors-node_modules_kinvolk_headlamp-plugin_lib_components_common_Resource_index_js-node_mod-dc3e88.iframe.bundle.js:34520:38)
    at ./node_modules/@kinvolk/headlamp-plugin/lib/lib/k8s/clusterRole.js (http://localhost:6007/vendors-node_modules_kinvolk_headlamp-plugin_lib_components_common_Resource_index_js-node_mod-dc3e88.iframe.bundle.js:37955:86)
    at __webpack_require__ (http://localhost:6007/runtime~main.iframe.bundle.js:28:33)
    at fn (http://localhost:6007/runtime~main.iframe.bundle.js:343:21)
    at ./node_modules/@kinvolk/headlamp-plugin/lib/lib/k8s/index.js (http://localhost:6007/vendors-node_modules_kinvolk_headlamp-plugin_lib_components_common_Resource_index_js-node_mod-dc3e88.iframe.bundle.js:39245:70)
    at __webpack_require__ (http://localhost:6007/runtime~main.iframe.bundle.js:28:33)
    at fn (http://localhost:6007/runtime~main.iframe.bundle.js:343:21)
    at ./node_modules/@kinvolk/headlamp-plugin/lib/components/account/Auth.js (http://localhost:6007/vendors-node_modules_kinvolk_headlamp-plugin_lib_components_common_Resource_index_js-node_mod-dc3e88.iframe.bundle.js:12957:66)
    at __webpack_require__ (http://localhost:6007/runtime~main.iframe.bundle.js:28:33)
    at fn (http://localhost:6007/runtime~main.iframe.bundle.js:343:21)

@illume
Copy link
Contributor

illume commented Jun 18, 2025

Ok, thanks for those notes. I’ll work on fixing them tomorrow.

Signed-off-by: Matt Boersma <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Headlamp plugin for Cluster API
3 participants