This commit is contained in:
Manabu Mccloskey 2023-06-20 15:04:32 -07:00
parent f581e1a45d
commit 4e04538e18
2 changed files with 73 additions and 66 deletions

View file

@ -1,4 +1,4 @@
import { KubernetesBuilder } from '@backstage/plugin-kubernetes-backend';
import {KubernetesBuilder, OidcKubernetesAuthTranslator} from '@backstage/plugin-kubernetes-backend';
import { Router } from 'express';
import { PluginEnvironment } from '../types';
import { CatalogClient } from '@backstage/catalog-client';
@ -11,6 +11,9 @@ export default async function createPlugin(
logger: env.logger,
config: env.config,
catalogApi,
permissions: env.permissions
}).build();
new OidcKubernetesAuthTranslator()
return router;
}

View file

@ -3,12 +3,11 @@ import { Config } from '@backstage/config';
import * as k8s from '@kubernetes/client-node';
import {Logger} from "winston";
import {HttpError} from "@kubernetes/client-node";
import {useApi} from "@backstage/core-plugin-api";
import {OidcKubernetesAuthTranslator} from "@backstage/plugin-kubernetes-backend";
type argoInput = {
namespace: string
clusterName: string
userOIDCToken: string
templateName: string
parameters: parameter[]
wait?: boolean
@ -100,9 +99,14 @@ export function createInvokeArgoAction(config: Config, logger: Logger) {
description: 'Name of Cluster',
type: 'string',
},
userOIDCToken: {
title: 'User\'s OIDC token',
description: "If specified, it will use the provided token to communicate with the Kubernetes cluster",
type: 'string'
},
templateName: {
title: 'Template name',
description: 'Argo Workflows template name',
description: 'Argo Workflows template name to run',
type: 'string',
},
parameters: {
@ -123,7 +127,7 @@ export function createInvokeArgoAction(config: Config, logger: Logger) {
},
wait: {
title: 'Wait for completion',
description: 'specify weather to wait for completion of this workflow',
description: 'specify weather to wait for completion of this workflow.',
type: 'boolean',
}
},
@ -145,78 +149,78 @@ export function createInvokeArgoAction(config: Config, logger: Logger) {
async handler(ctx: ActionContext<argoInput>) {
logger.debug(`Invoked with ${JSON.stringify(ctx.input)})`)
logger.info(JSON.stringify(ctx.secrets))
// const targetCluster = getClusterConfig(ctx.input.clusterName, config)
// const kc = new k8s.KubeConfig()
// kc.addCluster({
// name: ctx.input.clusterName,
// caData: targetCluster.getString("caData"),
// server: targetCluster.getString("url"),
// skipTLSVerify: targetCluster.getBoolean("skipTLSVerify"),
// })
// kc.addUser({
// name: "admin",
// token: targetCluster.getString("serviceAccountToken")
// })
// kc.addContext({
// cluster: ctx.input.clusterName,
// user: "admin",
// name: ctx.input.clusterName
// })
// kc.setCurrentContext(ctx.input.clusterName)
//
// const client = kc.makeApiClient(k8s.CustomObjectsApi)
// const wf = new Workflow(ctx.input.templateName, ctx.input.namespace, ctx.input.parameters)
// // const body = generateBody(ctx.input.templateName, ctx.input.namespace)
// try {
// const resp = await client.createNamespacedCustomObject(
// argoWorkflowsGroup, argoWorkflowsVersion, ctx.input.namespace,
// argoWorkFlowPlural, wf
// )
// const respBody = resp.body as Workflow
// logger.debug(`Workflow ID: ${respBody.metadata.name}, namespace ${respBody.metadata.namespace}`)
// ctx.output('workflowName', respBody.metadata.name!)
// ctx.output('workflowNamespace', respBody.metadata.namespace!)
// if (ctx.input.wait) {
// await wait(kc, respBody.metadata.namespace!, respBody.metadata.name!)
// }
// } catch (err) {
// if (err instanceof HttpError) {
// let msg = `${err.response.statusMessage}: `
// if ("kind" in err.body && err.body.kind === "Status" && "message" in err.body) {
// msg += err.body.message
// }
// logger.info(`error : ${err.response.statusCode} ${msg}`)
// throw new Error(`Failed to talk to the cluster: ${err.response.statusCode} ${err.response.statusMessage} \n ${msg}`)
// }
// if (err instanceof Error) {
// logger.error(`error while talking to cluster: ${err.name} ${err.message}`)
// }
// throw new Error("Unknown exception was encountered.")
// }
const targetCluster = getClusterConfig(ctx.input.clusterName, config)
const kc = new k8s.KubeConfig()
kc.addCluster({
name: targetCluster.getString("name"),
caData: targetCluster.getString("caData"),
server: targetCluster.getString("url"),
skipTLSVerify: targetCluster.getBoolean("skipTLSVerify"),
})
kc.addUser({
name: "scaffolder-user",
token: ctx.input.userOIDCToken? ctx.input.userOIDCToken : targetCluster.getString("serviceAccountToken")
})
kc.addContext({
cluster: ctx.input.clusterName,
user: "scaffolder-user",
name: ctx.input.clusterName
})
kc.setCurrentContext(ctx.input.clusterName)
const client = kc.makeApiClient(k8s.CustomObjectsApi)
const wf = new Workflow(ctx.input.templateName, ctx.input.namespace, ctx.input.parameters)
// const body = generateBody(ctx.input.templateName, ctx.input.namespace)
try {
const resp = await client.createNamespacedCustomObject(
argoWorkflowsGroup, argoWorkflowsVersion, ctx.input.namespace,
argoWorkFlowPlural, wf
)
const respBody = resp.body as Workflow
logger.debug(`Workflow ID: ${respBody.metadata.name}, namespace ${respBody.metadata.namespace}`)
ctx.output('workflowName', respBody.metadata.name!)
ctx.output('workflowNamespace', respBody.metadata.namespace!)
if (ctx.input.wait) {
await wait(kc, respBody.metadata.namespace!, respBody.metadata.name!)
}
} catch (err) {
if (err instanceof HttpError) {
let msg = `${err.response.statusMessage}: `
if ("kind" in err.body && err.body.kind === "Status" && "message" in err.body) {
msg += err.body.message
}
logger.info(`error : ${err.response.statusCode} ${msg}`)
throw new Error(`Failed to talk to the cluster: ${err.response.statusCode} ${err.response.statusMessage} \n ${msg}`)
}
if (err instanceof Error) {
logger.error(`error while talking to cluster: ${err.name} ${err.message}`)
}
throw new Error("Unknown exception was encountered.")
}
}
}
)
}
function getClusterConfig(name: string, config: Config): Config {
const at = new OidcKubernetesAuthTranslator();
const c = config.getConfigArray("kubernetes.clusterLocatorMethods")
const cc = c.filter(function(val) {
return val.getString("type") === "config"
})
const clusterConfigs = config.getConfigArray("kubernetes.clusterLocatorMethods").filter(
(val: Config) => {
return val.getString('type') === 'config'
}
)
const clusters = new Array<Config>();
// this is shit
cc.forEach(function(conf ) {
const cl = conf.getConfigArray("clusters")
cl.forEach(function(val) {
if (val.getString("name") === name) {
clusters.push(val)
}
clusterConfigs.filter( (conf: Config) => {
const cluster = conf.getConfigArray("clusters").find( (val: Config) => {
return val.getString("name") === name
})
if (cluster) {
clusters.push(cluster)
}
})
if (clusters.length === 0 ) {
throw new Error(`Cluster with name ${name} not found`)
}