Skip to content

Commit

Permalink
support allowAutoVolumeSizeIncrease
Browse files Browse the repository at this point in the history
  • Loading branch information
phuhung273 committed Dec 25, 2024
1 parent 2c546a8 commit decf8bc
Show file tree
Hide file tree
Showing 6 changed files with 312 additions and 37 deletions.
1 change: 1 addition & 0 deletions docs/parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The AWS EBS CSI Driver supports [tagging](tagging.md) through `StorageClass.para
| "type" | io1, io2, gp2, gp3, sc1, st1, standard, sbp1, sbg1 | gp3* | EBS volume type. |
| "iopsPerGB" | | | I/O operations per second per GiB. Can be specified for IO1, IO2, and GP3 volumes. |
| "allowAutoIOPSPerGBIncrease" | true, false | false | When `"true"`, the CSI driver increases IOPS for a volume when `iopsPerGB * <volume size>` is too low to fit into IOPS range supported by AWS. This allows dynamic provisioning to always succeed, even when user specifies too small PVC capacity or `iopsPerGB` value. On the other hand, it may introduce additional costs, as such volumes have higher IOPS than requested in `iopsPerGB`. |
| "allowAutoVolumeSizeIncrease" | true, false | false | When `"true"`, the CSI driver adjust volume size when it is too low to fit into Volume size range supported by AWS. This allows dynamic provisioning to always succeed, even when user specifies too small PVC size. On the other hand, it may introduce additional costs, as such volumes have higher size than requested. |
| "iops" | | | I/O operations per second. Can be specified for IO1, IO2, and GP3 volumes. |
| "throughput" | | 125 | Throughput in MiB/s. Only effective when gp3 volume type is specified. If empty, it will set to 125MiB/s as documented [here](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-volume-types.html). |
| "encrypted" | true, false | false | Whether the volume should be encrypted or not. Valid values are "true" or "false". |
Expand Down
80 changes: 67 additions & 13 deletions pkg/cloud/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,23 @@ const (
io1MinTotalIOPS = 100
io1MaxTotalIOPS = 64000
io1MaxIOPSPerGB = 50
io1MinSize = 4
io1MaxSize = 16 * 1024 // 16 TiB
io2MinTotalIOPS = 100
io2MaxTotalIOPS = 64000
io2BlockExpressMaxTotalIOPS = 256000
io2MaxIOPSPerGB = 500
io2MinSize = 4
io2MaxSize = 64 * 1024 // 64 TiB
gp3MaxTotalIOPS = 16000
gp3MinTotalIOPS = 3000
gp3MaxIOPSPerGB = 500
gpMinSize = 1
gpMaxSize = 16 * 1024 // 16 TiB
hddMinSize = 125
hddMaxSize = 16 * 1024 // 16 TiB
standardMinSize = 1
standardMaxSize = 1024
)

var (
Expand Down Expand Up @@ -204,18 +214,19 @@ type Disk struct {

// DiskOptions represents parameters to create an EBS volume.
type DiskOptions struct {
CapacityBytes int64
Tags map[string]string
VolumeType string
IOPSPerGB int32
AllowIOPSPerGBIncrease bool
IOPS int32
Throughput int32
AvailabilityZone string
OutpostArn string
Encrypted bool
BlockExpress bool
MultiAttachEnabled bool
CapacityBytes int64
Tags map[string]string
VolumeType string
IOPSPerGB int32
AllowIOPSPerGBIncrease bool
AllowVolumeSizeIncrease bool
IOPS int32
Throughput int32
AvailabilityZone string
OutpostArn string
Encrypted bool
BlockExpress bool
MultiAttachEnabled bool
// KmsKeyID represents a fully qualified resource name to the key to use for encryption.
// example: arn:aws:kms:us-east-1:012345678910:key/abcd1234-a123-456a-a12b-a123b4cd56ef
KmsKeyID string
Expand Down Expand Up @@ -533,6 +544,8 @@ func (c *cloud) CreateDisk(ctx context.Context, volumeName string, diskOptions *
minIops int32
maxIopsPerGb int32
requestedIops int32
minVolumeSize int32
maxVolumeSize int32
)

capacityGiB := util.BytesToGiB(diskOptions.CapacityBytes)
Expand All @@ -548,11 +561,22 @@ func (c *cloud) CreateDisk(ctx context.Context, volumeName string, diskOptions *
}

switch createType {
case VolumeTypeGP2, VolumeTypeSC1, VolumeTypeST1, VolumeTypeSBG1, VolumeTypeSBP1, VolumeTypeStandard:
case VolumeTypeSBG1, VolumeTypeSBP1:
case VolumeTypeSC1, VolumeTypeST1:
minVolumeSize = hddMinSize
maxVolumeSize = hddMaxSize
case VolumeTypeStandard:
minVolumeSize = standardMinSize
maxVolumeSize = standardMaxSize
case VolumeTypeGP2:
minVolumeSize = gpMinSize
maxVolumeSize = gpMaxSize
case VolumeTypeIO1:
maxIops = io1MaxTotalIOPS
minIops = io1MinTotalIOPS
maxIopsPerGb = io1MaxIOPSPerGB
minVolumeSize = io1MinSize
maxVolumeSize = io1MaxSize
case VolumeTypeIO2:
if diskOptions.BlockExpress {
maxIops = io2BlockExpressMaxTotalIOPS
Expand All @@ -561,11 +585,15 @@ func (c *cloud) CreateDisk(ctx context.Context, volumeName string, diskOptions *
}
minIops = io2MinTotalIOPS
maxIopsPerGb = io2MaxIOPSPerGB
minVolumeSize = io2MinSize
maxVolumeSize = io2MaxSize
case VolumeTypeGP3:
maxIops = gp3MaxTotalIOPS
minIops = gp3MinTotalIOPS
maxIopsPerGb = gp3MaxIOPSPerGB
throughput = diskOptions.Throughput
minVolumeSize = gpMinSize
maxVolumeSize = gpMaxSize
default:
return nil, fmt.Errorf("invalid AWS VolumeType %q", diskOptions.VolumeType)
}
Expand All @@ -574,6 +602,10 @@ func (c *cloud) CreateDisk(ctx context.Context, volumeName string, diskOptions *
return nil, errors.New("CreateDisk: multi-attach is only supported for io2 volumes")
}

if maxVolumeSize > 0 {
capacityGiB = capVolumeSize(createType, capacityGiB, minVolumeSize, maxVolumeSize, diskOptions.AllowVolumeSizeIncrease)
}

if maxIops > 0 {
if diskOptions.IOPS > 0 {
requestedIops = diskOptions.IOPS
Expand Down Expand Up @@ -1946,3 +1978,25 @@ func capIOPS(volumeType string, requestedCapacityGiB int32, requestedIops int32,
}
return iops
}

// Calculate actual Volume Size for a volume and cap it at supported AWS limits.
func capVolumeSize(volumeType string, requestedCapacityGiB int32, minSize, maxSize int32, allowIncrease bool) int32 {
// If requestedCapacityGiB is zero the user did not request a specific amount, and the default will be used instead
if requestedCapacityGiB == 0 {
return 0
}

size := requestedCapacityGiB

if size < minSize {
if allowIncrease {
size = minSize
klog.V(5).InfoS("[Debug] Increased Volume Size to the min supported limit", "volumeType", volumeType, "requestedCapacityGiB", requestedCapacityGiB, "limit", minSize)
}
}
if size > maxSize {
size = maxSize
klog.V(5).InfoS("[Debug] Capped Volume Size, volume at the max supported limit", "volumeType", volumeType, "requestedCapacityGiB", requestedCapacityGiB, "limit", maxSize)
}
return size
}
202 changes: 202 additions & 0 deletions pkg/cloud/cloud_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,208 @@ func TestCreateDisk(t *testing.T) {
},
expErr: nil,
},
{
name: "success: io1 with too low capacity and AllowVolumeSizeIncrease",
volumeName: "vol-test-name",
diskOptions: &DiskOptions{
CapacityBytes: util.GiBToBytes(1),
Tags: map[string]string{VolumeNameTagKey: "vol-test", AwsEbsDriverTagKey: "true"},
VolumeType: VolumeTypeIO1,
AllowVolumeSizeIncrease: true,
},
expDisk: &Disk{
VolumeID: "vol-test",
CapacityGiB: 1,
AvailabilityZone: defaultZone,
},
expCreateVolumeInput: &ec2.CreateVolumeInput{
Size: aws.Int32(4),
},
expErr: nil,
},
{
name: "success: io1 with too high capacity",
volumeName: "vol-test-name",
diskOptions: &DiskOptions{
CapacityBytes: util.TiBToBytes(17),
Tags: map[string]string{VolumeNameTagKey: "vol-test"},
VolumeType: VolumeTypeIO1,
},
expDisk: &Disk{
VolumeID: "vol-test",
CapacityGiB: util.TiBToGiB(17),
AvailabilityZone: defaultZone,
},
expCreateVolumeInput: &ec2.CreateVolumeInput{
Size: aws.Int32(util.TiBToGiB(16)),
},
expErr: nil,
},
{
name: "success: io2 with too low capacity and AllowVolumeSizeIncrease",
volumeName: "vol-test-name",
diskOptions: &DiskOptions{
CapacityBytes: util.GiBToBytes(1),
Tags: map[string]string{VolumeNameTagKey: "vol-test", AwsEbsDriverTagKey: "true"},
VolumeType: VolumeTypeIO2,
AllowVolumeSizeIncrease: true,
},
expDisk: &Disk{
VolumeID: "vol-test",
CapacityGiB: 1,
AvailabilityZone: defaultZone,
},
expCreateVolumeInput: &ec2.CreateVolumeInput{
Size: aws.Int32(4),
},
expErr: nil,
},
{
name: "success: io2 with too high capacity",
volumeName: "vol-test-name",
diskOptions: &DiskOptions{
CapacityBytes: util.TiBToBytes(65),
Tags: map[string]string{VolumeNameTagKey: "vol-test"},
VolumeType: VolumeTypeIO2,
},
expDisk: &Disk{
VolumeID: "vol-test",
CapacityGiB: util.TiBToGiB(65),
AvailabilityZone: defaultZone,
},
expCreateVolumeInput: &ec2.CreateVolumeInput{
Size: aws.Int32(util.TiBToGiB(64)),
},
expErr: nil,
},
{
name: "success: gp2 with too high capacity",
volumeName: "vol-test-name",
diskOptions: &DiskOptions{
CapacityBytes: util.TiBToBytes(17),
Tags: map[string]string{VolumeNameTagKey: "vol-test"},
VolumeType: VolumeTypeGP2,
},
expDisk: &Disk{
VolumeID: "vol-test",
CapacityGiB: util.TiBToGiB(17),
AvailabilityZone: defaultZone,
},
expCreateVolumeInput: &ec2.CreateVolumeInput{
Size: aws.Int32(util.TiBToGiB(16)),
},
expErr: nil,
},
{
name: "success: gp3 with too high capacity",
volumeName: "vol-test-name",
diskOptions: &DiskOptions{
CapacityBytes: util.TiBToBytes(17),
Tags: map[string]string{VolumeNameTagKey: "vol-test"},
VolumeType: VolumeTypeGP3,
},
expDisk: &Disk{
VolumeID: "vol-test",
CapacityGiB: util.TiBToGiB(17),
AvailabilityZone: defaultZone,
},
expCreateVolumeInput: &ec2.CreateVolumeInput{
Size: aws.Int32(util.TiBToGiB(16)),
},
expErr: nil,
},
{
name: "success: st1 with too low capacity and AllowVolumeSizeIncrease",
volumeName: "vol-test-name",
diskOptions: &DiskOptions{
CapacityBytes: util.GiBToBytes(100),
Tags: map[string]string{VolumeNameTagKey: "vol-test", AwsEbsDriverTagKey: "true"},
VolumeType: VolumeTypeST1,
AllowVolumeSizeIncrease: true,
},
expDisk: &Disk{
VolumeID: "vol-test",
CapacityGiB: 100,
AvailabilityZone: defaultZone,
},
expCreateVolumeInput: &ec2.CreateVolumeInput{
Size: aws.Int32(125),
},
expErr: nil,
},
{
name: "success: st1 with too high capacity",
volumeName: "vol-test-name",
diskOptions: &DiskOptions{
CapacityBytes: util.TiBToBytes(17),
Tags: map[string]string{VolumeNameTagKey: "vol-test"},
VolumeType: VolumeTypeST1,
},
expDisk: &Disk{
VolumeID: "vol-test",
CapacityGiB: util.TiBToGiB(17),
AvailabilityZone: defaultZone,
},
expCreateVolumeInput: &ec2.CreateVolumeInput{
Size: aws.Int32(util.TiBToGiB(16)),
},
expErr: nil,
},
{
name: "success: sc1 with too low capacity and AllowVolumeSizeIncrease",
volumeName: "vol-test-name",
diskOptions: &DiskOptions{
CapacityBytes: util.GiBToBytes(100),
Tags: map[string]string{VolumeNameTagKey: "vol-test", AwsEbsDriverTagKey: "true"},
VolumeType: VolumeTypeSC1,
AllowVolumeSizeIncrease: true,
},
expDisk: &Disk{
VolumeID: "vol-test",
CapacityGiB: 100,
AvailabilityZone: defaultZone,
},
expCreateVolumeInput: &ec2.CreateVolumeInput{
Size: aws.Int32(125),
},
expErr: nil,
},
{
name: "success: sc1 with too high capacity",
volumeName: "vol-test-name",
diskOptions: &DiskOptions{
CapacityBytes: util.TiBToBytes(17),
Tags: map[string]string{VolumeNameTagKey: "vol-test"},
VolumeType: VolumeTypeSC1,
},
expDisk: &Disk{
VolumeID: "vol-test",
CapacityGiB: util.TiBToGiB(17),
AvailabilityZone: defaultZone,
},
expCreateVolumeInput: &ec2.CreateVolumeInput{
Size: aws.Int32(util.TiBToGiB(16)),
},
expErr: nil,
},
{
name: "success: standard with too high capacity",
volumeName: "vol-test-name",
diskOptions: &DiskOptions{
CapacityBytes: util.TiBToBytes(2),
Tags: map[string]string{VolumeNameTagKey: "vol-test"},
VolumeType: VolumeTypeStandard,
},
expDisk: &Disk{
VolumeID: "vol-test",
CapacityGiB: util.TiBToGiB(2),
AvailabilityZone: defaultZone,
},
expCreateVolumeInput: &ec2.CreateVolumeInput{
Size: aws.Int32(util.TiBToGiB(1)),
},
expErr: nil,
},
{
name: "success: create volume when zone is snow and add tags",
volumeName: "vol-test-name",
Expand Down
3 changes: 3 additions & 0 deletions pkg/driver/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ const (
// AllowAutoIOPSPerGBIncreaseKey represents key for allowing automatic increase of IOPS.
AllowAutoIOPSPerGBIncreaseKey = "allowautoiopspergbincrease"

// AllowAutoVolumeSizeIncreaseKey represents key for allowing automatic increase of Volume size.
AllowAutoVolumeSizeIncreaseKey = "allowautovolumesizeincrease"

// Iops represents key for IOPS for volume.
IopsKey = "iops"

Expand Down
Loading

0 comments on commit decf8bc

Please sign in to comment.