diff --git a/frontend/packages/app/src/clutch.config.js b/frontend/packages/app/src/clutch.config.js index dabcf10315..2fbb7ad875 100644 --- a/frontend/packages/app/src/clutch.config.js +++ b/frontend/packages/app/src/clutch.config.js @@ -72,6 +72,12 @@ module.exports = { resolverType: "clutch.k8s.v1.Node", }, }, + updateLiveness: { + trending: true, + componentProps: { + resolverType: "clutch.k8s.v1.Deployment", + }, + }, }, "@clutch-sh/project-catalog": { catalog: { diff --git a/frontend/workflows/k8s/src/index.tsx b/frontend/workflows/k8s/src/index.tsx index 3987df0aaf..baf8a95d15 100644 --- a/frontend/workflows/k8s/src/index.tsx +++ b/frontend/workflows/k8s/src/index.tsx @@ -6,6 +6,7 @@ import DeletePod from "./delete-pod"; import KubeDashboard from "./k8s-dashboard"; import ResizeHPA from "./resize-hpa"; import ScaleResources from "./scale-resources"; +import UpdateLiveness from "./update-probe"; interface ResolverConfigProps { resolverType: string; @@ -66,6 +67,13 @@ const register = (): WorkflowConfiguration => { component: CordonNode, requiredConfigProps: ["resolverType"], }, + updateLiveness: { + path: "probe/update", + displayName: "Update Probes", + description: "Update Probes on deployments", + component: UpdateLiveness, + requiredConfigProps: ["resolverType"], + }, }, }; }; diff --git a/frontend/workflows/k8s/src/update-probe.tsx b/frontend/workflows/k8s/src/update-probe.tsx new file mode 100644 index 0000000000..47708abc20 --- /dev/null +++ b/frontend/workflows/k8s/src/update-probe.tsx @@ -0,0 +1,335 @@ +import React from "react"; +import type { clutch as IClutch } from "@clutch-sh/api"; +import { + Button, + ButtonGroup, + client, + Confirmation, + MetadataTable, + Resolver, + Select, + useWizardContext, +} from "@clutch-sh/core"; +import { useDataLayout } from "@clutch-sh/data-layout"; +import type { WizardChild } from "@clutch-sh/wizard"; +import { Wizard, WizardStep } from "@clutch-sh/wizard"; +import { string } from "yup"; + +import type { ConfirmChild, ResolverChild, WorkflowProps } from "."; + +// Examples of valid Seconds: 0.1, 100s +const SECONDS_REGEX = /^([-+]?[0-9]*[sS]*)$/; + +const DeploymentIdentifier: React.FC = ({ resolverType }) => { + const { onSubmit } = useWizardContext(); + const deploymentData = useDataLayout("deploymentData"); + const inputData = useDataLayout("inputData"); + + const onResolve = ({ results, input }) => { + deploymentData.assign(results[0]); + inputData.assign(input); + onSubmit(); + }; + + return ; +}; + +function findContainer(args: { + deploymentSpec: IClutch.k8s.v1.Deployment.IDeploymentSpec; + containerName: string; +}): IClutch.k8s.v1.Deployment.DeploymentSpec.PodTemplateSpec.PodSpec.IContainer { + return args.deploymentSpec.template.spec.containers.find( + container => container.name === args.containerName + ); +} + +const DeploymentDetails: React.FC = () => { + const { onSubmit, onBack } = useWizardContext(); + const deploymentData = useDataLayout("deploymentData"); + const deployment = deploymentData.displayValue() as IClutch.k8s.v1.Deployment; + const update = (key: string, value: boolean) => { + deploymentData.updateData(key, value); + }; + + const currentDeploymentData = useDataLayout("currentDeploymentData"); + + const { containers } = deployment.deploymentSpec.template.spec; + + const [containerName, setContainerName] = React.useState( + containers && containers.length > 0 ? containers[0].name : "" + ); + const [probeType, setProbeType] = React.useState("livenessProbe"); + + const [containerIndex, setContainerIndex] = React.useState(0); + + React.useEffect(() => { + // save the original values of deployment spec + if (deployment) { + currentDeploymentData.assign(deployment); + } + }, []); + + const currentDeployment = findContainer({ + deploymentSpec: deployment.deploymentSpec, + containerName, + }); + + const listedProbes = []; + + if (Object.keys(currentDeployment.livenessProbe).length !== 0) listedProbes.push("livenessProbe"); + if (Object.keys(currentDeployment.readinessProbe).length !== 0) + listedProbes.push("readinessProbe"); + + const containerBase = `deploymentSpec.template.spec.containers[${containerIndex}]`; + + return ( + + Deployment Details + { + setContainerName(value); + setContainerIndex(containers.findIndex(container => container.name === value)); + deploymentData.updateData("containerName", value); + }} + options={containers.map(container => ({ label: container.name }))} + /> + ), + }, + { + name: "Probe Type", + value: ( +