Skip to content

Commit 045b5c6

Browse files
Madhu-1claude
andcommitted
rbd: apply QoS during CreateVolume
When a PVC is created with VAC name already set,Kubernetes does not call ControllerModifyVolume. That RPC is only invoked when the VolumeAttributesClass is changed after creation. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
1 parent dc9fb51 commit 045b5c6

2 files changed

Lines changed: 81 additions & 17 deletions

File tree

internal/rbd/controllerserver.go

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,35 @@ func validateStriping(parameters map[string]string) error {
150150
return nil
151151
}
152152

153+
// validateQoSParameters validates QoS parameters from VolumeAttributesClass.
154+
// This validation happens before creating the RBD image to fail early on invalid parameters.
155+
func validateQoSParameters(mutableParams map[string]string) error {
156+
// Check if cgroup v2 QoS parameters and traditional NBD QoS parameters are mixed.
157+
hasCgroupQoS := hasCgroupQoSParams(mutableParams)
158+
hasNBDQoS := HasQoSParams(mutableParams)
159+
160+
if hasCgroupQoS && hasNBDQoS {
161+
return errors.New("cannot specify both cgroup v2 QoS parameters " +
162+
"and traditional NBD QoS parameters in the same request")
163+
}
164+
165+
// Validate cgroup QoS parameters if present.
166+
if hasCgroupQoS {
167+
if err := validateCgroupQoSParams(mutableParams); err != nil {
168+
return fmt.Errorf("invalid cgroup QoS parameters: %w", err)
169+
}
170+
}
171+
172+
// Validate traditional NBD QoS parameters if present.
173+
if hasNBDQoS {
174+
if err := validateNBDQoSParams(mutableParams); err != nil {
175+
return fmt.Errorf("invalid NBD QoS parameters: %w", err)
176+
}
177+
}
178+
179+
return nil
180+
}
181+
153182
// parseVolCreateRequest take create volume `request` argument and make use of the
154183
// request arguments for subsequent calls.
155184
func (cs *ControllerServer) parseVolCreateRequest(
@@ -230,10 +259,19 @@ func (cs *ControllerServer) parseVolCreateRequest(
230259
return nil, status.Error(codes.InvalidArgument, err.Error())
231260
}
232261

233-
// parse QOS parameters from mutable parameters
234-
err = rbdVol.SetQOS(ctx, req.GetMutableParameters())
235-
if err != nil {
236-
return nil, status.Error(codes.InvalidArgument, err.Error())
262+
// Validate QoS parameters from VolumeAttributesClass before creating the image.
263+
// This ensures we fail early if parameters are invalid, avoiding orphaned resources.
264+
mutableParams := req.GetMutableParameters()
265+
if len(mutableParams) > 0 {
266+
err = validateQoSParameters(mutableParams)
267+
if err != nil {
268+
return nil, status.Error(codes.InvalidArgument, err.Error())
269+
}
270+
271+
// Store BaseVolSize for capacity-based QoS calculations.
272+
if v, ok := mutableParams[baseVolSizeBytes]; ok && v != "" {
273+
rbdVol.BaseVolSize = v
274+
}
237275
}
238276

239277
err = rbdVol.Connect(cr)
@@ -814,19 +852,18 @@ func (cs *ControllerServer) createBackingImage(
814852
return status.Error(codes.Internal, err.Error())
815853
}
816854

817-
// Apply Qos parameters to rbd image.
818-
err = rbdVol.ApplyQOS(ctx)
819-
if err != nil {
820-
log.ErrorLog(ctx, "failed to apply QOS for rbd image: %s with error: %v", rbdVol, err)
855+
// Apply QoS parameters from VolumeAttributesClass if present.
856+
// This handles both traditional NBD QoS and cgroup v2 QoS.
857+
if len(mutableParameters) > 0 {
858+
// Set RequestedVolSize for QoS capacity-based calculations.
859+
rbdVol.RequestedVolSize = rbdVol.VolSize
821860

822-
return status.Error(codes.Internal, err.Error())
823-
}
824-
// Save Qos parameters from mutable parameters in Image metadata, we will use it while resize volume.
825-
err = rbdVol.SaveQOS(ctx, mutableParameters)
826-
if err != nil {
827-
log.ErrorLog(ctx, "failed to save QOS for rbd image: %s with error: %v", rbdVol, err)
861+
err = rbdVol.modifyVolumeAttributes(ctx, mutableParameters)
862+
if err != nil {
863+
log.ErrorLog(ctx, "failed to apply QoS for rbd image: %s with error: %v", rbdVol, err)
828864

829-
return status.Error(codes.Internal, err.Error())
865+
return status.Error(codes.Internal, err.Error())
866+
}
830867
}
831868

832869
return nil

internal/rbd/qos.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package rbd
1919
import (
2020
"context"
2121
"errors"
22+
"fmt"
2223
"strconv"
2324

2425
librbd "github.com/ceph/go-ceph/rbd"
@@ -117,9 +118,35 @@ func (h *nbdQoSHandler) HasParams(params map[string]string) bool {
117118
}
118119

119120
// Validate validates traditional NBD QoS parameters.
120-
// Currently returns nil as NBD QoS validation is done during SetQOS.
121121
func (h *nbdQoSHandler) Validate(params map[string]string) error {
122-
// NBD QoS validation is performed in SetQOS via calcQosBasedOnCapacity.
122+
return validateNBDQoSParams(params)
123+
}
124+
125+
// validateNBDQoSParams validates traditional NBD QoS parameters.
126+
// Ensures all numeric values are valid and positive.
127+
func validateNBDQoSParams(params map[string]string) error {
128+
// All NBD QoS parameter keys that accept numeric values
129+
numericParams := []string{
130+
baseIops, maxIops, baseReadIops, maxReadIops, baseWriteIops, maxWriteIops,
131+
baseBps, maxBps, baseReadBps, maxReadBps, baseWriteBps, maxWriteBps,
132+
iopsPerGiB, readIopsPerGiB, writeIopsPerGiB,
133+
bpsPerGiB, readBpsPerGiB, writeBpsPerGiB,
134+
baseVolSizeBytes,
135+
}
136+
137+
for _, key := range numericParams {
138+
if val, ok := params[key]; ok && val != "" {
139+
parsed, err := strconv.ParseInt(val, 10, 64)
140+
if err != nil {
141+
return fmt.Errorf("invalid value for %s: %s, must be a valid integer", key, val)
142+
}
143+
// Allow zero for base limits (can be omitted), but not negative
144+
if parsed < 0 {
145+
return fmt.Errorf("invalid value for %s: %s, must be non-negative", key, val)
146+
}
147+
}
148+
}
149+
123150
return nil
124151
}
125152

0 commit comments

Comments
 (0)