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
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,34 @@ Similarly, the deployment(s) can be torn down using:
./bin/roxie teardown [ <component> ]
```

### Multi-cluster deployments

roxie supports hub + spoke architectures where Central and SecuredCluster run on separate clusters.

1. Deploy Central on the hub cluster:
```bash
./roxie deploy central -t 4.9.2
```

2. Create a config file for the spoke cluster, pointing at the Central endpoint (printed during step 1):
```yaml
# spoke-config.yaml
securedCluster:
spec:
centralEndpoint: "<central-loadbalancer-ip>:443"
```

3. Switch kubectl context to the spoke cluster and deploy SecuredCluster:
```bash
ROX_ADMIN_PASSWORD=<admin-password> \
ROX_CA_CERT_FILE=<path-to-ca-cert> \
./roxie deploy secured-cluster -t 4.9.2 -c spoke-config.yaml
```

> **Tip:** If deploying from the roxie subshell, `ROX_ADMIN_PASSWORD` and `ROX_CA_CERT_FILE` are
> already set. For automation, consider using `--envrc <file>` on the Central deploy to write the
> environment to a file instead of spawning a subshell.

## Development

Enter the dev shell:
Expand Down
61 changes: 61 additions & 0 deletions internal/deployer/central_endpoint_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package deployer

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

func TestConfigureSpec_CentralEndpoint(t *testing.T) {
tests := []struct {
name string
spec map[string]interface{}
centralNamespace string
expected string
}{
{
name: "sets internal endpoint when not provided",
spec: map[string]interface{}{},
centralNamespace: "acs-central",
expected: "central.acs-central.svc:443",
},
{
name: "sets internal endpoint with custom namespace",
spec: map[string]interface{}{},
centralNamespace: "stackrox",
expected: "central.stackrox.svc:443",
},
{
name: "preserves user-provided endpoint",
spec: map[string]interface{}{"centralEndpoint": "central.example.com:443"},
centralNamespace: "acs-central",
expected: "central.example.com:443",
},
{
name: "user-provided endpoint takes precedence over internal default",
spec: map[string]interface{}{"centralEndpoint": "10.0.0.1:443"},
centralNamespace: "stackrox",
expected: "10.0.0.1:443",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sc := &SecuredClusterConfig{
Spec: tt.spec,
}
roxie := NewRoxieConfig()
central := &CentralConfig{Namespace: tt.centralNamespace}

err := sc.ConfigureSpec(&roxie, central)
require.NoError(t, err, "ConfigureSpec failed")

got, found, err := unstructured.NestedString(sc.Spec, "centralEndpoint")
require.NoError(t, err, "failed to get centralEndpoint from spec")
require.True(t, found, "centralEndpoint not found in spec")
assert.Equal(t, tt.expected, got)
})
}
}
6 changes: 2 additions & 4 deletions internal/deployer/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,8 @@ func (s *SecuredClusterConfig) ConfigureSpec(roxieConfig *RoxieConfig, centralCo
return err
}

if err := helpers.DeepMerge(s.Spec, map[string]interface{}{
"centralEndpoint": internalCentralEndpoint(centralConfig.Namespace),
}); err != nil {
return err
if _, exists := s.Spec["centralEndpoint"]; !exists {
s.Spec["centralEndpoint"] = internalCentralEndpoint(centralConfig.Namespace)
}

return nil
Expand Down
4 changes: 4 additions & 0 deletions internal/deployer/deployer.go
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,10 @@ func (d *Deployer) PrintSecuredClusterDeploymentSummary() {
log.Info(cyan.Sprint("│") + createRow("OLM", "Yes"))
}

if ep, ok := d.config.SecuredCluster.Spec["centralEndpoint"].(string); ok && ep != internalCentralEndpoint(d.config.Central.Namespace) {
log.Info(cyan.Sprint("│") + createRow("Central Endpoint", ep))
}

log.Info(cyan.Sprint("└" + strings.Repeat("─", boxWidth) + "┘"))
log.Info("")
}
Expand Down
Loading