Skip to content
600 changes: 433 additions & 167 deletions cmd/deploy.go

Large diffs are not rendered by default.

32 changes: 11 additions & 21 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,18 @@ import (

"github.com/fatih/color"
"github.com/spf13/cobra"
"github.com/stackrox/roxie/internal/deployer"
)

var (
// Global flags
verbose bool
earlyReadiness bool
olm bool
konflux bool
deployOperator bool
portForwarding bool
pauseReconciliation bool
overrideFile string
overrideSetExpressions []string
exposure string
resources string
shell string
envrc string
singleNamespace bool
tag string
featureFlags []string
centralWait string
securedClusterWait string
verbose bool
shell string
envrc string
dryRun bool

// We need this set up before command line flags are parsed.
deploySettings = deployer.NewConfig()
)

func main() {
Expand All @@ -48,9 +38,9 @@ Red Hat Advanced Cluster Security (ACS) on any Kubernetes/OpenShift cluster.`,

func init() {
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Enable verbose output (show CRs)")
rootCmd.PersistentFlags().BoolVar(&earlyReadiness, "early-readiness", true, "Only wait for essential workloads (central/sensor) to be ready")
rootCmd.AddCommand(newDeployCmd())
rootCmd.AddCommand(newTeardownCmd())
rootCmd.PersistentFlags().BoolVar(&dryRun, "dry-run", false, "Do not actually modify cluster")
rootCmd.AddCommand(newDeployCmd(&deploySettings))
rootCmd.AddCommand(newTeardownCmd(&deploySettings))
rootCmd.AddCommand(newVersionCmd())
rootCmd.AddCommand(newEnvCmd())
rootCmd.AddCommand(newLogsCmd())
Expand Down
38 changes: 19 additions & 19 deletions cmd/subshell.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/stackrox/roxie/internal/deployer"
"github.com/stackrox/roxie/internal/env"
"github.com/stackrox/roxie/internal/logger"
"github.com/stackrox/roxie/internal/types"
)

func spawnSubshell(d *deployer.Deployer, log *logger.Logger) error {
Expand All @@ -29,45 +30,44 @@ func spawnSubshell(d *deployer.Deployer, log *logger.Logger) error {

env := os.Environ()

endpoint, password, caCertFile, kubeContext, exposure := d.GetDeploymentInfo()
centralDeploymentInfo := d.GetCentralDeploymentInfo()

if endpoint != "" {
env = append(env, fmt.Sprintf("API_ENDPOINT=%s", endpoint))
env = append(env, fmt.Sprintf("ROX_ENDPOINT=%s", endpoint))
env = append(env, fmt.Sprintf("ROX_BASE_URL=https://%s", endpoint))
if centralDeploymentInfo.Endpoint != "" {
env = append(env, fmt.Sprintf("API_ENDPOINT=%s", centralDeploymentInfo.Endpoint))
env = append(env, fmt.Sprintf("ROX_ENDPOINT=%s", centralDeploymentInfo.Endpoint))
env = append(env, fmt.Sprintf("ROX_BASE_URL=https://%s", centralDeploymentInfo.Endpoint))
}

if password != "" {
env = append(env, fmt.Sprintf("ROX_ADMIN_PASSWORD=%s", password))
if centralDeploymentInfo.Password != "" {
env = append(env, fmt.Sprintf("ROX_ADMIN_PASSWORD=%s", centralDeploymentInfo.Password))
}

if caCertFile != "" {
env = append(env, fmt.Sprintf("ROX_CA_CERT_FILE=%s", caCertFile))
if centralDeploymentInfo.CACertFile != "" {
env = append(env, fmt.Sprintf("ROX_CA_CERT_FILE=%s", centralDeploymentInfo.CACertFile))
}

env = append(env, fmt.Sprintf("ROX_USERNAME=%s", deployer.AdminUsername))
env = append(env, "ROXIE_SHELL=1")
env = append(env, fmt.Sprintf("name=acs@%s", kubeContext))
env = append(env, fmt.Sprintf("name=acs@%s", centralDeploymentInfo.KubeContext))

haproxyAvailable := isHAProxyAvailable()

var haproxyCmd *exec.Cmd
var haproxyConfigPath string
var haproxyStarted bool

if haproxyAvailable && endpoint != "" && caCertFile != "" {
if haproxyAvailable && centralDeploymentInfo.Endpoint != "" && centralDeploymentInfo.CACertFile != "" {
var err error
haproxyCmd, haproxyConfigPath, err = startHAProxy(endpoint, caCertFile, log)
haproxyCmd, haproxyConfigPath, err = startHAProxy(centralDeploymentInfo.Endpoint, centralDeploymentInfo.CACertFile, log)
if err != nil {
log.Warningf("Failed to start HAProxy: %v", err)
} else {
env = append(env, fmt.Sprintf("ROXIE_HAPROXY_CFG_FILE=%s", haproxyConfigPath))
haproxyStarted = true
centralDeploymentInfo.HAProxyStarted = true
defer cleanupHAProxy(haproxyCmd, haproxyConfigPath)
}
}

printBanner(endpoint, exposure, haproxyAvailable, haproxyStarted)
printBanner(centralDeploymentInfo)

shellCmd := exec.Command(shellPath, "-i")
shellCmd.Env = env
Expand Down Expand Up @@ -171,7 +171,7 @@ func isHAProxyAvailable() bool {
return err == nil
}

func printBanner(endpoint, exposure string, haproxyAvailable, haproxyStarted bool) {
func printBanner(centralDeploymentInfo deployer.CentralDeploymentInfo) {
cyan := color.New(color.FgCyan, color.Bold)
cyan.Println("\n[roxie] Entering a subshell with ACS environment variables set.")
cyan.Println("[roxie]")
Expand All @@ -181,10 +181,10 @@ func printBanner(endpoint, exposure string, haproxyAvailable, haproxyStarted boo
cyan.Println("[roxie] * roxcurl /v1/clusters")
cyan.Println("[roxie]")

if haproxyStarted {
if centralDeploymentInfo.HAProxyStarted {
cyan.Println("[roxie] Central UI: http://localhost:8080 (username: admin, password: see $ROX_ADMIN_PASSWORD)")
} else if exposure != "none" && exposure != "" {
cyan.Printf("[roxie] Central UI: https://%s", endpoint)
} else if centralDeploymentInfo.Exposure != types.ExposureNone {
cyan.Printf("[roxie] Central UI: https://%s", centralDeploymentInfo.Endpoint)
} else if !env.RunningInRoxieContainer {
cyan.Println("[roxie] Note: Installing haproxy enables automatic HTTP access to Central at http://localhost:8080")
}
Expand Down
28 changes: 25 additions & 3 deletions cmd/teardown.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import (
"github.com/stackrox/roxie/internal/deployer"
"github.com/stackrox/roxie/internal/env"
"github.com/stackrox/roxie/internal/logger"
"gopkg.in/yaml.v3"
)

func newTeardownCmd() *cobra.Command {
func newTeardownCmd(settings *deployer.Config) *cobra.Command {
cmd := &cobra.Command{
Use: "teardown [component]",
Short: "Teardown ACS components",
Expand All @@ -22,7 +23,23 @@ func newTeardownCmd() *cobra.Command {
RunE: runTeardown,
}

cmd.Flags().BoolVar(&singleNamespace, "single-namespace", false, "Deploy all components in a single namespace ('stackrox' by default)")
// --single-namespace[=true/false].
flag := cmd.Flags().VarPF(
newConfigShortCut(
settings, "bool",
func(val string, settings *deployer.Config) error {
var valParsed bool
if err := yaml.Unmarshal([]byte(val), &valParsed); err != nil {
return err
}
if valParsed {
settings.Central.Namespace = sharedNamespace
settings.SecuredCluster.Namespace = sharedNamespace
}
return nil
},
), "single-namespace", "", "Deploy all components in a single namespace ('stackrox')")
flag.NoOptDefVal = "true"

return cmd
}
Expand All @@ -40,13 +57,18 @@ func runTeardown(cmd *cobra.Command, args []string) error {

log.Infof("Tearing down %s", components)

if dryRun {
log.Infof("Exiting because of enabled dry-run mode.")
return nil
}

d, err := deployer.New(log)
if err != nil {
return fmt.Errorf("failed to create deployer: %w", err)
}
defer d.Cleanup()

d.SetSingleNamespace(singleNamespace)
d.SetConfig(deploySettings)

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute)
defer cancel()
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ require (
github.com/fatih/color v1.16.0
github.com/google/go-containerregistry v0.21.0
github.com/spf13/cobra v1.10.2
github.com/spf13/pflag v1.0.9
github.com/stretchr/testify v1.11.1
golang.org/x/term v0.38.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/apimachinery v0.35.3
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4
)

require (
Expand All @@ -32,7 +34,6 @@ require (
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/pflag v1.0.9 // indirect
github.com/vbatts/tar-split v0.12.2 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
Expand All @@ -43,7 +44,6 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
Expand Down
Loading
Loading