diff --git a/plugins/catalog-backend-module-gcp/README.md b/plugins/catalog-backend-module-gcp/README.md index 87c6ff5f6c..0f9ed67576 100644 --- a/plugins/catalog-backend-module-gcp/README.md +++ b/plugins/catalog-backend-module-gcp/README.md @@ -62,4 +62,11 @@ catalog: "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/..." } + # Optional: Authentication provider for Kubernetes clusters + # Defaults to 'google' if not specified + # Common values: 'google', 'googleServiceAccount' + authProvider: googleServiceAccount + # Optional: Owner of the discovered GKE clusters + # Defaults to 'unknown' if not specified + owner: platform-team ``` diff --git a/plugins/catalog-backend-module-gcp/config.d.ts b/plugins/catalog-backend-module-gcp/config.d.ts index 2ad369ef89..4cf1815980 100644 --- a/plugins/catalog-backend-module-gcp/config.d.ts +++ b/plugins/catalog-backend-module-gcp/config.d.ts @@ -44,6 +44,16 @@ export interface Config { * @visibility secret */ googleServiceAccountCredentials?: string; + /** + * (Optional) Authentication provider to use for Kubernetes clusters + * Defaults to 'google' for backward compatibility + */ + authProvider?: string; + /** + * (Optional) Owner of the discovered clusters + * Defaults to 'unknown' if not specified + */ + owner?: string; }; }; }; diff --git a/plugins/catalog-backend-module-gcp/src/providers/GkeEntityProvider.test.ts b/plugins/catalog-backend-module-gcp/src/providers/GkeEntityProvider.test.ts index da34e46110..dcd7d5c05e 100644 --- a/plugins/catalog-backend-module-gcp/src/providers/GkeEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gcp/src/providers/GkeEntityProvider.test.ts @@ -196,6 +196,54 @@ describe('GkeEntityProvider', () => { }, ); + it('should use configured values for authProvider and owner', async () => { + const customGkeEntityProvider = GkeEntityProvider.fromConfigWithClient({ + logger: logger as any, + config: new ConfigReader({ + catalog: { + providers: { + gcp: { + gke: { + parents: ['projects/parent1/locations/-'], + authProvider: 'googleServiceAccount', + owner: 'sre', + schedule: { + frequency: { + minutes: 3, + }, + timeout: { + minutes: 3, + }, + }, + }, + }, + }, + }, + }), + scheduler: schedulerMock, + clusterManagerClient: clusterManagerClientMock as any, + }); + + clusterManagerClientMock.listClusters.mockImplementation(() => [ + { + clusters: [ + { + name: 'some-cluster', + endpoint: '127.0.0.1', + location: 'some-location', + selfLink: 'https://127.0.0.1/some-link', + masterAuth: { + clusterCaCertificate: 'abcdefg', + }, + }, + ], + }, + ]); + await customGkeEntityProvider.connect(connectionMock); + await customGkeEntityProvider.refresh(); + expect(connectionMock.applyMutation).toMatchSnapshot(); + }); + it('should log GKE API errors', async () => { clusterManagerClientMock.listClusters.mockRejectedValue( new Error('some-error'), @@ -365,5 +413,32 @@ describe('GkeEntityProvider', () => { expect(MockedClusterManagerClient).toHaveBeenCalledWith(); }); + + it('should read authProvider and owner from config', () => { + const provider = GkeEntityProvider.fromConfig({ + logger: logger as any, + config: new ConfigReader({ + catalog: { + providers: { + gcp: { + gke: { + parents: ['projects/test-project/locations/-'], + schedule: { + frequency: { minutes: 30 }, + timeout: { minutes: 3 }, + }, + authProvider: 'googleServiceAccount', + owner: 'platform-team', + }, + }, + }, + }, + }), + scheduler: schedulerMock, + }); + + expect(provider).toBeDefined(); + expect(MockedClusterManagerClient).toHaveBeenCalledWith(); + }); }); }); diff --git a/plugins/catalog-backend-module-gcp/src/providers/GkeEntityProvider.ts b/plugins/catalog-backend-module-gcp/src/providers/GkeEntityProvider.ts index 58acf19870..a60dd717a5 100644 --- a/plugins/catalog-backend-module-gcp/src/providers/GkeEntityProvider.ts +++ b/plugins/catalog-backend-module-gcp/src/providers/GkeEntityProvider.ts @@ -47,6 +47,8 @@ export class GkeEntityProvider implements EntityProvider { private readonly logger: LoggerService; private readonly scheduleFn: () => Promise; private readonly gkeParents: string[]; + private readonly gkeAuthProvider: string | undefined; + private readonly gkeOwner: string | undefined; private readonly clusterManagerClient: container.v1.ClusterManagerClient; private connection?: EntityProviderConnection; @@ -54,11 +56,15 @@ export class GkeEntityProvider implements EntityProvider { logger: LoggerService, taskRunner: SchedulerServiceTaskRunner, gkeParents: string[], + gkeAuthProvider: string | undefined, + gkeOwner: string | undefined, clusterManagerClient: container.v1.ClusterManagerClient, ) { this.logger = logger; this.scheduleFn = this.createScheduleFn(taskRunner); this.gkeParents = gkeParents; + this.gkeAuthProvider = gkeAuthProvider; + this.gkeOwner = gkeOwner; this.clusterManagerClient = clusterManagerClient; } @@ -125,6 +131,8 @@ export class GkeEntityProvider implements EntityProvider { logger, scheduler.createScheduledTaskRunner(schedule), gkeProviderConfig.getStringArray('parents'), + gkeProviderConfig.getOptionalString('authProvider'), + gkeProviderConfig.getOptionalString('owner'), clusterManagerClient, ); } @@ -179,7 +187,8 @@ export class GkeEntityProvider implements EntityProvider { [ANNOTATION_KUBERNETES_API_SERVER]: `https://${cluster.endpoint}`, [ANNOTATION_KUBERNETES_API_SERVER_CA]: cluster.masterAuth?.clusterCaCertificate || '', - [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'google', + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: + this.gkeAuthProvider || 'google', [ANNOTATION_KUBERNETES_DASHBOARD_APP]: 'gke', [ANNOTATION_LOCATION]: location, [ANNOTATION_ORIGIN_LOCATION]: location, @@ -194,7 +203,7 @@ export class GkeEntityProvider implements EntityProvider { }, spec: { type: 'kubernetes-cluster', - owner: 'unknown', + owner: this.gkeOwner || 'unknown', }, }, }; diff --git a/plugins/catalog-backend-module-gcp/src/providers/__snapshots__/GkeEntityProvider.test.ts.snap b/plugins/catalog-backend-module-gcp/src/providers/__snapshots__/GkeEntityProvider.test.ts.snap index d20efb9c8d..c903bcd192 100644 --- a/plugins/catalog-backend-module-gcp/src/providers/__snapshots__/GkeEntityProvider.test.ts.snap +++ b/plugins/catalog-backend-module-gcp/src/providers/__snapshots__/GkeEntityProvider.test.ts.snap @@ -67,3 +67,47 @@ exports[`GkeEntityProvider should return clusters as Resources 1`] = ` ], } `; + +exports[`GkeEntityProvider should use configured values for authProvider and owner 1`] = ` +[MockFunction] { + "calls": [ + [ + { + "entities": [ + { + "entity": { + "apiVersion": "backstage.io/v1alpha1", + "kind": "Resource", + "metadata": { + "annotations": { + "backstage.io/managed-by-location": "gcp-gke:some-location", + "backstage.io/managed-by-origin-location": "gcp-gke:some-location", + "kubernetes.io/api-server": "https://127.0.0.1", + "kubernetes.io/api-server-certificate-authority": "abcdefg", + "kubernetes.io/auth-provider": "googleServiceAccount", + "kubernetes.io/dashboard-app": "gke", + "kubernetes.io/dashboard-parameters": "{"projectId":"parent1","region":"some-location","clusterName":"some-cluster"}", + }, + "name": "some-cluster", + "namespace": "default", + }, + "spec": { + "owner": "sre", + "type": "kubernetes-cluster", + }, + }, + "locationKey": "gcp-gke:some-location", + }, + ], + "type": "full", + }, + ], + ], + "results": [ + { + "type": "return", + "value": undefined, + }, + ], +} +`;