diff --git a/docs/features/kubernetes/configuration.md b/docs/features/kubernetes/configuration.md index b78021c8f1..3009813961 100644 --- a/docs/features/kubernetes/configuration.md +++ b/docs/features/kubernetes/configuration.md @@ -57,12 +57,17 @@ This is an array used to determine where to retrieve cluster configuration from. Valid cluster locator methods are: +- [`catalog`](#catalog) - [`config`](#config) - [`gke`](#gke) - [custom `KubernetesClustersSupplier`](#custom-kubernetesclusterssupplier) #### `config` +This cluster locator method will read cluster information from the catalog. + +#### `config` + This cluster locator method will read cluster information from your app-config (see below). diff --git a/packages/backend/src/plugins/kubernetes.ts b/packages/backend/src/plugins/kubernetes.ts index 8023d549ff..376569a959 100644 --- a/packages/backend/src/plugins/kubernetes.ts +++ b/packages/backend/src/plugins/kubernetes.ts @@ -24,6 +24,7 @@ export default async function createPlugin( const { router } = await KubernetesBuilder.createBuilder({ logger: env.logger, config: env.config, + discovery: env.discovery, }).build(); return router; } diff --git a/plugins/kubernetes-backend/src/cluster-locator/CatalogClusterLocator.test.ts b/plugins/kubernetes-backend/src/cluster-locator/CatalogClusterLocator.test.ts new file mode 100644 index 0000000000..2a2432f858 --- /dev/null +++ b/plugins/kubernetes-backend/src/cluster-locator/CatalogClusterLocator.test.ts @@ -0,0 +1,56 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import '@backstage/backend-common'; +import { CatalogClusterLocator } from './CatalogClusterLocator'; +import { CatalogApi } from '@backstage/catalog-client'; + +describe('CatalogClusterLocator', () => { + it('empty clusters returns empty cluster details', async () => { + const mockCatalogApi = { + getEntityByRef: jest.fn(), + getEntities: async () => ({ + items: [ + { + apiVersion: 'version', + kind: 'User', + metadata: { + annotations: { + 'kubernetes.io/api-server': 'https://apiserver.com', + 'kubernetes.io/api-server-certificate-authority': 'caData', + 'kubernetes.io/auth-provider': 'aws', + }, + name: 'owned', + namespace: 'default', + }, + }, + ], + }), + } as Partial as CatalogApi; + + const sut = CatalogClusterLocator.fromConfig(mockCatalogApi); + + const result = await sut.getClusters(); + + expect(result).toHaveLength(1); + expect(result[0]).toMatchObject({ + name: 'owned', + url: 'https://apiserver.com', + caData: 'caData', + authProvider: 'aws', + }); + }); +}); diff --git a/plugins/kubernetes-backend/src/cluster-locator/CatalogClusterLocator.ts b/plugins/kubernetes-backend/src/cluster-locator/CatalogClusterLocator.ts index 1e474f637a..c762dc6fb6 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/CatalogClusterLocator.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/CatalogClusterLocator.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Backstage Authors + * Copyright 2022 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,21 +15,17 @@ */ import { ClusterDetails, KubernetesClustersSupplier } from '../types/types'; -import { - CATALOG_FILTER_EXISTS, - CatalogClient, -} from '@backstage/catalog-client'; -import { DiscoveryApi } from '@backstage/core-plugin-api'; +import { CATALOG_FILTER_EXISTS, CatalogApi } from '@backstage/catalog-client'; export class CatalogClusterLocator implements KubernetesClustersSupplier { - private catalogClient: CatalogClient; + private catalogClient: CatalogApi; - constructor(catalogClient: CatalogClient) { + constructor(catalogClient: CatalogApi) { this.catalogClient = catalogClient; } - static fromConfig(discoveryApi: DiscoveryApi): CatalogClusterLocator { - return new CatalogClusterLocator(new CatalogClient({ discoveryApi })); + static fromConfig(catalogApi: CatalogApi): CatalogClusterLocator { + return new CatalogClusterLocator(catalogApi); } async getClusters(): Promise { @@ -55,13 +51,13 @@ export class CatalogClusterLocator implements KubernetesClustersSupplier { name: entity.metadata.name, // @ts-ignore filtered out by catalog-client query. url: entity.metadata.annotations['kubernetes.io/api-server'], - // @ts-ignore filtered out by catalog-client query. caData: + // @ts-ignore filtered out by catalog-client query. entity.metadata.annotations[ 'kubernetes.io/api-server-certificate-authority' ], - // @ts-ignore filtered out by catalog-client query. authProvider: + // @ts-ignore filtered out by catalog-client query. entity.metadata.annotations['kubernetes.io/auth-provider'], }; diff --git a/plugins/kubernetes-backend/src/cluster-locator/index.ts b/plugins/kubernetes-backend/src/cluster-locator/index.ts index 53aeb44f8b..46f24f780b 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/index.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/index.ts @@ -19,6 +19,9 @@ import { Duration } from 'luxon'; import { ClusterDetails, KubernetesClustersSupplier } from '../types/types'; import { ConfigClusterLocator } from './ConfigClusterLocator'; import { GkeClusterLocator } from './GkeClusterLocator'; +import { CatalogClusterLocator } from './CatalogClusterLocator'; +import { PluginEndpointDiscovery } from '@backstage/backend-common/dist'; +import { CatalogClient } from '@backstage/catalog-client'; class CombinedClustersSupplier implements KubernetesClustersSupplier { constructor(readonly clusterSuppliers: KubernetesClustersSupplier[]) {} @@ -38,13 +41,17 @@ class CombinedClustersSupplier implements KubernetesClustersSupplier { export const getCombinedClusterSupplier = ( rootConfig: Config, + discovery: PluginEndpointDiscovery, refreshInterval: Duration | undefined = undefined, ): KubernetesClustersSupplier => { + const catalogClient = new CatalogClient({ discoveryApi: discovery }); const clusterSuppliers = rootConfig .getConfigArray('kubernetes.clusterLocatorMethods') .map(clusterLocatorMethod => { const type = clusterLocatorMethod.getString('type'); switch (type) { + case 'catalog': + return CatalogClusterLocator.fromConfig(catalogClient); case 'config': return ConfigClusterLocator.fromConfig(clusterLocatorMethod); case 'gke': diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts index 18c3fdc931..bd585c3f62 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts @@ -37,10 +37,12 @@ import { KubernetesFanOutHandler, } from './KubernetesFanOutHandler'; import { KubernetesClientBasedFetcher } from './KubernetesFetcher'; +import { PluginEndpointDiscovery } from '@backstage/backend-common/dist'; export interface KubernetesEnvironment { logger: Logger; config: Config; + discovery: PluginEndpointDiscovery; } /** @@ -171,7 +173,11 @@ export class KubernetesBuilder { refreshInterval: Duration, ): KubernetesClustersSupplier { const config = this.env.config; - return getCombinedClusterSupplier(config, refreshInterval); + return getCombinedClusterSupplier( + config, + this.env.discovery, + refreshInterval, + ); } protected buildObjectsProvider(