velero install: support velero/restic pod cpu/mem requests with unbounded limits (#1745)
* support velero/restic pod cpu/mem requests with unbounded limits explicitly treat "0" value as unbounded Signed-off-by: Adnan Abdulhussein <aadnan@vmware.com> * update flag documentation Signed-off-by: Adnan Abdulhussein <aadnan@vmware.com> * changelog Signed-off-by: Adnan Abdulhussein <aadnan@vmware.com> * update restic configmap docs Signed-off-by: Adnan Abdulhussein <aadnan@vmware.com>pull/1753/head
parent
ad026107c9
commit
7b7b96de74
|
@ -0,0 +1 @@
|
|||
support setting CPU/memory requests with unbounded limits using velero install
|
|
@ -72,14 +72,14 @@ func (o *InstallOptions) BindFlags(flags *pflag.FlagSet) {
|
|||
flags.StringVar(&o.Image, "image", o.Image, "image to use for the Velero and restic server pods. Optional.")
|
||||
flags.StringVar(&o.Prefix, "prefix", o.Prefix, "prefix under which all Velero data should be stored within the bucket. Optional.")
|
||||
flags.Var(&o.PodAnnotations, "pod-annotations", "annotations to add to the Velero and restic pods. Optional. Format is key1=value1,key2=value2")
|
||||
flags.StringVar(&o.VeleroPodCPURequest, "velero-pod-cpu-request", o.VeleroPodCPURequest, "CPU request for Velero pod. Optional.")
|
||||
flags.StringVar(&o.VeleroPodMemRequest, "velero-pod-mem-request", o.VeleroPodMemRequest, "memory request for Velero pod. Optional.")
|
||||
flags.StringVar(&o.VeleroPodCPULimit, "velero-pod-cpu-limit", o.VeleroPodCPULimit, "CPU limit for Velero pod. Optional.")
|
||||
flags.StringVar(&o.VeleroPodMemLimit, "velero-pod-mem-limit", o.VeleroPodMemLimit, "memory limit for Velero pod. Optional.")
|
||||
flags.StringVar(&o.ResticPodCPURequest, "restic-pod-cpu-request", o.ResticPodCPURequest, "CPU request for restic pods. Optional.")
|
||||
flags.StringVar(&o.ResticPodMemRequest, "restic-pod-mem-request", o.ResticPodMemRequest, "memory request for restic pods. Optional.")
|
||||
flags.StringVar(&o.ResticPodCPULimit, "restic-pod-cpu-limit", o.ResticPodCPULimit, "CPU limit for restic pods. Optional.")
|
||||
flags.StringVar(&o.ResticPodMemLimit, "restic-pod-mem-limit", o.ResticPodMemLimit, "memory limit for restic pods. Optional.")
|
||||
flags.StringVar(&o.VeleroPodCPURequest, "velero-pod-cpu-request", o.VeleroPodCPURequest, `CPU request for Velero pod. A value of "0" is treated as unbounded. Optional.`)
|
||||
flags.StringVar(&o.VeleroPodMemRequest, "velero-pod-mem-request", o.VeleroPodMemRequest, `memory request for Velero pod. A value of "0" is treated as unbounded. Optional.`)
|
||||
flags.StringVar(&o.VeleroPodCPULimit, "velero-pod-cpu-limit", o.VeleroPodCPULimit, `CPU limit for Velero pod. A value of "0" is treated as unbounded. Optional.`)
|
||||
flags.StringVar(&o.VeleroPodMemLimit, "velero-pod-mem-limit", o.VeleroPodMemLimit, `memory limit for Velero pod. A value of "0" is treated as unbounded. Optional.`)
|
||||
flags.StringVar(&o.ResticPodCPURequest, "restic-pod-cpu-request", o.ResticPodCPURequest, `CPU request for restic pod. A value of "0" is treated as unbounded. Optional.`)
|
||||
flags.StringVar(&o.ResticPodMemRequest, "restic-pod-mem-request", o.ResticPodMemRequest, `memory request for restic pod. A value of "0" is treated as unbounded. Optional.`)
|
||||
flags.StringVar(&o.ResticPodCPULimit, "restic-pod-cpu-limit", o.ResticPodCPULimit, `CPU limit for restic pod. A value of "0" is treated as unbounded. Optional.`)
|
||||
flags.StringVar(&o.ResticPodMemLimit, "restic-pod-mem-limit", o.ResticPodMemLimit, `memory limit for restic pod. A value of "0" is treated as unbounded. Optional.`)
|
||||
flags.Var(&o.BackupStorageConfig, "backup-location-config", "configuration to use for the backup storage location. Format is key1=value1,key2=value2")
|
||||
flags.Var(&o.VolumeSnapshotConfig, "snapshot-location-config", "configuration to use for the volume snapshot location. Format is key1=value1,key2=value2")
|
||||
flags.BoolVar(&o.UseVolumeSnapshots, "use-volume-snapshots", o.UseVolumeSnapshots, "whether or not to create snapshot location automatically. Set to false if you do not plan to create volume snapshots via a storage provider.")
|
||||
|
|
|
@ -26,7 +26,10 @@ import (
|
|||
// values and returns a ResourceRequirements struct to be used in a Container.
|
||||
// An error is returned if we cannot parse the request/limit.
|
||||
func ParseResourceRequirements(cpuRequest, memRequest, cpuLimit, memLimit string) (corev1.ResourceRequirements, error) {
|
||||
var resources corev1.ResourceRequirements
|
||||
resources := corev1.ResourceRequirements{
|
||||
Requests: corev1.ResourceList{},
|
||||
Limits: corev1.ResourceList{},
|
||||
}
|
||||
|
||||
parsedCPURequest, err := resource.ParseQuantity(cpuRequest)
|
||||
if err != nil {
|
||||
|
@ -48,21 +51,29 @@ func ParseResourceRequirements(cpuRequest, memRequest, cpuLimit, memLimit string
|
|||
return resources, errors.Wrapf(err, `couldn't parse memory limit "%s"`, memLimit)
|
||||
}
|
||||
|
||||
if parsedCPURequest.Cmp(parsedCPULimit) > 0 {
|
||||
// A quantity of 0 is treated as unbounded
|
||||
unbounded := resource.MustParse("0")
|
||||
|
||||
if parsedCPULimit != unbounded && parsedCPURequest.Cmp(parsedCPULimit) > 0 {
|
||||
return resources, errors.WithStack(errors.Errorf(`CPU request "%s" must be less than or equal to CPU limit "%s"`, cpuRequest, cpuLimit))
|
||||
}
|
||||
|
||||
if parsedMemRequest.Cmp(parsedMemLimit) > 0 {
|
||||
if parsedMemLimit != unbounded && parsedMemRequest.Cmp(parsedMemLimit) > 0 {
|
||||
return resources, errors.WithStack(errors.Errorf(`Memory request "%s" must be less than or equal to Memory limit "%s"`, memRequest, memLimit))
|
||||
}
|
||||
|
||||
resources.Requests = corev1.ResourceList{
|
||||
corev1.ResourceCPU: parsedCPURequest,
|
||||
corev1.ResourceMemory: parsedMemRequest,
|
||||
// Only set resources if they are not unbounded
|
||||
if parsedCPURequest != unbounded {
|
||||
resources.Requests[corev1.ResourceCPU] = parsedCPURequest
|
||||
}
|
||||
resources.Limits = corev1.ResourceList{
|
||||
corev1.ResourceCPU: parsedCPULimit,
|
||||
corev1.ResourceMemory: parsedMemLimit,
|
||||
if parsedMemRequest != unbounded {
|
||||
resources.Requests[corev1.ResourceMemory] = parsedMemRequest
|
||||
}
|
||||
if parsedCPULimit != unbounded {
|
||||
resources.Limits[corev1.ResourceCPU] = parsedCPULimit
|
||||
}
|
||||
if parsedMemLimit != unbounded {
|
||||
resources.Limits[corev1.ResourceMemory] = parsedMemLimit
|
||||
}
|
||||
|
||||
return resources, nil
|
||||
|
|
|
@ -32,15 +32,44 @@ func TestParseResourceRequirements(t *testing.T) {
|
|||
memLimit string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
expected *corev1.ResourceRequirements
|
||||
}{
|
||||
{"unbounded quantities", args{"0", "0", "0", "0"}, false},
|
||||
{"valid quantities", args{"100m", "128Mi", "200m", "256Mi"}, false},
|
||||
{"invalid quantity", args{"100m", "invalid", "200m", "256Mi"}, true},
|
||||
{"CPU request greater than limit", args{"300m", "128Mi", "200m", "256Mi"}, true},
|
||||
{"memory request greater than limit", args{"100m", "512Mi", "200m", "256Mi"}, true},
|
||||
{"unbounded quantities", args{"0", "0", "0", "0"}, false, &corev1.ResourceRequirements{
|
||||
Requests: corev1.ResourceList{},
|
||||
Limits: corev1.ResourceList{},
|
||||
}},
|
||||
{"valid quantities", args{"100m", "128Mi", "200m", "256Mi"}, false, nil},
|
||||
{"CPU request with unbounded limit", args{"100m", "128Mi", "0", "256Mi"}, false, &corev1.ResourceRequirements{
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("100m"),
|
||||
corev1.ResourceMemory: resource.MustParse("128Mi"),
|
||||
},
|
||||
Limits: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("256Mi"),
|
||||
},
|
||||
}},
|
||||
{"Mem request with unbounded limit", args{"100m", "128Mi", "200m", "0"}, false, &corev1.ResourceRequirements{
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("100m"),
|
||||
corev1.ResourceMemory: resource.MustParse("128Mi"),
|
||||
},
|
||||
Limits: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("200m"),
|
||||
},
|
||||
}},
|
||||
{"CPU/Mem requests with unbounded limits", args{"100m", "128Mi", "0", "0"}, false, &corev1.ResourceRequirements{
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("100m"),
|
||||
corev1.ResourceMemory: resource.MustParse("128Mi"),
|
||||
},
|
||||
Limits: corev1.ResourceList{},
|
||||
}},
|
||||
{"invalid quantity", args{"100m", "invalid", "200m", "256Mi"}, true, nil},
|
||||
{"CPU request greater than limit", args{"300m", "128Mi", "200m", "256Mi"}, true, nil},
|
||||
{"memory request greater than limit", args{"100m", "512Mi", "200m", "256Mi"}, true, nil},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
@ -49,17 +78,24 @@ func TestParseResourceRequirements(t *testing.T) {
|
|||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
expected := corev1.ResourceRequirements{
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse(tt.args.cpuRequest),
|
||||
corev1.ResourceMemory: resource.MustParse(tt.args.memRequest),
|
||||
},
|
||||
Limits: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse(tt.args.cpuLimit),
|
||||
corev1.ResourceMemory: resource.MustParse(tt.args.memLimit),
|
||||
},
|
||||
var expected corev1.ResourceRequirements
|
||||
if tt.expected == nil {
|
||||
expected = corev1.ResourceRequirements{
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse(tt.args.cpuRequest),
|
||||
corev1.ResourceMemory: resource.MustParse(tt.args.memRequest),
|
||||
},
|
||||
Limits: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse(tt.args.cpuLimit),
|
||||
corev1.ResourceMemory: resource.MustParse(tt.args.memLimit),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
expected = *tt.expected
|
||||
}
|
||||
|
||||
assert.Equal(t, expected, got)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -235,19 +235,19 @@ data:
|
|||
image: myregistry.io/my-custom-helper-image[:OPTIONAL_TAG]
|
||||
|
||||
# "cpuRequest" sets the request.cpu value on the restic init containers during restore.
|
||||
# If not set, it will default to "100m".
|
||||
# If not set, it will default to "100m". A value of "0" is treated as unbounded.
|
||||
cpuRequest: 200m
|
||||
|
||||
# "memRequest" sets the request.memory value on the restic init containers during restore.
|
||||
# If not set, it will default to "128Mi".
|
||||
# If not set, it will default to "128Mi". A value of "0" is treated as unbounded.
|
||||
memRequest: 128Mi
|
||||
|
||||
# "cpuLimit" sets the request.cpu value on the restic init containers during restore.
|
||||
# If not set, it will default to "100m".
|
||||
# If not set, it will default to "100m". A value of "0" is treated as unbounded.
|
||||
cpuLimit: 200m
|
||||
|
||||
# "memLimit" sets the request.memory value on the restic init containers during restore.
|
||||
# If not set, it will default to "128Mi".
|
||||
# If not set, it will default to "128Mi". A value of "0" is treated as unbounded.
|
||||
memLimit: 128Mi
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue