Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: experimental enclave building in the EMUI #2137

Merged
merged 19 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions enclave-manager/web/packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"private": true,
"homepage": ".",
"dependencies": {
"@dagrejs/dagre": "^1.0.4",
"ansi-to-html": "^0.7.2",
"enclave-manager-sdk": "file:../../../api/typescript",
"html-react-parser": "^4.2.2",
Expand All @@ -12,11 +13,16 @@
"kurtosis-ui-components": "0.86.16",
"react-error-boundary": "^4.0.11",
"react-hook-form": "^7.47.0",
"react-mentions": "^4.4.10",
"reactflow": "^11.10.2",
"uuid": "^9.0.1",
"yaml": "^2.3.4"
},
"devDependencies": {
"@types/js-cookie": "^3.0.6",
"@types/react-mentions": "^4.1.13",
"@types/streamsaver": "^2.0.4",
"@types/uuid": "^9.0.8",
"serve": "^14.2.1",
"source-map-explorer": "^2.5.3"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
DownloadFilesArtifactArgs,
FilesArtifactNameAndUuid,
RunStarlarkPackageArgs,
RunStarlarkScriptArgs,
ServiceInfo,
} from "enclave-manager-sdk/build/api_container_service_pb";
import {
Expand All @@ -22,6 +23,7 @@ import {
GetStarlarkRunRequest,
InspectFilesArtifactContentsRequest,
RunStarlarkPackageRequest,
RunStarlarkScriptRequest,
} from "enclave-manager-sdk/build/kurtosis_enclave_manager_api_pb";
import { assertDefined, asyncResult, isDefined, RemoveFunctions } from "kurtosis-ui-components";
import { EnclaveFullInfo } from "../../emui/enclaves/types";
Expand Down Expand Up @@ -202,17 +204,37 @@ export abstract class KurtosisClient {
apicInfo: RemoveFunctions<EnclaveAPIContainerInfo>,
packageId: string,
args: Record<string, any>,
dryRun: boolean = false,
) {
// Not currently using asyncResult as the return type here is an asyncIterable
const request = new RunStarlarkPackageRequest({
apicIpAddress: apicInfo.bridgeIpAddress,
apicPort: apicInfo.grpcPortInsideEnclave,
RunStarlarkPackageArgs: new RunStarlarkPackageArgs({
dryRun: false,
dryRun,
packageId: packageId,
serializedParams: JSON.stringify(args),
}),
});
return this.client.runStarlarkPackage(request, this.getHeaderOptions());
}

async runStarlarkScript(
apicInfo: RemoveFunctions<EnclaveAPIContainerInfo>,
serializedScript: string,
args: Record<string, any> = {},
dryRun: boolean = false,
) {
// Not currently using asyncResult as the return type here is an asyncIterable
const request = new RunStarlarkScriptRequest({
apicIpAddress: apicInfo.bridgeIpAddress,
apicPort: apicInfo.grpcPortInsideEnclave,
RunStarlarkScriptArgs: new RunStarlarkScriptArgs({
dryRun,
serializedScript,
serializedParams: JSON.stringify(args),
}),
});
return this.client.runStarlarkScript(request, this.getHeaderOptions());
}
}
19 changes: 12 additions & 7 deletions enclave-manager/web/packages/app/src/emui/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import { KurtosisClientProvider, useKurtosisClient } from "../client/enclaveMana
import { KurtosisPackageIndexerProvider } from "../client/packageIndexer/KurtosisPackageIndexerClientContext";
import { CatalogContextProvider } from "./catalog/CatalogContext";
import { catalogRoutes } from "./catalog/CatalogRoutes";
import { BuildEnclave } from "./enclaves/components/BuildEnclave";
import { CreateEnclave } from "./enclaves/components/CreateEnclave";
import { enclaveRoutes } from "./enclaves/EnclaveRoutes";
import { EnclavesContextProvider } from "./enclaves/EnclavesContext";
import { Navbar } from "./Navbar";
import { SettingsContextProvider } from "./settings";

