Skip to content

Commit 2f57a48

Browse files
author
Andrew Suderman
committed
Fix namespace management
1 parent 3d5f94e commit 2f57a48

File tree

5 files changed

+478
-42
lines changed

5 files changed

+478
-42
lines changed

pkg/course/course.go

+4-42
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ type FileV2 struct {
6262
// Hooks is a set of scripts to be run before or after the release is installed.
6363
Hooks Hooks `yaml:"hooks,omitempty" json:"hooks,omitempty"`
6464
// NamespaceMgmt contains the default namespace config for all namespaces managed by this course.
65-
NamespaceMgmt NamespaceMgmt `yaml:"namespace_management,omitempty" json:"namespace_management,omitempty"`
66-
Secrets SecretsList `yaml:"secrets,omitempty" json:"secrets,omitempty"`
65+
NamespaceMgmt *NamespaceMgmt `yaml:"namespace_management,omitempty" json:"namespace_management,omitempty"`
66+
Secrets SecretsList `yaml:"secrets,omitempty" json:"secrets,omitempty"`
6767
// Releases is the list of releases that should be maintained by this course file.
6868
Releases []*Release `yaml:"releases,omitempty" json:"releases,omitempty"`
6969
// HelmArgs is a list of arguments to pass to helm commands
@@ -192,11 +192,8 @@ type FileV1 struct {
192192
// Hooks is a set of scripts to be run before or after the release is installed.
193193
Hooks Hooks `yaml:"hooks" json:"hooks"`
194194
// NamespaceMgmt contains the default namespace config for all namespaces managed by this course.
195-
NamespaceMgmt struct {
196-
// Default is the default namespace config for this course
197-
Default *NamespaceConfig `yaml:"default" json:"default"`
198-
} `yaml:"namespace_management" json:"namespace_management"`
199-
Secrets SecretsList `yaml:"secrets,omitempty" json:"secrets,omitempty"`
195+
NamespaceMgmt *NamespaceMgmt `yaml:"namespace_management" json:"namespace_management"`
196+
Secrets SecretsList `yaml:"secrets,omitempty" json:"secrets,omitempty"`
200197
// Charts is the list of releases. In the actual file this will be a map, but we must convert to a list to preserve order.
201198
// This conversion is done in the ChartsListV1 UnmarshalYAML function.
202199
Charts ChartsListV1 `yaml:"charts" json:"charts"`
@@ -549,41 +546,6 @@ func (f *FileV2) populateEmptyChartNames() {
549546
}
550547
}
551548

552-
// populateNamespaceManagement populates each release with the default namespace management settings if they are not set
553-
func (f *FileV2) populateNamespaceManagement() {
554-
var emptyNamespaceMgmt NamespaceConfig
555-
if f.NamespaceMgmt.Default == nil {
556-
f.NamespaceMgmt.Default = &emptyNamespaceMgmt
557-
f.NamespaceMgmt.Default.Settings.Overwrite = boolPtr(false)
558-
} else if f.NamespaceMgmt.Default.Settings.Overwrite == nil {
559-
f.NamespaceMgmt.Default.Settings.Overwrite = boolPtr(false)
560-
}
561-
for releaseIndex, release := range f.Releases {
562-
if release.NamespaceMgmt == nil {
563-
klog.V(5).Infof("using default namespace management for release: %s", release.Name)
564-
release.NamespaceMgmt = f.NamespaceMgmt.Default
565-
f.Releases[releaseIndex] = release
566-
} else {
567-
release.NamespaceMgmt = mergeNamespaceManagement(f.NamespaceMgmt.Default, release.NamespaceMgmt)
568-
}
569-
}
570-
}
571-
572-
func mergeNamespaceManagement(defaults *NamespaceConfig, mergeInto *NamespaceConfig) *NamespaceConfig {
573-
d := defaults
574-
for k, v := range mergeInto.Metadata.Annotations {
575-
d.Metadata.Annotations[k] = v
576-
}
577-
for k, v := range mergeInto.Metadata.Labels {
578-
d.Metadata.Labels[k] = v
579-
}
580-
if mergeInto.Settings.Overwrite != nil {
581-
d.Settings.Overwrite = mergeInto.Settings.Overwrite
582-
}
583-
mergeInto = d
584-
return mergeInto
585-
}
586-
587549
func (f *FileV2) validateJsonSchema(schemaData []byte) error {
588550
klog.V(10).Infof("validating course file against schema: \n%s", string(schemaData))
589551
schema, err := gojsonschema.NewSchema(gojsonschema.NewBytesLoader(schemaData))

pkg/course/namespace.go

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package course
2+
3+
import (
4+
"k8s.io/klog/v2"
5+
)
6+
7+
// populateNamespaceManagement populates each release with the default namespace management settings if they are not set
8+
func (f *FileV2) populateNamespaceManagement() {
9+
var emptyNamespaceMgmt NamespaceConfig
10+
if f.NamespaceMgmt == nil {
11+
f.NamespaceMgmt = &NamespaceMgmt{}
12+
}
13+
if f.NamespaceMgmt.Default == nil {
14+
f.NamespaceMgmt.Default = &emptyNamespaceMgmt
15+
f.NamespaceMgmt.Default.Settings.Overwrite = boolPtr(false)
16+
} else if f.NamespaceMgmt.Default.Settings.Overwrite == nil {
17+
f.NamespaceMgmt.Default.Settings.Overwrite = boolPtr(false)
18+
}
19+
20+
for releaseIndex, release := range f.Releases {
21+
newRelease := *release
22+
if newRelease.NamespaceMgmt == nil {
23+
klog.V(5).Infof("using default namespace management for release: %s", release.Name)
24+
newRelease.NamespaceMgmt = f.NamespaceMgmt.Default
25+
} else {
26+
newRelease.NamespaceMgmt = mergeNamespaceManagement(*f.NamespaceMgmt.Default, *newRelease.NamespaceMgmt)
27+
28+
}
29+
f.Releases[releaseIndex] = &newRelease
30+
}
31+
}
32+
33+
// mergeNamespaceManagement merges the default namespace management settings with the release specific settings
34+
func mergeNamespaceManagement(defaults NamespaceConfig, mergeInto NamespaceConfig) *NamespaceConfig {
35+
for k, v := range defaults.Metadata.Annotations {
36+
if mergeInto.Metadata.Annotations == nil {
37+
mergeInto.Metadata.Annotations = map[string]string{}
38+
}
39+
if mergeInto.Metadata.Annotations[k] == "" {
40+
mergeInto.Metadata.Annotations[k] = v
41+
}
42+
}
43+
44+
for k, v := range defaults.Metadata.Labels {
45+
if mergeInto.Metadata.Labels == nil {
46+
mergeInto.Metadata.Labels = map[string]string{}
47+
}
48+
if mergeInto.Metadata.Labels[k] == "" {
49+
mergeInto.Metadata.Labels[k] = v
50+
}
51+
}
52+
53+
if mergeInto.Settings.Overwrite == nil {
54+
mergeInto.Settings.Overwrite = defaults.Settings.Overwrite
55+
}
56+
57+
return &mergeInto
58+
}

pkg/course/namespace_test.go

+252
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
package course
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func Test_mergeNamespaceManagement(t *testing.T) {
10+
type args struct {
11+
defaults NamespaceConfig
12+
mergeInto NamespaceConfig
13+
}
14+
tests := []struct {
15+
name string
16+
args args
17+
want *NamespaceConfig
18+
}{
19+
{
20+
name: "basic merge",
21+
args: args{
22+
defaults: NamespaceConfig{
23+
Metadata: NSMetadata{
24+
Annotations: map[string]string{
25+
"default-annotation": "default-value",
26+
},
27+
Labels: map[string]string{
28+
"default-label": "default-value",
29+
},
30+
},
31+
Settings: NSSettings{
32+
Overwrite: boolPtr(false),
33+
},
34+
},
35+
mergeInto: NamespaceConfig{
36+
Metadata: NSMetadata{
37+
Annotations: map[string]string{
38+
"merge-annotation": "merge-value",
39+
},
40+
Labels: map[string]string{
41+
"merge-label": "merge-value",
42+
},
43+
},
44+
Settings: NSSettings{
45+
Overwrite: boolPtr(false),
46+
},
47+
},
48+
},
49+
want: &NamespaceConfig{
50+
Metadata: NSMetadata{
51+
Annotations: map[string]string{
52+
"default-annotation": "default-value",
53+
"merge-annotation": "merge-value",
54+
},
55+
Labels: map[string]string{
56+
"default-label": "default-value",
57+
"merge-label": "merge-value",
58+
},
59+
},
60+
Settings: NSSettings{
61+
Overwrite: boolPtr(false),
62+
},
63+
},
64+
},
65+
}
66+
for _, tt := range tests {
67+
t.Run(tt.name, func(t *testing.T) {
68+
got := mergeNamespaceManagement(tt.args.defaults, tt.args.mergeInto)
69+
assert.EqualValues(t, tt.want, got)
70+
})
71+
}
72+
}
73+
74+
func TestFileV2_populateNamespaceManagement(t *testing.T) {
75+
tests := []struct {
76+
name string
77+
file *FileV2
78+
want *FileV2
79+
}{
80+
{
81+
name: "empty default",
82+
file: &FileV2{
83+
Releases: []*Release{},
84+
NamespaceMgmt: &NamespaceMgmt{},
85+
},
86+
want: &FileV2{
87+
NamespaceMgmt: &NamespaceMgmt{
88+
Default: &NamespaceConfig{
89+
Settings: NSSettings{
90+
Overwrite: boolPtr(false),
91+
},
92+
},
93+
},
94+
Releases: []*Release{},
95+
},
96+
},
97+
{
98+
name: "empty default overwrite",
99+
file: &FileV2{
100+
Releases: []*Release{},
101+
NamespaceMgmt: &NamespaceMgmt{
102+
Default: &NamespaceConfig{
103+
Settings: NSSettings{
104+
Overwrite: nil,
105+
},
106+
},
107+
},
108+
},
109+
want: &FileV2{
110+
NamespaceMgmt: &NamespaceMgmt{
111+
Default: &NamespaceConfig{
112+
Settings: NSSettings{
113+
Overwrite: boolPtr(false),
114+
},
115+
},
116+
},
117+
Releases: []*Release{},
118+
},
119+
},
120+
{
121+
name: "release default",
122+
file: &FileV2{
123+
Releases: []*Release{
124+
{
125+
Name: "default",
126+
},
127+
},
128+
NamespaceMgmt: &NamespaceMgmt{
129+
Default: nil,
130+
},
131+
},
132+
want: &FileV2{
133+
NamespaceMgmt: &NamespaceMgmt{
134+
Default: &NamespaceConfig{
135+
Settings: NSSettings{
136+
Overwrite: boolPtr(false),
137+
},
138+
},
139+
},
140+
Releases: []*Release{
141+
{
142+
Name: "default",
143+
NamespaceMgmt: &NamespaceConfig{
144+
Settings: NSSettings{
145+
Overwrite: boolPtr(false),
146+
},
147+
},
148+
},
149+
},
150+
},
151+
},
152+
{
153+
name: "release specific",
154+
file: &FileV2{
155+
Releases: []*Release{
156+
{
157+
Name: "default",
158+
NamespaceMgmt: &NamespaceConfig{
159+
Settings: NSSettings{
160+
Overwrite: boolPtr(false),
161+
},
162+
Metadata: NSMetadata{
163+
Annotations: map[string]string{
164+
"release-annotation": "release-value",
165+
},
166+
Labels: map[string]string{
167+
"release-label": "release-value",
168+
},
169+
},
170+
},
171+
},
172+
{
173+
Name: "release2",
174+
NamespaceMgmt: &NamespaceConfig{},
175+
},
176+
},
177+
NamespaceMgmt: &NamespaceMgmt{
178+
Default: &NamespaceConfig{
179+
Settings: NSSettings{},
180+
Metadata: NSMetadata{
181+
Annotations: map[string]string{
182+
"course-annotation": "course-value",
183+
},
184+
Labels: map[string]string{
185+
"course-label": "course-value",
186+
},
187+
},
188+
},
189+
},
190+
},
191+
want: &FileV2{
192+
NamespaceMgmt: &NamespaceMgmt{
193+
Default: &NamespaceConfig{
194+
Settings: NSSettings{
195+
Overwrite: boolPtr(false),
196+
},
197+
Metadata: NSMetadata{
198+
Annotations: map[string]string{
199+
"course-annotation": "course-value",
200+
},
201+
Labels: map[string]string{
202+
"course-label": "course-value",
203+
},
204+
},
205+
},
206+
},
207+
Releases: []*Release{
208+
{
209+
Name: "default",
210+
NamespaceMgmt: &NamespaceConfig{
211+
Settings: NSSettings{
212+
Overwrite: boolPtr(false),
213+
},
214+
Metadata: NSMetadata{
215+
Annotations: map[string]string{
216+
"course-annotation": "course-value",
217+
"release-annotation": "release-value",
218+
},
219+
Labels: map[string]string{
220+
"course-label": "course-value",
221+
"release-label": "release-value",
222+
},
223+
},
224+
},
225+
},
226+
{
227+
Name: "release2",
228+
NamespaceMgmt: &NamespaceConfig{
229+
Settings: NSSettings{
230+
Overwrite: boolPtr(false),
231+
},
232+
Metadata: NSMetadata{
233+
Annotations: map[string]string{
234+
"course-annotation": "course-value",
235+
},
236+
Labels: map[string]string{
237+
"course-label": "course-value",
238+
},
239+
},
240+
},
241+
},
242+
},
243+
},
244+
},
245+
}
246+
for _, tt := range tests {
247+
t.Run(tt.name, func(t *testing.T) {
248+
tt.file.populateNamespaceManagement()
249+
assert.EqualValues(t, tt.want, tt.file)
250+
})
251+
}
252+
}

0 commit comments

Comments
 (0)