refactor: Rework config to be driven by target baseUrls
Signed-off-by: Jack Palmer <jackpalmer@spotify.com>
This commit is contained in:
Vendored
+16
-4
@@ -203,13 +203,25 @@ export interface Config {
|
||||
* remove the default value that Backstage puts in place for that policy.
|
||||
*/
|
||||
csp?: { [policyId: string]: string[] | false };
|
||||
};
|
||||
|
||||
/** Discovery options. */
|
||||
discovery?: {
|
||||
/**
|
||||
* Discovery options.
|
||||
* Endpoints
|
||||
*
|
||||
* The keys are the plugin IDs, and the values are their endpoint URLs which
|
||||
* will be used by `HostDiscovery` implementation.
|
||||
* A list of target baseUrls and the associated plugins.
|
||||
*/
|
||||
discovery?: { [pluginId: string]: string };
|
||||
endpoints: {
|
||||
/**
|
||||
* The target baseUrl to use for the plugin
|
||||
*
|
||||
* Can be either a string or an object with internal and external keys.
|
||||
* Targets with `{pluginId}` in the url will be replaced with the pluginId.
|
||||
*/
|
||||
target: string | { internal: string; external: string };
|
||||
/** Array of plugins which use the target baseUrl. */
|
||||
plugins: string[];
|
||||
}[];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ describe('HostDiscovery', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('uses plugin specific baseUrl from config if provided', async () => {
|
||||
it('uses plugin specific targets from config if provided', async () => {
|
||||
const discovery = HostDiscovery.fromConfig(
|
||||
new ConfigReader({
|
||||
backend: {
|
||||
@@ -90,7 +90,41 @@ describe('HostDiscovery', () => {
|
||||
listen: { port: 80, host: 'localhost' },
|
||||
},
|
||||
discovery: {
|
||||
catalog: 'http://catalog-backend:8080/api/catalog',
|
||||
endpoints: [
|
||||
{
|
||||
target: {
|
||||
internal: 'http://catalog-backend-internal:8080/api/catalog',
|
||||
external: 'http://catalog-backend-external:8080/api/catalog',
|
||||
},
|
||||
plugins: ['catalog'],
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(discovery.getBaseUrl('catalog')).resolves.toBe(
|
||||
'http://catalog-backend-internal:8080/api/catalog',
|
||||
);
|
||||
await expect(discovery.getExternalBaseUrl('catalog')).resolves.toBe(
|
||||
'http://catalog-backend-external:8080/api/catalog',
|
||||
);
|
||||
});
|
||||
|
||||
it('uses a single target for internal and external for a plugin', async () => {
|
||||
const discovery = HostDiscovery.fromConfig(
|
||||
new ConfigReader({
|
||||
backend: {
|
||||
baseUrl: 'http://localhost:40',
|
||||
listen: { port: 80, host: 'localhost' },
|
||||
},
|
||||
discovery: {
|
||||
endpoints: [
|
||||
{
|
||||
target: 'http://catalog-backend:8080/api/catalog',
|
||||
plugins: ['catalog'],
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
);
|
||||
@@ -102,4 +136,75 @@ describe('HostDiscovery', () => {
|
||||
'http://catalog-backend:8080/api/catalog',
|
||||
);
|
||||
});
|
||||
|
||||
it('defaults to the backend baseUrl when there is not an endpoint for a plugin', async () => {
|
||||
const discovery = HostDiscovery.fromConfig(
|
||||
new ConfigReader({
|
||||
backend: {
|
||||
baseUrl: 'http://localhost:40',
|
||||
listen: { port: 80, host: 'localhost' },
|
||||
},
|
||||
discovery: {
|
||||
endpoints: [
|
||||
{
|
||||
target: 'http://catalog-backend:8080/api/catalog',
|
||||
plugins: ['catalog'],
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(discovery.getBaseUrl('scaffolder')).resolves.toBe(
|
||||
'http://localhost:80/api/scaffolder',
|
||||
);
|
||||
await expect(discovery.getExternalBaseUrl('scaffolder')).resolves.toBe(
|
||||
'http://localhost:40/api/scaffolder',
|
||||
);
|
||||
});
|
||||
|
||||
it('replaces {pluginId} in the target', async () => {
|
||||
const discovery = HostDiscovery.fromConfig(
|
||||
new ConfigReader({
|
||||
backend: {
|
||||
baseUrl: 'http://localhost:40',
|
||||
listen: { port: 80, host: 'localhost' },
|
||||
},
|
||||
discovery: {
|
||||
endpoints: [
|
||||
{
|
||||
target: 'http://common-backend:8080/api/{pluginId}',
|
||||
plugins: ['catalog', 'docs'],
|
||||
},
|
||||
{
|
||||
target: {
|
||||
internal: 'http://scaffolder-internal:8080/api/{pluginId}',
|
||||
external: 'http://scaffolder-external:8080/api/{pluginId}',
|
||||
},
|
||||
plugins: ['scaffolder'],
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(discovery.getBaseUrl('catalog')).resolves.toBe(
|
||||
'http://common-backend:8080/api/catalog',
|
||||
);
|
||||
await expect(discovery.getExternalBaseUrl('catalog')).resolves.toBe(
|
||||
'http://common-backend:8080/api/catalog',
|
||||
);
|
||||
await expect(discovery.getBaseUrl('docs')).resolves.toBe(
|
||||
'http://common-backend:8080/api/docs',
|
||||
);
|
||||
await expect(discovery.getExternalBaseUrl('docs')).resolves.toBe(
|
||||
'http://common-backend:8080/api/docs',
|
||||
);
|
||||
await expect(discovery.getBaseUrl('scaffolder')).resolves.toBe(
|
||||
'http://scaffolder-internal:8080/api/scaffolder',
|
||||
);
|
||||
await expect(discovery.getExternalBaseUrl('scaffolder')).resolves.toBe(
|
||||
'http://scaffolder-external:8080/api/scaffolder',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,6 +18,8 @@ import { Config } from '@backstage/config';
|
||||
import { PluginEndpointDiscovery } from './types';
|
||||
import { readHttpServerOptions } from '@backstage/backend-app-api';
|
||||
|
||||
type Target = string | { internal: string; external: string };
|
||||
|
||||
/**
|
||||
* HostDiscovery is a basic PluginEndpointDiscovery implementation
|
||||
* that assumes that all plugins are hosted in a single deployment.
|
||||
@@ -28,7 +30,6 @@ import { readHttpServerOptions } from '@backstage/backend-app-api';
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
export class HostDiscovery implements PluginEndpointDiscovery {
|
||||
/**
|
||||
* Creates a new HostDiscovery discovery instance by reading
|
||||
@@ -79,17 +80,39 @@ export class HostDiscovery implements PluginEndpointDiscovery {
|
||||
private readonly discoveryConfig: Config | undefined,
|
||||
) {}
|
||||
|
||||
private getTargetFromConfig(pluginId: string, type: 'internal' | 'external') {
|
||||
const endpoints = this.discoveryConfig?.getOptionalConfigArray('endpoints');
|
||||
|
||||
const target = endpoints
|
||||
?.find(endpoint => endpoint.getStringArray('plugins').includes(pluginId))
|
||||
?.get<Target>('target');
|
||||
|
||||
if (!target) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof target === 'string') {
|
||||
return target.replace('{pluginId}', pluginId);
|
||||
}
|
||||
|
||||
return target[type].replace('{pluginId}', pluginId);
|
||||
}
|
||||
|
||||
async getBaseUrl(pluginId: string): Promise<string> {
|
||||
if (this.discoveryConfig?.has(pluginId)) {
|
||||
return this.discoveryConfig.getString(pluginId);
|
||||
const target = this.getTargetFromConfig(pluginId, 'internal');
|
||||
|
||||
if (target) {
|
||||
return target;
|
||||
}
|
||||
|
||||
return `${this.internalBaseUrl}/${pluginId}`;
|
||||
}
|
||||
|
||||
async getExternalBaseUrl(pluginId: string): Promise<string> {
|
||||
if (this.discoveryConfig?.has(pluginId)) {
|
||||
return this.discoveryConfig.getString(pluginId);
|
||||
const target = this.getTargetFromConfig(pluginId, 'external');
|
||||
|
||||
if (target) {
|
||||
return target;
|
||||
}
|
||||
|
||||
return `${this.externalBaseUrl}/${pluginId}`;
|
||||
|
||||
Reference in New Issue
Block a user