Add initial code
Signed-off-by: Tomas Dabasinskas <tomas@dabasinskas.net>
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* 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 {
|
||||
TaskScheduleDefinition,
|
||||
TaskScheduleDefinitionConfig,
|
||||
} from '@backstage/backend-tasks';
|
||||
|
||||
/**
|
||||
* Represents the configuration for the Backstage.
|
||||
*/
|
||||
export interface Config {
|
||||
/**
|
||||
* Configuration for the catalog.
|
||||
*/
|
||||
catalog?: {
|
||||
/**
|
||||
* Configuration for the providers.
|
||||
*/
|
||||
providers?: {
|
||||
/**
|
||||
* Puppet entity provider configuration. Uses "default" as default ID for the single config variant.
|
||||
*/
|
||||
puppet?: ProviderConfig | Record<string, ProviderConfig>;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration of {@link PuppetDBEntityProvider}.
|
||||
*/
|
||||
interface ProviderConfig {
|
||||
/**
|
||||
* (Required) The host of PuppetDB API instance.
|
||||
*/
|
||||
host: string;
|
||||
/**
|
||||
* (Optional) PQL query to filter PuppetDB nodes.
|
||||
*/
|
||||
query?: string;
|
||||
/**
|
||||
* (Optional) Task schedule definition for the refresh.
|
||||
*/
|
||||
schedule?: TaskScheduleDefinition;
|
||||
}
|
||||
@@ -35,8 +35,14 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "workspace:^",
|
||||
"@backstage/backend-tasks": "workspace:^",
|
||||
"@backstage/catalog-model": "workspace:^",
|
||||
"@backstage/config": "workspace:^",
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@backstage/plugin-catalog-backend": "workspace:^",
|
||||
"@backstage/types": "workspace:^",
|
||||
"lodash": "^4.17.21",
|
||||
"luxon": "^3.0.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"uuid": "^8.0.0",
|
||||
"winston": "^3.2.1"
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A Backstage catalog backend module that helps integrate towards PuppetDB
|
||||
*
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
export * from './providers';
|
||||
export * from './puppet';
|
||||
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* 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 {
|
||||
EntityProvider,
|
||||
EntityProviderConnection,
|
||||
} from '@backstage/plugin-catalog-backend';
|
||||
import { Logger } from 'winston';
|
||||
import {
|
||||
PuppetDBEntityProviderConfig,
|
||||
readProviderConfigs,
|
||||
} from './PuppetDBEntityProviderConfig';
|
||||
import { Config } from '@backstage/config';
|
||||
import { PluginTaskScheduler, TaskRunner } from '@backstage/backend-tasks';
|
||||
import * as uuid from 'uuid';
|
||||
import { ResourceTransformer, defaultResourceTransformer } from '../puppet';
|
||||
import {
|
||||
ANNOTATION_LOCATION,
|
||||
ANNOTATION_ORIGIN_LOCATION,
|
||||
Entity,
|
||||
} from '@backstage/catalog-model/';
|
||||
import { merge } from 'lodash';
|
||||
import { readPuppetNodes } from '../puppet/read';
|
||||
import { ENDPOINT_NODES } from '../puppet/constants';
|
||||
|
||||
/**
|
||||
* Reads nodes from [PuppetDB](https://www.puppet.com/docs/puppet/6/puppetdb_overview.html)
|
||||
* based on the provided query and registers them as Resource entities in the catalog.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class PuppetDBEntityProvider implements EntityProvider {
|
||||
private readonly config: PuppetDBEntityProviderConfig;
|
||||
private readonly logger: Logger;
|
||||
private readonly scheduleFn: () => Promise<void>;
|
||||
private readonly transformer: ResourceTransformer;
|
||||
private connection?: EntityProviderConnection;
|
||||
|
||||
/**
|
||||
* Creates instances of {@link PuppetDBEntityProvider} from a configuration.
|
||||
*
|
||||
* @param config - The configuration to read provider information from.
|
||||
* @param deps - The dependencies for {@link PuppetDBEntityProvider}.
|
||||
*
|
||||
* @returns A list of {@link PuppetDBEntityProvider} instances.
|
||||
*/
|
||||
static fromConfig(
|
||||
config: Config,
|
||||
deps: {
|
||||
logger: Logger;
|
||||
schedule?: TaskRunner;
|
||||
scheduler?: PluginTaskScheduler;
|
||||
transformer?: ResourceTransformer;
|
||||
},
|
||||
): PuppetDBEntityProvider[] {
|
||||
if (!deps.schedule && !deps.scheduler) {
|
||||
throw new Error('Either schedule or scheduler must be provided.');
|
||||
}
|
||||
|
||||
return readProviderConfigs(config).map(providerConfig => {
|
||||
if (!deps.schedule && !providerConfig.schedule) {
|
||||
throw new Error(
|
||||
`No schedule provided neither via code nor config for puppet-provider:${providerConfig.id}.`,
|
||||
);
|
||||
}
|
||||
|
||||
const taskRunner =
|
||||
deps.schedule ??
|
||||
deps.scheduler!.createScheduledTaskRunner(providerConfig.schedule!);
|
||||
|
||||
const transformer = deps.transformer ?? defaultResourceTransformer;
|
||||
|
||||
return new PuppetDBEntityProvider(
|
||||
providerConfig,
|
||||
deps.logger,
|
||||
taskRunner,
|
||||
transformer,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of {@link PuppetDBEntityProvider}.
|
||||
*
|
||||
* @param config - Configuration of the provider.
|
||||
* @param logger - The instance of a {@link Logger}.
|
||||
* @param taskRunner - The instance of {@link TaskRunner}.
|
||||
* @param transformer - A {@link ResourceTransformer} function.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private constructor(
|
||||
config: PuppetDBEntityProviderConfig,
|
||||
logger: Logger,
|
||||
taskRunner: TaskRunner,
|
||||
transformer: ResourceTransformer,
|
||||
) {
|
||||
this.config = config;
|
||||
this.logger = logger.child({
|
||||
target: this.getProviderName(),
|
||||
});
|
||||
this.scheduleFn = this.createScheduleFn(taskRunner);
|
||||
this.transformer = transformer;
|
||||
}
|
||||
|
||||
/** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.connect} */
|
||||
async connect(connection: EntityProviderConnection): Promise<void> {
|
||||
this.connection = connection;
|
||||
await this.scheduleFn();
|
||||
}
|
||||
|
||||
/** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.getProviderName} */
|
||||
getProviderName(): string {
|
||||
return `puppetdb-provider:${this.config.id}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that can be used to schedule a refresh of the catalog.
|
||||
*
|
||||
* @param taskRunner - The instance of {@link TaskRunner}.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private createScheduleFn(taskRunner: TaskRunner): () => Promise<void> {
|
||||
return async () => {
|
||||
const taskId = `${this.getProviderName()}:refresh`;
|
||||
return taskRunner.run({
|
||||
id: taskId,
|
||||
fn: async () => {
|
||||
const logger = this.logger.child({
|
||||
class: PuppetDBEntityProvider.prototype.constructor.name,
|
||||
taskId,
|
||||
taskInstanceId: uuid.v4(),
|
||||
});
|
||||
try {
|
||||
await this.refresh(logger);
|
||||
} catch (error) {
|
||||
logger.error(`${this.getProviderName()} refresh failed`, error);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the catalog by reading nodes from PuppetDB and registering them as Resource Entities.
|
||||
*
|
||||
* @param logger - The instance of a {@link Logger}.
|
||||
*/
|
||||
async refresh(logger: Logger) {
|
||||
if (!this.connection) {
|
||||
throw new Error('Not initialized');
|
||||
}
|
||||
|
||||
const { markReadComplete } = trackProgress(logger);
|
||||
const entities = await readPuppetNodes(this.config, {
|
||||
logger,
|
||||
transformer: this.transformer,
|
||||
});
|
||||
const { markCommitComplete } = markReadComplete(entities);
|
||||
|
||||
await this.connection.applyMutation({
|
||||
type: 'full',
|
||||
entities: [...entities].map(entity => ({
|
||||
locationKey: this.getProviderName(),
|
||||
entity: withLocations(this.config.host, entity),
|
||||
})),
|
||||
});
|
||||
markCommitComplete(entities);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the entities have required annotation data.
|
||||
*
|
||||
* @param host - The host of the PuppetDB instance.
|
||||
* @param entity - The entity to add the annotations to.
|
||||
*
|
||||
* @returns Entity with @{@link ANNOTATION_LOCATION} and @{@link ANNOTATION_ORIGIN_LOCATION} annotations.
|
||||
*/
|
||||
function withLocations(host: string, entity: Entity): Entity {
|
||||
const location = new URL(host);
|
||||
location.pathname = `${ENDPOINT_NODES}/${entity.metadata?.name}`;
|
||||
|
||||
return merge(
|
||||
{
|
||||
metadata: {
|
||||
annotations: {
|
||||
[ANNOTATION_LOCATION]: `url:${location.toString()}`,
|
||||
[ANNOTATION_ORIGIN_LOCATION]: `url:${location.toString()}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
entity,
|
||||
) as Entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks the progress of the PuppetDB read and commit operations.
|
||||
*
|
||||
* @param logger - The instance of a {@link Logger}.
|
||||
*/
|
||||
function trackProgress(logger: Logger) {
|
||||
let timestamp = Date.now();
|
||||
|
||||
function markReadComplete(entities: Entity[]) {
|
||||
const readDuration = ((Date.now() - timestamp) / 1000).toFixed(1);
|
||||
timestamp = Date.now();
|
||||
logger.info(
|
||||
`Read ${entities?.length ?? 0} in ${readDuration} seconds. Committing...`,
|
||||
);
|
||||
return { markCommitComplete };
|
||||
}
|
||||
|
||||
function markCommitComplete(entities: Entity[]) {
|
||||
const commitDuration = ((Date.now() - timestamp) / 1000).toFixed(1);
|
||||
logger.info(
|
||||
`Committed ${entities?.length ?? 0} in ${commitDuration} seconds.`,
|
||||
);
|
||||
}
|
||||
|
||||
return { markReadComplete };
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* 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 {
|
||||
readTaskScheduleDefinitionFromConfig,
|
||||
TaskScheduleDefinition,
|
||||
} from '@backstage/backend-tasks';
|
||||
import { Config } from '@backstage/config';
|
||||
import { DEFAULT_PROVIDER_ID } from './constants';
|
||||
|
||||
/**
|
||||
* Configuration of {@link PuppetDBEntityProvider}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type PuppetDBEntityProviderConfig = {
|
||||
/**
|
||||
* ID of the provider.
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* (Required) The host of PuppetDB API instance.
|
||||
*/
|
||||
host: string;
|
||||
/**
|
||||
* (Optional) PQL query to filter PuppetDB nodes.
|
||||
*/
|
||||
query?: string;
|
||||
/**
|
||||
* (Optional) Task schedule definition for the refresh.
|
||||
*/
|
||||
schedule?: TaskScheduleDefinition;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reads the configuration of the PuppetDB Entity Providers.
|
||||
*
|
||||
* @param config - The application configuration.
|
||||
*
|
||||
* @returns PuppetDB Entity Provider configurations list.
|
||||
*/
|
||||
export function readProviderConfigs(
|
||||
config: Config,
|
||||
): PuppetDBEntityProviderConfig[] {
|
||||
const providersConfig = config.getOptionalConfig(
|
||||
'catalog.providers.puppetdb',
|
||||
);
|
||||
if (!providersConfig) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (providersConfig.has('host')) {
|
||||
return [readProviderConfig(DEFAULT_PROVIDER_ID, providersConfig)];
|
||||
}
|
||||
|
||||
return providersConfig.keys().map(id => {
|
||||
return readProviderConfig(id, providersConfig.getConfig(id));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the configuration for the PuppetDB Entity Provider.
|
||||
*
|
||||
* @param id - ID of the provider.
|
||||
* @param config - The application configuration.
|
||||
*
|
||||
* @returns The PuppetDB Entity Provider configuration.
|
||||
*/
|
||||
function readProviderConfig(
|
||||
id: string,
|
||||
config: Config,
|
||||
): PuppetDBEntityProviderConfig {
|
||||
const host = config.getString('host').replace(/\/+$/, '');
|
||||
const query = config.getOptionalString('query');
|
||||
|
||||
const schedule = config.has('schedule')
|
||||
? readTaskScheduleDefinitionFromConfig(config.getConfig('schedule'))
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
id,
|
||||
host,
|
||||
query,
|
||||
schedule,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Name of the default provider when a using a simple configuration.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const DEFAULT_PROVIDER_ID = 'default';
|
||||
|
||||
/**
|
||||
* Default owner for entities created by the PuppetDB provider.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const DEFAULT_OWNER = 'unknown';
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* 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 { PuppetDBEntityProvider } from './PuppetDBEntityProvider';
|
||||
export type { PuppetDBEntityProviderConfig } from './PuppetDBEntityProviderConfig';
|
||||
export { DEFAULT_PROVIDER_ID, DEFAULT_OWNER } from './constants';
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Annotation for specifying the certificate name of a node in PuppetDB.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const ANNOTATION_PUPPET_CERTNAME = 'puppet.com/certname';
|
||||
|
||||
/**
|
||||
* Path of PuppetDB FactSets endpoint.
|
||||
*/
|
||||
export const ENDPOINT_FACTSETS = '/pdb/query/v4/factsets';
|
||||
|
||||
/**
|
||||
* Path of PuppetDB Nodes endpoint.
|
||||
*/
|
||||
export const ENDPOINT_NODES = '/pdb/query/v4/nodes';
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* 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 { ANNOTATION_PUPPET_CERTNAME } from './constants';
|
||||
export { defaultResourceTransformer } from './transformers';
|
||||
export type {
|
||||
PuppetNode,
|
||||
PuppetFactSet,
|
||||
PuppetFact,
|
||||
ResourceTransformer,
|
||||
} from './types';
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* 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 { PuppetDBEntityProviderConfig } from '../providers';
|
||||
import { PuppetNode, ResourceTransformer } from './types';
|
||||
import { ResourceEntity } from '@backstage/catalog-model/';
|
||||
import { defaultResourceTransformer } from './transformers';
|
||||
import { ResponseError } from '@backstage/errors';
|
||||
import { ENDPOINT_FACTSETS } from './constants';
|
||||
import { Logger } from 'winston';
|
||||
|
||||
/**
|
||||
* Reads nodes and their facts from PuppetDB.
|
||||
*
|
||||
* @param config - The provider configuration.
|
||||
* @param opts - Additional options.
|
||||
*/
|
||||
export async function readPuppetNodes(
|
||||
config: PuppetDBEntityProviderConfig,
|
||||
opts?: {
|
||||
transformer?: ResourceTransformer;
|
||||
logger?: Logger;
|
||||
},
|
||||
): Promise<ResourceEntity[]> {
|
||||
const transformFn = opts?.transformer ?? defaultResourceTransformer;
|
||||
const url = new URL(config.host);
|
||||
url.pathname = ENDPOINT_FACTSETS;
|
||||
|
||||
if (config.query) {
|
||||
url.searchParams.set('query', config.query);
|
||||
}
|
||||
|
||||
if (opts?.logger) {
|
||||
opts.logger
|
||||
.child({ url: url.toString() })
|
||||
.debug('Reading nodes from PuppetDB');
|
||||
}
|
||||
|
||||
const response = await fetch(url.toString(), {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw await ResponseError.fromResponse(response);
|
||||
}
|
||||
|
||||
const nodes = (await response.json()) as PuppetNode[];
|
||||
const entities: ResourceEntity[] = [];
|
||||
|
||||
for (const node of nodes) {
|
||||
const entity = await transformFn(node, config);
|
||||
if (entity) {
|
||||
entities.push(entity);
|
||||
}
|
||||
}
|
||||
|
||||
return entities;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* 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 { ResourceTransformer } from './types';
|
||||
import { DEFAULT_NAMESPACE, ResourceEntity } from '@backstage/catalog-model';
|
||||
import { DEFAULT_OWNER } from '../providers';
|
||||
import { ANNOTATION_PUPPET_CERTNAME } from './constants';
|
||||
|
||||
/**
|
||||
* A default implementation of the {@link ResourceTransformer}.
|
||||
*
|
||||
* @param node - The found PuppetDB node entry in its source format. This is the entry that you want to transform.
|
||||
* @param _config - The configuration for the entity provider.
|
||||
*
|
||||
* @returns A `ResourceEntity`.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const defaultResourceTransformer: ResourceTransformer = async (
|
||||
node,
|
||||
_config,
|
||||
) => {
|
||||
const certName = node.certname.toLowerCase();
|
||||
const type = node.facts?.data?.find(e => e.name === 'is_virtual')?.value
|
||||
? 'virtual-machine'
|
||||
: 'physical-server';
|
||||
const kernel = node.facts?.data?.find(e => e.name === 'kernel')?.value;
|
||||
|
||||
const entity: ResourceEntity = {
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
kind: 'Resource',
|
||||
metadata: {
|
||||
name: certName,
|
||||
annotations: {
|
||||
[ANNOTATION_PUPPET_CERTNAME]: certName,
|
||||
},
|
||||
namespace: DEFAULT_NAMESPACE,
|
||||
description: node.facts?.data
|
||||
?.find(e => e.name === 'ipaddress')
|
||||
?.value?.toString(),
|
||||
tags: kernel ? [kernel.toString().toLowerCase()] : [],
|
||||
},
|
||||
spec: {
|
||||
type: type,
|
||||
owner: DEFAULT_OWNER,
|
||||
dependsOn: [],
|
||||
dependencyOf: [],
|
||||
},
|
||||
};
|
||||
|
||||
return entity;
|
||||
};
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* 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 { ResourceEntity } from '@backstage/catalog-model';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { PuppetDBEntityProviderConfig } from '../providers/PuppetDBEntityProviderConfig';
|
||||
|
||||
/**
|
||||
* Customize the ingested Resource entity.
|
||||
*
|
||||
* @param node - The found PuppetDB node entry in its source format. This is the entry that you want to transform.
|
||||
* @param config - The configuration for the entity provider.
|
||||
*
|
||||
* @returns A `ResourceEntity` or `undefined` if you want to ignore the found group for being ingested by the catalog.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ResourceTransformer = (
|
||||
node: PuppetNode,
|
||||
config: PuppetDBEntityProviderConfig,
|
||||
) => Promise<ResourceEntity | undefined>;
|
||||
|
||||
/**
|
||||
* A node in PuppetDB.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type PuppetNode = {
|
||||
/**
|
||||
* The most recent time of fact submission from the associated certname.
|
||||
*/
|
||||
timestamp: string;
|
||||
/**
|
||||
* The certname associated with the factset.
|
||||
*/
|
||||
certname: string;
|
||||
/**
|
||||
* A hash of the factset's certname, environment, timestamp, facts, and producer_timestamp.
|
||||
*/
|
||||
hash: string;
|
||||
/**
|
||||
* The most recent time of fact submission for the relevant certname from the Puppet Server.
|
||||
*/
|
||||
producer_timestamp: string;
|
||||
/**
|
||||
* The certname of the Puppet Server that sent the factset to PuppetDB.
|
||||
*/
|
||||
producer: string;
|
||||
/**
|
||||
* The environment associated with the fact.
|
||||
*/
|
||||
environment: string;
|
||||
/**
|
||||
* The facts associated with the factset.
|
||||
*/
|
||||
facts: PuppetFactSet;
|
||||
};
|
||||
|
||||
/**
|
||||
* The set of all facts for a single certname in PuppetDB.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type PuppetFactSet = {
|
||||
/**
|
||||
* The array of facts.
|
||||
*/
|
||||
data: PuppetFact[];
|
||||
/**
|
||||
* The URL to retrieve more information about the facts.
|
||||
*/
|
||||
href: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* A fact in PuppetDB.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type PuppetFact = {
|
||||
/**
|
||||
* The name of the fact.
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* The value of the fact, in JSON format.
|
||||
*/
|
||||
value: JsonValue;
|
||||
};
|
||||
@@ -5211,10 +5211,16 @@ __metadata:
|
||||
resolution: "@backstage/plugin-catalog-backend-module-puppetdb-backend@workspace:plugins/catalog-backend-module-puppetdb"
|
||||
dependencies:
|
||||
"@backstage/backend-common": "workspace:^"
|
||||
"@backstage/backend-tasks": "workspace:^"
|
||||
"@backstage/catalog-model": "workspace:^"
|
||||
"@backstage/cli": "workspace:^"
|
||||
"@backstage/config": "workspace:^"
|
||||
"@backstage/errors": "workspace:^"
|
||||
"@backstage/plugin-catalog-backend": "workspace:^"
|
||||
"@backstage/types": "workspace:^"
|
||||
"@types/lodash": ^4.14.151
|
||||
lodash: ^4.17.21
|
||||
luxon: ^3.0.0
|
||||
msw: ^0.49.0
|
||||
node-fetch: ^2.6.7
|
||||
uuid: ^8.0.0
|
||||
|
||||
Reference in New Issue
Block a user