From 39d853f1e90fffccc899f26ffe577ee903da10dd Mon Sep 17 00:00:00 2001 From: Lee Chapman Date: Sat, 17 Jan 2026 15:07:19 -0800 Subject: [PATCH] fix(freenas-api-nfs): return actual capacity in ControllerExpandVolume Fixes issue where volume expansion succeeds (quota is updated via PUT API) but ControllerExpandVolume returns capacity_bytes: 0 due to a logic condition evaluation, causing Kubernetes to reject the expansion with "capacity to 0" errors. Root Cause: The driver correctly uses PUT API call to update the quota, which succeeds. However, the return value logic condition evaluates to 0 when: - datasetEnableQuotas is false/undefined, AND - driverZfsResourceType is "filesystem" (not "volume") This happens even though the quota was successfully updated on the TrueNAS side. API Flow: 1. PUT /pool/dataset/id/{datasetName} - Updates refquota/volsize (returns 200 OK) 2. GET /pool/dataset/id/{datasetName} - Reads back refquota/volsize with rawvalue Changes: - Read actual capacity from dataset after expansion using DatasetGet (queries refquota for filesystems, volsize for volumes) - Use actual capacity from API response instead of relying on config flag - Add fallback to requested capacity if actual capacity cannot be retrieved The driver already uses the correct HTTP method (PUT) - no API changes needed. This fix ensures we return the actual capacity that was set, not 0. Fixes #394 --- src/driver/freenas/api.js | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/driver/freenas/api.js b/src/driver/freenas/api.js index 7eb94a3..a308249 100644 --- a/src/driver/freenas/api.js +++ b/src/driver/freenas/api.js @@ -3687,11 +3687,37 @@ class FreeNASApiDriver extends CsiBaseDriver { await this.expandVolume(call, datasetName); + // Get actual capacity from dataset to return accurate value + // This ensures we return the actual quota/volsize that was set, + // regardless of the datasetEnableQuotas config flag + // API flow: PUT /pool/dataset/id/{id} sets quota -> GET /pool/dataset/id/{id} reads it back + let actualCapacityBytes = capacity_bytes; + try { + const capacityProperty = driverZfsResourceType == "volume" + ? "volsize" + : "refquota"; + const currentProps = await httpApiClient.DatasetGet(datasetName, [ + capacityProperty, + ]); + if (currentProps && currentProps[capacityProperty]) { + const capacityProp = currentProps[capacityProperty]; + if (capacityProp && capacityProp.rawvalue) { + actualCapacityBytes = Number(capacityProp.rawvalue); + } + } + } catch (err) { + // If we can't get actual capacity, use requested capacity + // This is not ideal but better than returning 0 + driver.ctx.logger.warn( + `Could not retrieve actual capacity for ${datasetName}, using requested capacity: ${err.message}` + ); + } + return { capacity_bytes: this.options.zfs.datasetEnableQuotas || driverZfsResourceType == "volume" - ? capacity_bytes + ? actualCapacityBytes : 0, node_expansion_required: driverZfsResourceType == "volume" ? true : false, };