Skip to content

Commit 954384a

Browse files
committed
Migrate multi-cluster from CLI flags to config property
1 parent 0fdf763 commit 954384a

6 files changed

Lines changed: 55 additions & 140 deletions

File tree

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,16 +95,16 @@ MAIN_IMAGE_TAG=4.9.2 ./roxie deploy central
9595

9696
2. Switch kubectl context to the spoke cluster and deploy SecuredCluster:
9797
```bash
98+
ROX_ADMIN_PASSWORD=<admin-password> \
99+
ROX_CA_CERT_FILE=<path-to-ca-cert> \
98100
./roxie deploy secured-cluster \
99-
--central-endpoint=<central-loadbalancer-ip>:443 \
100-
--central-password=<admin-password> \
101-
--ca-cert-file=/tmp/roxie-ca-cert.pem
101+
--set securedCluster.centralEndpoint=<central-loadbalancer-ip>:443
102102
```
103103

104104
> **Note:** The Central endpoint is printed during deployment. If you are in the roxie subshell,
105-
> `API_ENDPOINT`, `ROX_ADMIN_PASSWORD`, and `ROX_CA_CERT_FILE` are already set, so you can run:
105+
> `ROX_ADMIN_PASSWORD` and `ROX_CA_CERT_FILE` are already set, so you can run:
106106
> ```bash
107-
> ./roxie deploy secured-cluster --central-endpoint=$API_ENDPOINT
107+
> ./roxie deploy secured-cluster --set securedCluster.centralEndpoint=$API_ENDPOINT
108108
> ```
109109
110110
## Development

cmd/deploy.go

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -240,11 +240,6 @@ Examples:
240240
return pflag.NormalizedName(name)
241241
})
242242

243-
cmd.Flags().StringVar(&centralEndpointFlag, "central-endpoint", "", "Central endpoint for multi-cluster SecuredCluster deployments (e.g., central.example.com:443)")
244-
cmd.Flags().StringVar(&centralPasswordFlag, "central-password", "", "Central admin password (takes precedence over ROX_ADMIN_PASSWORD)")
245-
cmd.Flags().StringVar(&caCertFileFlag, "ca-cert-file", "", "Path to Central CA certificate file (takes precedence over ROX_CA_CERT_FILE)")
246-
247-
248243
return cmd
249244
}
250245

@@ -304,17 +299,15 @@ func runDeploy(cmd *cobra.Command, args []string) error {
304299
}
305300
}
306301

