Merge pull request #24006 from backstage/blam/k8s-cluster-fix

kubernetes: fixing credentials propagation for cluster suppliers
This commit is contained in:
Ben Lambert
2024-04-09 10:23:31 +02:00
committed by GitHub
14 changed files with 325 additions and 159 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-kubernetes-backend': patch
'@backstage/plugin-kubernetes-node': patch
---
Fixing issue where `BackstageCredentials` were not properly forwarded for all calls
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-kubernetes-backend': minor
---
**BREAKING**: `KubernetesProxy` now requires the `DiscoveryService` to be passed to the constuctor
+8 -1
View File
@@ -26,6 +26,7 @@ import { KubernetesServiceLocator as KubernetesServiceLocator_2 } from '@backsta
import { Logger } from 'winston';
import { ObjectToFetch as ObjectToFetch_2 } from '@backstage/plugin-kubernetes-node';
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
import { PermissionsService } from '@backstage/backend-plugin-api';
import { PluginEndpointDiscovery } from '@backstage/backend-common';
import { RequestHandler } from 'http-proxy-middleware';
import { TokenCredential } from '@azure/identity';
@@ -190,6 +191,8 @@ export class KubernetesBuilder {
protected buildProxy(
logger: Logger,
clusterSupplier: KubernetesClustersSupplier_2,
discovery: DiscoveryService,
httpAuth: HttpAuthService,
): KubernetesProxy;
// (undocumented)
protected buildRouter(
@@ -239,6 +242,8 @@ export class KubernetesBuilder {
protected getProxy(
logger: Logger,
clusterSupplier: KubernetesClustersSupplier_2,
discovery: DiscoveryService,
httpAuth: HttpAuthService,
): KubernetesProxy;
// (undocumented)
protected getServiceLocator(): KubernetesServiceLocator_2;
@@ -337,7 +342,7 @@ export class KubernetesProxy {
// @public
export type KubernetesProxyCreateRequestHandlerOptions = {
permissionApi: PermissionEvaluator;
permissionApi: PermissionsService;
};
// @public
@@ -345,6 +350,8 @@ export type KubernetesProxyOptions = {
logger: Logger;
clusterSupplier: KubernetesClustersSupplier;
authStrategy: AuthenticationStrategy;
discovery: DiscoveryService;
httpAuth?: HttpAuthService;
};
// @public @deprecated (undocumented)
@@ -63,10 +63,13 @@ export const addResourceRoutesToRouter = (
router.post('/resources/workloads/query', async (req, res) => {
const entity = await getEntityByReq(req);
const response = await objectsProvider.getKubernetesObjectsByEntity({
entity,
auth: req.body.auth,
});
const response = await objectsProvider.getKubernetesObjectsByEntity(
{
entity,
auth: req.body.auth,
},
{ credentials: await httpAuth.credentials(req) },
);
res.json(response);
});
@@ -81,11 +84,14 @@ export const addResourceRoutesToRouter = (
throw new InputError('at least 1 customResource is required');
}
const response = await objectsProvider.getCustomResourcesByEntity({
entity,
customResources: req.body.customResources,
auth: req.body.auth,
});
const response = await objectsProvider.getCustomResourcesByEntity(
{
entity,
customResources: req.body.customResources,
auth: req.body.auth,
},
{ credentials: await httpAuth.credentials(req) },
);
res.json(response);
});
};
@@ -33,7 +33,7 @@ export class CatalogRelationServiceLocator implements KubernetesServiceLocator {
// As this implementation always returns all clusters serviceId is ignored here
getClustersByEntity(
entity: Entity,
_requestContext: ServiceLocatorRequestContext,
requestContext: ServiceLocatorRequestContext,
): Promise<{ clusters: ClusterDetails[] }> {
if (
entity.relations &&
@@ -41,13 +41,15 @@ export class CatalogRelationServiceLocator implements KubernetesServiceLocator {
r => r.type === 'dependsOn' && r.targetRef.includes('resource:'),
)
) {
return this.clusterSupplier.getClusters().then(clusters => {
return {
clusters: clusters.filter(c =>
this.doesEntityDependOnCluster(entity, c),
),
};
});
return this.clusterSupplier
.getClusters({ credentials: requestContext.credentials })
.then(clusters => {
return {
clusters: clusters.filter(c =>
this.doesEntityDependOnCluster(entity, c),
),
};
});
}
return Promise.resolve({ clusters: [] });
}
@@ -34,8 +34,10 @@ export class MultiTenantServiceLocator implements KubernetesServiceLocator {
// As this implementation always returns all clusters serviceId is ignored here
getClustersByEntity(
_entity: Entity,
_requestContext: ServiceLocatorRequestContext,
requestContext: ServiceLocatorRequestContext,
): Promise<{ clusters: ClusterDetails[] }> {
return this.clusterSupplier.getClusters().then(clusters => ({ clusters }));
return this.clusterSupplier
.getClusters({ credentials: requestContext.credentials })
.then(clusters => ({ clusters }));
}
}
@@ -34,21 +34,25 @@ export class SingleTenantServiceLocator implements KubernetesServiceLocator {
// As this implementation always returns all clusters serviceId is ignored here
getClustersByEntity(
_entity: Entity,
_requestContext: ServiceLocatorRequestContext,
requestContext: ServiceLocatorRequestContext,
): Promise<{ clusters: ClusterDetails[] }> {
return this.clusterSupplier.getClusters().then(clusters => {
if (_entity.metadata?.annotations?.['backstage.io/kubernetes-cluster']) {
return {
clusters: clusters.filter(
c =>
c.name ===
_entity.metadata?.annotations?.[
'backstage.io/kubernetes-cluster'
],
),
};
}
return { clusters };
});
return this.clusterSupplier
.getClusters({ credentials: requestContext.credentials })
.then(clusters => {
if (
_entity.metadata?.annotations?.['backstage.io/kubernetes-cluster']
) {
return {
clusters: clusters.filter(
c =>
c.name ===
_entity.metadata?.annotations?.[
'backstage.io/kubernetes-cluster'
],
),
};
}
return { clusters };
});
}
}
@@ -157,7 +157,12 @@ export class KubernetesBuilder {
const authStrategyMap = this.getAuthStrategyMap();
const proxy = this.getProxy(logger, clusterSupplier);
const proxy = this.getProxy(
logger,
clusterSupplier,
this.env.discovery,
httpAuth,
);
const serviceLocator = this.getServiceLocator();
@@ -350,6 +355,8 @@ export class KubernetesBuilder {
protected buildProxy(
logger: Logger,
clusterSupplier: KubernetesClustersSupplier,
discovery: DiscoveryService,
httpAuth: HttpAuthService,
): KubernetesProxy {
const authStrategyMap = this.getAuthStrategyMap();
const authStrategy = new DispatchStrategy({
@@ -359,6 +366,8 @@ export class KubernetesBuilder {
logger,
clusterSupplier,
authStrategy,
discovery,
httpAuth,
});
return this.proxy;
}
@@ -386,10 +395,13 @@ export class KubernetesBuilder {
const serviceId = req.params.serviceId;
const requestBody: ObjectsByEntityRequest = req.body;
try {
const response = await objectsProvider.getKubernetesObjectsByEntity({
entity: requestBody.entity,
auth: requestBody.auth || {},
});
const response = await objectsProvider.getKubernetesObjectsByEntity(
{
entity: requestBody.entity,
auth: requestBody.auth || {},
},
{ credentials: await httpAuth.credentials(req) },
);
res.json(response);
} catch (e) {
logger.error(
@@ -530,8 +542,13 @@ export class KubernetesBuilder {
protected getProxy(
logger: Logger,
clusterSupplier: KubernetesClustersSupplier,
discovery: DiscoveryService,
httpAuth: HttpAuthService,
) {
return this.proxy ?? this.buildProxy(logger, clusterSupplier);
return (
this.proxy ??
this.buildProxy(logger, clusterSupplier, discovery, httpAuth)
);
}
protected getAuthStrategyMap() {
@@ -35,6 +35,7 @@ import {
} from '@backstage/plugin-kubernetes-common';
import { Config, ConfigReader } from '@backstage/config';
import { Entity } from '@backstage/catalog-model';
import { BackstageCredentials } from '@backstage/backend-plugin-api';
describe('KubernetesFanOutHandler', () => {
const fetchObjectsForService = jest.fn();
@@ -62,6 +63,14 @@ describe('KubernetesFanOutHandler', () => {
pod: {},
};
const mockCredentials: BackstageCredentials = {
$$type: '@backstage/BackstageCredentials',
principal: {
userEntityRef: 'user:default/guest',
type: 'user',
},
};
const entity = {
apiVersion: 'backstage.io/v1beta1',
kind: 'Component',
@@ -372,10 +381,13 @@ describe('KubernetesFanOutHandler', () => {
sut = getKubernetesFanOutHandler([]);
const result = await sut.getKubernetesObjectsByEntity({
entity,
auth: {},
});
const result = await sut.getKubernetesObjectsByEntity(
{
entity,
auth: {},
},
{ credentials: mockCredentials },
);
expect(getClustersByEntity).toHaveBeenCalledTimes(1);
expect(fetchObjectsForService).toHaveBeenCalledTimes(1);
@@ -410,10 +422,13 @@ describe('KubernetesFanOutHandler', () => {
sut = getKubernetesFanOutHandler([]);
await sut.getKubernetesObjectsByEntity({
entity,
auth: {},
});
await sut.getKubernetesObjectsByEntity(
{
entity,
auth: {},
},
{ credentials: mockCredentials },
);
expect(fetchObjectsForService).toHaveBeenCalledTimes(1);
expect(
@@ -442,10 +457,13 @@ describe('KubernetesFanOutHandler', () => {
sut = getKubernetesFanOutHandler([]);
await sut.getKubernetesObjectsByEntity({
entity,
auth: {},
});
await sut.getKubernetesObjectsByEntity(
{
entity,
auth: {},
},
{ credentials: mockCredentials },
);
expect(fetchObjectsForService).toHaveBeenCalledTimes(2);
expect(fetchObjectsForService).toHaveBeenCalledWith(
@@ -497,10 +515,13 @@ describe('KubernetesFanOutHandler', () => {
},
]);
await sut.getKubernetesObjectsByEntity({
entity,
auth: {},
});
await sut.getKubernetesObjectsByEntity(
{
entity,
auth: {},
},
{ credentials: mockCredentials },
);
expect(fetchObjectsForService).toHaveBeenCalledTimes(2);
expect(fetchObjectsForService).toHaveBeenCalledWith(
@@ -559,10 +580,13 @@ describe('KubernetesFanOutHandler', () => {
},
]);
await sut.getKubernetesObjectsByEntity({
entity,
auth: {},
});
await sut.getKubernetesObjectsByEntity(
{
entity,
auth: {},
},
{ credentials: mockCredentials },
);
expect(fetchObjectsForService).toHaveBeenCalledWith(
expect.objectContaining({
@@ -600,10 +624,13 @@ describe('KubernetesFanOutHandler', () => {
},
]);
await sut.getKubernetesObjectsByEntity({
entity,
auth: {},
});
await sut.getKubernetesObjectsByEntity(
{
entity,
auth: {},
},
{ credentials: mockCredentials },
);
expect(fetchObjectsForService).toHaveBeenCalledWith(
expect.objectContaining({
@@ -665,10 +692,13 @@ describe('KubernetesFanOutHandler', () => {
sut = getKubernetesFanOutHandler([]);
const result = await sut.getKubernetesObjectsByEntity({
entity,
auth: {},
});
const result = await sut.getKubernetesObjectsByEntity(
{
entity,
auth: {},
},
{ credentials: mockCredentials },
);
expect(getClustersByEntity).toHaveBeenCalledTimes(1);
expect(fetchObjectsForService).toHaveBeenCalledTimes(1);
@@ -744,10 +774,13 @@ describe('KubernetesFanOutHandler', () => {
sut = getKubernetesFanOutHandler([]);
const result = await sut.getKubernetesObjectsByEntity({
entity,
auth: {},
});
const result = await sut.getKubernetesObjectsByEntity(
{
entity,
auth: {},
},
{ credentials: mockCredentials },
);
expect(getClustersByEntity).toHaveBeenCalledTimes(1);
expect(fetchObjectsForService).toHaveBeenCalledTimes(1);
@@ -779,12 +812,15 @@ describe('KubernetesFanOutHandler', () => {
sut = getKubernetesFanOutHandler([]);
const result = await sut.getKubernetesObjectsByEntity({
entity,
auth: {
google: 'google_token_123',
const result = await sut.getKubernetesObjectsByEntity(
{
entity,
auth: {
google: 'google_token_123',
},
},
});
{ credentials: mockCredentials },
);
expect(getClustersByEntity).toHaveBeenCalledTimes(1);
expect(fetchObjectsForService).toHaveBeenCalledTimes(2);
@@ -836,12 +872,15 @@ describe('KubernetesFanOutHandler', () => {
sut = getKubernetesFanOutHandler([]);
const result = await sut.getKubernetesObjectsByEntity({
entity,
auth: {
google: 'google_token_123',
const result = await sut.getKubernetesObjectsByEntity(
{
entity,
auth: {
google: 'google_token_123',
},
},
});
{ credentials: mockCredentials },
);
expect(getClustersByEntity).toHaveBeenCalledTimes(1);
expect(fetchObjectsForService).toHaveBeenCalledTimes(3);
@@ -897,12 +936,15 @@ describe('KubernetesFanOutHandler', () => {
sut = getKubernetesFanOutHandler([]);
const result = await sut.getKubernetesObjectsByEntity({
entity,
auth: {
google: 'google_token_123',
const result = await sut.getKubernetesObjectsByEntity(
{
entity,
auth: {
google: 'google_token_123',
},
},
});
{ credentials: mockCredentials },
);
expect(getClustersByEntity).toHaveBeenCalledTimes(1);
expect(fetchObjectsForService).toHaveBeenCalledTimes(4);
@@ -1015,12 +1057,15 @@ describe('KubernetesFanOutHandler', () => {
sut = getKubernetesFanOutHandler([]);
const result = await sut.getKubernetesObjectsByEntity({
entity,
auth: {
google: 'google_token_123',
const result = await sut.getKubernetesObjectsByEntity(
{
entity,
auth: {
google: 'google_token_123',
},
},
});
{ credentials: mockCredentials },
);
expect(getClustersByEntity).toHaveBeenCalledTimes(1);
expect(fetchObjectsForService).toHaveBeenCalledTimes(2);
@@ -1069,10 +1114,13 @@ describe('KubernetesFanOutHandler', () => {
sut = getKubernetesFanOutHandler([]);
const result = sut.getKubernetesObjectsByEntity({
entity,
auth: {},
});
const result = sut.getKubernetesObjectsByEntity(
{
entity,
auth: {},
},
{ credentials: mockCredentials },
);
await expect(result).rejects.toThrow(nonFetchError);
});
@@ -1155,10 +1203,13 @@ describe('KubernetesFanOutHandler', () => {
});
const result =
await kubernetesFanOutHandler.getKubernetesObjectsByEntity({
entity,
auth: {},
});
await kubernetesFanOutHandler.getKubernetesObjectsByEntity(
{
entity,
auth: {},
},
{ credentials: mockCredentials },
);
const expected: ObjectsByEntityResponse = {
items: [
@@ -1200,17 +1251,20 @@ describe('KubernetesFanOutHandler', () => {
sut = getKubernetesFanOutHandler([]);
await sut.getCustomResourcesByEntity({
entity,
auth: {},
customResources: [
{
group: 'parameter-crd.example.com',
apiVersion: 'v1alpha1',
plural: 'parameter-crd',
},
],
});
await sut.getCustomResourcesByEntity(
{
entity,
auth: {},
customResources: [
{
group: 'parameter-crd.example.com',
apiVersion: 'v1alpha1',
plural: 'parameter-crd',
},
],
},
{ credentials: mockCredentials },
);
expect(fetchObjectsForService).toHaveBeenCalledTimes(1);
expect(fetchObjectsForService).toHaveBeenCalledWith(
@@ -1262,17 +1316,20 @@ describe('KubernetesFanOutHandler', () => {
},
]);
await sut.getCustomResourcesByEntity({
entity,
auth: {},
customResources: [
{
group: 'parameter-crd.example.com',
apiVersion: 'v1alpha1',
plural: 'parameter-crd',
},
],
});
await sut.getCustomResourcesByEntity(
{
entity,
auth: {},
customResources: [
{
group: 'parameter-crd.example.com',
apiVersion: 'v1alpha1',
plural: 'parameter-crd',
},
],
},
{ credentials: mockCredentials },
);
expect(fetchObjectsForService).toHaveBeenCalledTimes(2);
expect(fetchObjectsForService).toHaveBeenCalledWith(
@@ -1329,17 +1386,20 @@ describe('KubernetesFanOutHandler', () => {
sut = getKubernetesFanOutHandler([]);
await sut.getCustomResourcesByEntity({
entity,
auth: {},
customResources: [
{
group: 'parameter-crd.example.com',
apiVersion: 'v1alpha1',
plural: 'parameter-crd',
},
],
});
await sut.getCustomResourcesByEntity(
{
entity,
auth: {},
customResources: [
{
group: 'parameter-crd.example.com',
apiVersion: 'v1alpha1',
plural: 'parameter-crd',
},
],
},
{ credentials: mockCredentials },
);
expect(fetchObjectsForService).toHaveBeenCalledWith(
expect.objectContaining({
@@ -48,7 +48,9 @@ import {
CustomResourcesByEntity,
KubernetesCredential,
KubernetesObjectsByEntity,
KubernetesObjectsProvider,
} from '@backstage/plugin-kubernetes-node';
import { BackstageCredentials } from '@backstage/backend-plugin-api';
/**
*
@@ -190,7 +192,7 @@ const toClientSafePodMetrics = (
type responseWithMetrics = [FetchResponseWrapper, PodStatusFetchResponse[]];
export class KubernetesFanOutHandler {
export class KubernetesFanOutHandler implements KubernetesObjectsProvider {
private readonly logger: Logger;
private readonly fetcher: KubernetesFetcher;
private readonly serviceLocator: KubernetesServiceLocator;
@@ -214,30 +216,38 @@ export class KubernetesFanOutHandler {
this.authStrategy = authStrategy;
}
async getCustomResourcesByEntity({
entity,
auth,
customResources,
}: CustomResourcesByEntity): Promise<ObjectsByEntityResponse> {
async getCustomResourcesByEntity(
{ entity, auth, customResources }: CustomResourcesByEntity,
options: { credentials: BackstageCredentials },
): Promise<ObjectsByEntityResponse> {
// Don't fetch the default object types only the provided custom resources
return this.fanOutRequests(
entity,
auth,
{ credentials: options.credentials },
new Set<ObjectToFetch>(),
customResources,
);
}
async getKubernetesObjectsByEntity({
entity,
auth,
}: KubernetesObjectsByEntity): Promise<ObjectsByEntityResponse> {
return this.fanOutRequests(entity, auth, this.objectTypesToFetch);
async getKubernetesObjectsByEntity(
{ entity, auth }: KubernetesObjectsByEntity,
options: { credentials: BackstageCredentials },
): Promise<ObjectsByEntityResponse> {
return this.fanOutRequests(
entity,
auth,
{
credentials: options.credentials,
},
this.objectTypesToFetch,
);
}
private async fanOutRequests(
entity: Entity,
auth: KubernetesRequestAuth,
options: { credentials: BackstageCredentials },
objectTypesToFetch: Set<ObjectToFetch>,
customResources?: CustomResourceMatcher[],
) {
@@ -248,6 +258,7 @@ export class KubernetesFanOutHandler {
const { clusters } = await this.serviceLocator.getClustersByEntity(entity, {
objectTypesToFetch: objectTypesToFetch,
customResources: customResources ?? [],
credentials: options.credentials,
});
this.logger.info(
@@ -55,6 +55,10 @@ import {
} from './KubernetesProxy';
import type { Request } from 'express';
import {
BackstageCredentials,
DiscoveryService,
} from '@backstage/backend-plugin-api';
const mockCertDir = createMockDirectory({
content: {
@@ -69,7 +73,10 @@ describe('KubernetesProxy', () => {
const logger = getVoidLogger();
const clusterSupplier: jest.Mocked<KubernetesClustersSupplier> = {
getClusters: jest.fn<Promise<ClusterDetails[]>, []>(),
getClusters: jest.fn<
Promise<ClusterDetails[]>,
[{ credentials: BackstageCredentials }]
>(),
};
const permissionApi: jest.Mocked<PermissionEvaluator> = {
@@ -77,6 +84,11 @@ describe('KubernetesProxy', () => {
authorizeConditional: jest.fn(),
};
const mockDisocveryApi: jest.Mocked<DiscoveryService> = {
getBaseUrl: jest.fn(),
getExternalBaseUrl: jest.fn(),
};
setupRequestMockHandlers(worker);
const buildMockRequest = (clusterName: any, path: string): Request => {
@@ -146,7 +158,12 @@ describe('KubernetesProxy', () => {
validateCluster: jest.fn(),
presentAuthMetadata: jest.fn(),
};
proxy = new KubernetesProxy({ logger, clusterSupplier, authStrategy });
proxy = new KubernetesProxy({
logger,
clusterSupplier,
authStrategy,
discovery: mockDisocveryApi,
});
permissionApi.authorize.mockResolvedValue([
{ result: AuthorizeResult.ALLOW },
]);
@@ -535,6 +552,7 @@ describe('KubernetesProxy', () => {
logger: getVoidLogger(),
clusterSupplier: clusterSupplier,
authStrategy: strategy,
discovery: mockDisocveryApi,
});
worker.use(
@@ -656,6 +674,7 @@ describe('KubernetesProxy', () => {
logger: getVoidLogger(),
clusterSupplier: new LocalKubectlProxyClusterLocator(),
authStrategy: new AnonymousStrategy(),
discovery: mockDisocveryApi,
});
worker.use(
@@ -20,16 +20,12 @@ import {
NotFoundError,
serializeError,
} from '@backstage/errors';
import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node';
import {
ANNOTATION_KUBERNETES_AUTH_PROVIDER,
KubernetesRequestAuth,
kubernetesProxyPermission,
} from '@backstage/plugin-kubernetes-common';
import {
AuthorizeResult,
PermissionEvaluator,
} from '@backstage/plugin-permission-common';
import { AuthorizeResult } from '@backstage/plugin-permission-common';
import {
Cluster,
KubeConfig,
@@ -45,6 +41,12 @@ import { ClusterDetails, KubernetesClustersSupplier } from '../types/types';
import type { Request } from 'express';
import { IncomingHttpHeaders } from 'http';
import {
DiscoveryService,
HttpAuthService,
PermissionsService,
} from '@backstage/backend-plugin-api';
import { createLegacyAuthAdapters } from '@backstage/backend-common';
export const APPLICATION_JSON: string = 'application/json';
@@ -69,7 +71,7 @@ export const HEADER_KUBERNETES_AUTH: string =
* @public
*/
export type KubernetesProxyCreateRequestHandlerOptions = {
permissionApi: PermissionEvaluator;
permissionApi: PermissionsService;
};
/**
@@ -81,6 +83,8 @@ export type KubernetesProxyOptions = {
logger: Logger;
clusterSupplier: KubernetesClustersSupplier;
authStrategy: AuthenticationStrategy;
discovery: DiscoveryService;
httpAuth?: HttpAuthService;
};
/**
@@ -93,11 +97,19 @@ export class KubernetesProxy {
private readonly logger: Logger;
private readonly clusterSupplier: KubernetesClustersSupplier;
private readonly authStrategy: AuthenticationStrategy;
private readonly httpAuth: HttpAuthService;
constructor(options: KubernetesProxyOptions) {
this.logger = options.logger;
this.clusterSupplier = options.clusterSupplier;
this.authStrategy = options.authStrategy;
const legacy = createLegacyAuthAdapters({
discovery: options.discovery,
httpAuth: options.httpAuth,
});
this.httpAuth = legacy.httpAuth;
}
public createRequestHandler(
@@ -108,9 +120,7 @@ export class KubernetesProxy {
const authorizeResponse = await permissionApi.authorize(
[{ permission: kubernetesProxyPermission }],
{
token: getBearerTokenFromAuthorizationHeader(
req.header('authorization'),
),
credentials: await this.httpAuth.credentials(req),
},
);
const auth = authorizeResponse[0];
@@ -220,7 +230,9 @@ export class KubernetesProxy {
private async getClusterForRequest(req: Request): Promise<ClusterDetails> {
const clusterName = req.headers[HEADER_KUBERNETES_CLUSTER.toLowerCase()];
const clusters = await this.clusterSupplier.getClusters();
const clusters = await this.clusterSupplier.getClusters({
credentials: await this.httpAuth.credentials(req),
});
if (!clusters || clusters.length <= 0) {
throw new NotFoundError(`No Clusters configured`);
+9 -1
View File
@@ -88,7 +88,7 @@ export const kubernetesAuthStrategyExtensionPoint: ExtensionPoint<KubernetesAuth
// @public
export interface KubernetesClustersSupplier {
getClusters(options?: {
getClusters(options: {
credentials: BackstageCredentials;
}): Promise<ClusterDetails[]>;
}
@@ -154,10 +154,16 @@ export interface KubernetesObjectsProvider {
// (undocumented)
getCustomResourcesByEntity(
customResourcesByEntity: CustomResourcesByEntity,
options: {
credentials: BackstageCredentials;
},
): Promise<ObjectsByEntityResponse>;
// (undocumented)
getKubernetesObjectsByEntity(
kubernetesObjectsByEntity: KubernetesObjectsByEntity,
options: {
credentials: BackstageCredentials;
},
): Promise<ObjectsByEntityResponse>;
}
@@ -269,6 +275,8 @@ export type PinnipedParameters = {
// @public (undocumented)
export interface ServiceLocatorRequestContext {
// (undocumented)
credentials: BackstageCredentials;
// (undocumented)
customResources: CustomResourceMatcher[];
// (undocumented)
+8 -1
View File
@@ -32,9 +32,15 @@ import { JsonObject } from '@backstage/types';
export interface KubernetesObjectsProvider {
getKubernetesObjectsByEntity(
kubernetesObjectsByEntity: KubernetesObjectsByEntity,
options: {
credentials: BackstageCredentials;
},
): Promise<ObjectsByEntityResponse>;
getCustomResourcesByEntity(
customResourcesByEntity: CustomResourcesByEntity,
options: {
credentials: BackstageCredentials;
},
): Promise<ObjectsByEntityResponse>;
}
@@ -135,7 +141,7 @@ export interface KubernetesClustersSupplier {
* Implementations _should_ cache the clusters and refresh them periodically,
* as getClusters is called whenever the list of clusters is needed.
*/
getClusters(options?: {
getClusters(options: {
credentials: BackstageCredentials;
}): Promise<ClusterDetails[]>;
}
@@ -248,6 +254,7 @@ export interface KubernetesFetcher {
export interface ServiceLocatorRequestContext {
objectTypesToFetch: Set<ObjectToFetch>;
customResources: CustomResourceMatcher[];
credentials: BackstageCredentials;
}
/**