Skip to content

Commit d05a8d7

Browse files
mclasmeierMoritz Clasmeierporridge
authored
New config-file first configuration approach (#129)
Co-authored-by: Moritz Clasmeier <mclasmeier@redhat.com> Co-authored-by: Marcin Owsiany <porridge@redhat.com>
1 parent b4991fe commit d05a8d7

28 files changed

Lines changed: 1745 additions & 1337 deletions

cmd/deploy.go

Lines changed: 316 additions & 161 deletions
Large diffs are not rendered by default.

cmd/deploy_test.go

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
package main
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"reflect"
7+
"testing"
8+
"time"
9+
10+
"github.com/stackrox/roxie/internal/deployer"
11+
"github.com/stackrox/roxie/internal/types"
12+
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/require"
14+
)
15+
16+
func TestNewDeployCmd_Flags(t *testing.T) {
17+
configFilePath := filepath.Join(t.TempDir(), "config.yaml")
18+
19+
tests := []struct {
20+
name string
21+
config string
22+
args []string
23+
assert func(t *testing.T, cfg deployer.Config)
24+
}{
25+
{
26+
name: "exposure loadbalancer",
27+
args: []string{"--exposure", "loadbalancer"},
28+
assert: func(t *testing.T, cfg deployer.Config) {
29+
require.NotNil(t, cfg.Central.Exposure, "Central.Exposure should be set")
30+
assert.Equal(t, types.ExposureLoadBalancer, *cfg.Central.Exposure, "Central.Exposure mismatch")
31+
},
32+
},
33+
{
34+
name: "resources small",
35+
args: []string{"--resources", "small"},
36+
assert: func(t *testing.T, cfg deployer.Config) {
37+
assert.Equal(t, types.ResourceProfileSmall, cfg.Central.ResourceProfile, "Central.ResourceProfile mismatch")
38+
assert.Equal(t, types.ResourceProfileSmall, cfg.SecuredCluster.ResourceProfile, "SecuredCluster.ResourceProfile mismatch")
39+
},
40+
},
41+
{
42+
name: "tag short flag",
43+
args: []string{"-t", "4.7.0"},
44+
assert: func(t *testing.T, cfg deployer.Config) {
45+
assert.Equal(t, "4.7.0", cfg.Roxie.Version, "Roxie.Version mismatch")
46+
},
47+
},
48+
{
49+
name: "tag long flag",
50+
args: []string{"--tag", "4.7.0"},
51+
assert: func(t *testing.T, cfg deployer.Config) {
52+
assert.Equal(t, "4.7.0", cfg.Roxie.Version, "Roxie.Version mismatch")
53+
},
54+
},
55+
{
56+
name: "port-forwarding enabled",
57+
args: []string{"--port-forwarding"},
58+
assert: func(t *testing.T, cfg deployer.Config) {
59+
require.NotNil(t, cfg.Central.PortForwarding, "Central.PortForwarding should be set")
60+
assert.True(t, *cfg.Central.PortForwarding, "Central.PortForwarding mismatch")
61+
},
62+
},
63+
{
64+
name: "port-forwarding disabled",
65+
args: []string{"--port-forwarding=false"},
66+
assert: func(t *testing.T, cfg deployer.Config) {
67+
require.NotNil(t, cfg.Central.PortForwarding, "Central.PortForwarding should be set")
68+
assert.False(t, *cfg.Central.PortForwarding, "Central.PortForwarding mismatch")
69+
},
70+
},
71+
{
72+
name: "single-namespace",
73+
args: []string{"--single-namespace"},
74+
assert: func(t *testing.T, cfg deployer.Config) {
75+
assert.Equal(t, "stackrox", cfg.Central.Namespace, "Central.Namespace mismatch")
76+
assert.Equal(t, "stackrox", cfg.SecuredCluster.Namespace, "SecuredCluster.Namespace mismatch")
77+
},
78+
},
79+
{
80+
name: "central-wait",
81+
args: []string{"--central-wait", "10m"},
82+
assert: func(t *testing.T, cfg deployer.Config) {
83+
assert.Equal(t, 10*time.Minute, cfg.Central.DeployTimeout, "Central.DeployTimeout mismatch")
84+
},
85+
},
86+
{
87+
name: "secured-cluster-wait",
88+
args: []string{"--secured-cluster-wait", "7m"},
89+
assert: func(t *testing.T, cfg deployer.Config) {
90+
assert.Equal(t, 7*time.Minute, cfg.SecuredCluster.DeployTimeout, "SecuredCluster.DeployTimeout mismatch")
91+
},
92+
},
93+
{
94+
name: "early-readiness",
95+
args: []string{"--early-readiness"},
96+
assert: func(t *testing.T, cfg deployer.Config) {
97+
assert.True(t, cfg.Central.EarlyReadiness, "Central.EarlyReadiness mismatch")
98+
assert.True(t, cfg.SecuredCluster.EarlyReadiness, "SecuredCluster.EarlyReadiness mismatch")
99+
},
100+
},
101+
{
102+
name: "disable early-readiness",
103+
args: []string{"--early-readiness=false"},
104+
assert: func(t *testing.T, cfg deployer.Config) {
105+
assert.False(t, cfg.Central.EarlyReadiness, "Central.EarlyReadiness mismatch")
106+
assert.False(t, cfg.SecuredCluster.EarlyReadiness, "SecuredCluster.EarlyReadiness mismatch")
107+
},
108+
},
109+
{
110+
name: "pause-reconciliation",
111+
args: []string{"--pause-reconciliation"},
112+
assert: func(t *testing.T, cfg deployer.Config) {
113+
assert.True(t, cfg.Central.PauseReconciliation, "Central.PauseReconciliation mismatch")
114+
assert.True(t, cfg.SecuredCluster.PauseReconciliation, "SecuredCluster.PauseReconciliation mismatch")
115+
},
116+
},
117+
{
118+
name: "olm",
119+
args: []string{"--olm"},
120+
assert: func(t *testing.T, cfg deployer.Config) {
121+
assert.True(t, cfg.Operator.DeployViaOlm, "Operator.DeployViaOlm mismatch")
122+
},
123+
},
124+
{
125+
name: "disable deploy-operator",
126+
args: []string{"--deploy-operator=false"},
127+
assert: func(t *testing.T, cfg deployer.Config) {
128+
assert.True(t, cfg.Operator.SkipDeployment, "Operator.SkipDeployment mismatch")
129+
},
130+
},
131+
{
132+
name: "multiple flags combined",
133+
args: []string{"--tag", "4.7.0", "--exposure", "loadbalancer", "--early-readiness", "--resources", "small"},
134+
assert: func(t *testing.T, cfg deployer.Config) {
135+
assert.Equal(t, "4.7.0", cfg.Roxie.Version, "Roxie.Version mismatch")
136+
require.NotNil(t, cfg.Central.Exposure, "Central.Exposure should be set")
137+
assert.Equal(t, types.ExposureLoadBalancer, *cfg.Central.Exposure, "Central.Exposure mismatch")
138+
assert.True(t, cfg.Central.EarlyReadiness, "Central.EarlyReadiness mismatch")
139+
assert.Equal(t, types.ResourceProfileSmall, cfg.Central.ResourceProfile, "Central.ResourceProfile mismatch")
140+
},
141+
},
142+
{
143+
name: "config file can be used",
144+
config: `
145+
roxie:
146+
version: 1.2.3
147+
securedCluster:
148+
spec:
149+
foo: bar
150+
`,
151+
args: []string{"--config", configFilePath},
152+
assert: func(t *testing.T, cfg deployer.Config) {
153+
assert.Equal(t, "1.2.3", cfg.Roxie.Version, "Roxie.Version mismatch")
154+
assert.True(t,
155+
reflect.DeepEqual(cfg.SecuredCluster.Spec,
156+
map[string]interface{}{
157+
"foo": "bar",
158+
}),
159+
"SecuredCluster.Spec mismatch",
160+
)
161+
},
162+
},
163+
164+
{
165+
name: "flags can override earlier specified config file",
166+
config: `
167+
central:
168+
resourceProfile: small
169+
portForwarding: true
170+
`,
171+
args: []string{"--config", configFilePath, "--port-forwarding=false", "--resources=medium"},
172+
assert: func(t *testing.T, cfg deployer.Config) {
173+
assert.Equal(t, types.ResourceProfileMedium, cfg.Central.ResourceProfile, "Central.ResourceProfile mismatch")
174+
require.NotNil(t, cfg.Central.PortForwarding, "Central.PortForwarding should be set")
175+
assert.False(t, *cfg.Central.PortForwarding, "Central.PortForwarding mismatch")
176+
},
177+
},
178+
179+
{
180+
name: "set expressions can be used",
181+
args: []string{"--set", "roxie.version=0.99.1", "--set", "central.deployTimeout=4m", "--set", "securedCluster.spec.clusterName=foo"},
182+
assert: func(t *testing.T, cfg deployer.Config) {
183+
assert.Equal(t, "0.99.1", cfg.Roxie.Version, "version mismatch")
184+
assert.Equal(t, 4*time.Minute, cfg.Central.DeployTimeout, "Central.DeployTimeout mismatch")
185+
assert.Equal(t,
186+
map[string]interface{}{
187+
"clusterName": "foo",
188+
},
189+
cfg.SecuredCluster.Spec,
190+
"SecuredCluster.Spec mismatch",
191+
)
192+
},
193+
},
194+
}
195+
196+
for _, tt := range tests {
197+
t.Run(tt.name, func(t *testing.T) {
198+
if tt.config != "" {
199+
require.NoError(t, os.WriteFile(configFilePath, []byte(tt.config), 0o644))
200+
}
201+
cfg := deployer.NewConfig()
202+
cmd := newDeployCmd(&cfg)
203+
require.NoError(t, cmd.ParseFlags(tt.args))
204+
tt.assert(t, cfg)
205+
})
206+
}
207+
}

