Skip to content

Commit 42a6816

Browse files
authored
[Feature] Add HostPath and PVC Volume types and allow templating (#990)
1 parent 8110293 commit 42a6816

File tree

10 files changed

+525
-19
lines changed

10 files changed

+525
-19
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- (Feature) Add agency leader discovery
1212
- (Feature) Add `ACSDeploymentSynced` condition type and fix comparison of `SecretHashes` method
1313
- (Feature) Add agency leader service
14+
- (Feature) Add HostPath and PVC Volume types and allow templating
1415

1516
## [1.2.12](https://github.com/arangodb/kube-arangodb/tree/1.2.12) (2022-05-10)
1617
- (Feature) Add CoreV1 Endpoints Inspector

pkg/apis/deployment/v1/server_group_volume.go

Lines changed: 170 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
sharedv1 "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1"
3030

3131
core "k8s.io/api/core/v1"
32+
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
3233
)
3334

3435
var (
@@ -44,6 +45,14 @@ var (
4445
}
4546
)
4647

48+
const (
49+
ServerGroupSpecVolumeRenderParamDeploymentName = "DEPLOYMENT_NAME"
50+
ServerGroupSpecVolumeRenderParamDeploymentNamespace = "DEPLOYMENT_NAMESPACE"
51+
ServerGroupSpecVolumeRenderParamMemberID = "MEMBER_ID"
52+
ServerGroupSpecVolumeRenderParamMemberRoleAbbr = "ROLE_ABBR"
53+
ServerGroupSpecVolumeRenderParamMemberRole = "ROLE"
54+
)
55+
4756
// IsRestrictedVolumeName check of volume name is restricted, for example for originally mounted volumes
4857
func IsRestrictedVolumeName(name string) bool {
4958
for _, restrictedVolumeName := range restrictedVolumeNames {
@@ -91,6 +100,17 @@ func (s ServerGroupSpecVolumes) Validate() error {
91100
return shared.WithErrors(validationErrors...)
92101
}
93102

103+
// RenderVolumes render volumes
104+
func (s ServerGroupSpecVolumes) RenderVolumes(depl meta.Object, group ServerGroup, member MemberStatus) []core.Volume {
105+
volumes := make([]core.Volume, len(s))
106+
107+
for id, volume := range s {
108+
volumes[id] = volume.RenderVolume(depl, group, member)
109+
}
110+
111+
return volumes
112+
}
113+
94114
// Volumes create volumes
95115
func (s ServerGroupSpecVolumes) Volumes() []core.Volume {
96116
volumes := make([]core.Volume, len(s))
@@ -115,6 +135,12 @@ type ServerGroupSpecVolume struct {
115135

116136
// EmptyDir
117137
EmptyDir *ServerGroupSpecVolumeEmptyDir `json:"emptyDir,omitempty"`
138+
139+
// HostPath
140+
HostPath *ServerGroupSpecVolumeHostPath `json:"hostPath,omitempty"`
141+
142+
// PersistentVolumeClaim
143+
PersistentVolumeClaim *ServerGroupSpecVolumePersistentVolumeClaim `json:"persistentVolumeClaim,omitempty"`
118144
}
119145

120146
// Validate if ServerGroupSpec volume is valid
@@ -128,18 +154,36 @@ func (s *ServerGroupSpecVolume) Validate() error {
128154
shared.PrefixResourceErrors("secret", s.Secret.Validate()),
129155
shared.PrefixResourceErrors("configMap", s.ConfigMap.Validate()),
130156
shared.PrefixResourceErrors("emptyDir", s.EmptyDir.Validate()),
157+
shared.PrefixResourceErrors("hostPath", s.HostPath.Validate()),
158+
shared.PrefixResourceErrors("persistentVolumeClaim", s.PersistentVolumeClaim.Validate()),
131159
s.validate(),
132160
)
133161
}
134162

163+
// RenderVolume create Pod Volume object with dynamic names
164+
func (s ServerGroupSpecVolume) RenderVolume(depl meta.Object, group ServerGroup, member MemberStatus) core.Volume {
165+
return core.Volume{
166+
Name: s.Name,
167+
VolumeSource: core.VolumeSource{
168+
ConfigMap: s.ConfigMap.render(depl, group, member),
169+
Secret: s.Secret.render(depl, group, member),
170+
EmptyDir: s.EmptyDir.render(),
171+
HostPath: s.HostPath.render(depl, group, member),
172+
PersistentVolumeClaim: s.PersistentVolumeClaim.render(depl, group, member),
173+
},
174+
}
175+
}
176+
135177
// Volume create Pod Volume object
136178
func (s ServerGroupSpecVolume) Volume() core.Volume {
137179
return core.Volume{
138180
Name: s.Name,
139181
VolumeSource: core.VolumeSource{
140-
ConfigMap: (*core.ConfigMapVolumeSource)(s.ConfigMap),
141-
Secret: (*core.SecretVolumeSource)(s.Secret),
142-
EmptyDir: (*core.EmptyDirVolumeSource)(s.EmptyDir),
182+
ConfigMap: (*core.ConfigMapVolumeSource)(s.ConfigMap),
183+
Secret: (*core.SecretVolumeSource)(s.Secret),
184+
EmptyDir: (*core.EmptyDirVolumeSource)(s.EmptyDir),
185+
HostPath: (*core.HostPathVolumeSource)(s.HostPath),
186+
PersistentVolumeClaim: (*core.PersistentVolumeClaimVolumeSource)(s.PersistentVolumeClaim),
143187
},
144188
}
145189
}
@@ -173,35 +217,154 @@ func (s *ServerGroupSpecVolume) notNilFields() int {
173217
i++
174218
}
175219

220+
if s.HostPath != nil {
221+
i++
222+
}
223+
224+
if s.PersistentVolumeClaim != nil {
225+
i++
226+
}
227+
176228
return i
177229
}
178230

231+
func renderVolumeResourceName(in string, depl meta.Object, group ServerGroup, member MemberStatus) string {
232+
return shared.RenderResourceName(in, map[string]string{
233+
ServerGroupSpecVolumeRenderParamDeploymentName: depl.GetName(),
234+
ServerGroupSpecVolumeRenderParamDeploymentNamespace: depl.GetNamespace(),
235+
ServerGroupSpecVolumeRenderParamMemberID: shared.StripArangodPrefix(member.ID),
236+
ServerGroupSpecVolumeRenderParamMemberRole: group.AsRole(),
237+
ServerGroupSpecVolumeRenderParamMemberRoleAbbr: group.AsRoleAbbreviated(),
238+
})
239+
}
240+
179241
type ServerGroupSpecVolumeSecret core.SecretVolumeSource
180242

181243
func (s *ServerGroupSpecVolumeSecret) Validate() error {
182-
if s == nil {
244+
q := s.render(&ArangoDeployment{
245+
ObjectMeta: meta.ObjectMeta{
246+
Name: "render",
247+
Namespace: "render",
248+
},
249+
}, ServerGroupSingle, MemberStatus{
250+
ID: "render",
251+
})
252+
253+
if q == nil {
183254
return nil
184255
}
185256

186257
return shared.WithErrors(
187-
shared.PrefixResourceError("secretName", sharedv1.AsKubernetesResourceName(&s.SecretName).Validate()),
258+
shared.PrefixResourceError("secretName", sharedv1.AsKubernetesResourceName(&q.SecretName).Validate()),
188259
)
189260
}
190261

262+
func (s *ServerGroupSpecVolumeSecret) render(depl meta.Object, group ServerGroup, member MemberStatus) *core.SecretVolumeSource {
263+
if s == nil {
264+
return nil
265+
}
266+
267+
var obj = core.SecretVolumeSource(*s)
268+
269+
obj.SecretName = renderVolumeResourceName(obj.SecretName, depl, group, member)
270+
271+
return &obj
272+
}
273+
191274
type ServerGroupSpecVolumeConfigMap core.ConfigMapVolumeSource
192275

193276
func (s *ServerGroupSpecVolumeConfigMap) Validate() error {
194-
if s == nil {
277+
q := s.render(&ArangoDeployment{
278+
ObjectMeta: meta.ObjectMeta{
279+
Name: "render",
280+
Namespace: "render",
281+
},
282+
}, ServerGroupSingle, MemberStatus{
283+
ID: "render",
284+
})
285+
286+
if q == nil {
195287
return nil
196288
}
197289

198290
return shared.WithErrors(
199-
shared.PrefixResourceError("name", sharedv1.AsKubernetesResourceName(&s.Name).Validate()),
291+
shared.PrefixResourceError("name", sharedv1.AsKubernetesResourceName(&q.Name).Validate()),
200292
)
201293
}
202294

295+
func (s *ServerGroupSpecVolumeConfigMap) render(depl meta.Object, group ServerGroup, member MemberStatus) *core.ConfigMapVolumeSource {
296+
if s == nil {
297+
return nil
298+
}
299+
300+
var obj = core.ConfigMapVolumeSource(*s)
301+
302+
obj.Name = renderVolumeResourceName(obj.Name, depl, group, member)
303+
304+
return &obj
305+
}
306+
203307
type ServerGroupSpecVolumeEmptyDir core.EmptyDirVolumeSource
204308

205309
func (s *ServerGroupSpecVolumeEmptyDir) Validate() error {
206310
return nil
207311
}
312+
313+
func (s *ServerGroupSpecVolumeEmptyDir) render() *core.EmptyDirVolumeSource {
314+
if s == nil {
315+
return nil
316+
}
317+
318+
return (*core.EmptyDirVolumeSource)(s)
319+
}
320+
321+
type ServerGroupSpecVolumeHostPath core.HostPathVolumeSource
322+
323+
func (s *ServerGroupSpecVolumeHostPath) Validate() error {
324+
return nil
325+
}
326+
327+
func (s *ServerGroupSpecVolumeHostPath) render(depl meta.Object, group ServerGroup, member MemberStatus) *core.HostPathVolumeSource {
328+
if s == nil {
329+
return nil
330+
}
331+
332+
var obj = core.HostPathVolumeSource(*s)
333+
334+
obj.Path = renderVolumeResourceName(obj.Path, depl, group, member)
335+
336+
return &obj
337+
}
338+
339+
type ServerGroupSpecVolumePersistentVolumeClaim core.PersistentVolumeClaimVolumeSource
340+
341+
func (s *ServerGroupSpecVolumePersistentVolumeClaim) Validate() error {
342+
q := s.render(&ArangoDeployment{
343+
ObjectMeta: meta.ObjectMeta{
344+
Name: "render",
345+
Namespace: "render",
346+
},
347+
}, ServerGroupSingle, MemberStatus{
348+
ID: "render",
349+
})
350+
351+
if q == nil {
352+
return nil
353+
}
354+
355+
return shared.WithErrors(
356+
shared.PrefixResourceError("claimName", sharedv1.AsKubernetesResourceName(&q.ClaimName).Validate()),
357+
)
358+
}
359+
360+
func (s *ServerGroupSpecVolumePersistentVolumeClaim) render(depl meta.Object, group ServerGroup, member MemberStatus) *core.PersistentVolumeClaimVolumeSource {
361+
if s == nil {
362+
return nil
363+
}
364+
365+
var obj = core.PersistentVolumeClaimVolumeSource(*s)
366+
367+
obj.ClaimName = renderVolumeResourceName(obj.ClaimName, depl, group, member)
368+
369+
return &obj
370+
}

pkg/apis/deployment/v1/server_group_volume_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,43 @@ func Test_Volume_Validation(t *testing.T) {
146146
},
147147
},
148148
},
149+
{
150+
name: "Templating",
151+
volumes: []ServerGroupSpecVolume{
152+
{
153+
Name: validName,
154+
Secret: &ServerGroupSpecVolumeSecret{
155+
SecretName: fmt.Sprintf("${%s}-secret", ServerGroupSpecVolumeRenderParamDeploymentName),
156+
},
157+
},
158+
},
159+
},
160+
{
161+
name: "Invalid templating",
162+
volumes: []ServerGroupSpecVolume{
163+
{
164+
Name: validName,
165+
Secret: &ServerGroupSpecVolumeSecret{
166+
SecretName: fmt.Sprintf("${%sRANDOM}-secret", ServerGroupSpecVolumeRenderParamDeploymentName),
167+
},
168+
},
169+
},
170+
fail: true,
171+
failedFields: map[string]string{
172+
"0.secret.secretName": labelValidationError,
173+
},
174+
},
175+
{
176+
name: "Templating with group name",
177+
volumes: []ServerGroupSpecVolume{
178+
{
179+
Name: validName,
180+
Secret: &ServerGroupSpecVolumeSecret{
181+
SecretName: fmt.Sprintf("${%s}-${%s}-${%s}-cache", ServerGroupSpecVolumeRenderParamDeploymentName, ServerGroupSpecVolumeRenderParamMemberRole, ServerGroupSpecVolumeRenderParamMemberID),
182+
},
183+
},
184+
},
185+
},
149186
}
150187

151188
for _, c := range cases {

pkg/apis/deployment/v1/zz_generated.deepcopy.go

Lines changed: 47 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/apis/deployment/v2alpha1/plan.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ const (
192192
// Rebalancer
193193
ActionTypeRebalancerGenerate ActionType = "RebalancerGenerate"
194194
ActionTypeRebalancerCheck ActionType = "RebalancerCheck"
195+
196+
// Resources
197+
ActionTypeResourceSync ActionType = "ResourceSync"
195198
)
196199

197200
const (

0 commit comments

Comments
 (0)