Skip to content

Commit b2a7239

Browse files
author
Moritz Clasmeier
committed
Implement OLM mode for operator deployment
1 parent 6f262ba commit b2a7239

6 files changed

Lines changed: 533 additions & 42 deletions

File tree

cmd/deploy.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Examples:
3030
}
3131

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

109+
if helm && olm {
110+
return errors.New("cannot use both --helm and --olm flags together")
111+
}
112+
108113
if helm {
109114
if err := d.SetUseHelm(true); err != nil {
110115
return err
111116
}
112117
}
113118

119+
if olm {
120+
if err := d.SetUseOLM(true); err != nil {
121+
return err
122+
}
123+
}
124+
114125
d.SetVerbose(verbose)
115126
d.SetEarlyReadiness(earlyReadiness)
116127
d.SetPortForwardingEnabled(portForwardEnabledFinal)

cmd/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ var (
1212
verbose bool
1313
earlyReadiness bool
1414
helm bool
15+
olm bool
1516
portForwarding bool
1617
overrideFile string
1718
overrideSetExpressions []string

pkg/deployer/deploy_via_operator.go

Lines changed: 58 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,76 @@ import (
1414
"gopkg.in/yaml.v3"
1515
)
1616

17-
// deployCentralOperator deploys Central using the operator
18-
func (d *Deployer) deployCentralOperator(ctx context.Context, resources, exposure string) error {
19-
d.logger.Info("🚀 Deploying Central via Operator...")
20-
17+
// ensureOperatorDeployed ensures the operator is deployed with the correct version and mode
18+
func (d *Deployer) ensureOperatorDeployed(ctx context.Context) error {
2119
if err := d.ensureCRDsInstalled(ctx); err != nil {
2220
return fmt.Errorf("failed to ensure CRDs installed: %w", err)
2321
}
2422

25-
operatorDeployed := d.isOperatorDeployed(ctx)
26-
needsDeployment := !operatorDeployed
27-
28-
if operatorDeployed {
29-
// Operator exists, check if version is correct
23+
// Detect current operator deployment mode
24+
operatorExists, currentMode := d.detectOperatorDeploymentMode(ctx)
25+
needsDeployment := false
26+
needsTeardown := false
27+
28+
if !operatorExists {
29+
needsDeployment = true
30+
} else if d.useOLM && currentMode == OperatorModeNonOLM {
31+
// Switching from non-OLM to OLM
32+
d.logger.Info("🔄 Switching operator from non-OLM to OLM mode...")
33+
needsTeardown = true
34+
needsDeployment = true
35+
} else if !d.useOLM && currentMode == OperatorModeOLM {
36+
// Switching from OLM to non-OLM
37+
d.logger.Info("🔄 Switching operator from OLM to non-OLM mode...")
38+
needsTeardown = true
39+
needsDeployment = true
40+
} else {
41+
// Same mode, check version
3042
if d.isOperatorVersionCorrect(ctx) {
3143
d.logger.Info("✓ Operator already deployed with correct version")
3244
} else {
3345
d.logger.Info("🔄 Operator version mismatch, redeploying...")
46+
needsTeardown = true
3447
needsDeployment = true
3548
}
3649
}
3750

51+
if needsTeardown {
52+
// Perform teardown for the current mode
53+
if currentMode == OperatorModeOLM {
54+
if err := d.teardownOperatorOLM(ctx); err != nil {
55+
return fmt.Errorf("failed to teardown OLM operator: %w", err)
56+
}
57+
} else {
58+
if err := d.teardownOperatorNonOLM(ctx); err != nil {
59+
return fmt.Errorf("failed to teardown non-OLM operator: %w", err)
60+
}
61+
}
62+
}
63+
3864
if needsDeployment {
39-
if err := d.deployOperator(ctx); err != nil {
40-
return fmt.Errorf("failed to deploy operator: %w", err)
65+
if d.useOLM {
66+
if err := d.deployOperatorViaOLM(ctx); err != nil {
67+
return fmt.Errorf("failed to deploy operator via OLM: %w", err)
68+
}
69+
} else {
70+
if err := d.deployOperator(ctx); err != nil {
71+
return fmt.Errorf("failed to deploy operator: %w", err)
72+
}
4173
}
4274
}
4375

76+
return nil
77+
}
78+
79+
// deployCentralOperator deploys Central using the operator
80+
func (d *Deployer) deployCentralOperator(ctx context.Context, resources, exposure string) error {
81+
d.logger.Info("🚀 Deploying Central via Operator...")
82+
83+
if err := d.ensureOperatorDeployed(ctx); err != nil {
84+
return err
85+
}
86+
4487
if err := d.prepareNamespace(ctx, d.centralNamespace); err != nil {
4588
return fmt.Errorf("failed to prepare namespace: %w", err)
4689
}
@@ -65,14 +108,6 @@ func (d *Deployer) deployCentralOperator(ctx context.Context, resources, exposur
65108
return d.configureCentralEndpoint(ctx, exposure)
66109
}
67110

68-
// isOperatorDeployed checks if the operator is already deployed
69-
func (d *Deployer) isOperatorDeployed(ctx context.Context) bool {
70-
_, err := d.runKubectl(ctx, KubectlOptions{
71-
Args: []string{"get", "deployment", operatorDeploymentName, "-n", operatorNamespace},
72-
})
73-
return err == nil
74-
}
75-
76111
// isOperatorVersionCorrect checks if the deployed operator matches the desired version
77112
func (d *Deployer) isOperatorVersionCorrect(ctx context.Context) bool {
78113
currentImage, err := d.getDeployedOperatorImage(ctx)
@@ -520,31 +555,12 @@ func (d *Deployer) configureCentralEndpoint(ctx context.Context, exposure string
520555
return nil
521556
}
522557

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

527-
if err := d.ensureCRDsInstalled(ctx); err != nil {
528-
return fmt.Errorf("failed to ensure CRDs installed: %w", err)
529-
}
530-
531-
operatorDeployed := d.isOperatorDeployed(ctx)
532-
needsDeployment := !operatorDeployed
533-
534-
if operatorDeployed {
535-
// Operator exists, check if version is correct
536-
if d.isOperatorVersionCorrect(ctx) {
537-
d.logger.Info("✓ Operator already deployed with correct version")
538-
} else {
539-
d.logger.Info("🔄 Operator version mismatch, redeploying...")
540-
needsDeployment = true
541-
}
542-
}
543-
544-
if needsDeployment {
545-
if err := d.deployOperator(ctx); err != nil {
546-
return fmt.Errorf("failed to deploy operator: %w", err)
547-
}
562+
if err := d.ensureOperatorDeployed(ctx); err != nil {
563+
return err
548564
}
549565

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

582-
// createSecuredClusterCR creates the SecuredCluster custom resource
598+
// createSecuredClusterCR creates the SecuredCluster custom resource.
583599
func (d *Deployer) createSecuredClusterCR(clusterName, resources string) (map[string]interface{}, error) {
584600
base := map[string]interface{}{
585601
"apiVersion": "platform.stackrox.io/v1alpha1",

pkg/deployer/deployer.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type Deployer struct {
5151
overrideSetExpressions []string
5252
envrcFile string
5353
useHelm bool
54+
useOLM bool
5455
verbose bool
5556
earlyReadiness bool
5657
}
@@ -462,6 +463,11 @@ func (d *Deployer) SetUseHelm(useHelm bool) error {
462463
return nil
463464
}
464465

466+
func (d *Deployer) SetUseOLM(useOLM bool) error {
467+
d.useOLM = useOLM
468+
return nil
469+
}
470+
465471
func (d *Deployer) SetVerbose(verbose bool) {
466472
d.verbose = verbose
467473
}
@@ -571,6 +577,7 @@ func (d *Deployer) PrintCentralDeploymentSummary() {
571577
component := "Central"
572578
mainImageTag := d.mainImageTag
573579
helm := d.useHelm
580+
olm := d.useOLM
574581
exposure := d.exposure
575582
portForwarding := d.portForwardEnabled
576583
log := d.logger
@@ -627,6 +634,11 @@ func (d *Deployer) PrintCentralDeploymentSummary() {
627634
log.Info(cyan.Sprint("│") + createRow("Main Tag", mainImageTag))
628635
log.Info(cyan.Sprint("│") + createRow("Kubernetes Context", kubeContext))
629636
log.Info(cyan.Sprint("│") + createRow("Deployment Method", map[bool]string{true: "Helm", false: "Operator"}[helm]))
637+
638+
if olm {
639+
log.Info(cyan.Sprint("│") + createRow("OLM", "Yes"))
640+
}
641+
630642
log.Info(cyan.Sprint("│") + createRow("Exposure", exposure))
631643

632644
if portForwarding || exposure == "none" {
@@ -734,6 +746,7 @@ func (d *Deployer) PrintSecuredClusterDeploymentSummary() {
734746
component := "Secured Cluster"
735747
mainImageTag := d.mainImageTag
736748
helm := d.useHelm
749+
olm := d.useOLM
737750
log := d.logger
738751
kubeContext := d.kubeContext
739752

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

805+
if olm {
806+
log.Info(cyan.Sprint("│") + createRow("OLM", "Yes"))
807+
}
808+
792809
log.Info(cyan.Sprint("└" + strings.Repeat("─", boxWidth) + "┘"))
793810
log.Info("")
794811
}

pkg/deployer/operator.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,3 +514,36 @@ func generateClusterName() string {
514514
n, _ := rand.Int(rand.Reader, big.NewInt(9000))
515515
return fmt.Sprintf("sensor-%d", n.Int64()+1000)
516516
}
517+
518+
// teardownOperatorNonOLM removes the operator when installed without OLM.
519+
func (d *Deployer) teardownOperatorNonOLM(ctx context.Context) error {
520+
d.logger.Info("🧹 Tearing down operator deployed without OLM...")
521+
522+
// Delete operator namespace.
523+
d.runKubectl(ctx, KubectlOptions{
524+
Args: []string{"delete", "namespace", operatorNamespace, "--wait=false"},
525+
IgnoreErrors: true,
526+
})
527+
528+
// Delete cluster-scoped resources created by non-OLM flow.
529+
clusterResources := []struct {
530+
name string
531+
kind string
532+
}{
533+
{name: "rhacs-operator-manager-rolebinding", kind: "clusterrolebinding"},
534+
{name: "rhacs-operator-manager-role", kind: "clusterrole"},
535+
}
536+
for _, resource := range clusterResources {
537+
d.runKubectl(ctx, KubectlOptions{
538+
Args: []string{"delete", resource.kind, resource.name, "--ignore-not-found=true"},
539+
IgnoreErrors: true,
540+
})
541+
}
542+
543+
if err := d.waitForNamespaceDeletion(operatorNamespace); err != nil {
544+
d.logger.Warningf("Namespace %s deletion incomplete: %v", operatorNamespace, err)
545+
}
546+
547+
d.logger.Success("✓ Non-OLM operator resources removed")
548+
return nil
549+
}

0 commit comments

Comments
 (0)