cmd/flags.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package main
2+
3+
import (
4+
"time"
5+
6+
"github.com/spf13/cobra"
7+
"github.com/stackrox/roxie/internal/deployer"
8+
"gopkg.in/yaml.v3"
9+
)
10+
11+
type cliFlag struct {
12+
config *deployer.Config
13+
longName string
14+
shortName string
15+
flagType string
16+
applyFn func(config *deployer.Config, val string) error
17+
noOptDefVal string
18+
description string
19+
}
20+
21+
type flagOpt func(opts *cliFlag)
22+
23+
func (f *cliFlag) Set(val string) error {
24+
return f.applyFn(f.config, val)
25+
}
26+
27+
func (f *cliFlag) String() string {
28+
return "" // Not sure what to return here.
29+
}
30+
31+
func (f *cliFlag) Type() string {
32+
return f.flagType
33+
}
34+
35+
func withApplyFnBool(boolApplyFn func(config *deployer.Config, val bool) error) flagOpt {
36+
return func(opts *cliFlag) {
37+
opts.flagType = "bool"
38+
opts.applyFn = func(config *deployer.Config, val string) error {
39+
var valParsed bool
40+
if err := yaml.Unmarshal([]byte(val), &valParsed); err != nil {
41+
return err
42+
}
43+
return boolApplyFn(config, valParsed)
44+
}
45+
}
46+
}
47+
48+
func withApplyFn(flagType string, stringApplyFn func(config *deployer.Config, val string) error) flagOpt {
49+
return func(opts *cliFlag) {
50+
opts.flagType = flagType
51+
opts.applyFn = func(config *deployer.Config, val string) error {
52+
return stringApplyFn(config, val)
53+
}
54+
}
55+
}
56+
57+
func withApplyFnDuration(durationApplyFn func(config *deployer.Config, duration time.Duration) error) flagOpt {
58+
return func(opts *cliFlag) {
59+
opts.flagType = "duration"
60+
opts.applyFn = func(config *deployer.Config, val string) error {
61+
var duration time.Duration
62+
duration, err := time.ParseDuration(val)
63+
if err != nil {
64+
return err
65+
}
66+
return durationApplyFn(config, duration)
67+
}
68+
}
69+
}
70+
71+
func withNoOptDefVal(defVal string) flagOpt {
72+
return func(opts *cliFlag) {
73+
opts.noOptDefVal = defVal
74+
}
75+
}
76+
77+
func withShortName(shortName string) flagOpt {
78+
return func(opts *cliFlag) {
79+
opts.shortName = shortName
80+
}
81+
}
82+
83+
func registerFlag(cmd *cobra.Command, settings *deployer.Config, longName string, description string, flagOpts ...flagOpt) {
84+
f := cliFlag{
85+
config: settings,
86+
longName: longName,
87+
description: description,
88+
}
89+
for _, applyOpt := range flagOpts {
90+
applyOpt(&f)
91+
}
92+
flag := cmd.Flags().VarPF(&f, f.longName, f.shortName, f.description)
93+
if f.noOptDefVal != "" {
94+
flag.NoOptDefVal = f.noOptDefVal
95+
}
96+
}