307-
hasMultiClusterFlags := centralEndpointFlag != "" || centralPasswordFlag != "" || caCertFileFlag != ""
308-
if hasMultiClusterFlags && components != component.SecuredCluster {
309-
return errors.New("--central-endpoint, --central-password, and --ca-cert-file flags can only be used with 'secured-cluster' component")
310-
}
311-
312-
if centralEndpointFlag != "" {
313-
if centralPasswordFlag == "" && os.Getenv("ROX_ADMIN_PASSWORD") == "" {
314-
return errors.New("--central-endpoint requires a Central admin password (set --central-password or ROX_ADMIN_PASSWORD)")
302+
if deploySettings.SecuredCluster.CentralEndpoint != "" {
303+
if !components.IncludesSensor() {
304+
return errors.New("securedCluster.centralEndpoint can only be used when deploying secured-cluster")
305+
}
306+
if os.Getenv("ROX_ADMIN_PASSWORD") == "" {
307+
return errors.New("securedCluster.centralEndpoint requires ROX_ADMIN_PASSWORD to be set")
315308
}
316-
if caCertFileFlag == "" && os.Getenv("ROX_CA_CERT_FILE") == "" {
317-
return errors.New("--central-endpoint requires a Central CA certificate (set --ca-cert-file or ROX_CA_CERT_FILE)")
309+
if os.Getenv("ROX_CA_CERT_FILE") == "" {
310+
return errors.New("securedCluster.centralEndpoint requires ROX_CA_CERT_FILE to be set")
318311
}
319312
}
320313

@@ -338,18 +331,6 @@ func runDeploy(cmd *cobra.Command, args []string) error {
338331
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute)
339332
defer cancel()
340333

341-
if centralEndpointFlag != "" {
342-
d.SetCentralEndpoint(centralEndpointFlag)
343-
}
344-
if centralPasswordFlag != "" {
345-
d.SetCentralPassword(centralPasswordFlag)
346-
}
347-
if caCertFileFlag != "" {
348-
if err := d.SetCACertFile(caCertFileFlag); err != nil {
349-
return err
350-
}
351-
}
352-
353334
if components.IncludesCentral() {
354335
d.PrintCentralDeploymentSummary()
355336
}

cmd/main.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,6 @@ var (
1515
envrc string
1616
dryRun bool
1717

18-
// Multi-cluster flags
19-
centralEndpointFlag string
20-
centralPasswordFlag string
21-
caCertFileFlag string
22-
2318
// We need this set up before command line flags are parsed.
2419
deploySettings = deployer.NewConfig()
2520
)

internal/deployer/central_endpoint_test.go

Lines changed: 32 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2,105 +2,65 @@ package deployer
22

33
import (
44
"testing"
5-
)
6-
7-
func TestSetCentralEndpoint(t *testing.T) {
8-
tests := []struct {
9-
name string
10-
input string
11-
expectedCentralEndpoint string
12-
expectedUserProvidedEndpoint string
13-
}{
14-
{
15-
name: "plain host:port",
16-
input: "10.0.0.1:443",
17-
expectedCentralEndpoint: "10.0.0.1:443",
18-
expectedUserProvidedEndpoint: "10.0.0.1:443",
19-
},
20-
{
21-
name: "strips https prefix",
22-
input: "https://10.0.0.1:443",
23-
expectedCentralEndpoint: "10.0.0.1:443",
24-
expectedUserProvidedEndpoint: "10.0.0.1:443",
25-
},
26-
{
27-
name: "hostname with port",
28-
input: "central.example.com:443",
29-
expectedCentralEndpoint: "central.example.com:443",
30-
expectedUserProvidedEndpoint: "central.example.com:443",
31-
},
32-
{
33-
name: "strips https from hostname",
34-
input: "https://central.example.com:443",
35-
expectedCentralEndpoint: "central.example.com:443",
36-
expectedUserProvidedEndpoint: "central.example.com:443",
37-
},
38-
{
39-
name: "strips http prefix",
40-
input: "http://10.0.0.1:443",
41-
expectedCentralEndpoint: "10.0.0.1:443",
42-
expectedUserProvidedEndpoint: "10.0.0.1:443",
43-
},
44-
{
45-
name: "strips http from hostname",
46-
input: "http://central.example.com:443",
47-
expectedCentralEndpoint: "central.example.com:443",
48-
expectedUserProvidedEndpoint: "central.example.com:443",
49-
},
50-
}
515

52-
for _, tt := range tests {
53-
t.Run(tt.name, func(t *testing.T) {
54-
d := &Deployer{}
55-
d.SetCentralEndpoint(tt.input)
56-
57-
if d.centralEndpoint != tt.expectedCentralEndpoint {
58-
t.Errorf("centralEndpoint: got %q, want %q", d.centralEndpoint, tt.expectedCentralEndpoint)
59-
}
60-
if d.userProvidedCentralEndpoint != tt.expectedUserProvidedEndpoint {
61-
t.Errorf("userProvidedCentralEndpoint: got %q, want %q", d.userProvidedCentralEndpoint, tt.expectedUserProvidedEndpoint)
62-
}
63-
})
64-
}
65-
}
6+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
7+
)
668

67-
func TestGetCentralEndpointForSensor(t *testing.T) {
9+
func TestConfigureSpec_CentralEndpoint(t *testing.T) {
6810
tests := []struct {
6911
name string
70-
userProvided string
12+
centralEndpoint string
7113
centralNamespace string
7214
expected string
7315
}{
7416
{
7517
name: "falls back to internal endpoint",
76-
userProvided: "",
18+
centralEndpoint: "",
7719
centralNamespace: "acs-central",
7820
expected: "central.acs-central.svc:443",
7921
},
8022
{
8123
name: "falls back to internal endpoint with custom namespace",
82-
userProvided: "",
24+
centralEndpoint: "",
8325
centralNamespace: "stackrox",
8426
expected: "central.stackrox.svc:443",
8527
},
8628
{
87-
name: "uses user-provided endpoint",
88-
userProvided: "10.0.0.1:443",
29+
name: "uses provided central endpoint",
30+
centralEndpoint: "central.example.com:443",
8931
centralNamespace: "acs-central",
32+
expected: "central.example.com:443",
33+
},
34+
{
35+
name: "provided endpoint takes precedence over namespace",
36+
centralEndpoint: "10.0.0.1:443",
37+
centralNamespace: "stackrox",
9038
expected: "10.0.0.1:443",
9139
},
9240
}
9341

9442
for _, tt := range tests {
9543
t.Run(tt.name, func(t *testing.T) {
96-
d := &Deployer{
97-
centralNamespace: tt.centralNamespace,
98-
userProvidedCentralEndpoint: tt.userProvided,
44+
sc := &SecuredClusterConfig{
45+
CentralEndpoint: tt.centralEndpoint,
46+
Spec: make(map[string]interface{}),
9947
}
48+
roxie := &RoxieConfig{FeatureFlags: make(map[string]bool)}
49+
central := &CentralConfig{Namespace: tt.centralNamespace}
10050

101-
result := d.getCentralEndpointForSensor()
102-
if result != tt.expected {
103-
t.Errorf("got %q, want %q", result, tt.expected)
51+
if err := sc.ConfigureSpec(roxie, central); err != nil {
52+
t.Fatalf("ConfigureSpec failed: %v", err)
53+
}
54+
55+
got, found, err := unstructured.NestedString(sc.Spec, "centralEndpoint")
56+
if err != nil {
57+
t.Fatalf("failed to get centralEndpoint from spec: %v", err)
58+
}
59+
if !found {
60+
t.Fatal("centralEndpoint not found in spec")
61+
}
62+
if got != tt.expected {
63+
t.Errorf("got %q, want %q", got, tt.expected)
10464
}
10565
})
10666
}

internal/deployer/config.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ func (c *CentralConfig) CustomResource() (map[string]interface{}, error) {
199199
// SecuredClusterConfig holds deployment settings for the SecuredCluster component.
200200
type SecuredClusterConfig struct {
201201
Namespace string `yaml:"namespace,omitempty"`
202+
CentralEndpoint string `yaml:"centralEndpoint,omitempty"`
202203
ResourceProfile types.ResourceProfile `yaml:"resourceProfile,omitempty"`
203204
PauseReconciliation bool `yaml:"pauseReconciliation,omitempty"`
204205
DeployTimeout time.Duration `yaml:"deployTimeout,omitempty"`
@@ -234,8 +235,13 @@ func (s *SecuredClusterConfig) ConfigureSpec(roxieConfig *RoxieConfig, centralCo
234235
return err
235236
}
236237

238+
centralEndpoint := internalCentralEndpoint(centralConfig.Namespace)
239+
if s.CentralEndpoint != "" {
240+
centralEndpoint = s.CentralEndpoint
241+
}
242+
237243
if err := helpers.DeepMerge(s.Spec, map[string]interface{}{
238-
"centralEndpoint": internalCentralEndpoint(centralConfig.Namespace),
244+
"centralEndpoint": centralEndpoint,
239245
}); err != nil {
240246
return err
241247
}

internal/deployer/deployer.go

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ type Deployer struct {
5151
config Config
5252

5353
// State
54-
centralEndpoint string
55-
userProvidedCentralEndpoint string
54+
centralEndpoint string
5655
centralPassword string
5756
roxCACertFile string
5857
tempDir string
@@ -654,32 +653,6 @@ func (d *Deployer) removePauseReconcileAnnotation(ctx context.Context, resourceT
654653
return nil
655654
}
656655

657-
func (d *Deployer) SetCentralEndpoint(endpoint string) {
658-
endpoint = strings.TrimPrefix(endpoint, "https://")
659-
endpoint = strings.TrimPrefix(endpoint, "http://")
660-
d.centralEndpoint = endpoint
661-
d.userProvidedCentralEndpoint = endpoint
662-
}
663-
664-
func (d *Deployer) SetCentralPassword(password string) {
665-
d.centralPassword = password
666-
}
667-
668-
func (d *Deployer) SetCACertFile(path string) error {
669-
if _, err := os.Stat(path); err != nil {
670-
return fmt.Errorf("CA cert file not found: %w", err)
671-
}
672-
d.roxCACertFile = path
673-
return nil
674-
}
675-
676-
func (d *Deployer) getCentralEndpointForSensor() string {
677-
if d.userProvidedCentralEndpoint != "" {
678-
return d.userProvidedCentralEndpoint
679-
}
680-
return internalCentralEndpoint(d.config.Central.Namespace)
681-
}
682-
683656
// WaitForCentral waits for Central to be ready and responding on its endpoint
684657
// Returns true if Central is ready, false if timeout occurs
685658
func (d *Deployer) WaitForCentral(timeout time.Duration) bool {
@@ -1022,8 +995,8 @@ func (d *Deployer) PrintSecuredClusterDeploymentSummary() {
1022995
log.Info(cyan.Sprint("│") + createRow("OLM", "Yes"))
1023996
}
1024997

1025-
if d.userProvidedCentralEndpoint != "" {
1026-
log.Info(cyan.Sprint("│") + createRow("Central Endpoint", d.userProvidedCentralEndpoint))
998+
if d.config.SecuredCluster.CentralEndpoint != "" {
999+
log.Info(cyan.Sprint("│") + createRow("Central Endpoint", d.config.SecuredCluster.CentralEndpoint))
10271000
}
10281001

10291002
log.Info(cyan.Sprint("└" + strings.Repeat("─", boxWidth) + "┘"))

0 commit comments

Comments
 (0)