From cd3d928ad2bc53e78e7b43897300d55b33b4a021 Mon Sep 17 00:00:00 2001 From: Tedi Mitiku Date: Thu, 2 May 2024 08:28:14 -0400 Subject: [PATCH] fix: update image UI arg parsing (#2419) ## Description Fixes how args are parsed and passing into script that updates images. Also fixes logic with how `initialSerializedParams` are set. ## Is this change user facing? NO ## References https://github.com/kurtosis-tech/kurtosis/pull/2406 --- .../server/api_container_service.go | 16 ++-- .../components/enclaveBuilder/utils.ts | 2 +- .../components/widgets/ImageButton.tsx | 89 +++++++++++-------- 3 files changed, 63 insertions(+), 44 deletions(-) diff --git a/core/server/api_container/server/api_container_service.go b/core/server/api_container/server/api_container_service.go index c1de99148a..78f6395a3f 100644 --- a/core/server/api_container/server/api_container_service.go +++ b/core/server/api_container/server/api_container_service.go @@ -115,7 +115,9 @@ func NewApiContainerService( metricsClient metrics_client.MetricsClient, githubAuthProvider *git_package_content_provider.GitHubPackageAuthProvider, ) (*ApiContainerService, error) { - var emptyInitialSerializedParams *string + var emptyInitialSerializedParams string + emptyInitialSerializedParamsPtr := &emptyInitialSerializedParams + *emptyInitialSerializedParamsPtr = "" service := &ApiContainerService{ filesArtifactStore: filesArtifactStore, serviceNetwork: serviceNetwork, @@ -132,7 +134,7 @@ func NewApiContainerService( MainFunctionName: "", ExperimentalFeatures: []kurtosis_core_rpc_api_bindings.KurtosisFeatureFlag{}, RestartPolicy: kurtosis_core_rpc_api_bindings.RestartPolicy_NEVER, - InitialSerializedParams: emptyInitialSerializedParams, + InitialSerializedParams: emptyInitialSerializedParamsPtr, }, metricsClient: metricsClient, githubAuthProvider: githubAuthProvider, @@ -175,9 +177,8 @@ func (apicService *ApiContainerService) RunStarlarkScript(args *kurtosis_core_rp args.GetExperimentalFeatures(), stream) - var initialSerializedParams *string if apicService.starlarkRun.InitialSerializedParams == nil || *apicService.starlarkRun.InitialSerializedParams == "" { - initialSerializedParams = &apicService.starlarkRun.SerializedParams + apicService.starlarkRun.InitialSerializedParams = &serializedParams } apicService.starlarkRun = &kurtosis_core_rpc_api_bindings.GetStarlarkRunResponse{ PackageId: apicService.starlarkRun.PackageId, @@ -188,7 +189,7 @@ func (apicService *ApiContainerService) RunStarlarkScript(args *kurtosis_core_rp MainFunctionName: mainFuncName, ExperimentalFeatures: experimentalFeatures, RestartPolicy: apicService.restartPolicy, - InitialSerializedParams: initialSerializedParams, + InitialSerializedParams: apicService.starlarkRun.InitialSerializedParams, } return nil @@ -323,9 +324,8 @@ func (apicService *ApiContainerService) RunStarlarkPackage(args *kurtosis_core_r serializedParams) apicService.runStarlark(parallelism, dryRun, detectedPackageId, detectedPackageReplaceOptions, mainFuncName, actualRelativePathToMainFile, scriptWithRunFunction, serializedParams, downloadMode, nonBlockingMode, args.ExperimentalFeatures, stream) - var initialSerializedParams *string if apicService.starlarkRun.InitialSerializedParams == nil || *apicService.starlarkRun.InitialSerializedParams == "" { - initialSerializedParams = &apicService.starlarkRun.SerializedParams + apicService.starlarkRun.InitialSerializedParams = &serializedParams } apicService.starlarkRun = &kurtosis_core_rpc_api_bindings.GetStarlarkRunResponse{ PackageId: packageIdFromArgs, @@ -336,7 +336,7 @@ func (apicService *ApiContainerService) RunStarlarkPackage(args *kurtosis_core_r MainFunctionName: mainFuncName, ExperimentalFeatures: args.ExperimentalFeatures, RestartPolicy: apicService.restartPolicy, - InitialSerializedParams: initialSerializedParams, + InitialSerializedParams: apicService.starlarkRun.InitialSerializedParams, } return nil } diff --git a/enclave-manager/web/packages/app/src/emui/enclaves/components/enclaveBuilder/utils.ts b/enclave-manager/web/packages/app/src/emui/enclaves/components/enclaveBuilder/utils.ts index 26d451ecd1..feb174821a 100644 --- a/enclave-manager/web/packages/app/src/emui/enclaves/components/enclaveBuilder/utils.ts +++ b/enclave-manager/web/packages/app/src/emui/enclaves/components/enclaveBuilder/utils.ts @@ -314,7 +314,7 @@ export function generateStarlarkFromGraph( o.forEach((arrayValue) => { result += `${objectToStarlark(arrayValue, indent + 4)},\n`; }); - result += `${padLeft}],\n`; + result += `${padLeft}]\n`; return result; } if (typeof o === "number") { diff --git a/enclave-manager/web/packages/app/src/emui/enclaves/components/widgets/ImageButton.tsx b/enclave-manager/web/packages/app/src/emui/enclaves/components/widgets/ImageButton.tsx index c60e955092..ff2b509cdf 100644 --- a/enclave-manager/web/packages/app/src/emui/enclaves/components/widgets/ImageButton.tsx +++ b/enclave-manager/web/packages/app/src/emui/enclaves/components/widgets/ImageButton.tsx @@ -12,9 +12,10 @@ import { ModalOverlay, } from "@chakra-ui/react"; import { isDefined, RemoveFunctions } from "kurtosis-ui-components"; -import { useMemo, useState } from "react"; +import { useCallback, useMemo, useState } from "react"; import { IoLogoDocker } from "react-icons/io5"; import { useNavigate } from "react-router-dom"; +import { useKurtosisPackageIndexerClient } from "../../../../client/packageIndexer/KurtosisPackageIndexerClientContext"; import { useEnclavesContext } from "../../EnclavesContext"; import { EnclaveFullInfo } from "../../types"; @@ -41,14 +42,14 @@ function objectToStarlark(o: any, indent: number) { o.forEach((arrayValue) => { result += `${objectToStarlark(arrayValue, indent + 4)},\n`; }); - result += `${padLeft}],\n`; + result += `${padLeft}]\n`; return result; } if (typeof o === "number") { return `${o}`; } if (typeof o === "string") { - return `${o}`; + return `"${o}"`; } if (typeof o === "boolean") { return o ? "True" : "False"; @@ -56,33 +57,17 @@ function objectToStarlark(o: any, indent: number) { if (typeof o === "object") { let result = "{"; Object.entries(o).forEach(([key, value]) => { - result += `\n${padLeft}"${key}": "${objectToStarlark(value, indent + 4)}",`; + result += `\n${padLeft}"${key}": ${objectToStarlark(value, indent + 4)},`; }); result += `${padLeft}}`; return result; } } -function deserializeParams(serializedParams: string): Record { - try { - const parsedParams = JSON.parse(serializedParams); - if (typeof parsedParams === "object" && parsedParams !== null) { - const deserialized: Record = {}; - for (const key in parsedParams) { - if (typeof parsedParams[key] === "string") { - deserialized[key] = parsedParams[key]; - } else { - throw new Error("Value is not a string."); - } - } - return deserialized; - } else { - throw new Error("Invalid JSON format."); - } - } catch (error) { - console.error("Error deserializing params:", error); - return {}; - } +function wrapWithArgs(args: Record) { + return { + args: args, + }; } export type SetImageModalProps = { @@ -97,8 +82,16 @@ export const SetImageModel = ({ isOpen, onClose, currentImage, serviceName, encl const { runStarlarkScript } = useEnclavesContext(); // Assuming this is defined elsewhere const [error, setError] = useState(null); const [newImage, setNewImage] = useState(""); + const packageIndexerClient = useKurtosisPackageIndexerClient(); const navigator = useNavigate(); + const getPackageInfo = useCallback( + async (packageName: string) => { + return await packageIndexerClient.readPackage(packageName); + }, + [packageIndexerClient], + ); + const handleSetImageSubmit = async (e: React.FormEvent) => { e.preventDefault(); @@ -109,25 +102,51 @@ export const SetImageModel = ({ isOpen, onClose, currentImage, serviceName, encl } const packageId = starlarkRun.value.packageId; + const packageInfoResponse = await getPackageInfo(packageId); + if (packageInfoResponse.isErr) { + setError(`Error occurred getting info about ${packageId} from indexer.`); + return; + } + if (!packageInfoResponse.value.package) { + setError(`Could not find package ${packageId}`); + return; + } + const packageArgs = packageInfoResponse.value.package.args; - let argsRecord; - if (starlarkRun.value.initialSerializedParams) { - console.log(`initial serialized params: ${starlarkRun.value.initialSerializedParams}`); - argsRecord = deserializeParams(starlarkRun.value.initialSerializedParams); - } else { - console.log(`serialized params: ${starlarkRun.value.serializedParams}`); - argsRecord = deserializeParams(starlarkRun.value.serializedParams); + console.log(`initial serialized params: ${starlarkRun.value.initialSerializedParams}`); + if (!starlarkRun.value.initialSerializedParams) { + setError(`Error occurred getting initial params used to start package.`); + return; + } + const argsRecord = JSON.parse(starlarkRun.value.initialSerializedParams); + if (typeof argsRecord !== "object" || argsRecord === null) { + setError("Error: deserializing initial params of starlark package run failed."); + return; } - const args = objectToStarlark(argsRecord, 8); - console.log(`initial args used to start package:\n${args}`); - const updateImageStarlarkScript = ` -package = import_module("${packageId}/main.star") + let args; + if (packageArgs.length === 2 && packageArgs[1].name === "args") { + args = objectToStarlark(wrapWithArgs(argsRecord), 4); + } else { + args = objectToStarlark(argsRecord, 4); + } + console.log(`args used to start package:\n${args}`); + + // if we've already run an update image, just append another set service instruction, otherwise create a new set service script + let updateImageStarlarkScript; + console.log(`serialized script: ${starlarkRun.value.serializedScript}`); + console.log(starlarkRun.value.serializedScript.slice(0, 7).toLowerCase()); + if (starlarkRun.value.serializedScript.slice(0, 7).toLowerCase() === "package") { + const latestSetService = `\n\n plan.set_service(name="${serviceName}", config=ServiceConfig(image="${newImage}"))`; + updateImageStarlarkScript = starlarkRun.value.serializedScript + latestSetService; + } else { + updateImageStarlarkScript = `package = import_module("${packageId}/main.star") def run(plan, args): package.run(plan, **${args}) plan.set_service(name="${serviceName}", config=ServiceConfig(image="${newImage}"))`; + } console.log(`starlark script to service ${serviceName} to image ${newImage}\n${updateImageStarlarkScript}`); try {