Skip to content

Commit 83d1b97

Browse files
author
lamai93
committed
First draft of volume claim templates.
1 parent 1a986ea commit 83d1b97

File tree

12 files changed

+170
-42
lines changed

12 files changed

+170
-42
lines changed

pkg/apis/deployment/v1alpha/server_group_spec.go

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ type ServerGroupSpec struct {
6060
Probes *ServerGroupProbesSpec `json:"probes,omitempty"`
6161
// PriorityClassName specifies a priority class name
6262
PriorityClassName string `json:"priorityClassName,omitempty"`
63+
// VolumeClaimTemplate specifies a template for volume claims
64+
VolumeClaimTemplate *v1.PersistentVolumeClaim `json:"volumeClaimTemplate,omitempty"`
6365
}
6466

6567
// ServerGroupProbesSpec contains specification for probes for pods of the server group
@@ -94,6 +96,16 @@ func (s ServerGroupProbesSpec) IsReadinessProbeDisabled() bool {
9496
return util.BoolOrDefault(s.ReadinessProbeDisabled)
9597
}
9698

99+
// HasVolumeClaimTemplate returns whether there is a volumeClaimTemplate or not
100+
func (s ServerGroupSpec) HasVolumeClaimTemplate() bool {
101+
return s.VolumeClaimTemplate != nil
102+
}
103+
104+
// GetVolumeClaimTemplate returns a pointer to a volume claim template or nil if none is specified
105+
func (s ServerGroupSpec) GetVolumeClaimTemplate() *v1.PersistentVolumeClaim {
106+
return s.VolumeClaimTemplate
107+
}
108+
97109
// GetCount returns the value of count.
98110
func (s ServerGroupSpec) GetCount() int {
99111
return util.IntOrDefault(s.Count)
@@ -236,13 +248,25 @@ func (s *ServerGroupSpec) SetDefaults(group ServerGroup, used bool, mode Deploym
236248
s.MinCount = nil
237249
s.MaxCount = nil
238250
}
239-
if _, found := s.Resources.Requests[v1.ResourceStorage]; !found {
240-
switch group {
241-
case ServerGroupSingle, ServerGroupAgents, ServerGroupDBServers:
242-
if s.Resources.Requests == nil {
243-
s.Resources.Requests = make(map[v1.ResourceName]resource.Quantity)
251+
if !s.HasVolumeClaimTemplate() {
252+
if _, found := s.Resources.Requests[v1.ResourceStorage]; !found {
253+
switch group {
254+
case ServerGroupSingle, ServerGroupAgents, ServerGroupDBServers:
255+
volumeMode := v1.PersistentVolumeFilesystem
256+
s.VolumeClaimTemplate = &v1.PersistentVolumeClaim{
257+
Spec: v1.PersistentVolumeClaimSpec{
258+
AccessModes: []v1.PersistentVolumeAccessMode{
259+
v1.ReadWriteOnce,
260+
},
261+
VolumeMode: &volumeMode,
262+
Resources: v1.ResourceRequirements{
263+
Requests: v1.ResourceList{
264+
v1.ResourceStorage: resource.MustParse("8Gi"),
265+
},
266+
},
267+
},
268+
}
244269
}
245-
s.Resources.Requests[v1.ResourceStorage] = resource.MustParse("8Gi")
246270
}
247271
}
248272
}
@@ -287,6 +311,9 @@ func (s *ServerGroupSpec) SetDefaultsFrom(source ServerGroupSpec) {
287311
}
288312
setDefaultsFromResourceList(&s.Resources.Limits, source.Resources.Limits)
289313
setDefaultsFromResourceList(&s.Resources.Requests, source.Resources.Requests)
314+
if s.VolumeClaimTemplate == nil {
315+
s.VolumeClaimTemplate = source.VolumeClaimTemplate.DeepCopy()
316+
}
290317
}
291318

292319
// ResetImmutableFields replaces all immutable fields in the given target with values from the source spec.
@@ -299,5 +326,9 @@ func (s ServerGroupSpec) ResetImmutableFields(group ServerGroup, fieldPrefix str
299326
resetFields = append(resetFields, fieldPrefix+".count")
300327
}
301328
}
329+
if s.HasVolumeClaimTemplate() != target.HasVolumeClaimTemplate() {
330+
target.VolumeClaimTemplate = s.GetVolumeClaimTemplate()
331+
resetFields = append(resetFields, fieldPrefix+".volumeClaimTemplate")
332+
}
302333
return resetFields
303334
}

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

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

