Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
335e58f
Enhance RFS volume support: add bandwidth/iops update handling, omit …
renukasingare Jun 25, 2025
11b0718
updated new changes for regional file
renukasingare Jun 28, 2025
4c9fb43
removed unnesasory comment
renukasingare Jun 28, 2025
934cd8d
fixed travis issues
renukasingare Jul 3, 2025
adbcf25
test.go files error
renukasingare Jul 4, 2025
4fc591a
removed glide and ppa
renukasingare Jul 7, 2025
0693822
fixed test.go file again
renukasingare Jul 7, 2025
afdaed8
updated config
renukasingare Jul 8, 2025
e50b28a
removed config file
renukasingare Jul 8, 2025
73bbe0c
addressed comments
renukasingare Jul 12, 2025
7f04972
removed unnassasory comments
renukasingare Jul 12, 2025
ef83869
removed unnassasory comments
renukasingare Jul 12, 2025
9408b07
Adressed comments
renukasingare Jul 14, 2025
d9e5359
removed unnassory changes
renukasingare Jul 14, 2025
79ee4f0
added retry code again
renukasingare Jul 15, 2025
a817ffc
added zone validation
renukasingare Jul 15, 2025
c0fd84f
updated version
renukasingare Jul 16, 2025
4dd651a
Addressed comment
renukasingare Jul 29, 2025
caa7925
Addressed comment
renukasingare Jul 29, 2025
9abc610
Fixed travis issue
renukasingare Jul 29, 2025
c6c661f
Addressed the comments
renukasingare Jul 30, 2025
054a27a
Adressed comment
renukasingare Jul 30, 2025
ca8a677
Addressed comment
renukasingare Jul 30, 2025
c46b472
Added UT of regional file
renukasingare Aug 1, 2025
24d216b
Addressed PR comments
renukasingare Aug 6, 2025
7a7c090
changed date
renukasingare Aug 7, 2025
d367d89
Added accessprotocol
renukasingare Aug 7, 2025
dccd18f
added accessprotocol validation
renukasingare Aug 7, 2025
285ad73
Added accessprotocol validation
renukasingare Aug 7, 2025
25b8c71
Addressed PR comments
renukasingare Aug 7, 2025
0fcf942
fixed traivs issue
renukasingare Aug 7, 2025
88e0ca2
Addressed PR comment
renukasingare Aug 8, 2025
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
2 changes: 0 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ sudo: true
before_install:
- openssl aes-256-cbc -K $encrypted_7937b810c182_key -iv $encrypted_7937b810c182_iv
-in ./e2e/config/secret.txt.enc -out secret.txt -d || true
- sudo add-apt-repository ppa:masterminds/glide -y && sudo apt-get update -q
- sudo apt-get install glide -y
- sudo apt-get install bc

before_script:
Expand Down
2 changes: 1 addition & 1 deletion common/vpcclient/models/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package models

