Skip to content

Commit

Permalink
feat: csi-cinder storage capacity
Browse files Browse the repository at this point in the history
Available capacity of disk storage

Signed-off-by: Serge Logvinov <[email protected]>
  • Loading branch information
sergelogvinov committed Aug 8, 2024
1 parent 75b1fbb commit 4fc81e3
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 2 deletions.
25 changes: 23 additions & 2 deletions pkg/csi/cinder/controllerserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"

corev1 "k8s.io/api/core/v1"
"k8s.io/cloud-provider-openstack/pkg/csi/cinder/openstack"
"k8s.io/cloud-provider-openstack/pkg/util"
cpoerrors "k8s.io/cloud-provider-openstack/pkg/util/errors"
Expand Down Expand Up @@ -944,7 +945,28 @@ func (cs *controllerServer) ValidateVolumeCapabilities(ctx context.Context, req
}

func (cs *controllerServer) GetCapacity(ctx context.Context, req *csi.GetCapacityRequest) (*csi.GetCapacityResponse, error) {
return nil, status.Error(codes.Unimplemented, "GetCapacity is not yet implemented")
klog.V(4).Infof("GetCapacity: called with args %+v", protosanitizer.StripSecrets(*req))

topology := req.GetAccessibleTopology()
if topology != nil {
region := topology.GetSegments()[corev1.LabelTopologyRegion]

cloud, cloudExist := cs.Clouds[region]
if !cloudExist {
return nil, status.Error(codes.InvalidArgument, "[GetCapacity] specified cloud undefined")
}

availableCapacity, err := cloud.GetFreeQuotaStorageSpace()
if err != nil {
return nil, status.Errorf(codes.Internal, "[GetCapacity]: failed with error %v", err)
}

return &csi.GetCapacityResponse{
AvailableCapacity: int64(availableCapacity * 1024 * 1024 * 1024),
}, nil
}

return &csi.GetCapacityResponse{}, nil
}

func (cs *controllerServer) ControllerGetVolume(ctx context.Context, req *csi.ControllerGetVolumeRequest) (*csi.ControllerGetVolumeResponse, error) {
Expand Down Expand Up @@ -1112,5 +1134,4 @@ func getCreateVolumeResponse(vol *volumes.Volume, ignoreVolumeAZ bool, accessibl
}

return resp

}
1 change: 1 addition & 0 deletions pkg/csi/cinder/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ func NewDriver(o *DriverOpts) *Driver {
csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME,
csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT,
csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS,
csi.ControllerServiceCapability_RPC_GET_CAPACITY,
csi.ControllerServiceCapability_RPC_EXPAND_VOLUME,
csi.ControllerServiceCapability_RPC_CLONE_VOLUME,
csi.ControllerServiceCapability_RPC_LIST_VOLUMES_PUBLISHED_NODES,
Expand Down
1 change: 1 addition & 0 deletions pkg/csi/cinder/openstack/openstack.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ type IOpenStack interface {
GetInstanceByID(instanceID string) (*servers.Server, error)
ExpandVolume(volumeID string, status string, size int) error
GetMaxVolLimit() int64
GetFreeQuotaStorageSpace() (int, error)
GetMetadataOpts() metadata.Opts
GetBlockStorageOpts() BlockStorageOpts
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/csi/cinder/openstack/openstack_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,10 @@ func (_m *OpenStackMock) GetMaxVolLimit() int64 {
return 256
}

func (_m *OpenStackMock) GetFreeQuotaStorageSpace() (int, error) {
return 100, nil
}

func (_m *OpenStackMock) BackupsAreEnabled() (bool, error) {
return true, nil
}
Expand Down
17 changes: 17 additions & 0 deletions pkg/csi/cinder/openstack/openstack_volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"time"

"github.com/gophercloud/gophercloud/v2/openstack"
"github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/limits"
"github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes"
"github.com/gophercloud/gophercloud/v2/openstack/compute/v2/volumeattach"
"github.com/gophercloud/gophercloud/v2/pagination"
Expand Down Expand Up @@ -396,6 +397,22 @@ func (os *OpenStack) GetMaxVolLimit() int64 {
return defaultMaxVolAttachLimit
}

// GetFreeQuotaStorageSpace returns the tenant quota capacity of the block storage, in GB
func (os *OpenStack) GetFreeQuotaStorageSpace() (int, error) {
mc := metrics.NewMetricContext("limits", "get")

res, err := limits.Get(context.TODO(), os.blockstorage).Extract()
if mc.ObserveRequest(err) != nil {
return 0, err
}

capacity := res.Absolute.MaxTotalVolumeGigabytes - res.Absolute.TotalGigabytesUsed
if capacity < 0 {
capacity = 0
}
return capacity, nil
}

// diskIsAttached queries if a volume is attached to a compute instance
func (os *OpenStack) diskIsAttached(instanceID, volumeID string) (bool, error) {
volume, err := os.GetVolume(volumeID)
Expand Down
4 changes: 4 additions & 0 deletions pkg/util/blockdevice/blockdevice_unsupported.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@ func GetBlockDeviceSize(path string) (int64, error) {
func RescanBlockDeviceGeometry(devicePath string, deviceMountPath string, newSize int64) error {
return errors.New("RescanBlockDeviceGeometry is not implemented for this OS")
}

func RescanDevice(devicePath string) error {
return errors.New("RescanDevice is not implemented for this OS")
}
4 changes: 4 additions & 0 deletions tests/sanity/cinder/fakecloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,10 @@ func (cloud *cloud) GetMaxVolLimit() int64 {
return 256
}

func (cloud *cloud) GetFreeQuotaStorageSpace() (int, error) {
return 100, nil
}

func (cloud *cloud) GetMetadataOpts() metadata.Opts {
var m metadata.Opts
m.SearchOrder = fmt.Sprintf("%s,%s", "configDrive", "metadataService")
Expand Down

0 comments on commit 4fc81e3

Please sign in to comment.