Rename locations -> instances

Signed-off-by: Julio Zynger <julio.zynger@soundcloud.com>
This commit is contained in:
Julio Zynger
2022-03-01 10:28:53 +01:00
committed by Fredrik Adelöw
parent f6e22fb230
commit 171be275ae
8 changed files with 54 additions and 51 deletions
+12 -11
View File
@@ -15,24 +15,24 @@
*/
import { Config } from '@backstage/config';
import { AggregatedError, NotFoundInLocation } from '../types';
import { AggregatedError, NotFoundInInstance } from '../types';
import fetch from 'node-fetch';
export type Options = {
config: Config;
};
type PeriskopLocation = {
type PeriskopInstance = {
name: string;
host: string;
};
export class PeriskopApi {
private readonly locations: PeriskopLocation[];
private readonly instances: PeriskopInstance[];
constructor(options: Options) {
this.locations = options.config
.getConfigArray('periskop.locations')
this.instances = options.config
.getConfigArray('periskop.instances')
.flatMap(locConf => {
const name = locConf.getString('name');
const host = locConf.getString('host');
@@ -40,18 +40,19 @@ export class PeriskopApi {
});
}
private getApiUrl(locationName: string): string | undefined {
return this.locations.find(loc => loc.name === locationName)?.host;
private getApiUrl(instanceName: string): string | undefined {
return this.instances.find(instance => instance.name === instanceName)
?.host;
}
async getErrors(
locationName: string,
instanceName: string,
serviceName: string,
): Promise<AggregatedError[] | NotFoundInLocation> {
const apiUrl = this.getApiUrl(locationName);
): Promise<AggregatedError[] | NotFoundInInstance> {
const apiUrl = this.getApiUrl(instanceName);
if (!apiUrl) {
throw new Error(
`failed to fetch data, no periskop location with name ${locationName}`,
`failed to fetch data, no periskop instance with name ${instanceName}`,
);
}
const response = await fetch(`${apiUrl}/services/${serviceName}/errors/`);
@@ -29,7 +29,7 @@ describe('createRouter', () => {
logger: getVoidLogger(),
config: new ConfigReader({
periskop: {
locations: [
instances: [
{
name: 'db',
host: 'http://periskop-db',
+1 -1
View File
@@ -43,6 +43,6 @@ export interface RequestHeaders {
[k: string]: string;
}
export interface NotFoundInLocation {
export interface NotFoundInInstance {
body: string;
}
+6 -5
View File
@@ -20,15 +20,16 @@ annotations:
periskop.io/name: '<THE NAME OF THE PERISKOP APP>'
```
### Locations
### Instances
The periskop plugin can be configured to fetch aggregated errors from multiple deployment locations. This is especially useful if you have a multi-zone deployment, or a federated setup and would like to drill deeper into a single instance of the federation. Each of the configured locations will be included in the plugin's UI via a dropdown on the errors table.
The periskop plugin can be configured to fetch aggregated errors from multiple deployment instances.
This is especially useful if you have a multi-zone deployment, or a federated setup and would like to drill deeper into a single instance of the federation. Each of the configured instances will be included in the plugin's UI via a dropdown on the errors table.
The plugin requires to configure _at least one_ Periskop API location in the [app-config.yaml](https://github.com/backstage/backstage/blob/master/app-config.yaml):
```yaml
periskop:
locations:
- name: <name of the location>
host: <HTTP/S host for the Periskop API location>
instances:
- name: <name of the instance>
host: <HTTP/S host for the Periskop API instance>
```
+1 -1
View File
@@ -23,7 +23,7 @@ export interface Config {
* Integration configuration for the periskop servers
* @visibility frontend
*/
locations: Array<{
instances: Array<{
/**
* The name of the given Periskop instance
* @visibility frontend
+15 -14
View File
@@ -15,14 +15,14 @@
*/
import { ConfigApi, DiscoveryApi } from '@backstage/core-plugin-api';
import { AggregatedError, NotFoundInLocation } from '../types';
import { AggregatedError, NotFoundInInstance } from '../types';
type Options = {
discoveryApi: DiscoveryApi;
configApi: ConfigApi;
};
type PeriskopLocation = {
type PeriskopInstance = {
name: string;
host: string;
};
@@ -34,12 +34,12 @@ type PeriskopLocation = {
*/
export class PeriskopApi {
private readonly discoveryApi: DiscoveryApi;
private readonly locations: PeriskopLocation[];
private readonly instances: PeriskopInstance[];
constructor(options: Options) {
this.discoveryApi = options.discoveryApi;
this.locations = options.configApi
.getConfigArray('periskop.locations')
this.instances = options.configApi
.getConfigArray('periskop.instances')
.flatMap(locConf => {
const name = locConf.getString('name');
const host = locConf.getString('host');
@@ -47,31 +47,32 @@ export class PeriskopApi {
});
}
private getApiUrl(locationName: string): string | undefined {
return this.locations.find(loc => loc.name === locationName)?.host;
private getApiUrl(instanceName: string): string | undefined {
return this.instances.find(instance => instance.name === instanceName)
?.host;
}
getLocationNames(): string[] {
return this.locations.map(e => e.name);
getInstanceNames(): string[] {
return this.instances.map(e => e.name);
}
getErrorInstanceUrl(
locationName: string,
instanceName: string,
serviceName: string,
error: AggregatedError,
): string {
return `${this.getApiUrl(
locationName,
instanceName,
)}/#/${serviceName}/errors/${encodeURIComponent(error.aggregation_key)}`;
}
async getErrors(
locationName: string,
instanceName: string,
serviceName: string,
): Promise<AggregatedError[] | NotFoundInLocation> {
): Promise<AggregatedError[] | NotFoundInInstance> {
const apiUrl = `${await this.discoveryApi.getBaseUrl(
'periskop',
)}/${locationName}/${serviceName}`;
)}/${instanceName}/${serviceName}`;
const response = await fetch(apiUrl);
if (!response.ok) {
@@ -35,7 +35,7 @@ import {
import Alert from '@material-ui/lab/Alert';
import useAsync from 'react-use/lib/useAsync';
import { periskopApiRef } from '../..';
import { AggregatedError, NotFoundInLocation } from '../../types';
import { AggregatedError, NotFoundInInstance } from '../../types';
/**
* Constant storing Periskop project name.
@@ -72,10 +72,10 @@ const renderLastOccurrence = (error: AggregatedError): React.ReactNode => {
return moment(new Date(error.latest_errors[0].timestamp * 1000)).fromNow();
};
function isNotFoundInLocation(
apiResult: AggregatedError[] | NotFoundInLocation | undefined,
): apiResult is NotFoundInLocation {
return (apiResult as NotFoundInLocation)?.body !== undefined;
function isNotFoundInInstance(
apiResult: AggregatedError[] | NotFoundInInstance | undefined,
): apiResult is NotFoundInInstance {
return (apiResult as NotFoundInInstance)?.body !== undefined;
}
export const PeriskopErrorsTable = () => {
@@ -86,17 +86,17 @@ export const PeriskopErrorsTable = () => {
| undefined) ?? entity.metadata.name;
const periskopApi = useApi(periskopApiRef);
const locations = periskopApi.getLocationNames();
const [locationOption, setLocationOption] = React.useState<string>(
locations[0],
const instanceNames = periskopApi.getInstanceNames();
const [instanceOption, setInstanceOption] = React.useState<string>(
instanceNames[0],
);
const {
value: aggregatedErrors,
loading,
error,
} = useAsync(async (): Promise<AggregatedError[] | NotFoundInLocation> => {
return periskopApi.getErrors(locationOption, entityPeriskopName);
}, [locationOption]);
} = useAsync(async (): Promise<AggregatedError[] | NotFoundInInstance> => {
return periskopApi.getErrors(instanceOption, entityPeriskopName);
}, [instanceOption]);
if (loading) {
return <Progress />;
@@ -112,7 +112,7 @@ export const PeriskopErrorsTable = () => {
sorting: false,
render: aggregatedError => {
const errorUrl = periskopApi.getErrorInstanceUrl(
locationOption,
instanceOption,
entityPeriskopName,
aggregatedError,
);
@@ -138,13 +138,13 @@ export const PeriskopErrorsTable = () => {
const sortingSelect = (
<Select
selected={locationOption}
label="Location"
items={locations.map(e => ({
selected={instanceOption}
label="Instance"
items={instanceNames.map(e => ({
label: e,
value: e,
}))}
onChange={el => setLocationOption(el.toString())}
onChange={el => setInstanceOption(el.toString())}
/>
);
@@ -154,7 +154,7 @@ export const PeriskopErrorsTable = () => {
</ContentHeader>
);
if (isNotFoundInLocation(aggregatedErrors)) {
if (isNotFoundInInstance(aggregatedErrors)) {
return (
<Content noPadding>
{contentHeader}
+1 -1
View File
@@ -43,6 +43,6 @@ export interface RequestHeaders {
[k: string]: string;
}
export interface NotFoundInLocation {
export interface NotFoundInInstance {
body: string;
}