Skip to content

Commit

Permalink
feat: enclave builder imagespec support (#2206)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dartoxian committed Feb 23, 2024
1 parent 402dc8e commit f0e316e
Show file tree
Hide file tree
Showing 8 changed files with 286 additions and 30 deletions.
Expand Up @@ -8,9 +8,10 @@ import { KurtosisFormControl } from "../form/KurtosisFormControl";
import { ListArgumentInput } from "../form/ListArgumentInput";
import { StringArgumentInput } from "../form/StringArgumentInput";
import { KurtosisFormInputProps } from "../form/types";
import { ImageConfigInput } from "./input/ImageConfigInput";
import { MentionStringArgumentInput } from "./input/MentionStringArgumentInput";
import { MountArtifactFileInput } from "./input/MountArtifactFileInput";
import { validateDockerLocator, validateDurationString, validateName } from "./input/validators";
import { validateDurationString, validateName } from "./input/validators";
import { KurtosisNode } from "./KurtosisNode";
import { KurtosisFileMount, KurtosisPythonNodeData } from "./types";
import { useVariableContext } from "./VariableContextProvider";
Expand All @@ -30,13 +31,8 @@ export const KurtosisPythonNode = memo(
<KurtosisFormControl<KurtosisPythonNodeData> name={"pythonName"} label={"Python Name"} isRequired>
<StringArgumentInput name={"pythonName"} size={"sm"} isRequired validate={validateName} />
</KurtosisFormControl>
<KurtosisFormControl<KurtosisPythonNodeData> name={"image"} label={"Container Image"}>
<StringArgumentInput
size={"sm"}
name={"image"}
validate={validateDockerLocator}
placeholder={"Default: python:3.11-alpine"}
/>
<KurtosisFormControl<KurtosisPythonNodeData> name={"image.image"} label={"Container Image"}>
<ImageConfigInput />
</KurtosisFormControl>
</Flex>
<Tabs>
Expand Down
Expand Up @@ -9,10 +9,11 @@ import { KurtosisFormControl } from "../form/KurtosisFormControl";
import { ListArgumentInput } from "../form/ListArgumentInput";
import { StringArgumentInput } from "../form/StringArgumentInput";
import { KurtosisFormInputProps } from "../form/types";
import { ImageConfigInput } from "./input/ImageConfigInput";
import { MentionStringArgumentInput } from "./input/MentionStringArgumentInput";
import { MountArtifactFileInput } from "./input/MountArtifactFileInput";
import { PortConfigurationField } from "./input/PortConfigurationInput";
import { validateDockerLocator, validateName } from "./input/validators";
import { validateName } from "./input/validators";
import { KurtosisNode } from "./KurtosisNode";
import { KurtosisFileMount, KurtosisPort, KurtosisServiceNodeData } from "./types";
import { useVariableContext } from "./VariableContextProvider";
Expand All @@ -32,8 +33,8 @@ export const KurtosisServiceNode = memo(
<KurtosisFormControl<KurtosisServiceNodeData> name={"serviceName"} label={"Service Name"} isRequired>
<StringArgumentInput name={"serviceName"} size={"sm"} isRequired validate={validateName} />
</KurtosisFormControl>
<KurtosisFormControl<KurtosisServiceNodeData> name={"image"} label={"Container Image"} isRequired>
<StringArgumentInput size={"sm"} name={"image"} isRequired validate={validateDockerLocator} />
<KurtosisFormControl<KurtosisServiceNodeData> name={"image.image"} label={"Container Image"} isRequired>
<ImageConfigInput />
</KurtosisFormControl>
</Flex>
<Tabs>
Expand Down
Expand Up @@ -8,9 +8,10 @@ import { DictArgumentInput } from "../form/DictArgumentInput";
import { KurtosisFormControl } from "../form/KurtosisFormControl";
import { ListArgumentInput } from "../form/ListArgumentInput";
import { StringArgumentInput } from "../form/StringArgumentInput";
import { ImageConfigInput } from "./input/ImageConfigInput";
import { MentionStringArgumentInput } from "./input/MentionStringArgumentInput";
import { MountArtifactFileInput } from "./input/MountArtifactFileInput";
import { validateDockerLocator, validateDurationString, validateName } from "./input/validators";
import { validateDurationString, validateName } from "./input/validators";
import { KurtosisNode } from "./KurtosisNode";
import { KurtosisFileMount, KurtosisShellNodeData } from "./types";
import { useVariableContext } from "./VariableContextProvider";
Expand All @@ -30,13 +31,8 @@ export const KurtosisShellNode = memo(
<KurtosisFormControl<KurtosisShellNodeData> name={"shellName"} label={"Shell Name"} isRequired>
<StringArgumentInput name={"shellName"} size={"sm"} isRequired validate={validateName} />
</KurtosisFormControl>
<KurtosisFormControl<KurtosisShellNodeData> name={"image"} label={"Container Image"}>
<StringArgumentInput
size={"sm"}
name={"image"}
validate={validateDockerLocator}
placeholder={"Default: badouralix/curl-jq"}
/>
<KurtosisFormControl<KurtosisShellNodeData> name={"image.image"} label={"Container Image"}>
<ImageConfigInput />
</KurtosisFormControl>
</Flex>
<Tabs>
Expand Down
Expand Up @@ -95,7 +95,17 @@ export const Visualiser = forwardRef<VisualiserImperativeAttributes, VisualiserP
updateData(id, {
type: "service",
serviceName: "",
image: "",
image: {
image: "",
type: "image",
buildContextDir: "",
flakeLocationDir: "",
flakeOutput: "",
registry: "",
registryPassword: "",
registryUsername: "",
targetStage: "",
},
ports: [],
env: [],
files: [],
Expand Down Expand Up @@ -133,7 +143,17 @@ export const Visualiser = forwardRef<VisualiserImperativeAttributes, VisualiserP
type: "shell",
shellName: "",
command: "",
image: "",
image: {
image: "",
type: "image",
buildContextDir: "",
flakeLocationDir: "",
flakeOutput: "",
registry: "",
registryPassword: "",
registryUsername: "",
targetStage: "",
},
env: [],
files: [],
store: "",
Expand All @@ -158,7 +178,17 @@ export const Visualiser = forwardRef<VisualiserImperativeAttributes, VisualiserP
pythonName: "",
command: "",
packages: [],
image: "",
image: {
image: "",
type: "image",
buildContextDir: "",
flakeLocationDir: "",
flakeOutput: "",
registry: "",
registryPassword: "",
registryUsername: "",
targetStage: "",
},
args: [],
files: [],
store: "",
Expand Down
@@ -0,0 +1,192 @@
import {
Code,
Flex,
IconButton,
InputGroup,
InputLeftAddon,
InputRightElement,
Popover,
PopoverArrow,
PopoverBody,
PopoverContent,
PopoverHeader,
PopoverTrigger,
Portal,
Tab,
TabList,
TabPanel,
TabPanels,
Tabs,
Text,
} from "@chakra-ui/react";

import { useState } from "react";
import { useFormContext } from "react-hook-form";
import { FiSettings } from "react-icons/fi";
import { KurtosisFormControl } from "../../form/KurtosisFormControl";
import { StringArgumentInput } from "../../form/StringArgumentInput";
import { KurtosisImageConfig, KurtosisImageType } from "../types";
import { validateDockerLocator } from "./validators";

const tabs: { display: string; value: KurtosisImageType }[] = [
{ display: "Image", value: "image" },
{ display: "Dockerfile", value: "dockerfile" },
{ display: "Nix", value: "nix" },
];

export const ImageConfigInput = () => {
const { setValue, watch } = useFormContext<{ image: KurtosisImageConfig }>();
const imageName = watch("image.image");
const imageType = watch("image.type");
const [activeTabIndex, setActiveTabIndex] = useState(tabs.findIndex((v) => v.value === imageType));

const handleTabsChange = (newTabIndex: number) => {
setActiveTabIndex(newTabIndex);
setValue("image.type", tabs[activeTabIndex].value);
};

return (
<InputGroup size={"sm"}>
<InputLeftAddon>{tabs[activeTabIndex].display}</InputLeftAddon>
<StringArgumentInput
name={"image.image"}
validate={validateDockerLocator}
placeholder={"Default: python:3.11-alpine"}
paddingInlineEnd={8}
/>
<InputRightElement>
<Popover placement={"right-end"} isLazy>
<PopoverTrigger>
<IconButton
icon={<FiSettings />}
bg={"gray.850"}
aria-label={"Image Configuration"}
variant={"ghost"}
size={"xs"}
/>
</PopoverTrigger>
<Portal>
<PopoverContent fontSize={"sm"} minW={"500px"} minH={"520px"}>
<PopoverArrow />
<PopoverHeader>Image Configuration</PopoverHeader>
<PopoverBody>
<Flex flexDirection={"column"} gap={"8px"}>
<Text>
Configuration for the container with <Code>{imageName}</Code>
</Text>
<Text>Select the image type:</Text>
<Tabs index={activeTabIndex} onChange={handleTabsChange}>
<TabList>
{tabs.map((tab, i) => (
<Tab key={i}>{tab.display}</Tab>
))}
</TabList>
<TabPanels>
<TabPanel>
<KurtosisFormControl
size={"xs"}
name={"image.username"}
label={"Username"}
helperText={"The username that will be used to pull the image from the given registry"}
>
<StringArgumentInput size={"xs"} name={"imageConfig.username"} />
</KurtosisFormControl>
<KurtosisFormControl
name={"image.password"}
label={"Username"}
size={"xs"}
helperText={"The pasword that will be used to pull the image from the given registry"}
>
<StringArgumentInput name={"imageConfig.password"} size={"xs"} type={"password"} />
</KurtosisFormControl>
<KurtosisFormControl
size={"xs"}
name={"image.registry"}
label={"Registry"}
helperText={"The URL of the registry"}
>
<StringArgumentInput
name={"image.username"}
size={"xs"}
placeholder={"http://my.registry.io"}
/>
</KurtosisFormControl>
</TabPanel>
<TabPanel>
<KurtosisFormControl
size={"xs"}
name={"image.buildContextDir"}
label={"Build Context Dir"}
helperText={
"Locator to build context within the Kurtosis package. As of now, Kurtosis expects a Dockerfile at the root of the build context"
}
isRequired={activeTabIndex === 1}
>
<StringArgumentInput
size={"xs"}
name={"imageConfig.buildContextDir"}
isRequired={activeTabIndex === 1}
/>
</KurtosisFormControl>
<KurtosisFormControl
name={"imageConfig.targetStage"}
label={"Target Stage"}
size={"xs"}
helperText={"Stage of image build to target for multi-stage container image"}
>
<StringArgumentInput name={"imageConfig.targetStage"} size={"xs"} />
</KurtosisFormControl>
</TabPanel>
<TabPanel>
<KurtosisFormControl
size={"xs"}
name={"image.buildContextDir"}
label={"Build Context Dir"}
helperText={"Locator to build context within the Kurtosis package."}
isRequired={activeTabIndex === 2}
>
<StringArgumentInput
size={"xs"}
name={"image.buildContextDir"}
isRequired={activeTabIndex === 2}
placeholder={"./"}
/>
</KurtosisFormControl>
<KurtosisFormControl
name={"image.flakeLocationDir"}
label={"Flake Location Dir"}
size={"xs"}
helperText={
"The relative path (from the `build_context_dir`) to the folder containing the flake.nix file"
}
isRequired={activeTabIndex === 2}
>
<StringArgumentInput
name={"image.flakeLocationDir"}
size={"xs"}
placeholder={"./hello-go"}
isRequired={activeTabIndex === 2}
/>
</KurtosisFormControl>
<KurtosisFormControl
name={"image.flakeOutput"}
label={"Flake Output"}
size={"xs"}
helperText={
"The selector for the Flake output with the image derivation. Fallbacks to the default package."
}
>
<StringArgumentInput name={"image.flakeOutput"} size={"xs"} />
</KurtosisFormControl>
</TabPanel>
</TabPanels>
</Tabs>
</Flex>
</PopoverBody>
</PopoverContent>
</Portal>
</Popover>
</InputRightElement>
</InputGroup>
);
};
Expand Up @@ -22,10 +22,24 @@ export type KurtosisAcceptableCode = {
value: number;
};

export type KurtosisImageType = "image" | "dockerfile" | "nix";

export type KurtosisImageConfig = {
image: string;
type: KurtosisImageType;
registryUsername: string;
registryPassword: string;
registry: string;
buildContextDir: string;
targetStage: string;
flakeLocationDir: string;
flakeOutput: string;
};

export type KurtosisServiceNodeData = {
type: "service";
serviceName: string;
image: string;
image: KurtosisImageConfig;
env: KurtosisEnvironmentVar[];
ports: KurtosisPort[];
files: KurtosisFileMount[];
Expand All @@ -45,7 +59,7 @@ export type KurtosisShellNodeData = {
type: "shell";
shellName: string;
command: string;
image: string;
image: KurtosisImageConfig;
env: KurtosisEnvironmentVar[];
files: KurtosisFileMount[];
store: string;
Expand All @@ -61,7 +75,7 @@ export type KurtosisPythonNodeData = {
type: "python";
pythonName: string;
command: string;
image: string;
image: KurtosisImageConfig;
packages: KurtosisPythonPackage[];
args: KurtosisPythonArg[];
files: KurtosisFileMount[];
Expand Down

0 comments on commit f0e316e

Please sign in to comment.