@backstage/plugin-kubernetes-backend 0.4.7 → 0.4.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/dist/index.cjs.js +15 -14
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +16 -10
- package/package.json +19 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# @backstage/plugin-kubernetes-backend
|
|
2
2
|
|
|
3
|
+
## 0.4.10
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 64acf65c03: Allow missing kubernetes config in development env
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @backstage/backend-common@0.11.0
|
|
10
|
+
- @backstage/catalog-model@0.11.0
|
|
11
|
+
- @backstage/plugin-kubernetes-common@0.2.5
|
|
12
|
+
|
|
13
|
+
## 0.4.9
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Fix for the previous release with missing type declarations.
|
|
18
|
+
- Updated dependencies
|
|
19
|
+
- @backstage/backend-common@0.10.9
|
|
20
|
+
- @backstage/catalog-model@0.10.1
|
|
21
|
+
- @backstage/config@0.1.15
|
|
22
|
+
- @backstage/errors@0.2.2
|
|
23
|
+
- @backstage/plugin-kubernetes-common@0.2.4
|
|
24
|
+
|
|
25
|
+
## 0.4.8
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- c77c5c7eb6: Added `backstage.role` to `package.json`
|
|
30
|
+
- 0107c9aa08: chore(deps): bump `helmet` from 4.4.1 to 5.0.2
|
|
31
|
+
- fb09a59a3f: Fixed a potential issue in AWS token encoding, where they might not always be properly converted to URL-safe base64.
|
|
32
|
+
- Updated dependencies
|
|
33
|
+
- @backstage/backend-common@0.10.8
|
|
34
|
+
- @backstage/errors@0.2.1
|
|
35
|
+
- @backstage/catalog-model@0.10.0
|
|
36
|
+
- @backstage/config@0.1.14
|
|
37
|
+
- @backstage/plugin-kubernetes-common@0.2.3
|
|
38
|
+
|
|
3
39
|
## 0.4.7
|
|
4
40
|
|
|
5
41
|
### Patch Changes
|
package/dist/index.cjs.js
CHANGED
|
@@ -239,12 +239,6 @@ class ServiceAccountKubernetesAuthTranslator {
|
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
-
const base64 = (str) => Buffer.from(str.toString(), "binary").toString("base64");
|
|
243
|
-
const prepend = (prep) => (str) => prep + str;
|
|
244
|
-
const replace = (search, substitution) => (str) => str.replace(search, substitution);
|
|
245
|
-
const pipe = (fns) => (thing) => fns.reduce((val, fn) => fn(val), thing);
|
|
246
|
-
const removePadding = replace(/=+$/, "");
|
|
247
|
-
const makeUrlSafe = pipe([replace("+", "-"), replace("/", "_")]);
|
|
248
242
|
class AwsIamKubernetesAuthTranslator {
|
|
249
243
|
constructor() {
|
|
250
244
|
this.awsGetCredentials = async () => {
|
|
@@ -308,14 +302,11 @@ class AwsIamKubernetesAuthTranslator {
|
|
|
308
302
|
},
|
|
309
303
|
signQuery: true
|
|
310
304
|
};
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
makeUrlSafe,
|
|
317
|
-
prepend("k8s-aws-v1.")
|
|
318
|
-
])(signedRequest);
|
|
305
|
+
const signed = aws4.sign(request, credentials);
|
|
306
|
+
const url = `https://${signed.host}${signed.path}`;
|
|
307
|
+
const base64Url = Buffer.from(url, "binary").toString("base64");
|
|
308
|
+
const urlSafeBase64Url = base64Url.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
309
|
+
return `k8s-aws-v1.${urlSafeBase64Url}`;
|
|
319
310
|
}
|
|
320
311
|
async decorateClusterDetailsWithAuth(clusterDetails) {
|
|
321
312
|
const clusterDetailsWithAuthToken = Object.assign({}, clusterDetails);
|
|
@@ -596,7 +587,17 @@ class KubernetesBuilder {
|
|
|
596
587
|
async build() {
|
|
597
588
|
var _a, _b, _c, _d;
|
|
598
589
|
const logger = this.env.logger;
|
|
590
|
+
const config = this.env.config;
|
|
599
591
|
logger.info("Initializing Kubernetes backend");
|
|
592
|
+
if (!config.has("kubernetes")) {
|
|
593
|
+
if (process.env.NODE_ENV !== "development") {
|
|
594
|
+
throw new Error("Kubernetes configuration is missing");
|
|
595
|
+
}
|
|
596
|
+
logger.warn("Failed to initialize kubernetes backend: kubernetes config is missing");
|
|
597
|
+
return {
|
|
598
|
+
router: Router__default["default"]()
|
|
599
|
+
};
|
|
600
|
+
}
|
|
600
601
|
const customResources = this.buildCustomResources();
|
|
601
602
|
const fetcher = (_a = this.fetcher) != null ? _a : this.buildFetcher();
|
|
602
603
|
const clusterSupplier = (_b = this.clusterSupplier) != null ? _b : this.buildClusterSupplier();
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../src/cluster-locator/ConfigClusterLocator.ts","../src/cluster-locator/GkeClusterLocator.ts","../src/cluster-locator/index.ts","../src/service-locator/MultiTenantServiceLocator.ts","../src/service/KubernetesClientProvider.ts","../src/kubernetes-auth-translator/GoogleKubernetesAuthTranslator.ts","../src/kubernetes-auth-translator/ServiceAccountKubernetesAuthTranslator.ts","../src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.ts","../src/kubernetes-auth-translator/GoogleServiceAccountAuthProvider.ts","../src/kubernetes-auth-translator/KubernetesAuthTranslatorGenerator.ts","../src/service/KubernetesFanOutHandler.ts","../src/service/KubernetesFetcher.ts","../src/service/KubernetesBuilder.ts","../src/service/router.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { ClusterDetails, KubernetesClustersSupplier } from '../types/types';\n\nexport class ConfigClusterLocator implements KubernetesClustersSupplier {\n private readonly clusterDetails: ClusterDetails[];\n\n constructor(clusterDetails: ClusterDetails[]) {\n this.clusterDetails = clusterDetails;\n }\n\n static fromConfig(config: Config): ConfigClusterLocator {\n // TODO: Add validation that authProvider is required and serviceAccountToken\n // is required if authProvider is serviceAccount\n return new ConfigClusterLocator(\n config.getConfigArray('clusters').map(c => {\n const authProvider = c.getString('authProvider');\n const clusterDetails: ClusterDetails = {\n name: c.getString('name'),\n url: c.getString('url'),\n serviceAccountToken: c.getOptionalString('serviceAccountToken'),\n skipTLSVerify: c.getOptionalBoolean('skipTLSVerify') ?? false,\n skipMetricsLookup: c.getOptionalBoolean('skipMetricsLookup') ?? false,\n caData: c.getOptionalString('caData'),\n authProvider: authProvider,\n };\n const dashboardUrl = c.getOptionalString('dashboardUrl');\n if (dashboardUrl) {\n clusterDetails.dashboardUrl = dashboardUrl;\n }\n const dashboardApp = c.getOptionalString('dashboardApp');\n if (dashboardApp) {\n clusterDetails.dashboardApp = dashboardApp;\n }\n if (c.has('dashboardParameters')) {\n clusterDetails.dashboardParameters = c.get('dashboardParameters');\n }\n\n switch (authProvider) {\n case 'google': {\n return clusterDetails;\n }\n case 'aws': {\n const assumeRole = c.getOptionalString('assumeRole');\n const externalId = c.getOptionalString('externalId');\n\n return { assumeRole, externalId, ...clusterDetails };\n }\n case 'serviceAccount': {\n return clusterDetails;\n }\n case 'googleServiceAccount': {\n return clusterDetails;\n }\n default: {\n throw new Error(\n `authProvider \"${authProvider}\" has no config associated with it`,\n );\n }\n }\n }),\n );\n }\n\n async getClusters(): Promise<ClusterDetails[]> {\n return this.clusterDetails;\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { ForwardedError } from '@backstage/errors';\nimport * as container from '@google-cloud/container';\nimport { GKEClusterDetails, KubernetesClustersSupplier } from '../types/types';\n\ntype GkeClusterLocatorOptions = {\n projectId: string;\n region?: string;\n skipTLSVerify?: boolean;\n skipMetricsLookup?: boolean;\n exposeDashboard?: boolean;\n};\n\nexport class GkeClusterLocator implements KubernetesClustersSupplier {\n constructor(\n private readonly options: GkeClusterLocatorOptions,\n private readonly client: container.v1.ClusterManagerClient,\n ) {}\n\n static fromConfigWithClient(\n config: Config,\n client: container.v1.ClusterManagerClient,\n ): GkeClusterLocator {\n const options = {\n projectId: config.getString('projectId'),\n region: config.getOptionalString('region') ?? '-',\n skipTLSVerify: config.getOptionalBoolean('skipTLSVerify') ?? false,\n skipMetricsLookup:\n config.getOptionalBoolean('skipMetricsLookup') ?? false,\n exposeDashboard: config.getOptionalBoolean('exposeDashboard') ?? false,\n };\n return new GkeClusterLocator(options, client);\n }\n\n static fromConfig(config: Config): GkeClusterLocator {\n return GkeClusterLocator.fromConfigWithClient(\n config,\n new container.v1.ClusterManagerClient(),\n );\n }\n\n // TODO pass caData into the object\n async getClusters(): Promise<GKEClusterDetails[]> {\n const {\n projectId,\n region,\n skipTLSVerify,\n skipMetricsLookup,\n exposeDashboard,\n } = this.options;\n const request = {\n parent: `projects/${projectId}/locations/${region}`,\n };\n\n try {\n const [response] = await this.client.listClusters(request);\n return (response.clusters ?? []).map(r => ({\n // TODO filter out clusters which don't have name or endpoint\n name: r.name ?? 'unknown',\n url: `https://${r.endpoint ?? ''}`,\n authProvider: 'google',\n skipTLSVerify,\n skipMetricsLookup,\n ...(exposeDashboard\n ? {\n dashboardApp: 'gke',\n dashboardParameters: {\n projectId,\n region,\n clusterName: r.name,\n },\n }\n : {}),\n }));\n } catch (e) {\n throw new ForwardedError(\n `There was an error retrieving clusters from GKE for projectId=${projectId} region=${region}`,\n e,\n );\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { ClusterDetails } from '../types/types';\nimport { ConfigClusterLocator } from './ConfigClusterLocator';\nimport { GkeClusterLocator } from './GkeClusterLocator';\n\nexport const getCombinedClusterDetails = async (\n rootConfig: Config,\n): Promise<ClusterDetails[]> => {\n return Promise.all(\n rootConfig\n .getConfigArray('kubernetes.clusterLocatorMethods')\n .map(clusterLocatorMethod => {\n const type = clusterLocatorMethod.getString('type');\n switch (type) {\n case 'config':\n return ConfigClusterLocator.fromConfig(\n clusterLocatorMethod,\n ).getClusters();\n case 'gke':\n return GkeClusterLocator.fromConfig(\n clusterLocatorMethod,\n ).getClusters();\n default:\n throw new Error(\n `Unsupported kubernetes.clusterLocatorMethods: \"${type}\"`,\n );\n }\n }),\n )\n .then(res => {\n return res.flat();\n })\n .catch(e => {\n throw e;\n });\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ClusterDetails, KubernetesServiceLocator } from '../types/types';\n\n// This locator assumes that every service is located on every cluster\n// Therefore it will always return all clusters provided\nexport class MultiTenantServiceLocator implements KubernetesServiceLocator {\n private readonly clusterDetails: ClusterDetails[];\n\n constructor(clusterDetails: ClusterDetails[]) {\n this.clusterDetails = clusterDetails;\n }\n\n // As this implementation always returns all clusters serviceId is ignored here\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n async getClustersByServiceId(_serviceId: string): Promise<ClusterDetails[]> {\n return this.clusterDetails;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n CoreV1Api,\n KubeConfig,\n Metrics,\n CustomObjectsApi,\n} from '@kubernetes/client-node';\nimport { ClusterDetails } from '../types/types';\n\nexport class KubernetesClientProvider {\n // visible for testing\n getKubeConfig(clusterDetails: ClusterDetails) {\n const cluster = {\n name: clusterDetails.name,\n server: clusterDetails.url,\n skipTLSVerify: clusterDetails.skipTLSVerify,\n caData: clusterDetails.caData,\n };\n\n // TODO configure\n const user = {\n name: 'backstage',\n token: clusterDetails.serviceAccountToken,\n };\n\n const context = {\n name: `${clusterDetails.name}`,\n user: user.name,\n cluster: cluster.name,\n };\n\n const kc = new KubeConfig();\n if (clusterDetails.serviceAccountToken) {\n kc.loadFromOptions({\n clusters: [cluster],\n users: [user],\n contexts: [context],\n currentContext: context.name,\n });\n } else {\n kc.loadFromDefault();\n }\n\n return kc;\n }\n\n getCoreClientByClusterDetails(clusterDetails: ClusterDetails) {\n const kc = this.getKubeConfig(clusterDetails);\n\n return kc.makeApiClient(CoreV1Api);\n }\n\n getMetricsClient(clusterDetails: ClusterDetails) {\n const kc = this.getKubeConfig(clusterDetails);\n\n return new Metrics(kc);\n }\n\n getCustomObjectsClient(clusterDetails: ClusterDetails) {\n const kc = this.getKubeConfig(clusterDetails);\n\n return kc.makeApiClient(CustomObjectsApi);\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { KubernetesAuthTranslator } from './types';\nimport { GKEClusterDetails } from '../types/types';\nimport { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common';\n\nexport class GoogleKubernetesAuthTranslator\n implements KubernetesAuthTranslator\n{\n async decorateClusterDetailsWithAuth(\n clusterDetails: GKEClusterDetails,\n requestBody: KubernetesRequestBody,\n ): Promise<GKEClusterDetails> {\n const clusterDetailsWithAuthToken: GKEClusterDetails = Object.assign(\n {},\n clusterDetails,\n );\n const authToken: string | undefined = requestBody.auth?.google;\n\n if (authToken) {\n clusterDetailsWithAuthToken.serviceAccountToken = authToken;\n } else {\n throw new Error(\n 'Google token not found under auth.google in request body',\n );\n }\n return clusterDetailsWithAuthToken;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { KubernetesAuthTranslator } from './types';\nimport { ServiceAccountClusterDetails } from '../types/types';\nimport { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common';\n\nexport class ServiceAccountKubernetesAuthTranslator\n implements KubernetesAuthTranslator\n{\n async decorateClusterDetailsWithAuth(\n clusterDetails: ServiceAccountClusterDetails,\n _requestBody: KubernetesRequestBody,\n ): Promise<ServiceAccountClusterDetails> {\n return clusterDetails;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport AWS, { Credentials } from 'aws-sdk';\nimport { sign } from 'aws4';\nimport { AWSClusterDetails } from '../types/types';\nimport { KubernetesAuthTranslator } from './types';\n\nconst base64 = (str: string) =>\n Buffer.from(str.toString(), 'binary').toString('base64');\nconst prepend = (prep: string) => (str: string) => prep + str;\nconst replace =\n (search: string | RegExp, substitution: string) => (str: string) =>\n str.replace(search, substitution);\nconst pipe =\n (fns: ReadonlyArray<any>) =>\n (thing: string): string =>\n fns.reduce((val, fn) => fn(val), thing);\nconst removePadding = replace(/=+$/, '');\nconst makeUrlSafe = pipe([replace('+', '-'), replace('/', '_')]);\n\ntype SigningCreds = {\n accessKeyId: string | undefined;\n secretAccessKey: string | undefined;\n sessionToken: string | undefined;\n};\n\nexport class AwsIamKubernetesAuthTranslator\n implements KubernetesAuthTranslator\n{\n validCredentials(creds: SigningCreds): boolean {\n return (creds?.accessKeyId && creds?.secretAccessKey) as unknown as boolean;\n }\n\n awsGetCredentials = async (): Promise<Credentials> => {\n return new Promise((resolve, reject) => {\n AWS.config.getCredentials(err => {\n if (err) {\n return reject(err);\n }\n\n return resolve(AWS.config.credentials as Credentials);\n });\n });\n };\n\n async getCredentials(\n assumeRole?: string,\n externalId?: string,\n ): Promise<SigningCreds> {\n return new Promise<SigningCreds>(async (resolve, reject) => {\n const awsCreds = await this.awsGetCredentials();\n\n if (!(awsCreds instanceof Credentials))\n return reject(Error('No AWS credentials found.'));\n\n let creds: SigningCreds = {\n accessKeyId: awsCreds.accessKeyId,\n secretAccessKey: awsCreds.secretAccessKey,\n sessionToken: awsCreds.sessionToken,\n };\n\n if (!this.validCredentials(creds))\n return reject(Error('Invalid AWS credentials found.'));\n if (!assumeRole) return resolve(creds);\n\n try {\n const params: AWS.STS.Types.AssumeRoleRequest = {\n RoleArn: assumeRole,\n RoleSessionName: 'backstage-login',\n };\n if (externalId) params.ExternalId = externalId;\n\n const assumedRole = await new AWS.STS().assumeRole(params).promise();\n\n if (!assumedRole.Credentials) {\n throw new Error(`No credentials returned for role ${assumeRole}`);\n }\n\n creds = {\n accessKeyId: assumedRole.Credentials.AccessKeyId,\n secretAccessKey: assumedRole.Credentials.SecretAccessKey,\n sessionToken: assumedRole.Credentials.SessionToken,\n };\n } catch (e) {\n console.warn(`There was an error assuming the role: ${e}`);\n return reject(Error(`Unable to assume role: ${e}`));\n }\n return resolve(creds);\n });\n }\n async getBearerToken(\n clusterName: string,\n assumeRole?: string,\n externalId?: string,\n ): Promise<string> {\n const credentials = await this.getCredentials(assumeRole, externalId);\n\n const request = {\n host: `sts.amazonaws.com`,\n path: `/?Action=GetCallerIdentity&Version=2011-06-15&X-Amz-Expires=60`,\n headers: {\n 'x-k8s-aws-id': clusterName,\n },\n signQuery: true,\n };\n\n const signedRequest = sign(request, credentials);\n\n return pipe([\n (signed: any) => `https://${signed.host}${signed.path}`,\n base64,\n removePadding,\n makeUrlSafe,\n prepend('k8s-aws-v1.'),\n ])(signedRequest);\n }\n\n async decorateClusterDetailsWithAuth(\n clusterDetails: AWSClusterDetails,\n ): Promise<AWSClusterDetails> {\n const clusterDetailsWithAuthToken: AWSClusterDetails = Object.assign(\n {},\n clusterDetails,\n );\n\n clusterDetailsWithAuthToken.serviceAccountToken = await this.getBearerToken(\n clusterDetails.name,\n clusterDetails.assumeRole,\n clusterDetails.externalId,\n );\n return clusterDetailsWithAuthToken;\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { KubernetesAuthTranslator } from './types';\nimport { GKEClusterDetails } from '../types/types';\nimport * as container from '@google-cloud/container';\n\nexport class GoogleServiceAccountAuthTranslator\n implements KubernetesAuthTranslator\n{\n async decorateClusterDetailsWithAuth(\n clusterDetails: GKEClusterDetails,\n ): Promise<GKEClusterDetails> {\n const clusterDetailsWithAuthToken: GKEClusterDetails = Object.assign(\n {},\n clusterDetails,\n );\n const client = new container.v1.ClusterManagerClient();\n const accessToken = await client.auth.getAccessToken();\n\n if (accessToken) {\n clusterDetailsWithAuthToken.serviceAccountToken = accessToken;\n } else {\n throw new Error(\n 'Unable to obtain access token for the current Google Application Default Credentials',\n );\n }\n return clusterDetailsWithAuthToken;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { KubernetesAuthTranslator } from './types';\nimport { GoogleKubernetesAuthTranslator } from './GoogleKubernetesAuthTranslator';\nimport { ServiceAccountKubernetesAuthTranslator } from './ServiceAccountKubernetesAuthTranslator';\nimport { AwsIamKubernetesAuthTranslator } from './AwsIamKubernetesAuthTranslator';\nimport { GoogleServiceAccountAuthTranslator } from './GoogleServiceAccountAuthProvider';\n\nexport class KubernetesAuthTranslatorGenerator {\n static getKubernetesAuthTranslatorInstance(\n authProvider: string,\n ): KubernetesAuthTranslator {\n switch (authProvider) {\n case 'google': {\n return new GoogleKubernetesAuthTranslator();\n }\n case 'aws': {\n return new AwsIamKubernetesAuthTranslator();\n }\n case 'serviceAccount': {\n return new ServiceAccountKubernetesAuthTranslator();\n }\n case 'googleServiceAccount': {\n return new GoogleServiceAccountAuthTranslator();\n }\n default: {\n throw new Error(\n `authProvider \"${authProvider}\" has no KubernetesAuthTranslator associated with it`,\n );\n }\n }\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Logger } from 'winston';\nimport {\n ClusterDetails,\n CustomResource,\n KubernetesFetcher,\n KubernetesObjectsProviderOptions,\n KubernetesServiceLocator,\n ObjectsByEntityRequest,\n ObjectToFetch,\n} from '../types/types';\nimport { KubernetesAuthTranslator } from '../kubernetes-auth-translator/types';\nimport { KubernetesAuthTranslatorGenerator } from '../kubernetes-auth-translator/KubernetesAuthTranslatorGenerator';\nimport {\n ClientContainerStatus,\n ClientCurrentResourceUsage,\n ClientPodStatus,\n ClusterObjects,\n FetchResponse,\n ObjectsByEntityResponse,\n PodFetchResponse,\n} from '@backstage/plugin-kubernetes-common';\nimport {\n ContainerStatus,\n CurrentResourceUsage,\n PodStatus,\n} from '@kubernetes/client-node';\n\nexport const DEFAULT_OBJECTS: ObjectToFetch[] = [\n {\n group: '',\n apiVersion: 'v1',\n plural: 'pods',\n objectType: 'pods',\n },\n {\n group: '',\n apiVersion: 'v1',\n plural: 'services',\n objectType: 'services',\n },\n {\n group: '',\n apiVersion: 'v1',\n plural: 'configmaps',\n objectType: 'configmaps',\n },\n {\n group: 'apps',\n apiVersion: 'v1',\n plural: 'deployments',\n objectType: 'deployments',\n },\n {\n group: 'apps',\n apiVersion: 'v1',\n plural: 'replicasets',\n objectType: 'replicasets',\n },\n {\n group: 'autoscaling',\n apiVersion: 'v1',\n plural: 'horizontalpodautoscalers',\n objectType: 'horizontalpodautoscalers',\n },\n {\n group: 'batch',\n apiVersion: 'v1',\n plural: 'jobs',\n objectType: 'jobs',\n },\n {\n group: 'batch',\n apiVersion: 'v1',\n plural: 'cronjobs',\n objectType: 'cronjobs',\n },\n {\n group: 'networking.k8s.io',\n apiVersion: 'v1',\n plural: 'ingresses',\n objectType: 'ingresses',\n },\n];\n\nexport interface KubernetesFanOutHandlerOptions\n extends KubernetesObjectsProviderOptions {}\n\nexport interface KubernetesRequestBody extends ObjectsByEntityRequest {}\n\nconst isPodFetchResponse = (fr: FetchResponse): fr is PodFetchResponse =>\n fr.type === 'pods';\nconst isString = (str: string | undefined): str is string => str !== undefined;\n\nconst numberOrBigIntToNumberOrString = (\n value: number | BigInt,\n): number | string => {\n return typeof value === 'bigint' ? value.toString() : (value as number);\n};\n\nconst toClientSafeResource = (\n current: CurrentResourceUsage,\n): ClientCurrentResourceUsage => {\n return {\n currentUsage: numberOrBigIntToNumberOrString(current.CurrentUsage),\n requestTotal: numberOrBigIntToNumberOrString(current.RequestTotal),\n limitTotal: numberOrBigIntToNumberOrString(current.LimitTotal),\n };\n};\n\nconst toClientSafeContainer = (\n container: ContainerStatus,\n): ClientContainerStatus => {\n return {\n container: container.Container,\n cpuUsage: toClientSafeResource(container.CPUUsage),\n memoryUsage: toClientSafeResource(container.MemoryUsage),\n };\n};\n\nconst toClientSafePodMetrics = (\n podMetrics: PodStatus[][],\n): ClientPodStatus[] => {\n return podMetrics.flat().map((pd: PodStatus): ClientPodStatus => {\n return {\n pod: pd.Pod,\n memory: toClientSafeResource(pd.Memory),\n cpu: toClientSafeResource(pd.CPU),\n containers: pd.Containers.map(toClientSafeContainer),\n };\n });\n};\n\nexport class KubernetesFanOutHandler {\n private readonly logger: Logger;\n private readonly fetcher: KubernetesFetcher;\n private readonly serviceLocator: KubernetesServiceLocator;\n private readonly customResources: CustomResource[];\n private readonly objectTypesToFetch: Set<ObjectToFetch>;\n\n constructor({\n logger,\n fetcher,\n serviceLocator,\n customResources,\n objectTypesToFetch = DEFAULT_OBJECTS,\n }: KubernetesFanOutHandlerOptions) {\n this.logger = logger;\n this.fetcher = fetcher;\n this.serviceLocator = serviceLocator;\n this.customResources = customResources;\n this.objectTypesToFetch = new Set(objectTypesToFetch);\n }\n\n async getKubernetesObjectsByEntity(\n requestBody: KubernetesRequestBody,\n ): Promise<ObjectsByEntityResponse> {\n const entityName =\n requestBody.entity?.metadata?.annotations?.[\n 'backstage.io/kubernetes-id'\n ] || requestBody.entity?.metadata?.name;\n\n const clusterDetails: ClusterDetails[] =\n await this.serviceLocator.getClustersByServiceId(entityName);\n\n // Execute all of these async actions simultaneously/without blocking sequentially as no common object is modified by them\n const promises: Promise<ClusterDetails>[] = clusterDetails.map(cd => {\n const kubernetesAuthTranslator: KubernetesAuthTranslator =\n KubernetesAuthTranslatorGenerator.getKubernetesAuthTranslatorInstance(\n cd.authProvider,\n );\n return kubernetesAuthTranslator.decorateClusterDetailsWithAuth(\n cd,\n requestBody,\n );\n });\n const clusterDetailsDecoratedForAuth: ClusterDetails[] = await Promise.all(\n promises,\n );\n\n this.logger.info(\n `entity.metadata.name=${entityName} clusterDetails=[${clusterDetailsDecoratedForAuth\n .map(c => c.name)\n .join(', ')}]`,\n );\n\n const labelSelector: string =\n requestBody.entity?.metadata?.annotations?.[\n 'backstage.io/kubernetes-label-selector'\n ] || `backstage.io/kubernetes-id=${entityName}`;\n\n return Promise.all(\n clusterDetailsDecoratedForAuth.map(clusterDetailsItem => {\n return this.fetcher\n .fetchObjectsForService({\n serviceId: entityName,\n clusterDetails: clusterDetailsItem,\n objectTypesToFetch: this.objectTypesToFetch,\n labelSelector,\n customResources: this.customResources,\n })\n .then(result => {\n if (clusterDetailsItem.skipMetricsLookup) {\n return Promise.all([\n Promise.resolve(result),\n Promise.resolve([]),\n ]);\n }\n // TODO refactor, extract as method\n const namespaces: Set<string> = new Set<string>(\n result.responses\n .filter(isPodFetchResponse)\n .flatMap(r => r.resources)\n .map(p => p.metadata?.namespace)\n .filter(isString),\n );\n\n const podMetrics = Array.from(namespaces).map(ns =>\n this.fetcher.fetchPodMetricsByNamespace(clusterDetailsItem, ns),\n );\n\n return Promise.all([\n Promise.resolve(result),\n Promise.all(podMetrics),\n ]);\n })\n .then(([result, metrics]) => {\n const objects: ClusterObjects = {\n cluster: {\n name: clusterDetailsItem.name,\n },\n podMetrics: toClientSafePodMetrics(metrics),\n resources: result.responses,\n errors: result.errors,\n };\n if (clusterDetailsItem.dashboardUrl) {\n objects.cluster.dashboardUrl = clusterDetailsItem.dashboardUrl;\n }\n if (clusterDetailsItem.dashboardApp) {\n objects.cluster.dashboardApp = clusterDetailsItem.dashboardApp;\n }\n if (clusterDetailsItem.dashboardParameters) {\n objects.cluster.dashboardParameters =\n clusterDetailsItem.dashboardParameters;\n }\n return objects;\n });\n }),\n ).then(r => ({\n items: r.filter(\n item =>\n (item.errors !== undefined && item.errors.length >= 1) ||\n (item.resources !== undefined &&\n item.resources.length >= 1 &&\n item.resources.some(fr => fr.resources.length >= 1)),\n ),\n }));\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CoreV1Api, topPods } from '@kubernetes/client-node';\nimport lodash, { Dictionary } from 'lodash';\nimport { Logger } from 'winston';\nimport {\n ClusterDetails,\n FetchResponseWrapper,\n KubernetesFetcher,\n KubernetesObjectTypes,\n ObjectFetchParams,\n ObjectToFetch,\n} from '../types/types';\nimport {\n FetchResponse,\n KubernetesFetchError,\n KubernetesErrorTypes,\n} from '@backstage/plugin-kubernetes-common';\nimport { KubernetesClientProvider } from './KubernetesClientProvider';\nimport { PodStatus } from '@kubernetes/client-node/dist/top';\n\nexport interface Clients {\n core: CoreV1Api;\n}\n\nexport interface KubernetesClientBasedFetcherOptions {\n kubernetesClientProvider: KubernetesClientProvider;\n logger: Logger;\n}\n\ntype FetchResult = FetchResponse | KubernetesFetchError;\n\nconst isError = (fr: FetchResult): fr is KubernetesFetchError =>\n fr.hasOwnProperty('errorType');\n\nfunction fetchResultsToResponseWrapper(\n results: FetchResult[],\n): FetchResponseWrapper {\n const groupBy: Dictionary<FetchResult[]> = lodash.groupBy(results, value => {\n return isError(value) ? 'errors' : 'responses';\n });\n\n return {\n errors: groupBy.errors ?? [],\n responses: groupBy.responses ?? [],\n } as FetchResponseWrapper; // TODO would be nice to get rid of this 'as'\n}\n\nconst statusCodeToErrorType = (statusCode: number): KubernetesErrorTypes => {\n switch (statusCode) {\n case 400:\n return 'BAD_REQUEST';\n case 401:\n return 'UNAUTHORIZED_ERROR';\n case 500:\n return 'SYSTEM_ERROR';\n default:\n return 'UNKNOWN_ERROR';\n }\n};\n\nexport class KubernetesClientBasedFetcher implements KubernetesFetcher {\n private readonly kubernetesClientProvider: KubernetesClientProvider;\n private readonly logger: Logger;\n\n constructor({\n kubernetesClientProvider,\n logger,\n }: KubernetesClientBasedFetcherOptions) {\n this.kubernetesClientProvider = kubernetesClientProvider;\n this.logger = logger;\n }\n\n fetchObjectsForService(\n params: ObjectFetchParams,\n ): Promise<FetchResponseWrapper> {\n const fetchResults = Array.from(params.objectTypesToFetch)\n .concat(params.customResources)\n .map(toFetch => {\n return this.fetchResource(\n params.clusterDetails,\n toFetch,\n params.labelSelector ||\n `backstage.io/kubernetes-id=${params.serviceId}`,\n toFetch.objectType,\n ).catch(this.captureKubernetesErrorsRethrowOthers.bind(this));\n });\n\n return Promise.all(fetchResults).then(fetchResultsToResponseWrapper);\n }\n\n fetchPodMetricsByNamespace(\n clusterDetails: ClusterDetails,\n namespace: string,\n ): Promise<PodStatus[]> {\n const metricsClient =\n this.kubernetesClientProvider.getMetricsClient(clusterDetails);\n const coreApi =\n this.kubernetesClientProvider.getCoreClientByClusterDetails(\n clusterDetails,\n );\n\n return topPods(coreApi, metricsClient, namespace);\n }\n\n private captureKubernetesErrorsRethrowOthers(e: any): KubernetesFetchError {\n if (e.response && e.response.statusCode) {\n this.logger.warn(\n `statusCode=${e.response.statusCode} for resource ${\n e.response.request.uri.pathname\n } body=[${JSON.stringify(e.response.body)}]`,\n );\n return {\n errorType: statusCodeToErrorType(e.response.statusCode),\n statusCode: e.response.statusCode,\n resourcePath: e.response.request.uri.pathname,\n };\n }\n throw e;\n }\n\n private fetchResource(\n clusterDetails: ClusterDetails,\n resource: ObjectToFetch,\n labelSelector: string,\n objectType: KubernetesObjectTypes,\n ): Promise<FetchResponse> {\n const customObjects =\n this.kubernetesClientProvider.getCustomObjectsClient(clusterDetails);\n\n customObjects.addInterceptor((requestOptions: any) => {\n requestOptions.uri = requestOptions.uri.replace('/apis//v1/', '/api/v1/');\n });\n\n return customObjects\n .listClusterCustomObject(\n resource.group,\n resource.apiVersion,\n resource.plural,\n '',\n false,\n '',\n '',\n labelSelector,\n )\n .then(r => {\n return {\n type: objectType,\n resources: (r.body as any).items,\n };\n });\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Config } from '@backstage/config';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { Logger } from 'winston';\nimport { getCombinedClusterDetails } from '../cluster-locator';\nimport { MultiTenantServiceLocator } from '../service-locator/MultiTenantServiceLocator';\nimport {\n ClusterDetails,\n KubernetesObjectTypes,\n ServiceLocatorMethod,\n CustomResource,\n KubernetesObjectsProvider,\n ObjectsByEntityRequest,\n KubernetesClustersSupplier,\n KubernetesFetcher,\n KubernetesServiceLocator,\n KubernetesObjectsProviderOptions,\n} from '../types/types';\nimport { KubernetesClientProvider } from './KubernetesClientProvider';\nimport {\n DEFAULT_OBJECTS,\n KubernetesFanOutHandler,\n} from './KubernetesFanOutHandler';\nimport { KubernetesClientBasedFetcher } from './KubernetesFetcher';\n\nexport interface KubernetesEnvironment {\n logger: Logger;\n config: Config;\n}\n\nexport class KubernetesBuilder {\n private clusterSupplier?: KubernetesClustersSupplier;\n private objectsProvider?: KubernetesObjectsProvider;\n private fetcher?: KubernetesFetcher;\n private serviceLocator?: KubernetesServiceLocator;\n\n static createBuilder(env: KubernetesEnvironment) {\n return new KubernetesBuilder(env);\n }\n\n constructor(protected readonly env: KubernetesEnvironment) {}\n\n public async build() {\n const logger = this.env.logger;\n\n logger.info('Initializing Kubernetes backend');\n\n const customResources = this.buildCustomResources();\n\n const fetcher = this.fetcher ?? this.buildFetcher();\n\n const clusterSupplier = this.clusterSupplier ?? this.buildClusterSupplier();\n\n const clusterDetails = await this.fetchClusterDetails(clusterSupplier);\n\n const serviceLocator =\n this.serviceLocator ??\n this.buildServiceLocator(this.getServiceLocatorMethod(), clusterDetails);\n\n const objectsProvider =\n this.objectsProvider ??\n this.buildObjectsProvider({\n logger,\n fetcher,\n serviceLocator,\n customResources,\n objectTypesToFetch: this.getObjectTypesToFetch(),\n });\n\n const router = this.buildRouter(objectsProvider, clusterDetails);\n\n return {\n clusterDetails,\n clusterSupplier,\n customResources,\n fetcher,\n objectsProvider,\n router,\n serviceLocator,\n };\n }\n\n public setClusterSupplier(clusterSupplier?: KubernetesClustersSupplier) {\n this.clusterSupplier = clusterSupplier;\n return this;\n }\n\n public setObjectsProvider(objectsProvider?: KubernetesObjectsProvider) {\n this.objectsProvider = objectsProvider;\n return this;\n }\n\n public setFetcher(fetcher?: KubernetesFetcher) {\n this.fetcher = fetcher;\n return this;\n }\n\n public setServiceLocator(serviceLocator?: KubernetesServiceLocator) {\n this.serviceLocator = serviceLocator;\n return this;\n }\n\n protected buildCustomResources() {\n const customResources: CustomResource[] = (\n this.env.config.getOptionalConfigArray('kubernetes.customResources') ?? []\n ).map(\n c =>\n ({\n group: c.getString('group'),\n apiVersion: c.getString('apiVersion'),\n plural: c.getString('plural'),\n objectType: 'customresources',\n } as CustomResource),\n );\n\n this.env.logger.info(\n `action=LoadingCustomResources numOfCustomResources=${customResources.length}`,\n );\n return customResources;\n }\n\n protected buildClusterSupplier(): KubernetesClustersSupplier {\n const config = this.env.config;\n return {\n getClusters() {\n return getCombinedClusterDetails(config);\n },\n };\n }\n\n protected buildObjectsProvider(\n options: KubernetesObjectsProviderOptions,\n ): KubernetesObjectsProvider {\n return new KubernetesFanOutHandler(options);\n }\n\n protected buildFetcher(): KubernetesFetcher {\n return new KubernetesClientBasedFetcher({\n kubernetesClientProvider: new KubernetesClientProvider(),\n logger: this.env.logger,\n });\n }\n\n protected buildServiceLocator(\n method: ServiceLocatorMethod,\n clusterDetails: ClusterDetails[],\n ): KubernetesServiceLocator {\n switch (method) {\n case 'multiTenant':\n return this.buildMultiTenantServiceLocator(clusterDetails);\n case 'http':\n return this.buildHttpServiceLocator(clusterDetails);\n default:\n throw new Error(\n `Unsupported kubernetes.clusterLocatorMethod \"${method}\"`,\n );\n }\n }\n\n protected buildMultiTenantServiceLocator(\n clusterDetails: ClusterDetails[],\n ): KubernetesServiceLocator {\n return new MultiTenantServiceLocator(clusterDetails);\n }\n\n protected buildHttpServiceLocator(\n _clusterDetails: ClusterDetails[],\n ): KubernetesServiceLocator {\n throw new Error('not implemented');\n }\n\n protected buildRouter(\n objectsProvider: KubernetesObjectsProvider,\n clusterDetails: ClusterDetails[],\n ): express.Router {\n const logger = this.env.logger;\n const router = Router();\n router.use(express.json());\n\n router.post('/services/:serviceId', async (req, res) => {\n const serviceId = req.params.serviceId;\n const requestBody: ObjectsByEntityRequest = req.body;\n try {\n const response = await objectsProvider.getKubernetesObjectsByEntity(\n requestBody,\n );\n res.json(response);\n } catch (e) {\n logger.error(\n `action=retrieveObjectsByServiceId service=${serviceId}, error=${e}`,\n );\n res.status(500).json({ error: e.message });\n }\n });\n\n router.get('/clusters', async (_, res) => {\n res.json({\n items: clusterDetails.map(cd => ({\n name: cd.name,\n dashboardUrl: cd.dashboardUrl,\n authProvider: cd.authProvider,\n })),\n });\n });\n return router;\n }\n\n protected async fetchClusterDetails(\n clusterSupplier: KubernetesClustersSupplier,\n ) {\n const clusterDetails = await clusterSupplier.getClusters();\n\n this.env.logger.info(\n `action=loadClusterDetails numOfClustersLoaded=${clusterDetails.length}`,\n );\n\n return clusterDetails;\n }\n\n protected getServiceLocatorMethod() {\n return this.env.config.getString(\n 'kubernetes.serviceLocatorMethod.type',\n ) as ServiceLocatorMethod;\n }\n\n protected getObjectTypesToFetch() {\n const objectTypesToFetchStrings = this.env.config.getOptionalStringArray(\n 'kubernetes.objectTypes',\n ) as KubernetesObjectTypes[];\n\n const apiVersionOverrides = this.env.config.getOptionalConfig(\n 'kubernetes.apiVersionOverrides',\n );\n\n let objectTypesToFetch;\n\n if (objectTypesToFetchStrings) {\n objectTypesToFetch = DEFAULT_OBJECTS.filter(obj =>\n objectTypesToFetchStrings.includes(obj.objectType),\n );\n }\n\n if (apiVersionOverrides) {\n objectTypesToFetch = objectTypesToFetch ?? DEFAULT_OBJECTS;\n\n for (const obj of objectTypesToFetch) {\n if (apiVersionOverrides.has(obj.objectType)) {\n obj.apiVersion = apiVersionOverrides.getString(obj.objectType);\n }\n }\n }\n\n return objectTypesToFetch;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { Logger } from 'winston';\nimport { KubernetesClustersSupplier } from '../types/types';\nimport express from 'express';\nimport { KubernetesBuilder } from './KubernetesBuilder';\n\nexport interface RouterOptions {\n logger: Logger;\n config: Config;\n clusterSupplier?: KubernetesClustersSupplier;\n}\n\n/**\n * creates and configure a new router for handling the kubernetes backend APIs\n * @param options - specifies the options required by this plugin\n * @returns a new router\n * @deprecated Please use the new KubernetesBuilder instead like this\n * ```\n * import { KubernetesBuilder } from '@backstage/plugin-kubernetes-backend';\n * const { router } = await KubernetesBuilder.createBuilder({\n * logger,\n * config,\n * }).build();\n * ```\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { router } = await KubernetesBuilder.createBuilder(options)\n .setClusterSupplier(options.clusterSupplier)\n .build();\n return router;\n}\n"],"names":["container","ForwardedError","KubeConfig","CoreV1Api","Metrics","CustomObjectsApi","AWS","Credentials","sign","lodash","topPods","Router","express"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../src/cluster-locator/ConfigClusterLocator.ts","../src/cluster-locator/GkeClusterLocator.ts","../src/cluster-locator/index.ts","../src/service-locator/MultiTenantServiceLocator.ts","../src/service/KubernetesClientProvider.ts","../src/kubernetes-auth-translator/GoogleKubernetesAuthTranslator.ts","../src/kubernetes-auth-translator/ServiceAccountKubernetesAuthTranslator.ts","../src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.ts","../src/kubernetes-auth-translator/GoogleServiceAccountAuthProvider.ts","../src/kubernetes-auth-translator/KubernetesAuthTranslatorGenerator.ts","../src/service/KubernetesFanOutHandler.ts","../src/service/KubernetesFetcher.ts","../src/service/KubernetesBuilder.ts","../src/service/router.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { ClusterDetails, KubernetesClustersSupplier } from '../types/types';\n\nexport class ConfigClusterLocator implements KubernetesClustersSupplier {\n private readonly clusterDetails: ClusterDetails[];\n\n constructor(clusterDetails: ClusterDetails[]) {\n this.clusterDetails = clusterDetails;\n }\n\n static fromConfig(config: Config): ConfigClusterLocator {\n // TODO: Add validation that authProvider is required and serviceAccountToken\n // is required if authProvider is serviceAccount\n return new ConfigClusterLocator(\n config.getConfigArray('clusters').map(c => {\n const authProvider = c.getString('authProvider');\n const clusterDetails: ClusterDetails = {\n name: c.getString('name'),\n url: c.getString('url'),\n serviceAccountToken: c.getOptionalString('serviceAccountToken'),\n skipTLSVerify: c.getOptionalBoolean('skipTLSVerify') ?? false,\n skipMetricsLookup: c.getOptionalBoolean('skipMetricsLookup') ?? false,\n caData: c.getOptionalString('caData'),\n authProvider: authProvider,\n };\n const dashboardUrl = c.getOptionalString('dashboardUrl');\n if (dashboardUrl) {\n clusterDetails.dashboardUrl = dashboardUrl;\n }\n const dashboardApp = c.getOptionalString('dashboardApp');\n if (dashboardApp) {\n clusterDetails.dashboardApp = dashboardApp;\n }\n if (c.has('dashboardParameters')) {\n clusterDetails.dashboardParameters = c.get('dashboardParameters');\n }\n\n switch (authProvider) {\n case 'google': {\n return clusterDetails;\n }\n case 'aws': {\n const assumeRole = c.getOptionalString('assumeRole');\n const externalId = c.getOptionalString('externalId');\n\n return { assumeRole, externalId, ...clusterDetails };\n }\n case 'serviceAccount': {\n return clusterDetails;\n }\n case 'googleServiceAccount': {\n return clusterDetails;\n }\n default: {\n throw new Error(\n `authProvider \"${authProvider}\" has no config associated with it`,\n );\n }\n }\n }),\n );\n }\n\n async getClusters(): Promise<ClusterDetails[]> {\n return this.clusterDetails;\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { ForwardedError } from '@backstage/errors';\nimport * as container from '@google-cloud/container';\nimport { GKEClusterDetails, KubernetesClustersSupplier } from '../types/types';\n\ntype GkeClusterLocatorOptions = {\n projectId: string;\n region?: string;\n skipTLSVerify?: boolean;\n skipMetricsLookup?: boolean;\n exposeDashboard?: boolean;\n};\n\nexport class GkeClusterLocator implements KubernetesClustersSupplier {\n constructor(\n private readonly options: GkeClusterLocatorOptions,\n private readonly client: container.v1.ClusterManagerClient,\n ) {}\n\n static fromConfigWithClient(\n config: Config,\n client: container.v1.ClusterManagerClient,\n ): GkeClusterLocator {\n const options = {\n projectId: config.getString('projectId'),\n region: config.getOptionalString('region') ?? '-',\n skipTLSVerify: config.getOptionalBoolean('skipTLSVerify') ?? false,\n skipMetricsLookup:\n config.getOptionalBoolean('skipMetricsLookup') ?? false,\n exposeDashboard: config.getOptionalBoolean('exposeDashboard') ?? false,\n };\n return new GkeClusterLocator(options, client);\n }\n\n static fromConfig(config: Config): GkeClusterLocator {\n return GkeClusterLocator.fromConfigWithClient(\n config,\n new container.v1.ClusterManagerClient(),\n );\n }\n\n // TODO pass caData into the object\n async getClusters(): Promise<GKEClusterDetails[]> {\n const {\n projectId,\n region,\n skipTLSVerify,\n skipMetricsLookup,\n exposeDashboard,\n } = this.options;\n const request = {\n parent: `projects/${projectId}/locations/${region}`,\n };\n\n try {\n const [response] = await this.client.listClusters(request);\n return (response.clusters ?? []).map(r => ({\n // TODO filter out clusters which don't have name or endpoint\n name: r.name ?? 'unknown',\n url: `https://${r.endpoint ?? ''}`,\n authProvider: 'google',\n skipTLSVerify,\n skipMetricsLookup,\n ...(exposeDashboard\n ? {\n dashboardApp: 'gke',\n dashboardParameters: {\n projectId,\n region,\n clusterName: r.name,\n },\n }\n : {}),\n }));\n } catch (e) {\n throw new ForwardedError(\n `There was an error retrieving clusters from GKE for projectId=${projectId} region=${region}`,\n e,\n );\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { ClusterDetails } from '../types/types';\nimport { ConfigClusterLocator } from './ConfigClusterLocator';\nimport { GkeClusterLocator } from './GkeClusterLocator';\n\nexport const getCombinedClusterDetails = async (\n rootConfig: Config,\n): Promise<ClusterDetails[]> => {\n return Promise.all(\n rootConfig\n .getConfigArray('kubernetes.clusterLocatorMethods')\n .map(clusterLocatorMethod => {\n const type = clusterLocatorMethod.getString('type');\n switch (type) {\n case 'config':\n return ConfigClusterLocator.fromConfig(\n clusterLocatorMethod,\n ).getClusters();\n case 'gke':\n return GkeClusterLocator.fromConfig(\n clusterLocatorMethod,\n ).getClusters();\n default:\n throw new Error(\n `Unsupported kubernetes.clusterLocatorMethods: \"${type}\"`,\n );\n }\n }),\n )\n .then(res => {\n return res.flat();\n })\n .catch(e => {\n throw e;\n });\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ClusterDetails, KubernetesServiceLocator } from '../types/types';\n\n// This locator assumes that every service is located on every cluster\n// Therefore it will always return all clusters provided\nexport class MultiTenantServiceLocator implements KubernetesServiceLocator {\n private readonly clusterDetails: ClusterDetails[];\n\n constructor(clusterDetails: ClusterDetails[]) {\n this.clusterDetails = clusterDetails;\n }\n\n // As this implementation always returns all clusters serviceId is ignored here\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n async getClustersByServiceId(_serviceId: string): Promise<ClusterDetails[]> {\n return this.clusterDetails;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n CoreV1Api,\n KubeConfig,\n Metrics,\n CustomObjectsApi,\n} from '@kubernetes/client-node';\nimport { ClusterDetails } from '../types/types';\n\nexport class KubernetesClientProvider {\n // visible for testing\n getKubeConfig(clusterDetails: ClusterDetails) {\n const cluster = {\n name: clusterDetails.name,\n server: clusterDetails.url,\n skipTLSVerify: clusterDetails.skipTLSVerify,\n caData: clusterDetails.caData,\n };\n\n // TODO configure\n const user = {\n name: 'backstage',\n token: clusterDetails.serviceAccountToken,\n };\n\n const context = {\n name: `${clusterDetails.name}`,\n user: user.name,\n cluster: cluster.name,\n };\n\n const kc = new KubeConfig();\n if (clusterDetails.serviceAccountToken) {\n kc.loadFromOptions({\n clusters: [cluster],\n users: [user],\n contexts: [context],\n currentContext: context.name,\n });\n } else {\n kc.loadFromDefault();\n }\n\n return kc;\n }\n\n getCoreClientByClusterDetails(clusterDetails: ClusterDetails) {\n const kc = this.getKubeConfig(clusterDetails);\n\n return kc.makeApiClient(CoreV1Api);\n }\n\n getMetricsClient(clusterDetails: ClusterDetails) {\n const kc = this.getKubeConfig(clusterDetails);\n\n return new Metrics(kc);\n }\n\n getCustomObjectsClient(clusterDetails: ClusterDetails) {\n const kc = this.getKubeConfig(clusterDetails);\n\n return kc.makeApiClient(CustomObjectsApi);\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { KubernetesAuthTranslator } from './types';\nimport { GKEClusterDetails } from '../types/types';\nimport { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common';\n\nexport class GoogleKubernetesAuthTranslator\n implements KubernetesAuthTranslator\n{\n async decorateClusterDetailsWithAuth(\n clusterDetails: GKEClusterDetails,\n requestBody: KubernetesRequestBody,\n ): Promise<GKEClusterDetails> {\n const clusterDetailsWithAuthToken: GKEClusterDetails = Object.assign(\n {},\n clusterDetails,\n );\n const authToken: string | undefined = requestBody.auth?.google;\n\n if (authToken) {\n clusterDetailsWithAuthToken.serviceAccountToken = authToken;\n } else {\n throw new Error(\n 'Google token not found under auth.google in request body',\n );\n }\n return clusterDetailsWithAuthToken;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { KubernetesAuthTranslator } from './types';\nimport { ServiceAccountClusterDetails } from '../types/types';\nimport { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common';\n\nexport class ServiceAccountKubernetesAuthTranslator\n implements KubernetesAuthTranslator\n{\n async decorateClusterDetailsWithAuth(\n clusterDetails: ServiceAccountClusterDetails,\n _requestBody: KubernetesRequestBody,\n ): Promise<ServiceAccountClusterDetails> {\n return clusterDetails;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport AWS, { Credentials } from 'aws-sdk';\nimport { sign } from 'aws4';\nimport { AWSClusterDetails } from '../types/types';\nimport { KubernetesAuthTranslator } from './types';\n\ntype SigningCreds = {\n accessKeyId: string | undefined;\n secretAccessKey: string | undefined;\n sessionToken: string | undefined;\n};\n\nexport class AwsIamKubernetesAuthTranslator\n implements KubernetesAuthTranslator\n{\n validCredentials(creds: SigningCreds): boolean {\n return (creds?.accessKeyId && creds?.secretAccessKey) as unknown as boolean;\n }\n\n awsGetCredentials = async (): Promise<Credentials> => {\n return new Promise((resolve, reject) => {\n AWS.config.getCredentials(err => {\n if (err) {\n return reject(err);\n }\n\n return resolve(AWS.config.credentials as Credentials);\n });\n });\n };\n\n async getCredentials(\n assumeRole?: string,\n externalId?: string,\n ): Promise<SigningCreds> {\n return new Promise<SigningCreds>(async (resolve, reject) => {\n const awsCreds = await this.awsGetCredentials();\n\n if (!(awsCreds instanceof Credentials))\n return reject(Error('No AWS credentials found.'));\n\n let creds: SigningCreds = {\n accessKeyId: awsCreds.accessKeyId,\n secretAccessKey: awsCreds.secretAccessKey,\n sessionToken: awsCreds.sessionToken,\n };\n\n if (!this.validCredentials(creds))\n return reject(Error('Invalid AWS credentials found.'));\n if (!assumeRole) return resolve(creds);\n\n try {\n const params: AWS.STS.Types.AssumeRoleRequest = {\n RoleArn: assumeRole,\n RoleSessionName: 'backstage-login',\n };\n if (externalId) params.ExternalId = externalId;\n\n const assumedRole = await new AWS.STS().assumeRole(params).promise();\n\n if (!assumedRole.Credentials) {\n throw new Error(`No credentials returned for role ${assumeRole}`);\n }\n\n creds = {\n accessKeyId: assumedRole.Credentials.AccessKeyId,\n secretAccessKey: assumedRole.Credentials.SecretAccessKey,\n sessionToken: assumedRole.Credentials.SessionToken,\n };\n } catch (e) {\n console.warn(`There was an error assuming the role: ${e}`);\n return reject(Error(`Unable to assume role: ${e}`));\n }\n return resolve(creds);\n });\n }\n async getBearerToken(\n clusterName: string,\n assumeRole?: string,\n externalId?: string,\n ): Promise<string> {\n const credentials = await this.getCredentials(assumeRole, externalId);\n\n const request = {\n host: `sts.amazonaws.com`,\n path: `/?Action=GetCallerIdentity&Version=2011-06-15&X-Amz-Expires=60`,\n headers: {\n 'x-k8s-aws-id': clusterName,\n },\n signQuery: true,\n };\n\n const signed = sign(request, credentials);\n const url = `https://${signed.host}${signed.path}`;\n const base64Url = Buffer.from(url, 'binary').toString('base64');\n const urlSafeBase64Url = base64Url\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n\n return `k8s-aws-v1.${urlSafeBase64Url}`;\n }\n\n async decorateClusterDetailsWithAuth(\n clusterDetails: AWSClusterDetails,\n ): Promise<AWSClusterDetails> {\n const clusterDetailsWithAuthToken: AWSClusterDetails = Object.assign(\n {},\n clusterDetails,\n );\n\n clusterDetailsWithAuthToken.serviceAccountToken = await this.getBearerToken(\n clusterDetails.name,\n clusterDetails.assumeRole,\n clusterDetails.externalId,\n );\n return clusterDetailsWithAuthToken;\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { KubernetesAuthTranslator } from './types';\nimport { GKEClusterDetails } from '../types/types';\nimport * as container from '@google-cloud/container';\n\nexport class GoogleServiceAccountAuthTranslator\n implements KubernetesAuthTranslator\n{\n async decorateClusterDetailsWithAuth(\n clusterDetails: GKEClusterDetails,\n ): Promise<GKEClusterDetails> {\n const clusterDetailsWithAuthToken: GKEClusterDetails = Object.assign(\n {},\n clusterDetails,\n );\n const client = new container.v1.ClusterManagerClient();\n const accessToken = await client.auth.getAccessToken();\n\n if (accessToken) {\n clusterDetailsWithAuthToken.serviceAccountToken = accessToken;\n } else {\n throw new Error(\n 'Unable to obtain access token for the current Google Application Default Credentials',\n );\n }\n return clusterDetailsWithAuthToken;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { KubernetesAuthTranslator } from './types';\nimport { GoogleKubernetesAuthTranslator } from './GoogleKubernetesAuthTranslator';\nimport { ServiceAccountKubernetesAuthTranslator } from './ServiceAccountKubernetesAuthTranslator';\nimport { AwsIamKubernetesAuthTranslator } from './AwsIamKubernetesAuthTranslator';\nimport { GoogleServiceAccountAuthTranslator } from './GoogleServiceAccountAuthProvider';\n\nexport class KubernetesAuthTranslatorGenerator {\n static getKubernetesAuthTranslatorInstance(\n authProvider: string,\n ): KubernetesAuthTranslator {\n switch (authProvider) {\n case 'google': {\n return new GoogleKubernetesAuthTranslator();\n }\n case 'aws': {\n return new AwsIamKubernetesAuthTranslator();\n }\n case 'serviceAccount': {\n return new ServiceAccountKubernetesAuthTranslator();\n }\n case 'googleServiceAccount': {\n return new GoogleServiceAccountAuthTranslator();\n }\n default: {\n throw new Error(\n `authProvider \"${authProvider}\" has no KubernetesAuthTranslator associated with it`,\n );\n }\n }\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Logger } from 'winston';\nimport {\n ClusterDetails,\n CustomResource,\n KubernetesFetcher,\n KubernetesObjectsProviderOptions,\n KubernetesServiceLocator,\n ObjectsByEntityRequest,\n ObjectToFetch,\n} from '../types/types';\nimport { KubernetesAuthTranslator } from '../kubernetes-auth-translator/types';\nimport { KubernetesAuthTranslatorGenerator } from '../kubernetes-auth-translator/KubernetesAuthTranslatorGenerator';\nimport {\n ClientContainerStatus,\n ClientCurrentResourceUsage,\n ClientPodStatus,\n ClusterObjects,\n FetchResponse,\n ObjectsByEntityResponse,\n PodFetchResponse,\n} from '@backstage/plugin-kubernetes-common';\nimport {\n ContainerStatus,\n CurrentResourceUsage,\n PodStatus,\n} from '@kubernetes/client-node';\n\nexport const DEFAULT_OBJECTS: ObjectToFetch[] = [\n {\n group: '',\n apiVersion: 'v1',\n plural: 'pods',\n objectType: 'pods',\n },\n {\n group: '',\n apiVersion: 'v1',\n plural: 'services',\n objectType: 'services',\n },\n {\n group: '',\n apiVersion: 'v1',\n plural: 'configmaps',\n objectType: 'configmaps',\n },\n {\n group: 'apps',\n apiVersion: 'v1',\n plural: 'deployments',\n objectType: 'deployments',\n },\n {\n group: 'apps',\n apiVersion: 'v1',\n plural: 'replicasets',\n objectType: 'replicasets',\n },\n {\n group: 'autoscaling',\n apiVersion: 'v1',\n plural: 'horizontalpodautoscalers',\n objectType: 'horizontalpodautoscalers',\n },\n {\n group: 'batch',\n apiVersion: 'v1',\n plural: 'jobs',\n objectType: 'jobs',\n },\n {\n group: 'batch',\n apiVersion: 'v1',\n plural: 'cronjobs',\n objectType: 'cronjobs',\n },\n {\n group: 'networking.k8s.io',\n apiVersion: 'v1',\n plural: 'ingresses',\n objectType: 'ingresses',\n },\n];\n\nexport interface KubernetesFanOutHandlerOptions\n extends KubernetesObjectsProviderOptions {}\n\nexport interface KubernetesRequestBody extends ObjectsByEntityRequest {}\n\nconst isPodFetchResponse = (fr: FetchResponse): fr is PodFetchResponse =>\n fr.type === 'pods';\nconst isString = (str: string | undefined): str is string => str !== undefined;\n\nconst numberOrBigIntToNumberOrString = (\n value: number | BigInt,\n): number | string => {\n return typeof value === 'bigint' ? value.toString() : (value as number);\n};\n\nconst toClientSafeResource = (\n current: CurrentResourceUsage,\n): ClientCurrentResourceUsage => {\n return {\n currentUsage: numberOrBigIntToNumberOrString(current.CurrentUsage),\n requestTotal: numberOrBigIntToNumberOrString(current.RequestTotal),\n limitTotal: numberOrBigIntToNumberOrString(current.LimitTotal),\n };\n};\n\nconst toClientSafeContainer = (\n container: ContainerStatus,\n): ClientContainerStatus => {\n return {\n container: container.Container,\n cpuUsage: toClientSafeResource(container.CPUUsage),\n memoryUsage: toClientSafeResource(container.MemoryUsage),\n };\n};\n\nconst toClientSafePodMetrics = (\n podMetrics: PodStatus[][],\n): ClientPodStatus[] => {\n return podMetrics.flat().map((pd: PodStatus): ClientPodStatus => {\n return {\n pod: pd.Pod,\n memory: toClientSafeResource(pd.Memory),\n cpu: toClientSafeResource(pd.CPU),\n containers: pd.Containers.map(toClientSafeContainer),\n };\n });\n};\n\nexport class KubernetesFanOutHandler {\n private readonly logger: Logger;\n private readonly fetcher: KubernetesFetcher;\n private readonly serviceLocator: KubernetesServiceLocator;\n private readonly customResources: CustomResource[];\n private readonly objectTypesToFetch: Set<ObjectToFetch>;\n\n constructor({\n logger,\n fetcher,\n serviceLocator,\n customResources,\n objectTypesToFetch = DEFAULT_OBJECTS,\n }: KubernetesFanOutHandlerOptions) {\n this.logger = logger;\n this.fetcher = fetcher;\n this.serviceLocator = serviceLocator;\n this.customResources = customResources;\n this.objectTypesToFetch = new Set(objectTypesToFetch);\n }\n\n async getKubernetesObjectsByEntity(\n requestBody: KubernetesRequestBody,\n ): Promise<ObjectsByEntityResponse> {\n const entityName =\n requestBody.entity?.metadata?.annotations?.[\n 'backstage.io/kubernetes-id'\n ] || requestBody.entity?.metadata?.name;\n\n const clusterDetails: ClusterDetails[] =\n await this.serviceLocator.getClustersByServiceId(entityName);\n\n // Execute all of these async actions simultaneously/without blocking sequentially as no common object is modified by them\n const promises: Promise<ClusterDetails>[] = clusterDetails.map(cd => {\n const kubernetesAuthTranslator: KubernetesAuthTranslator =\n KubernetesAuthTranslatorGenerator.getKubernetesAuthTranslatorInstance(\n cd.authProvider,\n );\n return kubernetesAuthTranslator.decorateClusterDetailsWithAuth(\n cd,\n requestBody,\n );\n });\n const clusterDetailsDecoratedForAuth: ClusterDetails[] = await Promise.all(\n promises,\n );\n\n this.logger.info(\n `entity.metadata.name=${entityName} clusterDetails=[${clusterDetailsDecoratedForAuth\n .map(c => c.name)\n .join(', ')}]`,\n );\n\n const labelSelector: string =\n requestBody.entity?.metadata?.annotations?.[\n 'backstage.io/kubernetes-label-selector'\n ] || `backstage.io/kubernetes-id=${entityName}`;\n\n return Promise.all(\n clusterDetailsDecoratedForAuth.map(clusterDetailsItem => {\n return this.fetcher\n .fetchObjectsForService({\n serviceId: entityName,\n clusterDetails: clusterDetailsItem,\n objectTypesToFetch: this.objectTypesToFetch,\n labelSelector,\n customResources: this.customResources,\n })\n .then(result => {\n if (clusterDetailsItem.skipMetricsLookup) {\n return Promise.all([\n Promise.resolve(result),\n Promise.resolve([]),\n ]);\n }\n // TODO refactor, extract as method\n const namespaces: Set<string> = new Set<string>(\n result.responses\n .filter(isPodFetchResponse)\n .flatMap(r => r.resources)\n .map(p => p.metadata?.namespace)\n .filter(isString),\n );\n\n const podMetrics = Array.from(namespaces).map(ns =>\n this.fetcher.fetchPodMetricsByNamespace(clusterDetailsItem, ns),\n );\n\n return Promise.all([\n Promise.resolve(result),\n Promise.all(podMetrics),\n ]);\n })\n .then(([result, metrics]) => {\n const objects: ClusterObjects = {\n cluster: {\n name: clusterDetailsItem.name,\n },\n podMetrics: toClientSafePodMetrics(metrics),\n resources: result.responses,\n errors: result.errors,\n };\n if (clusterDetailsItem.dashboardUrl) {\n objects.cluster.dashboardUrl = clusterDetailsItem.dashboardUrl;\n }\n if (clusterDetailsItem.dashboardApp) {\n objects.cluster.dashboardApp = clusterDetailsItem.dashboardApp;\n }\n if (clusterDetailsItem.dashboardParameters) {\n objects.cluster.dashboardParameters =\n clusterDetailsItem.dashboardParameters;\n }\n return objects;\n });\n }),\n ).then(r => ({\n items: r.filter(\n item =>\n (item.errors !== undefined && item.errors.length >= 1) ||\n (item.resources !== undefined &&\n item.resources.length >= 1 &&\n item.resources.some(fr => fr.resources.length >= 1)),\n ),\n }));\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CoreV1Api, topPods } from '@kubernetes/client-node';\nimport lodash, { Dictionary } from 'lodash';\nimport { Logger } from 'winston';\nimport {\n ClusterDetails,\n FetchResponseWrapper,\n KubernetesFetcher,\n KubernetesObjectTypes,\n ObjectFetchParams,\n ObjectToFetch,\n} from '../types/types';\nimport {\n FetchResponse,\n KubernetesFetchError,\n KubernetesErrorTypes,\n} from '@backstage/plugin-kubernetes-common';\nimport { KubernetesClientProvider } from './KubernetesClientProvider';\nimport { PodStatus } from '@kubernetes/client-node/dist/top';\n\nexport interface Clients {\n core: CoreV1Api;\n}\n\nexport interface KubernetesClientBasedFetcherOptions {\n kubernetesClientProvider: KubernetesClientProvider;\n logger: Logger;\n}\n\ntype FetchResult = FetchResponse | KubernetesFetchError;\n\nconst isError = (fr: FetchResult): fr is KubernetesFetchError =>\n fr.hasOwnProperty('errorType');\n\nfunction fetchResultsToResponseWrapper(\n results: FetchResult[],\n): FetchResponseWrapper {\n const groupBy: Dictionary<FetchResult[]> = lodash.groupBy(results, value => {\n return isError(value) ? 'errors' : 'responses';\n });\n\n return {\n errors: groupBy.errors ?? [],\n responses: groupBy.responses ?? [],\n } as FetchResponseWrapper; // TODO would be nice to get rid of this 'as'\n}\n\nconst statusCodeToErrorType = (statusCode: number): KubernetesErrorTypes => {\n switch (statusCode) {\n case 400:\n return 'BAD_REQUEST';\n case 401:\n return 'UNAUTHORIZED_ERROR';\n case 500:\n return 'SYSTEM_ERROR';\n default:\n return 'UNKNOWN_ERROR';\n }\n};\n\nexport class KubernetesClientBasedFetcher implements KubernetesFetcher {\n private readonly kubernetesClientProvider: KubernetesClientProvider;\n private readonly logger: Logger;\n\n constructor({\n kubernetesClientProvider,\n logger,\n }: KubernetesClientBasedFetcherOptions) {\n this.kubernetesClientProvider = kubernetesClientProvider;\n this.logger = logger;\n }\n\n fetchObjectsForService(\n params: ObjectFetchParams,\n ): Promise<FetchResponseWrapper> {\n const fetchResults = Array.from(params.objectTypesToFetch)\n .concat(params.customResources)\n .map(toFetch => {\n return this.fetchResource(\n params.clusterDetails,\n toFetch,\n params.labelSelector ||\n `backstage.io/kubernetes-id=${params.serviceId}`,\n toFetch.objectType,\n ).catch(this.captureKubernetesErrorsRethrowOthers.bind(this));\n });\n\n return Promise.all(fetchResults).then(fetchResultsToResponseWrapper);\n }\n\n fetchPodMetricsByNamespace(\n clusterDetails: ClusterDetails,\n namespace: string,\n ): Promise<PodStatus[]> {\n const metricsClient =\n this.kubernetesClientProvider.getMetricsClient(clusterDetails);\n const coreApi =\n this.kubernetesClientProvider.getCoreClientByClusterDetails(\n clusterDetails,\n );\n\n return topPods(coreApi, metricsClient, namespace);\n }\n\n private captureKubernetesErrorsRethrowOthers(e: any): KubernetesFetchError {\n if (e.response && e.response.statusCode) {\n this.logger.warn(\n `statusCode=${e.response.statusCode} for resource ${\n e.response.request.uri.pathname\n } body=[${JSON.stringify(e.response.body)}]`,\n );\n return {\n errorType: statusCodeToErrorType(e.response.statusCode),\n statusCode: e.response.statusCode,\n resourcePath: e.response.request.uri.pathname,\n };\n }\n throw e;\n }\n\n private fetchResource(\n clusterDetails: ClusterDetails,\n resource: ObjectToFetch,\n labelSelector: string,\n objectType: KubernetesObjectTypes,\n ): Promise<FetchResponse> {\n const customObjects =\n this.kubernetesClientProvider.getCustomObjectsClient(clusterDetails);\n\n customObjects.addInterceptor((requestOptions: any) => {\n requestOptions.uri = requestOptions.uri.replace('/apis//v1/', '/api/v1/');\n });\n\n return customObjects\n .listClusterCustomObject(\n resource.group,\n resource.apiVersion,\n resource.plural,\n '',\n false,\n '',\n '',\n labelSelector,\n )\n .then(r => {\n return {\n type: objectType,\n resources: (r.body as any).items,\n };\n });\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Config } from '@backstage/config';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { Logger } from 'winston';\nimport { getCombinedClusterDetails } from '../cluster-locator';\nimport { MultiTenantServiceLocator } from '../service-locator/MultiTenantServiceLocator';\nimport {\n ClusterDetails,\n KubernetesObjectTypes,\n ServiceLocatorMethod,\n CustomResource,\n KubernetesObjectsProvider,\n ObjectsByEntityRequest,\n KubernetesClustersSupplier,\n KubernetesFetcher,\n KubernetesServiceLocator,\n KubernetesObjectsProviderOptions,\n} from '../types/types';\nimport { KubernetesClientProvider } from './KubernetesClientProvider';\nimport {\n DEFAULT_OBJECTS,\n KubernetesFanOutHandler,\n} from './KubernetesFanOutHandler';\nimport { KubernetesClientBasedFetcher } from './KubernetesFetcher';\n\nexport interface KubernetesEnvironment {\n logger: Logger;\n config: Config;\n}\n\n/**\n * The return type of the `KubernetesBuilder.build` method\n *\n * @public\n */\nexport type KubernetesBuilderReturn = Promise<{\n router: express.Router;\n clusterDetails: ClusterDetails[];\n clusterSupplier: KubernetesClustersSupplier;\n customResources: CustomResource[];\n fetcher: KubernetesFetcher;\n objectsProvider: KubernetesObjectsProvider;\n serviceLocator: KubernetesServiceLocator;\n}>;\n\nexport class KubernetesBuilder {\n private clusterSupplier?: KubernetesClustersSupplier;\n private objectsProvider?: KubernetesObjectsProvider;\n private fetcher?: KubernetesFetcher;\n private serviceLocator?: KubernetesServiceLocator;\n\n static createBuilder(env: KubernetesEnvironment) {\n return new KubernetesBuilder(env);\n }\n\n constructor(protected readonly env: KubernetesEnvironment) {}\n\n public async build(): KubernetesBuilderReturn {\n const logger = this.env.logger;\n const config = this.env.config;\n\n logger.info('Initializing Kubernetes backend');\n\n if (!config.has('kubernetes')) {\n if (process.env.NODE_ENV !== 'development') {\n throw new Error('Kubernetes configuration is missing');\n }\n logger.warn(\n 'Failed to initialize kubernetes backend: kubernetes config is missing',\n );\n return {\n router: Router(),\n } as unknown as KubernetesBuilderReturn;\n }\n const customResources = this.buildCustomResources();\n\n const fetcher = this.fetcher ?? this.buildFetcher();\n\n const clusterSupplier = this.clusterSupplier ?? this.buildClusterSupplier();\n\n const clusterDetails = await this.fetchClusterDetails(clusterSupplier);\n\n const serviceLocator =\n this.serviceLocator ??\n this.buildServiceLocator(this.getServiceLocatorMethod(), clusterDetails);\n\n const objectsProvider =\n this.objectsProvider ??\n this.buildObjectsProvider({\n logger,\n fetcher,\n serviceLocator,\n customResources,\n objectTypesToFetch: this.getObjectTypesToFetch(),\n });\n\n const router = this.buildRouter(objectsProvider, clusterDetails);\n\n return {\n clusterDetails,\n clusterSupplier,\n customResources,\n fetcher,\n objectsProvider,\n router,\n serviceLocator,\n };\n }\n\n public setClusterSupplier(clusterSupplier?: KubernetesClustersSupplier) {\n this.clusterSupplier = clusterSupplier;\n return this;\n }\n\n public setObjectsProvider(objectsProvider?: KubernetesObjectsProvider) {\n this.objectsProvider = objectsProvider;\n return this;\n }\n\n public setFetcher(fetcher?: KubernetesFetcher) {\n this.fetcher = fetcher;\n return this;\n }\n\n public setServiceLocator(serviceLocator?: KubernetesServiceLocator) {\n this.serviceLocator = serviceLocator;\n return this;\n }\n\n protected buildCustomResources() {\n const customResources: CustomResource[] = (\n this.env.config.getOptionalConfigArray('kubernetes.customResources') ?? []\n ).map(\n c =>\n ({\n group: c.getString('group'),\n apiVersion: c.getString('apiVersion'),\n plural: c.getString('plural'),\n objectType: 'customresources',\n } as CustomResource),\n );\n\n this.env.logger.info(\n `action=LoadingCustomResources numOfCustomResources=${customResources.length}`,\n );\n return customResources;\n }\n\n protected buildClusterSupplier(): KubernetesClustersSupplier {\n const config = this.env.config;\n return {\n getClusters() {\n return getCombinedClusterDetails(config);\n },\n };\n }\n\n protected buildObjectsProvider(\n options: KubernetesObjectsProviderOptions,\n ): KubernetesObjectsProvider {\n return new KubernetesFanOutHandler(options);\n }\n\n protected buildFetcher(): KubernetesFetcher {\n return new KubernetesClientBasedFetcher({\n kubernetesClientProvider: new KubernetesClientProvider(),\n logger: this.env.logger,\n });\n }\n\n protected buildServiceLocator(\n method: ServiceLocatorMethod,\n clusterDetails: ClusterDetails[],\n ): KubernetesServiceLocator {\n switch (method) {\n case 'multiTenant':\n return this.buildMultiTenantServiceLocator(clusterDetails);\n case 'http':\n return this.buildHttpServiceLocator(clusterDetails);\n default:\n throw new Error(\n `Unsupported kubernetes.clusterLocatorMethod \"${method}\"`,\n );\n }\n }\n\n protected buildMultiTenantServiceLocator(\n clusterDetails: ClusterDetails[],\n ): KubernetesServiceLocator {\n return new MultiTenantServiceLocator(clusterDetails);\n }\n\n protected buildHttpServiceLocator(\n _clusterDetails: ClusterDetails[],\n ): KubernetesServiceLocator {\n throw new Error('not implemented');\n }\n\n protected buildRouter(\n objectsProvider: KubernetesObjectsProvider,\n clusterDetails: ClusterDetails[],\n ): express.Router {\n const logger = this.env.logger;\n const router = Router();\n router.use(express.json());\n\n router.post('/services/:serviceId', async (req, res) => {\n const serviceId = req.params.serviceId;\n const requestBody: ObjectsByEntityRequest = req.body;\n try {\n const response = await objectsProvider.getKubernetesObjectsByEntity(\n requestBody,\n );\n res.json(response);\n } catch (e) {\n logger.error(\n `action=retrieveObjectsByServiceId service=${serviceId}, error=${e}`,\n );\n res.status(500).json({ error: e.message });\n }\n });\n\n router.get('/clusters', async (_, res) => {\n res.json({\n items: clusterDetails.map(cd => ({\n name: cd.name,\n dashboardUrl: cd.dashboardUrl,\n authProvider: cd.authProvider,\n })),\n });\n });\n return router;\n }\n\n protected async fetchClusterDetails(\n clusterSupplier: KubernetesClustersSupplier,\n ) {\n const clusterDetails = await clusterSupplier.getClusters();\n\n this.env.logger.info(\n `action=loadClusterDetails numOfClustersLoaded=${clusterDetails.length}`,\n );\n\n return clusterDetails;\n }\n\n protected getServiceLocatorMethod() {\n return this.env.config.getString(\n 'kubernetes.serviceLocatorMethod.type',\n ) as ServiceLocatorMethod;\n }\n\n protected getObjectTypesToFetch() {\n const objectTypesToFetchStrings = this.env.config.getOptionalStringArray(\n 'kubernetes.objectTypes',\n ) as KubernetesObjectTypes[];\n\n const apiVersionOverrides = this.env.config.getOptionalConfig(\n 'kubernetes.apiVersionOverrides',\n );\n\n let objectTypesToFetch;\n\n if (objectTypesToFetchStrings) {\n objectTypesToFetch = DEFAULT_OBJECTS.filter(obj =>\n objectTypesToFetchStrings.includes(obj.objectType),\n );\n }\n\n if (apiVersionOverrides) {\n objectTypesToFetch = objectTypesToFetch ?? DEFAULT_OBJECTS;\n\n for (const obj of objectTypesToFetch) {\n if (apiVersionOverrides.has(obj.objectType)) {\n obj.apiVersion = apiVersionOverrides.getString(obj.objectType);\n }\n }\n }\n\n return objectTypesToFetch;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { Logger } from 'winston';\nimport { KubernetesClustersSupplier } from '../types/types';\nimport express from 'express';\nimport { KubernetesBuilder } from './KubernetesBuilder';\n\nexport interface RouterOptions {\n logger: Logger;\n config: Config;\n clusterSupplier?: KubernetesClustersSupplier;\n}\n\n/**\n * creates and configure a new router for handling the kubernetes backend APIs\n * @param options - specifies the options required by this plugin\n * @returns a new router\n * @deprecated Please use the new KubernetesBuilder instead like this\n * ```\n * import { KubernetesBuilder } from '@backstage/plugin-kubernetes-backend';\n * const { router } = await KubernetesBuilder.createBuilder({\n * logger,\n * config,\n * }).build();\n * ```\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { router } = await KubernetesBuilder.createBuilder(options)\n .setClusterSupplier(options.clusterSupplier)\n .build();\n return router;\n}\n"],"names":["container","ForwardedError","KubeConfig","CoreV1Api","Metrics","CustomObjectsApi","AWS","Credentials","sign","lodash","topPods","Router","express"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -129,6 +129,20 @@ interface KubernetesEnvironment {
|
|
|
129
129
|
logger: Logger;
|
|
130
130
|
config: Config;
|
|
131
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* The return type of the `KubernetesBuilder.build` method
|
|
134
|
+
*
|
|
135
|
+
* @public
|
|
136
|
+
*/
|
|
137
|
+
declare type KubernetesBuilderReturn = Promise<{
|
|
138
|
+
router: express.Router;
|
|
139
|
+
clusterDetails: ClusterDetails[];
|
|
140
|
+
clusterSupplier: KubernetesClustersSupplier;
|
|
141
|
+
customResources: CustomResource[];
|
|
142
|
+
fetcher: KubernetesFetcher;
|
|
143
|
+
objectsProvider: KubernetesObjectsProvider;
|
|
144
|
+
serviceLocator: KubernetesServiceLocator;
|
|
145
|
+
}>;
|
|
132
146
|
declare class KubernetesBuilder {
|
|
133
147
|
protected readonly env: KubernetesEnvironment;
|
|
134
148
|
private clusterSupplier?;
|
|
@@ -137,15 +151,7 @@ declare class KubernetesBuilder {
|
|
|
137
151
|
private serviceLocator?;
|
|
138
152
|
static createBuilder(env: KubernetesEnvironment): KubernetesBuilder;
|
|
139
153
|
constructor(env: KubernetesEnvironment);
|
|
140
|
-
build():
|
|
141
|
-
clusterDetails: ClusterDetails[];
|
|
142
|
-
clusterSupplier: KubernetesClustersSupplier;
|
|
143
|
-
customResources: CustomResource[];
|
|
144
|
-
fetcher: KubernetesFetcher;
|
|
145
|
-
objectsProvider: KubernetesObjectsProvider;
|
|
146
|
-
router: express.Router;
|
|
147
|
-
serviceLocator: KubernetesServiceLocator;
|
|
148
|
-
}>;
|
|
154
|
+
build(): KubernetesBuilderReturn;
|
|
149
155
|
setClusterSupplier(clusterSupplier?: KubernetesClustersSupplier): this;
|
|
150
156
|
setObjectsProvider(objectsProvider?: KubernetesObjectsProvider): this;
|
|
151
157
|
setFetcher(fetcher?: KubernetesFetcher): this;
|
|
@@ -165,4 +171,4 @@ declare class KubernetesBuilder {
|
|
|
165
171
|
|
|
166
172
|
declare const DEFAULT_OBJECTS: ObjectToFetch[];
|
|
167
173
|
|
|
168
|
-
export { AWSClusterDetails, ClusterDetails, CustomResource, DEFAULT_OBJECTS, FetchResponseWrapper, GKEClusterDetails, KubernetesBuilder, KubernetesClustersSupplier, KubernetesEnvironment, KubernetesFetcher, KubernetesObjectTypes, KubernetesObjectsProvider, KubernetesObjectsProviderOptions, KubernetesServiceLocator, ObjectFetchParams, ObjectToFetch, ObjectsByEntityRequest, RouterOptions, ServiceAccountClusterDetails, ServiceLocatorMethod, createRouter };
|
|
174
|
+
export { AWSClusterDetails, ClusterDetails, CustomResource, DEFAULT_OBJECTS, FetchResponseWrapper, GKEClusterDetails, KubernetesBuilder, KubernetesBuilderReturn, KubernetesClustersSupplier, KubernetesEnvironment, KubernetesFetcher, KubernetesObjectTypes, KubernetesObjectsProvider, KubernetesObjectsProviderOptions, KubernetesServiceLocator, ObjectFetchParams, ObjectToFetch, ObjectsByEntityRequest, RouterOptions, ServiceAccountClusterDetails, ServiceLocatorMethod, createRouter };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-kubernetes-backend",
|
|
3
3
|
"description": "A Backstage backend plugin that integrates towards Kubernetes",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.10",
|
|
5
5
|
"main": "dist/index.cjs.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"license": "Apache-2.0",
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
"main": "dist/index.cjs.js",
|
|
12
12
|
"types": "dist/index.d.ts"
|
|
13
13
|
},
|
|
14
|
+
"backstage": {
|
|
15
|
+
"role": "backend-plugin"
|
|
16
|
+
},
|
|
14
17
|
"homepage": "https://backstage.io",
|
|
15
18
|
"repository": {
|
|
16
19
|
"type": "git",
|
|
@@ -23,20 +26,20 @@
|
|
|
23
26
|
],
|
|
24
27
|
"configSchema": "schema.d.ts",
|
|
25
28
|
"scripts": {
|
|
26
|
-
"start": "backstage-cli
|
|
27
|
-
"build": "backstage-cli
|
|
28
|
-
"lint": "backstage-cli lint",
|
|
29
|
-
"test": "backstage-cli test",
|
|
30
|
-
"prepack": "backstage-cli prepack",
|
|
31
|
-
"postpack": "backstage-cli postpack",
|
|
32
|
-
"clean": "backstage-cli clean"
|
|
29
|
+
"start": "backstage-cli package start",
|
|
30
|
+
"build": "backstage-cli package build",
|
|
31
|
+
"lint": "backstage-cli package lint",
|
|
32
|
+
"test": "backstage-cli package test",
|
|
33
|
+
"prepack": "backstage-cli package prepack",
|
|
34
|
+
"postpack": "backstage-cli package postpack",
|
|
35
|
+
"clean": "backstage-cli package clean"
|
|
33
36
|
},
|
|
34
37
|
"dependencies": {
|
|
35
|
-
"@backstage/backend-common": "^0.
|
|
36
|
-
"@backstage/catalog-model": "^0.
|
|
37
|
-
"@backstage/config": "^0.1.
|
|
38
|
-
"@backstage/errors": "^0.2.
|
|
39
|
-
"@backstage/plugin-kubernetes-common": "^0.2.
|
|
38
|
+
"@backstage/backend-common": "^0.11.0",
|
|
39
|
+
"@backstage/catalog-model": "^0.11.0",
|
|
40
|
+
"@backstage/config": "^0.1.15",
|
|
41
|
+
"@backstage/errors": "^0.2.2",
|
|
42
|
+
"@backstage/plugin-kubernetes-common": "^0.2.5",
|
|
40
43
|
"@google-cloud/container": "^2.2.0",
|
|
41
44
|
"@kubernetes/client-node": "^0.16.0",
|
|
42
45
|
"@types/express": "^4.17.6",
|
|
@@ -47,7 +50,7 @@
|
|
|
47
50
|
"express": "^4.17.1",
|
|
48
51
|
"express-promise-router": "^4.1.0",
|
|
49
52
|
"fs-extra": "9.1.0",
|
|
50
|
-
"helmet": "^
|
|
53
|
+
"helmet": "^5.0.2",
|
|
51
54
|
"lodash": "^4.17.21",
|
|
52
55
|
"morgan": "^1.10.0",
|
|
53
56
|
"stream-buffers": "^3.0.2",
|
|
@@ -55,7 +58,7 @@
|
|
|
55
58
|
"yn": "^4.0.0"
|
|
56
59
|
},
|
|
57
60
|
"devDependencies": {
|
|
58
|
-
"@backstage/cli": "^0.
|
|
61
|
+
"@backstage/cli": "^0.14.1",
|
|
59
62
|
"@types/aws4": "^1.5.1",
|
|
60
63
|
"aws-sdk-mock": "^5.2.1",
|
|
61
64
|
"bdd-lazy-var": "^2.6.0",
|
|
@@ -65,5 +68,5 @@
|
|
|
65
68
|
"dist",
|
|
66
69
|
"schema.d.ts"
|
|
67
70
|
],
|
|
68
|
-
"gitHead": "
|
|
71
|
+
"gitHead": "a15da6ea1e3e8adc37be98be064071c8b5279b4a"
|
|
69
72
|
}
|