pkg/deployment/context_impl.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,23 @@ func (d *Deployment) UpdateStatus(status api.DeploymentStatus, lastVersion int32
118118
return nil
119119
}
120120

121+
// UpdateMember updates the deployment status wrt the given member.
122+
func (d *Deployment) UpdateMember(member api.MemberStatus) error {
123+
status, lastVersion := d.GetStatus()
124+
_, group, found := status.Members.ElementByID(member.ID)
125+
if !found {
126+
return maskAny(fmt.Errorf("Member %s not found", member.ID))
127+
}
128+
if err := status.Members.Update(member, group); err != nil {
129+
return maskAny(err)
130+
}
131+
if err := d.UpdateStatus(status, lastVersion); err != nil {
132+
log.Debug().Err(err).Msg("Updating CR status failed")
133+
return maskAny(err)
134+
}
135+
return nil
136+
}
137+
121138
// GetDatabaseClient returns a cached client for the entire database (cluster coordinators or single server),
122139
// creating one if needed.
123140
func (d *Deployment) GetDatabaseClient(ctx context.Context) (driver.Client, error) {

pkg/deployment/images.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ func (ib *imagesBuilder) fetchArangoDBImageIDAndVersion(ctx context.Context, ima
198198
}
199199
}
200200
if err := k8sutil.CreateArangodPod(ib.KubeCli, true, ib.APIObject, role, id, podName, "", image, "", "", ib.Spec.GetImagePullPolicy(), "", false, terminationGracePeriod, args, env, nil, nil, nil,
201-
tolerations, serviceAccountName, "", "", "", nil, "", v1.ResourceRequirements{}); err != nil {
201+
tolerations, serviceAccountName, "", "", "", nil, "", v1.ResourceRequirements{}, nil); err != nil {
202202
log.Debug().Err(err).Msg("Failed to create image ID pod")
203203
return true, maskAny(err)
204204
}

