Skip to content

Commit 64196e6

Browse files
authoredMay 27, 2024··
Get max drive size cloudops interface (#166)
Signed-off-by: Prince <[email protected]>
1 parent f78dd2f commit 64196e6

File tree

17 files changed

+763
-123
lines changed

17 files changed

+763
-123
lines changed
 

‎aws/storagemanager/aws.go

+6
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ func (a *awsStorageManager) RecommendStoragePoolUpdate(
7979
return resp, nil
8080
}
8181

82+
func (a *awsStorageManager) GetMaxDriveSize(
83+
request *cloudops.MaxDriveSizeRequest) (*cloudops.MaxDriveSizeResponse, error) {
84+
resp, err := storagedistribution.GetMaxDriveSize(request, a.decisionMatrix)
85+
return resp, err
86+
}
87+
8288
func determineIOPSForPool(instStorage *cloudops.StoragePoolSpec, row *cloudops.StorageDecisionMatrixRow, currentIOPS uint64) uint64 {
8389
if instStorage.DriveType == DriveTypeGp2 {
8490
return instStorage.DriveCapacityGiB * Gp2IopsMultiplier

‎aws/storagemanager/aws_test.go

+61
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ func TestAWSStorageManager(t *testing.T) {
3030
t.Run("setup", setup)
3131
t.Run("storageDistribution", storageDistribution)
3232
t.Run("storageUpdate", storageUpdate)
33+
t.Run("maxDriveSize", maxDriveSize)
3334
}
3435

3536
func setup(t *testing.T) {
@@ -775,6 +776,66 @@ func storageUpdate(t *testing.T) {
775776
}
776777
}
777778

779+
func maxDriveSize(t *testing.T) {
780+
testMatrix := []struct {
781+
expectedErr error
782+
request *cloudops.MaxDriveSizeRequest
783+
response *cloudops.MaxDriveSizeResponse
784+
}{
785+
{
786+
// Test1: empty drive type
787+
request: &cloudops.MaxDriveSizeRequest{
788+
DriveType: "",
789+
},
790+
response: nil,
791+
expectedErr: &cloudops.ErrInvalidMaxDriveSizeRequest{Request: &cloudops.MaxDriveSizeRequest{DriveType: ""}, Reason: "empty drive type"},
792+
},
793+
{
794+
// Test2: invalid drive type
795+
request: &cloudops.MaxDriveSizeRequest{
796+
DriveType: "invalid_drive",
797+
},
798+
response: nil,
799+
expectedErr: &cloudops.ErrMaxDriveSizeCandidateNotFound{Request: &cloudops.MaxDriveSizeRequest{DriveType: "invalid_drive"}, Reason: "no matching inputs found for input drive type"},
800+
},
801+
802+
{
803+
// Test3: gp2 drive
804+
request: &cloudops.MaxDriveSizeRequest{
805+
DriveType: "gp2",
806+
},
807+
response: &cloudops.MaxDriveSizeResponse{
808+
MaxSize: 16000,
809+
},
810+
expectedErr: nil,
811+
},
812+
813+
{
814+
// Test4: io1 drive
815+
request: &cloudops.MaxDriveSizeRequest{
816+
DriveType: "io1",
817+
},
818+
response: &cloudops.MaxDriveSizeResponse{
819+
MaxSize: 16000,
820+
},
821+
expectedErr: nil,
822+
},
823+
}
824+
825+
for j, test := range testMatrix {
826+
fmt.Println("Executing test case: ", j+1)
827+
response, err := storageManager.GetMaxDriveSize(test.request)
828+
if test.expectedErr == nil {
829+
require.Nil(t, err, "GetMaxDriveSize returned an error")
830+
require.NotNil(t, response, "GetMaxDriveSize returned empty response")
831+
require.Equal(t, test.response.MaxSize, response.MaxSize, "expected and actual max drive size not equal")
832+
} else {
833+
require.NotNil(t, err, "GetMaxDriveSize should have returned an error")
834+
require.Equal(t, test.expectedErr.Error(), err.Error(), "received unexpected type of error")
835+
}
836+
}
837+
}
838+
778839
func logUpdateTestInput(test updateTestInput) {
779840
logrus.Infof("### RUNNING TEST")
780841
logrus.Infof("### REQUEST: new capacity: %d GiB op_type: %v",

‎azure/storagemanager/azure.go

+6
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ func (a *azureStorageManager) RecommendStoragePoolUpdate(
6767
return resp, nil
6868
}
6969

70+
func (a *azureStorageManager) GetMaxDriveSize(
71+
request *cloudops.MaxDriveSizeRequest) (*cloudops.MaxDriveSizeResponse, error) {
72+
resp, err := storagedistribution.GetMaxDriveSize(request, a.decisionMatrix)
73+
return resp, err
74+
}
75+
7076
func determineIOPSForPool(row *cloudops.StorageDecisionMatrixRow) uint64 {
7177
return row.MinIOPS
7278
}

‎azure/storagemanager/azure_test.go

+94
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func TestAzureStorageManager(t *testing.T) {
3333
t.Run("setup", setup)
3434
t.Run("storageDistribution", storageDistribution)
3535
t.Run("storageUpdate", storageUpdate)
36+
t.Run("maxDriveSize", maxDriveSize)
3637
}
3738

3839
func setup(t *testing.T) {
@@ -783,6 +784,99 @@ func storageUpdate(t *testing.T) {
783784
}
784785
}
785786

787+
func maxDriveSize(t *testing.T) {
788+
testMatrix := []struct {
789+
expectedErr error
790+
request *cloudops.MaxDriveSizeRequest
791+
response *cloudops.MaxDriveSizeResponse
792+
}{
793+
{
794+
// Test1: empty drive type
795+
request: &cloudops.MaxDriveSizeRequest{
796+
DriveType: "",
797+
},
798+
response: nil,
799+
expectedErr: &cloudops.ErrInvalidMaxDriveSizeRequest{Request: &cloudops.MaxDriveSizeRequest{DriveType: ""}, Reason: "empty drive type"},
800+
},
801+
{
802+
// Test2: invalid drive type
803+
request: &cloudops.MaxDriveSizeRequest{
804+
DriveType: "invalid_drive",
805+
},
806+
response: nil,
807+
expectedErr: &cloudops.ErrMaxDriveSizeCandidateNotFound{Request: &cloudops.MaxDriveSizeRequest{DriveType: "invalid_drive"}, Reason: "no matching inputs found for input drive type"},
808+
},
809+
810+
{
811+
// Test3: Premium_LRS drive
812+
request: &cloudops.MaxDriveSizeRequest{
813+
DriveType: "Premium_LRS",
814+
},
815+
response: &cloudops.MaxDriveSizeResponse{
816+
MaxSize: 32768,
817+
},
818+
expectedErr: nil,
819+
},
820+
821+
{
822+
// Test4: StandardSSD_LRS drive
823+
request: &cloudops.MaxDriveSizeRequest{
824+
DriveType: "StandardSSD_LRS",
825+
},
826+
response: &cloudops.MaxDriveSizeResponse{
827+
MaxSize: 32768,
828+
},
829+
expectedErr: nil,
830+
},
831+
832+
{
833+
// Test5: Standard_LRS drive
834+
request: &cloudops.MaxDriveSizeRequest{
835+
DriveType: "Standard_LRS",
836+
},
837+
response: &cloudops.MaxDriveSizeResponse{
838+
MaxSize: 32768,
839+
},
840+
expectedErr: nil,
841+
},
842+
843+
{
844+
// Test6: PremiumV2_LRS drive
845+
request: &cloudops.MaxDriveSizeRequest{
846+
DriveType: "PremiumV2_LRS",
847+
},
848+
response: &cloudops.MaxDriveSizeResponse{
849+
MaxSize: 65536,
850+
},
851+
expectedErr: nil,
852+
},
853+
854+
{
855+
// Test7: UltraSSD_LRS drive
856+
request: &cloudops.MaxDriveSizeRequest{
857+
DriveType: "UltraSSD_LRS",
858+
},
859+
response: &cloudops.MaxDriveSizeResponse{
860+
MaxSize: 65536,
861+
},
862+
expectedErr: nil,
863+
},
864+
}
865+
866+
for j, test := range testMatrix {
867+
fmt.Println("Executing test case: ", j+1)
868+
response, err := storageManager.GetMaxDriveSize(test.request)
869+
if test.expectedErr == nil {
870+
require.Nil(t, err, "GetMaxDriveSize returned an error")
871+
require.NotNil(t, response, "GetMaxDriveSize returned empty response")
872+
require.Equal(t, test.response.MaxSize, response.MaxSize, "expected and actual max drive size not equal")
873+
} else {
874+
require.NotNil(t, err, "GetMaxDriveSize should have returned an error")
875+
require.Equal(t, test.expectedErr.Error(), err.Error(), "received unexpected type of error")
876+
}
877+
}
878+
}
879+
786880
func logUpdateTestInput(test updateTestInput) {
787881
logrus.Infof("### RUNNING TEST")
788882
logrus.Infof("### REQUEST: new capacity: %d GiB op_type: %v",

‎cloud_storage_management.go

+20
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,17 @@ type StoragePoolUpdateResponse struct {
155155
ResizeOperationType api.SdkStoragePool_ResizeOperationType
156156
}
157157

158+
type MaxDriveSizeRequest struct {
159+
// DriveType is the type of drive specified in terms of cloud provided names.
160+
DriveType string `json:"drive_type" yaml:"drive_type"`
161+
}
162+
163+
type MaxDriveSizeResponse struct {
164+
// MaxSize is the maximum size of the drive that can be provisioned
165+
// for input drive type.
166+
MaxSize uint64 `json:"max_size" yaml:"max_size"`
167+
}
168+
158169
// StorageManager interface provides a set of APIs to manage cloud storage drives
159170
// across multiple nodes in the cluster.
160171
type StorageManager interface {
@@ -163,6 +174,8 @@ type StorageManager interface {
163174
// RecommendStoragePoolUpdate returns the recommended storage configuration on
164175
// the instance based on the given request
165176
RecommendStoragePoolUpdate(request *StoragePoolUpdateRequest) (*StoragePoolUpdateResponse, error)
177+
// GetMaxDriveSize returns the maximum size a drive can expand to for given cloud drive type
178+
GetMaxDriveSize(request *MaxDriveSizeRequest) (*MaxDriveSizeResponse, error)
166179
}
167180

168181
var (
@@ -310,3 +323,10 @@ func (dm *StorageDecisionMatrix) SortByPriority() {
310323
return dm.Rows[l].Priority < dm.Rows[r].Priority
311324
})
312325
}
326+
327+
// SortByMaxSize sorts the rows of the decision matrix in descending order by MaxSize supported by that row.
328+
func (dm *StorageDecisionMatrix) SortByMaxSize() {
329+
sort.SliceStable(dm.Rows, func(l, r int) bool {
330+
return dm.Rows[l].MaxSize > dm.Rows[r].MaxSize
331+
})
332+
}

‎csi/storagemanager/csi.go

+6
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ func (a *csiStorageManager) RecommendStoragePoolUpdate(
6363
return resp, err
6464
}
6565

66+
func (a *csiStorageManager) GetMaxDriveSize(
67+
request *cloudops.MaxDriveSizeRequest) (*cloudops.MaxDriveSizeResponse, error) {
68+
resp, err := storagedistribution.GetMaxDriveSize(request, a.decisionMatrix)
69+
return resp, err
70+
}
71+
6672
func init() {
6773
cloudops.RegisterStorageManager(cloudops.CSI, newCSIStorageManager)
6874
}

‎errors.go

+28
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,31 @@ type ErrCloudProviderRequestFailure struct {
126126
func (e *ErrCloudProviderRequestFailure) Error() string {
127127
return fmt.Sprintf("Request %s returns %s", e.Request, e.Message)
128128
}
129+
130+
// ErrInvalidMaxDriveSizeRequest is returned when an unsupported or invalid request
131+
// is sent to get the max drive size
132+
type ErrInvalidMaxDriveSizeRequest struct {
133+
// Request is the request that caused the invalid error
134+
Request *MaxDriveSizeRequest
135+
// Reason is the reason why the request was invalid
136+
Reason string
137+
}
138+
139+
func (e *ErrInvalidMaxDriveSizeRequest) Error() string {
140+
return fmt.Sprintf("Invalid request to get the max drive size: %s Request: %v",
141+
e.Reason, e.Request)
142+
}
143+
144+
// ErrMaxDriveSizeCandidateNotFound is returned when an unsupported or invalid request
145+
// is sent to get the max drive size
146+
type ErrMaxDriveSizeCandidateNotFound struct {
147+
// Request is the request that caused the error
148+
Request *MaxDriveSizeRequest
149+
// Reason is the reason why the request caused an error
150+
Reason string
151+
}
152+
153+
func (e *ErrMaxDriveSizeCandidateNotFound) Error() string {
154+
return fmt.Sprintf("could not find a suitable max drive size candidate: %s Request: %v",
155+
e.Reason, e.Request)
156+
}

‎gce/storagemanager/gce.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ const (
4343
GCESSDMaxIopsLeast uint64 = 15000
4444
// GCESSDMaxIopsMost is the most of all the maximum iops that can be achieved with disk type px-ssd.
4545
GCESSDMaxIopsMost uint64 = 100000
46-
4746
)
4847

4948
// NewStorageManager returns a GCE specific implementation of StorageManager interface.
@@ -125,6 +124,19 @@ func (g *gceStorageManager) RecommendStoragePoolUpdate(request *cloudops.Storage
125124
return resp, nil
126125
}
127126

127+
func (g *gceStorageManager) GetMaxDriveSize(request *cloudops.MaxDriveSizeRequest) (*cloudops.MaxDriveSizeResponse, error) {
128+
// this hack is required because the gce drive type comes as urls:
129+
// https://www.googleapis.com/compute/v1/projects/portworx-eng/zones/us-east1-b/diskTypes/pd-standard
130+
// or https://www.googleapis.com/compute/v1/projects/portworx-eng/zones/us-east1-b/diskTypes/pd-ssd
131+
if request.DriveType != "" {
132+
split := strings.Split(request.DriveType, "/")
133+
request.DriveType = split[len(split)-1]
134+
}
135+
136+
resp, err := storagedistribution.GetMaxDriveSize(request, g.decisionMatrix)
137+
return resp, err
138+
}
139+
128140
func determineIOPSForPool(instStorage *cloudops.StoragePoolSpec, row *cloudops.StorageDecisionMatrixRow) uint64 {
129141
iops := uint64(0)
130142
maxIops := uint64(0)

‎gce/storagemanager/gce_test.go

+72
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ func TestGCEStorageManager(t *testing.T) {
3030
t.Run("setup", setup)
3131
t.Run("storageDistribution", storageDistribution)
3232
t.Run("storageUpdate", storageUpdate)
33+
t.Run("maxDriveSize", maxDriveSize)
3334
}
3435

3536
func setup(t *testing.T) {
@@ -821,6 +822,77 @@ func storageUpdate(t *testing.T) {
821822
}
822823
}
823824

825+
func maxDriveSize(t *testing.T) {
826+
testMatrix := []struct {
827+
expectedErr error
828+
request *cloudops.MaxDriveSizeRequest
829+
response *cloudops.MaxDriveSizeResponse
830+
}{
831+
{
832+
// Test1: empty drive type
833+
request: &cloudops.MaxDriveSizeRequest{
834+
DriveType: "",
835+
},
836+
response: nil,
837+
expectedErr: &cloudops.ErrInvalidMaxDriveSizeRequest{Request: &cloudops.MaxDriveSizeRequest{DriveType: ""}, Reason: "empty drive type"},
838+
},
839+
{
840+
// Test2: invalid drive type
841+
request: &cloudops.MaxDriveSizeRequest{
842+
DriveType: "invalid_drive",
843+
},
844+
response: nil,
845+
expectedErr: &cloudops.ErrMaxDriveSizeCandidateNotFound{Request: &cloudops.MaxDriveSizeRequest{DriveType: "invalid_drive"}, Reason: "no matching inputs found for input drive type"},
846+
},
847+
848+
{
849+
// Test3: GCEDriveTypeStandard drive
850+
request: &cloudops.MaxDriveSizeRequest{
851+
DriveType: genDriveType(GCEDriveTypeBalanced),
852+
},
853+
response: &cloudops.MaxDriveSizeResponse{
854+
MaxSize: 64000,
855+
},
856+
expectedErr: nil,
857+
},
858+
859+
{
860+
// Test4: GCEDriveTypeBalanced drive
861+
request: &cloudops.MaxDriveSizeRequest{
862+
DriveType: genDriveType(GCEDriveTypeBalanced),
863+
},
864+
response: &cloudops.MaxDriveSizeResponse{
865+
MaxSize: 64000,
866+
},
867+
expectedErr: nil,
868+
},
869+
870+
{
871+
// Test5: GCEDriveTypeSSD drive
872+
request: &cloudops.MaxDriveSizeRequest{
873+
DriveType: genDriveType(GCEDriveTypeSSD),
874+
},
875+
response: &cloudops.MaxDriveSizeResponse{
876+
MaxSize: 64000,
877+
},
878+
expectedErr: nil,
879+
},
880+
}
881+
882+
for j, test := range testMatrix {
883+
fmt.Println("Executing test case: ", j+1)
884+
response, err := storageManager.GetMaxDriveSize(test.request)
885+
if test.expectedErr == nil {
886+
require.Nil(t, err, "GetMaxDriveSize returned an error")
887+
require.NotNil(t, response, "GetMaxDriveSize returned empty response")
888+
require.Equal(t, test.response.MaxSize, response.MaxSize, "expected and actual max drive size not equal")
889+
} else {
890+
require.NotNil(t, err, "GetMaxDriveSize should have returned an error")
891+
require.Equal(t, test.expectedErr.Error(), err.Error(), "received unexpected type of error")
892+
}
893+
}
894+
}
895+
824896
func genDriveType(dType string) string {
825897
// the gce drive path comes as https://www.googleapis.com/compute/v1/projects/portworx-eng/zones/us-east1-b/diskTypes/pd-standard
826898
// or https://www.googleapis.com/compute/v1/projects/portworx-eng/zones/us-east1-b/diskTypes/pd-ssd

‎mock/cloud_storage_management.mock.go

+24-10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎mock/cloudops.mock.go

+81-82
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎oracle/storagemanager/oracle.go

+6
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ func (o *oracleStorageManager) RecommendStoragePoolUpdate(request *cloudops.Stor
7070
return resp, nil
7171
}
7272

73+
func (o *oracleStorageManager) GetMaxDriveSize(
74+
request *cloudops.MaxDriveSizeRequest) (*cloudops.MaxDriveSizeResponse, error) {
75+
resp, err := storagedistribution.GetMaxDriveSize(request, o.decisionMatrix)
76+
return resp, err
77+
}
78+
7379
func determineIOPSForPool(instStorage *cloudops.StoragePoolSpec, row *cloudops.StorageDecisionMatrixRow) uint64 {
7480
var iopsPerGB, maxIopsPerVol int64
7581
switch row.DriveType {

‎oracle/storagemanager/oracle_test.go

+182
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ func TestOracleStorageManager(t *testing.T) {
3030
t.Run("setup", setup)
3131
t.Run("storageDistribution", storageDistribution)
3232
t.Run("storageUpdate", storageUpdate)
33+
t.Run("maxDriveSize", maxDriveSize)
3334
}
3435

3536
func setup(t *testing.T) {
@@ -564,3 +565,184 @@ func storageUpdate(t *testing.T) {
564565
}
565566
}
566567
}
568+
569+
func maxDriveSize(t *testing.T) {
570+
testMatrix := []struct {
571+
expectedErr error
572+
request *cloudops.MaxDriveSizeRequest
573+
response *cloudops.MaxDriveSizeResponse
574+
}{
575+
{
576+
// Test1: empty drive type
577+
request: &cloudops.MaxDriveSizeRequest{
578+
DriveType: "",
579+
},
580+
response: nil,
581+
expectedErr: &cloudops.ErrInvalidMaxDriveSizeRequest{Request: &cloudops.MaxDriveSizeRequest{DriveType: ""}, Reason: "empty drive type"},
582+
},
583+
{
584+
// Test2: invalid drive type
585+
request: &cloudops.MaxDriveSizeRequest{
586+
DriveType: "invalid_drive",
587+
},
588+
response: nil,
589+
expectedErr: &cloudops.ErrMaxDriveSizeCandidateNotFound{Request: &cloudops.MaxDriveSizeRequest{DriveType: "invalid_drive"}, Reason: "no matching inputs found for input drive type"},
590+
},
591+
592+
{
593+
// Test3: pv-0 drive
594+
request: &cloudops.MaxDriveSizeRequest{
595+
DriveType: "pv-0",
596+
},
597+
response: &cloudops.MaxDriveSizeResponse{
598+
MaxSize: 32768,
599+
},
600+
expectedErr: nil,
601+
},
602+
603+
{
604+
// Test4: pv-10 drive
605+
request: &cloudops.MaxDriveSizeRequest{
606+
DriveType: "pv-10",
607+
},
608+
response: &cloudops.MaxDriveSizeResponse{
609+
MaxSize: 32768,
610+
},
611+
expectedErr: nil,
612+
},
613+
614+
{
615+
// Test5: pv-20 drive
616+
request: &cloudops.MaxDriveSizeRequest{
617+
DriveType: "pv-20",
618+
},
619+
response: &cloudops.MaxDriveSizeResponse{
620+
MaxSize: 32768,
621+
},
622+
expectedErr: nil,
623+
},
624+
625+
{
626+
// Test6: pv-30 drive
627+
request: &cloudops.MaxDriveSizeRequest{
628+
DriveType: "pv-30",
629+
},
630+
response: &cloudops.MaxDriveSizeResponse{
631+
MaxSize: 32768,
632+
},
633+
expectedErr: nil,
634+
},
635+
636+
{
637+
// Test7: pv-40 drive
638+
request: &cloudops.MaxDriveSizeRequest{
639+
DriveType: "pv-40",
640+
},
641+
response: &cloudops.MaxDriveSizeResponse{
642+
MaxSize: 32768,
643+
},
644+
expectedErr: nil,
645+
},
646+
647+
{
648+
// Test8: pv-50 drive
649+
request: &cloudops.MaxDriveSizeRequest{
650+
DriveType: "pv-50",
651+
},
652+
response: &cloudops.MaxDriveSizeResponse{
653+
MaxSize: 32768,
654+
},
655+
expectedErr: nil,
656+
},
657+
658+
{
659+
// Test9: pv-60 drive
660+
request: &cloudops.MaxDriveSizeRequest{
661+
DriveType: "pv-60",
662+
},
663+
response: &cloudops.MaxDriveSizeResponse{
664+
MaxSize: 32768,
665+
},
666+
expectedErr: nil,
667+
},
668+
669+
{
670+
// Test10: pv-70 drive
671+
request: &cloudops.MaxDriveSizeRequest{
672+
DriveType: "pv-70",
673+
},
674+
response: &cloudops.MaxDriveSizeResponse{
675+
MaxSize: 32768,
676+
},
677+
expectedErr: nil,
678+
},
679+
680+
{
681+
// Test11: pv-80 drive
682+
request: &cloudops.MaxDriveSizeRequest{
683+
DriveType: "pv-80",
684+
},
685+
response: &cloudops.MaxDriveSizeResponse{
686+
MaxSize: 32768,
687+
},
688+
expectedErr: nil,
689+
},
690+
691+
{
692+
// Test12: pv-90 drive
693+
request: &cloudops.MaxDriveSizeRequest{
694+
DriveType: "pv-90",
695+
},
696+
response: &cloudops.MaxDriveSizeResponse{
697+
MaxSize: 32768,
698+
},
699+
expectedErr: nil,
700+
},
701+
702+
{
703+
// Test13: pv-100 drive
704+
request: &cloudops.MaxDriveSizeRequest{
705+
DriveType: "pv-100",
706+
},
707+
response: &cloudops.MaxDriveSizeResponse{
708+
MaxSize: 32768,
709+
},
710+
expectedErr: nil,
711+
},
712+
713+
{
714+
// Test14: pv-110 drive
715+
request: &cloudops.MaxDriveSizeRequest{
716+
DriveType: "pv-110",
717+
},
718+
response: &cloudops.MaxDriveSizeResponse{
719+
MaxSize: 32768,
720+
},
721+
expectedErr: nil,
722+
},
723+
724+
{
725+
// Test15: pv-120 drive
726+
request: &cloudops.MaxDriveSizeRequest{
727+
DriveType: "pv-120",
728+
},
729+
response: &cloudops.MaxDriveSizeResponse{
730+
MaxSize: 32768,
731+
},
732+
expectedErr: nil,
733+
},
734+
}
735+
736+
for j, test := range testMatrix {
737+
fmt.Println("Executing test case: ", j+1)
738+
response, err := storageManager.GetMaxDriveSize(test.request)
739+
if test.expectedErr == nil {
740+
require.Nil(t, err, "GetMaxDriveSize returned an error")
741+
require.NotNil(t, response, "GetMaxDriveSize returned empty response")
742+
require.Equal(t, test.response.MaxSize, response.MaxSize, "expected and actual max drive size not equal")
743+
} else {
744+
require.NotNil(t, err, "GetMaxDriveSize should have returned an error")
745+
require.Equal(t, test.expectedErr.Error(), err.Error(), "received unexpected type of error")
746+
}
747+
}
748+
}

‎pkg/storagedistribution/storagedistribution.go

+77-30
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,14 @@ func GetStorageUpdateConfig(
7070
// - Calculate currentDriveSize from the request. //
7171
// - Calculate the requiredDriveCount for achieving the deltaCapacity. //
7272
// - Find out if any rows from the decision matrix fit in our new configuration //
73-
// - Filter out the rows which do not have the same input.DriveType //
74-
// - Filter out rows which do not fit input.CurrentDriveSize in row.MinSize and row.MaxSize //
75-
// - Filter out rows which do not fit requiredDriveCount in row.InstanceMinDrives and row.InstanceMaxDrives //
73+
// - Filter out the rows which do not have the same input.DriveType //
74+
// - Filter out rows which do not fit input.CurrentDriveSize in row.MinSize and row.MaxSize //
75+
// - Filter out rows which do not fit requiredDriveCount in row.InstanceMinDrives and row.InstanceMaxDrives //
76+
//
7677
// - Pick the 1st row from the decision matrix as your candidate. //
7778
// - If no row found: //
78-
// - failed to AddDisk //
79+
// - failed to AddDisk //
80+
//
7981
// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
8082
func AddDisk(
8183
request *cloudops.StoragePoolUpdateRequest,
@@ -173,9 +175,10 @@ func AddDisk(
173175
// - Sort the rows by IOPS //
174176
// - First row in the filtered decision matrix is our best candidate. //
175177
// - If input.CurrentDriveSize + deltaCapacityPerDrive > row.MaxSize: //
176-
// - failed to expand //
177-
// Else //
178-
// - success //
178+
// - failed to expand //
179+
// Else //
180+
// - success //
181+
//
179182
// ////////////////////////////////////////////////////////////////////////////////////////////////
180183
func ResizeDisk(
181184
request *cloudops.StoragePoolUpdateRequest,
@@ -267,31 +270,34 @@ func calculateDriveCapacity(request *cloudops.StoragePoolUpdateRequest) uint64 {
267270
// to achieve this:
268271
//
269272
// ////////////////////////////////////////////////////////////////////////////
270-
// - Calculate minCapacityPerZone = input.MinCapacity / zoneCount //
271-
// - Calculate maxCapacityPerZone = input.MaxCapacity / zoneCount //
272-
// - Filter the decision matrix based of our requirements: //
273-
// - Filter out the rows which do not have the same input.DriveType //
274-
// - Filter out the rows which do not meet input.IOPS //
275-
// - Sort the decision matrix by IOPS //
276-
// - Sort the decision matrix by Priority //
277-
// - instancesPerZone = input.RequestedInstancesPerZone //
278-
// - (row_loop) For each of the filtered row: //
279-
// - (instances_per_zone_loop) For instancesPerZone > 0: //
273+
// - Calculate minCapacityPerZone = input.MinCapacity / zoneCount //
274+
// - Calculate maxCapacityPerZone = input.MaxCapacity / zoneCount //
275+
// - Filter the decision matrix based of our requirements: //
276+
// - Filter out the rows which do not have the same input.DriveType //
277+
// - Filter out the rows which do not meet input.IOPS //
278+
// - Sort the decision matrix by IOPS //
279+
// - Sort the decision matrix by Priority //
280+
//
281+
// - instancesPerZone = input.RequestedInstancesPerZone //
282+
// - (row_loop) For each of the filtered row: //
283+
// - (instances_per_zone_loop) For instancesPerZone > 0: //
280284
// - Find capacityPerNode = minCapacityPerZone / instancesPerZone //
281285
// - (drive_count_loop) For driveCount > row.InstanceMinDrives: //
282-
// - driveSize = capacityPerNode / driveCount //
283-
// - If driveSize within row.MinSize and row.MaxSize: //
284-
// break drive_count_loop (Found candidate) //
285-
// - If (drive_count_loop) fails/exhausts: //
286-
// - reduce instancesPerZone by 1 //
287-
// - goto (instances_per_zone_loop) //
288-
// Else found candidate //
289-
// - break instances_per_zone_loop (Found candidate) //
290-
// - If (instances_per_zone_loop) fails: //
291-
// - Try the next filtered row //
292-
// - goto (row_loop) //
293-
// - If (row_loop) fails: //
294-
// - failed to get a candidate //
286+
// - driveSize = capacityPerNode / driveCount //
287+
// - If driveSize within row.MinSize and row.MaxSize: //
288+
// break drive_count_loop (Found candidate) //
289+
// - If (drive_count_loop) fails/exhausts: //
290+
// - reduce instancesPerZone by 1 //
291+
// - goto (instances_per_zone_loop) //
292+
// Else found candidate //
293+
// - break instances_per_zone_loop (Found candidate) //
294+
// - If (instances_per_zone_loop) fails: //
295+
// - Try the next filtered row //
296+
// - goto (row_loop) //
297+
//
298+
// - If (row_loop) fails: //
299+
// - failed to get a candidate //
300+
//
295301
// ////////////////////////////////////////////////////////////////////////////
296302
func GetStorageDistributionForPool(
297303
decisionMatrix *cloudops.StorageDecisionMatrix,
@@ -396,6 +402,39 @@ row_loop:
396402

397403
}
398404

405+
// GetMaxDriveSize returns the max drive size given an input
406+
// cloud drive type
407+
// Filter out rows matching input drive type
408+
// Process the rows to find the max size
409+
func GetMaxDriveSize(
410+
request *cloudops.MaxDriveSizeRequest,
411+
decisionMatrix *cloudops.StorageDecisionMatrix,
412+
) (*cloudops.MaxDriveSizeResponse, error) {
413+
logMaxDriveSizeRequest(request)
414+
415+
if len(request.DriveType) == 0 {
416+
return nil, &cloudops.ErrInvalidMaxDriveSizeRequest{
417+
Request: request,
418+
Reason: "empty drive type",
419+
}
420+
}
421+
422+
dm := utils.CopyDecisionMatrix(decisionMatrix)
423+
424+
// Filter the decision matrix rows based on the input request
425+
dm.FilterByDriveType(request.DriveType).SortByMaxSize()
426+
if len(dm.Rows) == 0 {
427+
return nil, &cloudops.ErrMaxDriveSizeCandidateNotFound{
428+
Request: request,
429+
Reason: "no matching inputs found for input drive type",
430+
}
431+
}
432+
433+
return &cloudops.MaxDriveSizeResponse{
434+
MaxSize: dm.Rows[0].MaxSize,
435+
}, nil
436+
}
437+
399438
// validateUpdateRequest validates the StoragePoolUpdateRequest
400439
func validateUpdateRequest(
401440
request *cloudops.StoragePoolUpdateRequest,
@@ -470,3 +509,11 @@ func logUpdateRequest(
470509
"OperationType": request.ResizeOperationType,
471510
}).Debugf("-- Storage Distribution Pool Update Request --")
472511
}
512+
513+
func logMaxDriveSizeRequest(
514+
request *cloudops.MaxDriveSizeRequest,
515+
) {
516+
logrus.WithFields(logrus.Fields{
517+
"DriveType": request.DriveType,
518+
}).Debugf("-- Get Max Drive Size request --")
519+
}

‎unsupported/unsupported.go

+7
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,10 @@ func (u *unsupportedStorageManager) RecommendStoragePoolUpdate(
217217
Operation: "RecommendStoragePoolUpdate",
218218
}
219219
}
220+
221+
func (u *unsupportedStorageManager) GetMaxDriveSize(
222+
request *cloudops.MaxDriveSizeRequest) (*cloudops.MaxDriveSizeResponse, error) {
223+
return nil, &cloudops.ErrNotSupported{
224+
Operation: "GetMaxDriveSize",
225+
}
226+
}

‎vsphere/storagemanager/vsphere.go

+7
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ func (a *vsphereStorageManager) RecommendStoragePoolUpdate(
5555
resp, _, err := storagedistribution.GetStorageUpdateConfig(request, a.decisionMatrix)
5656
return resp, err
5757
}
58+
59+
func (a *vsphereStorageManager) GetMaxDriveSize(
60+
request *cloudops.MaxDriveSizeRequest) (*cloudops.MaxDriveSizeResponse, error) {
61+
resp, err := storagedistribution.GetMaxDriveSize(request, a.decisionMatrix)
62+
return resp, err
63+
}
64+
5865
func init() {
5966
cloudops.RegisterStorageManager(cloudops.Vsphere, newVsphereStorageManager)
6067
}

‎vsphere/storagemanager/vsphere_test.go

+73
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//go:build unittest
12
// +build unittest
23

34
package storagemanager
@@ -32,6 +33,7 @@ func TestVsphereStorageManager(t *testing.T) {
3233
t.Run("setup", setup)
3334
t.Run("storageDistribution", storageDistribution)
3435
t.Run("storageUpdate", storageUpdate)
36+
t.Run("maxDriveSize", maxDriveSize)
3537
}
3638

3739
func setup(t *testing.T) {
@@ -417,6 +419,77 @@ func storageUpdate(t *testing.T) {
417419
}
418420
}
419421

422+
func maxDriveSize(t *testing.T) {
423+
testMatrix := []struct {
424+
expectedErr error
425+
request *cloudops.MaxDriveSizeRequest
426+
response *cloudops.MaxDriveSizeResponse
427+
}{
428+
{
429+
// Test1: empty drive type
430+
request: &cloudops.MaxDriveSizeRequest{
431+
DriveType: "",
432+
},
433+
response: nil,
434+
expectedErr: &cloudops.ErrInvalidMaxDriveSizeRequest{Request: &cloudops.MaxDriveSizeRequest{DriveType: ""}, Reason: "empty drive type"},
435+
},
436+
{
437+
// Test2: invalid drive type
438+
request: &cloudops.MaxDriveSizeRequest{
439+
DriveType: "invalid_drive",
440+
},
441+
response: nil,
442+
expectedErr: &cloudops.ErrMaxDriveSizeCandidateNotFound{Request: &cloudops.MaxDriveSizeRequest{DriveType: "invalid_drive"}, Reason: "no matching inputs found for input drive type"},
443+
},
444+
445+
{
446+
// Test3: thin drive
447+
request: &cloudops.MaxDriveSizeRequest{
448+
DriveType: "thin",
449+
},
450+
response: &cloudops.MaxDriveSizeResponse{
451+
MaxSize: 8192,
452+
},
453+
expectedErr: nil,
454+
},
455+
456+
{
457+
// Test4: zeroedthick drive
458+
request: &cloudops.MaxDriveSizeRequest{
459+
DriveType: "zeroedthick",
460+
},
461+
response: &cloudops.MaxDriveSizeResponse{
462+
MaxSize: 8192,
463+
},
464+
expectedErr: nil,
465+
},
466+
467+
{
468+
// Test5: eagerzeroedthick drive
469+
request: &cloudops.MaxDriveSizeRequest{
470+
DriveType: "eagerzeroedthick",
471+
},
472+
response: &cloudops.MaxDriveSizeResponse{
473+
MaxSize: 8192,
474+
},
475+
expectedErr: nil,
476+
},
477+
}
478+
479+
for j, test := range testMatrix {
480+
fmt.Println("Executing test case: ", j+1)
481+
response, err := storageManager.GetMaxDriveSize(test.request)
482+
if test.expectedErr == nil {
483+
require.Nil(t, err, "GetMaxDriveSize returned an error")
484+
require.NotNil(t, response, "GetMaxDriveSize returned empty response")
485+
require.Equal(t, test.response.MaxSize, response.MaxSize, "expected and actual max drive size not equal")
486+
} else {
487+
require.NotNil(t, err, "GetMaxDriveSize should have returned an error")
488+
require.Equal(t, test.expectedErr.Error(), err.Error(), "received unexpected type of error")
489+
}
490+
}
491+
}
492+
420493
func logTest(test testInput) {
421494
logrus.Infof("### RUNNING TEST")
422495
logrus.Infof("### REQUEST: new capacity: %d GiB op_type: %v",

0 commit comments

Comments
 (0)
Please sign in to comment.