feat: promote instance metadata to stable

Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>
This commit is contained in:
aramissennyeydd
2025-09-03 09:48:34 -04:00
committed by Fredrik Adelöw
parent 6fb48a2754
commit a17d9df2ee
15 changed files with 119 additions and 112 deletions
@@ -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;
},
});
}