Skip to content

Commit

Permalink
Merge pull request #1069 from AmericanAirlines/getAllArgoApps
Browse files Browse the repository at this point in the history
get all argo apps and check if app exists with same repo and source path
  • Loading branch information
Xantier authored Aug 8, 2023
2 parents 0716d0b + 2566008 commit 3363a60
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 16 deletions.
5 changes: 5 additions & 0 deletions .changeset/popular-starfishes-laugh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@roadiehq/backstage-plugin-argo-cd-backend': minor
---

Add endpoint that grabs all argo projects and another endpoint that checks if app already exists in a given cluster with the same repo and source
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ export class ArgoService implements ArgoServiceApi {
getArgoAppDataResp = await this.getArgoAppData(
argoInstance.url,
argoInstance.name,
options,
token,
options,
);
} catch (error: any) {
return null;
Expand Down Expand Up @@ -208,15 +208,19 @@ export class ArgoService implements ArgoServiceApi {
async getArgoAppData(
baseUrl: string,
argoInstanceName: string,
options: {
argoToken: string,
options?: {
name?: string;
selector?: string;
},
argoToken: string,
): Promise<any> {
const urlSuffix = options.name
? `/${options.name}`
: `?selector=${options.selector}`;
let urlSuffix = '';
if (options?.name) {
urlSuffix = `/${options.name}`;
}
if (options?.selector) {
urlSuffix = `?selector=${options.selector}`;
}
const requestOptions: RequestInit = {
method: 'GET',
headers: {
Expand All @@ -239,7 +243,7 @@ export class ArgoService implements ArgoServiceApi {
(data.items as any[]).forEach(item => {
item.metadata.instance = { name: argoInstanceName };
});
} else if (data && options.name) {
} else if (data && options?.name) {
data.instance = argoInstanceName;
}
return data;
Expand Down Expand Up @@ -688,8 +692,8 @@ export class ArgoService implements ArgoServiceApi {
const argoApp = await this.getArgoAppData(
matchedArgoInstance.url,
matchedArgoInstance.name,
{ name: argoAppName },
token,
{ name: argoAppName },
);

isAppPendingDelete = 'metadata' in argoApp;
Expand Down Expand Up @@ -813,8 +817,8 @@ export class ArgoService implements ArgoServiceApi {
const appData = await this.getArgoAppData(
instanceConfig.url,
instanceConfig.name,
{ name: appName },
argoToken,
{ name: appName },
);
if (!appData.spec?.source?.repoURL) {
this.logger.error(`No repo URL found for argo app ${projectName}`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,55 @@ describe('ArgoCD service', () => {
).rejects.toThrow();
});

it('should get all argo app data if no option is provided', async () => {
fetchMock.mockResponseOnce(
JSON.stringify({
items: [
{
metadata: {
name: 'testAppName',
namespace: 'testNamespace',
},
},
{
metadata: {
name: 'testAppName2',
namespace: 'testNamespace2',
},
},
],
}),
);
const resp = await argoService.getArgoAppData(
'https://argoInstance1.com',
'argoInstance1',
'testToken',
);

expect(resp).toStrictEqual({
items: [
{
metadata: {
name: 'testAppName',
namespace: 'testNamespace',
instance: {
name: 'argoInstance1',
},
},
},
{
metadata: {
name: 'testAppName2',
namespace: 'testNamespace2',
instance: {
name: 'argoInstance1',
},
},
},
],
});
});

it('should get argo app data', async () => {
fetchMock.mockResponseOnce(
JSON.stringify({
Expand All @@ -131,8 +180,8 @@ describe('ArgoCD service', () => {
const resp = await argoService.getArgoAppData(
'https://argoInstance1.com',
'argoInstance1',
{ name: 'testApp' },
'testToken',
{ name: 'testApp' },
);

expect(resp).toStrictEqual({
Expand All @@ -151,8 +200,8 @@ describe('ArgoCD service', () => {
argoService.getArgoAppData(
'https://argoInstance1.com',
'argoInstance1',
{ name: 'testApp' },
'testToken',
{ name: 'testApp' },
),
).rejects.toThrow();
});
Expand Down Expand Up @@ -245,8 +294,8 @@ describe('ArgoCD service', () => {
const resp = await argoService.getArgoAppData(
'https://argoInstance1.com',
'argoInstance1',
{ selector: 'service=testApp' },
'testToken',
{ selector: 'service=testApp' },
);

expect(resp).toStrictEqual({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ describe('router', () => {
password: 'password',
},
]);

const response = await request(app).post('/createArgo').send({
clusterName: 'argoInstance1',
namespace: 'test-namespace',
Expand All @@ -116,6 +115,64 @@ describe('router', () => {
});
});

it('checks to see if source already exists in argo', async () => {
mockGetArgoInstanceArray.mockReturnValue([
{
name: 'argoInstance1',
url: 'https://argoInstance1.com',
token: 'token',
username: 'username',
password: 'password',
},
{
name: 'argoInstance2',
url: 'https://argoInstance2.com',
token: 'token',
username: 'username',
password: 'password',
},
]);
mockGetArgoToken.mockReturnValue('token');
mockGetArgoAppData.mockReturnValue({
items: [
{
metadata: {
name: 'testAppName',
namespace: 'testNamespace',
},
spec: {
source: {
repoURL: 'test.repo.url',
path: 'source/path',
},
},
},
{
metadata: {
name: 'testAppName2',
namespace: 'testNamespace2',
},
spec: {
source: {
repoURL: 'test.repo.url.two',
path: 'source/path',
},
},
},
],
});

const response = await request(app).get(
'/argoInstance/argoInstance1/repo/testrepo/source/testsource',
);
expect(response.body).toEqual(false);

const response2 = await request(app).get(
'/argoInstance/argoInstance1/repo/test.repo.url/source/source%2Fpath',
);
expect(response2.body).toEqual(true);
});

it('delete sends back status of app and project deletion', async () => {
mockDeleteAppandProject.mockResolvedValue({
argoDeleteAppResp: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,70 @@ export function createRouter({
return token;
}

router.get('/allArgoApps/:argoInstanceName', async (request, response) => {
const argoInstanceName = request.params.argoInstanceName;
const matchedArgoInstance = findArgoInstance(argoInstanceName);
if (matchedArgoInstance === undefined) {
return response.status(500).send({
status: 'failed',
message: 'cannot find an argo instance to match this cluster',
});
}
const token: string = await findMatchedArgoInstanceToken(
matchedArgoInstance,
);
if (!token) {
return response.status(500).send({
status: 'failed',
message: 'could not generate token',
});
}
return response.send(
await argoSvc.getArgoAppData(
matchedArgoInstance.url,
matchedArgoInstance.name,
token,
),
);
});

router.get(
'/argoInstance/:argoInstance/repo/:repo/source/:source',
async (request, response) => {
const argoInstanceName = request.params.argoInstance;
const matchedArgoInstance = findArgoInstance(argoInstanceName);
if (matchedArgoInstance === undefined) {
return response.status(500).send({
status: 'failed',
message: 'cannot find an argo instance to match this cluster',
});
}
const token: string = await findMatchedArgoInstanceToken(
matchedArgoInstance,
);
if (!token) {
return response.status(500).send({
status: 'failed',
message: 'could not generate token',
});
}
const argoData = await argoSvc.getArgoAppData(
matchedArgoInstance.url,
matchedArgoInstance.name,
token,
);
const repoAndSource = argoData.items.map(
(argoApp: any) =>
`${argoApp?.spec?.source?.repoURL}/${argoApp?.spec?.source?.path}`,
);
return response.send(
repoAndSource.includes(
`${request.params.repo}/${decodeURIComponent(request.params.source)}`,
),
);
},
);

router.get('/find/name/:argoAppName', async (request, response) => {
const argoAppName = request.params.argoAppName;
response.send(await argoSvc.findArgoApp({ name: argoAppName }));
Expand Down Expand Up @@ -100,8 +164,8 @@ export function createRouter({
const resp = await argoSvc.getArgoAppData(
matchedArgoInstance.url,
matchedArgoInstance.name,
{ name: argoAppName },
token,
{ name: argoAppName },
);
return response.send(resp);
},
Expand Down Expand Up @@ -131,8 +195,8 @@ export function createRouter({
const resp = await argoSvc.getArgoAppData(
matchedArgoInstance.url,
matchedArgoInstance.name,
{ selector: argoAppSelector },
token,
{ selector: argoAppSelector },
);
return response.send(resp);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,11 @@ export interface ArgoServiceApi {
getArgoAppData: (
baseUrl: string,
argoInstanceName: string,
argoToken: string,
options: {
name: string;
selector: string;
},
argoToken: string,
) => Promise<object>;
createArgoProject: (props: CreateArgoProjectProps) => Promise<object>;
createArgoApplication: (props: CreateArgoApplicationProps) => Promise<object>;
Expand Down

0 comments on commit 3363a60

Please sign in to comment.