Skip to content

Commit

Permalink
Merge pull request #67 from SamoKopecky/upgrade-indicator
Browse files Browse the repository at this point in the history
  • Loading branch information
tumido authored Jan 17, 2023
2 parents a67fe25 + ffb7a12 commit 84ac89a
Show file tree
Hide file tree
Showing 8 changed files with 227 additions and 10 deletions.
3 changes: 2 additions & 1 deletion plugins/ocm-backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
"node-fetch": "^3.0.0",
"semver": "^7.3.8",
"winston": "^3.2.1",
"yn": "^5.0.0"
},
"devDependencies": {
"@types/express": "4.17.14",
"@backstage/cli": "0.21.1",
"@types/express": "4.17.14",
"@types/supertest": "2.0.12",
"msw": "0.49.1",
"nock": "13.2.9",
Expand Down
32 changes: 32 additions & 0 deletions plugins/ocm-backend/src/helpers/kubernetes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
hubApiClient,
getManagedCluster,
getManagedClusters,
getManagedClustersInfo,
} from './kubernetes';
import { createLogger } from 'winston';
import transports from 'winston/lib/winston/transports';
Expand Down Expand Up @@ -176,3 +177,34 @@ describe('getManagedCluster', () => {
expect(result.name).toBe('NotFound');
});
});

describe('getManagedClustersInfo', () => {
it('should return some clusters', async () => {
nock(kubeConfig.clusters[0].server)
.get(
'/apis/internal.open-cluster-management.io/v1beta1/managedclusterinfos',
)
.reply(200, {
body: {
items: [
{
kind: 'ManagedClusterInfo',
metadata: {
name: 'cluster1',
},
},
{
kind: 'ManagedClusterInfo',
metadata: {
name: 'cluster2',
},
},
],
},
});

const result: any = await getManagedClustersInfo(getApi());
expect(result.body.items[0].metadata.name).toBe('cluster1');
expect(result.body.items[1].metadata.name).toBe('cluster2');
});
});
10 changes: 10 additions & 0 deletions plugins/ocm-backend/src/helpers/kubernetes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,13 @@ export const getManagedClusters = (api: CustomObjectsApi) => {
),
);
};

export const getManagedClustersInfo = (api: CustomObjectsApi) => {
return kubeApiResponseHandler(
api.listClusterCustomObject(
'internal.open-cluster-management.io',
'v1beta1',
'managedclusterinfos',
),
);
};
120 changes: 119 additions & 1 deletion plugins/ocm-backend/src/helpers/parser.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { ClusterDetails } from '@janus-idp/backstage-plugin-ocm-common';
import { getClaim, parseManagedCluster, parseResources } from './parser';
import {
getClaim,
parseManagedCluster,
parseResources,
parseUpdateInfo,
} from './parser';

