From 5ebda16fc9d9f7a4b471828f5f66504e47fba1a9 Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Thu, 30 Oct 2025 12:56:40 +0100 Subject: [PATCH] Remove init function contacting the cluster so that 'roxie version' does not block --- cmd/deploy.go | 4 +-- cmd/env.go | 4 +-- cmd/logs.go | 15 ++++++++-- pkg/deployer/deploy_via_operator.go | 2 +- pkg/deployer/deployer.go | 4 +-- pkg/env/env.go | 43 ++++++++++++++++++++++------- 6 files changed, 53 insertions(+), 19 deletions(-) diff --git a/cmd/deploy.go b/cmd/deploy.go index 507a190c..02319db3 100644 --- a/cmd/deploy.go +++ b/cmd/deploy.go @@ -78,7 +78,7 @@ func runDeploy(cmd *cobra.Command, args []string) error { } // On infra OpenShift we already get image pull secrets for Quay automatically. - if env.CurrentClusterType != env.InfraOpenShift4 { + if env.GetCurrentClusterType() != env.InfraOpenShift4 { if os.Getenv("REGISTRY_USERNAME") == "" || os.Getenv("REGISTRY_PASSWORD") == "" { return errors.New("containerized mode requires REGISTRY_USERNAME and REGISTRY_PASSWORD environment variables") } @@ -129,7 +129,7 @@ func runDeploy(cmd *cobra.Command, args []string) error { // Resolve "auto" resources based on cluster type resolvedResources := resources if resources == "auto" { - resolvedResources = resolveAutoResources(env.CurrentClusterType, log) + resolvedResources = resolveAutoResources(env.GetCurrentClusterType(), log) } ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute) diff --git a/cmd/env.go b/cmd/env.go index b0d278a4..c92b2af7 100644 --- a/cmd/env.go +++ b/cmd/env.go @@ -23,6 +23,6 @@ func runEnv(cmd *cobra.Command, args []string) { fmt.Println("Roxie Environment Information:") fmt.Println("==============================") fmt.Printf("Running in Container: %v\n", env.RunningInContainer) - fmt.Printf("Current Context: %s\n", env.CurrentContext) - fmt.Printf("Cluster Type: %s\n", env.CurrentClusterType.String()) + fmt.Printf("Current Context: %s\n", env.GetCurrentContext()) + fmt.Printf("Cluster Type: %s\n", env.GetCurrentClusterType().String()) } diff --git a/cmd/logs.go b/cmd/logs.go index cb7b51d8..f67795f7 100644 --- a/cmd/logs.go +++ b/cmd/logs.go @@ -2,11 +2,13 @@ package main import ( "bufio" + "context" "fmt" "io" "os" "os/exec" "strings" + "time" "github.com/fatih/color" "github.com/spf13/cobra" @@ -53,8 +55,13 @@ func runLogsOperator(cmd *cobra.Command, args []string) error { kubectlArgs = append(kubectlArgs, "-f") } - // Create kubectl command - kubectlCmd := exec.Command("kubectl", kubectlArgs...) + // Create context with timeout for initial connection + // Use a longer timeout (30s) to allow for cluster connection + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + // Create kubectl command with context + kubectlCmd := exec.CommandContext(ctx, "kubectl", kubectlArgs...) // Get stdout pipe for streaming stdout, err := kubectlCmd.StdoutPipe() @@ -75,6 +82,10 @@ func runLogsOperator(cmd *cobra.Command, args []string) error { // Wait for command to complete if err := kubectlCmd.Wait(); err != nil { + // Check if it was a timeout + if ctx.Err() == context.DeadlineExceeded { + return fmt.Errorf("timeout connecting to cluster - ensure your kubeconfig is correct and the cluster is reachable") + } // Don't return error if kubectl was interrupted (e.g., Ctrl+C) if _, ok := err.(*exec.ExitError); ok { return nil diff --git a/pkg/deployer/deploy_via_operator.go b/pkg/deployer/deploy_via_operator.go index 66b778c3..be8c574a 100644 --- a/pkg/deployer/deploy_via_operator.go +++ b/pkg/deployer/deploy_via_operator.go @@ -155,7 +155,7 @@ func (d *Deployer) prepareNamespace(ctx context.Context, namespace string) error return err } - if env.CurrentClusterType != env.InfraOpenShift4 { + if env.GetCurrentClusterType() != env.InfraOpenShift4 { if err := d.ensurePullSecretExists(ctx, namespace); err != nil { return fmt.Errorf("ensuring image pull secret exists: %w", err) } diff --git a/pkg/deployer/deployer.go b/pkg/deployer/deployer.go index 4e48d2b3..e43c773f 100644 --- a/pkg/deployer/deployer.go +++ b/pkg/deployer/deployer.go @@ -654,7 +654,7 @@ func (d *Deployer) PrintCentralDeploymentSummary() { // Deployment details log.Info(cyan.Sprint("│") + createRow("Component", component)) - log.Info(cyan.Sprint("│") + createRow("Cluster Type", env.CurrentClusterType.String())) + log.Info(cyan.Sprint("│") + createRow("Cluster Type", env.GetCurrentClusterType().String())) log.Info(cyan.Sprint("│") + createRow("Main Tag", mainImageTag)) log.Info(cyan.Sprint("│") + createRow("Kubernetes Context", kubeContext)) log.Info(cyan.Sprint("│") + createRow("Deployment Method", map[bool]string{true: "Helm", false: "Operator"}[helm])) @@ -821,7 +821,7 @@ func (d *Deployer) PrintSecuredClusterDeploymentSummary() { // Deployment details log.Info(cyan.Sprint("│") + createRow("Component", component)) - log.Info(cyan.Sprint("│") + createRow("Cluster Type", env.CurrentClusterType.String())) + log.Info(cyan.Sprint("│") + createRow("Cluster Type", env.GetCurrentClusterType().String())) log.Info(cyan.Sprint("│") + createRow("Main Tag", mainImageTag)) log.Info(cyan.Sprint("│") + createRow("Kubernetes Context", kubeContext)) log.Info(cyan.Sprint("│") + createRow("Deployment Method", map[bool]string{true: "Helm", false: "Operator"}[helm])) diff --git a/pkg/env/env.go b/pkg/env/env.go index ed0222a7..f182a4cd 100644 --- a/pkg/env/env.go +++ b/pkg/env/env.go @@ -29,13 +29,16 @@ const ( ) var ( - // CurrentClusterType holds the detected cluster type for the current kubectl context - // This is automatically populated during package initialization - CurrentClusterType ClusterType + // currentClusterType holds the detected cluster type for the current kubectl context + // This is lazily populated on first access via GetCurrentClusterType() + currentClusterType ClusterType - // CurrentContext holds the name of the current kubectl context - // This is automatically populated during package initialization - CurrentContext string + // currentContext holds the name of the current kubectl context + // This is lazily populated on first access via GetCurrentContext() + currentContext string + + // initialized tracks whether we've performed the lazy initialization + initialized bool ) func init() { @@ -43,10 +46,30 @@ func init() { if RunningInContainer { os.Setenv("KUBECONFIG", "/kubeconfig") } - kubeConfig := fetchKubeConfig() - CurrentContext = kubeConfig.CurrentContext - apiResources := fetchAPIResources() - CurrentClusterType = detectClusterType(kubeConfig, apiResources) +} + +// ensureInitialized performs lazy initialization of cluster information +// This avoids contacting the cluster on package import +func ensureInitialized() { + if !initialized { + kubeConfig := fetchKubeConfig() + currentContext = kubeConfig.CurrentContext + apiResources := fetchAPIResources() + currentClusterType = detectClusterType(kubeConfig, apiResources) + initialized = true + } +} + +// GetCurrentClusterType returns the current cluster type, initializing if needed +func GetCurrentClusterType() ClusterType { + ensureInitialized() + return currentClusterType +} + +// GetCurrentContext returns the current kubectl context, initializing if needed +func GetCurrentContext() string { + ensureInitialized() + return currentContext } // String returns the string representation of a ClusterType