initial implementation

This commit is contained in:
Manabu Mccloskey 2023-06-20 13:20:55 -07:00
parent d001ee0c17
commit f581e1a45d
2 changed files with 62 additions and 23 deletions

View file

@ -8,7 +8,7 @@ export const GetK8sOIDCTokenExtension = scaffolderPlugin.provide(
{
name: 'GetK8sOIDCToken',
component: GetK8sOIDCToken,
schema: ClusterPickerSchema
schema: ClusterPickerSchema,
}
)
)

View file

@ -1,40 +1,78 @@
import React from 'react';
import React, {useCallback, useEffect} from 'react';
import FormControl from '@material-ui/core/FormControl';
import {useApi} from "@backstage/core-plugin-api";
import {kubernetesApiRef, kubernetesAuthProvidersApiRef} from "@backstage/plugin-kubernetes";
import {FormHelperText} from "@material-ui/core";
import {
useApi, configApiRef, discoveryApiRef, oauthRequestApiRef
} from "@backstage/core-plugin-api";
import { kubernetesApiRef } from "@backstage/plugin-kubernetes";
import { FormHelperText } from "@material-ui/core";
import {Progress, Select} from "@backstage/core-components";
import useAsync from "react-use/lib/useAsync";
import {useTemplateSecrets} from "@backstage/plugin-scaffolder-react";
import {ClusterPickerProps} from "./schema";
import {OAuth2} from "@backstage/core-app-api";
export const GetK8sOIDCToken = (props: ClusterPickerProps) => {
const k8sApi = useApi(kubernetesApiRef)
const k8sAuthProviderApi = useApi(kubernetesAuthProvidersApiRef)
const { setSecrets } = useTemplateSecrets();
const { setSecrets, secrets } = 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 discoveryApi = useApi(discoveryApiRef)
const oauthRequestApi = useApi(oauthRequestApiRef)
const configApi = useApi(configApiRef)
const {uiSchema, required} = props
let {rawErrors} = props
const {value: {clusters} = {clusters: []}, loading } = useAsync(
async () => {
const c = await k8sApi.getClusters()
return {clusters: c.map(i => ({ label: i.name, value: i.name}))}
}
)
if (!rawErrors) {
rawErrors = []
}
const getToken = useCallback( async (clusterName: string) => {
const {requestUserCredentials} = uiSchema?.['ui:options'] ?? {}
if (!requestUserCredentials) {
return;
}
const cs = await k8sApi.getClusters()
const cluster = cs.find(c => {
return c.name === clusterName
})
if (cluster?.oidcTokenProvider === undefined) {
throw new Error("no oidc provider defined for this cluster")
}
const oidc = OAuth2.create({
discoveryApi,
oauthRequestApi,
provider: {
id: cluster.oidcTokenProvider,
title: 'OIDC',
icon: () => null,
},
environment: configApi.getOptionalString('auth.environment'),
defaultScopes: ['openid', 'profile', 'email', 'groups'],
})
const token = await oidc.getIdToken()
setSecrets({ [requestUserCredentials.secretKey]: token })
}, [configApi, discoveryApi, k8sApi, oauthRequestApi, setSecrets, uiSchema]
)
useEffect(() => {
const {requestUserCredentials} = uiSchema?.['ui:options'] ?? {}
if (!requestUserCredentials?.secretKey || secrets[requestUserCredentials?.secretKey!]) {
return
}
if (clusters.length) {
getToken(clusters[0].value).catch(console.error)
}
}, [clusters, getToken, secrets, uiSchema])
if (loading) {
return <Progress />;
@ -44,13 +82,14 @@ export const GetK8sOIDCToken = (props: ClusterPickerProps) => {
<FormControl
margin="normal"
required={required}
error={rawErrors?.length > 0 && !formData}
error={rawErrors?.length > 0}
>
<Select
native
label="Cluster"
items={clusters}
onChange={getToken}
onChange={e => getToken(e.toString())}
placeholder="select one"
/>
<FormHelperText id="entityName">
Kubernetes Cluster Name