describe('getClaim', () => {
it('should extract a cluster claim value from a cluster object', () => {
Expand Down Expand Up @@ -274,3 +279,116 @@ describe('parseManagedCluster', () => {
expect(result).toStrictEqual(expected);
});
});

describe('parseUpdateInfo', () => {
it('should correctly parse update information from ClusterInfo', () => {
const clusterInfo = {
metadata: {},
status: {
distributionInfo: {
ocp: {
availableUpdates: ['1.0.1', '1.0.2', '1.0.3', '1.0.0'],
versionAvailableUpdates: [
{
url: 'http://exampleone.com',
version: '1.0.1',
},
{
url: 'http://exampletwo.com',
version: '1.0.2',
},
{
url: 'http://examplethree.com',
version: '1.0.3',
},
{
url: 'http://examplezero.com',
version: '1.0.0',
},
],
},
},
},
};

const result = parseUpdateInfo(clusterInfo);

expect(result).toEqual({
update: {
available: true,
version: '1.0.3',
url: 'http://examplethree.com',
},
});
});

it('should correctly parse while there are no updates available with no arrays', () => {
const clusterInfo = {
metadata: {},
status: {
distributionInfo: {
ocp: {},
},
},
};

const result = parseUpdateInfo(clusterInfo);

expect(result).toEqual({
update: {
available: false,
},
});
});

it('should correctly parse while there are no updates available with empty arrays', () => {
const clusterInfo = {
metadata: {},
status: {
distributionInfo: {
ocp: {
availableUpdates: [],
versionAvailableUpdates: [],
},
},
},
};

const result = parseUpdateInfo(clusterInfo);

expect(result).toEqual({
update: {
available: false,
},
});
});

it('should correctly parse while there is only one update available', () => {
const clusterInfo = {
metadata: {},
status: {
distributionInfo: {
ocp: {
availableUpdates: ['1.0.1'],
versionAvailableUpdates: [
{
url: 'http://exampleone.com',
version: '1.0.1',
},
],
},
},
},
};

const result = parseUpdateInfo(clusterInfo);

expect(result).toEqual({
update: {
available: true,
version: '1.0.1',
url: 'http://exampleone.com',
},
});
});
});
27 changes: 27 additions & 0 deletions plugins/ocm-backend/src/helpers/parser.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CONSOLE_CLAIM } from '../constants';
import { ClusterDetails } from '@janus-idp/backstage-plugin-ocm-common';
import { maxSatisfying } from 'semver';

const convertCpus = (cpus: string | undefined): number | undefined => {
if (!cpus) {
Expand Down Expand Up @@ -58,3 +59,29 @@ export const parseManagedCluster = (cluster: any): ClusterDetails => {
...parsedClusterInfo,
};
};

export const parseUpdateInfo = (clusterInfo: any) => {
const { availableUpdates, versionAvailableUpdates } =
clusterInfo.status.distributionInfo.ocp;
/*
* We assume here that if availableUpdates is empty
* versionAvailableUpdates also has to be empty
*/
if (!availableUpdates || availableUpdates.length === 0) {
return {
update: {
available: false,
},
};
}

const version = maxSatisfying(availableUpdates, '*');

return {
update: {
available: true,
version,
url: versionAvailableUpdates[availableUpdates.indexOf(version)].url,
},
};
};
32 changes: 24 additions & 8 deletions plugins/ocm-backend/src/service/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ import { Config } from '@backstage/config';
import express from 'express';
import Router from 'express-promise-router';
import { Logger } from 'winston';
import { ClusterDetails } from '@janus-idp/backstage-plugin-ocm-common';
import { HUB_CLUSTER_NAME_IN_OCM } from '../constants';
import {
getManagedCluster,
getManagedClusters,
getManagedClustersInfo,
hubApiClient,
} from '../helpers/kubernetes';
import { parseManagedCluster } from '../helpers/parser';
import { parseManagedCluster, parseUpdateInfo } from '../helpers/parser';
import { getHubClusterName } from '../helpers/config';

export interface RouterOptions {
Expand Down Expand Up @@ -56,19 +56,35 @@ export async function createRouter(

return (
getManagedCluster(api, normalizedClusterName) as Promise<any>
).then(resp => {
response.send(parseManagedCluster(resp));
).then(async resp => {
response.send({
...parseManagedCluster(resp),
...parseUpdateInfo(
(await (getManagedClustersInfo(api) as Promise<any>)).items.find(
(clusterInfo: any) =>
clusterInfo.metadata.name === normalizedClusterName,
),
),
});
});
},
);

router.get('/status', (_, response) => {
logger.info(`Incoming status request for all clusters`);

return (getManagedClusters(api) as Promise<any>).then(resp => {
const parsedClusters: Array<ClusterDetails> =
resp.items.map(parseManagedCluster);
response.send(parsedClusters);
return (getManagedClusters(api) as Promise<any>).then(async resp => {
const clusterInfo = (await (getManagedClustersInfo(api) as Promise<any>))
.items;

response.send(
resp.items.map((clusterStatus: any, index: number) => {
return {
...parseManagedCluster(clusterStatus),
...parseUpdateInfo(clusterInfo[index]),
};
}),
);
});
});

Expand Down
5 changes: 5 additions & 0 deletions plugins/ocm-common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ export type ClusterDetails = {
memorySize?: string;
numberOfPods?: number;
};
update?: {
available?: boolean;
version?: string;
url?: string;
};
status: {
available: boolean;
reason: string;
Expand Down
8 changes: 8 additions & 0 deletions plugins/ocm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ This plugin integrates your Backstage instance with Open Cluster Management's Mu
- get
- watch
- list
- apiGroups:
- internal.open-cluster-management.io
resources:
- managedclusterinfos
verbs:
- get
- watch
- list
```
## Capabilities
Expand Down

0 comments on commit 84ac89a

Please sign in to comment.