mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 17:11:30 +00:00
feat: honor gp3 Iops on CreateVolume + clear UnknownVolumeType error (#451)
CreateVolume hardcoded iops to 3000, silently dropping a caller-supplied Iops, and rejected non-gp3 VolumeType with the generic InvalidParameterValue. Honor input.Iops within the gp3 envelope (3000 baseline, 500 IOPS/GiB, 16000 ceiling) and return the volume-type-specific UnknownVolumeType for unsupported types. Closes EBS CSI API gaps #3-4 (siv-380); gp3 Throughput (gap #2) deferred.
This commit is contained in:
committed by
Julian Sommer
parent
c9629d3bf6
commit
9934be33c3
@@ -23,7 +23,7 @@ func ValidateCreateVolumeInput(input *ec2.CreateVolumeInput) error {
|
||||
}
|
||||
|
||||
if input.VolumeType != nil && *input.VolumeType != "" && *input.VolumeType != "gp3" {
|
||||
return errors.New(awserrors.ErrorInvalidParameterValue)
|
||||
return errors.New(awserrors.ErrorUnknownVolumeType)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -105,7 +105,7 @@ func TestValidateCreateVolumeInput(t *testing.T) {
|
||||
VolumeType: aws.String("io1"),
|
||||
},
|
||||
wantErr: true,
|
||||
errMsg: awserrors.ErrorInvalidParameterValue,
|
||||
errMsg: awserrors.ErrorUnknownVolumeType,
|
||||
},
|
||||
{
|
||||
name: "InvalidVolumeType_GP2",
|
||||
@@ -115,7 +115,7 @@ func TestValidateCreateVolumeInput(t *testing.T) {
|
||||
VolumeType: aws.String("gp2"),
|
||||
},
|
||||
wantErr: true,
|
||||
errMsg: awserrors.ErrorInvalidParameterValue,
|
||||
errMsg: awserrors.ErrorUnknownVolumeType,
|
||||
},
|
||||
{
|
||||
name: "ValidInput_EmptyVolumeType",
|
||||
|
||||
@@ -28,7 +28,13 @@ import (
|
||||
"github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
const defaultGP3IOPS = 3000
|
||||
const (
|
||||
// gp3 IOPS envelope (AWS): 3000 baseline on any size, up to 500 IOPS/GiB,
|
||||
// capped at 16000.
|
||||
defaultGP3IOPS = 3000
|
||||
maxGP3IOPS = 16000
|
||||
gp3IOPSPerGiB = 500
|
||||
)
|
||||
|
||||
// Ensure VolumeServiceImpl implements VolumeService
|
||||
var _ VolumeService = (*VolumeServiceImpl)(nil)
|
||||
@@ -92,7 +98,7 @@ func (s *VolumeServiceImpl) CreateVolume(input *ec2.CreateVolumeInput, accountID
|
||||
|
||||
// Validate volume type: only gp3 supported (or empty defaults to gp3)
|
||||
if input.VolumeType != nil && *input.VolumeType != "" && *input.VolumeType != "gp3" {
|
||||
return nil, errors.New(awserrors.ErrorInvalidParameterValue)
|
||||
return nil, errors.New(awserrors.ErrorUnknownVolumeType)
|
||||
}
|
||||
volumeType := "gp3"
|
||||
|
||||
@@ -141,7 +147,17 @@ func (s *VolumeServiceImpl) CreateVolume(input *ec2.CreateVolumeInput, accountID
|
||||
now := time.Now()
|
||||
volumeID := utils.GenerateResourceID("vol")
|
||||
|
||||
// Honor caller-supplied Iops for gp3, else the 3000 baseline. The ceiling is
|
||||
// min(16000, 500*size) but never below the free baseline, so small volumes
|
||||
// still get 3000.
|
||||
iops := defaultGP3IOPS
|
||||
if input.Iops != nil {
|
||||
iops = int(*input.Iops)
|
||||
}
|
||||
maxIOPS := min(max(int(size)*gp3IOPSPerGiB, defaultGP3IOPS), maxGP3IOPS)
|
||||
if iops < defaultGP3IOPS || iops > maxIOPS {
|
||||
return nil, errors.New(awserrors.ErrorInvalidParameterValue)
|
||||
}
|
||||
|
||||
slog.Info("CreateVolume", "volumeId", volumeID, "size", size, "type", volumeType,
|
||||
"az", *input.AvailabilityZone, "snapshotId", snapshotID)
|
||||
|
||||
@@ -92,7 +92,7 @@ func TestCreateVolume_Validation(t *testing.T) {
|
||||
AvailabilityZone: aws.String("ap-southeast-2a"),
|
||||
VolumeType: aws.String("io1"),
|
||||
},
|
||||
wantErr: awserrors.ErrorInvalidParameterValue,
|
||||
wantErr: awserrors.ErrorUnknownVolumeType,
|
||||
},
|
||||
{
|
||||
name: "UnsupportedVolumeType_GP2",
|
||||
@@ -102,7 +102,7 @@ func TestCreateVolume_Validation(t *testing.T) {
|
||||
AvailabilityZone: aws.String("ap-southeast-2a"),
|
||||
VolumeType: aws.String("gp2"),
|
||||
},
|
||||
wantErr: awserrors.ErrorInvalidParameterValue,
|
||||
wantErr: awserrors.ErrorUnknownVolumeType,
|
||||
},
|
||||
{
|
||||
name: "UnsupportedVolumeType_ST1",
|
||||
@@ -112,6 +112,36 @@ func TestCreateVolume_Validation(t *testing.T) {
|
||||
AvailabilityZone: aws.String("ap-southeast-2a"),
|
||||
VolumeType: aws.String("st1"),
|
||||
},
|
||||
wantErr: awserrors.ErrorUnknownVolumeType,
|
||||
},
|
||||
{
|
||||
name: "Iops_BelowBaseline",
|
||||
az: "ap-southeast-2a",
|
||||
input: &ec2.CreateVolumeInput{
|
||||
Size: aws.Int64(80),
|
||||
AvailabilityZone: aws.String("ap-southeast-2a"),
|
||||
Iops: aws.Int64(2999),
|
||||
},
|
||||
wantErr: awserrors.ErrorInvalidParameterValue,
|
||||
},
|
||||
{
|
||||
name: "Iops_AboveCeiling",
|
||||
az: "ap-southeast-2a",
|
||||
input: &ec2.CreateVolumeInput{
|
||||
Size: aws.Int64(80),
|
||||
AvailabilityZone: aws.String("ap-southeast-2a"),
|
||||
Iops: aws.Int64(16001),
|
||||
},
|
||||
wantErr: awserrors.ErrorInvalidParameterValue,
|
||||
},
|
||||
{
|
||||
name: "Iops_AboveRatioForSmallVolume",
|
||||
az: "ap-southeast-2a",
|
||||
input: &ec2.CreateVolumeInput{
|
||||
Size: aws.Int64(10),
|
||||
AvailabilityZone: aws.String("ap-southeast-2a"),
|
||||
Iops: aws.Int64(6000),
|
||||
},
|
||||
wantErr: awserrors.ErrorInvalidParameterValue,
|
||||
},
|
||||
{
|
||||
@@ -180,6 +210,14 @@ func TestCreateVolume_PassesValidation(t *testing.T) {
|
||||
AvailabilityZone: aws.String("ap-southeast-2a"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ExplicitIopsInRange",
|
||||
input: &ec2.CreateVolumeInput{
|
||||
Size: aws.Int64(80),
|
||||
AvailabilityZone: aws.String("ap-southeast-2a"),
|
||||
Iops: aws.Int64(8000),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
Reference in New Issue
Block a user