@backstage/plugin-kubernetes-backend 0.4.14-next.0 → 0.5.1-next.0

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 CHANGED
@@ -1,5 +1,151 @@
1
1
  # @backstage/plugin-kubernetes-backend
2
2
 
3
+ ## 0.5.1-next.0
4
+
5
+ ### Patch Changes
6
+
7
+ - b9f7ffb162: Add filtering to GKE cluster locator
8
+ - cfc0f19699: Updated dependency `fs-extra` to `10.1.0`.
9
+ - Updated dependencies
10
+ - @backstage/backend-common@0.13.3-next.0
11
+
12
+ ## 0.5.0
13
+
14
+ ### Minor Changes
15
+
16
+ - 3d45427666: **BREAKING** Custom cluster suppliers need to cache their getClusters result
17
+
18
+ To allow custom `KubernetesClustersSupplier` instances to refresh the list of clusters
19
+ the `getClusters` method is now called whenever the list of clusters is needed.
20
+
21
+ Existing `KubernetesClustersSupplier` implementations will need to ensure that `getClusters`
22
+ can be called frequently and should return a cached result from `getClusters` instead.
23
+
24
+ For example, here's a simple example of a custom supplier in `packages/backend/src/plugins/kubernetes.ts`:
25
+
26
+ ```diff
27
+ -import { KubernetesBuilder } from '@backstage/plugin-kubernetes-backend';
28
+ +import {
29
+ + ClusterDetails,
30
+ + KubernetesBuilder,
31
+ + KubernetesClustersSupplier,
32
+ +} from '@backstage/plugin-kubernetes-backend';
33
+ import { Router } from 'express';
34
+ import { PluginEnvironment } from '../types';
35
+ +import { Duration } from 'luxon';
36
+ +
37
+ +export class CustomClustersSupplier implements KubernetesClustersSupplier {
38
+ + constructor(private clusterDetails: ClusterDetails[] = []) {}
39
+ +
40
+ + static create(refreshInterval: Duration) {
41
+ + const clusterSupplier = new CustomClustersSupplier();
42
+ + // setup refresh, e.g. using a copy of https://github.com/backstage/backstage/blob/master/plugins/search-backend-node/src/runPeriodically.ts
43
+ + runPeriodically(
44
+ + () => clusterSupplier.refreshClusters(),
45
+ + refreshInterval.toMillis(),
46
+ + );
47
+ + return clusterSupplier;
48
+ + }
49
+ +
50
+ + async refreshClusters(): Promise<void> {
51
+ + this.clusterDetails = []; // fetch from somewhere
52
+ + }
53
+ +
54
+ + async getClusters(): Promise<ClusterDetails[]> {
55
+ + return this.clusterDetails;
56
+ + }
57
+ +}
58
+
59
+ export default async function createPlugin(
60
+ env: PluginEnvironment,
61
+ ): Promise<Router> {
62
+ - const { router } = await KubernetesBuilder.createBuilder({
63
+ + const builder = await KubernetesBuilder.createBuilder({
64
+ logger: env.logger,
65
+ config: env.config,
66
+ - }).build();
67
+ + });
68
+ + builder.setClusterSupplier(
69
+ + CustomClustersSupplier.create(Duration.fromObject({ minutes: 60 })),
70
+ + );
71
+ + const { router } = await builder.build();
72
+ ```
73
+
74
+ ### Patch Changes
75
+
76
+ - 753a20c89e: Add kubernetes namespace annotation `backstage.io/kubernetes-namespace` to allow namespaced Kubernetes resources fetches
77
+ - Updated dependencies
78
+ - @backstage/catalog-model@1.0.1
79
+ - @backstage/backend-common@0.13.2
80
+ - @backstage/plugin-kubernetes-common@0.2.9
81
+
82
+ ## 0.5.0-next.1
83
+
84
+ ### Minor Changes
85
+
86
+ - 3d45427666: **BREAKING** Custom cluster suppliers need to cache their getClusters result
87
+
88
+ To allow custom `KubernetesClustersSupplier` instances to refresh the list of clusters
89
+ the `getClusters` method is now called whenever the list of clusters is needed.
90
+
91
+ Existing `KubernetesClustersSupplier` implementations will need to ensure that `getClusters`
92
+ can be called frequently and should return a cached result from `getClusters` instead.
93
+
94
+ For example, here's a simple example of a custom supplier in `packages/backend/src/plugins/kubernetes.ts`:
95
+
96
+ ```diff
97
+ -import { KubernetesBuilder } from '@backstage/plugin-kubernetes-backend';
98
+ +import {
99
+ + ClusterDetails,
100
+ + KubernetesBuilder,
101
+ + KubernetesClustersSupplier,
102
+ +} from '@backstage/plugin-kubernetes-backend';
103
+ import { Router } from 'express';
104
+ import { PluginEnvironment } from '../types';
105
+ +import { Duration } from 'luxon';
106
+ +
107
+ +export class CustomClustersSupplier implements KubernetesClustersSupplier {
108
+ + constructor(private clusterDetails: ClusterDetails[] = []) {}
109
+ +
110
+ + static create(refreshInterval: Duration) {
111
+ + const clusterSupplier = new CustomClustersSupplier();
112
+ + // setup refresh, e.g. using a copy of https://github.com/backstage/backstage/blob/master/plugins/search-backend-node/src/runPeriodically.ts
113
+ + runPeriodically(
114
+ + () => clusterSupplier.refreshClusters(),
115
+ + refreshInterval.toMillis(),
116
+ + );
117
+ + return clusterSupplier;
118
+ + }
119
+ +
120
+ + async refreshClusters(): Promise<void> {
121
+ + this.clusterDetails = []; // fetch from somewhere
122
+ + }
123
+ +
124
+ + async getClusters(): Promise<ClusterDetails[]> {
125
+ + return this.clusterDetails;
126
+ + }
127
+ +}
128
+
129
+ export default async function createPlugin(
130
+ env: PluginEnvironment,
131
+ ): Promise<Router> {
132
+ - const { router } = await KubernetesBuilder.createBuilder({
133
+ + const builder = await KubernetesBuilder.createBuilder({
134
+ logger: env.logger,
135
+ config: env.config,
136
+ - }).build();
137
+ + });
138
+ + builder.setClusterSupplier(
139
+ + CustomClustersSupplier.create(Duration.fromObject({ minutes: 60 })),
140
+ + );
141
+ + const { router } = await builder.build();
142
+ ```
143
+
144
+ ### Patch Changes
145
+
146
+ - Updated dependencies
147
+ - @backstage/backend-common@0.13.2-next.2
148
+
3
149
  ## 0.4.14-next.0
