Skip to content
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ test-e2e: build ## Run end-to-end tests (requires kubectl context and cluster ac
echo "❌ skopeo not found. Please install skopeo for E2E tests."; \
exit 1; \
fi
$(GOTEST) -v -tags=e2e -timeout=120m ./tests/e2e/...
$(GOTEST) -v -tags=e2e -timeout=120m -parallel=1 ./tests/e2e/...

.PHONY: test-all
test-all: test test-e2e ## Run all tests (unit + e2e)
Expand Down
11 changes: 11 additions & 0 deletions cmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Examples:
}

cmd.Flags().BoolVar(&helm, "helm", false, "Deploy using Helm charts instead of operator")
cmd.Flags().BoolVar(&olm, "olm", false, "Deploy operator via OLM (requires OLM installed)")
cmd.Flags().BoolVar(&portForwarding, "port-forwarding", false, "Enable localhost port-forward for Central")
cmd.Flags().StringVar(&overrideFile, "override", "", "Path to YAML file with overrides")
cmd.Flags().StringArrayVar(&overrideSetExpressions, "set", []string{}, "Set override values (can specify multiple times, e.g., --set foo.bar=val)")
Expand Down Expand Up @@ -105,12 +106,22 @@ func runDeploy(cmd *cobra.Command, args []string) error {
d.SetEnvrcFile(envrc)
}

if helm && olm {
return errors.New("cannot use both --helm and --olm flags together")
}

if helm {
if err := d.SetUseHelm(true); err != nil {
return err
}
}

if olm {
if err := d.SetUseOLM(true); err != nil {
return err
}
}

