Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/storagei #33

Merged
merged 7 commits into from
Apr 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/iscsi/storage-class.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ parameters:
fsType: ext4 # Desired filesystem
pool: A # Pool for volumes provisioning
volPrefix: stx # Desired prefix for volume naming, an underscore is appended
storageProtocol: iscsi # The storage interface (iscsi, fc, sas) being used for storage i/o
1 change: 1 addition & 0 deletions example/storage-class.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ parameters:
csi.storage.k8s.io/controller-expand-secret-namespace: default
fsType: ext4 # Desired filesystem
pool: A # Pool to use on the IQN to provision volumes
storageProtocol: iscsi # The storage interface (iscsi, fc, sas) being used for storage i/o
1 change: 1 addition & 0 deletions example/storageclass-example1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ parameters:
fsType: ext4 # Desired filesystem
pool: A # Pool to use on the IQN to provision volumes
volPrefix: csi # Desired prefix for volume naming, an underscore is appended
storageProtocol: iscsi # The storage interface (iscsi, fc, sas) being used for storage i/o
5 changes: 5 additions & 0 deletions pkg/common/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,18 @@ const PluginName = "csi-exos-x.seagate.com"

// Configuration constants
const (
AugmentKey = "##"
FsTypeConfigKey = "fsType"
PoolConfigKey = "pool"
APIAddressConfigKey = "apiAddress"
UsernameSecretKey = "username"
PasswordSecretKey = "password"
StorageClassAnnotationKey = "storageClass"
VolumePrefixKey = "volPrefix"
StorageProtocolKey = "storageProtocol"
StorageProtocolISCSI = "iscsi"
StorageProtocolFC = "fc"
StorageProtocolSAS = "sas"

MaximumLUN = 255
VolumeNameMaxLength = 32
Expand Down
69 changes: 50 additions & 19 deletions pkg/common/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package common

import (
"fmt"
"strings"
"unicode"

Expand All @@ -45,34 +46,34 @@ func ValidateName(s string) bool {
func TranslateName(name, prefix string) (string, error) {

klog.V(2).Infof("TranslateName VolumeNameMaxLength=%d name=[%d]%q prefix=[%d]%q", VolumeNameMaxLength, len(name), name, len(prefix), prefix)
volumeID := name
volumeName := name

if len(prefix) == 0 {
// If string is greater than max, truncate it, otherwise return original string
if len(volumeID) > VolumeNameMaxLength {
if len(volumeName) > VolumeNameMaxLength {
// Skip over 'pvc-'
if len(volumeID) >= 4 && volumeID[0:4] == "pvc-" {
volumeID = volumeID[4:]
if len(volumeName) >= 4 && volumeName[0:4] == "pvc-" {
volumeName = volumeName[4:]
}
// Skip over 'snapshot-'
if len(volumeID) >= 9 && volumeID[0:9] == "snapshot-" {
volumeID = volumeID[9:]
if len(volumeName) >= 9 && volumeName[0:9] == "snapshot-" {
volumeName = volumeName[9:]
}
volumeID = strings.ReplaceAll(volumeID, "-", "")
klog.V(2).Infof("volumeID=[%d]%q", len(volumeID), volumeID)
if len(volumeID) > VolumeNameMaxLength {
volumeID = volumeID[:VolumeNameMaxLength]
volumeName = strings.ReplaceAll(volumeName, "-", "")
klog.V(2).Infof("volumeName=[%d]%q", len(volumeName), volumeName)
if len(volumeName) > VolumeNameMaxLength {
volumeName = volumeName[:VolumeNameMaxLength]
}
}
} else {
// Skip over 'pvc-' and remove all dashes
uuid := volumeID
if len(volumeID) >= 4 && volumeID[0:4] == "pvc-" {
uuid = volumeID[4:]
uuid := volumeName
if len(volumeName) >= 4 && volumeName[0:4] == "pvc-" {
uuid = volumeName[4:]
klog.Infof("TranslateName(pvc): uuid=%q", uuid)
}
if len(volumeID) >= 9 && volumeID[0:9] == "snapshot-" {
uuid = volumeID[9:]
if len(volumeName) >= 9 && volumeName[0:9] == "snapshot-" {
uuid = volumeName[9:]
klog.Infof("TranslateName(snapshot): uuid=%q", uuid)
}
uuid = strings.ReplaceAll(uuid, "-", "")
Expand All @@ -85,13 +86,43 @@ func TranslateName(name, prefix string) (string, error) {

if len(prefix)+len(uuid) > VolumeNameMaxLength {
truncate := VolumeNameMaxLength - len(prefix)
volumeID = prefix + uuid[len(uuid)-truncate:]
volumeName = prefix + uuid[len(uuid)-truncate:]
} else {
volumeID = prefix + uuid
volumeName = prefix + uuid
}
}

klog.Infof("TranslateName %q[%d], prefix %q[%d], result %q[%d]", name, len(name), prefix, len(prefix), volumeID, len(volumeID))
klog.Infof("TranslateName %q[%d], prefix %q[%d], result %q[%d]", name, len(name), prefix, len(prefix), volumeName, len(volumeName))

return volumeID, nil
return volumeName, nil
}

// VolumeIdGetName: Decode the augmented volume identifier and return the name only
func VolumeIdGetName(volumeId string) (string, error) {
tokens := strings.Split(volumeId, AugmentKey)

if len(tokens) > 0 {
return tokens[0], nil
} else {
return "", fmt.Errorf("Unable to retrieve volume name from (%s)", volumeId)
}
}

// VolumeIdGetStorageProtocol: Decode the augmented volume identifier and return the storage protocol only
func VolumeIdGetStorageProtocol(volumeId string) (string, error) {
tokens := strings.Split(volumeId, AugmentKey)

if len(tokens) > 1 {
return tokens[1], nil
} else {
return "", fmt.Errorf("Unable to retrieve storage protocol from (%s)", volumeId)
}
}

// VolumeIdAugment: Extend the volume name by augmenting it with storage protocol
func VolumeIdAugment(volumename, storageprotocol string) string {

volumeId := volumename + AugmentKey + storageprotocol
klog.V(2).Infof("VolumeIdAugment: %s", volumeId)
return volumeId
}
7 changes: 4 additions & 3 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,14 +148,15 @@ func (controller *Controller) ControllerGetCapabilities(ctx context.Context, req
// ValidateVolumeCapabilities checks whether the volume capabilities requested
// are supported.
func (controller *Controller) ValidateVolumeCapabilities(ctx context.Context, req *csi.ValidateVolumeCapabilitiesRequest) (*csi.ValidateVolumeCapabilitiesResponse, error) {
volumeID := req.GetVolumeId()
if len(volumeID) == 0 {
volumeName, _ := common.VolumeIdGetName(req.GetVolumeId())

if len(volumeName) == 0 {
return nil, status.Error(codes.InvalidArgument, "cannot validate volume with empty ID")
}
if len(req.GetVolumeCapabilities()) == 0 {
return nil, status.Error(codes.InvalidArgument, "cannot validate volume without capabilities")
}
_, _, err := controller.client.ShowVolumes(volumeID)
_, _, err := controller.client.ShowVolumes(volumeName)
if err != nil {
return nil, status.Error(codes.NotFound, "cannot validate volume not found")
}
Expand Down
15 changes: 8 additions & 7 deletions pkg/controller/expander.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"strconv"

"github.com/Seagate/seagate-exos-x-csi/pkg/common"
"github.com/container-storage-interface/spec/lib/go/csi"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand All @@ -13,24 +14,24 @@ import (

// ControllerExpandVolume expands a volume to the given new size
func (controller *Controller) ControllerExpandVolume(ctx context.Context, req *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error) {
volumeID := req.GetVolumeId()
if volumeID == "" {
volumeName, _ := common.VolumeIdGetName(req.GetVolumeId())
if volumeName == "" {
return nil, status.Error(codes.InvalidArgument, "cannot expand a volume with an empty ID")
}
klog.Infof("expanding volume %q", volumeID)
klog.Infof("expanding volume %q", volumeName)

newSize := req.GetCapacityRange().GetRequiredBytes()
if newSize == 0 {
newSize = req.GetCapacityRange().GetLimitBytes()
}
klog.V(2).Infof("requested size: %d bytes", newSize)

response, _, err := controller.client.ShowVolumes(volumeID)
response, _, err := controller.client.ShowVolumes(volumeName)
var expansionSize int64
if err != nil {
return nil, err
} else if volume, ok := response.ObjectsMap["volume"]; !ok {
return nil, fmt.Errorf("volume %q not found", volumeID)
return nil, fmt.Errorf("volume %q not found", volumeName)
} else if sizeNumeric, ok := volume.PropertiesMap["size-numeric"]; !ok {
return nil, fmt.Errorf("could not get current volume size, thus volume expansion is not possible")
} else if currentBlocks, err := strconv.ParseInt(sizeNumeric.Data, 10, 32); err != nil {
Expand All @@ -43,11 +44,11 @@ func (controller *Controller) ControllerExpandVolume(ctx context.Context, req *c
}

expansionSizeStr := getSizeStr(expansionSize)
if _, _, err := controller.client.ExpandVolume(volumeID, expansionSizeStr); err != nil {
if _, _, err := controller.client.ExpandVolume(volumeName, expansionSizeStr); err != nil {
return nil, err
}

klog.Infof("volume %q successfully expanded", volumeID)
klog.Infof("volume %q successfully expanded", volumeName)

return &csi.ControllerExpandVolumeResponse{
CapacityBytes: newSize,
Expand Down
63 changes: 36 additions & 27 deletions pkg/controller/provisioner.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,15 @@ var (
func (controller *Controller) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) (*csi.CreateVolumeResponse, error) {

parameters := req.GetParameters()
volumeID, err := common.TranslateName(req.GetName(), parameters[common.VolumePrefixKey])
volumeName, err := common.TranslateName(req.GetName(), parameters[common.VolumePrefixKey])
if err != nil {
return nil, status.Error(codes.InvalidArgument, "trnaslate volume name contains invalid characters")
return nil, status.Error(codes.InvalidArgument, "translate volume name contains invalid characters")
}

if common.ValidateName(volumeID) == false {
// Extract the storage interface protocol to be used for this volume (iscsi, fc, sas, etc)
storageProtocol := parameters[common.StorageProtocolKey]

if common.ValidateName(volumeName) == false {
return nil, status.Error(codes.InvalidArgument, "volume name contains invalid characters")
}

Expand All @@ -49,61 +52,66 @@ func (controller *Controller) CreateVolume(ctx context.Context, req *csi.CreateV
poolType = "Virtual"
}

klog.Infof("creating volume %q (size %s) in pool %q [%s]", volumeID, sizeStr, pool, poolType)
klog.Infof("creating volume %q (size %s) pool %q [%s] using protocol (%s)", volumeName, sizeStr, pool, poolType, storageProtocol)

volumeExists, err := controller.client.CheckVolumeExists(volumeID, size)
volumeExists, err := controller.client.CheckVolumeExists(volumeName, size)
if err != nil {
return nil, err
}

if !volumeExists {
var sourceID string
var sourceId string

if volume := req.VolumeContentSource.GetVolume(); volume != nil {
sourceID = volume.VolumeId
klog.Infof("-- GetVolume sourceID %q", sourceID)
sourceId = volume.VolumeId
klog.Infof("-- GetVolume sourceID %q", sourceId)
}

if snapshot := req.VolumeContentSource.GetSnapshot(); sourceID == "" && snapshot != nil {
sourceID = snapshot.SnapshotId
klog.Infof("-- GetSnapshot sourceID %q", sourceID)
if snapshot := req.VolumeContentSource.GetSnapshot(); sourceId == "" && snapshot != nil {
sourceId = snapshot.SnapshotId
klog.Infof("-- GetSnapshot sourceID %q", sourceId)
}

if sourceID != "" {
_, apistatus, err2 := controller.client.CopyVolume(sourceID, volumeID, parameters[common.PoolConfigKey])
if sourceId != "" {
_, apistatus, err2 := controller.client.CopyVolume(sourceId, volumeName, parameters[common.PoolConfigKey])
if err2 != nil {
klog.Infof("-- CopyVolume apistatus.ReturnCode %v", apistatus.ReturnCode)
if apistatus != nil && apistatus.ReturnCode == snapshotNotFoundErrorCode {
return nil, status.Errorf(codes.NotFound, "Snapshot source (%s) not found", sourceID)
return nil, status.Errorf(codes.NotFound, "Snapshot source (%s) not found", sourceId)
} else {
return nil, err2
}
}

} else {
_, _, err2 := controller.client.CreateVolume(volumeID, sizeStr, parameters[common.PoolConfigKey], poolType)
_, _, err2 := controller.client.CreateVolume(volumeName, sizeStr, parameters[common.PoolConfigKey], poolType)
if err2 != nil {
return nil, err
}
}
}

// Fill iSCSI context parameters
targetid, _ := controller.client.Info.GetTargetId("iSCSI")
req.GetParameters()["iqn"] = targetid
portals, _ := controller.client.Info.GetPortals()
req.GetParameters()["portals"] = portals
if storageProtocol == common.StorageProtocolISCSI {
// Fill iSCSI context parameters
targetId, _ := controller.client.Info.GetTargetId("iSCSI")
req.GetParameters()["iqn"] = targetId
portals, _ := controller.client.Info.GetPortals()
req.GetParameters()["portals"] = portals
}

volumeId := common.VolumeIdAugment(volumeName, storageProtocol)

volume := &csi.CreateVolumeResponse{
Volume: &csi.Volume{
VolumeId: volumeID,
VolumeId: volumeId,
VolumeContext: parameters,
CapacityBytes: req.GetCapacityRange().GetRequiredBytes(),
ContentSource: req.GetVolumeContentSource(),
},
}

klog.Infof("created volume %s (%s)", volumeID, sizeStr)
klog.Infof("created volume %s (%s)", volumeId, sizeStr)

// Log struct with field names
klog.V(8).Infof("created volume %+v", volume)
return volume, nil
Expand All @@ -114,22 +122,23 @@ func (controller *Controller) DeleteVolume(ctx context.Context, req *csi.DeleteV
if len(req.GetVolumeId()) == 0 {
return nil, status.Error(codes.InvalidArgument, "cannot delete volume with empty ID")
}
volumeName, _ := common.VolumeIdGetName(req.GetVolumeId())
klog.Infof("deleting volume %s", volumeName)

klog.Infof("deleting volume %s", req.GetVolumeId())
_, respStatus, err := controller.client.DeleteVolume(req.GetVolumeId())
_, respStatus, err := controller.client.DeleteVolume(volumeName)
if err != nil {
if respStatus != nil {
if respStatus.ReturnCode == volumeNotFoundErrorCode {
klog.Infof("volume %s does not exist, assuming it has already been deleted", req.GetVolumeId())
klog.Infof("volume %s does not exist, assuming it has already been deleted", volumeName)
return &csi.DeleteVolumeResponse{}, nil
} else if respStatus.ReturnCode == volumeHasSnapshot {
return nil, status.Error(codes.FailedPrecondition, fmt.Sprintf("volume %s cannot be deleted since it has snapshots", req.GetVolumeId()))
return nil, status.Error(codes.FailedPrecondition, fmt.Sprintf("volume %s cannot be deleted since it has snapshots", volumeName))
}
}
return nil, err
}

klog.Infof("successfully deleted volume %s", req.GetVolumeId())
klog.Infof("successfully deleted volume %s", volumeName)
return &csi.DeleteVolumeResponse{}, nil
}

Expand Down
10 changes: 6 additions & 4 deletions pkg/controller/publisher.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package controller
import (
"context"

"github.com/Seagate/seagate-exos-x-csi/pkg/common"
"github.com/container-storage-interface/spec/lib/go/csi"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand All @@ -21,7 +22,7 @@ func (driver *Controller) ControllerPublishVolume(ctx context.Context, req *csi.
return nil, status.Error(codes.InvalidArgument, "cannot publish volume without capabilities")
}

volumeName := req.GetVolumeId()
volumeName, _ := common.VolumeIdGetName(req.GetVolumeId())
initiatorName := req.GetNodeId()
klog.Infof("attach request for initiator %s, volume id: %s", initiatorName, volumeName)

Expand All @@ -42,8 +43,9 @@ func (driver *Controller) ControllerUnpublishVolume(ctx context.Context, req *cs
return nil, status.Error(codes.InvalidArgument, "cannot unpublish volume with empty ID")
}

klog.Infof("unmapping volume %s from initiator %s", req.GetVolumeId(), req.GetNodeId())
_, status, err := driver.client.UnmapVolume(req.GetVolumeId(), req.GetNodeId())
volumeName, _ := common.VolumeIdGetName(req.GetVolumeId())
klog.Infof("unmapping volume %s from initiator %s", volumeName, req.GetNodeId())
_, status, err := driver.client.UnmapVolume(volumeName, req.GetNodeId())
if err != nil {
if status != nil && status.ReturnCode == unmapFailedErrorCode {
klog.Info("unmap failed, assuming volume is already unmapped")
Expand All @@ -53,6 +55,6 @@ func (driver *Controller) ControllerUnpublishVolume(ctx context.Context, req *cs
return nil, err
}

klog.Infof("successfully unmapped volume %s from all initiators", req.GetVolumeId())
klog.Infof("successfully unmapped volume %s from all initiators", volumeName)
return &csi.ControllerUnpublishVolumeResponse{}, nil
}
Loading