Implement the functionallity
Signed-off-by: Tomas Dabasinskas <tomas@dabasinskas.net>
This commit is contained in:
+1
-1
@@ -124,7 +124,7 @@ proxy:
|
||||
St2-Api-Key: ${ST2_API_KEY}
|
||||
|
||||
'/puppetdb':
|
||||
#target: https://your.puppetdb.instance.com
|
||||
target: https://your.puppetdb.instance.com
|
||||
|
||||
organization:
|
||||
name: My Company
|
||||
|
||||
@@ -116,7 +116,10 @@ import {
|
||||
EntityRollbarContent,
|
||||
isRollbarAvailable,
|
||||
} from '@backstage/plugin-rollbar';
|
||||
import { PuppetDbTab, isPuppetDbAvailable } from '@backstage/plugin-puppetdb';
|
||||
import {
|
||||
PuppetDbContent,
|
||||
isPuppetDbAvailable,
|
||||
} from '@backstage/plugin-puppetdb';
|
||||
import { EntitySentryContent } from '@backstage/plugin-sentry';
|
||||
import { EntityTechdocsContent } from '@backstage/plugin-techdocs';
|
||||
import { EntityTechInsightsScorecardCard } from '@backstage/plugin-tech-insights';
|
||||
@@ -858,7 +861,7 @@ const resourcePage = (
|
||||
title="Puppet"
|
||||
if={isPuppetDbAvailable}
|
||||
>
|
||||
<PuppetDbTab />
|
||||
<PuppetDbContent />
|
||||
</EntityLayout.Route>
|
||||
<EntityLayout.Route path="/todos" title="TODOs">
|
||||
<EntityTodoContent />
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 224 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 229 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 301 KiB |
@@ -34,9 +34,11 @@
|
||||
"postpack": "backstage-cli package postpack"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "workspace:^",
|
||||
"@backstage/core-components": "workspace:^",
|
||||
"@backstage/core-plugin-api": "workspace:^",
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@backstage/plugin-catalog-react": "workspace:^",
|
||||
"@backstage/theme": "workspace:^",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
|
||||
@@ -13,7 +13,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { PuppetDbApi, PuppetDbNode, PuppetDbReport } from './types';
|
||||
import {
|
||||
PuppetDbApi,
|
||||
PuppetDbReport,
|
||||
PuppetDbReportEvent,
|
||||
PuppetDbReportLog,
|
||||
} from './types';
|
||||
import { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';
|
||||
import { ResponseError } from '@backstage/errors';
|
||||
|
||||
@@ -51,19 +56,6 @@ export class PuppetDbClient implements PuppetDbApi {
|
||||
throw await ResponseError.fromResponse(response);
|
||||
}
|
||||
|
||||
async getPuppetDbNode(
|
||||
puppetDbCertName: string,
|
||||
): Promise<PuppetDbNode | undefined> {
|
||||
if (!puppetDbCertName) {
|
||||
throw new Error('PuppetDB certname is required');
|
||||
}
|
||||
|
||||
return this.callApi(
|
||||
`/pdb/query/v4/nodes/${encodeURIComponent(puppetDbCertName)}`,
|
||||
{},
|
||||
);
|
||||
}
|
||||
|
||||
async getPuppetDbReport(
|
||||
puppetDbReportHash: string,
|
||||
): Promise<PuppetDbReport | undefined> {
|
||||
@@ -82,6 +74,44 @@ export class PuppetDbClient implements PuppetDbApi {
|
||||
return reports[0];
|
||||
}
|
||||
|
||||
async getPuppetDbReportEvents(
|
||||
puppetDbReportHash: string,
|
||||
): Promise<PuppetDbReportEvent[] | undefined> {
|
||||
if (!puppetDbReportHash) {
|
||||
throw new Error('PuppetDB report hash is required');
|
||||
}
|
||||
|
||||
const events = (await this.callApi(
|
||||
`/pdb/query/v4/reports/${puppetDbReportHash}/events`,
|
||||
{},
|
||||
)) as PuppetDbReportEvent[];
|
||||
|
||||
if (!events || events.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
async getPuppetDbReportLogs(
|
||||
puppetDbReportHash: string,
|
||||
): Promise<PuppetDbReportLog[] | undefined> {
|
||||
if (!puppetDbReportHash) {
|
||||
throw new Error('PuppetDB report hash is required');
|
||||
}
|
||||
|
||||
const events = (await this.callApi(
|
||||
`/pdb/query/v4/reports/${puppetDbReportHash}/logs`,
|
||||
{},
|
||||
)) as PuppetDbReportLog[];
|
||||
|
||||
if (!events || events.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
async getPuppetDbNodeReports(
|
||||
puppetDbCertName: string,
|
||||
): Promise<PuppetDbReport[] | undefined> {
|
||||
@@ -92,7 +122,7 @@ export class PuppetDbClient implements PuppetDbApi {
|
||||
return this.callApi(`/pdb/query/v4/reports`, {
|
||||
query: `["=","certname","${puppetDbCertName}"]`,
|
||||
order_by: `[{"field": "start_time", "order": "desc"},{"field": "end_time", "order": "desc"}]`,
|
||||
limit: 30,
|
||||
limit: 100,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export type { PuppetDbNode, PuppetDbReport } from './types';
|
||||
export type { PuppetDbReport, PuppetDbReportEvent } from './types';
|
||||
export { puppetDbApiRef } from './types';
|
||||
export { PuppetDbClient } from './PuppetDbClient';
|
||||
|
||||
+115
-148
@@ -15,179 +15,131 @@
|
||||
*/
|
||||
import { createApiRef } from '@backstage/core-plugin-api';
|
||||
|
||||
/**
|
||||
* A node in PuppetDB.
|
||||
*/
|
||||
export type PuppetDbNode = {
|
||||
/**
|
||||
* The name of the node that the report was received from.
|
||||
*/
|
||||
certname: string;
|
||||
/**
|
||||
* The environment for the last received catalog.
|
||||
*/
|
||||
catalog_environment: string;
|
||||
/**
|
||||
* The environment for the last received fact set.
|
||||
*/
|
||||
facts_environment: string;
|
||||
/**
|
||||
* The environment for the last received report.
|
||||
*/
|
||||
report_environment: string;
|
||||
/**
|
||||
* The last time a catalog was received. Timestamps are always ISO-8601 compatible date/time strings.
|
||||
*/
|
||||
catalog_timestamp: string;
|
||||
/**
|
||||
* The last time a fact set was received. Timestamps are always ISO-8601 compatible date/time strings.
|
||||
*/
|
||||
facts_timestamp: string;
|
||||
/**
|
||||
* The last time a report run was complete. Timestamps are always ISO-8601 compatible date/time strings.
|
||||
*/
|
||||
report_timestamp: string;
|
||||
/**
|
||||
* The status of the latest report. Possible values come from Puppet's report status.
|
||||
*/
|
||||
latest_report_status: string;
|
||||
/**
|
||||
* Indicates whether the most recent report for the node was a noop run.
|
||||
*/
|
||||
latest_report_noop: boolean;
|
||||
/**
|
||||
* Indicates whether the most recent report for the node contained noop events.
|
||||
*/
|
||||
latest_report_noop_pending: boolean;
|
||||
/**
|
||||
* A flag indicating whether the latest report for the node included events that remediated configuration drift.
|
||||
*/
|
||||
latest_report_corrective_change: boolean;
|
||||
/**
|
||||
* Cached catalog status of the last puppet run for the node. Possible values are explicitly_requested, on_failure, not_used or null.
|
||||
*/
|
||||
cached_catalog_status: string;
|
||||
/**
|
||||
* A hash of the latest report for the node.
|
||||
*/
|
||||
latest_report_hash: string;
|
||||
/**
|
||||
* The job id associated with the latest report.
|
||||
*/
|
||||
latest_report_job_id?: string;
|
||||
/**
|
||||
* Indicates whether the node is currently in the deactivated state.
|
||||
*/
|
||||
deactivated?: boolean;
|
||||
/**
|
||||
* Indicates whether the node is currently in the expired state.
|
||||
*/
|
||||
expired?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Report from a PuppetDB.
|
||||
*/
|
||||
export type PuppetDbReport = {
|
||||
/**
|
||||
* The name of the node that the report was received from.
|
||||
*/
|
||||
/** The name of the node that the report was received from. */
|
||||
certname: string;
|
||||
/**
|
||||
* The ID of the report.
|
||||
*/
|
||||
/** The ID of the report. */
|
||||
hash: string;
|
||||
/**
|
||||
* The environment assigned to the node that submitted the report.
|
||||
*/
|
||||
/** The environment assigned to the node that submitted the report. */
|
||||
environment: string;
|
||||
/**
|
||||
* The status associated to report's node.
|
||||
*/
|
||||
/** The status associated to report's node. */
|
||||
status: string;
|
||||
/**
|
||||
* The job id associated with the report.
|
||||
*/
|
||||
/** The job id associated with the report. */
|
||||
job_id?: string;
|
||||
/**
|
||||
* A flag indicating whether the report was produced by a noop run.
|
||||
*/
|
||||
/** A flag indicating whether the report was produced by a noop run. */
|
||||
noop: boolean;
|
||||
/**
|
||||
* A flag indicating whether the report contains noop events.
|
||||
*/
|
||||
/** A flag indicating whether the report contains noop events. */
|
||||
noop_pending?: boolean;
|
||||
/**
|
||||
* The version of Puppet that generated the report.
|
||||
*/
|
||||
/** The version of Puppet that generated the report. */
|
||||
puppet_version: string;
|
||||
/**
|
||||
* The version number of the report format that Puppet used to generate the original report data.
|
||||
*/
|
||||
/** The version number of the report format that Puppet used to generate the original report data. */
|
||||
report_format: number;
|
||||
/**
|
||||
* An identifier string that Puppet uses to match a specific catalog for a node to a specific Puppet run.
|
||||
*/
|
||||
/** An identifier string that Puppet uses to match a specific catalog for a node to a specific Puppet run. */
|
||||
configuration_version: string;
|
||||
/**
|
||||
* The time on the agent at which the Puppet run began.
|
||||
*/
|
||||
/** The time on the agent at which the Puppet run began. */
|
||||
start_time: string;
|
||||
/**
|
||||
* The time on the agent at which the Puppet run ended.
|
||||
*/
|
||||
/** The time on the agent at which the Puppet run ended. */
|
||||
end_time: string;
|
||||
/**
|
||||
* The time of catalog submission from the Puppet Server to PuppetDB.
|
||||
*/
|
||||
/** The time of catalog submission from the Puppet Server to PuppetDB. */
|
||||
producer_timestamp: string;
|
||||
/**
|
||||
* The time at which PuppetDB received the report.
|
||||
*/
|
||||
/** The time at which PuppetDB received the report. */
|
||||
receive_time: string;
|
||||
/**
|
||||
* The certname of the Puppet Server that sent the report to PuppetDB.
|
||||
*/
|
||||
/** The certname of the Puppet Server that sent the report to PuppetDB. */
|
||||
producer: string;
|
||||
/**
|
||||
* A string used to identify a Puppet run.
|
||||
*/
|
||||
/** A string used to identify a Puppet run. */
|
||||
transaction_uuid: string;
|
||||
/**
|
||||
* A string used to tie a catalog to a report to the catalog used from that Puppet run.
|
||||
*/
|
||||
/** A string used to tie a catalog to a report to the catalog used from that Puppet run. */
|
||||
catalog_uuid: string;
|
||||
/**
|
||||
* A string used to tie a catalog to the Puppet code which generated the catalog.
|
||||
*/
|
||||
/** A string used to tie a catalog to the Puppet code which generated the catalog. */
|
||||
code_id: string;
|
||||
/**
|
||||
* A string used to identify whether the Puppet run used a cached catalogs.
|
||||
*/
|
||||
/** A string used to identify whether the Puppet run used a cached catalogs. */
|
||||
cached_catalog_status: string;
|
||||
/**
|
||||
* Either "agent", "plan", or "any" to restrict the results to reports submitted from that source.
|
||||
*/
|
||||
/** Either "agent", "plan", or "any" to restrict the results to reports submitted from that source. */
|
||||
type: string;
|
||||
/**
|
||||
* A flag indicating whether any of the report's events remediated configuration drift.
|
||||
*/
|
||||
/** A flag indicating whether any of the report's events remediated configuration drift. */
|
||||
corrective_change: boolean;
|
||||
/**
|
||||
* Report metrics.
|
||||
*/
|
||||
/** Report metrics. */
|
||||
metrics: {
|
||||
/**
|
||||
* Metrics data.
|
||||
*/
|
||||
/** Metrics data. */
|
||||
data: PuppetDbReportMetric[];
|
||||
/**
|
||||
* Link to the metrics endpoint.
|
||||
*/
|
||||
/** Link to the metrics endpoint. */
|
||||
href: string;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Resource event generated from Puppet report.
|
||||
*/
|
||||
export type PuppetDbReportEvent = {
|
||||
/** The name of the node on which the event occurred. */
|
||||
certname: string;
|
||||
/** The ID of the report that the event occurred in. */
|
||||
report: string;
|
||||
/** The status of the event. Legal values are success, failure, noop, and skipped. */
|
||||
status: string;
|
||||
/** The timestamp (from the Puppet agent) at which the event occurred. Timestamps are always ISO-8601 compatible date/time strings. */
|
||||
timestamp: string;
|
||||
/** The timestamp (from the Puppet agent) at which the Puppet run began. Timestamps are always ISO-8601 compatible date/time strings. */
|
||||
run_start_time: string;
|
||||
/** The timestamp (from the Puppet agent) at which the Puppet run finished. Timestamps are always ISO-8601 compatible date/time strings. */
|
||||
run_end_time: string;
|
||||
/** The timestamp (from the PuppetDB server) at which the Puppet report was received. Timestamps are always ISO-8601 compatible date/time strings. */
|
||||
report_receive_time: string;
|
||||
/** The type of resource that the event occurred on, such as File, Package, etc. */
|
||||
resource_type: string;
|
||||
/** The title of the resource on which the event occurred. */
|
||||
resource_title: string;
|
||||
/** The property/parameter of the resource on which the event occurred. For example, on a Package resource, this field might have a value of ensure. */
|
||||
property: string | null;
|
||||
/** The name of the resource on which the event occurred. */
|
||||
name: string | null;
|
||||
/** The new value that Puppet was attempting to set for the specified resource property. Any rich data values will appear as readable strings. */
|
||||
new_value: string | null;
|
||||
/** The previous value of the resource property, which Puppet was attempting to change. Any rich data values will appear as readable strings. */
|
||||
old_value: string | null;
|
||||
/** A description (supplied by the resource provider) of what happened during the event. */
|
||||
message: string | null;
|
||||
/** The manifest file in which the resource definition is located. */
|
||||
file: string | null;
|
||||
/** The line (of the containing manifest file) at which the resource definition can be found. */
|
||||
line: number | null;
|
||||
/** The Puppet class where this resource is declared. */
|
||||
containing_class: string | null;
|
||||
/** Whether the event occurred in the most recent Puppet run (per-node). */
|
||||
latest_report?: boolean;
|
||||
/** The environment associated with the reporting node. */
|
||||
environment: string;
|
||||
/** An identifier string that Puppet uses to match a specific catalog for a node to a specific Puppet run. */
|
||||
configuration_version: string;
|
||||
/** The containment path associated with the event, as an ordered array that ends with the most specific containing element. */
|
||||
containment_path: string[];
|
||||
/** Whether the event represents a "corrective change", meaning the event rectified configuration drift. */
|
||||
corrective_change: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resource log generated from Puppet report.
|
||||
*/
|
||||
export type PuppetDbReportLog = {
|
||||
/** The manifest file in which the resource definition is located. */
|
||||
file: string | null;
|
||||
/** The line (of the containing manifest file) at which the resource definition can be found. */
|
||||
line: number | null;
|
||||
/** The timestamp (from the Puppet agent) at which the event occurred. Timestamps are always ISO-8601 compatible date/time strings. */
|
||||
time: string;
|
||||
/** A description (supplied by the resource provider) of what happened during the event. */
|
||||
message: string | null;
|
||||
/** The log level. */
|
||||
level: string;
|
||||
/** Log source */
|
||||
source: string;
|
||||
/** Resource tags */
|
||||
tags: string[];
|
||||
};
|
||||
|
||||
/**
|
||||
* A metric from a PuppetDB report.
|
||||
*/
|
||||
@@ -214,12 +166,6 @@ export const puppetDbApiRef = createApiRef<PuppetDbApi>({
|
||||
* The API provided by the PuppetDB plugin.
|
||||
*/
|
||||
export type PuppetDbApi = {
|
||||
/**
|
||||
*
|
||||
* @param puppetDbCertName - The name of the PuppetDB node.
|
||||
* @returns A PuppetDB node.
|
||||
*/
|
||||
getPuppetDbNode(puppetDbCertName: string): Promise<PuppetDbNode | undefined>;
|
||||
/**
|
||||
* Get a list of PuppetDB reports for the specified node.
|
||||
*
|
||||
@@ -229,6 +175,7 @@ export type PuppetDbApi = {
|
||||
getPuppetDbNodeReports(
|
||||
puppetDbCertName: string,
|
||||
): Promise<PuppetDbReport[] | undefined>;
|
||||
|
||||
/**
|
||||
* Get a specific PuppetDB report.
|
||||
*
|
||||
@@ -238,4 +185,24 @@ export type PuppetDbApi = {
|
||||
getPuppetDbReport(
|
||||
puppetDbReportHash: string,
|
||||
): Promise<PuppetDbReport | undefined>;
|
||||
|
||||
/**
|
||||
* Get a specific PuppetDB report events.
|
||||
*
|
||||
* @param puppetDbReportHash - The ID of the report.
|
||||
* @returns Events from a specific PuppetDB report.
|
||||
*/
|
||||
getPuppetDbReportEvents(
|
||||
puppetDbReportHash: string,
|
||||
): Promise<PuppetDbReportEvent[] | undefined>;
|
||||
|
||||
/**
|
||||
* Get a specific PuppetDB report logs.
|
||||
*
|
||||
* @param puppetDbReportHash - The ID of the report.
|
||||
* @returns Logs from a specific PuppetDB report.
|
||||
*/
|
||||
getPuppetDbReportLogs(
|
||||
puppetDbReportHash: string,
|
||||
): Promise<PuppetDbReportLog[] | undefined>;
|
||||
};
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 React from 'react';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { Progress, ResponseErrorPanel } from '@backstage/core-components';
|
||||
import { InfoCard } from '@backstage/core-components';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { puppetDbApiRef } from '../../../api';
|
||||
|
||||
type PuppetDbNodeCardProps = {
|
||||
certName: string;
|
||||
};
|
||||
|
||||
export const NodeCard = (props: PuppetDbNodeCardProps) => {
|
||||
const { certName } = props;
|
||||
const puppetDbApi = useApi(puppetDbApiRef);
|
||||
|
||||
const { value, loading, error } = useAsync(async () => {
|
||||
return puppetDbApi.getPuppetDbReport(certName);
|
||||
}, [puppetDbApi, certName]);
|
||||
|
||||
if (loading) {
|
||||
return <Progress />;
|
||||
} else if (error) {
|
||||
return <ResponseErrorPanel error={error} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<InfoCard title={`Puppet node: ${certName}`}>
|
||||
<pre>{JSON.stringify(value, null, 2)}</pre>
|
||||
</InfoCard>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2022 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 Typography from '@material-ui/core/Typography';
|
||||
import React from 'react';
|
||||
import { puppetDbApiRef } from '../../api';
|
||||
import {
|
||||
ResponseErrorPanel,
|
||||
Table,
|
||||
TableColumn,
|
||||
} from '@backstage/core-components';
|
||||
import { PuppetDbReportEvent } from '../../api/types';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { StatusField } from '../StatusField';
|
||||
|
||||
type ReportEventsTableProps = {
|
||||
hash: string;
|
||||
};
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
empty: {
|
||||
padding: theme.spacing(2),
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
}));
|
||||
|
||||
/**
|
||||
* Component for displaying PuppetDB report events.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const ReportDetailsEventsTable = (props: ReportEventsTableProps) => {
|
||||
const { hash } = props;
|
||||
const puppetDbApi = useApi(puppetDbApiRef);
|
||||
const classes = useStyles();
|
||||
const { value, loading, error } = useAsync(async () => {
|
||||
return puppetDbApi.getPuppetDbReportEvents(hash);
|
||||
}, [puppetDbApi, hash]);
|
||||
|
||||
if (error) {
|
||||
return <ResponseErrorPanel error={error} />;
|
||||
}
|
||||
|
||||
const columns: TableColumn<PuppetDbReportEvent>[] = [
|
||||
{
|
||||
title: 'Run Start Time',
|
||||
field: 'run_start_time',
|
||||
align: 'center',
|
||||
width: '300px',
|
||||
render: rowData => (
|
||||
<Typography noWrap>
|
||||
{new Date(Date.parse(rowData.run_start_time)).toLocaleString()}
|
||||
</Typography>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Run End Time',
|
||||
field: 'run_end_time',
|
||||
align: 'center',
|
||||
width: '300px',
|
||||
render: rowData => (
|
||||
<Typography noWrap>
|
||||
{new Date(Date.parse(rowData.run_end_time)).toLocaleString()}
|
||||
</Typography>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Containing Class',
|
||||
field: 'containing_class',
|
||||
render: rowData => (
|
||||
<Typography noWrap title={rowData.file || ''}>
|
||||
{rowData.containing_class}
|
||||
</Typography>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Resource',
|
||||
field: 'resource_title',
|
||||
render: rowData => (
|
||||
<Typography noWrap>
|
||||
{rowData.resource_type}[{rowData.resource_title}]
|
||||
</Typography>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Property',
|
||||
field: 'property',
|
||||
render: rowData => <Typography noWrap>{rowData.property}</Typography>,
|
||||
},
|
||||
{
|
||||
title: 'Old Value',
|
||||
field: 'old_value',
|
||||
render: rowData => <Typography noWrap>{rowData.old_value}</Typography>,
|
||||
},
|
||||
{
|
||||
title: 'New Value',
|
||||
field: 'new_value',
|
||||
render: rowData => <Typography noWrap>{rowData.new_value}</Typography>,
|
||||
},
|
||||
{
|
||||
title: 'Status',
|
||||
field: 'status',
|
||||
render: rowData => <StatusField status={rowData.status} />,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Table
|
||||
options={{
|
||||
sorting: true,
|
||||
actionsColumnIndex: -1,
|
||||
loadingType: 'linear',
|
||||
padding: 'dense',
|
||||
showEmptyDataSourceMessage: !loading,
|
||||
showTitle: true,
|
||||
toolbar: true,
|
||||
pageSize: 10,
|
||||
pageSizeOptions: [10],
|
||||
}}
|
||||
emptyContent={
|
||||
<Typography color="textSecondary" className={classes.empty}>
|
||||
No events
|
||||
</Typography>
|
||||
}
|
||||
title="Latest events"
|
||||
columns={columns}
|
||||
data={value || []}
|
||||
isLoading={loading}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2022 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 Typography from '@material-ui/core/Typography';
|
||||
import React from 'react';
|
||||
import { puppetDbApiRef } from '../../api';
|
||||
import {
|
||||
ResponseErrorPanel,
|
||||
Table,
|
||||
TableColumn,
|
||||
} from '@backstage/core-components';
|
||||
import { PuppetDbReportLog } from '../../api/types';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
|
||||
type ReportLogsTableProps = {
|
||||
hash: string;
|
||||
};
|
||||
|
||||
const useStyles = makeStyles<BackstageTheme>(theme => ({
|
||||
empty: {
|
||||
padding: theme.spacing(2),
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
level_error: {
|
||||
color: theme.palette.error.light,
|
||||
},
|
||||
level_warning: {
|
||||
color: theme.palette.warning.light,
|
||||
},
|
||||
level_notice: {
|
||||
color: theme.palette.info.light,
|
||||
},
|
||||
}));
|
||||
|
||||
/**
|
||||
* Component for displaying PuppetDB report logs.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const ReportDetailsLogsTable = (props: ReportLogsTableProps) => {
|
||||
const { hash } = props;
|
||||
const puppetDbApi = useApi(puppetDbApiRef);
|
||||
const classes = useStyles();
|
||||
const { value, loading, error } = useAsync(async () => {
|
||||
return puppetDbApi.getPuppetDbReportLogs(hash);
|
||||
}, [puppetDbApi, hash]);
|
||||
|
||||
if (error) {
|
||||
return <ResponseErrorPanel error={error} />;
|
||||
}
|
||||
|
||||
const columns: TableColumn<PuppetDbReportLog>[] = [
|
||||
{
|
||||
title: 'Level',
|
||||
field: 'level',
|
||||
align: 'center',
|
||||
width: '100px',
|
||||
render: rowData => (
|
||||
<Typography
|
||||
noWrap
|
||||
className={
|
||||
(rowData.level === 'warning' && classes.level_warning) ||
|
||||
(rowData.level === 'error' && classes.level_error) ||
|
||||
classes.level_notice
|
||||
}
|
||||
>
|
||||
{rowData.level.toLocaleUpperCase('en-US')}
|
||||
</Typography>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Timestamp',
|
||||
field: 'time',
|
||||
align: 'center',
|
||||
width: '300px',
|
||||
render: rowData => (
|
||||
<Typography noWrap>
|
||||
{new Date(Date.parse(rowData.time)).toLocaleString()}
|
||||
</Typography>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Source',
|
||||
field: 'source',
|
||||
render: rowData => <Typography noWrap>{rowData.source}</Typography>,
|
||||
},
|
||||
{
|
||||
title: 'Message',
|
||||
field: 'message',
|
||||
render: rowData => <Typography noWrap>{rowData.message}</Typography>,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Table
|
||||
options={{
|
||||
sorting: true,
|
||||
actionsColumnIndex: -1,
|
||||
loadingType: 'linear',
|
||||
padding: 'dense',
|
||||
showEmptyDataSourceMessage: !loading,
|
||||
showTitle: true,
|
||||
toolbar: true,
|
||||
pageSize: 10,
|
||||
pageSizeOptions: [10],
|
||||
}}
|
||||
emptyContent={
|
||||
<Typography color="textSecondary" className={classes.empty}>
|
||||
No logs
|
||||
</Typography>
|
||||
}
|
||||
title="Latest logs"
|
||||
columns={columns}
|
||||
data={value || []}
|
||||
isLoading={loading}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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 { Link as RouterLink, useParams } from 'react-router-dom';
|
||||
import { Breadcrumbs, Link } from '@backstage/core-components';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { useRouteRef } from '@backstage/core-plugin-api';
|
||||
import { puppetDbRouteRef } from '../../routes';
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
Tab,
|
||||
Box,
|
||||
Typography,
|
||||
Tabs,
|
||||
} from '@material-ui/core';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { ReportDetailsEventsTable } from './ReportDetailsEventsTable';
|
||||
import { ReportDetailsLogsTable } from './ReportDetailsLogsTable';
|
||||
|
||||
const useStyles = makeStyles<BackstageTheme>(theme => ({
|
||||
cards: {
|
||||
marginTop: theme.spacing(2),
|
||||
},
|
||||
tabs: {
|
||||
borderBottom: `1px solid ${theme.palette.textVerySubtle}`,
|
||||
backgroundColor: theme.palette.background.default,
|
||||
padding: theme.spacing(0, 4),
|
||||
},
|
||||
default: {
|
||||
padding: theme.spacing(2),
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
color: theme.palette.text.secondary,
|
||||
textTransform: 'uppercase',
|
||||
},
|
||||
selected: {
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
}));
|
||||
|
||||
/**
|
||||
* Component for displaying the details of a PuppetDB report.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const ReportDetailsPage = () => {
|
||||
const { hash = '' } = useParams();
|
||||
const classes = useStyles();
|
||||
const [tabIndex, setTabIndex] = useState(0);
|
||||
const reportsRouteLink = useRouteRef(puppetDbRouteRef);
|
||||
const tabs = [
|
||||
{ id: 'events', label: 'Events' },
|
||||
{ id: 'logs', label: 'Logs' },
|
||||
];
|
||||
const safeTabIndex = tabIndex > tabs.length - 1 ? 0 : tabIndex;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Breadcrumbs aria-label="breadcrumb">
|
||||
<Link component={RouterLink} to={reportsRouteLink()}>
|
||||
PuppetDB Reports
|
||||
</Link>
|
||||
<Typography noWrap>{hash}</Typography>
|
||||
</Breadcrumbs>
|
||||
<Card
|
||||
style={{ position: 'relative', overflow: 'visible' }}
|
||||
className={classes.cards}
|
||||
>
|
||||
<CardContent>
|
||||
<Tabs
|
||||
indicatorColor="primary"
|
||||
onChange={(_, index) => setTabIndex(index)}
|
||||
value={safeTabIndex}
|
||||
>
|
||||
{tabs.map((tab, index) => (
|
||||
<Tab
|
||||
className={classes.default}
|
||||
label={tab.label}
|
||||
key={tab.id}
|
||||
value={index}
|
||||
classes={{ selected: classes.selected }}
|
||||
/>
|
||||
))}
|
||||
</Tabs>
|
||||
<Box ml={2} pt={2} my={1} display="flex" flexDirection="column">
|
||||
{safeTabIndex === 0 && <ReportDetailsEventsTable hash={hash} />}
|
||||
{safeTabIndex === 1 && <ReportDetailsLogsTable hash={hash} />}
|
||||
</Box>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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 { ReportDetailsPage } from './ReportDetailsPage';
|
||||
export { ReportDetailsEventsTable } from './ReportDetailsEventsTable';
|
||||
export { ReportDetailsLogsTable } from './ReportDetailsLogsTable';
|
||||
+11
-20
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
* 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.
|
||||
@@ -14,29 +14,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import {
|
||||
Page,
|
||||
Content,
|
||||
MissingAnnotationEmptyState,
|
||||
} from '@backstage/core-components';
|
||||
import { ReportsTable } from './ReportsTable';
|
||||
import { Page, Content } from '@backstage/core-components';
|
||||
import { useEntity } from '@backstage/plugin-catalog-react';
|
||||
import { isPuppetDbAvailable } from '../../plugin';
|
||||
import { ANNOTATION_PUPPET_CERTNAME } from '../../constants';
|
||||
import { ReportsTable } from '../Reports/ReportsTable/ReportsTable';
|
||||
import { NodeCard } from '../Node';
|
||||
|
||||
export const PuppetDbTab = () => {
|
||||
/**
|
||||
* Component to display PuppetDB reports page.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const ReportsPage = () => {
|
||||
const { entity } = useEntity();
|
||||
|
||||
if (!isPuppetDbAvailable(entity)) {
|
||||
return (
|
||||
<MissingAnnotationEmptyState annotation={ANNOTATION_PUPPET_CERTNAME} />
|
||||
);
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
// TODO(tdabasinskas): Remove the static value after the testing.
|
||||
const certName = entity.metadata.annotations[ANNOTATION_PUPPET_CERTNAME];
|
||||
const certName =
|
||||
entity?.metadata?.annotations?.[ANNOTATION_PUPPET_CERTNAME] ?? '';
|
||||
|
||||
return (
|
||||
<Page themeId="tool">
|
||||
+26
-105
@@ -13,25 +13,21 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { puppetDbApiRef, PuppetDbReport } from '../../../api';
|
||||
import { puppetDbApiRef, PuppetDbReport } from '../../api';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import React from 'react';
|
||||
import {
|
||||
Link,
|
||||
ResponseErrorPanel,
|
||||
Table,
|
||||
StatusPending,
|
||||
StatusRunning,
|
||||
StatusOK,
|
||||
StatusAborted,
|
||||
StatusError,
|
||||
TableColumn,
|
||||
} from '@backstage/core-components';
|
||||
import { useApi, useRouteRef } from '@backstage/core-plugin-api';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { Link as RouterLink } from 'react-router-dom';
|
||||
import { buildRouteRef } from '../../../routes';
|
||||
import { puppetDbReportRouteRef } from '../../routes';
|
||||
import { StatusField } from '../StatusField';
|
||||
|
||||
type ReportsTableProps = {
|
||||
certName: string;
|
||||
@@ -45,10 +41,15 @@ const useStyles = makeStyles(theme => ({
|
||||
},
|
||||
}));
|
||||
|
||||
/**
|
||||
* Component for displaying a table of PuppetDB reports for a given node.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const ReportsTable = (props: ReportsTableProps) => {
|
||||
const { certName } = props;
|
||||
const puppetDbApi = useApi(puppetDbApiRef);
|
||||
const routeLink = useRouteRef(buildRouteRef);
|
||||
const reportsRouteLink = useRouteRef(puppetDbReportRouteRef);
|
||||
const classes = useStyles();
|
||||
|
||||
const { value, loading, error } = useAsync(async () => {
|
||||
@@ -64,8 +65,17 @@ export const ReportsTable = (props: ReportsTableProps) => {
|
||||
title: 'Configuration Version',
|
||||
field: 'configuration_version',
|
||||
render: rowData => (
|
||||
<Link component={RouterLink} to={routeLink({ hash: rowData.hash! })}>
|
||||
<Typography noWrap>{rowData.configuration_version}</Typography>
|
||||
<Link
|
||||
component={RouterLink}
|
||||
to={reportsRouteLink({ hash: rowData.hash! })}
|
||||
>
|
||||
{rowData.configuration_version !== '' ? (
|
||||
<Typography noWrap>{rowData.configuration_version}</Typography>
|
||||
) : (
|
||||
<Typography noWrap>
|
||||
<em>(N/A)</em>
|
||||
</Typography>
|
||||
)}
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
@@ -73,8 +83,9 @@ export const ReportsTable = (props: ReportsTableProps) => {
|
||||
title: 'Start Time',
|
||||
field: 'start_time',
|
||||
align: 'center',
|
||||
width: '300px',
|
||||
render: rowData => (
|
||||
<Typography>
|
||||
<Typography noWrap>
|
||||
{new Date(Date.parse(rowData.start_time)).toLocaleString()}
|
||||
</Typography>
|
||||
),
|
||||
@@ -83,8 +94,9 @@ export const ReportsTable = (props: ReportsTableProps) => {
|
||||
title: 'End Time',
|
||||
field: 'end_time',
|
||||
align: 'center',
|
||||
width: '300px',
|
||||
render: rowData => (
|
||||
<Typography>
|
||||
<Typography noWrap>
|
||||
{new Date(Date.parse(rowData.end_time)).toLocaleString()}
|
||||
</Typography>
|
||||
),
|
||||
@@ -92,6 +104,7 @@ export const ReportsTable = (props: ReportsTableProps) => {
|
||||
{
|
||||
title: 'Run Duration',
|
||||
align: 'center',
|
||||
width: '400px',
|
||||
render: rowData => {
|
||||
const start_date = new Date(Date.parse(rowData.start_time));
|
||||
const end_date = new Date(Date.parse(rowData.end_time));
|
||||
@@ -125,52 +138,7 @@ export const ReportsTable = (props: ReportsTableProps) => {
|
||||
title: 'Status',
|
||||
field: 'status',
|
||||
align: 'center',
|
||||
render: rowData => {
|
||||
if (rowData.noop) {
|
||||
return (
|
||||
<>
|
||||
<StatusAborted />
|
||||
{rowData.status.charAt(0).toLocaleUpperCase() +
|
||||
rowData.status.slice(1)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
switch (rowData.status) {
|
||||
case 'failed':
|
||||
return (
|
||||
<>
|
||||
<StatusError />
|
||||
{rowData.status.charAt(0).toLocaleUpperCase() +
|
||||
rowData.status.slice(1)}
|
||||
</>
|
||||
);
|
||||
case 'changed':
|
||||
return (
|
||||
<>
|
||||
<StatusRunning />
|
||||
{rowData.status.charAt(0).toLocaleUpperCase() +
|
||||
rowData.status.slice(1)}
|
||||
</>
|
||||
);
|
||||
case 'unchanged':
|
||||
return (
|
||||
<>
|
||||
<StatusPending />
|
||||
{rowData.status.charAt(0).toLocaleUpperCase() +
|
||||
rowData.status.slice(1)}
|
||||
</>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<>
|
||||
<StatusOK />
|
||||
{rowData.status.charAt(0).toLocaleUpperCase() +
|
||||
rowData.status.slice(1)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
},
|
||||
render: rowData => <StatusField status={rowData.status} />,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -198,51 +166,4 @@ export const ReportsTable = (props: ReportsTableProps) => {
|
||||
isLoading={loading}
|
||||
/>
|
||||
);
|
||||
|
||||
/*
|
||||
return (
|
||||
|
||||
|
||||
|
||||
<TableContainer className={classes.table}>
|
||||
<Table size="small">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Start Time</TableCell>
|
||||
<TableCell>End Time</TableCell>
|
||||
<TableCell>Duration</TableCell>
|
||||
<TableCell>Environment</TableCell>
|
||||
<TableCell>Configuration Version</TableCell>
|
||||
<TableCell>Puppet Version</TableCell>
|
||||
<TableCell>NoOp</TableCell>
|
||||
<TableCell>Status</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{value?.map((report) => {
|
||||
const start_date = new Date(Date.parse(report.start_time));
|
||||
const end_date = new Date(Date.parse(report.end_time));
|
||||
const duration = new Date(end_date.getTime() - start_date.getTime());
|
||||
|
||||
return (<TableRow>
|
||||
<TableCell>{start_date.toLocaleString()}</TableCell>
|
||||
<TableCell>{end_date.toLocaleString()}</TableCell>
|
||||
<TableCell>
|
||||
{duration.getUTCHours().toString().padStart(2, '0')}:
|
||||
{duration.getUTCMinutes().toString().padStart(2, '0')}:
|
||||
{duration.getUTCSeconds().toString().padStart(2, '0')}.
|
||||
{duration.getUTCMilliseconds().toString().padStart(4, '0')}
|
||||
</TableCell>
|
||||
<TableCell>{report.environment}</TableCell>
|
||||
<TableCell>{report.configuration_version}</TableCell>
|
||||
<TableCell>{report.puppet_version}</TableCell>
|
||||
<TableCell>{report.noop ? 'Yes' : 'No'}</TableCell>
|
||||
<TableCell>{report.status}</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
);*/
|
||||
};
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
* 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.
|
||||
@@ -13,4 +13,5 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { NodeCard } from './NodeCard/NodeCard';
|
||||
export { ReportsPage } from './ReportsPage';
|
||||
export { ReportsTable } from './ReportsTable';
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 React from 'react';
|
||||
import { Routes, Route } from 'react-router-dom';
|
||||
import { puppetDbReportRouteRef } from '../routes';
|
||||
import { ANNOTATION_PUPPET_CERTNAME } from '../constants';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { useEntity } from '@backstage/plugin-catalog-react';
|
||||
import { MissingAnnotationEmptyState } from '@backstage/core-components';
|
||||
import { ReportsPage } from './ReportsPage/ReportsPage';
|
||||
import { ReportDetailsPage } from './ReportDetailsPage';
|
||||
|
||||
/**
|
||||
* Checks if the entity has a puppet certname annotation.
|
||||
* @param entity - The entity to check for the puppet certname annotation.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const isPuppetDbAvailable = (entity: Entity) =>
|
||||
Boolean(entity.metadata.annotations?.[ANNOTATION_PUPPET_CERTNAME]);
|
||||
|
||||
/** @public */
|
||||
export const Router = () => {
|
||||
const { entity } = useEntity();
|
||||
|
||||
if (!isPuppetDbAvailable(entity)) {
|
||||
return (
|
||||
<MissingAnnotationEmptyState annotation={ANNOTATION_PUPPET_CERTNAME} />
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/" element={<ReportsPage />} />
|
||||
<Route
|
||||
path={`${puppetDbReportRouteRef.path}`}
|
||||
element={<ReportDetailsPage />}
|
||||
/>
|
||||
</Routes>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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 React from 'react';
|
||||
import {
|
||||
StatusPending,
|
||||
StatusRunning,
|
||||
StatusOK,
|
||||
StatusError,
|
||||
} from '@backstage/core-components';
|
||||
|
||||
type StatusCellProps = {
|
||||
status: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Component to display status field for Puppet reports and events.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const StatusField = (props: StatusCellProps) => {
|
||||
const { status } = props;
|
||||
|
||||
const statusUC = status.toLocaleUpperCase('en-US');
|
||||
switch (status) {
|
||||
case 'failed':
|
||||
return (
|
||||
<>
|
||||
<StatusError />
|
||||
{statusUC}
|
||||
</>
|
||||
);
|
||||
case 'changed':
|
||||
return (
|
||||
<>
|
||||
<StatusRunning />
|
||||
{statusUC}
|
||||
</>
|
||||
);
|
||||
case 'unchanged':
|
||||
return (
|
||||
<>
|
||||
<StatusPending />
|
||||
{statusUC}
|
||||
</>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<>
|
||||
<StatusOK />
|
||||
{statusUC}
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
* 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.
|
||||
@@ -13,4 +13,4 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { PuppetDbTab } from './PuppetDbTab';
|
||||
export { StatusField } from './StatusField';
|
||||
@@ -13,4 +13,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { puppetdbPlugin, PuppetDbTab, isPuppetDbAvailable } from './plugin';
|
||||
export {
|
||||
puppetdbPlugin,
|
||||
puppetdbPlugin as plugin,
|
||||
PuppetDbContent,
|
||||
} from './plugin';
|
||||
export {
|
||||
Router,
|
||||
isPuppetDbAvailable,
|
||||
isPuppetDbAvailable as isPluginApplicableToEntity,
|
||||
} from './components/Router';
|
||||
export * from './routes';
|
||||
|
||||
@@ -21,51 +21,35 @@ import {
|
||||
fetchApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
|
||||
import { rootRouteRef } from './routes';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { ANNOTATION_PUPPET_CERTNAME } from './constants';
|
||||
import { puppetDbApiRef, PuppetDbClient } from './api';
|
||||
import { puppetDbRouteRef } from './routes';
|
||||
|
||||
/**
|
||||
* Create the PuppetDB frontend plugin.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
* */
|
||||
export const puppetdbPlugin = createPlugin({
|
||||
id: 'puppetdb',
|
||||
id: 'puppetDb',
|
||||
apis: [
|
||||
createApiFactory({
|
||||
api: puppetDbApiRef,
|
||||
deps: {
|
||||
discoveryApi: discoveryApiRef,
|
||||
fetchApi: fetchApiRef,
|
||||
},
|
||||
deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef },
|
||||
factory: ({ discoveryApi, fetchApi }) =>
|
||||
new PuppetDbClient({
|
||||
discoveryApi,
|
||||
fetchApi,
|
||||
}),
|
||||
new PuppetDbClient({ discoveryApi, fetchApi }),
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks if the entity has a puppet certname annotation.
|
||||
* @public
|
||||
* @param entity - The entity to check for the puppet cername annotation.
|
||||
*/
|
||||
export const isPuppetDbAvailable = (entity: Entity) =>
|
||||
// TODO(tdabasinskas): Remove the `|| true` once testing is done.
|
||||
Boolean(entity.metadata.annotations?.[ANNOTATION_PUPPET_CERTNAME]) || true;
|
||||
|
||||
/**
|
||||
* Creates a routable extension for the PuppetDB plugin tab.
|
||||
* Creates a routable extension for the PuppetDB plugin content.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const PuppetDbTab = puppetdbPlugin.provide(
|
||||
export const PuppetDbContent = puppetdbPlugin.provide(
|
||||
createRoutableExtension({
|
||||
name: 'PuppetdbPage',
|
||||
component: () =>
|
||||
import('./components/PuppetDbTab').then(m => m.PuppetDbTab),
|
||||
mountPoint: rootRouteRef,
|
||||
name: 'PuppetDbContent',
|
||||
component: () => import('./components/Router').then(m => m.Router),
|
||||
mountPoint: puppetDbRouteRef,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -15,12 +15,14 @@
|
||||
*/
|
||||
import { createRouteRef, createSubRouteRef } from '@backstage/core-plugin-api';
|
||||
|
||||
export const rootRouteRef = createRouteRef({
|
||||
/** @public */
|
||||
export const puppetDbRouteRef = createRouteRef({
|
||||
id: 'puppetdb',
|
||||
});
|
||||
|
||||
export const buildRouteRef = createSubRouteRef({
|
||||
/** @public */
|
||||
export const puppetDbReportRouteRef = createSubRouteRef({
|
||||
id: 'puppetdb/report',
|
||||
path: '/:hash',
|
||||
parent: rootRouteRef,
|
||||
parent: puppetDbRouteRef,
|
||||
});
|
||||
|
||||
@@ -7928,12 +7928,14 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@backstage/plugin-puppetdb@workspace:plugins/puppetdb"
|
||||
dependencies:
|
||||
"@backstage/catalog-model": "workspace:^"
|
||||
"@backstage/cli": "workspace:^"
|
||||
"@backstage/core-app-api": "workspace:^"
|
||||
"@backstage/core-components": "workspace:^"
|
||||
"@backstage/core-plugin-api": "workspace:^"
|
||||
"@backstage/dev-utils": "workspace:^"
|
||||
"@backstage/errors": "workspace:^"
|
||||
"@backstage/plugin-catalog-react": "workspace:^"
|
||||
"@backstage/test-utils": "workspace:^"
|
||||
"@backstage/theme": "workspace:^"
|
||||
"@material-ui/core": ^4.12.2
|
||||
|
||||
Reference in New Issue
Block a user