diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f0b97a3..faa19c9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## unreleased +* Make volumes-per-node limit configurable + [[GH-575]](https://github.com/digitalocean/csi-digitalocean/pull/575) + ## v4.10.0 - 2024.06.05 * Handle new max-volumes-per-node error message diff --git a/cmd/do-csi-plugin/main.go b/cmd/do-csi-plugin/main.go index d93be9ae..ae973873 100644 --- a/cmd/do-csi-plugin/main.go +++ b/cmd/do-csi-plugin/main.go @@ -40,6 +40,7 @@ func main() { defaultVolumesPageSize = flag.Uint("default-volumes-page-size", 0, "The default page size used when paging through volumes results (default: do not specify and let the DO API choose)") doAPIRateLimitQPS = flag.Float64("do-api-rate-limit", 0, "Impose QPS rate limit on DigitalOcean API usage (default: do not rate limit)") validateAttachment = flag.Bool("validate-attachment", false, "Validate if the attachment has fully completed before formatting/mounting the device") + volumeLimit = flag.Uint("volume-limit", 7, "Volumes per node limit to report; needs to match limit imposed by DO storage backend (honored by Node service only)") version = flag.Bool("version", false, "Print the version and exit.") ) flag.Parse() @@ -64,6 +65,7 @@ func main() { DefaultVolumesPageSize: *defaultVolumesPageSize, DOAPIRateLimitQPS: *doAPIRateLimitQPS, ValidateAttachment: *validateAttachment, + VolumeLimit: *volumeLimit, }) if err != nil { log.Fatalln(err) diff --git a/driver/driver.go b/driver/driver.go index 709cad90..5bc1b342 100644 --- a/driver/driver.go +++ b/driver/driver.go @@ -42,6 +42,8 @@ const ( // DefaultDriverName defines the name that is used in Kubernetes and the CSI // system for the canonical, official name of this plugin DefaultDriverName = "dobs.csi.digitalocean.com" + + defaultMaxVolumesPerNode = 7 ) var ( @@ -86,8 +88,9 @@ type Driver struct { // ready defines whether the driver is ready to function. This value will // be used by the `Identity` service via the `Probe()` method. - readyMu sync.Mutex // protects ready - ready bool + readyMu sync.Mutex // protects ready + ready bool + volumeLimit uint } // NewDriverParams defines the parameters that can be passed to NewDriver. @@ -102,6 +105,7 @@ type NewDriverParams struct { DefaultVolumesPageSize uint DOAPIRateLimitQPS float64 ValidateAttachment bool + VolumeLimit uint } // NewDriver returns a CSI plugin that contains the necessary gRPC @@ -167,6 +171,7 @@ func NewDriver(p NewDriverParams) (*Driver, error) { endpoint: p.Endpoint, debugAddr: p.DebugAddr, defaultVolumesPageSize: p.DefaultVolumesPageSize, + volumeLimit: p.VolumeLimit, hostID: func() string { return hostID }, region: region, @@ -236,7 +241,7 @@ func (d *Driver) Run(ctx context.Context) error { d.log.WithFields(logrus.Fields{ "limit": details.limit, "num_volumes": details.numVolumes, - }).Warn("CSI plugin will not function correctly, please resolve volume limit") + }).Warn("CSI plugin may not function correctly, please resolve volume limit") } if d.debugAddr != "" { diff --git a/driver/driver_test.go b/driver/driver_test.go index a7666eac..06b791e9 100644 --- a/driver/driver_test.go +++ b/driver/driver_test.go @@ -311,7 +311,7 @@ func (f *fakeStorageActionsDriver) Attach(ctx context.Context, volumeID string, return nil, resp, errors.New("droplet was not found") } - if len(droplet.VolumeIDs) >= maxVolumesPerNode { + if len(droplet.VolumeIDs) >= defaultMaxVolumesPerNode { resp.Response = &http.Response{ StatusCode: http.StatusUnprocessableEntity, } diff --git a/driver/node.go b/driver/node.go index 6e03a744..872a64cc 100644 --- a/driver/node.go +++ b/driver/node.go @@ -45,9 +45,6 @@ const ( diskIDPath = "/dev/disk/by-id" diskDOPrefix = "scsi-0DO_Volume_" - // See: https://www.digitalocean.com/docs/volumes/overview/#limits - maxVolumesPerNode = 7 - volumeModeBlock = "block" volumeModeFilesystem = "filesystem" ) @@ -343,7 +340,7 @@ func (d *Driver) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRequest) ( d.log.WithField("method", "node_get_info").Info("node get info called") return &csi.NodeGetInfoResponse{ NodeId: d.hostID(), - MaxVolumesPerNode: maxVolumesPerNode, + MaxVolumesPerNode: int64(d.volumeLimit), // make sure that the driver works on this particular region only AccessibleTopology: &csi.Topology{