Add Kubernetes Router extension point, add fetcher to custom objects provider

Signed-off-by: Ilya Savich <isavich@box.com>
This commit is contained in:
Ilya Savich
2025-10-07 18:06:10 +02:00
parent c16d83c70c
commit 7f9846fd55
6 changed files with 133 additions and 4 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-kubernetes-backend': minor
'@backstage/plugin-kubernetes-node': minor
---
Add possibility to extends Kubernetes REST API. Add fetcher to parameters for custom objects provider
+27
View File
@@ -36,6 +36,9 @@ import {
kubernetesObjectsProviderExtensionPoint,
type KubernetesObjectsProviderExtensionPoint,
KubernetesObjectsProviderFactory,
KubernetesRouterExtensionPoint,
kubernetesRouterExtensionPoint,
KubernetesRouterFactory,
type KubernetesServiceLocator,
kubernetesServiceLocatorExtensionPoint,
type KubernetesServiceLocatorExtensionPoint,
@@ -157,6 +160,24 @@ class AuthStrategy implements KubernetesAuthStrategyExtensionPoint {
}
}
class CustomRouter implements KubernetesRouterExtensionPoint {
private router: KubernetesRouterFactory | undefined;
getRouter() {
return this.router;
}
addRouter(router: KubernetesRouterFactory) {
if (this.router) {
throw new Error(
'Multiple Kubernetes routers is not supported at this time',
);
}
this.router = router;
}
}
/**
* This is the backend plugin that provides the Kubernetes integration.
* @public
@@ -169,6 +190,7 @@ export const kubernetesPlugin = createBackendPlugin({
const extPointAuthStrategy = new AuthStrategy();
const extPointFetcher = new Fetcher();
const extPointServiceLocator = new ServiceLocator();
const extPointRouter = new CustomRouter()
env.registerExtensionPoint(
kubernetesObjectsProviderExtensionPoint,
@@ -190,6 +212,10 @@ export const kubernetesPlugin = createBackendPlugin({
kubernetesServiceLocatorExtensionPoint,
extPointServiceLocator,
);
env.registerExtensionPoint(
kubernetesRouterExtensionPoint,
extPointRouter,
);
env.registerInit({
deps: {
@@ -247,6 +273,7 @@ export const kubernetesPlugin = createBackendPlugin({
clusterSupplier,
serviceLocator,
objectsProvider,
customRouter: extPointRouter.getRouter(),
});
http.use(await router.getRouter());
@@ -209,6 +209,7 @@ export class KubernetesInitializer {
customResources,
objectTypesToFetch,
}),
fetcher,
clusterSupplier,
serviceLocator,
customResources,
@@ -28,6 +28,7 @@ import {
KubernetesFetcher,
KubernetesServiceLocator,
KubernetesCredential,
kubernetesRouterExtensionPoint,
} from '@backstage/plugin-kubernetes-node';
import {
HEADER_KUBERNETES_CLUSTER,
@@ -809,4 +810,39 @@ metadata:
'Unsupported kubernetes.serviceLocatorMethod "unsupported"',
);
});
it('custom router', async () => {
const { server } = await startTestBackend({
features: [
minimalValidConfigService,
import('@backstage/plugin-kubernetes-backend'),
createBackendModule({
pluginId: 'kubernetes',
moduleId: 'testRouter',
register(env) {
env.registerInit({
deps: { extension: kubernetesRouterExtensionPoint },
async init({ extension }) {
extension.addRouter(({ getDefault }) => {
const router = getDefault();
router.get('/test', (_req, res) => {
res.json({ status: 'ok' });
});
return router;
});
},
});
},
}),
],
});
app = server;
const response = await request(app).get('/api/kubernetes/test');
expect(response.body).toEqual({ status: 'ok' });
expect(response.status).toEqual(200);
});
});
@@ -40,7 +40,7 @@ import {
AuthMetadata,
KubernetesClustersSupplier,
KubernetesFetcher,
KubernetesObjectsProvider,
KubernetesObjectsProvider, KubernetesRouterFactory,
KubernetesServiceLocator,
} from '@backstage/plugin-kubernetes-node';
import { addResourceRoutesToRouter } from '../routes/resourcesRoutes';
@@ -62,6 +62,7 @@ export interface KubernetesEnvironment {
clusterSupplier: KubernetesClustersSupplier;
serviceLocator: KubernetesServiceLocator;
objectsProvider: KubernetesObjectsProvider;
customRouter?: KubernetesRouterFactory;
}
export class KubernetesRouter {
@@ -86,6 +87,7 @@ export class KubernetesRouter {
catalog,
discovery,
httpAuth,
customRouter,
} = this.env;
logger.info('Initializing Kubernetes backend');
@@ -108,7 +110,23 @@ export class KubernetesRouter {
authStrategyMap,
);
return this.buildRouter(
return customRouter?.({
getDefault: () => this.buildDefaultRouter(
objectsProvider,
clusterSupplier,
catalog,
proxy,
permissions,
httpAuth,
authStrategyMap,
),
objectsProvider,
clusterSupplier,
catalog,
permissions,
httpAuth,
authStrategyMap,
}) ?? this.buildDefaultRouter(
objectsProvider,
clusterSupplier,
catalog,
@@ -138,7 +156,7 @@ export class KubernetesRouter {
});
}
private buildRouter(
private buildDefaultRouter(
objectsProvider: KubernetesObjectsProvider,
clusterSupplier: KubernetesClustersSupplier,
catalog: CatalogService,
+42 -1
View File
@@ -13,7 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createExtensionPoint } from '@backstage/backend-plugin-api';
import {
createExtensionPoint,
HttpAuthService,
} from '@backstage/backend-plugin-api';
import {
AuthenticationStrategy,
CustomResource,
@@ -23,6 +26,9 @@ import {
KubernetesObjectsProvider,
KubernetesServiceLocator,
} from '@backstage/plugin-kubernetes-node';
import type express from 'express';
import type { CatalogService } from '@backstage/plugin-catalog-node';
import type { PermissionEvaluator } from '@backstage/plugin-permission-common';
/**
* A factory function for creating a KubernetesObjectsProvider.
@@ -33,6 +39,7 @@ export type KubernetesObjectsProviderFactory = (opts: {
getDefault: () => Promise<KubernetesObjectsProvider>;
clusterSupplier: KubernetesClustersSupplier;
serviceLocator: KubernetesServiceLocator;
fetcher: KubernetesFetcher;
customResources: CustomResource[];
objectTypesToFetch?: ObjectToFetch[];
authStrategy: AuthenticationStrategy;
@@ -168,3 +175,37 @@ export const kubernetesServiceLocatorExtensionPoint =
createExtensionPoint<KubernetesServiceLocatorExtensionPoint>({
id: 'kubernetes.service-locator',
});
/**
* A factory function for creating a kubernetes router.
*
* @public
*/
export type KubernetesRouterFactory = (opts: {
getDefault: () => express.Router;
objectsProvider: KubernetesObjectsProvider;
clusterSupplier: KubernetesClustersSupplier;
catalog: CatalogService;
permissions: PermissionEvaluator;
httpAuth: HttpAuthService;
authStrategyMap: { [key: string]: AuthenticationStrategy };
}) => express.Router;
/**
* The interface for {@link kubernetesRouterExtensionPoint}.
*
* @public
*/
export interface KubernetesRouterExtensionPoint {
addRouter(router: KubernetesRouterFactory): void;
}
/**
* An extension point the exposes the ability to configure a kubernetes service locator.
*
* @public
*/
export const kubernetesRouterExtensionPoint =
createExtensionPoint<KubernetesRouterExtensionPoint>({
id: 'kubernetes.router',
});