pkg/deployment/reconcile/context.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ type Context interface {
4646
// UpdateStatus replaces the status of the deployment with the given status and
4747
// updates the resources in k8s.
4848
UpdateStatus(status api.DeploymentStatus, lastVersion int32, force ...bool) error
49+
// UpdateMember updates the deployment status wrt the given member.
50+
UpdateMember(member api.MemberStatus) error
4951
// GetDatabaseClient returns a cached client for the entire database (cluster coordinators or single server),
5052
// creating one if needed.
5153
GetDatabaseClient(ctx context.Context) (driver.Client, error)

pkg/deployment/reconcile/plan_builder.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,9 +365,14 @@ func podNeedsRotation(log zerolog.Logger, p v1.Pod, apiObject metav1.Object, spe
365365
}
366366

367367
// Check resource requirements
368-
if resourcesRequireRotation(
369-
k8sutil.FilterStorageResourceRequirement(spec.GetServerGroupSpec(group).Resources),
370-
k8sutil.GetArangoDBContainerFromPod(&p).Resources) {
368+
var resources v1.ResourceRequirements
369+
if groupSpec.HasVolumeClaimTemplate() {
370+
resources = groupSpec.Resources // If there is a volume claim template compare all resources
371+
} else {
372+
resources = k8sutil.ExtractPodResourceRequirement(groupSpec.Resources)
373+
}
374+
375+
if resourcesRequireRotation(resources, k8sutil.GetArangoDBContainerFromPod(&p).Resources) {
371376
return true, "Resource Requirements changed"
372377
}
373378

pkg/deployment/reconcile/reconciler.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ func (r *Reconciler) CheckDeployment() error {
6363
r.log.Error().Err(err).Msg("Failed to delete pod")
6464
}
6565
m.Phase = api.MemberPhaseNone
66-
if err := status.Members.Update(m, api.ServerGroupCoordinators); err != nil {
66+
67+
if err := r.context.UpdateMember(m); err != nil {
6768
r.log.Error().Err(err).Msg("Failed to update member")
6869
}
6970
}

pkg/deployment/resources/pod_creator.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ func (r *Resources) createPodForMember(spec api.DeploymentSpec, memberID string,
609609
finalizers := r.createPodFinalizers(group)
610610
if err := k8sutil.CreateArangodPod(kubecli, spec.IsDevelopment(), apiObject, role, m.ID, m.PodName, m.PersistentVolumeClaimName, imageInfo.ImageID, lifecycleImage, alpineImage, spec.GetImagePullPolicy(),
611611
engine, requireUUID, terminationGracePeriod, args, env, finalizers, livenessProbe, readinessProbe, tolerations, serviceAccountName, tlsKeyfileSecretName, rocksdbEncryptionSecretName,
612-
clusterJWTSecretName, groupSpec.GetNodeSelector(), groupSpec.PriorityClassName, groupSpec.Resources); err != nil {
612+
clusterJWTSecretName, groupSpec.GetNodeSelector(), groupSpec.PriorityClassName, groupSpec.Resources, groupSpec.VolumeClaimTemplate); err != nil {
613613
return maskAny(err)
614614
}
615615
log.Debug().Str("pod-name", m.PodName).Msg("Created pod")
@@ -723,6 +723,7 @@ func (r *Resources) EnsurePods() error {
723723
imageNotFoundOnce := &sync.Once{}
724724
if err := iterator.ForeachServerGroup(func(group api.ServerGroup, groupSpec api.ServerGroupSpec, status *api.MemberStatusList) error {
725725
for _, m := range *status {
726+
r.log.Debug().Str("phase", string(m.Phase)).Str("pod", m.PodName).Msg("EnsurePods")
726727
if m.Phase != api.MemberPhaseNone {
727728
continue
728729
}

pkg/deployment/resources/pvc_inspector.go

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -83,24 +83,41 @@ func (r *Resources) InspectPVCs(ctx context.Context) (util.Interval, error) {
8383

8484
// Resize inspector
8585
groupSpec := spec.GetServerGroupSpec(group)
86-
if requestedSize, ok := groupSpec.Resources.Requests[apiv1.ResourceStorage]; ok {
87-
if volumeSize, ok := p.Spec.Resources.Requests[apiv1.ResourceStorage]; ok {
88-
cmp := volumeSize.Cmp(requestedSize)
89-
if cmp < 0 {
90-
// Size of the volume is smaller than the requested size
91-
// Update the pvc with the request size
92-
p.Spec.Resources.Requests[apiv1.ResourceStorage] = requestedSize
93-
94-
log.Debug().Str("pvc-capacity", volumeSize.String()).Str("requested", requestedSize.String()).Msg("PVC capacity differs - updating")
95-
kube := r.context.GetKubeCli()
96-
if _, err := kube.CoreV1().PersistentVolumeClaims(r.context.GetNamespace()).Update(&p); err != nil {
97-
log.Error().Err(err).Msg("Failed to update pvc")
98-
}
86+
87+
if groupSpec.HasVolumeClaimTemplate() {
88+
res := groupSpec.GetVolumeClaimTemplate().Spec.Resources.Requests
89+
// For pvc only resources.requests is mutable
90+
if compareResourceList(p.Spec.Resources.Requests, res) {
91+
p.Spec.Resources.Requests = res
92+
log.Debug().Msg("volumeClaimTemplate requested resources changed - updating")
93+
kube := r.context.GetKubeCli()
94+
if _, err := kube.CoreV1().PersistentVolumeClaims(r.context.GetNamespace()).Update(&p); err != nil {
95+
log.Error().Err(err).Msg("Failed to update pvc")
96+
} else {
9997
r.context.CreateEvent(k8sutil.NewPVCResizedEvent(r.context.GetAPIObject(), p.Name))
100-
} else if cmp > 0 {
101-
log.Error().Str("server-group", group.AsRole()).Str("pvc-storage-size", volumeSize.String()).Str("requested-size", requestedSize.String()).
102-
Msg("Volume size should not shrink")
103-
r.context.CreateEvent(k8sutil.NewCannotShrinkVolumeEvent(r.context.GetAPIObject(), p.Name))
98+
}
99+
}
100+
} else {
101+
if requestedSize, ok := groupSpec.Resources.Requests[apiv1.ResourceStorage]; ok {
102+
if volumeSize, ok := p.Spec.Resources.Requests[apiv1.ResourceStorage]; ok {
103+
cmp := volumeSize.Cmp(requestedSize)
104+
if cmp < 0 {
105+
// Size of the volume is smaller than the requested size
106+
// Update the pvc with the request size
107+
p.Spec.Resources.Requests[apiv1.ResourceStorage] = requestedSize
108+
109+
log.Debug().Str("pvc-capacity", volumeSize.String()).Str("requested", requestedSize.String()).Msg("PVC capacity differs - updating")
110+
kube := r.context.GetKubeCli()
111+
if _, err := kube.CoreV1().PersistentVolumeClaims(r.context.GetNamespace()).Update(&p); err != nil {
112+
log.Error().Err(err).Msg("Failed to update pvc")
113+
} else {
114+
r.context.CreateEvent(k8sutil.NewPVCResizedEvent(r.context.GetAPIObject(), p.Name))
115+
}
116+
} else if cmp > 0 {
117+
log.Error().Str("server-group", group.AsRole()).Str("pvc-storage-size", volumeSize.String()).Str("requested-size", requestedSize.String()).
118+
Msg("Volume size should not shrink")
119+
r.context.CreateEvent(k8sutil.NewCannotShrinkVolumeEvent(r.context.GetAPIObject(), p.Name))
120+
}
104121
}
105122
}
106123
}
@@ -118,3 +135,21 @@ func (r *Resources) InspectPVCs(ctx context.Context) (util.Interval, error) {
118135

119136
return nextInterval, nil
120137
}
138+
139+
func compareResourceList(wanted, given apiv1.ResourceList) bool {
140+
for k, v := range wanted {
141+
if gv, ok := given[k]; !ok {
142+
return true
143+
} else if v.Cmp(gv) != 0 {
144+
return true
145+
}
146+
}
147+
148+
for k := range given {
149+
if _, ok := wanted[k]; !ok {
150+
return true
151+
}
152+
}
153+
154+
return false
155+
}

pkg/deployment/resources/pvcs.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ func (r *Resources) EnsurePVCs() error {
5454
storageClassName := spec.GetStorageClassName()
5555
role := group.AsRole()
5656
resources := spec.Resources
57+
vct := spec.VolumeClaimTemplate
5758
finalizers := r.createPVCFinalizers(group)
58-
if err := k8sutil.CreatePersistentVolumeClaim(pvcs, m.PersistentVolumeClaimName, deploymentName, ns, storageClassName, role, enforceAntiAffinity, resources, finalizers, owner); err != nil {
59+
if err := k8sutil.CreatePersistentVolumeClaim(pvcs, m.PersistentVolumeClaimName, deploymentName, ns, storageClassName, role, enforceAntiAffinity, resources, vct, finalizers, owner); err != nil {
5960
return maskAny(err)
6061
}
6162
}

0 commit comments

Comments
 (0)