From 844328f731fff32e5d058476c777550d99684d36 Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Wed, 13 May 2026 17:25:26 +0200 Subject: [PATCH 01/18] Remove unused code --- internal/deployer/deployer.go | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/internal/deployer/deployer.go b/internal/deployer/deployer.go index 2c602e2..9aec79d 100644 --- a/internal/deployer/deployer.go +++ b/internal/deployer/deployer.go @@ -45,8 +45,7 @@ type Deployer struct { dockerCreds *dockerauth.Credentials envrcFile string - kubeContext string - clusterResourceKinds map[string]struct{} + kubeContext string config Config @@ -264,40 +263,11 @@ func New(log *logger.Logger) (*Deployer, error) { d.kubeContext = env.GetCurrentContext() - if d.kubeContext != "" { - clusterResourceKinds, err := d.getClusterResourceKinds() - if err != nil { - return nil, fmt.Errorf("failed to get cluster resource kinds: %w", err) - } - d.clusterResourceKinds = clusterResourceKinds - } - log.Success("🚀 ACS Deployer initialized") return d, nil } -func (d *Deployer) getClusterResourceKinds() (map[string]struct{}, error) { - result, err := d.runKubectl(context.Background(), k8s.KubectlOptions{ - Args: []string{"api-resources", "-o", "name"}, - }) - if err != nil { - return nil, fmt.Errorf("failed to get cluster resource kinds: %w", err) - } - kinds := make(map[string]struct{}) - lines := strings.Split(strings.TrimSpace(result.Stdout), "\n") - for _, line := range lines { - fields := strings.SplitN(line, ".", 2) - if len(fields) == 0 || fields[0] == "" { - continue - } - kind := fields[0] - kinds[kind] = struct{}{} - } - - return kinds, nil -} - // Cleanup cleans up any temporary resources created by the deployer, such as temporary files. func (d *Deployer) Cleanup() { if d.tempDir != "" && d.envrcFile == "" { From 2e2b206c7f60eaf5bc412222e260ebd82bc6bada Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Wed, 13 May 2026 21:06:25 +0200 Subject: [PATCH 02/18] Make cluster type overwritable, e.g. for testing purposes --- cmd/deploy.go | 17 +++++--- internal/clusterdefaults/clusterdefaults.go | 6 +-- .../clusterdefaults/clusterdefaults_test.go | 3 +- internal/deployer/config.go | 7 +-- internal/deployer/deploy_via_operator.go | 4 +- internal/deployer/deployer.go | 6 +-- internal/deployer/operator.go | 7 ++- internal/types/cluster_type.go | 43 +++++++++++++++++++ 8 files changed, 71 insertions(+), 22 deletions(-) diff --git a/cmd/deploy.go b/cmd/deploy.go index 87d7caa..dc5c7c2 100644 --- a/cmd/deploy.go +++ b/cmd/deploy.go @@ -347,11 +347,15 @@ func runDeploy(cmd *cobra.Command, args []string) error { } func configureConfig(log *logger.Logger, components component.Component, deploySettings *deployer.Config) error { - clusterType := env.GetCurrentClusterType() - log.Dimf("Detected cluster type: %v", clusterType) - defaults, err := clusterdefaults.ApplyClusterDefaults(clusterType, deploySettings) + if deploySettings.Roxie.ClusterType == types.ClusterTypeUnknown { + clusterType := env.GetCurrentClusterType() + log.Dimf("Detected cluster type: %v", clusterType) + deploySettings.Roxie.ClusterType = clusterType + } + clusterType := deploySettings.Roxie.ClusterType + defaults, err := clusterdefaults.ApplyClusterDefaults(deploySettings) if err != nil { - return fmt.Errorf("applying defaults for cluster type %v: %w", clusterType, err) + return err } if verbose { log.Dimf("Applying the following defaults based on detected cluster type %v:", clusterType) @@ -409,6 +413,8 @@ func deployValidate(components component.Component, deploySettings *deployer.Con return errors.New("running without a controlling terminal requires --envrc to be set") } + clusterType := deploySettings.Roxie.ClusterType + if env.RunningInRoxieContainer { // For running containerized we have specific requirements. if deploySettings.Central.PortForwardingEnabled() { @@ -419,7 +425,7 @@ func deployValidate(components component.Component, deploySettings *deployer.Con } // On infra OpenShift we already get image pull secrets for Quay automatically. - if clusterType := env.GetCurrentClusterType(); clusterType != types.ClusterTypeInfraOpenShift4 { + if clusterType != types.ClusterTypeInfraOpenShift4 { if os.Getenv("REGISTRY_USERNAME") == "" || os.Getenv("REGISTRY_PASSWORD") == "" { return fmt.Errorf("containerized mode requires REGISTRY_USERNAME and REGISTRY_PASSWORD environment variables for clusters of type %s", clusterType) } @@ -437,7 +443,6 @@ func deployValidate(components component.Component, deploySettings *deployer.Con if deploySettings.Operator.DeployViaOlm { return errors.New("using Konflux images while deploying operator via OLM is not supported") } - clusterType := env.GetCurrentClusterType() if !clusterType.IsOpenShift() { return fmt.Errorf("--konflux flag is only supported on OpenShift 4 clusters (current cluster type: %s)", clusterType.String()) } diff --git a/internal/clusterdefaults/clusterdefaults.go b/internal/clusterdefaults/clusterdefaults.go index 588c8e9..739a981 100644 --- a/internal/clusterdefaults/clusterdefaults.go +++ b/internal/clusterdefaults/clusterdefaults.go @@ -13,12 +13,12 @@ import ( // provided deployer.Config. // Returns *just* the assembled defaults for the given cluster type for logging purposes. func ApplyClusterDefaults( - clusterType types.ClusterType, config *deployer.Config, ) (*deployer.Config, error) { if config == nil { panic("applying cluster defaults to nil config") } + clusterType := config.Roxie.ClusterType defaults := getDefaultsForClusterType(clusterType) if defaults == nil { return nil, nil @@ -27,11 +27,11 @@ func ApplyClusterDefaults( // Make a copy. defaultsCopy, err := defaults.DeepCopy() if err != nil { - return nil, fmt.Errorf("deep-copying cluster defaults: %w", err) + return nil, fmt.Errorf("deep-copying cluster defaults for cluster type %s: %w", clusterType, err) } if err := mergo.Merge(config, defaultsCopy, mergo.WithoutDereference); err != nil { - return nil, fmt.Errorf("merging-in cluster defaults: %w", err) + return nil, fmt.Errorf("merging-in cluster defaults for cluster type %s: %w", clusterType, err) } return defaultsCopy, nil diff --git a/internal/clusterdefaults/clusterdefaults_test.go b/internal/clusterdefaults/clusterdefaults_test.go index f0dab56..78b59e1 100644 --- a/internal/clusterdefaults/clusterdefaults_test.go +++ b/internal/clusterdefaults/clusterdefaults_test.go @@ -113,7 +113,8 @@ func TestClusterDefaults(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { config := tt.config - _, err := ApplyClusterDefaults(tt.clusterType, &config) + config.Roxie.ClusterType = tt.clusterType + _, err := ApplyClusterDefaults(&config) require.NoError(t, err) if tt.wantConfig.Central.Exposure == nil { diff --git a/internal/deployer/config.go b/internal/deployer/config.go index 907fc4b..b4fbeab 100644 --- a/internal/deployer/config.go +++ b/internal/deployer/config.go @@ -44,9 +44,10 @@ func (c *Config) DeepCopy() (*Config, error) { // RoxieConfig holds roxie-level settings such as version and feature flags. type RoxieConfig struct { - Version string `yaml:"version,omitempty"` - KonfluxImages bool `yaml:"konfluxImages,omitempty"` - FeatureFlags map[string]bool `yaml:"featureFlags,omitempty"` + Version string `yaml:"version,omitempty"` + KonfluxImages bool `yaml:"konfluxImages,omitempty"` + FeatureFlags map[string]bool `yaml:"featureFlags,omitempty"` + ClusterType types.ClusterType `yaml:"clusterType,omitempty"` } // NewRoxieConfig returns a RoxieConfig with initialized defaults. diff --git a/internal/deployer/deploy_via_operator.go b/internal/deployer/deploy_via_operator.go index f97a923..ed5bae2 100644 --- a/internal/deployer/deploy_via_operator.go +++ b/internal/deployer/deploy_via_operator.go @@ -119,7 +119,7 @@ func (d *Deployer) ensureOperatorDeployed(ctx context.Context) error { func (d *Deployer) deployCentralOperator(ctx context.Context) error { d.logger.Info("🚀 Deploying Central via Operator...") - needPullSecrets := env.GetCurrentClusterType() != types.ClusterTypeInfraOpenShift4 + needPullSecrets := d.config.Roxie.ClusterType != types.ClusterTypeInfraOpenShift4 if err := d.prepareNamespace(ctx, d.config.Central.Namespace, needPullSecrets); err != nil { return fmt.Errorf("failed to prepare namespace: %w", err) } @@ -655,7 +655,7 @@ func (d *Deployer) configureCentralEndpoint(ctx context.Context) error { func (d *Deployer) deploySecuredClusterOperator(ctx context.Context) error { d.logger.Info("🚀 Deploying SecuredCluster via Operator...") - needPullSecrets := env.GetCurrentClusterType() != types.ClusterTypeInfraOpenShift4 + needPullSecrets := d.config.Roxie.ClusterType != types.ClusterTypeInfraOpenShift4 if err := d.prepareNamespace(ctx, d.config.SecuredCluster.Namespace, needPullSecrets); err != nil { return fmt.Errorf("failed to prepare namespace: %w", err) } diff --git a/internal/deployer/deployer.go b/internal/deployer/deployer.go index 9aec79d..2bd76e1 100644 --- a/internal/deployer/deployer.go +++ b/internal/deployer/deployer.go @@ -298,7 +298,7 @@ func (d *Deployer) stopDetachedPortForward() { // Deploy deploys the specified components to the cluster. func (d *Deployer) Deploy(ctx context.Context, components component.Component) error { // Prepare and verify credentials early to fail fast. - if env.GetCurrentClusterType() != types.ClusterTypeInfraOpenShift4 { + if d.config.Roxie.ClusterType != types.ClusterTypeInfraOpenShift4 { if err := d.prepareCredentials(); err != nil { return fmt.Errorf("failed to prepare credentials: %w", err) } @@ -778,7 +778,7 @@ func (d *Deployer) PrintCentralDeploymentSummary() { // Deployment details log.Info(cyan.Sprint("│") + createRow("Component", component)) - log.Info(cyan.Sprint("│") + createRow("Cluster Type", env.GetCurrentClusterType().String())) + log.Info(cyan.Sprint("│") + createRow("Cluster Type", d.config.Roxie.ClusterType.String())) log.Info(cyan.Sprint("│") + createRow("Main Tag", mainImageTag)) log.Info(cyan.Sprint("│") + createRow("Kubernetes Context", kubeContext)) @@ -957,7 +957,7 @@ func (d *Deployer) PrintSecuredClusterDeploymentSummary() { // Deployment details log.Info(cyan.Sprint("│") + createRow("Component", component)) - log.Info(cyan.Sprint("│") + createRow("Cluster Type", env.GetCurrentClusterType().String())) + log.Info(cyan.Sprint("│") + createRow("Cluster Type", d.config.Roxie.ClusterType.String())) log.Info(cyan.Sprint("│") + createRow("Main Tag", mainImageTag)) log.Info(cyan.Sprint("│") + createRow("Kubernetes Context", kubeContext)) diff --git a/internal/deployer/operator.go b/internal/deployer/operator.go index 8f451c4..106476b 100644 --- a/internal/deployer/operator.go +++ b/internal/deployer/operator.go @@ -14,7 +14,6 @@ import ( "gopkg.in/yaml.v3" - "github.com/stackrox/roxie/internal/env" "github.com/stackrox/roxie/internal/k8s" "github.com/stackrox/roxie/internal/ocihelper" "github.com/stackrox/roxie/internal/types" @@ -202,7 +201,7 @@ func (d *Deployer) getOperatorBundleImage() string { // ensureKonfluxImageRewriting configures image rewriting for Konflux images func (d *Deployer) ensureKonfluxImageRewriting(ctx context.Context) error { - if !env.GetCurrentClusterType().IsOpenShift() { + if !d.config.Roxie.ClusterType.IsOpenShift() { return errors.New("image rewriting for Konflux is only supported on OpenShift4 clusters") } @@ -290,7 +289,7 @@ func (d *Deployer) applyImageContentSourcePolicy(ctx context.Context) error { // removeKonfluxImageRewriting removes the ImageContentSourcePolicy for Konflux images if it exists func (d *Deployer) removeKonfluxImageRewriting(ctx context.Context) error { - if !env.GetCurrentClusterType().IsOpenShift() { + if !d.config.Roxie.ClusterType.IsOpenShift() { return nil } @@ -320,7 +319,7 @@ func (d *Deployer) deployOperatorFromCSV(ctx context.Context, bundleDir string) } serviceAccountName := deploymentSpec["service_account"].(string) - d.useOperatorPullSecrets = d.config.Roxie.KonfluxImages && env.GetCurrentClusterType() != types.ClusterTypeInfraOpenShift4 + d.useOperatorPullSecrets = d.config.Roxie.KonfluxImages && d.config.Roxie.ClusterType != types.ClusterTypeInfraOpenShift4 d.logger.Info("📋 Operator deployment plan:") d.logger.Dim(fmt.Sprintf(" • Namespace: %s", operatorNamespace)) diff --git a/internal/types/cluster_type.go b/internal/types/cluster_type.go index 47146a2..2eb6344 100644 --- a/internal/types/cluster_type.go +++ b/internal/types/cluster_type.go @@ -1,5 +1,7 @@ package types +import "fmt" + // ClusterType represents different types of Kubernetes clusters type ClusterType int @@ -22,6 +24,27 @@ const ( ClusterTypeCRC ) +var ( + clusterTypeToIdentifier = map[ClusterType]string{ + ClusterTypeUnknown: "Unknown", + ClusterTypeInfraGKE: "InfraGKE", + ClusterTypeInfraOpenShift4: "InfraOpenShift4", + ClusterTypeOpenShift4: "OpenShift4", + ClusterTypeKind: "Kind", + ClusterTypeMinikube: "Minikube", + ClusterTypeK3s: "K3s", + ClusterTypeCRC: "CRC", + } + + identifierToClusterType = func() map[string]ClusterType { + m := make(map[string]ClusterType, len(clusterTypeToIdentifier)) + for k, v := range clusterTypeToIdentifier { + m[v] = k + } + return m + }() +) + func (ct ClusterType) IsOpenShift() bool { return ct == ClusterTypeInfraOpenShift4 || ct == ClusterTypeOpenShift4 } @@ -59,3 +82,23 @@ func AllClusterTypes() []ClusterType { ClusterTypeOpenShift4, } } + +func (ct ClusterType) MarshalYAML() (any, error) { + if id, ok := clusterTypeToIdentifier[ct]; ok { + return id, nil + } + return nil, fmt.Errorf("unknown cluster type: %d", ct) +} + +func (ct *ClusterType) UnmarshalYAML(unmarshal func(any) error) error { + var s string + if err := unmarshal(&s); err != nil { + return err + } + parsed, ok := identifierToClusterType[s] + if !ok { + return fmt.Errorf("unknown cluster type identifier: %q", s) + } + *ct = parsed + return nil +} From 0dadc8cc599750eecf4383abc4b1a707e001fd22 Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Wed, 13 May 2026 22:07:05 +0200 Subject: [PATCH 03/18] ClusterType Tests --- internal/types/cluster_type_test.go | 75 +++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 internal/types/cluster_type_test.go diff --git a/internal/types/cluster_type_test.go b/internal/types/cluster_type_test.go new file mode 100644 index 0000000..7758c1e --- /dev/null +++ b/internal/types/cluster_type_test.go @@ -0,0 +1,75 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" +) + +func TestClusterTypeMarshalYAML(t *testing.T) { + tests := []struct { + clusterType ClusterType + expected string + }{ + {ClusterTypeUnknown, "Unknown"}, + {ClusterTypeInfraGKE, "InfraGKE"}, + {ClusterTypeInfraOpenShift4, "InfraOpenShift4"}, + {ClusterTypeOpenShift4, "OpenShift4"}, + {ClusterTypeKind, "Kind"}, + {ClusterTypeMinikube, "Minikube"}, + {ClusterTypeK3s, "K3s"}, + {ClusterTypeCRC, "CRC"}, + } + for _, tt := range tests { + t.Run(tt.expected, func(t *testing.T) { + out, err := yaml.Marshal(tt.clusterType) + require.NoError(t, err) + assert.Equal(t, tt.expected+"\n", string(out)) + }) + } +} + +func TestClusterTypeUnmarshalYAML(t *testing.T) { + tests := []struct { + input string + expected ClusterType + }{ + {"InfraGKE", ClusterTypeInfraGKE}, + {"InfraOpenShift4", ClusterTypeInfraOpenShift4}, + {"OpenShift4", ClusterTypeOpenShift4}, + {"Kind", ClusterTypeKind}, + {"Minikube", ClusterTypeMinikube}, + {"K3s", ClusterTypeK3s}, + {"CRC", ClusterTypeCRC}, + {"Unknown", ClusterTypeUnknown}, + } + for _, tt := range tests { + t.Run(tt.input, func(t *testing.T) { + var ct ClusterType + err := yaml.Unmarshal([]byte(tt.input), &ct) + require.NoError(t, err) + assert.Equal(t, tt.expected, ct) + }) + } +} + +func TestClusterTypeUnmarshalYAML_Invalid(t *testing.T) { + var ct ClusterType + err := yaml.Unmarshal([]byte("bogus"), &ct) + assert.ErrorContains(t, err, "unknown cluster type identifier") +} + +func TestClusterTypeRoundTrip(t *testing.T) { + for _, ct := range AllClusterTypes() { + t.Run(ct.String(), func(t *testing.T) { + out, err := yaml.Marshal(ct) + require.NoError(t, err) + + var parsed ClusterType + require.NoError(t, yaml.Unmarshal(out, &parsed)) + assert.Equal(t, ct, parsed) + }) + } +} From a33d6b8ebbc50594c0a69055e62a8d620252ae9c Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Fri, 15 May 2026 10:17:47 +0200 Subject: [PATCH 04/18] Prettier cluster names Fix test --- internal/env/env_test.go | 2 +- internal/types/cluster_type.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/env/env_test.go b/internal/env/env_test.go index 8e0fed7..b9ccdb7 100644 --- a/internal/env/env_test.go +++ b/internal/env/env_test.go @@ -291,7 +291,7 @@ func TestClusterTypeString(t *testing.T) { { name: "types.ClusterTypeInfraGKE", clusterType: types.ClusterTypeInfraGKE, - want: "GKE", + want: "GKE (infra)", }, { name: "InfraOpenShift4", diff --git a/internal/types/cluster_type.go b/internal/types/cluster_type.go index 2eb6344..a93959e 100644 --- a/internal/types/cluster_type.go +++ b/internal/types/cluster_type.go @@ -53,7 +53,7 @@ func (ct ClusterType) IsOpenShift() bool { func (ct ClusterType) String() string { switch ct { case ClusterTypeInfraGKE: - return "GKE" + return "GKE (infra)" case ClusterTypeInfraOpenShift4: return "OpenShift4 (infra)" case ClusterTypeOpenShift4: @@ -61,11 +61,11 @@ func (ct ClusterType) String() string { case ClusterTypeKind: return "Kind" case ClusterTypeMinikube: - return "minikube" + return "Minikube" case ClusterTypeK3s: - return "k3s" + return "K3s" case ClusterTypeCRC: - return "crc" + return "CRC" default: return "Unknown" } From b2dd002bebe21bd43f4aea339f73a3a198927bb5 Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Mon, 18 May 2026 12:28:25 +0200 Subject: [PATCH 05/18] Make ClusterType a string wrapper --- internal/types/cluster_type.go | 60 +++++++++-------------------- internal/types/cluster_type_test.go | 2 - 2 files changed, 18 insertions(+), 44 deletions(-) diff --git a/internal/types/cluster_type.go b/internal/types/cluster_type.go index a93959e..e49ff45 100644 --- a/internal/types/cluster_type.go +++ b/internal/types/cluster_type.go @@ -3,46 +3,25 @@ package types import "fmt" // ClusterType represents different types of Kubernetes clusters -type ClusterType int +type ClusterType string const ( // ClusterTypeUnknown represents an unidentified cluster type - ClusterTypeUnknown ClusterType = iota + ClusterTypeUnknown ClusterType = "Unknown" // ClusterTypeInfraGKE represents a GKE cluster created via Infra. - ClusterTypeInfraGKE + ClusterTypeInfraGKE ClusterType = "InfraGKE" // ClusterTypeInfraOpenShift4 represents an OpenShift 4 cluster - ClusterTypeInfraOpenShift4 + ClusterTypeInfraOpenShift4 ClusterType = "InfraOpenShift4" // Generic OpenShift4 cluster (e.g. for prow CI) - ClusterTypeOpenShift4 + ClusterTypeOpenShift4 ClusterType = "OpenShift4" // ClusterTypeKind represents a Kind (Kubernetes in Docker) cluster - ClusterTypeKind + ClusterTypeKind ClusterType = "Kind" // ClusterTypeMinikube represents a Minikube cluster - ClusterTypeMinikube + ClusterTypeMinikube ClusterType = "Minikube" // ClusterTypeK3s represents a K3s cluster - ClusterTypeK3s + ClusterTypeK3s ClusterType = "K3s" // ClusterTypeCRC represents a CRC (CodeReady Containers) cluster - ClusterTypeCRC -) - -var ( - clusterTypeToIdentifier = map[ClusterType]string{ - ClusterTypeUnknown: "Unknown", - ClusterTypeInfraGKE: "InfraGKE", - ClusterTypeInfraOpenShift4: "InfraOpenShift4", - ClusterTypeOpenShift4: "OpenShift4", - ClusterTypeKind: "Kind", - ClusterTypeMinikube: "Minikube", - ClusterTypeK3s: "K3s", - ClusterTypeCRC: "CRC", - } - - identifierToClusterType = func() map[string]ClusterType { - m := make(map[string]ClusterType, len(clusterTypeToIdentifier)) - for k, v := range clusterTypeToIdentifier { - m[v] = k - } - return m - }() + ClusterTypeCRC ClusterType = "CRC" ) func (ct ClusterType) IsOpenShift() bool { @@ -83,22 +62,19 @@ func AllClusterTypes() []ClusterType { } } -func (ct ClusterType) MarshalYAML() (any, error) { - if id, ok := clusterTypeToIdentifier[ct]; ok { - return id, nil - } - return nil, fmt.Errorf("unknown cluster type: %d", ct) -} - func (ct *ClusterType) UnmarshalYAML(unmarshal func(any) error) error { var s string if err := unmarshal(&s); err != nil { return err } - parsed, ok := identifierToClusterType[s] - if !ok { - return fmt.Errorf("unknown cluster type identifier: %q", s) + + var sAsClusterType ClusterType = ClusterType(s) + + for _, valid := range AllClusterTypes() { + if sAsClusterType == valid { + *ct = valid + return nil + } } - *ct = parsed - return nil + return fmt.Errorf("unknown cluster type identifier: %q", s) } diff --git a/internal/types/cluster_type_test.go b/internal/types/cluster_type_test.go index 7758c1e..127d78a 100644 --- a/internal/types/cluster_type_test.go +++ b/internal/types/cluster_type_test.go @@ -13,7 +13,6 @@ func TestClusterTypeMarshalYAML(t *testing.T) { clusterType ClusterType expected string }{ - {ClusterTypeUnknown, "Unknown"}, {ClusterTypeInfraGKE, "InfraGKE"}, {ClusterTypeInfraOpenShift4, "InfraOpenShift4"}, {ClusterTypeOpenShift4, "OpenShift4"}, @@ -43,7 +42,6 @@ func TestClusterTypeUnmarshalYAML(t *testing.T) { {"Minikube", ClusterTypeMinikube}, {"K3s", ClusterTypeK3s}, {"CRC", ClusterTypeCRC}, - {"Unknown", ClusterTypeUnknown}, } for _, tt := range tests { t.Run(tt.input, func(t *testing.T) { From 015dc4a9627787c549d68ad0af463cd0abfc0e36 Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Mon, 18 May 2026 12:34:31 +0200 Subject: [PATCH 06/18] linter --- internal/types/cluster_type.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/types/cluster_type.go b/internal/types/cluster_type.go index e49ff45..1386673 100644 --- a/internal/types/cluster_type.go +++ b/internal/types/cluster_type.go @@ -68,7 +68,7 @@ func (ct *ClusterType) UnmarshalYAML(unmarshal func(any) error) error { return err } - var sAsClusterType ClusterType = ClusterType(s) + var sAsClusterType = ClusterType(s) for _, valid := range AllClusterTypes() { if sAsClusterType == valid { From 01f62c80af85fa5dd366db3e2d629236b18c432a Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Wed, 13 May 2026 21:06:25 +0200 Subject: [PATCH 07/18] Make cluster type overwritable, e.g. for testing purposes --- cmd/deploy.go | 17 +++++--- internal/clusterdefaults/clusterdefaults.go | 6 +-- .../clusterdefaults/clusterdefaults_test.go | 3 +- internal/deployer/config.go | 7 +-- internal/deployer/deploy_via_operator.go | 4 +- internal/deployer/deployer.go | 6 +-- internal/deployer/operator.go | 7 ++- internal/types/cluster_type.go | 43 +++++++++++++++++++ 8 files changed, 71 insertions(+), 22 deletions(-) diff --git a/cmd/deploy.go b/cmd/deploy.go index 87d7caa..dc5c7c2 100644 --- a/cmd/deploy.go +++ b/cmd/deploy.go @@ -347,11 +347,15 @@ func runDeploy(cmd *cobra.Command, args []string) error { } func configureConfig(log *logger.Logger, components component.Component, deploySettings *deployer.Config) error { - clusterType := env.GetCurrentClusterType() - log.Dimf("Detected cluster type: %v", clusterType) - defaults, err := clusterdefaults.ApplyClusterDefaults(clusterType, deploySettings) + if deploySettings.Roxie.ClusterType == types.ClusterTypeUnknown { + clusterType := env.GetCurrentClusterType() + log.Dimf("Detected cluster type: %v", clusterType) + deploySettings.Roxie.ClusterType = clusterType + } + clusterType := deploySettings.Roxie.ClusterType + defaults, err := clusterdefaults.ApplyClusterDefaults(deploySettings) if err != nil { - return fmt.Errorf("applying defaults for cluster type %v: %w", clusterType, err) + return err } if verbose { log.Dimf("Applying the following defaults based on detected cluster type %v:", clusterType) @@ -409,6 +413,8 @@ func deployValidate(components component.Component, deploySettings *deployer.Con return errors.New("running without a controlling terminal requires --envrc to be set") } + clusterType := deploySettings.Roxie.ClusterType + if env.RunningInRoxieContainer { // For running containerized we have specific requirements. if deploySettings.Central.PortForwardingEnabled() { @@ -419,7 +425,7 @@ func deployValidate(components component.Component, deploySettings *deployer.Con } // On infra OpenShift we already get image pull secrets for Quay automatically. - if clusterType := env.GetCurrentClusterType(); clusterType != types.ClusterTypeInfraOpenShift4 { + if clusterType != types.ClusterTypeInfraOpenShift4 { if os.Getenv("REGISTRY_USERNAME") == "" || os.Getenv("REGISTRY_PASSWORD") == "" { return fmt.Errorf("containerized mode requires REGISTRY_USERNAME and REGISTRY_PASSWORD environment variables for clusters of type %s", clusterType) } @@ -437,7 +443,6 @@ func deployValidate(components component.Component, deploySettings *deployer.Con if deploySettings.Operator.DeployViaOlm { return errors.New("using Konflux images while deploying operator via OLM is not supported") } - clusterType := env.GetCurrentClusterType() if !clusterType.IsOpenShift() { return fmt.Errorf("--konflux flag is only supported on OpenShift 4 clusters (current cluster type: %s)", clusterType.String()) } diff --git a/internal/clusterdefaults/clusterdefaults.go b/internal/clusterdefaults/clusterdefaults.go index 588c8e9..739a981 100644 --- a/internal/clusterdefaults/clusterdefaults.go +++ b/internal/clusterdefaults/clusterdefaults.go @@ -13,12 +13,12 @@ import ( // provided deployer.Config. // Returns *just* the assembled defaults for the given cluster type for logging purposes. func ApplyClusterDefaults( - clusterType types.ClusterType, config *deployer.Config, ) (*deployer.Config, error) { if config == nil { panic("applying cluster defaults to nil config") } + clusterType := config.Roxie.ClusterType defaults := getDefaultsForClusterType(clusterType) if defaults == nil { return nil, nil @@ -27,11 +27,11 @@ func ApplyClusterDefaults( // Make a copy. defaultsCopy, err := defaults.DeepCopy() if err != nil { - return nil, fmt.Errorf("deep-copying cluster defaults: %w", err) + return nil, fmt.Errorf("deep-copying cluster defaults for cluster type %s: %w", clusterType, err) } if err := mergo.Merge(config, defaultsCopy, mergo.WithoutDereference); err != nil { - return nil, fmt.Errorf("merging-in cluster defaults: %w", err) + return nil, fmt.Errorf("merging-in cluster defaults for cluster type %s: %w", clusterType, err) } return defaultsCopy, nil diff --git a/internal/clusterdefaults/clusterdefaults_test.go b/internal/clusterdefaults/clusterdefaults_test.go index f0dab56..78b59e1 100644 --- a/internal/clusterdefaults/clusterdefaults_test.go +++ b/internal/clusterdefaults/clusterdefaults_test.go @@ -113,7 +113,8 @@ func TestClusterDefaults(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { config := tt.config - _, err := ApplyClusterDefaults(tt.clusterType, &config) + config.Roxie.ClusterType = tt.clusterType + _, err := ApplyClusterDefaults(&config) require.NoError(t, err) if tt.wantConfig.Central.Exposure == nil { diff --git a/internal/deployer/config.go b/internal/deployer/config.go index 907fc4b..b4fbeab 100644 --- a/internal/deployer/config.go +++ b/internal/deployer/config.go @@ -44,9 +44,10 @@ func (c *Config) DeepCopy() (*Config, error) { // RoxieConfig holds roxie-level settings such as version and feature flags. type RoxieConfig struct { - Version string `yaml:"version,omitempty"` - KonfluxImages bool `yaml:"konfluxImages,omitempty"` - FeatureFlags map[string]bool `yaml:"featureFlags,omitempty"` + Version string `yaml:"version,omitempty"` + KonfluxImages bool `yaml:"konfluxImages,omitempty"` + FeatureFlags map[string]bool `yaml:"featureFlags,omitempty"` + ClusterType types.ClusterType `yaml:"clusterType,omitempty"` } // NewRoxieConfig returns a RoxieConfig with initialized defaults. diff --git a/internal/deployer/deploy_via_operator.go b/internal/deployer/deploy_via_operator.go index f97a923..ed5bae2 100644 --- a/internal/deployer/deploy_via_operator.go +++ b/internal/deployer/deploy_via_operator.go @@ -119,7 +119,7 @@ func (d *Deployer) ensureOperatorDeployed(ctx context.Context) error { func (d *Deployer) deployCentralOperator(ctx context.Context) error { d.logger.Info("🚀 Deploying Central via Operator...") - needPullSecrets := env.GetCurrentClusterType() != types.ClusterTypeInfraOpenShift4 + needPullSecrets := d.config.Roxie.ClusterType != types.ClusterTypeInfraOpenShift4 if err := d.prepareNamespace(ctx, d.config.Central.Namespace, needPullSecrets); err != nil { return fmt.Errorf("failed to prepare namespace: %w", err) } @@ -655,7 +655,7 @@ func (d *Deployer) configureCentralEndpoint(ctx context.Context) error { func (d *Deployer) deploySecuredClusterOperator(ctx context.Context) error { d.logger.Info("🚀 Deploying SecuredCluster via Operator...") - needPullSecrets := env.GetCurrentClusterType() != types.ClusterTypeInfraOpenShift4 + needPullSecrets := d.config.Roxie.ClusterType != types.ClusterTypeInfraOpenShift4 if err := d.prepareNamespace(ctx, d.config.SecuredCluster.Namespace, needPullSecrets); err != nil { return fmt.Errorf("failed to prepare namespace: %w", err) } diff --git a/internal/deployer/deployer.go b/internal/deployer/deployer.go index 9aec79d..2bd76e1 100644 --- a/internal/deployer/deployer.go +++ b/internal/deployer/deployer.go @@ -298,7 +298,7 @@ func (d *Deployer) stopDetachedPortForward() { // Deploy deploys the specified components to the cluster. func (d *Deployer) Deploy(ctx context.Context, components component.Component) error { // Prepare and verify credentials early to fail fast. - if env.GetCurrentClusterType() != types.ClusterTypeInfraOpenShift4 { + if d.config.Roxie.ClusterType != types.ClusterTypeInfraOpenShift4 { if err := d.prepareCredentials(); err != nil { return fmt.Errorf("failed to prepare credentials: %w", err) } @@ -778,7 +778,7 @@ func (d *Deployer) PrintCentralDeploymentSummary() { // Deployment details log.Info(cyan.Sprint("│") + createRow("Component", component)) - log.Info(cyan.Sprint("│") + createRow("Cluster Type", env.GetCurrentClusterType().String())) + log.Info(cyan.Sprint("│") + createRow("Cluster Type", d.config.Roxie.ClusterType.String())) log.Info(cyan.Sprint("│") + createRow("Main Tag", mainImageTag)) log.Info(cyan.Sprint("│") + createRow("Kubernetes Context", kubeContext)) @@ -957,7 +957,7 @@ func (d *Deployer) PrintSecuredClusterDeploymentSummary() { // Deployment details log.Info(cyan.Sprint("│") + createRow("Component", component)) - log.Info(cyan.Sprint("│") + createRow("Cluster Type", env.GetCurrentClusterType().String())) + log.Info(cyan.Sprint("│") + createRow("Cluster Type", d.config.Roxie.ClusterType.String())) log.Info(cyan.Sprint("│") + createRow("Main Tag", mainImageTag)) log.Info(cyan.Sprint("│") + createRow("Kubernetes Context", kubeContext)) diff --git a/internal/deployer/operator.go b/internal/deployer/operator.go index 8f451c4..106476b 100644 --- a/internal/deployer/operator.go +++ b/internal/deployer/operator.go @@ -14,7 +14,6 @@ import ( "gopkg.in/yaml.v3" - "github.com/stackrox/roxie/internal/env" "github.com/stackrox/roxie/internal/k8s" "github.com/stackrox/roxie/internal/ocihelper" "github.com/stackrox/roxie/internal/types" @@ -202,7 +201,7 @@ func (d *Deployer) getOperatorBundleImage() string { // ensureKonfluxImageRewriting configures image rewriting for Konflux images func (d *Deployer) ensureKonfluxImageRewriting(ctx context.Context) error { - if !env.GetCurrentClusterType().IsOpenShift() { + if !d.config.Roxie.ClusterType.IsOpenShift() { return errors.New("image rewriting for Konflux is only supported on OpenShift4 clusters") } @@ -290,7 +289,7 @@ func (d *Deployer) applyImageContentSourcePolicy(ctx context.Context) error { // removeKonfluxImageRewriting removes the ImageContentSourcePolicy for Konflux images if it exists func (d *Deployer) removeKonfluxImageRewriting(ctx context.Context) error { - if !env.GetCurrentClusterType().IsOpenShift() { + if !d.config.Roxie.ClusterType.IsOpenShift() { return nil } @@ -320,7 +319,7 @@ func (d *Deployer) deployOperatorFromCSV(ctx context.Context, bundleDir string) } serviceAccountName := deploymentSpec["service_account"].(string) - d.useOperatorPullSecrets = d.config.Roxie.KonfluxImages && env.GetCurrentClusterType() != types.ClusterTypeInfraOpenShift4 + d.useOperatorPullSecrets = d.config.Roxie.KonfluxImages && d.config.Roxie.ClusterType != types.ClusterTypeInfraOpenShift4 d.logger.Info("📋 Operator deployment plan:") d.logger.Dim(fmt.Sprintf(" • Namespace: %s", operatorNamespace)) diff --git a/internal/types/cluster_type.go b/internal/types/cluster_type.go index 47146a2..2eb6344 100644 --- a/internal/types/cluster_type.go +++ b/internal/types/cluster_type.go @@ -1,5 +1,7 @@ package types +import "fmt" + // ClusterType represents different types of Kubernetes clusters type ClusterType int @@ -22,6 +24,27 @@ const ( ClusterTypeCRC ) +var ( + clusterTypeToIdentifier = map[ClusterType]string{ + ClusterTypeUnknown: "Unknown", + ClusterTypeInfraGKE: "InfraGKE", + ClusterTypeInfraOpenShift4: "InfraOpenShift4", + ClusterTypeOpenShift4: "OpenShift4", + ClusterTypeKind: "Kind", + ClusterTypeMinikube: "Minikube", + ClusterTypeK3s: "K3s", + ClusterTypeCRC: "CRC", + } + + identifierToClusterType = func() map[string]ClusterType { + m := make(map[string]ClusterType, len(clusterTypeToIdentifier)) + for k, v := range clusterTypeToIdentifier { + m[v] = k + } + return m + }() +) + func (ct ClusterType) IsOpenShift() bool { return ct == ClusterTypeInfraOpenShift4 || ct == ClusterTypeOpenShift4 } @@ -59,3 +82,23 @@ func AllClusterTypes() []ClusterType { ClusterTypeOpenShift4, } } + +func (ct ClusterType) MarshalYAML() (any, error) { + if id, ok := clusterTypeToIdentifier[ct]; ok { + return id, nil + } + return nil, fmt.Errorf("unknown cluster type: %d", ct) +} + +func (ct *ClusterType) UnmarshalYAML(unmarshal func(any) error) error { + var s string + if err := unmarshal(&s); err != nil { + return err + } + parsed, ok := identifierToClusterType[s] + if !ok { + return fmt.Errorf("unknown cluster type identifier: %q", s) + } + *ct = parsed + return nil +} From a70bc7a29020875999e6147c6f14861335f6ffd2 Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Wed, 13 May 2026 22:07:05 +0200 Subject: [PATCH 08/18] ClusterType Tests --- internal/types/cluster_type_test.go | 75 +++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 internal/types/cluster_type_test.go diff --git a/internal/types/cluster_type_test.go b/internal/types/cluster_type_test.go new file mode 100644 index 0000000..7758c1e --- /dev/null +++ b/internal/types/cluster_type_test.go @@ -0,0 +1,75 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" +) + +func TestClusterTypeMarshalYAML(t *testing.T) { + tests := []struct { + clusterType ClusterType + expected string + }{ + {ClusterTypeUnknown, "Unknown"}, + {ClusterTypeInfraGKE, "InfraGKE"}, + {ClusterTypeInfraOpenShift4, "InfraOpenShift4"}, + {ClusterTypeOpenShift4, "OpenShift4"}, + {ClusterTypeKind, "Kind"}, + {ClusterTypeMinikube, "Minikube"}, + {ClusterTypeK3s, "K3s"}, + {ClusterTypeCRC, "CRC"}, + } + for _, tt := range tests { + t.Run(tt.expected, func(t *testing.T) { + out, err := yaml.Marshal(tt.clusterType) + require.NoError(t, err) + assert.Equal(t, tt.expected+"\n", string(out)) + }) + } +} + +func TestClusterTypeUnmarshalYAML(t *testing.T) { + tests := []struct { + input string + expected ClusterType + }{ + {"InfraGKE", ClusterTypeInfraGKE}, + {"InfraOpenShift4", ClusterTypeInfraOpenShift4}, + {"OpenShift4", ClusterTypeOpenShift4}, + {"Kind", ClusterTypeKind}, + {"Minikube", ClusterTypeMinikube}, + {"K3s", ClusterTypeK3s}, + {"CRC", ClusterTypeCRC}, + {"Unknown", ClusterTypeUnknown}, + } + for _, tt := range tests { + t.Run(tt.input, func(t *testing.T) { + var ct ClusterType + err := yaml.Unmarshal([]byte(tt.input), &ct) + require.NoError(t, err) + assert.Equal(t, tt.expected, ct) + }) + } +} + +func TestClusterTypeUnmarshalYAML_Invalid(t *testing.T) { + var ct ClusterType + err := yaml.Unmarshal([]byte("bogus"), &ct) + assert.ErrorContains(t, err, "unknown cluster type identifier") +} + +func TestClusterTypeRoundTrip(t *testing.T) { + for _, ct := range AllClusterTypes() { + t.Run(ct.String(), func(t *testing.T) { + out, err := yaml.Marshal(ct) + require.NoError(t, err) + + var parsed ClusterType + require.NoError(t, yaml.Unmarshal(out, &parsed)) + assert.Equal(t, ct, parsed) + }) + } +} From 4c323297499dc105752ade708d3d29f1fe70e898 Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Fri, 15 May 2026 10:17:47 +0200 Subject: [PATCH 09/18] Prettier cluster names Fix test --- internal/env/env_test.go | 2 +- internal/types/cluster_type.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/env/env_test.go b/internal/env/env_test.go index 8e0fed7..b9ccdb7 100644 --- a/internal/env/env_test.go +++ b/internal/env/env_test.go @@ -291,7 +291,7 @@ func TestClusterTypeString(t *testing.T) { { name: "types.ClusterTypeInfraGKE", clusterType: types.ClusterTypeInfraGKE, - want: "GKE", + want: "GKE (infra)", }, { name: "InfraOpenShift4", diff --git a/internal/types/cluster_type.go b/internal/types/cluster_type.go index 2eb6344..a93959e 100644 --- a/internal/types/cluster_type.go +++ b/internal/types/cluster_type.go @@ -53,7 +53,7 @@ func (ct ClusterType) IsOpenShift() bool { func (ct ClusterType) String() string { switch ct { case ClusterTypeInfraGKE: - return "GKE" + return "GKE (infra)" case ClusterTypeInfraOpenShift4: return "OpenShift4 (infra)" case ClusterTypeOpenShift4: @@ -61,11 +61,11 @@ func (ct ClusterType) String() string { case ClusterTypeKind: return "Kind" case ClusterTypeMinikube: - return "minikube" + return "Minikube" case ClusterTypeK3s: - return "k3s" + return "K3s" case ClusterTypeCRC: - return "crc" + return "CRC" default: return "Unknown" } From 1171b6e44850a4e38a2ec8daf3ea06d34342d663 Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Mon, 18 May 2026 12:28:25 +0200 Subject: [PATCH 10/18] Make ClusterType a string wrapper --- internal/types/cluster_type.go | 60 +++++++++-------------------- internal/types/cluster_type_test.go | 2 - 2 files changed, 18 insertions(+), 44 deletions(-) diff --git a/internal/types/cluster_type.go b/internal/types/cluster_type.go index a93959e..e49ff45 100644 --- a/internal/types/cluster_type.go +++ b/internal/types/cluster_type.go @@ -3,46 +3,25 @@ package types import "fmt" // ClusterType represents different types of Kubernetes clusters -type ClusterType int +type ClusterType string const ( // ClusterTypeUnknown represents an unidentified cluster type - ClusterTypeUnknown ClusterType = iota + ClusterTypeUnknown ClusterType = "Unknown" // ClusterTypeInfraGKE represents a GKE cluster created via Infra. - ClusterTypeInfraGKE + ClusterTypeInfraGKE ClusterType = "InfraGKE" // ClusterTypeInfraOpenShift4 represents an OpenShift 4 cluster - ClusterTypeInfraOpenShift4 + ClusterTypeInfraOpenShift4 ClusterType = "InfraOpenShift4" // Generic OpenShift4 cluster (e.g. for prow CI) - ClusterTypeOpenShift4 + ClusterTypeOpenShift4 ClusterType = "OpenShift4" // ClusterTypeKind represents a Kind (Kubernetes in Docker) cluster - ClusterTypeKind + ClusterTypeKind ClusterType = "Kind" // ClusterTypeMinikube represents a Minikube cluster - ClusterTypeMinikube + ClusterTypeMinikube ClusterType = "Minikube" // ClusterTypeK3s represents a K3s cluster - ClusterTypeK3s + ClusterTypeK3s ClusterType = "K3s" // ClusterTypeCRC represents a CRC (CodeReady Containers) cluster - ClusterTypeCRC -) - -var ( - clusterTypeToIdentifier = map[ClusterType]string{ - ClusterTypeUnknown: "Unknown", - ClusterTypeInfraGKE: "InfraGKE", - ClusterTypeInfraOpenShift4: "InfraOpenShift4", - ClusterTypeOpenShift4: "OpenShift4", - ClusterTypeKind: "Kind", - ClusterTypeMinikube: "Minikube", - ClusterTypeK3s: "K3s", - ClusterTypeCRC: "CRC", - } - - identifierToClusterType = func() map[string]ClusterType { - m := make(map[string]ClusterType, len(clusterTypeToIdentifier)) - for k, v := range clusterTypeToIdentifier { - m[v] = k - } - return m - }() + ClusterTypeCRC ClusterType = "CRC" ) func (ct ClusterType) IsOpenShift() bool { @@ -83,22 +62,19 @@ func AllClusterTypes() []ClusterType { } } -func (ct ClusterType) MarshalYAML() (any, error) { - if id, ok := clusterTypeToIdentifier[ct]; ok { - return id, nil - } - return nil, fmt.Errorf("unknown cluster type: %d", ct) -} - func (ct *ClusterType) UnmarshalYAML(unmarshal func(any) error) error { var s string if err := unmarshal(&s); err != nil { return err } - parsed, ok := identifierToClusterType[s] - if !ok { - return fmt.Errorf("unknown cluster type identifier: %q", s) + + var sAsClusterType ClusterType = ClusterType(s) + + for _, valid := range AllClusterTypes() { + if sAsClusterType == valid { + *ct = valid + return nil + } } - *ct = parsed - return nil + return fmt.Errorf("unknown cluster type identifier: %q", s) } diff --git a/internal/types/cluster_type_test.go b/internal/types/cluster_type_test.go index 7758c1e..127d78a 100644 --- a/internal/types/cluster_type_test.go +++ b/internal/types/cluster_type_test.go @@ -13,7 +13,6 @@ func TestClusterTypeMarshalYAML(t *testing.T) { clusterType ClusterType expected string }{ - {ClusterTypeUnknown, "Unknown"}, {ClusterTypeInfraGKE, "InfraGKE"}, {ClusterTypeInfraOpenShift4, "InfraOpenShift4"}, {ClusterTypeOpenShift4, "OpenShift4"}, @@ -43,7 +42,6 @@ func TestClusterTypeUnmarshalYAML(t *testing.T) { {"Minikube", ClusterTypeMinikube}, {"K3s", ClusterTypeK3s}, {"CRC", ClusterTypeCRC}, - {"Unknown", ClusterTypeUnknown}, } for _, tt := range tests { t.Run(tt.input, func(t *testing.T) { From f9ce245f10de272ff453d9884c1bdb60faf6d97e Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Mon, 18 May 2026 12:34:31 +0200 Subject: [PATCH 11/18] linter --- internal/types/cluster_type.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/types/cluster_type.go b/internal/types/cluster_type.go index e49ff45..1386673 100644 --- a/internal/types/cluster_type.go +++ b/internal/types/cluster_type.go @@ -68,7 +68,7 @@ func (ct *ClusterType) UnmarshalYAML(unmarshal func(any) error) error { return err } - var sAsClusterType ClusterType = ClusterType(s) + var sAsClusterType = ClusterType(s) for _, valid := range AllClusterTypes() { if sAsClusterType == valid { From 7e75a71576363bd23c88d650a86a9098ce7db6f3 Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier <111092021+mclasmeier@users.noreply.github.com> Date: Tue, 19 May 2026 09:20:41 +0200 Subject: [PATCH 12/18] Update cmd/deploy.go Co-authored-by: Marcin Owsiany --- cmd/deploy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/deploy.go b/cmd/deploy.go index dc5c7c2..4a6b28c 100644 --- a/cmd/deploy.go +++ b/cmd/deploy.go @@ -358,7 +358,7 @@ func configureConfig(log *logger.Logger, components component.Component, deployS return err } if verbose { - log.Dimf("Applying the following defaults based on detected cluster type %v:", clusterType) + log.Dimf("Applying the following defaults based on cluster type %v:", clusterType) helpers.LogMultilineYaml(log, defaults) } From 74164def1065399e906b5524bec33f2f9094e556 Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Tue, 19 May 2026 21:27:23 +0200 Subject: [PATCH 13/18] Rename function: GetCurrentClusterType -> GetAutoDetectedClusterType --- cmd/deploy.go | 2 +- cmd/env.go | 2 +- internal/env/env.go | 6 +++--- internal/env/env_integration_test.go | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/deploy.go b/cmd/deploy.go index 4a6b28c..1b09733 100644 --- a/cmd/deploy.go +++ b/cmd/deploy.go @@ -348,7 +348,7 @@ func runDeploy(cmd *cobra.Command, args []string) error { func configureConfig(log *logger.Logger, components component.Component, deploySettings *deployer.Config) error { if deploySettings.Roxie.ClusterType == types.ClusterTypeUnknown { - clusterType := env.GetCurrentClusterType() + clusterType := env.GetAutoDetectedClusterType() log.Dimf("Detected cluster type: %v", clusterType) deploySettings.Roxie.ClusterType = clusterType } diff --git a/cmd/env.go b/cmd/env.go index 6ad05bb..0e59264 100644 --- a/cmd/env.go +++ b/cmd/env.go @@ -32,7 +32,7 @@ func runEnv(cmd *cobra.Command, args []string) error { fmt.Printf("Kube config: %s\n", os.Getenv("KUBECONFIG")) fmt.Printf("Running in roxie container: %v\n", env.RunningInRoxieContainer) fmt.Printf("Current Context: %s\n", env.GetCurrentContext()) - fmt.Printf("Cluster Type: %s\n", env.GetCurrentClusterType().String()) + fmt.Printf("Cluster Type: %s\n", env.GetAutoDetectedClusterType().String()) return nil } diff --git a/internal/env/env.go b/internal/env/env.go index 9d85814..9b4c93c 100644 --- a/internal/env/env.go +++ b/internal/env/env.go @@ -26,7 +26,7 @@ var ( var ( // currentClusterType holds the detected cluster type for the current kubectl context - // This is lazily populated on first access via GetCurrentClusterType() + // This is lazily populated on first access via GetAutoDetectedClusterType() currentClusterType types.ClusterType // currentContext holds the name of the current kubectl context @@ -78,8 +78,8 @@ func ensureInitialized(log *logger.Logger) error { return nil } -// GetCurrentClusterType returns the current cluster type, initializing if needed -func GetCurrentClusterType() types.ClusterType { +// GetAutoDetectedClusterType returns the current cluster type, initializing if needed +func GetAutoDetectedClusterType() types.ClusterType { return currentClusterType } diff --git a/internal/env/env_integration_test.go b/internal/env/env_integration_test.go index 6a5677b..8a7ed5d 100644 --- a/internal/env/env_integration_test.go +++ b/internal/env/env_integration_test.go @@ -16,7 +16,7 @@ func TestDetectClusterType_Integration(t *testing.T) { // This test uses the current kubectl context // The result will depend on the active cluster - clusterType := GetCurrentClusterType() + clusterType := GetAutoDetectedClusterType() t.Logf("Detected cluster type: %s", clusterType) From 8307b550410c403ced84cbef0c7a7bdb779e05aa Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier <111092021+mclasmeier@users.noreply.github.com> Date: Tue, 19 May 2026 21:31:53 +0200 Subject: [PATCH 14/18] Update cmd/deploy.go Co-authored-by: Marcin Owsiany --- cmd/deploy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/deploy.go b/cmd/deploy.go index 4a6b28c..0ad2972 100644 --- a/cmd/deploy.go +++ b/cmd/deploy.go @@ -444,7 +444,7 @@ func deployValidate(components component.Component, deploySettings *deployer.Con return errors.New("using Konflux images while deploying operator via OLM is not supported") } if !clusterType.IsOpenShift() { - return fmt.Errorf("--konflux flag is only supported on OpenShift 4 clusters (current cluster type: %s)", clusterType.String()) + return fmt.Errorf("--konflux flag is only supported on OpenShift 4 clusters (current cluster type: %s)", clusterType) } } From 87ba2cdf8a77b5372c9c38607fc8ca04cb18d897 Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Tue, 19 May 2026 21:37:46 +0200 Subject: [PATCH 15/18] New ClusterType method: NeedsPullSecrets --- cmd/deploy.go | 2 +- internal/deployer/deploy_via_operator.go | 4 ++-- internal/deployer/deployer.go | 2 +- internal/deployer/operator.go | 3 +-- internal/types/cluster_type.go | 4 ++++ 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/cmd/deploy.go b/cmd/deploy.go index 1b09733..4254897 100644 --- a/cmd/deploy.go +++ b/cmd/deploy.go @@ -425,7 +425,7 @@ func deployValidate(components component.Component, deploySettings *deployer.Con } // On infra OpenShift we already get image pull secrets for Quay automatically. - if clusterType != types.ClusterTypeInfraOpenShift4 { + if clusterType.NeedsPullSecrets() { if os.Getenv("REGISTRY_USERNAME") == "" || os.Getenv("REGISTRY_PASSWORD") == "" { return fmt.Errorf("containerized mode requires REGISTRY_USERNAME and REGISTRY_PASSWORD environment variables for clusters of type %s", clusterType) } diff --git a/internal/deployer/deploy_via_operator.go b/internal/deployer/deploy_via_operator.go index ed5bae2..44b0a47 100644 --- a/internal/deployer/deploy_via_operator.go +++ b/internal/deployer/deploy_via_operator.go @@ -119,7 +119,7 @@ func (d *Deployer) ensureOperatorDeployed(ctx context.Context) error { func (d *Deployer) deployCentralOperator(ctx context.Context) error { d.logger.Info("🚀 Deploying Central via Operator...") - needPullSecrets := d.config.Roxie.ClusterType != types.ClusterTypeInfraOpenShift4 + needPullSecrets := d.config.Roxie.ClusterType.NeedsPullSecrets() if err := d.prepareNamespace(ctx, d.config.Central.Namespace, needPullSecrets); err != nil { return fmt.Errorf("failed to prepare namespace: %w", err) } @@ -655,7 +655,7 @@ func (d *Deployer) configureCentralEndpoint(ctx context.Context) error { func (d *Deployer) deploySecuredClusterOperator(ctx context.Context) error { d.logger.Info("🚀 Deploying SecuredCluster via Operator...") - needPullSecrets := d.config.Roxie.ClusterType != types.ClusterTypeInfraOpenShift4 + needPullSecrets := d.config.Roxie.ClusterType.NeedsPullSecrets() if err := d.prepareNamespace(ctx, d.config.SecuredCluster.Namespace, needPullSecrets); err != nil { return fmt.Errorf("failed to prepare namespace: %w", err) } diff --git a/internal/deployer/deployer.go b/internal/deployer/deployer.go index 2bd76e1..44565b8 100644 --- a/internal/deployer/deployer.go +++ b/internal/deployer/deployer.go @@ -298,7 +298,7 @@ func (d *Deployer) stopDetachedPortForward() { // Deploy deploys the specified components to the cluster. func (d *Deployer) Deploy(ctx context.Context, components component.Component) error { // Prepare and verify credentials early to fail fast. - if d.config.Roxie.ClusterType != types.ClusterTypeInfraOpenShift4 { + if d.config.Roxie.ClusterType.NeedsPullSecrets() { if err := d.prepareCredentials(); err != nil { return fmt.Errorf("failed to prepare credentials: %w", err) } diff --git a/internal/deployer/operator.go b/internal/deployer/operator.go index 106476b..c10b4c3 100644 --- a/internal/deployer/operator.go +++ b/internal/deployer/operator.go @@ -16,7 +16,6 @@ import ( "github.com/stackrox/roxie/internal/k8s" "github.com/stackrox/roxie/internal/ocihelper" - "github.com/stackrox/roxie/internal/types" ) const ( @@ -319,7 +318,7 @@ func (d *Deployer) deployOperatorFromCSV(ctx context.Context, bundleDir string) } serviceAccountName := deploymentSpec["service_account"].(string) - d.useOperatorPullSecrets = d.config.Roxie.KonfluxImages && d.config.Roxie.ClusterType != types.ClusterTypeInfraOpenShift4 + d.useOperatorPullSecrets = d.config.Roxie.KonfluxImages && d.config.Roxie.ClusterType.NeedsPullSecrets() d.logger.Info("📋 Operator deployment plan:") d.logger.Dim(fmt.Sprintf(" • Namespace: %s", operatorNamespace)) diff --git a/internal/types/cluster_type.go b/internal/types/cluster_type.go index 1386673..9e0747c 100644 --- a/internal/types/cluster_type.go +++ b/internal/types/cluster_type.go @@ -78,3 +78,7 @@ func (ct *ClusterType) UnmarshalYAML(unmarshal func(any) error) error { } return fmt.Errorf("unknown cluster type identifier: %q", s) } + +func (ct ClusterType) NeedsPullSecrets() bool { + return ct != ClusterTypeInfraOpenShift4 +} From ba47e5385e9941968f6250be6ec111d817a1acd2 Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Tue, 19 May 2026 21:46:36 +0200 Subject: [PATCH 16/18] Simplify ClusterType String() implementation --- internal/types/cluster_type.go | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/internal/types/cluster_type.go b/internal/types/cluster_type.go index 9e0747c..d16e3a7 100644 --- a/internal/types/cluster_type.go +++ b/internal/types/cluster_type.go @@ -35,18 +35,8 @@ func (ct ClusterType) String() string { return "GKE (infra)" case ClusterTypeInfraOpenShift4: return "OpenShift4 (infra)" - case ClusterTypeOpenShift4: - return "OpenShift4" - case ClusterTypeKind: - return "Kind" - case ClusterTypeMinikube: - return "Minikube" - case ClusterTypeK3s: - return "K3s" - case ClusterTypeCRC: - return "CRC" default: - return "Unknown" + return string(ct) } } From 8d06f3cf817fb58dd0d61a6920ef731cb590ef33 Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Tue, 19 May 2026 21:51:25 +0200 Subject: [PATCH 17/18] Make ClusterTypeUnknown be backed by empty string --- internal/types/cluster_type.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/types/cluster_type.go b/internal/types/cluster_type.go index d16e3a7..dfdaa0c 100644 --- a/internal/types/cluster_type.go +++ b/internal/types/cluster_type.go @@ -7,7 +7,7 @@ type ClusterType string const ( // ClusterTypeUnknown represents an unidentified cluster type - ClusterTypeUnknown ClusterType = "Unknown" + ClusterTypeUnknown ClusterType = "" // ClusterTypeInfraGKE represents a GKE cluster created via Infra. ClusterTypeInfraGKE ClusterType = "InfraGKE" // ClusterTypeInfraOpenShift4 represents an OpenShift 4 cluster @@ -35,6 +35,8 @@ func (ct ClusterType) String() string { return "GKE (infra)" case ClusterTypeInfraOpenShift4: return "OpenShift4 (infra)" + case ClusterTypeUnknown: + return "Unknown" default: return string(ct) } From 2fcc87f1ec7cb7c30de415809fcec8fcbef842be Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Tue, 19 May 2026 21:55:54 +0200 Subject: [PATCH 18/18] Test case for ClusterTypeUnknown unmarshaling --- internal/types/cluster_type_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/types/cluster_type_test.go b/internal/types/cluster_type_test.go index 127d78a..b97ff6b 100644 --- a/internal/types/cluster_type_test.go +++ b/internal/types/cluster_type_test.go @@ -42,6 +42,7 @@ func TestClusterTypeUnmarshalYAML(t *testing.T) { {"Minikube", ClusterTypeMinikube}, {"K3s", ClusterTypeK3s}, {"CRC", ClusterTypeCRC}, + {"", ClusterTypeUnknown}, } for _, tt := range tests { t.Run(tt.input, func(t *testing.T) {