Skip to content

updated regional file functionality #53

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

Closed
wants to merge 3 commits into from
Closed
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
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fmt:

.PHONY: dofmt
dofmt:
golangci-lint run --disable-all --enable=gofmt --fix
golangci-lint run --fix --config=.golangci.yml

.PHONY: lint
lint:
Expand All @@ -32,7 +32,7 @@ makefmt:

.PHONY: build
build:
go build -gcflags '-N -l' -o libSample samples/main.go samples/volume_operations.go
go build -gcflags '-N -l' -o libSample samples/main.go

.PHONY: test
test:
Expand Down
2 changes: 1 addition & 1 deletion common/vpcclient/client/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ type ResponseConsumer interface {
func (r *Request) path() string {
path := r.operation.PathPattern
for k, v := range r.pathParams {
path = strings.Replace(path, "{"+k+"}", v, -1)
path = strings.ReplaceAll(path, "{"+k+"}", v)
}
return path
}
Expand Down
1 change: 1 addition & 0 deletions common/vpcclient/models/share.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type Share struct {
Name string `json:"name,omitempty"`
Size int64 `json:"size,omitempty"`
Iops int64 `json:"iops,omitempty"`
Bandwidth *int64 `json:"bandwidth,omitempty"`
EncryptionKey *EncryptionKey `json:"encryption_key,omitempty"`
ResourceGroup *ResourceGroup `json:"resource_group,omitempty"`
InitialOwner *InitialOwner `json:"initial_owner,omitempty"`
Expand Down
4 changes: 2 additions & 2 deletions e2e/pvc_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ var _ = Describe("[ics-e2e] [sc] [with-deploy] [retain] Dynamic Provisioning usi
ReplicaCount: replicaCount,
}
test.Run(cs, ns)
if _, err = fpointer.WriteString(fmt.Sprintf("VPC-FILE-CSI-TEST: VERIFYING PVC CREATE/DELETE WITH %s STORAGE CLASS : PASS\n", sc_retain)); err != nil {
if _, err = fmt.Fprintf(fpointer, "VPC-FILE-CSI-TEST: VERIFYING PVC CREATE/DELETE WITH %s STORAGE CLASS : PASS\n", sc_retain); err != nil {
panic(err)
}
})
Expand Down Expand Up @@ -181,7 +181,7 @@ var _ = Describe("[ics-e2e] [sc] [with-deploy] Dynamic Provisioning for dp2 SC w
ReplicaCount: replicaCount,
}
test.Run(cs, ns)
if _, err = fpointer.WriteString(fmt.Sprintf("VPC-FILE-CSI-TEST: VERIFYING PVC CREATE/DELETE WITH %s STORAGE CLASS : PASS\n", sc)); err != nil {
if _, err = fmt.Fprintf(fpointer, "VPC-FILE-CSI-TEST: VERIFYING PVC CREATE/DELETE WITH %s STORAGE CLASS : PASS\n", sc); err != nil {
panic(err)
}
})
Expand Down
30 changes: 15 additions & 15 deletions e2e/testsuites/baseutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -606,8 +606,8 @@ func (t *TestPersistentVolumeClaim) ValidateProvisionedPersistentVolume() {
framework.Logf("checking PV [%s]", t.persistentVolume.Name)
expectedAccessModes := t.requestedPersistentVolumeClaim.Spec.AccessModes
Expect(t.persistentVolume.Spec.AccessModes).To(Equal(expectedAccessModes))
Expect(t.persistentVolume.Spec.ClaimRef.Name).To(Equal(t.persistentVolumeClaim.ObjectMeta.Name))
Expect(t.persistentVolume.Spec.ClaimRef.Namespace).To(Equal(t.persistentVolumeClaim.ObjectMeta.Namespace))
Expect(t.persistentVolume.Spec.ClaimRef.Name).To(Equal(t.persistentVolumeClaim.Name))
Expect(t.persistentVolume.Spec.ClaimRef.Namespace).To(Equal(t.persistentVolumeClaim.Namespace))
// If storageClass is nil, PV was pre-provisioned with these values already set
if t.storageClass != nil {
Expect(t.persistentVolume.Spec.PersistentVolumeReclaimPolicy).To(Equal(*t.storageClass.ReclaimPolicy))
Expand Down Expand Up @@ -686,12 +686,12 @@ func generatePVC(name, namespace,
func (t *TestPersistentVolumeClaim) Cleanup() {

var volumeHandle []string
if strings.Contains(t.persistentVolume.Spec.PersistentVolumeSource.CSI.VolumeHandle, VolumeIDSeperator) {
if strings.Contains(t.persistentVolume.Spec.CSI.VolumeHandle, VolumeIDSeperator) {
//Volume ID is in format volumeID#volumeAccessPointID
volumeHandle = strings.Split(t.persistentVolume.Spec.PersistentVolumeSource.CSI.VolumeHandle, VolumeIDSeperator)
volumeHandle = strings.Split(t.persistentVolume.Spec.CSI.VolumeHandle, VolumeIDSeperator)
} else {
//Deprecated -- Try for volumeID:volumeAccessPointID, support for old format for few releases.
volumeHandle = strings.Split(t.persistentVolume.Spec.PersistentVolumeSource.CSI.VolumeHandle, DeprecatedVolumeIDSeperator)
volumeHandle = strings.Split(t.persistentVolume.Spec.CSI.VolumeHandle, DeprecatedVolumeIDSeperator)
}

getShareMountTargetOptions := &vpcbetav1.GetShareMountTargetOptions{
Expand All @@ -700,7 +700,7 @@ func (t *TestPersistentVolumeClaim) Cleanup() {
}

By(fmt.Sprintf("Logging volumeHandle: %s", volumeHandle))
By(fmt.Sprintf("Verifying if file share mount target is created"))
By("Verifying if file share mount target is created")
shareMountTarget, response, err := VPCService.GetShareMountTarget(getShareMountTargetOptions)
if err != nil {
panic(err)
Expand All @@ -711,7 +711,7 @@ func (t *TestPersistentVolumeClaim) Cleanup() {
Expect(response.StatusCode).To(Equal(200))
Expect(shareMountTarget).ToNot(BeNil())

By(fmt.Sprintf("Verifying if VNI is created"))
By("Verifying if VNI is created")
if *(shareMountTarget.AccessControlMode) == "security_group" {

getVirtualNetworkInterfaceOptions := &vpcbetav1.GetVirtualNetworkInterfaceOptions{
Expand Down Expand Up @@ -761,13 +761,13 @@ func (t *TestPersistentVolumeClaim) Cleanup() {
ID: &volumeHandle[1],
}

By(fmt.Sprintf("Deleting file share target"))
By("Deleting file share target")
shareMountTarget, response, err := VPCService.DeleteShareMountTarget(deleteShareMountTargetOptions)
if err != nil {
panic(err)
}

By(fmt.Sprintf("Wating for file share target to be deleted"))
By("Wating for file share target to be deleted")
// end-delete_share_mount_target
time.Sleep(1 * time.Minute)

Expand All @@ -779,7 +779,7 @@ func (t *TestPersistentVolumeClaim) Cleanup() {
ID: &volumeHandle[0],
}

By(fmt.Sprintf("Deleting file share"))
By("Deleting file share")
share, response, err := VPCService.DeleteShare(deleteShareOptions)
if err != nil {
panic(err)
Expand All @@ -792,11 +792,11 @@ func (t *TestPersistentVolumeClaim) Cleanup() {
Expect(share).ToNot(BeNil())
}

By(fmt.Sprintf("Wating for file share to be deleted"))
By("Wating for file share to be deleted")
// end-delete_share_mount_target
time.Sleep(30 * time.Second)

By(fmt.Sprintf("Verying if VNI is deleted"))
By("Verying if VNI is deleted")
//Verifying if VNI is deleted
if *(shareMountTarget.AccessControlMode) == "security_group" {

Expand All @@ -812,7 +812,7 @@ func (t *TestPersistentVolumeClaim) Cleanup() {
Expect(virtualNetworkInterface).To(BeNil())
}

By(fmt.Sprintf("Verying if shareMountTarget is deleted"))
By("Verying if shareMountTarget is deleted")
//Verifying if shareMountTarget is deleted
shareMountTarget, response, err = VPCService.GetShareMountTarget(getShareMountTargetOptions)
// end-get_share_mount_target
Expand All @@ -821,7 +821,7 @@ func (t *TestPersistentVolumeClaim) Cleanup() {
Expect(response.StatusCode).To(Equal(404))
Expect(shareMountTarget).To(BeNil())

By(fmt.Sprintf("Verying if share is deleted"))
By("Verying if share is deleted")
//Verifying if share is deleted
getShareOptions := &vpcbetav1.GetShareOptions{
ID: &volumeHandle[1],
Expand Down Expand Up @@ -1321,7 +1321,7 @@ func (t *TestVolumeSnapshotClass) ReadyToUse(snapshot *volumesnapshotv1.VolumeSn
}
return *vs.Status.ReadyToUse, nil
})
if snapFail == true {
if snapFail {
Expect(err).To(HaveOccurred())
} else {
framework.ExpectNoError(err)
Expand Down
2 changes: 1 addition & 1 deletion e2e/testsuites/test_statefulset.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (t *StatefulsetWithVolWRTest) Run(client clientset.Interface, namespace *v1
By("checking pod exec before pod delete")
tStatefulset.Exec(t.PodCheck.Cmd, t.PodCheck.ExpectedString01)
}
if drainNode == true {
if drainNode {
tStatefulset.drainNode()
defer tStatefulset.uncordonNode()
By("checking again that the pod(s) is/are running")
Expand Down
90 changes: 68 additions & 22 deletions file/provider/create_volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
package provider

import (
"encoding/json"
"fmt"
"time"

userError "github.com/IBM/ibmcloud-volume-file-vpc/common/messages"
Expand All @@ -31,20 +33,27 @@ const (
minSize = 10 //10 GB
maxSize = 16000 //16 TB
customProfile = "custom-iops"
dp2Profile = "dp2"
)

var (
SupportedProfiles = []string{"dp2", "rfs"}
IOPSAllowedProfiles = []string{"dp2"}
BandwidthAllowedProfiles = []string{"rfs"}
)

// CreateVolume creates file share
func (vpcs *VPCSession) CreateVolume(volumeRequest provider.Volume) (volumeResponse *provider.Volume, err error) {
vpcs.Logger.Debug("Entry of CreateVolume method...")
defer vpcs.Logger.Debug("Exit from CreateVolume method...")
defer metrics.UpdateDurationFromStart(vpcs.Logger, "CreateVolume", time.Now())

var iops int64
vpcs.Logger.Info("Basic validation for CreateVolume request... ", zap.Reflect("RequestedVolumeDetails", volumeRequest))
resourceGroup, iops, err := validateVolumeRequest(volumeRequest)

resourceGroup, iops, bandwidth, err := validateVolumeRequest(volumeRequest)
if err != nil {
return nil, err
}

vpcs.Logger.Info("Successfully validated inputs for CreateVolume request... ")

// Build the share template to send to backend
Expand All @@ -58,9 +67,22 @@ func (vpcs *VPCSession) CreateVolume(volumeRequest provider.Volume) (volumeRespo
Profile: &models.Profile{
Name: volumeRequest.VPCVolume.Profile.Name,
},
Zone: &models.Zone{
Name: volumeRequest.Az,
},
Bandwidth: func() *int64 {
profile := volumeRequest.VPCVolume.Profile.Name
if contains(BandwidthAllowedProfiles, profile) && bandwidth > 0 {
return &bandwidth
}
return nil
}(),
Zone: func() *models.Zone {
profile := volumeRequest.VPCVolume.Profile.Name
if contains(IOPSAllowedProfiles, profile) || contains(SupportedProfiles, profile) {
if volumeRequest.Az != nil && *volumeRequest.Az != "" {
return &models.Zone{Name: *volumeRequest.Az}
}
}
return nil
}(),
}

// Check for VPC ID, SubnetID or PrimaryIPID either of the one is mandatory for VolumeAccessPoint/FileShareTarget creation
Expand Down Expand Up @@ -89,7 +111,8 @@ func (vpcs *VPCSession) CreateVolume(volumeRequest provider.Volume) (volumeRespo

volumeAccessPointList := make([]models.ShareTarget, 1)
volumeAccessPointList[0] = shareTargetTemplate

jsonBytes, _ := json.Marshal(shareTemplate)
fmt.Println("DEBUG PAYLOAD:\n", string(jsonBytes))
shareTemplate.ShareTargets = &volumeAccessPointList
}

Expand All @@ -110,6 +133,10 @@ func (vpcs *VPCSession) CreateVolume(volumeRequest provider.Volume) (volumeRespo
vpcs.Logger.Debug("Failed to create volume from VPC provider", zap.Reflect("BackendError", err))
return nil, userError.GetUserError("FailedToPlaceOrder", err)
}
if volume == nil {
vpcs.Logger.Error("CreateFileShare returned nil volume but no error")
return nil, userError.GetUserError("FailedToPlaceOrder", fmt.Errorf("nil volume received from backend"))
}

vpcs.Logger.Info("Successfully created volume from VPC provider...", zap.Reflect("VolumeDetails", volume))

Expand All @@ -134,45 +161,64 @@ func (vpcs *VPCSession) CreateVolume(volumeRequest provider.Volume) (volumeRespo
return volumeResponse, err
}

func contains(slice []string, item string) bool {
for _, v := range slice {
if v == item {
return true
}
}
return false
}

// validateVolumeRequest validating volume request
func validateVolumeRequest(volumeRequest provider.Volume) (models.ResourceGroup, int64, error) {
func validateVolumeRequest(volumeRequest provider.Volume) (models.ResourceGroup, int64, int64, error) {
resourceGroup := models.ResourceGroup{}
var iops int64
var bandwidth int64 = 0
iops = 0

// Volume name should not be empty
if volumeRequest.Name == nil {
return resourceGroup, iops, userError.GetUserError("InvalidVolumeName", nil, nil)
return resourceGroup, iops, 0, userError.GetUserError("InvalidVolumeName", nil, nil)
} else if len(*volumeRequest.Name) == 0 {
return resourceGroup, iops, userError.GetUserError("InvalidVolumeName", nil, *volumeRequest.Name)
return resourceGroup, iops, 0, userError.GetUserError("InvalidVolumeName", nil, *volumeRequest.Name)
}

// Capacity should not be empty
if volumeRequest.Capacity == nil {
return resourceGroup, iops, userError.GetUserError("VolumeCapacityInvalid", nil, nil)
return resourceGroup, iops, 0, userError.GetUserError("VolumeCapacityInvalid", nil, nil)
} else if *volumeRequest.Capacity < minSize {
return resourceGroup, iops, userError.GetUserError("VolumeCapacityInvalid", nil, *volumeRequest.Capacity)
return resourceGroup, iops, 0, userError.GetUserError("VolumeCapacityInvalid", nil, *volumeRequest.Capacity)
}

// Read user provided error, no harm to pass the 0 values to RIaaS in case of tiered profiles
if volumeRequest.Iops != nil {
iops = ToInt64(*volumeRequest.Iops)
}

if volumeRequest.Bandwidth != nil {
bandwidth = ToInt64(*volumeRequest.Bandwidth)
}

if volumeRequest.VPCVolume.Profile == nil {
return resourceGroup, iops, userError.GetUserError("VolumeProfileEmpty", nil)
return resourceGroup, iops, 0, userError.GetUserError("VolumeProfileEmpty", nil)
}
if volumeRequest.VPCVolume.Profile.Name != customProfile && volumeRequest.VPCVolume.Profile.Name != dp2Profile && iops > 0 {
return resourceGroup, iops, userError.GetUserError("VolumeProfileIopsInvalid", nil)

profile := volumeRequest.VPCVolume.Profile.Name
if !contains(SupportedProfiles, profile) {
return resourceGroup, iops, bandwidth, userError.GetUserError("VolumeProfileNotSupported", nil)
}

// validate and add resource group ID or Name whichever is provided by user
if volumeRequest.VPCVolume.ResourceGroup == nil {
return resourceGroup, iops, userError.GetUserError("EmptyResourceGroup", nil)
if iops > 0 && !contains(IOPSAllowedProfiles, profile) {
return resourceGroup, iops, bandwidth, userError.GetUserError("VolumeProfileIopsInvalid", nil)
}

// validate and add resource group ID or Name whichever is provided by user
if len(volumeRequest.VPCVolume.ResourceGroup.ID) == 0 && len(volumeRequest.VPCVolume.ResourceGroup.Name) == 0 {
return resourceGroup, iops, userError.GetUserError("EmptyResourceGroupIDandName", nil)
if bandwidth > 0 && !contains(BandwidthAllowedProfiles, profile) {
return resourceGroup, iops, bandwidth, userError.GetUserError("VolumeProfileBandwidthInvalid", nil)
}

if volumeRequest.VPCVolume.ResourceGroup == nil {
return resourceGroup, iops, bandwidth, userError.GetUserError("EmptyResourceGroup", nil)
}

if len(volumeRequest.VPCVolume.ResourceGroup.ID) > 0 {
Expand All @@ -183,7 +229,7 @@ func validateVolumeRequest(volumeRequest provider.Volume) (models.ResourceGroup,
resourceGroup.Name = volumeRequest.VPCVolume.ResourceGroup.Name
}

return resourceGroup, iops, nil
return resourceGroup, iops, bandwidth, nil
}

func setENIParameters(shareTarget *models.ShareTarget, volumeRequest provider.Volume) {
Expand Down
Loading