diff --git a/csi/src/controllerserver.go b/csi/src/controllerserver.go index b9ffba00..50778f08 100644 --- a/csi/src/controllerserver.go +++ b/csi/src/controllerserver.go @@ -334,6 +334,7 @@ func (cs *ControllerServer) ControllerGetCapabilities(ctx context.Context, req * for _, capability := range []csi.ControllerServiceCapability_RPC_Type{ csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME, csi.ControllerServiceCapability_RPC_LIST_VOLUMES, + csi.ControllerServiceCapability_RPC_EXPAND_VOLUME, csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT, csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS, // TODO: csi.ControllerServiceCapability_RPC_CLONE_VOLUME, @@ -507,10 +508,58 @@ func (cs *ControllerServer) ListSnapshots(ctx context.Context, req *csi.ListSnap return resp, nil } -// ControllerExpandVolume resizes a volume +// ControllerExpandVolume increases the size of a volume func (cs *ControllerServer) ControllerExpandVolume(ctx context.Context, req *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error) { - return nil, status.Error(codes.Unimplemented, "") + klog.Infof("received controller expand volume request %+v", protosanitizer.StripSecrets(req)) + if (req == nil) + { + return nil, status.Error(codes.InvalidArgument, "request cannot be empty") + } + if (req.VolumeId == "" || req.CapacityRange == nil || req.CapacityRange.RequiredBytes == 0) + { + return nil, status.Error(codes.InvalidArgument, "VolumeId, CapacityRange and RequiredBytes are required fields") + } + + volVars := make(map[string]string) + err := json.Unmarshal([]byte(req.VolumeId), &volVars) + if (err != nil) + { + return nil, status.Error(codes.Internal, "volume ID not in JSON format") + } + volName := volVars["name"] + ctxVars, _, _ := GetConnectionParams(volVars) + + inodeCfg, err := invokeList(ctxVars, volName, true) + if (err != nil) + { + return nil, err + } + + if (req.CapacityRange.RequiredBytes > 0 && inodeCfg[0].Size < uint64(req.CapacityRange.RequiredBytes)) + { + sz := ((req.CapacityRange.RequiredBytes+4095)/4096)*4096 + _, err := invokeCLI(ctxVars, []string{ "modify", "--inc_size", "1", "--resize", fmt.Sprintf("%d", sz), volName }) + if (err != nil) + { + return nil, err + } + inodeCfg, err := invokeList(ctxVars, volName, true) + if (err != nil) + { + return nil, err + } + return &csi.ControllerExpandVolumeResponse{ + CapacityBytes: int64(inodeCfg[0].Size), + // Node expansion is required for FS + NodeExpansionRequired: req.VolumeCapability == nil || req.VolumeCapability.GetBlock() == nil, + }, nil + } + + return &csi.ControllerExpandVolumeResponse{ + CapacityBytes: int64(inodeCfg[0].Size), + NodeExpansionRequired: false, + }, nil } // ControllerGetVolume get volume info diff --git a/csi/src/identityserver.go b/csi/src/identityserver.go index b1050411..dbe2bc6a 100644 --- a/csi/src/identityserver.go +++ b/csi/src/identityserver.go @@ -49,6 +49,13 @@ func (is *IdentityServer) GetPluginCapabilities(ctx context.Context, req *csi.Ge }, }, }, + { + Type: &csi.PluginCapability_VolumeExpansion_{ + VolumeExpansion: &csi.PluginCapability_VolumeExpansion{ + Type: csi.PluginCapability_VolumeExpansion_OFFLINE, + }, + }, + }, }, }, nil }