feat: promote instance metadata to stable
Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>
This commit is contained in:
committed by
Fredrik Adelöw
parent
6fb48a2754
commit
a17d9df2ee
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-plugin-api': minor
|
||||
---
|
||||
|
||||
Promote `instanceMetadata` service to main entrypoint.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-gateway-backend': minor
|
||||
---
|
||||
|
||||
Update usage of the `instanceMetadata` service.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-app-api': minor
|
||||
---
|
||||
|
||||
Updates API for `instanceMetadata` service to return a list of plugins not features. Also adds an HTTP endpoint that returns information about the current instance.
|
||||
@@ -48,7 +48,8 @@
|
||||
"dependencies": {
|
||||
"@backstage/backend-plugin-api": "workspace:^",
|
||||
"@backstage/config": "workspace:^",
|
||||
"@backstage/errors": "workspace:^"
|
||||
"@backstage/errors": "workspace:^",
|
||||
"express-promise-router": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/backend-defaults": "workspace:^",
|
||||
|
||||
@@ -22,9 +22,9 @@ import {
|
||||
createExtensionPoint,
|
||||
createBackendFeatureLoader,
|
||||
ServiceRef,
|
||||
coreServices,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { BackendInitializer } from './BackendInitializer';
|
||||
import { instanceMetadataServiceRef } from '@backstage/backend-plugin-api/alpha';
|
||||
import { mockServices } from '@backstage/backend-test-utils';
|
||||
|
||||
const baseFactories = [
|
||||
@@ -32,6 +32,9 @@ const baseFactories = [
|
||||
mockServices.lifecycle.factory(),
|
||||
mockServices.rootLogger.factory(),
|
||||
mockServices.logger.factory(),
|
||||
mockServices.rootConfig.factory(),
|
||||
mockServices.rootHttpRouter.mock().factory,
|
||||
mockServices.rootHealth.factory(),
|
||||
];
|
||||
|
||||
function mkNoopFactory(ref: ServiceRef<{}, 'plugin'>) {
|
||||
@@ -1074,7 +1077,7 @@ describe('BackendInitializer', () => {
|
||||
});
|
||||
|
||||
it('should properly add plugins + modules to the instance metadata service', async () => {
|
||||
expect.assertions(2);
|
||||
expect.assertions(1);
|
||||
const backend = new BackendInitializer(baseFactories);
|
||||
const plugin = createBackendPlugin({
|
||||
pluginId: 'test',
|
||||
@@ -1090,31 +1093,23 @@ describe('BackendInitializer', () => {
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: {
|
||||
instanceMetadata: instanceMetadataServiceRef,
|
||||
instanceMetadata: coreServices.instanceMetadata,
|
||||
},
|
||||
async init({ instanceMetadata }) {
|
||||
expect(instanceMetadata.getInstalledFeatures()).toEqual([
|
||||
expect(instanceMetadata.getInstalledPlugins()).toEqual([
|
||||
{
|
||||
pluginId: 'test',
|
||||
type: 'plugin',
|
||||
},
|
||||
{
|
||||
pluginId: 'test',
|
||||
moduleId: 'test',
|
||||
type: 'module',
|
||||
modules: [
|
||||
{
|
||||
moduleId: 'test',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
pluginId: 'instance-metadata',
|
||||
type: 'plugin',
|
||||
modules: [],
|
||||
},
|
||||
]);
|
||||
expect(instanceMetadata.getInstalledFeatures().map(String)).toEqual(
|
||||
[
|
||||
'plugin{pluginId=test}',
|
||||
'module{moduleId=test,pluginId=test}',
|
||||
'plugin{pluginId=instance-metadata}',
|
||||
],
|
||||
);
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
@@ -36,14 +36,13 @@ import type {
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
import type { InternalServiceFactory } from '../../../backend-plugin-api/src/services/system/types';
|
||||
import { ForwardedError, ConflictError, assertError } from '@backstage/errors';
|
||||
import {
|
||||
instanceMetadataServiceRef,
|
||||
BackendFeatureMeta,
|
||||
} from '@backstage/backend-plugin-api/alpha';
|
||||
import { DependencyGraph } from '../lib/DependencyGraph';
|
||||
import { ServiceRegistry } from './ServiceRegistry';
|
||||
import { createInitializationLogger } from './createInitializationLogger';
|
||||
import { unwrapFeature } from './helpers';
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
import type { BackendPlugin } from '../../../backend-plugin-api/src/services/definitions/InstanceMetadataService';
|
||||
import Router from 'express-promise-router';
|
||||
|
||||
export interface BackendRegisterInit {
|
||||
consumes: Set<ServiceOrExtensionPoint>;
|
||||
@@ -104,53 +103,58 @@ const instanceRegistry = new (class InstanceRegistry {
|
||||
function createInstanceMetadataServiceFactory(
|
||||
registrations: InternalBackendRegistrations[],
|
||||
) {
|
||||
const installedFeatures = registrations
|
||||
.map(registration => {
|
||||
if (registration.featureType === 'registrations') {
|
||||
return registration
|
||||
.getRegistrations()
|
||||
.map(feature => {
|
||||
if (feature.type === 'plugin') {
|
||||
return Object.defineProperty(
|
||||
{
|
||||
type: 'plugin',
|
||||
pluginId: feature.pluginId,
|
||||
},
|
||||
'toString',
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: () => `plugin{pluginId=${feature.pluginId}}`,
|
||||
},
|
||||
);
|
||||
} else if (feature.type === 'module') {
|
||||
return Object.defineProperty(
|
||||
{
|
||||
type: 'module',
|
||||
pluginId: feature.pluginId,
|
||||
moduleId: feature.moduleId,
|
||||
},
|
||||
'toString',
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: () =>
|
||||
`module{moduleId=${feature.moduleId},pluginId=${feature.pluginId}}`,
|
||||
},
|
||||
);
|
||||
}
|
||||
// Ignore unknown feature types.
|
||||
return undefined;
|
||||
})
|
||||
.filter(Boolean) as BackendFeatureMeta[];
|
||||
const installedPlugins: { [pluginId: string]: BackendPlugin } = {};
|
||||
for (const registration of registrations) {
|
||||
if (registration.featureType === 'registrations') {
|
||||
for (const feature of registration.getRegistrations()) {
|
||||
if (feature.type === 'plugin') {
|
||||
if (!installedPlugins[feature.pluginId]) {
|
||||
installedPlugins[feature.pluginId] = {
|
||||
pluginId: feature.pluginId,
|
||||
modules: [],
|
||||
};
|
||||
}
|
||||
} else if (feature.type === 'module') {
|
||||
if (!installedPlugins[feature.pluginId]) {
|
||||
installedPlugins[feature.pluginId] = {
|
||||
pluginId: feature.pluginId,
|
||||
modules: [],
|
||||
};
|
||||
}
|
||||
installedPlugins[feature.pluginId].modules.push({
|
||||
moduleId: feature.moduleId,
|
||||
});
|
||||
}
|
||||
}
|
||||
return [];
|
||||
})
|
||||
.flat();
|
||||
}
|
||||
}
|
||||
return createServiceFactory({
|
||||
service: instanceMetadataServiceRef,
|
||||
deps: {},
|
||||
factory: async () => ({ getInstalledFeatures: () => installedFeatures }),
|
||||
service: coreServices.instanceMetadata,
|
||||
deps: {
|
||||
httpRouter: coreServices.rootHttpRouter,
|
||||
logger: coreServices.rootLogger,
|
||||
},
|
||||
factory: async ({ logger, httpRouter }) => {
|
||||
const instanceMetadata = {
|
||||
getInstalledPlugins: () => Object.values(installedPlugins),
|
||||
};
|
||||
|
||||
logger.info(
|
||||
`Installed plugins on this instance: ${instanceMetadata
|
||||
.getInstalledPlugins()
|
||||
.map(p => p.pluginId)
|
||||
.join(', ')}`,
|
||||
);
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get('/info', (_, res) => {
|
||||
res.json({ plugins: Object.values(installedPlugins) });
|
||||
});
|
||||
|
||||
httpRouter.use('/.backstage/instanceMetadata/v1', router);
|
||||
return instanceMetadata;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -14,11 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export type {
|
||||
BackendFeatureMeta,
|
||||
InstanceMetadataService,
|
||||
} from './InstanceMetadataService';
|
||||
|
||||
export type {
|
||||
ActionsRegistryService,
|
||||
ActionsRegistryActionOptions,
|
||||
@@ -27,8 +22,4 @@ export type {
|
||||
|
||||
export type { ActionsService, ActionsServiceAction } from './ActionsService';
|
||||
|
||||
export {
|
||||
actionsRegistryServiceRef,
|
||||
actionsServiceRef,
|
||||
instanceMetadataServiceRef,
|
||||
} from './refs';
|
||||
export { actionsRegistryServiceRef, actionsServiceRef } from './refs';
|
||||
|
||||
@@ -16,15 +16,6 @@
|
||||
|
||||
import { createServiceRef } from '@backstage/backend-plugin-api';
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export const instanceMetadataServiceRef = createServiceRef<
|
||||
import('./InstanceMetadataService').InstanceMetadataService
|
||||
>({
|
||||
id: 'core.instanceMetadata',
|
||||
});
|
||||
|
||||
/**
|
||||
* Service for calling distributed actions
|
||||
*
|
||||
|
||||
+7
-12
@@ -14,19 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/** @alpha */
|
||||
export type BackendFeatureMeta =
|
||||
| {
|
||||
type: 'plugin';
|
||||
pluginId: string;
|
||||
}
|
||||
| {
|
||||
type: 'module';
|
||||
pluginId: string;
|
||||
moduleId: string;
|
||||
};
|
||||
export interface BackendPlugin {
|
||||
pluginId: string;
|
||||
modules: {
|
||||
moduleId: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
/** @alpha */
|
||||
export interface InstanceMetadataService {
|
||||
getInstalledFeatures: () => BackendFeatureMeta[];
|
||||
getInstalledPlugins: () => readonly BackendPlugin[];
|
||||
}
|
||||
@@ -277,4 +277,15 @@ export namespace coreServices {
|
||||
export const urlReader = createServiceRef<
|
||||
import('./UrlReaderService').UrlReaderService
|
||||
>({ id: 'core.urlReader' });
|
||||
|
||||
/**
|
||||
* Information about the current Backstage instance.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const instanceMetadata = createServiceRef<
|
||||
import('./InstanceMetadataService').InstanceMetadataService
|
||||
>({
|
||||
id: 'core.instanceMetadata',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -85,4 +85,8 @@ export type {
|
||||
UrlReaderServiceSearchResponseFile,
|
||||
} from './UrlReaderService';
|
||||
export type { BackstageUserInfo, UserInfoService } from './UserInfoService';
|
||||
export type {
|
||||
InstanceMetadataService,
|
||||
BackendPlugin,
|
||||
} from './InstanceMetadataService';
|
||||
export { coreServices } from './coreServices';
|
||||
|
||||
@@ -17,21 +17,21 @@ import {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { instanceMetadataServiceRef } from '@backstage/backend-plugin-api/alpha';
|
||||
|
||||
// Example usage of the instance metadata service to log the installed features.
|
||||
// Example usage of the instance metadata service to log the installed plugins.
|
||||
export default createBackendPlugin({
|
||||
pluginId: 'instance-metadata-logging',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
instanceMetadata: instanceMetadataServiceRef,
|
||||
instanceMetadata: coreServices.instanceMetadata,
|
||||
logger: coreServices.logger,
|
||||
},
|
||||
async init({ instanceMetadata, logger }) {
|
||||
logger.info(
|
||||
`Installed features on this instance: ${instanceMetadata
|
||||
.getInstalledFeatures()
|
||||
`Installed plugins on this instance: ${instanceMetadata
|
||||
.getInstalledPlugins()
|
||||
.map(e => e.pluginId)
|
||||
.join(', ')}`,
|
||||
);
|
||||
},
|
||||
|
||||
@@ -18,7 +18,6 @@ import {
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { createRouter } from './router';
|
||||
import { instanceMetadataServiceRef } from '@backstage/backend-plugin-api/alpha';
|
||||
import { Handler } from 'express';
|
||||
|
||||
/**
|
||||
@@ -33,7 +32,7 @@ export const gatewayPlugin = createBackendPlugin({
|
||||
deps: {
|
||||
logger: coreServices.logger,
|
||||
rootHttpRouter: coreServices.rootHttpRouter,
|
||||
instanceMeta: instanceMetadataServiceRef,
|
||||
instanceMeta: coreServices.instanceMetadata,
|
||||
discovery: coreServices.discovery,
|
||||
},
|
||||
async init({ logger, discovery, instanceMeta, rootHttpRouter }) {
|
||||
|
||||
@@ -13,8 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { DiscoveryService, LoggerService } from '@backstage/backend-plugin-api';
|
||||
import { InstanceMetadataService } from '@backstage/backend-plugin-api/alpha';
|
||||
import {
|
||||
DiscoveryService,
|
||||
InstanceMetadataService,
|
||||
LoggerService,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { createProxyMiddleware } from 'http-proxy-middleware';
|
||||
import { context } from '@opentelemetry/api';
|
||||
@@ -29,10 +32,7 @@ export function createRouter({
|
||||
logger: LoggerService;
|
||||
}) {
|
||||
const localPluginIds = new Set(
|
||||
instanceMeta
|
||||
.getInstalledFeatures()
|
||||
.filter(f => f.type === 'plugin')
|
||||
.map(f => f.pluginId),
|
||||
instanceMeta.getInstalledPlugins().map(f => f.pluginId),
|
||||
);
|
||||
|
||||
const proxy = createProxyMiddleware({
|
||||
|
||||
Reference in New Issue
Block a user