feat: Add temporary argo scaffolder plugin that creates an argo application

This commit is contained in:
jeangab
2024-04-30 21:11:15 -04:00
parent 58f3fa8625
commit b76fbfc34a
5 changed files with 151 additions and 10 deletions

View File

@@ -49,4 +49,30 @@ backend.add(import('@backstage/plugin-search-backend/alpha'));
backend.add(import('@backstage/plugin-devtools-backend'));
import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha';
import { createBackendModule } from '@backstage/backend-plugin-api';
import { createNewFileAction } from './plugins/scaffolder/actions/custom';
import { createArgoProjectAction } from './plugins/scaffolder/actions/argo';
const scaffolderModuleCustomExtensions = createBackendModule({
pluginId: 'scaffolder', // name of the plugin that the module is targeting
moduleId: 'custom-extensions',
register(env) {
env.registerInit({
deps: {
scaffolder: scaffolderActionsExtensionPoint,
// ... and other dependencies as needed
},
async init({ scaffolder /* ..., other dependencies */ }) {
// Here you have the opportunity to interact with the extension
// point before the plugin itself gets instantiated
scaffolder.addActions(createNewFileAction()); // just an example
scaffolder.addActions(createArgoProjectAction()); // just an example
},
});
},
});
backend.add(scaffolderModuleCustomExtensions());
backend.start();

View File

@@ -0,0 +1,69 @@
import { exec } from 'child_process';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import { z } from 'zod';
export const createArgoProjectAction = () => {
return createTemplateAction({
id: 'argocd:app:create',
schema: {
input: z.object({
appName: z.string().describe('The name of the application'),
argoInstance: z.string().describe('The ARGO instance URL'),
namespace: z.string().describe('The Kubernetes namespace'),
repoUrl: z.string().describe('The repository URL to publish the artifacts'),
repoPath: z.string().describe('The path in the repository that argo must watch'),
labelValue: z.string().describe('The value for the label based on the app name'),
valuesFiles: z.array(z.string()).describe('List of value files'),
}),
},
async handler(ctx) {
createArgoProject(ctx.input)
// throw new Error(`Yay we are in handler with ctx ${ctx}`)
},
});
};
type ArgoProjectParams = {
appName: string;
argoInstance: string;
namespace: string;
repoUrl: string;
repoPath: string;
labelValue: string;
valuesFiles: string[];
}
function createArgoProject(params: ArgoProjectParams): void {
const command = `argocd app create ${params.appName} --project default --repo ${params.repoUrl} --path ${params.repoPath} --dest-server https://kubernetes.default.svc --dest-namespace ${params.namespace} --sync-policy auto`;
exec(command, (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
throw new Error(`createArgoProject failed due to ${error}`);
}
console.log(`stdout: ${stdout}`);
console.error(`stderr: ${stderr}`);
});
executeWithRetry(command, 1, 5); // Start the retry mechanism with the first attempt
}
function executeWithRetry(command: string, attempt: number, maxAttemps: number = 5): void {
exec(command, (error, stdout, stderr) => {
if (error) {
console.error(`exec error on attempt ${attempt}: ${error}`);
// If it's not the last retry, wait for 2 seconds and try again
if (attempt < maxAttemps) {
setTimeout(() => executeWithRetry(command, attempt + 1, maxAttemps), 2000);
} else {
console.error(`Failed after ${attempt} attempts: ${stderr}`);
}
} else {
console.log(`stdout: ${stdout}`);
}
});
}

View File

@@ -0,0 +1,21 @@
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import { z } from 'zod';
export const createNewFileAction = () => {
return createTemplateAction({
id: 'acme:file:create',
schema: {
input: z.object({
contents: z.string().describe('The contents of the file'),
filename: z
.string()
.describe('The filename of the file that will be created'),
}),
},
async handler(ctx) {
throw new Error(`Yay we are in handler with ctx ${ctx}`)
},
});
};