const logLogo = (t: string) => console.log(`%c ${t}`, "background: black; color: #00C223");
logLogo(`
Expand All @@ -35,13 +37,15 @@ console.log(`Kurtosis web UI version: ${process.env.REACT_APP_VERSION || "Unknow

export const EmuiApp = () => {
return (
<KurtosisThemeProvider>
<KurtosisPackageIndexerProvider>
<KurtosisClientProvider>
<KurtosisRouter />
</KurtosisClientProvider>
</KurtosisPackageIndexerProvider>
</KurtosisThemeProvider>
<SettingsContextProvider>
<KurtosisThemeProvider>
<KurtosisPackageIndexerProvider>
<KurtosisClientProvider>
<KurtosisRouter />
</KurtosisClientProvider>
</KurtosisPackageIndexerProvider>
</KurtosisThemeProvider>
</SettingsContextProvider>
);
};

Expand All @@ -65,6 +69,7 @@ const KurtosisRouter = () => {
<EnclavesContextProvider>
<Outlet />
<CreateEnclave />
<BuildEnclave />
</EnclavesContextProvider>
),
children: enclaveRoutes(),
Expand Down
32 changes: 31 additions & 1 deletion enclave-manager/web/packages/app/src/emui/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {
Button,
FormControl,
FormLabel,
Input,
InputGroup,
InputRightElement,
Expand All @@ -10,6 +12,7 @@ import {
ModalFooter,
ModalHeader,
ModalOverlay,
Switch,
Text,
} from "@chakra-ui/react";
import { CopyButton, NavButton, Navigation, NavigationDivider } from "kurtosis-ui-components";
Expand All @@ -21,8 +24,10 @@ import { PiLinkSimpleBold } from "react-icons/pi";
import { Link, useLocation } from "react-router-dom";
import { KURTOSIS_CLOUD_CONNECT_URL } from "../client/constants";
import { useKurtosisClient } from "../client/enclaveManager/KurtosisClientContext";
import { settingKeys, useSettings } from "./settings";

export const Navbar = () => {
const { updateSetting, settings } = useSettings();
const location = useLocation();
const kurtosisClient = useKurtosisClient();
const [showAboutDialog, setShowAboutDialog] = useState(false);
Expand Down Expand Up @@ -78,7 +83,32 @@ export const Navbar = () => {
/>
</InputRightElement>
</InputGroup>
<Text></Text>
<Text
as={"h2"}
fontSize={"lg"}
m={"16px 0"}
pt={"16px"}
borderTopWidth={"1px"}
borderTopColor={"gray.60"}
fontWeight={"semibold"}
>
Settings:
</Text>
<FormControl display="flex" alignItems="center">
<FormLabel htmlFor="experimental-build" mb="0">
Enable experimental enclave builder interface?
</FormLabel>
<Switch
id="experimental-build"
onChange={() =>
updateSetting(
settingKeys.ENABLE_EXPERIMENTAL_BUILD_ENCLAVE,
!settings.ENABLE_EXPERIMENTAL_BUILD_ENCLAVE,
)
}
isChecked={settings.ENABLE_EXPERIMENTAL_BUILD_ENCLAVE}
/>
</FormControl>
</ModalBody>

<ModalFooter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { Flex, Heading, Spinner } from "@chakra-ui/react";
import { GetPackagesResponse, KurtosisPackage } from "kurtosis-cloud-indexer-sdk";
import { ReadPackageResponse } from "kurtosis-cloud-indexer-sdk/build/kurtosis_package_indexer_pb";
import { isDefined, SavedPackagesProvider } from "kurtosis-ui-components";
import { createContext, PropsWithChildren, useCallback, useContext, useEffect, useState } from "react";
import { createContext, PropsWithChildren, useCallback, useContext, useEffect, useLayoutEffect, useState } from "react";
import { Result } from "true-myth";
import { useKurtosisPackageIndexerClient } from "../../client/packageIndexer/KurtosisPackageIndexerClientContext";
import { loadSavedPackageNames, storeSavedPackages } from "./storage";
import { settingKeys, useSettings } from "../settings";

export type CatalogState = {
catalog: Result<GetPackagesResponse, string>;
Expand All @@ -16,6 +16,7 @@ export type CatalogState = {
const CatalogContext = createContext<CatalogState>(null as any);

export const CatalogContextProvider = ({ children }: PropsWithChildren) => {
const { settings, updateSetting } = useSettings();
const packageIndexerClient = useKurtosisPackageIndexerClient();
const [catalog, setCatalog] = useState<Result<GetPackagesResponse, string>>();
const [savedPackages, setSavedPackages] = useState<KurtosisPackage[]>([]);
Expand All @@ -25,24 +26,25 @@ export const CatalogContextProvider = ({ children }: PropsWithChildren) => {
const catalog = await packageIndexerClient.getPackages();
setCatalog(catalog);

if (catalog.isOk) {
const savedPackageNames = new Set(loadSavedPackageNames());
setSavedPackages(catalog.value.packages.filter((kurtosisPackage) => savedPackageNames.has(kurtosisPackage.name)));
}

return catalog;
}, [packageIndexerClient]);

const togglePackageSaved = useCallback((kurtosisPackage: KurtosisPackage) => {
setSavedPackages((savedPackages) => {
const packageSavedAlready = savedPackages.some((p) => p.name === kurtosisPackage.name);
const newSavedPackages: KurtosisPackage[] = packageSavedAlready
? savedPackages.filter((p) => p.name !== kurtosisPackage.name)
: [...savedPackages, kurtosisPackage];
storeSavedPackages(newSavedPackages);
return newSavedPackages;
});
}, []);
const togglePackageSaved = useCallback(
(kurtosisPackage: KurtosisPackage) => {
setSavedPackages((savedPackages) => {
const packageSavedAlready = savedPackages.some((p) => p.name === kurtosisPackage.name);
const newSavedPackages: KurtosisPackage[] = packageSavedAlready
? savedPackages.filter((p) => p.name !== kurtosisPackage.name)
: [...savedPackages, kurtosisPackage];
updateSetting(
settingKeys.SAVED_PACKAGES,
newSavedPackages.map((kurtosisPackage) => kurtosisPackage.name),
);
return newSavedPackages;
});
},
[updateSetting],
);

const getSinglePackage = useCallback(
async (packageName: string) => {
Expand All @@ -55,6 +57,14 @@ export const CatalogContextProvider = ({ children }: PropsWithChildren) => {
refreshCatalog();
}, [refreshCatalog]);

// Use a Layout effect so that the saved packages are set before first render.
useLayoutEffect(() => {
if (isDefined(catalog) && catalog.isOk) {
const savedPackageNames = new Set(settings.SAVED_PACKAGES);
setSavedPackages(catalog.value.packages.filter((kurtosisPackage) => savedPackageNames.has(kurtosisPackage.name)));
}
}, [catalog, settings.SAVED_PACKAGES]);

if (!isDefined(catalog)) {
return (
<Flex width="100%" direction="column" alignItems={"center"} gap={"1rem"} padding={"3rem"}>
Expand Down
26 changes: 0 additions & 26 deletions enclave-manager/web/packages/app/src/emui/catalog/storage.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ export type EnclavesState = {
enclave: RemoveFunctions<EnclaveInfo>,
packageId: string,
args: Record<string, any>,
dryRun?: boolean,
) => Promise<AsyncIterable<StarlarkRunResponseLine>>;
runStarlarkScript: (
enclave: RemoveFunctions<EnclaveInfo>,
script: string,
args: Record<string, any>,
dryRun?: boolean,
) => Promise<AsyncIterable<StarlarkRunResponseLine>>;
updateStarlarkFinishedInEnclave: (enclave: RemoveFunctions<EnclaveInfo>) => void;
};
Expand Down Expand Up @@ -168,10 +175,30 @@ export const EnclavesContextProvider = ({ skipInitialLoad, children }: EnclavesC
);

const runStarlarkPackage = useCallback(
async (enclave: RemoveFunctions<EnclaveInfo>, packageId: string, args: Record<string, any>) => {
async (
enclave: RemoveFunctions<EnclaveInfo>,
packageId: string,
args: Record<string, any>,
dryRun: boolean = false,
) => {
setState((state) => ({ ...state, starlarkRunningInEnclaves: [...state.starlarkRunningInEnclaves, enclave] }));
assertDefined(enclave.apiContainerInfo, `apic info not defined in enclave ${enclave.name}`);
const resp = await kurtosisClient.runStarlarkPackage(enclave.apiContainerInfo, packageId, args, dryRun);
return resp;
},
[kurtosisClient],
);

const runStarlarkScript = useCallback(
async (
enclave: RemoveFunctions<EnclaveInfo>,
script: string,
args: Record<string, any>,
dryRun: boolean = false,
) => {
setState((state) => ({ ...state, starlarkRunningInEnclaves: [...state.starlarkRunningInEnclaves, enclave] }));
assertDefined(enclave.apiContainerInfo, `apic info not defined in enclave ${enclave.name}`);
const resp = await kurtosisClient.runStarlarkPackage(enclave.apiContainerInfo, packageId, args);
const resp = await kurtosisClient.runStarlarkScript(enclave.apiContainerInfo, script, args, dryRun);
return resp;
},
[kurtosisClient],
Expand Down Expand Up @@ -217,6 +244,7 @@ export const EnclavesContextProvider = ({ skipInitialLoad, children }: EnclavesC
createEnclave,
destroyEnclaves,
runStarlarkPackage,
runStarlarkScript,
updateStarlarkFinishedInEnclave,
}}
>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { isDefined } from "kurtosis-ui-components";
import { useEffect, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { useSettings } from "../../settings";
import { KURTOSIS_BUILD_ENCLAVE_URL_ARG } from "./configuration/drawer/constants";
import { EnclaveBuilderModal } from "./modals/EnclaveBuilderModal";

export const BuildEnclave = () => {
const { settings } = useSettings();
const navigate = useNavigate();
const location = useLocation();

const [buildEnclaveOpen, setBuildEnclaveOpen] = useState(false);

useEffect(() => {
setBuildEnclaveOpen(location.hash === `#${KURTOSIS_BUILD_ENCLAVE_URL_ARG}`);
}, [location]);

const handleCloseBuildEnclave = () => {
setBuildEnclaveOpen(false);
if (isDefined(location.hash)) {
navigate(`${location.pathname}${location.search}`);
}
};

if (!settings.ENABLE_EXPERIMENTAL_BUILD_ENCLAVE) {
return null;
}

return <EnclaveBuilderModal isOpen={buildEnclaveOpen} onClose={handleCloseBuildEnclave} />;
};
Loading
Loading