From 343dbbd037d5070815836d7fd8386a00b5061e07 Mon Sep 17 00:00:00 2001 From: Laurent Luce Date: Wed, 12 Jun 2024 16:47:53 -0400 Subject: [PATCH] feat: Self cloud hosting (#2485) ## Description The Kurtosis CLI supports the local use case (localhost) and the Kurtosis cloud use case (cloud.kurtosis.com). We need to be able to build the CLI once and deploy it to multiple environments with different domain names. Add option to the engine to set a domain name used by the EM UI. The domain name is set in a static js file read by the EM UI. More details on this approach discussed here: https://kurtosistech.slack.com/archives/C032ZB39AHH/p1717770540781579 Adding Nginx in front of the engine + install script will be done as a cloud-config PR. ## Is this change user facing? YES --- .../engine_consuming_kurtosis_command.go | 2 +- cli/cli/commands/cluster/set/set.go | 2 +- cli/cli/commands/enclave/add/add.go | 3 ++- cli/cli/commands/engine/restart/restart.go | 22 +++++++++++++--- cli/cli/commands/engine/start/start.go | 26 +++++++++++++++---- cli/cli/commands/github/login/login.go | 2 +- cli/cli/commands/kurtosis_context/set/set.go | 2 +- cli/cli/defaults/defaults.go | 2 ++ .../engine_existence_guarantor.go | 10 +++++++ .../helpers/engine_manager/engine_manager.go | 9 +++++-- .../web/packages/app/public/index.html | 1 + .../web/packages/app/src/client/constants.ts | 8 ++++++ .../enclaveManager/LocalKurtosisClient.ts | 9 ++++--- .../enclaves/components/tables/PortsTable.tsx | 2 ++ engine/launcher/args/args.go | 6 +++++ .../engine_server_launcher.go | 6 ++++- engine/server/engine/main.go | 19 +++++++++++++- 17 files changed, 110 insertions(+), 21 deletions(-) diff --git a/cli/cli/command_framework/highlevel/engine_consuming_kurtosis_command/engine_consuming_kurtosis_command.go b/cli/cli/command_framework/highlevel/engine_consuming_kurtosis_command/engine_consuming_kurtosis_command.go index cb991f19c3..fd72080716 100644 --- a/cli/cli/command_framework/highlevel/engine_consuming_kurtosis_command/engine_consuming_kurtosis_command.go +++ b/cli/cli/command_framework/highlevel/engine_consuming_kurtosis_command/engine_consuming_kurtosis_command.go @@ -187,7 +187,7 @@ func (cmd *EngineConsumingKurtosisCommand) getSetupFunc() func(context.Context) kurtosisBackend := engineManager.GetKurtosisBackend() dontRestartAPIContainers := false - engineClient, closeClientFunc, err := engineManager.StartEngineIdempotentlyWithDefaultVersion(ctx, defaults.DefaultEngineLogLevel, defaults.DefaultEngineEnclavePoolSize, defaults.DefaultGitHubAuthTokenOverride, dontRestartAPIContainers) + engineClient, closeClientFunc, err := engineManager.StartEngineIdempotentlyWithDefaultVersion(ctx, defaults.DefaultEngineLogLevel, defaults.DefaultEngineEnclavePoolSize, defaults.DefaultGitHubAuthTokenOverride, dontRestartAPIContainers, defaults.DefaultDomain) if err != nil { return nil, stacktrace.Propagate(err, "An error occurred creating a new Kurtosis engine client") } diff --git a/cli/cli/commands/cluster/set/set.go b/cli/cli/commands/cluster/set/set.go index 0561734453..b31b22ad07 100644 --- a/cli/cli/commands/cluster/set/set.go +++ b/cli/cli/commands/cluster/set/set.go @@ -124,7 +124,7 @@ func run(ctx context.Context, flags *flags.ParsedFlags, args *args.ParsedArgs) e // TODO - fix the idempotent starter longer term if engineStatus == engine_manager.EngineStatus_Stopped { dontRestartAPIContainers := false - _, engineClientCloseFunc, err := engineManagerNewCluster.StartEngineIdempotentlyWithDefaultVersion(ctx, defaults.DefaultEngineLogLevel, defaults.DefaultEngineEnclavePoolSize, defaults.DefaultGitHubAuthTokenOverride, dontRestartAPIContainers) + _, engineClientCloseFunc, err := engineManagerNewCluster.StartEngineIdempotentlyWithDefaultVersion(ctx, defaults.DefaultEngineLogLevel, defaults.DefaultEngineEnclavePoolSize, defaults.DefaultGitHubAuthTokenOverride, dontRestartAPIContainers, defaults.DefaultDomain) if err != nil { return stacktrace.Propagate(err, "Engine could not be started after cluster was updated. Its status can be retrieved "+ "running 'kurtosis %s %s' and it can potentially be started running 'kurtosis %s %s'", diff --git a/cli/cli/commands/enclave/add/add.go b/cli/cli/commands/enclave/add/add.go index a3cb013e99..1eb3e304e4 100644 --- a/cli/cli/commands/enclave/add/add.go +++ b/cli/cli/commands/enclave/add/add.go @@ -120,7 +120,8 @@ func run( if err != nil { return stacktrace.Propagate(err, "An error occurred creating an engine manager.") } - engineClient, closeClientFunc, err := engineManager.StartEngineIdempotentlyWithDefaultVersion(ctx, defaults.DefaultEngineLogLevel, defaults.DefaultEngineEnclavePoolSize, defaults.DefaultGitHubAuthTokenOverride, dontRestartAPIContainers) + + engineClient, closeClientFunc, err := engineManager.StartEngineIdempotentlyWithDefaultVersion(ctx, defaults.DefaultEngineLogLevel, defaults.DefaultEngineEnclavePoolSize, defaults.DefaultGitHubAuthTokenOverride, dontRestartAPIContainers, defaults.DefaultDomain) if err != nil { return stacktrace.Propagate(err, "An error occurred creating a new Kurtosis engine client") } diff --git a/cli/cli/commands/engine/restart/restart.go b/cli/cli/commands/engine/restart/restart.go index 0dceb666d8..0be78b0b28 100644 --- a/cli/cli/commands/engine/restart/restart.go +++ b/cli/cli/commands/engine/restart/restart.go @@ -3,6 +3,9 @@ package restart import ( "context" "fmt" + "strconv" + "strings" + "github.com/kurtosis-tech/kurtosis/cli/cli/command_framework/lowlevel" "github.com/kurtosis-tech/kurtosis/cli/cli/command_framework/lowlevel/args" "github.com/kurtosis-tech/kurtosis/cli/cli/command_framework/lowlevel/flags" @@ -14,8 +17,6 @@ import ( "github.com/kurtosis-tech/kurtosis/kurtosis_version" "github.com/kurtosis-tech/stacktrace" "github.com/sirupsen/logrus" - "strconv" - "strings" ) const ( @@ -29,6 +30,9 @@ const ( defaultShouldRestartAPIContainers = "false" restartAPIContainersFlagKey = "restart-api-containers" + + domainFlagKey = "domain" + defaultDomain = "" ) var RestartCmd = &lowlevel.LowlevelKurtosisCommand{ @@ -81,6 +85,13 @@ var RestartCmd = &lowlevel.LowlevelKurtosisCommand{ Type: flags.FlagType_Bool, Default: defaultShouldRestartAPIContainers, }, + { + Key: domainFlagKey, + Usage: "The domain name of the enclave manager UI if self-hosting (blank defaults to localhost for the local use case and cloud.kurtosis.com for the Kurtosis cloud use case)", + Shorthand: "", + Type: flags.FlagType_String, + Default: defaultDomain, + }, }, PreValidationAndRunFunc: nil, RunFunc: run, @@ -142,9 +153,14 @@ func run(_ context.Context, flags *flags.ParsedFlags, _ *args.ParsedArgs) error return stacktrace.Propagate(err, "Expected a value for the '%v' flag but failed to get it", restartAPIContainersFlagKey) } + domain, err := flags.GetString(domainFlagKey) + if err != nil { + return stacktrace.Propagate(err, "An error occurred while getting the Kurtosis engine enclave manager UI domain name using the flag with key '%v'; this is a bug in Kurtosis", domainFlagKey) + } + var engineClientCloseFunc func() error var restartEngineErr error - _, engineClientCloseFunc, restartEngineErr = engineManager.RestartEngineIdempotently(ctx, logLevel, engineVersion, restartEngineOnSameVersionIfAnyRunning, enclavePoolSize, shouldStartInDebugMode, githubAuthTokenOverride, shouldRestartAPIContainers) + _, engineClientCloseFunc, restartEngineErr = engineManager.RestartEngineIdempotently(ctx, logLevel, engineVersion, restartEngineOnSameVersionIfAnyRunning, enclavePoolSize, shouldStartInDebugMode, githubAuthTokenOverride, shouldRestartAPIContainers, domain) if restartEngineErr != nil { return stacktrace.Propagate(restartEngineErr, "An error occurred restarting the Kurtosis engine") } diff --git a/cli/cli/commands/engine/start/start.go b/cli/cli/commands/engine/start/start.go index 29bcbdf278..4420a4b46f 100644 --- a/cli/cli/commands/engine/start/start.go +++ b/cli/cli/commands/engine/start/start.go @@ -3,6 +3,9 @@ package start import ( "context" "fmt" + "strconv" + "strings" + "github.com/kurtosis-tech/kurtosis/cli/cli/command_framework/lowlevel" "github.com/kurtosis-tech/kurtosis/cli/cli/command_framework/lowlevel/args" "github.com/kurtosis-tech/kurtosis/cli/cli/command_framework/lowlevel/flags" @@ -14,8 +17,6 @@ import ( "github.com/kurtosis-tech/kurtosis/kurtosis_version" "github.com/kurtosis-tech/stacktrace" "github.com/sirupsen/logrus" - "strconv" - "strings" ) const ( @@ -30,6 +31,9 @@ const ( defaultShouldRestartAPIContainers = "false" restartAPIContainersFlagKey = "restart-api-containers" + + domainFlagKey = "domain" + defaultDomain = "" ) var StartCmd = &lowlevel.LowlevelKurtosisCommand{ @@ -82,6 +86,13 @@ var StartCmd = &lowlevel.LowlevelKurtosisCommand{ Type: flags.FlagType_Bool, Default: defaultShouldRestartAPIContainers, }, + { + Key: domainFlagKey, + Usage: "The domain name of the enclave manager UI if self-hosting (blank defaults to localhost for the local use case and cloud.kurtosis.com for the Kurtosis cloud use case)", + Shorthand: "", + Type: flags.FlagType_String, + Default: defaultDomain, + }, }, PreValidationAndRunFunc: nil, RunFunc: run, @@ -138,16 +149,21 @@ func run(_ context.Context, flags *flags.ParsedFlags, _ *args.ParsedArgs) error return stacktrace.Propagate(err, "Expected a value for the '%v' flag but failed to get it", restartAPIContainersFlagKey) } + domain, err := flags.GetString(domainFlagKey) + if err != nil { + return stacktrace.Propagate(err, "An error occurred while getting the Kurtosis engine enclave manager UI domain name using the flag with key '%v'; this is a bug in Kurtosis", domainFlagKey) + } + if engineVersion == defaultEngineVersion && isDebugMode { engineDebugVersion := fmt.Sprintf("%s-%s", kurtosis_version.KurtosisVersion, defaults.DefaultKurtosisContainerDebugImageNameSuffix) logrus.Infof("Starting Kurtosis engine in debug mode from image '%v%v%v'...", kurtosisTechEngineImagePrefix, imageVersionDelimiter, engineDebugVersion) - _, engineClientCloseFunc, startEngineErr = engineManager.StartEngineIdempotentlyWithCustomVersion(ctx, engineDebugVersion, logLevel, enclavePoolSize, true, githubAuthTokenOverride, shouldRestartAPIContainers) + _, engineClientCloseFunc, startEngineErr = engineManager.StartEngineIdempotentlyWithCustomVersion(ctx, engineDebugVersion, logLevel, enclavePoolSize, true, githubAuthTokenOverride, shouldRestartAPIContainers, domain) } else if engineVersion == defaultEngineVersion { logrus.Infof("Starting Kurtosis engine from image '%v%v%v'...", kurtosisTechEngineImagePrefix, imageVersionDelimiter, kurtosis_version.KurtosisVersion) - _, engineClientCloseFunc, startEngineErr = engineManager.StartEngineIdempotentlyWithDefaultVersion(ctx, logLevel, enclavePoolSize, githubAuthTokenOverride, shouldRestartAPIContainers) + _, engineClientCloseFunc, startEngineErr = engineManager.StartEngineIdempotentlyWithDefaultVersion(ctx, logLevel, enclavePoolSize, githubAuthTokenOverride, shouldRestartAPIContainers, domain) } else { logrus.Infof("Starting Kurtosis engine from image '%v%v%v'...", kurtosisTechEngineImagePrefix, imageVersionDelimiter, engineVersion) - _, engineClientCloseFunc, startEngineErr = engineManager.StartEngineIdempotentlyWithCustomVersion(ctx, engineVersion, logLevel, enclavePoolSize, defaults.DefaultEnableDebugMode, githubAuthTokenOverride, shouldRestartAPIContainers) + _, engineClientCloseFunc, startEngineErr = engineManager.StartEngineIdempotentlyWithCustomVersion(ctx, engineVersion, logLevel, enclavePoolSize, defaults.DefaultEnableDebugMode, githubAuthTokenOverride, shouldRestartAPIContainers, domain) } if startEngineErr != nil { return stacktrace.Propagate(startEngineErr, "An error occurred starting the Kurtosis engine") diff --git a/cli/cli/commands/github/login/login.go b/cli/cli/commands/github/login/login.go index d0e5ffb86a..4a7ca9b3f4 100644 --- a/cli/cli/commands/github/login/login.go +++ b/cli/cli/commands/github/login/login.go @@ -71,7 +71,7 @@ func RestartEngineAfterGitHubAuth(ctx context.Context) error { var engineClientCloseFunc func() error var restartEngineErr error dontRestartAPIContainers := false - _, engineClientCloseFunc, restartEngineErr = engineManager.RestartEngineIdempotently(ctx, defaults.DefaultEngineLogLevel, defaultEngineVersion, restartEngineOnSameVersionIfAnyRunning, defaults.DefaultEngineEnclavePoolSize, defaults.DefaultEnableDebugMode, defaults.DefaultGitHubAuthTokenOverride, dontRestartAPIContainers) + _, engineClientCloseFunc, restartEngineErr = engineManager.RestartEngineIdempotently(ctx, defaults.DefaultEngineLogLevel, defaultEngineVersion, restartEngineOnSameVersionIfAnyRunning, defaults.DefaultEngineEnclavePoolSize, defaults.DefaultEnableDebugMode, defaults.DefaultGitHubAuthTokenOverride, dontRestartAPIContainers, defaults.DefaultDomain) if restartEngineErr != nil { return stacktrace.Propagate(restartEngineErr, "An error occurred restarting the Kurtosis engine") } diff --git a/cli/cli/commands/kurtosis_context/set/set.go b/cli/cli/commands/kurtosis_context/set/set.go index bf00452fb6..e6bde17d42 100644 --- a/cli/cli/commands/kurtosis_context/set/set.go +++ b/cli/cli/commands/kurtosis_context/set/set.go @@ -148,7 +148,7 @@ func SetContext( } dontRestartAPIContainers := false - _, engineClientCloseFunc, startEngineErr := engineManager.StartEngineIdempotentlyWithDefaultVersion(ctx, logrus.InfoLevel, defaults.DefaultEngineEnclavePoolSize, defaults.DefaultGitHubAuthTokenOverride, dontRestartAPIContainers) + _, engineClientCloseFunc, startEngineErr := engineManager.StartEngineIdempotentlyWithDefaultVersion(ctx, logrus.InfoLevel, defaults.DefaultEngineEnclavePoolSize, defaults.DefaultGitHubAuthTokenOverride, dontRestartAPIContainers, defaults.DefaultDomain) if startEngineErr != nil { logrus.Warnf("The context was successfully set to '%s' but Kurtosis failed to start an engine in "+ "this new context. A new engine should be started manually with '%s %s %s'. The error was:\n%v", diff --git a/cli/cli/defaults/defaults.go b/cli/cli/defaults/defaults.go index 27e8032fd2..84c52a430d 100644 --- a/cli/cli/defaults/defaults.go +++ b/cli/cli/defaults/defaults.go @@ -24,6 +24,8 @@ const ( DefaultKurtosisContainerDebugImageNameSuffix = "debug" DefaultGitHubAuthTokenOverride = "" + + DefaultDomain = "" ) var DefaultApiContainerLogLevel = logrus.DebugLevel diff --git a/cli/cli/helpers/engine_manager/engine_existence_guarantor.go b/cli/cli/helpers/engine_manager/engine_existence_guarantor.go index 04c6286ee4..c09a536a14 100644 --- a/cli/cli/helpers/engine_manager/engine_existence_guarantor.go +++ b/cli/cli/helpers/engine_manager/engine_existence_guarantor.go @@ -3,6 +3,7 @@ package engine_manager import ( "context" "fmt" + "github.com/kurtosis-tech/kurtosis/cli/cli/helpers/github_auth_store" "github.com/Masterminds/semver/v3" @@ -84,6 +85,9 @@ type engineExistenceGuarantor struct { // To restart the current API containers after the engine has been restarted restartAPIContainers bool + + // Enclave manager UI domain name + domain string } func newEngineExistenceGuarantorWithDefaultVersion( @@ -102,6 +106,7 @@ func newEngineExistenceGuarantorWithDefaultVersion( shouldRunInDebugMode bool, githubAuthTokenOverride string, restartAPIContainers bool, + domain string, ) *engineExistenceGuarantor { return newEngineExistenceGuarantorWithCustomVersion( ctx, @@ -120,6 +125,7 @@ func newEngineExistenceGuarantorWithDefaultVersion( shouldRunInDebugMode, githubAuthTokenOverride, restartAPIContainers, + domain, ) } @@ -140,6 +146,7 @@ func newEngineExistenceGuarantorWithCustomVersion( shouldRunInDebugMode bool, githubAuthTokenOverride string, restartAPIContainers bool, + domain string, ) *engineExistenceGuarantor { return &engineExistenceGuarantor{ ctx: ctx, @@ -160,6 +167,7 @@ func newEngineExistenceGuarantorWithCustomVersion( shouldRunInDebugMode: shouldRunInDebugMode, githubAuthTokenOverride: githubAuthTokenOverride, restartAPIContainers: restartAPIContainers, + domain: domain, } } @@ -219,6 +227,7 @@ func (guarantor *engineExistenceGuarantor) VisitStopped() error { guarantor.shouldRunInDebugMode, githubAuthToken, guarantor.restartAPIContainers, + guarantor.domain, ) } else { _, _, engineLaunchErr = guarantor.engineServerLauncher.LaunchWithCustomVersion( @@ -239,6 +248,7 @@ func (guarantor *engineExistenceGuarantor) VisitStopped() error { guarantor.shouldRunInDebugMode, githubAuthToken, guarantor.restartAPIContainers, + guarantor.domain, ) } if engineLaunchErr != nil { diff --git a/cli/cli/helpers/engine_manager/engine_manager.go b/cli/cli/helpers/engine_manager/engine_manager.go index 68cfcc8281..564240afb4 100644 --- a/cli/cli/helpers/engine_manager/engine_manager.go +++ b/cli/cli/helpers/engine_manager/engine_manager.go @@ -182,6 +182,7 @@ func (manager *EngineManager) StartEngineIdempotentlyWithDefaultVersion( poolSize uint8, githubAuthTokenOverride string, restartAPIContainers bool, + domain string, ) (kurtosis_engine_rpc_api_bindings.EngineServiceClient, func() error, error) { status, maybeHostMachinePortBinding, engineVersion, err := manager.GetEngineStatus(ctx) if err != nil { @@ -205,6 +206,7 @@ func (manager *EngineManager) StartEngineIdempotentlyWithDefaultVersion( doNotStartTheEngineInDebugModeForDefaultVersion, githubAuthTokenOverride, restartAPIContainers, + domain, ) // TODO Need to handle the Kubernetes case, where a gateway needs to be started after the engine is started but // before we can return an EngineClient @@ -224,6 +226,7 @@ func (manager *EngineManager) StartEngineIdempotentlyWithCustomVersion( shouldStartInDebugMode bool, githubAuthTokenOverride string, restartAPIContainers bool, + domain string, ) (kurtosis_engine_rpc_api_bindings.EngineServiceClient, func() error, error) { status, maybeHostMachinePortBinding, engineVersion, err := manager.GetEngineStatus(ctx) if err != nil { @@ -248,6 +251,7 @@ func (manager *EngineManager) StartEngineIdempotentlyWithCustomVersion( shouldStartInDebugMode, githubAuthTokenOverride, restartAPIContainers, + domain, ) engineClient, engineClientCloseFunc, err := manager.startEngineWithGuarantor(ctx, status, engineGuarantor) if err != nil { @@ -348,6 +352,7 @@ func (manager *EngineManager) RestartEngineIdempotently( shouldStartInDebugMode bool, githubAuthTokenOverride string, shouldRestartAPIContainers bool, + domain string, ) (kurtosis_engine_rpc_api_bindings.EngineServiceClient, func() error, error) { var versionOfNewEngine string // We try to do our best to restart an engine on the same version the current on is on @@ -373,9 +378,9 @@ func (manager *EngineManager) RestartEngineIdempotently( var engineClientCloseFunc func() error var restartEngineErr error if versionOfNewEngine != defaultEngineVersion { - _, engineClientCloseFunc, restartEngineErr = manager.StartEngineIdempotentlyWithCustomVersion(ctx, versionOfNewEngine, logLevel, poolSize, shouldStartInDebugMode, githubAuthTokenOverride, shouldRestartAPIContainers) + _, engineClientCloseFunc, restartEngineErr = manager.StartEngineIdempotentlyWithCustomVersion(ctx, versionOfNewEngine, logLevel, poolSize, shouldStartInDebugMode, githubAuthTokenOverride, shouldRestartAPIContainers, domain) } else { - _, engineClientCloseFunc, restartEngineErr = manager.StartEngineIdempotentlyWithDefaultVersion(ctx, logLevel, poolSize, githubAuthTokenOverride, shouldRestartAPIContainers) + _, engineClientCloseFunc, restartEngineErr = manager.StartEngineIdempotentlyWithDefaultVersion(ctx, logLevel, poolSize, githubAuthTokenOverride, shouldRestartAPIContainers, domain) } if restartEngineErr != nil { return nil, nil, stacktrace.Propagate(restartEngineErr, "An error occurred starting a new engine") diff --git a/enclave-manager/web/packages/app/public/index.html b/enclave-manager/web/packages/app/public/index.html index 653ae6eb39..f810cc42b9 100644 --- a/enclave-manager/web/packages/app/public/index.html +++ b/enclave-manager/web/packages/app/public/index.html @@ -6,6 +6,7 @@ +