const (
// APIVersion is the target RIaaS API spec version
APIVersion = "2023-07-11"
APIVersion = "2025-08-05"

// APIGeneration ...
APIGeneration = 1
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 @@ -30,6 +30,7 @@ type Share struct {
Size int64 `json:"size,omitempty"`
Iops int64 `json:"iops,omitempty"`
EncryptionKey *EncryptionKey `json:"encryption_key,omitempty"`
Bandwidth int32 `json:"bandwidth,omitempty"`
ResourceGroup *ResourceGroup `json:"resource_group,omitempty"`
InitialOwner *InitialOwner `json:"initial_owner,omitempty"`
Profile *Profile `json:"profile,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions common/vpcclient/models/share_target.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type ShareTarget struct {
VPC *provider.VPC `json:"vpc,omitempty"`
//EncryptionInTransit
TransitEncryption string `json:"transit_encryption,omitempty"`
AccessProtocol string `json:"access_protocol,omitempty"`
VirtualNetworkInterface *VirtualNetworkInterface `json:"virtual_network_interface,omitempty"`
//Share ID this target is associated to
ShareID string `json:"-"`
Expand Down
1 change: 1 addition & 0 deletions common/vpcclient/riaas/riaas.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ func New(config Config) (*Session, error) {
queryValues := url.Values{
"version": []string{backendAPIVersion},
"generation": []string{strconv.Itoa(apiGen)},
"maturity": []string{"beta"},
}

riaasClient := client.New(ctx, config.baseURL(), queryValues, config.httpClient(), config.ContextID, config.ResourceGroup)
Expand Down
61 changes: 40 additions & 21 deletions file/provider/create_volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,8 @@ import (
)

const (
minSize = 10 //10 GB
maxSize = 16000 //16 TB
customProfile = "custom-iops"
dp2Profile = "dp2"
minSize = 10 //10 GB
RFSProfile = "rfs"
)

// CreateVolume creates file share
Expand All @@ -40,27 +38,37 @@ func (vpcs *VPCSession) CreateVolume(volumeRequest provider.Volume) (volumeRespo
defer vpcs.Logger.Debug("Exit from CreateVolume method...")
defer metrics.UpdateDurationFromStart(vpcs.Logger, "CreateVolume", time.Now())

var iops int64
var bandwidth int32
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... ")

// Set zone if provided
var zone *models.Zone
if volumeRequest.Az != "" {
zone = &models.Zone{
Name: volumeRequest.Az,
}
}

// Build the share template to send to backend
shareTemplate := &models.Share{
Name: *volumeRequest.Name,
Size: int64(*volumeRequest.Capacity),
InitialOwner: (*models.InitialOwner)(volumeRequest.InitialOwner),
Iops: iops,
Bandwidth: bandwidth,
AccessControlMode: volumeRequest.AccessControlMode,
ResourceGroup: &resourceGroup,
Profile: &models.Profile{
Name: volumeRequest.VPCVolume.Profile.Name,
},
Zone: &models.Zone{
Name: volumeRequest.Az,
},
Zone: zone,
}

// Check for VPC ID, SubnetID or PrimaryIPID either of the one is mandatory for VolumeAccessPoint/FileShareTarget creation
Expand All @@ -87,6 +95,12 @@ func (vpcs *VPCSession) CreateVolume(volumeRequest provider.Volume) (volumeRespo
shareTargetTemplate.TransitEncryption = volumeRequest.TransitEncryption
}

// Set access_protocol and transit_encryption ONLY for 'rfs' profile
if volumeRequest.VPCVolume.Profile != nil && volumeRequest.VPCVolume.Profile.Name == RFSProfile {
shareTargetTemplate.AccessProtocol = "nfs4"
shareTargetTemplate.TransitEncryption = "none"
}

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

Expand All @@ -101,6 +115,7 @@ func (vpcs *VPCSession) CreateVolume(volumeRequest provider.Volume) (volumeRespo

vpcs.Logger.Info("Calling VPC provider for volume creation...")
var volume *models.Share

err = retry(vpcs.Logger, func() error {
volume, err = vpcs.Apiclient.FileShareService().CreateFileShare(shareTemplate, vpcs.Logger)
return err
Expand All @@ -118,6 +133,7 @@ func (vpcs *VPCSession) CreateVolume(volumeRequest provider.Volume) (volumeRespo
if err != nil {
return nil, userError.GetUserError("VolumeNotInValidState", err, volume.ID)
}

vpcs.Logger.Info("Volume got valid (stable) state", zap.Reflect("VolumeDetails", volume))

// Converting share to lib volume type
Expand All @@ -135,44 +151,47 @@ func (vpcs *VPCSession) CreateVolume(volumeRequest provider.Volume) (volumeRespo
}

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

// Volume name should not be empty
if volumeRequest.Name == nil {
return resourceGroup, iops, userError.GetUserError("InvalidVolumeName", nil, nil)
return resourceGroup, iops, bandwidth, userError.GetUserError("InvalidVolumeName", nil, nil)
} else if len(*volumeRequest.Name) == 0 {
return resourceGroup, iops, userError.GetUserError("InvalidVolumeName", nil, *volumeRequest.Name)
return resourceGroup, iops, bandwidth, 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, bandwidth, userError.GetUserError("VolumeCapacityInvalid", nil, nil)
} else if *volumeRequest.Capacity < minSize {
return resourceGroup, iops, userError.GetUserError("VolumeCapacityInvalid", nil, *volumeRequest.Capacity)
return resourceGroup, iops, bandwidth, 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.VPCVolume.Profile == nil {
return resourceGroup, iops, userError.GetUserError("VolumeProfileEmpty", nil)

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

if volumeRequest.VPCVolume.Profile == nil {
return resourceGroup, iops, bandwidth, userError.GetUserError("VolumeProfileEmpty", 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)
return resourceGroup, iops, bandwidth, userError.GetUserError("EmptyResourceGroup", 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)
return resourceGroup, iops, bandwidth, userError.GetUserError("EmptyResourceGroupIDandName", nil)
}

if len(volumeRequest.VPCVolume.ResourceGroup.ID) > 0 {
Expand All @@ -183,7 +202,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
138 changes: 138 additions & 0 deletions file/provider/create_volume_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,144 @@ func TestCreateVolume(t *testing.T) {
assert.NotNil(t, err)
},
},
{
testCaseName: "No Bandwidth",
profileName: "rfs",
baseVolume: &models.Share{
ID: "vol-no-bw",
Name: "volume-no-bandwidth",
Status: models.StatusType("stable"),
Size: int64(1024),
Zone: &models.Zone{Name: "zone1"},
},
providerVolume: provider.Volume{
VolumeID: "vol-no-bw",
Name: String("volume-no-bandwidth"),
Capacity: Int(1024),
VPCVolume: provider.VPCVolume{
Profile: &provider.Profile{Name: "rfs"},
ResourceGroup: &provider.ResourceGroup{ID: "rg-1", Name: "rg1"},
},
},
},
{
testCaseName: "Min Bandwidth and Min Size",
profileName: "rfs",
baseVolume: &models.Share{
ID: "vol-min-bw",
Name: "volume-min-bandwidth",
Status: models.StatusType("stable"),
Size: int64(10),
Bandwidth: int32(25),
Zone: &models.Zone{Name: "zone1"},
},
providerVolume: provider.Volume{
VolumeID: "vol-min-bw",
Name: String("volume-min-bandwidth"),
Capacity: Int(10),
VPCVolume: provider.VPCVolume{
Profile: &provider.Profile{Name: "rfs"},
Bandwidth: int32(25),
ResourceGroup: &provider.ResourceGroup{ID: "rg-1", Name: "rg1"},
},
},
verify: func(t *testing.T, volumeResponse *provider.Volume, err error) {
assert.NotNil(t, volumeResponse)
assert.Nil(t, err)
},
},
{
testCaseName: "Valid Bandwidth and Invalid Size",
profileName: "rfs",
baseVolume: &models.Share{
ID: "vol-valid-bw",
Name: "volume-valid-bandwidth",
Status: models.StatusType("stable"),
Size: int64(34000),
Bandwidth: int32(8192),
Zone: &models.Zone{Name: "zone1"},
},
providerVolume: provider.Volume{
VolumeID: "vol-valid-bw",
Name: String("volume-valid-bandwidth"),
Capacity: Int(34000),
VPCVolume: provider.VPCVolume{
Profile: &provider.Profile{Name: "rfs"},
Bandwidth: int32(8192),
ResourceGroup: &provider.ResourceGroup{ID: "rg-1", Name: "rg1"},
},
},
verify: func(t *testing.T, volumeResponse *provider.Volume, err error) {
assert.NotNil(t, volumeResponse)
assert.Nil(t, err)
},
},
{
testCaseName: "Invalid Bandwidth and Valid Size",
profileName: "rfs",
baseVolume: &models.Share{
ID: "vol-invalid-bw",
Name: "volume-invalid-bandwidth",
Status: models.StatusType("stable"),
Size: int64(1000),
Bandwidth: int32(9000),
Zone: &models.Zone{Name: "zone1"},
},
providerVolume: provider.Volume{
VolumeID: "vol-invalid-bw",
Name: String("volume-invalid-bandwidth"),
Capacity: Int(1000),
VPCVolume: provider.VPCVolume{
Profile: &provider.Profile{Name: "rfs"},
Bandwidth: int32(9000),
ResourceGroup: &provider.ResourceGroup{ID: "rg-1", Name: "rg1"},
},
},
verify: func(t *testing.T, volumeResponse *provider.Volume, err error) {
assert.NotNil(t, volumeResponse)
assert.Nil(t, err)
},
},
{
testCaseName: "Zero Bandwidth",
profileName: "rfs",
providerVolume: provider.Volume{
VolumeID: "vol-zero-bw",
Name: String("volume-zero-bandwidth"),
Capacity: Int(100),
VPCVolume: provider.VPCVolume{
Profile: &provider.Profile{Name: "rfs"},
Bandwidth: 0,
ResourceGroup: &provider.ResourceGroup{ID: "rg-1", Name: "rg1"},
},
},
expectedErr: "{Code:ErrorUnclassified, Type:InvalidRequest, Description: bandwidth must be between '1' Mbps and '8192' Mbps for the specified size of 10 GB. }",
expectedReasonCode: "ErrorUnclassified",
verify: func(t *testing.T, volumeResponse *provider.Volume, err error) {
assert.Nil(t, volumeResponse)
assert.NotNil(t, err)
},
},
{
testCaseName: "Invalid Bandwidth - 9000",
profileName: "rfs",
providerVolume: provider.Volume{
VolumeID: "vol-invalid-bw",
Name: String("volume-invalid-bandwidth"),
Capacity: Int(100),
VPCVolume: provider.VPCVolume{
Profile: &provider.Profile{Name: "rfs"},
Bandwidth: int32(9000),
ResourceGroup: &provider.ResourceGroup{ID: "rg-1", Name: "rg1"},
},
},
expectedErr: "{Code:ErrorUnclassified, Type:InvalidRequest, Description: bandwidth must be between '1' Mbps and '8192' Mbps for the specified size of 10 GB. }",
expectedReasonCode: "ErrorUnclassified",
verify: func(t *testing.T, volumeResponse *provider.Volume, err error) {
assert.Nil(t, volumeResponse)
assert.NotNil(t, err)
},
},
}

for _, testcase := range testCases {
Expand Down
Loading