cmd/main.go

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,18 @@ import (
55

66
"github.com/fatih/color"
77
"github.com/spf13/cobra"
8+
"github.com/stackrox/roxie/internal/deployer"
89
)
910

1011
var (
1112
// Global flags
12-
verbose bool
13-
earlyReadiness bool
14-
olm bool
15-
konflux bool
16-
deployOperator bool
17-
portForwarding bool
18-
pauseReconciliation bool
19-
overrideFile string
20-
overrideSetExpressions []string
21-
exposure string
22-
resources string
23-
shell string
24-
envrc string
25-
singleNamespace bool
26-
tag string
27-
featureFlags []string
28-
centralWait string
29-
securedClusterWait string
13+
verbose bool
14+
shell string
15+
envrc string
16+
dryRun bool
17+
18+
// We need this set up before command line flags are parsed.
19+
deploySettings = deployer.NewConfig()
3020
)
3121

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

4939
func init() {
5040
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Enable verbose output (show CRs)")
51-
rootCmd.PersistentFlags().BoolVar(&earlyReadiness, "early-readiness", true, "Only wait for essential workloads (central/sensor) to be ready")
52-
rootCmd.AddCommand(newDeployCmd())
53-
rootCmd.AddCommand(newTeardownCmd())
41+
rootCmd.PersistentFlags().BoolVar(&dryRun, "dry-run", false, "Do not actually modify cluster")
42+
rootCmd.AddCommand(newDeployCmd(&deploySettings))
43+
rootCmd.AddCommand(newTeardownCmd(&deploySettings))
5444
rootCmd.AddCommand(newVersionCmd())
5545
rootCmd.AddCommand(newEnvCmd())
5646
rootCmd.AddCommand(newLogsCmd())

0 commit comments

Comments
 (0)