From 53294f452adbba087eaf2b222488cd0b1cfd4e19 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 18 Jan 2023 13:47:54 +0100 Subject: [PATCH 01/18] docs: Add backend plugin migration guide Signed-off-by: Johan Haals --- .../08-migrating.md | 221 +++++++++++++++++- 1 file changed, 220 insertions(+), 1 deletion(-) diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index 2f3fd5ebcc..b9bd392583 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -6,4 +6,223 @@ sidebar_label: Migration Guide description: How to migrate existing backend plugins to the new backend system --- -# Overview +Migrating an existing backend plugin to the new backend system is fairly straightforward and similar across as the majority of return a `Router` that is then wired up in the index.ts file. The primary thing that we need to do is to make sure that the dependencies that are required by the plugin are available and then register the router with the http router service. + +Let's look at an example of migrating the Kubernetes Backend Plugin. In the existing(old) system the kubernetes backend is structured like this: + +```ts +// @backstage/plugin-kubernetes-backend/src/service/router.ts + +import { KubernetesBuilder } from './KubernetesBuilder'; +export interface RouterOptions { + logger: Logger; + config: Config; + catalogApi: CatalogApi; + clusterSupplier?: KubernetesClustersSupplier; + discovery: PluginEndpointDiscovery; +} + +export async function createRouter( + options: RouterOptions, +): Promise { + const { router } = await KubernetesBuilder.createBuilder(options) + .setClusterSupplier(options.clusterSupplier) + .build(); + return router; +} +``` + +We can re-use the `router` created by the `KubernetesBuilder` in the new backend system. We only need to make sure that the dependencies specified in `RouterOptions` above are available. All of them are part of the `coreServices` which makes migration easy. + +```ts +import { + coreServices, + createBackendPlugin, +} from '@backstage/backend-plugin-api'; +import { catalogServiceRef } from '@backstage/plugin-catalog-node'; +import { Router } from 'express'; +import { KubernetesBuilder } from './KubernetesBuilder'; + +export const kubernetesPlugin = createBackendPlugin({ + id: 'kubernetes', + register(env) { + env.registerInit({ + deps: { + logger: coreServices.logger, + config: coreServices.config, + catalogApi: catalogServiceRef, + discovery: coreServices.discovery, + // The http router service is used to register the router created by the KubernetesBuilder. + http: coreServices.httpRouter, + }, + async init({ config, logger, catalogApi, discovery, http }) { + const { router } = await KubernetesBuilder.createBuilder({ + config, + logger, + catalogApi, + discovery, + }).build(); + + // We registered the router with the http service. + http.use(router); + }, + }); + }, +}); +``` + +Done! Users of this plugin are now able to import the `kubernetesPlugin` and register it in their backend using + +```ts +// packages/backend/src/index.ts +import { kubernetesPlugin } from '@backstage/plugin-kubernetes-backend'; +backend.add(kubernetesPlugin); +``` + +There's one thing missing that those sharp eyed readers might have noticed, the `clusterSupplier` option is missing from the original plugin. Let's add it and discuss the alternatives. + +One alternative is pass the `ClusterSupplier` in as options to the plugin which is quick and easy but not very flexible and hard to evolve without introducing breaking changes as it changes the public API for the plugin. Having complex types passed in directly to the plugin also clutters the backend setup code and makes it harder to read. + +Options are primarily used for simple configuration values that are not complex types. In this case we want to allow users to register their own `ClusterSupplier` implementations to the plugin. This is where the new backend system's [ExtensionPoints](fixme.md) but let's look at doing this with options first. + +```ts +/* omitted imports but they remain the same as above */ + +export interface KubernetesOptions { + clusterSupplier?: KubernetesClustersSupplier; +} + +const kubernetesPlugin = createBackendPlugin((options: KubernetesOptions) => ({ + id: 'kubernetes', + register(env) { + env.registerInit({ + deps: { + /* omitted imports but they remain the same as above */ + }, + async init({ config, logger, catalogApi, discovery, http }) { + const { router } = await KubernetesBuilder.createBuilder({ + config, + logger, + catalogApi, + discovery, + }) + .setClusterSupplier(options.clusterSupplier) + .build(); + http.use(router); + }, + }); + }, +})); +``` + +The above would allow users to specify their own `ClusterSupplier` implementation to the plugin like this: + +```ts +backend.add( + kubernetesPlugin({ clusterSupplier: new MyCustomClusterSupplier() }), +); +``` + +Just to echo what was said above, this is not a very flexible solution and will for example be problematic to maintain backwards compatible if we start evolving the options to for example accept multiple suppliers or tweak the `ClusterSupplier` interface. + +The new [ExtensionPoints](fixme.md) API allows [Modules](fixme) to add function into the backend plugin itself, in this case an additional `ClusterSupplier` + +The kubernetes backend plugin only supports one `ClusterSupplier` at this time but let's look at how we could add support for multiple suppliers using extension points. This allows users to install several modules that add their own `ClusterSupplier` implementations to the plugin like this: + +```ts +backend.add(kubernetesPlugin()); +backend.add(GoogleContainerEngineModule()); +backend.add(EKSModule()); +``` + +Now let's look at how to implement this with extension points. First we need to define the extension point itself. As the ExtensionPoint will be used by other modules we need to export its common practice to export these from a shared package so that they can be imported by other modules and plugins. + +We'll go ahead and create a `@backstage/plugin-kubernetes-node` package for this and from there we'll export the extension point. + +```ts +import { createExtensionPoint } from '@backstage/backend-plugin-api'; + +export interface KubernetesClusterSupplierExtensionPoint { + addClusterSupplier(supplier: KubernetesClustersSupplier): void; +} + +/** + * An extension point that allows other plugins to add catalog processors. + * @public + */ +export const kubernetesClustersSupplierExtensionPoint = + createExtensionPoint({ + id: 'kubernetes.cluster-supplier', + }); +``` + +Now we can use this extension point in the kubernetes backend plugin to register the ExtensionPoint for modules to use. + +```ts +import { kubernetesClustersSupplierExtensionPoint } from '@backstage/plugin-kubernetes-node'; + +// Our internal implementation of the extensionPoint which we do not need to export. +class ClusterSupplier implements KubernetesClustersSupplier { + private clusterSuppliers: KubernetesClustersSupplier[] = []; + + // This method is private and only used internally to retrieve the registered suppliers. + getClusterSuppliers(): KubernetesClustersSupplier[] { + return this.clusterSuppliers; + } + + addClusterSupplier(supplier: KubernetesClustersSupplier) { + this.clusterSuppliers.push(supplier); + } +} + +export const kubernetesPlugin = createBackendPlugin({ + id: 'kubernetes', + register(env) { + const extensionPoint = new ClusterSupplier(); + // We register the extensionPoint with the backend which allows modules to register their own ClusterSupplier. + env.registerExtensionPoint( + kubernetesClustersSupplierExtensionPoint, + extensionPoint, + ); + + env.registerInit({ + deps: { + ... omitted ... + }, + async init({ config, logger, catalogApi, discovery, http }) { + const { router } = await KubernetesBuilder.createBuilder({ + config, + logger, + catalogApi, + discovery, + }) + // We pass in the all the registered suppliers to the builder. + .setClusterSuppliers(...extensionPoint.getClusterSuppliers()) + .build(); + http.use(router); + }, + }); + }, +}); +``` + +And that's it! Modules can now be built that add clusters into to the kubernetes backend plugin, here's an example of a module that adds a `GoogleContainerEngineSupplier` to the kubernetes backend. + +```ts +import { kubernetesClustersSupplierExtensionPoint } from '@backstage/plugin-kubernetes-node'; + +export const kubernetesGKEClusterSupplier = createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'gce.supplier', + register(env) { + env.registerInit({ + deps: { + supplier: kubernetesClustersSupplierExtensionPoint, + }, + async init({ supplier }) { + supplier.addClusterSupplier(new GoogleContainerEngineSupplier()); + }, + }); + }, +}); +``` From 4a997f5f571d43554893500cb28119c463bde588 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 18 Jan 2023 14:55:32 +0100 Subject: [PATCH 02/18] Update docs/backend-system/building-plugins-and-modules/08-migrating.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johan Haals Co-authored-by: Fredrik Adelöw Signed-off-by: Johan Haals --- .../backend-system/building-plugins-and-modules/08-migrating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index b9bd392583..8f5182ae12 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -6,7 +6,7 @@ sidebar_label: Migration Guide description: How to migrate existing backend plugins to the new backend system --- -Migrating an existing backend plugin to the new backend system is fairly straightforward and similar across as the majority of return a `Router` that is then wired up in the index.ts file. The primary thing that we need to do is to make sure that the dependencies that are required by the plugin are available and then register the router with the http router service. +Migrating an existing backend plugin to the new backend system is fairly straightforward. The process is similar across the majority of plugins which just return a `Router` that is then wired up in the `index.ts` file of your backend. The primary thing that we need to do is to make sure that the dependencies that are required by the plugin are available, and then registering the router with the HTTP router service. Let's look at an example of migrating the Kubernetes Backend Plugin. In the existing(old) system the kubernetes backend is structured like this: From 39179d4fa0ea7a3eb79807b6f549e891e6303c08 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 18 Jan 2023 14:55:39 +0100 Subject: [PATCH 03/18] Update docs/backend-system/building-plugins-and-modules/08-migrating.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johan Haals Co-authored-by: Fredrik Adelöw Signed-off-by: Johan Haals --- .../backend-system/building-plugins-and-modules/08-migrating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index 8f5182ae12..2ea7c49d55 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -8,7 +8,7 @@ description: How to migrate existing backend plugins to the new backend system Migrating an existing backend plugin to the new backend system is fairly straightforward. The process is similar across the majority of plugins which just return a `Router` that is then wired up in the `index.ts` file of your backend. The primary thing that we need to do is to make sure that the dependencies that are required by the plugin are available, and then registering the router with the HTTP router service. -Let's look at an example of migrating the Kubernetes Backend Plugin. In the existing(old) system the kubernetes backend is structured like this: +Let's look at an example of migrating the Kubernetes backend plugin. In the existing (old) system, the kubernetes backend is structured like this: ```ts // @backstage/plugin-kubernetes-backend/src/service/router.ts From 03ea9b4be450cfc05901bfd8965c024e256e93f9 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 18 Jan 2023 14:55:47 +0100 Subject: [PATCH 04/18] Update docs/backend-system/building-plugins-and-modules/08-migrating.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johan Haals Co-authored-by: Fredrik Adelöw Signed-off-by: Johan Haals --- .../backend-system/building-plugins-and-modules/08-migrating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index 2ea7c49d55..02cc705689 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -63,7 +63,7 @@ export const kubernetesPlugin = createBackendPlugin({ discovery, }).build(); - // We registered the router with the http service. + // We register the router with the http service. http.use(router); }, }); From b4d4246dbfacc66886aa76af4d8f45539fb34df5 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 18 Jan 2023 14:55:55 +0100 Subject: [PATCH 05/18] Update docs/backend-system/building-plugins-and-modules/08-migrating.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johan Haals Co-authored-by: Fredrik Adelöw Signed-off-by: Johan Haals --- .../backend-system/building-plugins-and-modules/08-migrating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index 02cc705689..3e275f4157 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -156,7 +156,7 @@ export const kubernetesClustersSupplierExtensionPoint = }); ``` -Now we can use this extension point in the kubernetes backend plugin to register the ExtensionPoint for modules to use. +Now we can use this extension point in the kubernetes backend plugin to register the extension point for modules to use. ```ts import { kubernetesClustersSupplierExtensionPoint } from '@backstage/plugin-kubernetes-node'; From 0c149d1c689615ef8d38ddafed0634f8ca925427 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 18 Jan 2023 14:56:03 +0100 Subject: [PATCH 06/18] Update docs/backend-system/building-plugins-and-modules/08-migrating.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johan Haals Co-authored-by: Fredrik Adelöw Signed-off-by: Johan Haals --- .../building-plugins-and-modules/08-migrating.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index 3e275f4157..794253a412 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -179,7 +179,8 @@ export const kubernetesPlugin = createBackendPlugin({ id: 'kubernetes', register(env) { const extensionPoint = new ClusterSupplier(); - // We register the extensionPoint with the backend which allows modules to register their own ClusterSupplier. + // We register the extension point with the backend, which allows modules to + // register their own ClusterSupplier. env.registerExtensionPoint( kubernetesClustersSupplierExtensionPoint, extensionPoint, From 2fcb536dc08a7123b45eadcd969ffbbf86490603 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 18 Jan 2023 14:56:17 +0100 Subject: [PATCH 07/18] Update docs/backend-system/building-plugins-and-modules/08-migrating.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johan Haals Co-authored-by: Fredrik Adelöw Signed-off-by: Johan Haals --- .../backend-system/building-plugins-and-modules/08-migrating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index 794253a412..01187c2332 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -214,7 +214,7 @@ import { kubernetesClustersSupplierExtensionPoint } from '@backstage/plugin-kube export const kubernetesGKEClusterSupplier = createBackendModule({ pluginId: 'kubernetes', - moduleId: 'gce.supplier', + moduleId: 'gke.supplier', register(env) { env.registerInit({ deps: { From 38fffb5780ac3615eeaf854af5bb3cbef1f44f59 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 18 Jan 2023 14:56:31 +0100 Subject: [PATCH 08/18] Update docs/backend-system/building-plugins-and-modules/08-migrating.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johan Haals Co-authored-by: Fredrik Adelöw Signed-off-by: Johan Haals --- .../backend-system/building-plugins-and-modules/08-migrating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index 01187c2332..f63f48edf3 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -79,7 +79,7 @@ import { kubernetesPlugin } from '@backstage/plugin-kubernetes-backend'; backend.add(kubernetesPlugin); ``` -There's one thing missing that those sharp eyed readers might have noticed, the `clusterSupplier` option is missing from the original plugin. Let's add it and discuss the alternatives. +There's one thing missing that those sharp eyed readers might have noticed: the `clusterSupplier` option is missing from the original plugin. Let's add it and discuss the alternatives. One alternative is pass the `ClusterSupplier` in as options to the plugin which is quick and easy but not very flexible and hard to evolve without introducing breaking changes as it changes the public API for the plugin. Having complex types passed in directly to the plugin also clutters the backend setup code and makes it harder to read. From 0d14af7bedc313da44359bdedaf1599dc571b9be Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 18 Jan 2023 14:56:39 +0100 Subject: [PATCH 09/18] Update docs/backend-system/building-plugins-and-modules/08-migrating.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johan Haals Co-authored-by: Fredrik Adelöw Signed-off-by: Johan Haals --- .../backend-system/building-plugins-and-modules/08-migrating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index f63f48edf3..5f45d02ad3 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -161,7 +161,7 @@ Now we can use this extension point in the kubernetes backend plugin to register ```ts import { kubernetesClustersSupplierExtensionPoint } from '@backstage/plugin-kubernetes-node'; -// Our internal implementation of the extensionPoint which we do not need to export. +// Our internal implementation of the extension point, should not be exported. class ClusterSupplier implements KubernetesClustersSupplier { private clusterSuppliers: KubernetesClustersSupplier[] = []; From fc1e3897c3312040ef4a0c510deb3bc8812a2598 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 18 Jan 2023 14:56:50 +0100 Subject: [PATCH 10/18] Update docs/backend-system/building-plugins-and-modules/08-migrating.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johan Haals Co-authored-by: Fredrik Adelöw Signed-off-by: Johan Haals --- .../backend-system/building-plugins-and-modules/08-migrating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index 5f45d02ad3..0888924ac6 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -212,7 +212,7 @@ And that's it! Modules can now be built that add clusters into to the kubernetes ```ts import { kubernetesClustersSupplierExtensionPoint } from '@backstage/plugin-kubernetes-node'; -export const kubernetesGKEClusterSupplier = createBackendModule({ +export const kubernetesGkeClusterSupplier = createBackendModule({ pluginId: 'kubernetes', moduleId: 'gke.supplier', register(env) { From 6487d9b260bfba9087b84c3d384454426e114aba Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 18 Jan 2023 14:57:23 +0100 Subject: [PATCH 11/18] Update docs/backend-system/building-plugins-and-modules/08-migrating.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johan Haals Co-authored-by: Fredrik Adelöw Signed-off-by: Johan Haals --- .../backend-system/building-plugins-and-modules/08-migrating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index 0888924ac6..f05870a167 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -81,7 +81,7 @@ backend.add(kubernetesPlugin); There's one thing missing that those sharp eyed readers might have noticed: the `clusterSupplier` option is missing from the original plugin. Let's add it and discuss the alternatives. -One alternative is pass the `ClusterSupplier` in as options to the plugin which is quick and easy but not very flexible and hard to evolve without introducing breaking changes as it changes the public API for the plugin. Having complex types passed in directly to the plugin also clutters the backend setup code and makes it harder to read. +One alternative is to pass the `ClusterSupplier` in as options to the plugin, which is quick and easy but not very flexible, and also hard to evolve without introducing breaking changes as it changes the public API for the plugin. Having complex types passed in directly to the plugin also clutters the backend setup code and makes it harder to read. Options are primarily used for simple configuration values that are not complex types. In this case we want to allow users to register their own `ClusterSupplier` implementations to the plugin. This is where the new backend system's [ExtensionPoints](fixme.md) but let's look at doing this with options first. From aa854bed44bef69d0e4572a2b843f59928695fea Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 18 Jan 2023 14:57:41 +0100 Subject: [PATCH 12/18] Update docs/backend-system/building-plugins-and-modules/08-migrating.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johan Haals Co-authored-by: Fredrik Adelöw Signed-off-by: Johan Haals --- .../backend-system/building-plugins-and-modules/08-migrating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index f05870a167..0a201cc21c 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -83,7 +83,7 @@ There's one thing missing that those sharp eyed readers might have noticed: the One alternative is to pass the `ClusterSupplier` in as options to the plugin, which is quick and easy but not very flexible, and also hard to evolve without introducing breaking changes as it changes the public API for the plugin. Having complex types passed in directly to the plugin also clutters the backend setup code and makes it harder to read. -Options are primarily used for simple configuration values that are not complex types. In this case we want to allow users to register their own `ClusterSupplier` implementations to the plugin. This is where the new backend system's [ExtensionPoints](fixme.md) but let's look at doing this with options first. +Options are primarily used for simple configuration values that are not complex types. In this case we want to allow users to register their own `ClusterSupplier` implementations to the plugin. This is where the new backend system's [extension points](fixme.md) come in handy, but let's look at doing this with options first. ```ts /* omitted imports but they remain the same as above */ From 9be9ad859baeb52eda6e3a9c481d46bf62d9e764 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 18 Jan 2023 14:57:53 +0100 Subject: [PATCH 13/18] Update docs/backend-system/building-plugins-and-modules/08-migrating.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johan Haals Co-authored-by: Fredrik Adelöw Signed-off-by: Johan Haals --- .../backend-system/building-plugins-and-modules/08-migrating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index 0a201cc21c..55ace3746f 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -97,7 +97,7 @@ const kubernetesPlugin = createBackendPlugin((options: KubernetesOptions) => ({ register(env) { env.registerInit({ deps: { - /* omitted imports but they remain the same as above */ + /* omitted dependencies but they remain the same as above */ }, async init({ config, logger, catalogApi, discovery, http }) { const { router } = await KubernetesBuilder.createBuilder({ From 82146882a22bfa8a65178dac7ac91dd768242852 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 18 Jan 2023 14:58:15 +0100 Subject: [PATCH 14/18] Update docs/backend-system/building-plugins-and-modules/08-migrating.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johan Haals Co-authored-by: Fredrik Adelöw Signed-off-by: Johan Haals --- .../backend-system/building-plugins-and-modules/08-migrating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index 55ace3746f..fddd79e122 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -123,7 +123,7 @@ backend.add( ); ``` -Just to echo what was said above, this is not a very flexible solution and will for example be problematic to maintain backwards compatible if we start evolving the options to for example accept multiple suppliers or tweak the `ClusterSupplier` interface. +Just to echo what was said above, this is not a very flexible solution and will for example be problematic to keep backwards compatible if we start evolving the options to for example accept multiple suppliers or tweak the `ClusterSupplier` interface. The new [ExtensionPoints](fixme.md) API allows [Modules](fixme) to add function into the backend plugin itself, in this case an additional `ClusterSupplier` From e2c751d04dbd5495d9cb3f2bf6263ccda51692cc Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 18 Jan 2023 14:58:38 +0100 Subject: [PATCH 15/18] Update docs/backend-system/building-plugins-and-modules/08-migrating.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johan Haals Co-authored-by: Fredrik Adelöw Signed-off-by: Johan Haals --- .../backend-system/building-plugins-and-modules/08-migrating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index fddd79e122..0c4344f610 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -147,7 +147,7 @@ export interface KubernetesClusterSupplierExtensionPoint { } /** - * An extension point that allows other plugins to add catalog processors. + * An extension point that allows other plugins to add cluster suppliers. * @public */ export const kubernetesClustersSupplierExtensionPoint = From 313e441e9584fb5edd13d376d57be77ff1e1c8e9 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 18 Jan 2023 14:58:52 +0100 Subject: [PATCH 16/18] Update docs/backend-system/building-plugins-and-modules/08-migrating.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johan Haals Co-authored-by: Fredrik Adelöw Signed-off-by: Johan Haals --- .../backend-system/building-plugins-and-modules/08-migrating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index 0c4344f610..dfa6bb97de 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -125,7 +125,7 @@ backend.add( Just to echo what was said above, this is not a very flexible solution and will for example be problematic to keep backwards compatible if we start evolving the options to for example accept multiple suppliers or tweak the `ClusterSupplier` interface. -The new [ExtensionPoints](fixme.md) API allows [Modules](fixme) to add function into the backend plugin itself, in this case an additional `ClusterSupplier` +The new [extension points](fixme.md) API allows [modules](fixme) to add functionality into the backend plugin itself, in this case an additional `ClusterSupplier`. The kubernetes backend plugin only supports one `ClusterSupplier` at this time but let's look at how we could add support for multiple suppliers using extension points. This allows users to install several modules that add their own `ClusterSupplier` implementations to the plugin like this: From 8922d52ee6dfe08c1f772b6a83ee3243ac0588ca Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 18 Jan 2023 14:59:25 +0100 Subject: [PATCH 17/18] Update docs/backend-system/building-plugins-and-modules/08-migrating.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johan Haals Co-authored-by: Fredrik Adelöw Signed-off-by: Johan Haals --- .../backend-system/building-plugins-and-modules/08-migrating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index dfa6bb97de..1044f093c9 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -135,7 +135,7 @@ backend.add(GoogleContainerEngineModule()); backend.add(EKSModule()); ``` -Now let's look at how to implement this with extension points. First we need to define the extension point itself. As the ExtensionPoint will be used by other modules we need to export its common practice to export these from a shared package so that they can be imported by other modules and plugins. +Now let's look at how to implement this with extension points. First we need to define the extension point itself. As the extension point will be used by other modules, it's common practice to export these from a shared package so that they can be imported by other modules and plugins. We'll go ahead and create a `@backstage/plugin-kubernetes-node` package for this and from there we'll export the extension point. From 22b8eee8b74b8571e69bafbb0313a851f1648837 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 18 Jan 2023 15:18:44 +0100 Subject: [PATCH 18/18] tweak docs Signed-off-by: Johan Haals --- .../08-migrating.md | 57 ++++++++++--------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index 1044f093c9..ec003a6fec 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -83,7 +83,7 @@ There's one thing missing that those sharp eyed readers might have noticed: the One alternative is to pass the `ClusterSupplier` in as options to the plugin, which is quick and easy but not very flexible, and also hard to evolve without introducing breaking changes as it changes the public API for the plugin. Having complex types passed in directly to the plugin also clutters the backend setup code and makes it harder to read. -Options are primarily used for simple configuration values that are not complex types. In this case we want to allow users to register their own `ClusterSupplier` implementations to the plugin. This is where the new backend system's [extension points](fixme.md) come in handy, but let's look at doing this with options first. +Options are primarily used for simple configuration values that are not complex types. In this case we want to allow users to register their own `ClusterSupplier` implementations to the plugin. This is where the new backend system's [extension points](../architecture/05-extension-points.md) come in handy, but let's look at doing this with options first. ```ts /* omitted imports but they remain the same as above */ @@ -125,14 +125,14 @@ backend.add( Just to echo what was said above, this is not a very flexible solution and will for example be problematic to keep backwards compatible if we start evolving the options to for example accept multiple suppliers or tweak the `ClusterSupplier` interface. -The new [extension points](fixme.md) API allows [modules](fixme) to add functionality into the backend plugin itself, in this case an additional `ClusterSupplier`. +The new [extension points](../architecture/05-extension-points.md) API allows [modules](../architecture/06-modules.md) to add functionality into the backend plugin itself, in this case an additional `ClusterSupplier`. The kubernetes backend plugin only supports one `ClusterSupplier` at this time but let's look at how we could add support for multiple suppliers using extension points. This allows users to install several modules that add their own `ClusterSupplier` implementations to the plugin like this: ```ts backend.add(kubernetesPlugin()); -backend.add(GoogleContainerEngineModule()); -backend.add(EKSModule()); +backend.add(kubernetesGoogleContainerEngineClusterSupplier()); +backend.add(kubernetesElasticContainerEngine()); ``` Now let's look at how to implement this with extension points. First we need to define the extension point itself. As the extension point will be used by other modules, it's common practice to export these from a shared package so that they can be imported by other modules and plugins. @@ -159,19 +159,23 @@ export const kubernetesClustersSupplierExtensionPoint = Now we can use this extension point in the kubernetes backend plugin to register the extension point for modules to use. ```ts -import { kubernetesClustersSupplierExtensionPoint } from '@backstage/plugin-kubernetes-node'; +import { kubernetesClustersSupplierExtensionPoint, KubernetesClusterSupplierExtensionPoint } from '@backstage/plugin-kubernetes-node'; // Our internal implementation of the extension point, should not be exported. -class ClusterSupplier implements KubernetesClustersSupplier { - private clusterSuppliers: KubernetesClustersSupplier[] = []; +class ClusterSupplier implements KubernetesClusterSupplierExtensionPoint { + private clusterSuppliers: KubernetesClustersSupplier | undefined; - // This method is private and only used internally to retrieve the registered suppliers. - getClusterSuppliers(): KubernetesClustersSupplier[] { + // This method is private and only used internally to retrieve the registered supplier. + getClusterSupplier() { return this.clusterSuppliers; } addClusterSupplier(supplier: KubernetesClustersSupplier) { - this.clusterSuppliers.push(supplier); + // We can remove this check once the plugin support multiple suppliers. + if(this.clusterSuppliers) { + throw new Error('Multiple Kubernetes cluster suppliers is not supported at this time'); + } + this.clusterSuppliers = supplier; } } @@ -197,8 +201,8 @@ export const kubernetesPlugin = createBackendPlugin({ catalogApi, discovery, }) - // We pass in the all the registered suppliers to the builder. - .setClusterSuppliers(...extensionPoint.getClusterSuppliers()) + // We pass in the registered supplier from the extension point. + .setClusterSupplier(extensionPoint.getClusterSupplier()) .build(); http.use(router); }, @@ -212,18 +216,19 @@ And that's it! Modules can now be built that add clusters into to the kubernetes ```ts import { kubernetesClustersSupplierExtensionPoint } from '@backstage/plugin-kubernetes-node'; -export const kubernetesGkeClusterSupplier = createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'gke.supplier', - register(env) { - env.registerInit({ - deps: { - supplier: kubernetesClustersSupplierExtensionPoint, - }, - async init({ supplier }) { - supplier.addClusterSupplier(new GoogleContainerEngineSupplier()); - }, - }); - }, -}); +export const kubernetesGoogleContainerEngineClusterSupplier = + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'gke.supplier', + register(env) { + env.registerInit({ + deps: { + supplier: kubernetesClustersSupplierExtensionPoint, + }, + async init({ supplier }) { + supplier.addClusterSupplier(new GoogleContainerEngineSupplier()); + }, + }); + }, + }); ```