d.SetVerbose(verbose)
d.SetEarlyReadiness(earlyReadiness)
d.SetPortForwardingEnabled(portForwardEnabledFinal)
Expand Down
1 change: 1 addition & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ var (
verbose bool
earlyReadiness bool
helm bool
olm bool
portForwarding bool
overrideFile string
overrideSetExpressions []string
Expand Down
100 changes: 58 additions & 42 deletions pkg/deployer/deploy_via_operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,76 @@ import (
"gopkg.in/yaml.v3"
)

// deployCentralOperator deploys Central using the operator
func (d *Deployer) deployCentralOperator(ctx context.Context, resources, exposure string) error {
d.logger.Info("🚀 Deploying Central via Operator...")

// ensureOperatorDeployed ensures the operator is deployed with the correct version and mode
func (d *Deployer) ensureOperatorDeployed(ctx context.Context) error {
if err := d.ensureCRDsInstalled(ctx); err != nil {
return fmt.Errorf("failed to ensure CRDs installed: %w", err)
}

operatorDeployed := d.isOperatorDeployed(ctx)
needsDeployment := !operatorDeployed

if operatorDeployed {
// Operator exists, check if version is correct
// Detect current operator deployment mode
operatorExists, currentMode := d.detectOperatorDeploymentMode(ctx)
needsDeployment := false
needsTeardown := false

if !operatorExists {
needsDeployment = true
} else if d.useOLM && currentMode == OperatorModeNonOLM {
// Switching from non-OLM to OLM
d.logger.Info("🔄 Switching operator from non-OLM to OLM mode...")
needsTeardown = true
needsDeployment = true
} else if !d.useOLM && currentMode == OperatorModeOLM {
// Switching from OLM to non-OLM
d.logger.Info("🔄 Switching operator from OLM to non-OLM mode...")
needsTeardown = true
needsDeployment = true
} else {
// Same mode, check version
if d.isOperatorVersionCorrect(ctx) {
d.logger.Info("✓ Operator already deployed with correct version")
} else {
d.logger.Info("🔄 Operator version mismatch, redeploying...")
needsTeardown = true
needsDeployment = true
}
}

if needsTeardown {
// Perform teardown for the current mode
if currentMode == OperatorModeOLM {
if err := d.teardownOperatorOLM(ctx); err != nil {
return fmt.Errorf("failed to teardown OLM operator: %w", err)
}
} else {
if err := d.teardownOperatorNonOLM(ctx); err != nil {
return fmt.Errorf("failed to teardown non-OLM operator: %w", err)
}
}
}

if needsDeployment {
if err := d.deployOperator(ctx); err != nil {
return fmt.Errorf("failed to deploy operator: %w", err)
if d.useOLM {
if err := d.deployOperatorViaOLM(ctx); err != nil {
return fmt.Errorf("failed to deploy operator via OLM: %w", err)
}
} else {
if err := d.deployOperator(ctx); err != nil {
return fmt.Errorf("failed to deploy operator: %w", err)
}
}
}

return nil
}

// deployCentralOperator deploys Central using the operator
func (d *Deployer) deployCentralOperator(ctx context.Context, resources, exposure string) error {
d.logger.Info("🚀 Deploying Central via Operator...")

if err := d.ensureOperatorDeployed(ctx); err != nil {
return err
}

if err := d.prepareNamespace(ctx, d.centralNamespace); err != nil {
return fmt.Errorf("failed to prepare namespace: %w", err)
}
Expand All @@ -65,14 +108,6 @@ func (d *Deployer) deployCentralOperator(ctx context.Context, resources, exposur
return d.configureCentralEndpoint(ctx, exposure)
}

// isOperatorDeployed checks if the operator is already deployed
func (d *Deployer) isOperatorDeployed(ctx context.Context) bool {
_, err := d.runKubectl(ctx, KubectlOptions{
Args: []string{"get", "deployment", operatorDeploymentName, "-n", operatorNamespace},
})
return err == nil
}

// isOperatorVersionCorrect checks if the deployed operator matches the desired version
func (d *Deployer) isOperatorVersionCorrect(ctx context.Context) bool {
currentImage, err := d.getDeployedOperatorImage(ctx)
Expand Down Expand Up @@ -520,31 +555,12 @@ func (d *Deployer) configureCentralEndpoint(ctx context.Context, exposure string
return nil
}

// deploySecuredClusterOperator deploys SecuredCluster using the operator
// deploySecuredClusterOperator deploys SecuredCluster using the operator.
func (d *Deployer) deploySecuredClusterOperator(ctx context.Context, resources string) error {
d.logger.Info("🚀 Deploying SecuredCluster via Operator...")

if err := d.ensureCRDsInstalled(ctx); err != nil {
return fmt.Errorf("failed to ensure CRDs installed: %w", err)
}

operatorDeployed := d.isOperatorDeployed(ctx)
needsDeployment := !operatorDeployed

if operatorDeployed {
// Operator exists, check if version is correct
if d.isOperatorVersionCorrect(ctx) {
d.logger.Info("✓ Operator already deployed with correct version")
} else {
d.logger.Info("🔄 Operator version mismatch, redeploying...")
needsDeployment = true
}
}

if needsDeployment {
if err := d.deployOperator(ctx); err != nil {
return fmt.Errorf("failed to deploy operator: %w", err)
}
if err := d.ensureOperatorDeployed(ctx); err != nil {
return err
}

if err := d.prepareNamespace(ctx, d.sensorNamespace); err != nil {
Expand Down Expand Up @@ -579,7 +595,7 @@ func (d *Deployer) deploySecuredClusterOperator(ctx context.Context, resources s
return nil
}

// createSecuredClusterCR creates the SecuredCluster custom resource
// createSecuredClusterCR creates the SecuredCluster custom resource.
func (d *Deployer) createSecuredClusterCR(clusterName, resources string) (map[string]interface{}, error) {
base := map[string]interface{}{
"apiVersion": "platform.stackrox.io/v1alpha1",
Expand Down
17 changes: 17 additions & 0 deletions pkg/deployer/deployer.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type Deployer struct {
overrideSetExpressions []string
envrcFile string
useHelm bool
useOLM bool
verbose bool
earlyReadiness bool
}
Expand Down Expand Up @@ -462,6 +463,11 @@ func (d *Deployer) SetUseHelm(useHelm bool) error {
return nil
}

func (d *Deployer) SetUseOLM(useOLM bool) error {
d.useOLM = useOLM
return nil
}

func (d *Deployer) SetVerbose(verbose bool) {
d.verbose = verbose
}
Expand Down Expand Up @@ -571,6 +577,7 @@ func (d *Deployer) PrintCentralDeploymentSummary() {
component := "Central"
mainImageTag := d.mainImageTag
helm := d.useHelm
olm := d.useOLM
exposure := d.exposure
portForwarding := d.portForwardEnabled
log := d.logger
Expand Down Expand Up @@ -627,6 +634,11 @@ func (d *Deployer) PrintCentralDeploymentSummary() {
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]))

if olm {
log.Info(cyan.Sprint("│") + createRow("OLM", "Yes"))
}

log.Info(cyan.Sprint("│") + createRow("Exposure", exposure))

if portForwarding || exposure == "none" {
Expand Down Expand Up @@ -734,6 +746,7 @@ func (d *Deployer) PrintSecuredClusterDeploymentSummary() {
component := "Secured Cluster"
mainImageTag := d.mainImageTag
helm := d.useHelm
olm := d.useOLM
log := d.logger
kubeContext := d.kubeContext

Expand Down Expand Up @@ -789,6 +802,10 @@ func (d *Deployer) PrintSecuredClusterDeploymentSummary() {
log.Info(cyan.Sprint("│") + createRow("Kubernetes Context", kubeContext))
log.Info(cyan.Sprint("│") + createRow("Deployment Method", map[bool]string{true: "Helm", false: "Operator"}[helm]))

if olm {
log.Info(cyan.Sprint("│") + createRow("OLM", "Yes"))
}

log.Info(cyan.Sprint("└" + strings.Repeat("─", boxWidth) + "┘"))
log.Info("")
}
33 changes: 33 additions & 0 deletions pkg/deployer/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -514,3 +514,36 @@ func generateClusterName() string {
n, _ := rand.Int(rand.Reader, big.NewInt(9000))
return fmt.Sprintf("sensor-%d", n.Int64()+1000)
}

// teardownOperatorNonOLM removes the operator when installed without OLM.
func (d *Deployer) teardownOperatorNonOLM(ctx context.Context) error {
d.logger.Info("🧹 Tearing down operator deployed without OLM...")

// Delete operator namespace.
d.runKubectl(ctx, KubectlOptions{
Args: []string{"delete", "namespace", operatorNamespace, "--wait=false"},
IgnoreErrors: true,
})

// Delete cluster-scoped resources created by non-OLM flow.
clusterResources := []struct {
name string
kind string
}{
{name: "rhacs-operator-manager-rolebinding", kind: "clusterrolebinding"},
{name: "rhacs-operator-manager-role", kind: "clusterrole"},
}
for _, resource := range clusterResources {
d.runKubectl(ctx, KubectlOptions{
Args: []string{"delete", resource.kind, resource.name, "--ignore-not-found=true"},
IgnoreErrors: true,
})
}

if err := d.waitForNamespaceDeletion(operatorNamespace); err != nil {
d.logger.Warningf("Namespace %s deletion incomplete: %v", operatorNamespace, err)
}

d.logger.Success("✓ Non-OLM operator resources removed")
return nil
}
Loading