From d001ee0c17714d217d1a56ac52727fa650fa87dc Mon Sep 17 00:00:00 2001 From: Manabu Mccloskey Date: Fri, 16 Jun 2023 15:49:51 -0700 Subject: [PATCH] add cluster picker and credential retriever --- backstage.json | 2 +- package.json | 2 +- packages/app/package.json | 56 +- packages/app/src/App.tsx | 8 +- .../src/scaffolder/credentials/extensions.ts | 14 + .../scaffolder/credentials/getOIDCToken.tsx | 63 + .../app/src/scaffolder/credentials/index.ts | 1 + .../app/src/scaffolder/credentials/schema.ts | 20 + packages/backend/package.json | 42 +- packages/backend/src/plugins/workflow-argo.ts | 103 +- plugins/workflows/package.json | 16 +- yarn.lock | 3332 +++++++++-------- 12 files changed, 1962 insertions(+), 1697 deletions(-) create mode 100644 packages/app/src/scaffolder/credentials/extensions.ts create mode 100644 packages/app/src/scaffolder/credentials/getOIDCToken.tsx create mode 100644 packages/app/src/scaffolder/credentials/index.ts create mode 100644 packages/app/src/scaffolder/credentials/schema.ts diff --git a/backstage.json b/backstage.json index bd61f69..8c10389 100644 --- a/backstage.json +++ b/backstage.json @@ -1,3 +1,3 @@ { - "version": "1.12.1" + "version": "1.14.2" } diff --git a/package.json b/package.json index 06ddb90..29d1922 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ ] }, "devDependencies": { - "@backstage/cli": "^0.22.5", + "@backstage/cli": "^0.22.7", "@spotify/prettier-config": "^12.0.0", "concurrently": "^6.0.0", "lerna": "^4.0.0", diff --git a/packages/app/package.json b/packages/app/package.json index b6b7764..94f67d7 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -18,35 +18,37 @@ "cy:run": "cypress run --browser chrome" }, "dependencies": { - "@backstage/app-defaults": "^1.2.1", - "@backstage/catalog-model": "^1.2.1", - "@backstage/cli": "^0.22.5", - "@backstage/core-app-api": "^1.6.0", - "@backstage/core-components": "^0.12.5", - "@backstage/core-plugin-api": "^1.5.0", - "@backstage/integration-react": "^1.1.11", - "@backstage/plugin-api-docs": "^0.9.1", - "@backstage/plugin-catalog": "^1.9.0", - "@backstage/plugin-catalog-common": "^1.0.12", - "@backstage/plugin-catalog-graph": "^0.2.28", - "@backstage/plugin-catalog-import": "^0.9.6", - "@backstage/plugin-catalog-react": "^1.4.0", - "@backstage/plugin-github-actions": "^0.5.16", - "@backstage/plugin-kubernetes": "^0.7.9", - "@backstage/plugin-org": "^0.6.6", - "@backstage/plugin-permission-react": "^0.4.11", - "@backstage/plugin-scaffolder": "^1.12.0", - "@backstage/plugin-search": "^1.1.1", - "@backstage/plugin-search-react": "^1.5.1", - "@backstage/plugin-tech-radar": "^0.6.2", - "@backstage/plugin-techdocs": "^1.6.0", - "@backstage/plugin-techdocs-module-addons-contrib": "^1.0.11", - "@backstage/plugin-techdocs-react": "^1.1.4", - "@backstage/plugin-user-settings": "^0.7.1", - "@backstage/theme": "^0.2.18", + "@backstage/app-defaults": "^1.3.1", + "@backstage/catalog-model": "^1.3.0", + "@backstage/cli": "^0.22.7", + "@backstage/core-app-api": "^1.8.0", + "@backstage/core-components": "^0.13.1", + "@backstage/core-plugin-api": "^1.5.1", + "@backstage/integration-react": "^1.1.13", + "@backstage/plugin-api-docs": "^0.9.4", + "@backstage/plugin-catalog": "^1.11.1", + "@backstage/plugin-catalog-common": "^1.0.13", + "@backstage/plugin-catalog-graph": "^0.2.30", + "@backstage/plugin-catalog-import": "^0.9.8", + "@backstage/plugin-catalog-react": "^1.6.0", + "@backstage/plugin-github-actions": "^0.5.18", + "@backstage/plugin-kubernetes": "^0.9.1", + "@backstage/plugin-org": "^0.6.8", + "@backstage/plugin-permission-react": "^0.4.12", + "@backstage/plugin-scaffolder": "^1.13.1", + "@backstage/plugin-scaffolder-react": "^1.4.0", + "@backstage/plugin-search": "^1.3.1", + "@backstage/plugin-search-react": "^1.6.1", + "@backstage/plugin-tech-radar": "^0.6.4", + "@backstage/plugin-techdocs": "^1.6.3", + "@backstage/plugin-techdocs-module-addons-contrib": "^1.0.13", + "@backstage/plugin-techdocs-react": "^1.1.6", + "@backstage/plugin-user-settings": "^0.7.3", + "@backstage/theme": "^0.3.0", "@internal/plugin-workflows": "^0.1.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", + "@rjsf/core": "^5.8.1", "history": "^5.0.0", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -54,7 +56,7 @@ "react-use": "^17.2.4" }, "devDependencies": { - "@backstage/test-utils": "^1.2.6", + "@backstage/test-utils": "^1.3.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 309df30..cb9d603 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -11,6 +11,7 @@ import { catalogImportPlugin, } from '@backstage/plugin-catalog-import'; import { ScaffolderPage, scaffolderPlugin } from '@backstage/plugin-scaffolder'; +import {ScaffolderFieldExtensions} from '@backstage/plugin-scaffolder-react' import { orgPlugin } from '@backstage/plugin-org'; import { SearchPage } from '@backstage/plugin-search'; import { TechRadarPage } from '@backstage/plugin-tech-radar'; @@ -34,6 +35,7 @@ import { AppRouter, FlatRoutes } from '@backstage/core-app-api'; import { CatalogGraphPage } from '@backstage/plugin-catalog-graph'; import { RequirePermission } from '@backstage/plugin-permission-react'; import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha'; +import {GetK8sOIDCTokenExtension} from "./scaffolder/credentials"; const app = createApp({ apis, @@ -88,7 +90,11 @@ const routes = ( - } /> + }> + + + + } /> { + + const k8sApi = useApi(kubernetesApiRef) + const k8sAuthProviderApi = useApi(kubernetesAuthProvidersApiRef) + const { setSecrets } = useTemplateSecrets(); + + const {uiSchema, onChange, rawErrors, formData, required} = props + const getToken = async () => { + const {requestUserCredentials} = uiSchema?.['ui:options'] ?? {} + if (!requestUserCredentials) { + return; + } + + const clusters = await k8sApi.getClusters() + const cluster = clusters.find(c => { + return c.name === formData + }) + const creds = await k8sAuthProviderApi.getCredentials(cluster!.oidcTokenProvider!) + setSecrets({ [requestUserCredentials.secretKey]: creds.token! }) + } + + const {value: {clusters} = {clusters: []}, loading } = useAsync( + async () => { + const c = await k8sApi.getClusters() + return {clusters: c.map(i => ({ label: i.name, value: i.name}))} + } + ) + + if (loading) { + return ; + } + + return ( + 0 && !formData} + > +