split service locator and cluster locators (#2900)
* split service locator and cluster locators * fix test
This commit is contained in:
+3
-1
@@ -60,7 +60,9 @@ lighthouse:
|
||||
baseUrl: http://localhost:3003
|
||||
|
||||
kubernetes:
|
||||
clusterLocatorMethod: 'configMultiTenant'
|
||||
serviceLocatorMethod: 'multiTenant'
|
||||
clusterLocatorMethods:
|
||||
- 'config'
|
||||
clusters: []
|
||||
|
||||
integrations:
|
||||
|
||||
@@ -8,21 +8,33 @@ It responds to Kubernetes requests from the frontend.
|
||||
|
||||
## Configuration
|
||||
|
||||
### clusterLocatorMethod
|
||||
### serviceLocatorMethod
|
||||
|
||||
This configures how to determine which clusters a component is running in.
|
||||
|
||||
Currently, the only valid locator method is:
|
||||
Currently, the only valid serviceLocatorMethod is:
|
||||
|
||||
#### configMultiTenant
|
||||
#### multiTenant
|
||||
|
||||
This configuration assumes that all components run on all the provided clusters.
|
||||
|
||||
### clusterLocatorMethods
|
||||
|
||||
This is used to determine where to retrieve cluster configuration from.
|
||||
|
||||
Currently, the only valid serviceLocatorMethod is:
|
||||
|
||||
#### config
|
||||
|
||||
This clusterLocatorMethod will read cluster information in from config
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
kubernetes:
|
||||
clusterLocatorMethod: 'configMultiTenant'
|
||||
serviceLocatorMethod: 'multiTenant'
|
||||
clusterLocatorMethods:
|
||||
- 'config'
|
||||
clusters:
|
||||
- url: http://127.0.0.1:9999
|
||||
name: minikube
|
||||
@@ -35,7 +47,7 @@ kubernetes:
|
||||
|
||||
##### clusters
|
||||
|
||||
Used by the `configMultiTenant` `clusterLocatorMethod` to construct Kubernetes clients.
|
||||
Used by the `config` `clusterLocatorMethods` to construct Kubernetes clients.
|
||||
|
||||
###### url
|
||||
|
||||
|
||||
@@ -27,7 +27,9 @@ Update `app-config.development.yaml` as follows.
|
||||
|
||||
```yaml
|
||||
kubernetes:
|
||||
clusterLocatorMethod: 'configMultiTenant'
|
||||
serviceLocatorMethod: 'multiTenant'
|
||||
clusterLocatorMethods:
|
||||
- 'config'
|
||||
clusters:
|
||||
- url: <KUBERNETES MASTER BASE URL FROM STEP 2>
|
||||
name: minikube
|
||||
|
||||
+8
-8
@@ -15,10 +15,10 @@
|
||||
*/
|
||||
|
||||
import '@backstage/backend-common';
|
||||
import { MultiTenantConfigClusterLocator } from './MultiTenantConfigClusterLocator';
|
||||
import { ConfigReader, Config } from '@backstage/config';
|
||||
import { ConfigClusterLocator } from './ConfigClusterLocator';
|
||||
|
||||
describe('MultiTenantConfigClusterLocator', () => {
|
||||
describe('ConfigClusterLocator', () => {
|
||||
it('empty clusters returns empty cluster details', async () => {
|
||||
const config: Config = new ConfigReader(
|
||||
{
|
||||
@@ -27,11 +27,11 @@ describe('MultiTenantConfigClusterLocator', () => {
|
||||
'ctx',
|
||||
);
|
||||
|
||||
const sut = MultiTenantConfigClusterLocator.fromConfig(
|
||||
const sut = ConfigClusterLocator.fromConfig(
|
||||
config.getConfigArray('clusters'),
|
||||
);
|
||||
|
||||
const result = await sut.getClusterByServiceId('ignored');
|
||||
const result = await sut.getClusters();
|
||||
|
||||
expect(result).toStrictEqual([]);
|
||||
});
|
||||
@@ -50,11 +50,11 @@ describe('MultiTenantConfigClusterLocator', () => {
|
||||
'ctx',
|
||||
);
|
||||
|
||||
const sut = MultiTenantConfigClusterLocator.fromConfig(
|
||||
const sut = ConfigClusterLocator.fromConfig(
|
||||
config.getConfigArray('clusters'),
|
||||
);
|
||||
|
||||
const result = await sut.getClusterByServiceId('ignored');
|
||||
const result = await sut.getClusters();
|
||||
|
||||
expect(result).toStrictEqual([
|
||||
{
|
||||
@@ -86,11 +86,11 @@ describe('MultiTenantConfigClusterLocator', () => {
|
||||
'ctx',
|
||||
);
|
||||
|
||||
const sut = MultiTenantConfigClusterLocator.fromConfig(
|
||||
const sut = ConfigClusterLocator.fromConfig(
|
||||
config.getConfigArray('clusters'),
|
||||
);
|
||||
|
||||
const result = await sut.getClusterByServiceId('ignored');
|
||||
const result = await sut.getClusters();
|
||||
|
||||
expect(result).toStrictEqual([
|
||||
{
|
||||
+5
-10
@@ -14,23 +14,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ClusterDetails, KubernetesClustersSupplier } from '..';
|
||||
import { Config } from '@backstage/config';
|
||||
import { ClusterDetails, KubernetesClusterLocator } from '..';
|
||||
|
||||
// This cluster locator assumes that every service is located on every cluster
|
||||
// Therefore it will always return all clusters in an app configuration file
|
||||
export class MultiTenantConfigClusterLocator
|
||||
implements KubernetesClusterLocator {
|
||||
export class ConfigClusterLocator implements KubernetesClustersSupplier {
|
||||
private readonly clusterDetails: ClusterDetails[];
|
||||
|
||||
constructor(clusterDetails: ClusterDetails[]) {
|
||||
this.clusterDetails = clusterDetails;
|
||||
}
|
||||
|
||||
static fromConfig(config: Config[]): MultiTenantConfigClusterLocator {
|
||||
static fromConfig(config: Config[]): ConfigClusterLocator {
|
||||
// TODO: Add validation that authProvider is required and serviceAccountToken
|
||||
// is required if authProvider is serviceAccount
|
||||
return new MultiTenantConfigClusterLocator(
|
||||
return new ConfigClusterLocator(
|
||||
config.map(c => {
|
||||
return {
|
||||
name: c.getString('name'),
|
||||
@@ -42,9 +39,7 @@ export class MultiTenantConfigClusterLocator
|
||||
);
|
||||
}
|
||||
|
||||
// As this implementation always returns all clusters serviceId is ignored here
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async getClusterByServiceId(_serviceId: string): Promise<ClusterDetails[]> {
|
||||
async getClusters(): Promise<ClusterDetails[]> {
|
||||
return this.clusterDetails;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Config, ConfigReader } from '../../../../packages/config/src';
|
||||
import { getCombinedClusterDetails } from './index';
|
||||
|
||||
describe('getCombinedClusterDetails', () => {
|
||||
it('should retrieve cluster details from config', async () => {
|
||||
const config: Config = new ConfigReader(
|
||||
{
|
||||
kubernetes: {
|
||||
clusters: [
|
||||
{
|
||||
name: 'cluster1',
|
||||
serviceAccountToken: 'token',
|
||||
url: 'http://localhost:8080',
|
||||
authProvider: 'serviceAccount',
|
||||
},
|
||||
{
|
||||
name: 'cluster2',
|
||||
url: 'http://localhost:8081',
|
||||
authProvider: 'google',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
'ctx',
|
||||
);
|
||||
|
||||
const result = await getCombinedClusterDetails(['config'], config);
|
||||
|
||||
expect(result).toStrictEqual([
|
||||
{
|
||||
name: 'cluster1',
|
||||
serviceAccountToken: 'token',
|
||||
url: 'http://localhost:8080',
|
||||
authProvider: 'serviceAccount',
|
||||
},
|
||||
{
|
||||
name: 'cluster2',
|
||||
serviceAccountToken: undefined,
|
||||
url: 'http://localhost:8081',
|
||||
authProvider: 'google',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('throws an error when using an unsupported cluster locator', async () => {
|
||||
await expect(
|
||||
getCombinedClusterDetails(['magic' as any], new ConfigReader({}, 'ctx')),
|
||||
).rejects.toStrictEqual(
|
||||
new Error('Unsupported kubernetes.clusterLocatorMethods: "magic"'),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ClusterDetails, ClusterLocatorMethod } from '..';
|
||||
import { Config } from '../../../../packages/config/src';
|
||||
import { ConfigClusterLocator } from './ConfigClusterLocator';
|
||||
|
||||
export { ConfigClusterLocator } from './ConfigClusterLocator';
|
||||
|
||||
export const getCombinedClusterDetails = async (
|
||||
clusterLocatorMethods: ClusterLocatorMethod[],
|
||||
rootConfig: Config,
|
||||
): Promise<ClusterDetails[]> => {
|
||||
return Promise.all(
|
||||
clusterLocatorMethods.map(clusterLocatorMethod => {
|
||||
switch (clusterLocatorMethod) {
|
||||
case 'config':
|
||||
return ConfigClusterLocator.fromConfig(
|
||||
rootConfig.getConfigArray('kubernetes.clusters'),
|
||||
).getClusters();
|
||||
default:
|
||||
throw new Error(
|
||||
`Unsupported kubernetes.clusterLocatorMethods: "${clusterLocatorMethod}"`,
|
||||
);
|
||||
}
|
||||
}),
|
||||
)
|
||||
.then(res => {
|
||||
return res.flat();
|
||||
})
|
||||
.catch(e => {
|
||||
throw e;
|
||||
});
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export type ClusterLocatorMethod = 'configMultiTenant' | 'http';
|
||||
export type AuthProviderType = 'google' | 'serviceAccount';
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import '@backstage/backend-common';
|
||||
import { MultiTenantServiceLocator } from './MultiTenantServiceLocator';
|
||||
|
||||
describe('MultiTenantConfigClusterLocator', () => {
|
||||
it('empty clusters returns empty cluster details', async () => {
|
||||
const sut = new MultiTenantServiceLocator([]);
|
||||
|
||||
const result = await sut.getClustersByServiceId('ignored');
|
||||
|
||||
expect(result).toStrictEqual([]);
|
||||
});
|
||||
|
||||
it('one clusters returns one cluster details', async () => {
|
||||
const sut = new MultiTenantServiceLocator([
|
||||
{
|
||||
name: 'cluster1',
|
||||
url: 'http://localhost:8080',
|
||||
authProvider: 'serviceAccount',
|
||||
serviceAccountToken: '12345',
|
||||
},
|
||||
]);
|
||||
|
||||
const result = await sut.getClustersByServiceId('ignored');
|
||||
|
||||
expect(result).toStrictEqual([
|
||||
{
|
||||
name: 'cluster1',
|
||||
serviceAccountToken: '12345',
|
||||
url: 'http://localhost:8080',
|
||||
authProvider: 'serviceAccount',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('two clusters returns two cluster details', async () => {
|
||||
const sut = new MultiTenantServiceLocator([
|
||||
{
|
||||
name: 'cluster1',
|
||||
serviceAccountToken: 'token',
|
||||
url: 'http://localhost:8080',
|
||||
authProvider: 'serviceAccount',
|
||||
},
|
||||
{
|
||||
name: 'cluster2',
|
||||
url: 'http://localhost:8081',
|
||||
authProvider: 'google',
|
||||
},
|
||||
]);
|
||||
|
||||
const result = await sut.getClustersByServiceId('ignored');
|
||||
|
||||
expect(result).toStrictEqual([
|
||||
{
|
||||
name: 'cluster1',
|
||||
serviceAccountToken: 'token',
|
||||
url: 'http://localhost:8080',
|
||||
authProvider: 'serviceAccount',
|
||||
},
|
||||
{
|
||||
name: 'cluster2',
|
||||
url: 'http://localhost:8081',
|
||||
authProvider: 'google',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ClusterDetails, KubernetesServiceLocator } from '..';
|
||||
|
||||
// This locator assumes that every service is located on every cluster
|
||||
// Therefore it will always return all clusters provided
|
||||
export class MultiTenantServiceLocator implements KubernetesServiceLocator {
|
||||
private readonly clusterDetails: ClusterDetails[];
|
||||
|
||||
constructor(clusterDetails: ClusterDetails[]) {
|
||||
this.clusterDetails = clusterDetails;
|
||||
}
|
||||
|
||||
// As this implementation always returns all clusters serviceId is ignored here
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async getClustersByServiceId(_serviceId: string): Promise<ClusterDetails[]> {
|
||||
return this.clusterDetails;
|
||||
}
|
||||
}
|
||||
+7
-7
@@ -22,7 +22,7 @@ const TEST_SERVICE_ID = 'my-service';
|
||||
|
||||
const fetchObjectsByServiceId = jest.fn();
|
||||
|
||||
const getClusterByServiceId = jest.fn();
|
||||
const getClustersByServiceId = jest.fn();
|
||||
|
||||
const mockFetch = (mock: jest.Mock) => {
|
||||
mock.mockImplementation((serviceId: string, clusterDetails: ClusterDetails) =>
|
||||
@@ -70,7 +70,7 @@ describe('handleGetKubernetesObjectsByServiceId', () => {
|
||||
});
|
||||
|
||||
it('retrieve objects for one cluster', async () => {
|
||||
getClusterByServiceId.mockImplementation(() =>
|
||||
getClustersByServiceId.mockImplementation(() =>
|
||||
Promise.resolve([
|
||||
{
|
||||
name: 'test-cluster',
|
||||
@@ -87,13 +87,13 @@ describe('handleGetKubernetesObjectsByServiceId', () => {
|
||||
fetchObjectsByServiceId,
|
||||
},
|
||||
{
|
||||
getClusterByServiceId,
|
||||
getClustersByServiceId,
|
||||
},
|
||||
getVoidLogger(),
|
||||
{},
|
||||
);
|
||||
|
||||
expect(getClusterByServiceId.mock.calls.length).toBe(1);
|
||||
expect(getClustersByServiceId.mock.calls.length).toBe(1);
|
||||
expect(fetchObjectsByServiceId.mock.calls.length).toBe(1);
|
||||
expect(result).toStrictEqual({
|
||||
items: [
|
||||
@@ -140,7 +140,7 @@ describe('handleGetKubernetesObjectsByServiceId', () => {
|
||||
});
|
||||
|
||||
it('retrieve objects for two clusters', async () => {
|
||||
getClusterByServiceId.mockImplementation(() =>
|
||||
getClustersByServiceId.mockImplementation(() =>
|
||||
Promise.resolve([
|
||||
{
|
||||
name: 'test-cluster',
|
||||
@@ -161,7 +161,7 @@ describe('handleGetKubernetesObjectsByServiceId', () => {
|
||||
fetchObjectsByServiceId,
|
||||
},
|
||||
{
|
||||
getClusterByServiceId,
|
||||
getClustersByServiceId,
|
||||
},
|
||||
getVoidLogger(),
|
||||
{
|
||||
@@ -171,7 +171,7 @@ describe('handleGetKubernetesObjectsByServiceId', () => {
|
||||
},
|
||||
);
|
||||
|
||||
expect(getClusterByServiceId.mock.calls.length).toBe(1);
|
||||
expect(getClustersByServiceId.mock.calls.length).toBe(1);
|
||||
expect(fetchObjectsByServiceId.mock.calls.length).toBe(2);
|
||||
expect(result).toStrictEqual({
|
||||
items: [
|
||||
|
||||
@@ -18,7 +18,7 @@ import { Logger } from 'winston';
|
||||
import {
|
||||
AuthRequestBody,
|
||||
ClusterDetails,
|
||||
KubernetesClusterLocator,
|
||||
KubernetesServiceLocator,
|
||||
KubernetesFetcher,
|
||||
KubernetesObjectTypes,
|
||||
ObjectsByServiceIdResponse,
|
||||
@@ -29,7 +29,7 @@ import { KubernetesAuthTranslatorGenerator } from '../kubernetes-auth-translator
|
||||
export type GetKubernetesObjectsByServiceIdHandler = (
|
||||
serviceId: string,
|
||||
fetcher: KubernetesFetcher,
|
||||
clusterLocator: KubernetesClusterLocator,
|
||||
serviceLocator: KubernetesServiceLocator,
|
||||
logger: Logger,
|
||||
requestBody: AuthRequestBody,
|
||||
objectsToFetch?: Set<KubernetesObjectTypes>,
|
||||
@@ -49,12 +49,12 @@ const DEFAULT_OBJECTS = new Set<KubernetesObjectTypes>([
|
||||
export const handleGetKubernetesObjectsByServiceId: GetKubernetesObjectsByServiceIdHandler = async (
|
||||
serviceId,
|
||||
fetcher,
|
||||
clusterLocator,
|
||||
serviceLocator,
|
||||
logger,
|
||||
requestBody,
|
||||
objectsToFetch = DEFAULT_OBJECTS,
|
||||
) => {
|
||||
const clusterDetails: ClusterDetails[] = await clusterLocator.getClusterByServiceId(
|
||||
const clusterDetails: ClusterDetails[] = await serviceLocator.getClustersByServiceId(
|
||||
serviceId,
|
||||
);
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import express from 'express';
|
||||
import request from 'supertest';
|
||||
import { makeRouter } from './router';
|
||||
import {
|
||||
KubernetesClusterLocator,
|
||||
KubernetesServiceLocator,
|
||||
KubernetesFetcher,
|
||||
ObjectsByServiceIdResponse,
|
||||
} from '..';
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
describe('router', () => {
|
||||
let app: express.Express;
|
||||
let kubernetesFetcher: jest.Mocked<KubernetesFetcher>;
|
||||
let kubernetesClusterLocator: jest.Mocked<KubernetesClusterLocator>;
|
||||
let kubernetesServiceLocator: jest.Mocked<KubernetesServiceLocator>;
|
||||
let handleGetByServiceId: jest.Mock<Promise<ObjectsByServiceIdResponse>>;
|
||||
|
||||
beforeAll(async () => {
|
||||
@@ -35,8 +35,8 @@ describe('router', () => {
|
||||
fetchObjectsByServiceId: jest.fn(),
|
||||
};
|
||||
|
||||
kubernetesClusterLocator = {
|
||||
getClusterByServiceId: jest.fn(),
|
||||
kubernetesServiceLocator = {
|
||||
getClustersByServiceId: jest.fn(),
|
||||
};
|
||||
|
||||
handleGetByServiceId = jest.fn();
|
||||
@@ -44,7 +44,7 @@ describe('router', () => {
|
||||
const router = makeRouter(
|
||||
getVoidLogger(),
|
||||
kubernetesFetcher,
|
||||
kubernetesClusterLocator,
|
||||
kubernetesServiceLocator,
|
||||
handleGetByServiceId as any,
|
||||
);
|
||||
app = express().use(router);
|
||||
|
||||
@@ -18,8 +18,7 @@ import express from 'express';
|
||||
import Router from 'express-promise-router';
|
||||
import { Logger } from 'winston';
|
||||
import { Config } from '@backstage/config';
|
||||
import { ClusterLocatorMethod } from '../cluster-locator/types';
|
||||
import { MultiTenantConfigClusterLocator } from '../cluster-locator/MultiTenantConfigClusterLocator';
|
||||
import { MultiTenantServiceLocator } from '../service-locator/MultiTenantServiceLocator';
|
||||
import { KubernetesClientBasedFetcher } from './KubernetesFetcher';
|
||||
import { KubernetesClientProvider } from './KubernetesClientProvider';
|
||||
import {
|
||||
@@ -28,30 +27,35 @@ import {
|
||||
} from './getKubernetesObjectsByServiceIdHandler';
|
||||
import {
|
||||
AuthRequestBody,
|
||||
KubernetesClusterLocator,
|
||||
KubernetesServiceLocator,
|
||||
KubernetesFetcher,
|
||||
} from '../types/types';
|
||||
ServiceLocatorMethod,
|
||||
ClusterLocatorMethod,
|
||||
ClusterDetails,
|
||||
} from '..';
|
||||
import { getCombinedClusterDetails } from '../cluster-locator';
|
||||
|
||||
export interface RouterOptions {
|
||||
logger: Logger;
|
||||
config: Config;
|
||||
}
|
||||
|
||||
const getClusterLocator = (config: Config): KubernetesClusterLocator => {
|
||||
const clusterLocatorMethod = config.getString(
|
||||
'kubernetes.clusterLocatorMethod',
|
||||
) as ClusterLocatorMethod;
|
||||
const getServiceLocator = (
|
||||
config: Config,
|
||||
clusterDetails: ClusterDetails[],
|
||||
): KubernetesServiceLocator => {
|
||||
const serviceLocatorMethod = config.getString(
|
||||
'kubernetes.serviceLocatorMethod',
|
||||
) as ServiceLocatorMethod;
|
||||
|
||||
switch (clusterLocatorMethod) {
|
||||
case 'configMultiTenant':
|
||||
return MultiTenantConfigClusterLocator.fromConfig(
|
||||
config.getConfigArray('kubernetes.clusters'),
|
||||
);
|
||||
switch (serviceLocatorMethod) {
|
||||
case 'multiTenant':
|
||||
return new MultiTenantServiceLocator(clusterDetails);
|
||||
case 'http':
|
||||
throw new Error('not implemented');
|
||||
default:
|
||||
throw new Error(
|
||||
`Unsupported kubernetes.clusterLocatorMethod "${clusterLocatorMethod}"`,
|
||||
`Unsupported kubernetes.clusterLocatorMethod "${serviceLocatorMethod}"`,
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -59,13 +63,12 @@ const getClusterLocator = (config: Config): KubernetesClusterLocator => {
|
||||
export const makeRouter = (
|
||||
logger: Logger,
|
||||
fetcher: KubernetesFetcher,
|
||||
clusterLocator: KubernetesClusterLocator,
|
||||
serviceLocator: KubernetesServiceLocator,
|
||||
handleGetByServiceId: GetKubernetesObjectsByServiceIdHandler,
|
||||
): express.Router => {
|
||||
const router = Router();
|
||||
router.use(express.json());
|
||||
|
||||
// TODO error handling
|
||||
router.post('/services/:serviceId', async (req, res) => {
|
||||
const serviceId = req.params.serviceId;
|
||||
const requestBody: AuthRequestBody = req.body;
|
||||
@@ -73,7 +76,7 @@ export const makeRouter = (
|
||||
const response = await handleGetByServiceId(
|
||||
serviceId,
|
||||
fetcher,
|
||||
clusterLocator,
|
||||
serviceLocator,
|
||||
logger,
|
||||
requestBody,
|
||||
);
|
||||
@@ -96,17 +99,26 @@ export async function createRouter(
|
||||
|
||||
logger.info('Initializing Kubernetes backend');
|
||||
|
||||
const clusterLocator = getClusterLocator(options.config);
|
||||
|
||||
const fetcher = new KubernetesClientBasedFetcher({
|
||||
kubernetesClientProvider: new KubernetesClientProvider(),
|
||||
logger,
|
||||
});
|
||||
|
||||
const clusterLocatorMethods = options.config.getStringArray(
|
||||
'kubernetes.clusterLocatorMethods',
|
||||
) as ClusterLocatorMethod[];
|
||||
|
||||
const clusterDetails = await getCombinedClusterDetails(
|
||||
clusterLocatorMethods,
|
||||
options.config,
|
||||
);
|
||||
|
||||
const serviceLocator = getServiceLocator(options.config, clusterDetails);
|
||||
|
||||
return makeRouter(
|
||||
logger,
|
||||
fetcher,
|
||||
clusterLocator,
|
||||
serviceLocator,
|
||||
handleGetKubernetesObjectsByServiceId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -118,8 +118,13 @@ export interface KubernetesFetcher {
|
||||
}
|
||||
|
||||
// Used to locate which cluster(s) a service is running on
|
||||
export interface KubernetesClusterLocator {
|
||||
getClusterByServiceId(serviceId: string): Promise<ClusterDetails[]>;
|
||||
export interface KubernetesServiceLocator {
|
||||
getClustersByServiceId(serviceId: string): Promise<ClusterDetails[]>;
|
||||
}
|
||||
|
||||
// Used to load cluster details from different sources
|
||||
export interface KubernetesClustersSupplier {
|
||||
getClusters(): Promise<ClusterDetails[]>;
|
||||
}
|
||||
|
||||
export type KubernetesErrorTypes =
|
||||
@@ -132,3 +137,7 @@ export interface KubernetesFetchError {
|
||||
statusCode?: number;
|
||||
resourcePath?: string;
|
||||
}
|
||||
|
||||
export type ServiceLocatorMethod = 'multiTenant' | 'http'; // TODO implement http
|
||||
export type ClusterLocatorMethod = 'config';
|
||||
export type AuthProviderType = 'google' | 'serviceAccount';
|
||||
|
||||
Reference in New Issue
Block a user