4
150
 
5
151
  ### Patch Changes
package/dist/index.cjs.js CHANGED
@@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var express = require('express');
6
6
  var Router = require('express-promise-router');
7
+ var luxon = require('luxon');
7
8
  var errors = require('@backstage/errors');
8
9
  var container = require('@google-cloud/container');
9
10
  var clientNode = require('@kubernetes/client-node');
@@ -91,40 +92,90 @@ class ConfigClusterLocator {
91
92
  }
92
93
  }
93
94
 
95
+ function runPeriodically(fn, delayMs) {
96
+ let cancel;
97
+ let cancelled = false;
98
+ const cancellationPromise = new Promise((resolve) => {
99
+ cancel = () => {
100
+ resolve();
101
+ cancelled = true;
102
+ };
103
+ });
104
+ const startRefresh = async () => {
105
+ while (!cancelled) {
106
+ try {
107
+ await fn();
108
+ } catch {
109
+ }
110
+ await Promise.race([
111
+ new Promise((resolve) => setTimeout(resolve, delayMs)),
112
+ cancellationPromise
113
+ ]);
114
+ }
115
+ };
116
+ startRefresh();
117
+ return cancel;
118
+ }
119
+
94
120
  class GkeClusterLocator {
95
- constructor(options, client) {
121
+ constructor(options, client, clusterDetails = void 0, hasClusterDetails = false) {
96
122
  this.options = options;
97
123
  this.client = client;
124
+ this.clusterDetails = clusterDetails;
125
+ this.hasClusterDetails = hasClusterDetails;
98
126
  }
99
- static fromConfigWithClient(config, client) {
100
- var _a, _b, _c, _d;
127
+ static fromConfigWithClient(config, client, refreshInterval) {
128
+ var _a, _b, _c, _d, _e, _f;
129
+ const matchingResourceLabels = (_b = (_a = config.getOptionalConfigArray("matchingResourceLabels")) == null ? void 0 : _a.map((mrl) => {
130
+ return { key: mrl.getString("key"), value: mrl.getString("value") };
131
+ })) != null ? _b : [];
101
132
  const options = {
102
133
  projectId: config.getString("projectId"),
103
- region: (_a = config.getOptionalString("region")) != null ? _a : "-",
104
- skipTLSVerify: (_b = config.getOptionalBoolean("skipTLSVerify")) != null ? _b : false,
105
- skipMetricsLookup: (_c = config.getOptionalBoolean("skipMetricsLookup")) != null ? _c : false,
106
- exposeDashboard: (_d = config.getOptionalBoolean("exposeDashboard")) != null ? _d : false
134
+ region: (_c = config.getOptionalString("region")) != null ? _c : "-",
135
+ skipTLSVerify: (_d = config.getOptionalBoolean("skipTLSVerify")) != null ? _d : false,
136
+ skipMetricsLookup: (_e = config.getOptionalBoolean("skipMetricsLookup")) != null ? _e : false,
137
+ exposeDashboard: (_f = config.getOptionalBoolean("exposeDashboard")) != null ? _f : false,
138
+ matchingResourceLabels
107
139
  };
108
- return new GkeClusterLocator(options, client);
140
+ const gkeClusterLocator = new GkeClusterLocator(options, client);
141
+ if (refreshInterval) {
142
+ runPeriodically(() => gkeClusterLocator.refreshClusters(), refreshInterval.toMillis());
143
+ }
144
+ return gkeClusterLocator;
109
145
  }
110
- static fromConfig(config) {
111
- return GkeClusterLocator.fromConfigWithClient(config, new container__namespace.v1.ClusterManagerClient());
146
+ static fromConfig(config, refreshInterval = void 0) {
147
+ return GkeClusterLocator.fromConfigWithClient(config, new container__namespace.v1.ClusterManagerClient(), refreshInterval);
112
148
  }
113
149
  async getClusters() {
150
+ var _a;
151
+ if (!this.hasClusterDetails) {
152
+ await this.refreshClusters();
153
+ }
154
+ return (_a = this.clusterDetails) != null ? _a : [];
155
+ }
156
+ async refreshClusters() {
114
157
  var _a;
115
158
  const {
116
159
  projectId,
117
160
  region,
118
161
  skipTLSVerify,
119
162
  skipMetricsLookup,
120
- exposeDashboard
163
+ exposeDashboard,
164
+ matchingResourceLabels
121
165
  } = this.options;
122
166
  const request = {
123
167
  parent: `projects/${projectId}/locations/${region}`
124
168
  };
125
169
  try {
126
170
  const [response] = await this.client.listClusters(request);
127
- return ((_a = response.clusters) != null ? _a : []).map((r) => {
171
+ this.clusterDetails = ((_a = response.clusters) != null ? _a : []).filter((r) => {
172
+ return matchingResourceLabels == null ? void 0 : matchingResourceLabels.every((mrl) => {
173
+ if (!r.resourceLabels) {
174
+ return false;
175
+ }
176
+ return r.resourceLabels[mrl.key] === mrl.value;
177
+ });
178
+ }).map((r) => {
128
179
  var _a2, _b;
129
180
  return {
130
181
  name: (_a2 = r.name) != null ? _a2 : "unknown",
@@ -142,36 +193,46 @@ class GkeClusterLocator {
142
193
  } : {}
143
194
  };
144
195
  });
196
+ this.hasClusterDetails = true;
145
197
  } catch (e) {
146
198
  throw new errors.ForwardedError(`There was an error retrieving clusters from GKE for projectId=${projectId} region=${region}`, e);
147
199
  }
148
200
  }
149
201
  }
150
202
 
151
- const getCombinedClusterDetails = async (rootConfig) => {
152
- return Promise.all(rootConfig.getConfigArray("kubernetes.clusterLocatorMethods").map((clusterLocatorMethod) => {
203
+ class CombinedClustersSupplier {
204
+ constructor(clusterSuppliers) {
205
+ this.clusterSuppliers = clusterSuppliers;
206
+ }
207
+ async getClusters() {
208
+ return await Promise.all(this.clusterSuppliers.map((supplier) => supplier.getClusters())).then((res) => {
209
+ return res.flat();
210
+ }).catch((e) => {
211
+ throw e;
212
+ });
213
+ }
214
+ }
215
+ const getCombinedClusterSupplier = (rootConfig, refreshInterval = void 0) => {
216
+ const clusterSuppliers = rootConfig.getConfigArray("kubernetes.clusterLocatorMethods").map((clusterLocatorMethod) => {
153
217
  const type = clusterLocatorMethod.getString("type");
154
218
  switch (type) {
155
219
  case "config":
156
- return ConfigClusterLocator.fromConfig(clusterLocatorMethod).getClusters();
220
+ return ConfigClusterLocator.fromConfig(clusterLocatorMethod);
157
221
  case "gke":
158
- return GkeClusterLocator.fromConfig(clusterLocatorMethod).getClusters();
222
+ return GkeClusterLocator.fromConfig(clusterLocatorMethod, refreshInterval);
159
223
  default:
160
224
  throw new Error(`Unsupported kubernetes.clusterLocatorMethods: "${type}"`);
161
225
  }
162
- })).then((res) => {
163
- return res.flat();
164
- }).catch((e) => {
165
- throw e;
166
226
  });
227
+ return new CombinedClustersSupplier(clusterSuppliers);
167
228
  };
168
229
 
169
230
  class MultiTenantServiceLocator {
170
- constructor(clusterDetails) {
171
- this.clusterDetails = clusterDetails;
231
+ constructor(clusterSupplier) {
232
+ this.clusterSupplier = clusterSupplier;
172
233
  }
173
234
  async getClustersByServiceId(_serviceId) {
174
- return this.clusterDetails;
235
+ return this.clusterSupplier.getClusters();
175
236
  }
176
237
  }
177
238
 
@@ -451,7 +512,7 @@ class KubernetesFanOutHandler {
451
512
  this.objectTypesToFetch = new Set(objectTypesToFetch);
452
513
  }
453
514
  async getKubernetesObjectsByEntity(requestBody) {
454
- var _a, _b, _c, _d, _e, _f, _g, _h;
515
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
455
516
  const entityName = ((_c = (_b = (_a = requestBody.entity) == null ? void 0 : _a.metadata) == null ? void 0 : _b.annotations) == null ? void 0 : _c["backstage.io/kubernetes-id"]) || ((_e = (_d = requestBody.entity) == null ? void 0 : _d.metadata) == null ? void 0 : _e.name);
456
517
  const clusterDetails = await this.serviceLocator.getClustersByServiceId(entityName);
457
518
  const promises = clusterDetails.map((cd) => {
@@ -461,17 +522,22 @@ class KubernetesFanOutHandler {
461
522
  const clusterDetailsDecoratedForAuth = await Promise.all(promises);
462
523
  this.logger.info(`entity.metadata.name=${entityName} clusterDetails=[${clusterDetailsDecoratedForAuth.map((c) => c.name).join(", ")}]`);
463
524
  const labelSelector = ((_h = (_g = (_f = requestBody.entity) == null ? void 0 : _f.metadata) == null ? void 0 : _g.annotations) == null ? void 0 : _h["backstage.io/kubernetes-label-selector"]) || `backstage.io/kubernetes-id=${entityName}`;
525
+ const namespace = (_k = (_j = (_i = requestBody.entity) == null ? void 0 : _i.metadata) == null ? void 0 : _j.annotations) == null ? void 0 : _k["backstage.io/kubernetes-namespace"];
464
526
  return Promise.all(clusterDetailsDecoratedForAuth.map((clusterDetailsItem) => {
465
527
  return this.fetcher.fetchObjectsForService({
466
528
  serviceId: entityName,
467
529
  clusterDetails: clusterDetailsItem,
468
530
  objectTypesToFetch: this.objectTypesToFetch,
469
531
  labelSelector,
470
- customResources: this.customResources
532
+ customResources: this.customResources,
533
+ namespace
471
534
  }).then((result) => this.getMetricsForPods(clusterDetailsItem, result)).then((r) => this.toClusterObjects(clusterDetailsItem, r));
472
- })).then((r) => ({
473
- items: r.filter((item) => item.errors !== void 0 && item.errors.length >= 1 || item.resources !== void 0 && item.resources.length >= 1 && item.resources.some((fr) => fr.resources.length >= 1))
474
- }));
535
+ })).then(this.toObjectsByEntityResponse);
536
+ }
537
+ toObjectsByEntityResponse(clusterObjects) {
538
+ return {
539
+ items: clusterObjects.filter((item) => item.errors !== void 0 && item.errors.length >= 1 || item.resources !== void 0 && item.resources.length >= 1 && item.resources.some((fr) => fr.resources.length >= 1))
540
+ };
475
541
  }
476
542
  toClusterObjects(clusterDetails, [result, metrics]) {
477
543
  const objects = {
@@ -539,7 +605,7 @@ class KubernetesClientBasedFetcher {
539
605
  }
540
606
  fetchObjectsForService(params) {
541
607
  const fetchResults = Array.from(params.objectTypesToFetch).concat(params.customResources).map((toFetch) => {
542
- return this.fetchResource(params.clusterDetails, toFetch, params.labelSelector || `backstage.io/kubernetes-id=${params.serviceId}`, toFetch.objectType).catch(this.captureKubernetesErrorsRethrowOthers.bind(this));
608
+ return this.fetchResource(params.clusterDetails, toFetch, params.labelSelector || `backstage.io/kubernetes-id=${params.serviceId}`, toFetch.objectType, params.namespace).catch(this.captureKubernetesErrorsRethrowOthers.bind(this));
543
609
  });
544
610
  return Promise.all(fetchResults).then(fetchResultsToResponseWrapper);
545
611
  }
@@ -559,11 +625,19 @@ class KubernetesClientBasedFetcher {
559
625
  }
560
626
  throw e;
561
627
  }
562
- fetchResource(clusterDetails, resource, labelSelector, objectType) {
628
+ fetchResource(clusterDetails, resource, labelSelector, objectType, namespace) {
563
629
  const customObjects = this.kubernetesClientProvider.getCustomObjectsClient(clusterDetails);
564
630
  customObjects.addInterceptor((requestOptions) => {
565
631
  requestOptions.uri = requestOptions.uri.replace("/apis//v1/", "/api/v1/");
566
632
  });
633
+ if (namespace) {
634
+ return customObjects.listNamespacedCustomObject(resource.group, resource.apiVersion, namespace, resource.plural, "", false, "", "", labelSelector).then((r) => {
635
+ return {
636
+ type: objectType,
637
+ resources: r.body.items
638
+ };
639
+ });
640
+ }
567
641
  return customObjects.listClusterCustomObject(resource.group, resource.apiVersion, resource.plural, "", false, "", "", labelSelector).then((r) => {
568
642
  return {
569
643
  type: objectType,
@@ -576,6 +650,9 @@ class KubernetesClientBasedFetcher {
576
650
  class KubernetesBuilder {
577
651
  constructor(env) {
578
652
  this.env = env;
653
+ this.defaultClusterRefreshInterval = luxon.Duration.fromObject({
654
+ minutes: 60
655
+ });
579
656
  }
580
657
  static createBuilder(env) {
581
658
  return new KubernetesBuilder(env);
@@ -596,9 +673,8 @@ class KubernetesBuilder {
596
673
  }
597
674
  const customResources = this.buildCustomResources();
598
675
  const fetcher = (_a = this.fetcher) != null ? _a : this.buildFetcher();
599
- const clusterSupplier = (_b = this.clusterSupplier) != null ? _b : this.buildClusterSupplier();
600
- const clusterDetails = await this.fetchClusterDetails(clusterSupplier);
601
- const serviceLocator = (_c = this.serviceLocator) != null ? _c : this.buildServiceLocator(this.getServiceLocatorMethod(), clusterDetails);
676
+ const clusterSupplier = (_b = this.clusterSupplier) != null ? _b : this.buildClusterSupplier(this.defaultClusterRefreshInterval);
677
+ const serviceLocator = (_c = this.serviceLocator) != null ? _c : this.buildServiceLocator(this.getServiceLocatorMethod(), clusterSupplier);
602
678
  const objectsProvider = (_d = this.objectsProvider) != null ? _d : this.buildObjectsProvider({
603
679
  logger,
604
680
  fetcher,
@@ -606,9 +682,8 @@ class KubernetesBuilder {
606
682
  customResources,
607
683
  objectTypesToFetch: this.getObjectTypesToFetch()
608
684
  });
609
- const router = this.buildRouter(objectsProvider, clusterDetails);
685
+ const router = this.buildRouter(objectsProvider, clusterSupplier);
610
686
  return {
611
- clusterDetails,
612
687
  clusterSupplier,
613
688
  customResources,
614
689
  fetcher,
@@ -621,6 +696,10 @@ class KubernetesBuilder {
621
696
  this.clusterSupplier = clusterSupplier;
622
697
  return this;
623
698
  }
699
+ setDefaultClusterRefreshInterval(refreshInterval) {
700
+ this.defaultClusterRefreshInterval = refreshInterval;
701
+ return this;
702
+ }
624
703
  setObjectsProvider(objectsProvider) {
625
704
  this.objectsProvider = objectsProvider;
626
705
  return this;
@@ -644,13 +723,9 @@ class KubernetesBuilder {
644
723
  this.env.logger.info(`action=LoadingCustomResources numOfCustomResources=${customResources.length}`);
645
724
  return customResources;
646
725
  }
647
- buildClusterSupplier() {
726
+ buildClusterSupplier(refreshInterval) {
648
727
  const config = this.env.config;
649
- return {
650
- getClusters() {
651
- return getCombinedClusterDetails(config);
652
- }
653
- };
728
+ return getCombinedClusterSupplier(config, refreshInterval);
654
729
  }
655
730
  buildObjectsProvider(options) {
656
731
  return new KubernetesFanOutHandler(options);
@@ -661,23 +736,23 @@ class KubernetesBuilder {
661
736
  logger: this.env.logger
662
737
  });
663
738
  }
664
- buildServiceLocator(method, clusterDetails) {
739
+ buildServiceLocator(method, clusterSupplier) {
665
740
  switch (method) {
666
741
  case "multiTenant":
667
- return this.buildMultiTenantServiceLocator(clusterDetails);
742
+ return this.buildMultiTenantServiceLocator(clusterSupplier);
668
743
  case "http":
669
- return this.buildHttpServiceLocator(clusterDetails);
744
+ return this.buildHttpServiceLocator(clusterSupplier);
670
745
  default:
671
746
  throw new Error(`Unsupported kubernetes.clusterLocatorMethod "${method}"`);
672
747
  }
673
748
  }
674
- buildMultiTenantServiceLocator(clusterDetails) {
675
- return new MultiTenantServiceLocator(clusterDetails);
749
+ buildMultiTenantServiceLocator(clusterSupplier) {
750
+ return new MultiTenantServiceLocator(clusterSupplier);
676
751
  }
677
- buildHttpServiceLocator(_clusterDetails) {
752
+ buildHttpServiceLocator(_clusterSupplier) {
678
753
  throw new Error("not implemented");
679
754
  }
680
- buildRouter(objectsProvider, clusterDetails) {
755
+ buildRouter(objectsProvider, clusterSupplier) {
681
756
  const logger = this.env.logger;
682
757
  const router = Router__default["default"]();
683
758
  router.use(express__default["default"].json());
@@ -693,6 +768,7 @@ class KubernetesBuilder {
693
768
  }
694
769
  });
695
770
  router.get("/clusters", async (_, res) => {
771
+ const clusterDetails = await this.fetchClusterDetails(clusterSupplier);
696
772
  res.json({
697
773
  items: clusterDetails.map((cd) => ({
698
774
  name: cd.name,
@@ -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\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 FetchResponseWrapper,\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\ntype responseWithMetrics = [FetchResponseWrapper, PodStatus[][]];\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 => this.getMetricsForPods(clusterDetailsItem, result))\n .then(r => this.toClusterObjects(clusterDetailsItem, r));\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 toClusterObjects(\n clusterDetails: ClusterDetails,\n [result, metrics]: responseWithMetrics,\n ): ClusterObjects {\n const objects: ClusterObjects = {\n cluster: {\n name: clusterDetails.name,\n },\n podMetrics: toClientSafePodMetrics(metrics),\n resources: result.responses,\n errors: result.errors,\n };\n if (clusterDetails.dashboardUrl) {\n objects.cluster.dashboardUrl = clusterDetails.dashboardUrl;\n }\n if (clusterDetails.dashboardApp) {\n objects.cluster.dashboardApp = clusterDetails.dashboardApp;\n }\n if (clusterDetails.dashboardParameters) {\n objects.cluster.dashboardParameters = clusterDetails.dashboardParameters;\n }\n return objects;\n }\n\n async getMetricsForPods(\n clusterDetails: ClusterDetails,\n result: FetchResponseWrapper,\n ): Promise<responseWithMetrics> {\n if (clusterDetails.skipMetricsLookup) {\n return [result, []];\n }\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(clusterDetails, ns),\n );\n\n return Promise.all([result, Promise.all(podMetrics)]);\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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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/cluster-locator/ConfigClusterLocator.ts","../src/service/runPeriodically.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 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\n/**\n * Runs a function repeatedly, with a fixed wait between invocations.\n *\n * Supports async functions, and silently ignores exceptions and rejections.\n *\n * @param fn - The function to run. May return a Promise.\n * @param delayMs - The delay between a completed function invocation and the\n * next.\n * @returns A function that, when called, stops the invocation loop.\n */\nexport function runPeriodically(fn: () => any, delayMs: number): () => void {\n let cancel: () => void;\n let cancelled = false;\n const cancellationPromise = new Promise<void>(resolve => {\n cancel = () => {\n resolve();\n cancelled = true;\n };\n });\n\n const startRefresh = async () => {\n while (!cancelled) {\n try {\n await fn();\n } catch {\n // ignore intentionally\n }\n\n await Promise.race([\n new Promise(resolve => setTimeout(resolve, delayMs)),\n cancellationPromise,\n ]);\n }\n };\n startRefresh();\n\n return cancel!;\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 { Duration } from 'luxon';\nimport { runPeriodically } from '../service/runPeriodically';\nimport {\n ClusterDetails,\n GKEClusterDetails,\n KubernetesClustersSupplier,\n} from '../types/types';\n\ninterface MatchResourceLabelEntry {\n key: string;\n value: string;\n}\n\ntype GkeClusterLocatorOptions = {\n projectId: string;\n region?: string;\n skipTLSVerify?: boolean;\n skipMetricsLookup?: boolean;\n exposeDashboard?: boolean;\n matchingResourceLabels?: MatchResourceLabelEntry[];\n};\n\nexport class GkeClusterLocator implements KubernetesClustersSupplier {\n constructor(\n private readonly options: GkeClusterLocatorOptions,\n private readonly client: container.v1.ClusterManagerClient,\n private clusterDetails: GKEClusterDetails[] | undefined = undefined,\n private hasClusterDetails: boolean = false,\n ) {}\n\n static fromConfigWithClient(\n config: Config,\n client: container.v1.ClusterManagerClient,\n refreshInterval?: Duration,\n ): GkeClusterLocator {\n const matchingResourceLabels: MatchResourceLabelEntry[] =\n config.getOptionalConfigArray('matchingResourceLabels')?.map(mrl => {\n return { key: mrl.getString('key'), value: mrl.getString('value') };\n }) ?? [];\n\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 matchingResourceLabels,\n };\n const gkeClusterLocator = new GkeClusterLocator(options, client);\n if (refreshInterval) {\n runPeriodically(\n () => gkeClusterLocator.refreshClusters(),\n refreshInterval.toMillis(),\n );\n }\n return gkeClusterLocator;\n }\n\n static fromConfig(\n config: Config,\n refreshInterval: Duration | undefined = undefined,\n ): GkeClusterLocator {\n return GkeClusterLocator.fromConfigWithClient(\n config,\n new container.v1.ClusterManagerClient(),\n refreshInterval,\n );\n }\n\n async getClusters(): Promise<ClusterDetails[]> {\n if (!this.hasClusterDetails) {\n // refresh at least once when first called, when retries are disabled and in tests\n await this.refreshClusters();\n }\n return this.clusterDetails ?? [];\n }\n\n // TODO pass caData into the object\n async refreshClusters(): Promise<void> {\n const {\n projectId,\n region,\n skipTLSVerify,\n skipMetricsLookup,\n exposeDashboard,\n matchingResourceLabels,\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 this.clusterDetails = (response.clusters ?? [])\n .filter(r => {\n return matchingResourceLabels?.every(mrl => {\n if (!r.resourceLabels) {\n return false;\n }\n return r.resourceLabels[mrl.key] === mrl.value;\n });\n })\n .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 this.hasClusterDetails = true;\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 { Duration } from 'luxon';\nimport { ClusterDetails, KubernetesClustersSupplier } from '../types/types';\nimport { ConfigClusterLocator } from './ConfigClusterLocator';\nimport { GkeClusterLocator } from './GkeClusterLocator';\n\nclass CombinedClustersSupplier implements KubernetesClustersSupplier {\n constructor(readonly clusterSuppliers: KubernetesClustersSupplier[]) {}\n\n async getClusters(): Promise<ClusterDetails[]> {\n return await Promise.all(\n this.clusterSuppliers.map(supplier => supplier.getClusters()),\n )\n .then(res => {\n return res.flat();\n })\n .catch(e => {\n throw e;\n });\n }\n}\n\nexport const getCombinedClusterSupplier = (\n rootConfig: Config,\n refreshInterval: Duration | undefined = undefined,\n): KubernetesClustersSupplier => {\n const clusterSuppliers = rootConfig\n .getConfigArray('kubernetes.clusterLocatorMethods')\n .map(clusterLocatorMethod => {\n const type = clusterLocatorMethod.getString('type');\n switch (type) {\n case 'config':\n return ConfigClusterLocator.fromConfig(clusterLocatorMethod);\n case 'gke':\n return GkeClusterLocator.fromConfig(\n clusterLocatorMethod,\n refreshInterval,\n );\n default:\n throw new Error(\n `Unsupported kubernetes.clusterLocatorMethods: \"${type}\"`,\n );\n }\n });\n\n return new CombinedClustersSupplier(clusterSuppliers);\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 ClusterDetails,\n KubernetesClustersSupplier,\n KubernetesServiceLocator,\n} 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 clusterSupplier: KubernetesClustersSupplier;\n\n constructor(clusterSupplier: KubernetesClustersSupplier) {\n this.clusterSupplier = clusterSupplier;\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.clusterSupplier.getClusters();\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 FetchResponseWrapper,\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\ntype responseWithMetrics = [FetchResponseWrapper, PodStatus[][]];\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 const namespace =\n requestBody.entity?.metadata?.annotations?.[\n 'backstage.io/kubernetes-namespace'\n ];\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 namespace,\n })\n .then(result => this.getMetricsForPods(clusterDetailsItem, result))\n .then(r => this.toClusterObjects(clusterDetailsItem, r));\n }),\n ).then(this.toObjectsByEntityResponse);\n }\n\n toObjectsByEntityResponse(\n clusterObjects: ClusterObjects[],\n ): ObjectsByEntityResponse {\n return {\n items: clusterObjects.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 toClusterObjects(\n clusterDetails: ClusterDetails,\n [result, metrics]: responseWithMetrics,\n ): ClusterObjects {\n const objects: ClusterObjects = {\n cluster: {\n name: clusterDetails.name,\n },\n podMetrics: toClientSafePodMetrics(metrics),\n resources: result.responses,\n errors: result.errors,\n };\n if (clusterDetails.dashboardUrl) {\n objects.cluster.dashboardUrl = clusterDetails.dashboardUrl;\n }\n if (clusterDetails.dashboardApp) {\n objects.cluster.dashboardApp = clusterDetails.dashboardApp;\n }\n if (clusterDetails.dashboardParameters) {\n objects.cluster.dashboardParameters = clusterDetails.dashboardParameters;\n }\n return objects;\n }\n\n async getMetricsForPods(\n clusterDetails: ClusterDetails,\n result: FetchResponseWrapper,\n ): Promise<responseWithMetrics> {\n if (clusterDetails.skipMetricsLookup) {\n return [result, []];\n }\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(clusterDetails, ns),\n );\n\n return Promise.all([result, Promise.all(podMetrics)]);\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 params.namespace,\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 namespace?: string,\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 if (namespace) {\n return customObjects\n .listNamespacedCustomObject(\n resource.group,\n resource.apiVersion,\n namespace,\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 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 { Duration } from 'luxon';\nimport { getCombinedClusterSupplier } from '../cluster-locator';\nimport { MultiTenantServiceLocator } from '../service-locator/MultiTenantServiceLocator';\nimport {\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 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 defaultClusterRefreshInterval: Duration = Duration.fromObject({\n minutes: 60,\n });\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 =\n this.clusterSupplier ??\n this.buildClusterSupplier(this.defaultClusterRefreshInterval);\n\n const serviceLocator =\n this.serviceLocator ??\n this.buildServiceLocator(this.getServiceLocatorMethod(), clusterSupplier);\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, clusterSupplier);\n\n return {\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 setDefaultClusterRefreshInterval(refreshInterval: Duration) {\n this.defaultClusterRefreshInterval = refreshInterval;\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(\n refreshInterval: Duration,\n ): KubernetesClustersSupplier {\n const config = this.env.config;\n return getCombinedClusterSupplier(config, refreshInterval);\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 clusterSupplier: KubernetesClustersSupplier,\n ): KubernetesServiceLocator {\n switch (method) {\n case 'multiTenant':\n return this.buildMultiTenantServiceLocator(clusterSupplier);\n case 'http':\n return this.buildHttpServiceLocator(clusterSupplier);\n default:\n throw new Error(\n `Unsupported kubernetes.clusterLocatorMethod \"${method}\"`,\n );\n }\n }\n\n protected buildMultiTenantServiceLocator(\n clusterSupplier: KubernetesClustersSupplier,\n ): KubernetesServiceLocator {\n return new MultiTenantServiceLocator(clusterSupplier);\n }\n\n protected buildHttpServiceLocator(\n _clusterSupplier: KubernetesClustersSupplier,\n ): KubernetesServiceLocator {\n throw new Error('not implemented');\n }\n\n protected buildRouter(\n objectsProvider: KubernetesObjectsProvider,\n clusterSupplier: KubernetesClustersSupplier,\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 const clusterDetails = await this.fetchClusterDetails(clusterSupplier);\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","Duration","Router","express"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ import { JsonObject } from '@backstage/types';
4
4
  import { KubernetesFetchError, FetchResponse, KubernetesRequestBody, ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common';
5
5
  import { PodStatus } from '@kubernetes/client-node/dist/top';
6
6
  import express from 'express';
7
+ import { Duration } from 'luxon';
7
8
 
8
9
  interface ObjectFetchParams {
9
10
  serviceId: string;
@@ -11,6 +12,7 @@ interface ObjectFetchParams {
11
12
  objectTypesToFetch: Set<ObjectToFetch>;
12
13
  labelSelector: string;
13
14
  customResources: CustomResource[];
15
+ namespace?: string;
14
16
  }
15
17
  interface KubernetesFetcher {
16
18
  fetchObjectsForService(params: ObjectFetchParams): Promise<FetchResponseWrapper>;
@@ -31,6 +33,12 @@ interface CustomResource extends ObjectToFetch {
31
33
  }
32
34
  declare type KubernetesObjectTypes = 'pods' | 'services' | 'configmaps' | 'deployments' | 'replicasets' | 'horizontalpodautoscalers' | 'jobs' | 'cronjobs' | 'ingresses' | 'customresources';
33
35
  interface KubernetesClustersSupplier {
36
+ /**
37
+ * Returns the cached list of clusters.
38
+ *
39
+ * Implementations _should_ cache the clusters and refresh them periodically,
40
+ * as getClusters is called whenever the list of clusters is needed.
41
+ */
34
42
  getClusters(): Promise<ClusterDetails[]>;
35
43
  }
36
44
  interface KubernetesServiceLocator {
@@ -136,7 +144,6 @@ interface KubernetesEnvironment {
136
144
  */
137
145
  declare type KubernetesBuilderReturn = Promise<{
138
146
  router: express.Router;
139
- clusterDetails: ClusterDetails[];
140
147
  clusterSupplier: KubernetesClustersSupplier;
141
148
  customResources: CustomResource[];
142
149
  fetcher: KubernetesFetcher;
@@ -146,6 +153,7 @@ declare type KubernetesBuilderReturn = Promise<{
146
153
  declare class KubernetesBuilder {
147
154
  protected readonly env: KubernetesEnvironment;
148
155
  private clusterSupplier?;
156
+ private defaultClusterRefreshInterval;
149
157
  private objectsProvider?;
150
158
  private fetcher?;
151
159
  private serviceLocator?;
@@ -153,17 +161,18 @@ declare class KubernetesBuilder {
153
161
  constructor(env: KubernetesEnvironment);
154
162
  build(): KubernetesBuilderReturn;
155
163
  setClusterSupplier(clusterSupplier?: KubernetesClustersSupplier): this;
164
+ setDefaultClusterRefreshInterval(refreshInterval: Duration): this;
156
165
  setObjectsProvider(objectsProvider?: KubernetesObjectsProvider): this;
157
166
  setFetcher(fetcher?: KubernetesFetcher): this;
158
167
  setServiceLocator(serviceLocator?: KubernetesServiceLocator): this;
159
168
  protected buildCustomResources(): CustomResource[];
160
- protected buildClusterSupplier(): KubernetesClustersSupplier;
169
+ protected buildClusterSupplier(refreshInterval: Duration): KubernetesClustersSupplier;
161
170
  protected buildObjectsProvider(options: KubernetesObjectsProviderOptions): KubernetesObjectsProvider;
162
171
  protected buildFetcher(): KubernetesFetcher;
163
- protected buildServiceLocator(method: ServiceLocatorMethod, clusterDetails: ClusterDetails[]): KubernetesServiceLocator;
164
- protected buildMultiTenantServiceLocator(clusterDetails: ClusterDetails[]): KubernetesServiceLocator;
165
- protected buildHttpServiceLocator(_clusterDetails: ClusterDetails[]): KubernetesServiceLocator;
166
- protected buildRouter(objectsProvider: KubernetesObjectsProvider, clusterDetails: ClusterDetails[]): express.Router;
172
+ protected buildServiceLocator(method: ServiceLocatorMethod, clusterSupplier: KubernetesClustersSupplier): KubernetesServiceLocator;
173
+ protected buildMultiTenantServiceLocator(clusterSupplier: KubernetesClustersSupplier): KubernetesServiceLocator;
174
+ protected buildHttpServiceLocator(_clusterSupplier: KubernetesClustersSupplier): KubernetesServiceLocator;
175
+ protected buildRouter(objectsProvider: KubernetesObjectsProvider, clusterSupplier: KubernetesClustersSupplier): express.Router;
167
176
  protected fetchClusterDetails(clusterSupplier: KubernetesClustersSupplier): Promise<ClusterDetails[]>;
168
177
  protected getServiceLocatorMethod(): ServiceLocatorMethod;
169
178
  protected getObjectTypesToFetch(): ObjectToFetch[] | undefined;
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.14-next.0",
4
+ "version": "0.5.1-next.0",
5
5
  "main": "dist/index.cjs.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "license": "Apache-2.0",
@@ -35,38 +35,39 @@
35
35
  "clean": "backstage-cli package clean"
36
36
  },
37
37
  "dependencies": {
38
- "@backstage/backend-common": "^0.13.2-next.0",
39
- "@backstage/catalog-model": "^1.0.1-next.0",
38
+ "@backstage/backend-common": "^0.13.3-next.0",
39
+ "@backstage/catalog-model": "^1.0.1",
40
40
  "@backstage/config": "^1.0.0",
41
41
  "@backstage/errors": "^1.0.0",
42
- "@backstage/plugin-kubernetes-common": "^0.2.9-next.0",
42
+ "@backstage/plugin-kubernetes-common": "^0.2.9",
43
43
  "@google-cloud/container": "^3.0.0",
44
44
  "@kubernetes/client-node": "^0.16.0",
45
45
  "@types/express": "^4.17.6",
46
+ "@types/luxon": "^2.0.4",
46
47
  "aws-sdk": "^2.840.0",
47
48
  "aws4": "^1.11.0",
48
49
  "compression": "^1.7.4",
49
50
  "cors": "^2.8.5",
50
51
  "express": "^4.17.1",
51
52
  "express-promise-router": "^4.1.0",
52
- "fs-extra": "10.0.1",
53
+ "fs-extra": "10.1.0",
53
54
  "helmet": "^5.0.2",
54
55
  "lodash": "^4.17.21",
56
+ "luxon": "^2.0.2",
55
57
  "morgan": "^1.10.0",
56
58
  "stream-buffers": "^3.0.2",
57
59
  "winston": "^3.2.1",
58
60
  "yn": "^4.0.0"
59
61
  },
60
62
  "devDependencies": {
61
- "@backstage/cli": "^0.16.1-next.0",
63
+ "@backstage/cli": "^0.17.1-next.0",
62
64
  "@types/aws4": "^1.5.1",
63
65
  "aws-sdk-mock": "^5.2.1",
64
- "bdd-lazy-var": "^2.6.0",
65
66
  "supertest": "^6.1.3"
66
67
  },
67
68
  "files": [
68
69
  "dist",
69
70
  "schema.d.ts"
70
71
  ],
71
- "gitHead": "6bc4253672337538ce7ea5aadb3e9f60daeb3f80"
72
+ "gitHead": "88ee375f5ee44b7a7917297785ddf88691fe3381"
72
73
  }