feat: Add temporary argo scaffolder plugin that creates an argo application
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -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}`)
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user