From 2eec08aa02915ef9cce06b7231b9a99b21696bb1 Mon Sep 17 00:00:00 2001 From: Robert Lucian Chiriac Date: Wed, 28 Apr 2021 17:06:15 +0300 Subject: [PATCH 01/13] Change default volume type to gp3 --- docs/clusters/management/create.md | 4 ++-- pkg/types/clusterconfig/cluster_config.go | 2 +- pkg/types/clusterconfig/volume_types.go | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/clusters/management/create.md b/docs/clusters/management/create.md index 5e778707f7..6f46e51b74 100644 --- a/docs/clusters/management/create.md +++ b/docs/clusters/management/create.md @@ -36,7 +36,7 @@ node_groups: min_instances: 1 # minimum number of instances max_instances: 5 # maximum number of instances instance_volume_size: 50 # disk storage size per instance (GB) - instance_volume_type: gp2 # instance volume type [gp2 | io1 | st1 | sc1] + instance_volume_type: gp3 # instance volume type [gp2 | gp3 | io1 | st1 | sc1] # instance_volume_iops: 3000 # instance volume iops (only applicable to io1) spot: false # whether to use spot instances @@ -45,7 +45,7 @@ node_groups: min_instances: 1 max_instances: 5 instance_volume_size: 50 - instance_volume_type: gp2 + instance_volume_type: gp3 # instance_volume_iops: 3000 spot: false ... diff --git a/pkg/types/clusterconfig/cluster_config.go b/pkg/types/clusterconfig/cluster_config.go index 118de60759..006892cd43 100644 --- a/pkg/types/clusterconfig/cluster_config.go +++ b/pkg/types/clusterconfig/cluster_config.go @@ -478,7 +478,7 @@ var ManagedConfigStructFieldValidations = []*cr.StructFieldValidation{ StructField: "InstanceVolumeType", StringValidation: &cr.StringValidation{ AllowedValues: VolumeTypesStrings(), - Default: GP2VolumeType.String(), + Default: GP3VolumeType.String(), }, Parser: func(str string) (interface{}, error) { return VolumeTypeFromString(str), nil diff --git a/pkg/types/clusterconfig/volume_types.go b/pkg/types/clusterconfig/volume_types.go index 74bc83c6d7..6c36d06733 100644 --- a/pkg/types/clusterconfig/volume_types.go +++ b/pkg/types/clusterconfig/volume_types.go @@ -21,6 +21,7 @@ type VolumeType int const ( UnknownVolumeType VolumeType = iota GP2VolumeType + GP3VolumeType IO1VolumeType SC1VolumeType ST1VolumeType @@ -29,6 +30,7 @@ const ( var _availableVolumeTypes = []string{ "unknown", "gp2", + "gp3", "io1", "sc1", "st1", From e7a162a2553c1a80064eb0a26e43f2a1a097b3fc Mon Sep 17 00:00:00 2001 From: Robert Lucian Chiriac Date: Wed, 28 Apr 2021 17:06:37 +0300 Subject: [PATCH 02/13] Use gp3 for cortex's internal volumes --- cli/cmd/cluster.go | 4 ++-- cli/cmd/lib_cluster_config.go | 4 ++-- manager/manifests/prometheus-monitoring.yaml.j2 | 2 +- pkg/operator/operator/cron.go | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cli/cmd/cluster.go b/cli/cmd/cluster.go index 0b784f4432..3f5104ce9c 100644 --- a/cli/cmd/cluster.go +++ b/cli/cmd/cluster.go @@ -786,8 +786,8 @@ func getInfoOperatorResponse(operatorEndpoint string) (*schema.InfoResponse, err func printInfoPricing(infoResponse *schema.InfoResponse, clusterConfig clusterconfig.Config) { eksPrice := aws.EKSPrices[clusterConfig.Region] operatorInstancePrice := aws.InstanceMetadatas[clusterConfig.Region]["t3.medium"].Price - operatorEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp2"].PriceGB * 20 / 30 / 24 - metricsEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp2"].PriceGB * 40 / 30 / 24 + operatorEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp3"].PriceGB * 20 / 30 / 24 + metricsEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp3"].PriceGB * 40 / 30 / 24 nlbPrice := aws.NLBMetadatas[clusterConfig.Region].Price natUnitPrice := aws.NATMetadatas[clusterConfig.Region].Price diff --git a/cli/cmd/lib_cluster_config.go b/cli/cmd/lib_cluster_config.go index 16399c8024..1c11ba2170 100644 --- a/cli/cmd/lib_cluster_config.go +++ b/cli/cmd/lib_cluster_config.go @@ -149,8 +149,8 @@ func getInstallClusterConfig(awsClient *aws.Client, clusterConfigFile string, di func confirmInstallClusterConfig(clusterConfig *clusterconfig.Config, awsClient *aws.Client, disallowPrompt bool) { eksPrice := aws.EKSPrices[clusterConfig.Region] operatorInstancePrice := aws.InstanceMetadatas[clusterConfig.Region]["t3.medium"].Price - operatorEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp2"].PriceGB * 20 / 30 / 24 - metricsEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp2"].PriceGB * 40 / 30 / 24 + operatorEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp3"].PriceGB * 20 / 30 / 24 + metricsEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp3"].PriceGB * 40 / 30 / 24 nlbPrice := aws.NLBMetadatas[clusterConfig.Region].Price natUnitPrice := aws.NATMetadatas[clusterConfig.Region].Price diff --git a/manager/manifests/prometheus-monitoring.yaml.j2 b/manager/manifests/prometheus-monitoring.yaml.j2 index 3158510120..0e6b0782c4 100644 --- a/manager/manifests/prometheus-monitoring.yaml.j2 +++ b/manager/manifests/prometheus-monitoring.yaml.j2 @@ -19,7 +19,7 @@ metadata: volumeBindingMode: WaitForFirstConsumer provisioner: kubernetes.io/aws-ebs parameters: - type: gp2 + type: gp3 --- diff --git a/pkg/operator/operator/cron.go b/pkg/operator/operator/cron.go index 4344cca5b7..f1299043ad 100644 --- a/pkg/operator/operator/cron.go +++ b/pkg/operator/operator/cron.go @@ -196,8 +196,8 @@ func getEBSPriceForNodeGroupInstance(ngs []*clusterconfig.NodeGroup, ngName stri func clusterFixedPrice() float64 { eksPrice := aws.EKSPrices[config.CoreConfig.Region] operatorInstancePrice := aws.InstanceMetadatas[config.CoreConfig.Region]["t3.medium"].Price - operatorEBSPrice := aws.EBSMetadatas[config.CoreConfig.Region]["gp2"].PriceGB * 20 / 30 / 24 - metricsEBSPrice := aws.EBSMetadatas[config.CoreConfig.Region]["gp2"].PriceGB * 40 / 30 / 24 + operatorEBSPrice := aws.EBSMetadatas[config.CoreConfig.Region]["gp3"].PriceGB * 20 / 30 / 24 + metricsEBSPrice := aws.EBSMetadatas[config.CoreConfig.Region]["gp3"].PriceGB * 40 / 30 / 24 nlbPrice := aws.NLBMetadatas[config.CoreConfig.Region].Price natUnitPrice := aws.NATMetadatas[config.CoreConfig.Region].Price var natTotalPrice float64 From a7f7cbd0c5ba04c5a0c41b71da1e136adba2b453 Mon Sep 17 00:00:00 2001 From: Robert Lucian Chiriac Date: Wed, 28 Apr 2021 23:08:50 +0300 Subject: [PATCH 03/13] Revert "Use gp3 for cortex's internal volumes" This reverts commit e7a162a2553c1a80064eb0a26e43f2a1a097b3fc. --- cli/cmd/cluster.go | 4 ++-- cli/cmd/lib_cluster_config.go | 4 ++-- manager/manifests/prometheus-monitoring.yaml.j2 | 2 +- pkg/operator/operator/cron.go | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cli/cmd/cluster.go b/cli/cmd/cluster.go index 3f5104ce9c..0b784f4432 100644 --- a/cli/cmd/cluster.go +++ b/cli/cmd/cluster.go @@ -786,8 +786,8 @@ func getInfoOperatorResponse(operatorEndpoint string) (*schema.InfoResponse, err func printInfoPricing(infoResponse *schema.InfoResponse, clusterConfig clusterconfig.Config) { eksPrice := aws.EKSPrices[clusterConfig.Region] operatorInstancePrice := aws.InstanceMetadatas[clusterConfig.Region]["t3.medium"].Price - operatorEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp3"].PriceGB * 20 / 30 / 24 - metricsEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp3"].PriceGB * 40 / 30 / 24 + operatorEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp2"].PriceGB * 20 / 30 / 24 + metricsEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp2"].PriceGB * 40 / 30 / 24 nlbPrice := aws.NLBMetadatas[clusterConfig.Region].Price natUnitPrice := aws.NATMetadatas[clusterConfig.Region].Price diff --git a/cli/cmd/lib_cluster_config.go b/cli/cmd/lib_cluster_config.go index 1c11ba2170..16399c8024 100644 --- a/cli/cmd/lib_cluster_config.go +++ b/cli/cmd/lib_cluster_config.go @@ -149,8 +149,8 @@ func getInstallClusterConfig(awsClient *aws.Client, clusterConfigFile string, di func confirmInstallClusterConfig(clusterConfig *clusterconfig.Config, awsClient *aws.Client, disallowPrompt bool) { eksPrice := aws.EKSPrices[clusterConfig.Region] operatorInstancePrice := aws.InstanceMetadatas[clusterConfig.Region]["t3.medium"].Price - operatorEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp3"].PriceGB * 20 / 30 / 24 - metricsEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp3"].PriceGB * 40 / 30 / 24 + operatorEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp2"].PriceGB * 20 / 30 / 24 + metricsEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp2"].PriceGB * 40 / 30 / 24 nlbPrice := aws.NLBMetadatas[clusterConfig.Region].Price natUnitPrice := aws.NATMetadatas[clusterConfig.Region].Price diff --git a/manager/manifests/prometheus-monitoring.yaml.j2 b/manager/manifests/prometheus-monitoring.yaml.j2 index 0e6b0782c4..3158510120 100644 --- a/manager/manifests/prometheus-monitoring.yaml.j2 +++ b/manager/manifests/prometheus-monitoring.yaml.j2 @@ -19,7 +19,7 @@ metadata: volumeBindingMode: WaitForFirstConsumer provisioner: kubernetes.io/aws-ebs parameters: - type: gp3 + type: gp2 --- diff --git a/pkg/operator/operator/cron.go b/pkg/operator/operator/cron.go index f1299043ad..4344cca5b7 100644 --- a/pkg/operator/operator/cron.go +++ b/pkg/operator/operator/cron.go @@ -196,8 +196,8 @@ func getEBSPriceForNodeGroupInstance(ngs []*clusterconfig.NodeGroup, ngName stri func clusterFixedPrice() float64 { eksPrice := aws.EKSPrices[config.CoreConfig.Region] operatorInstancePrice := aws.InstanceMetadatas[config.CoreConfig.Region]["t3.medium"].Price - operatorEBSPrice := aws.EBSMetadatas[config.CoreConfig.Region]["gp3"].PriceGB * 20 / 30 / 24 - metricsEBSPrice := aws.EBSMetadatas[config.CoreConfig.Region]["gp3"].PriceGB * 40 / 30 / 24 + operatorEBSPrice := aws.EBSMetadatas[config.CoreConfig.Region]["gp2"].PriceGB * 20 / 30 / 24 + metricsEBSPrice := aws.EBSMetadatas[config.CoreConfig.Region]["gp2"].PriceGB * 40 / 30 / 24 nlbPrice := aws.NLBMetadatas[config.CoreConfig.Region].Price natUnitPrice := aws.NATMetadatas[config.CoreConfig.Region].Price var natTotalPrice float64 From 2dea0afdccec0c76434461c6000e5ba90363459f Mon Sep 17 00:00:00 2001 From: Robert Lucian Chiriac Date: Wed, 28 Apr 2021 23:52:33 +0300 Subject: [PATCH 04/13] Validate gp3 volume type --- docs/clusters/management/create.md | 5 +- manager/generate_eks.py | 6 +- pkg/types/clusterconfig/cluster_config.go | 70 +++++++++++++++++------ pkg/types/clusterconfig/config_key.go | 1 + pkg/types/clusterconfig/errors.go | 20 ++++++- 5 files changed, 79 insertions(+), 23 deletions(-) diff --git a/docs/clusters/management/create.md b/docs/clusters/management/create.md index 6f46e51b74..a55abef1ad 100644 --- a/docs/clusters/management/create.md +++ b/docs/clusters/management/create.md @@ -36,8 +36,9 @@ node_groups: min_instances: 1 # minimum number of instances max_instances: 5 # maximum number of instances instance_volume_size: 50 # disk storage size per instance (GB) - instance_volume_type: gp3 # instance volume type [gp2 | gp3 | io1 | st1 | sc1] - # instance_volume_iops: 3000 # instance volume iops (only applicable to io1) + instance_volume_type: gp2 # instance volume type [gp2 | gp3 | io1 | st1 | sc1] + # instance_volume_iops: 3000 # instance volume iops (only applicable to io1/gp3) + # instance_volume_throughput: 125 # instance volume throughput (only applicable to gp3) spot: false # whether to use spot instances - name: ng-gpu diff --git a/manager/generate_eks.py b/manager/generate_eks.py index 5800d84247..81dc963871 100644 --- a/manager/generate_eks.py +++ b/manager/generate_eks.py @@ -85,9 +85,11 @@ def apply_clusterconfig(nodegroup, config): "volumeType": config["instance_volume_type"], "desiredCapacity": 1 if config["min_instances"] == 0 else config["min_instances"], } - # add iops to settings if volume_type is io1 - if config["instance_volume_type"] == "io1": + # add iops to settings if volume_type is io1/gp3 + if config["instance_volume_type"] in ["io1", "gp3"]: clusterconfig_settings["volumeIOPS"] = config["instance_volume_iops"] + if config["instance_volume_type"] == "gp3": + clusterconfig_settings["volumeThroughput"] = config["instance_volume_throughput"] return merge_override(nodegroup, clusterconfig_settings) diff --git a/pkg/types/clusterconfig/cluster_config.go b/pkg/types/clusterconfig/cluster_config.go index 006892cd43..ab5b76660d 100644 --- a/pkg/types/clusterconfig/cluster_config.go +++ b/pkg/types/clusterconfig/cluster_config.go @@ -60,6 +60,8 @@ var ( _cachedCNISupportedInstances *string _defaultIAMPolicies = []string{"arn:aws:iam::aws:policy/AmazonS3FullAccess"} _invalidTagPrefixes = []string{"kubernetes.io/", "k8s.io/", "eksctl.", "alpha.eksctl.", "beta.eksctl.", "aws:", "Aws:", "aWs:", "awS:", "aWS:", "AwS:", "aWS:", "AWS:"} + _highestIOPSForIO1VolumeType = int64(64000) + _highestIOPSForGP3VolumeType = int64(16000) // This regex is stricter than the actual S3 rules _strictS3BucketRegex = regexp.MustCompile(`^([a-z0-9])+(-[a-z0-9]+)*$`) ) @@ -115,15 +117,16 @@ type ManagedConfig struct { } type NodeGroup struct { - Name string `json:"name" yaml:"name"` - InstanceType string `json:"instance_type" yaml:"instance_type"` - MinInstances int64 `json:"min_instances" yaml:"min_instances"` - MaxInstances int64 `json:"max_instances" yaml:"max_instances"` - InstanceVolumeSize int64 `json:"instance_volume_size" yaml:"instance_volume_size"` - InstanceVolumeType VolumeType `json:"instance_volume_type" yaml:"instance_volume_type"` - InstanceVolumeIOPS *int64 `json:"instance_volume_iops" yaml:"instance_volume_iops"` - Spot bool `json:"spot" yaml:"spot"` - SpotConfig *SpotConfig `json:"spot_config" yaml:"spot_config"` + Name string `json:"name" yaml:"name"` + InstanceType string `json:"instance_type" yaml:"instance_type"` + MinInstances int64 `json:"min_instances" yaml:"min_instances"` + MaxInstances int64 `json:"max_instances" yaml:"max_instances"` + InstanceVolumeSize int64 `json:"instance_volume_size" yaml:"instance_volume_size"` + InstanceVolumeType VolumeType `json:"instance_volume_type" yaml:"instance_volume_type"` + InstanceVolumeIOPS *int64 `json:"instance_volume_iops" yaml:"instance_volume_iops"` + InstanceVolumeThroughput *int64 `json:"instance_volume_throughput" yaml:"instance_volume_throughput"` + Spot bool `json:"spot" yaml:"spot"` + SpotConfig *SpotConfig `json:"spot_config" yaml:"spot_config"` } type SpotConfig struct { @@ -488,7 +491,14 @@ var ManagedConfigStructFieldValidations = []*cr.StructFieldValidation{ StructField: "InstanceVolumeIOPS", Int64PtrValidation: &cr.Int64PtrValidation{ GreaterThanOrEqualTo: pointer.Int64(100), - LessThanOrEqualTo: pointer.Int64(64000), + AllowExplicitNull: true, + }, + }, + { + StructField: "InstanceVolumeThroughput", + Int64PtrValidation: &cr.Int64PtrValidation{ + GreaterThanOrEqualTo: pointer.Int64(100), + LessThanOrEqualTo: pointer.Int64(1000), AllowExplicitNull: true, }, }, @@ -935,19 +945,41 @@ func (ng *NodeGroup) validateNodeGroup(awsClient *aws.Client, region string) err return errors.Wrap(ErrorInstanceTypeNotSupportedInRegion(primaryInstanceType, region), InstanceTypeKey) } - // Throw error if IOPS defined for other storage than io1 - if ng.InstanceVolumeType != IO1VolumeType && ng.InstanceVolumeIOPS != nil { + // throw error if IOPS defined for other storage than io1/gp3 + if ng.InstanceVolumeType != IO1VolumeType || ng.InstanceVolumeType != GP3VolumeType && ng.InstanceVolumeIOPS != nil { return ErrorIOPSNotSupported(ng.InstanceVolumeType) } - if ng.InstanceVolumeType == IO1VolumeType && ng.InstanceVolumeIOPS != nil { - if *ng.InstanceVolumeIOPS > ng.InstanceVolumeSize*50 { - return ErrorIOPSTooLarge(*ng.InstanceVolumeIOPS, ng.InstanceVolumeSize) + // throw error if throughput defined for other storage than gp3 + if ng.InstanceVolumeType != GP3VolumeType && ng.InstanceVolumeThroughput != nil { + return ErrorThroughputNotSupported(ng.InstanceVolumeType) + } + + if ng.InstanceVolumeIOPS != nil { + if ng.InstanceVolumeType == IO1VolumeType { + if *ng.InstanceVolumeIOPS > _highestIOPSForIO1VolumeType { + return ErrorIOPSTooLarge(*ng.InstanceVolumeIOPS, _highestIOPSForIO1VolumeType) + } + if *ng.InstanceVolumeIOPS > ng.InstanceVolumeSize*50 { + return ErrorIOPSTooLargeDueToVolumeSize(*ng.InstanceVolumeIOPS, ng.InstanceVolumeSize) + } + } else { + if *ng.InstanceVolumeIOPS > _highestIOPSForGP3VolumeType { + return ErrorIOPSTooLarge(*ng.InstanceVolumeIOPS, _highestIOPSForGP3VolumeType) + } } } if aws.EBSMetadatas[region][ng.InstanceVolumeType.String()].IOPSConfigurable && ng.InstanceVolumeIOPS == nil { - ng.InstanceVolumeIOPS = pointer.Int64(libmath.MinInt64(ng.InstanceVolumeSize*50, 3000)) + if ng.InstanceVolumeType == GP3VolumeType { + ng.InstanceVolumeIOPS = pointer.Int64(3000) + } else { + ng.InstanceVolumeIOPS = pointer.Int64(libmath.MinInt64(ng.InstanceVolumeSize*50, 3000)) + } + } + + if ng.InstanceVolumeType == GP3VolumeType && ng.InstanceVolumeThroughput == nil { + ng.InstanceVolumeThroughput = pointer.Int64(125) } if ng.Spot { @@ -1370,7 +1402,11 @@ func (mc *ManagedConfig) TelemetryEvent() map[string]interface{} { event[nodeGroupKey("instance_volume_type")] = ng.InstanceVolumeType if ng.InstanceVolumeIOPS != nil { event[nodeGroupKey("instance_volume_iops.is_defined")] = true - event[nodeGroupKey("instance_volume_iops")] = ng.InstanceVolumeIOPS + event[nodeGroupKey("instance_volume_iops")] = *ng.InstanceVolumeIOPS + } + if ng.InstanceVolumeThroughput != nil { + event[nodeGroupKey("instance_volume_throughput.is_defined")] = true + event[nodeGroupKey("instance_volume_throughput")] = *ng.InstanceVolumeThroughput } event[nodeGroupKey("spot")] = ng.Spot diff --git a/pkg/types/clusterconfig/config_key.go b/pkg/types/clusterconfig/config_key.go index 345fd44315..220251adfe 100644 --- a/pkg/types/clusterconfig/config_key.go +++ b/pkg/types/clusterconfig/config_key.go @@ -32,6 +32,7 @@ const ( InstanceVolumeSizeKey = "instance_volume_size" InstanceVolumeTypeKey = "instance_volume_type" InstanceVolumeIOPSKey = "instance_volume_iops" + InstanceVolumeThroughputKey = "instance_volume_throughput" InstancePoolsKey = "instance_pools" MaxPriceKey = "max_price" NetworkKey = "network" diff --git a/pkg/types/clusterconfig/errors.go b/pkg/types/clusterconfig/errors.go index 414e6fd81b..acb94fbb9f 100644 --- a/pkg/types/clusterconfig/errors.go +++ b/pkg/types/clusterconfig/errors.go @@ -63,7 +63,9 @@ const ( ErrS3RegionDiffersFromCluster = "clusterconfig.s3_region_differs_from_cluster" ErrInvalidInstanceType = "clusterconfig.invalid_instance_type" ErrIOPSNotSupported = "clusterconfig.iops_not_supported" + ErrThroughputNotSupported = "clusterconfig.throughput_not_supported" ErrIOPSTooLarge = "clusterconfig.iops_too_large" + ErrIOPSTooLargeDueToVolumeSize = "clusterconfig.iops_too_large_due_to_volume_siz" ErrCantOverrideDefaultTag = "clusterconfig.cant_override_default_tag" ErrSSLCertificateARNNotFound = "clusterconfig.ssl_certificate_arn_not_found" ErrIAMPolicyARNNotFound = "clusterconfig.iam_policy_arn_not_found" @@ -322,13 +324,27 @@ func ErrorInvalidInstanceType(instanceType string) error { func ErrorIOPSNotSupported(volumeType VolumeType) error { return errors.WithStack(&errors.Error{ Kind: ErrIOPSNotSupported, - Message: fmt.Sprintf("IOPS cannot be configured for volume type %s; set `%s: %s` or remove `%s` from your cluster configuration file", volumeType, InstanceVolumeTypeKey, IO1VolumeType, InstanceVolumeIOPSKey), + Message: fmt.Sprintf("IOPS cannot be configured for volume type %s; set `%s: %s`, `%s: %s` or remove `%s` from your cluster configuration file", volumeType, InstanceVolumeTypeKey, IO1VolumeType, InstanceVolumeTypeKey, GP3VolumeType, InstanceVolumeIOPSKey), }) } -func ErrorIOPSTooLarge(iops int64, volumeSize int64) error { +func ErrorThroughputNotSupported(volumeType VolumeType) error { + return errors.WithStack(&errors.Error{ + Kind: ErrThroughputNotSupported, + Message: fmt.Sprintf("throughput cannot be configured for volume type %s; set `%s: %s` or remove `%s` from your cluster configuration file", volumeType, InstanceVolumeTypeKey, GP3VolumeType, InstanceVolumeThroughputKey), + }) +} + +func ErrorIOPSTooLarge(iops, maxIOPS int64) error { return errors.WithStack(&errors.Error{ Kind: ErrIOPSTooLarge, + Message: fmt.Sprintf("%s (%d) cannot be larger than %d", InstanceVolumeIOPSKey, iops, maxIOPS), + }) +} + +func ErrorIOPSTooLargeDueToVolumeSize(iops int64, volumeSize int64) error { + return errors.WithStack(&errors.Error{ + Kind: ErrIOPSTooLargeDueToVolumeSize, Message: fmt.Sprintf("%s (%d) cannot be more than 50 times larger than %s (%d); increase `%s` or decrease `%s` in your cluster configuration file", InstanceVolumeIOPSKey, iops, InstanceVolumeSizeKey, volumeSize, InstanceVolumeSizeKey, InstanceVolumeIOPSKey), }) } From ac81ca4ee236101acca67aa810f88f1990785f77 Mon Sep 17 00:00:00 2001 From: Robert Lucian Chiriac Date: Thu, 29 Apr 2021 00:03:13 +0300 Subject: [PATCH 05/13] Set volume type to gp2 & fix logic error --- pkg/types/clusterconfig/cluster_config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/types/clusterconfig/cluster_config.go b/pkg/types/clusterconfig/cluster_config.go index ab5b76660d..bf57993ab5 100644 --- a/pkg/types/clusterconfig/cluster_config.go +++ b/pkg/types/clusterconfig/cluster_config.go @@ -481,7 +481,7 @@ var ManagedConfigStructFieldValidations = []*cr.StructFieldValidation{ StructField: "InstanceVolumeType", StringValidation: &cr.StringValidation{ AllowedValues: VolumeTypesStrings(), - Default: GP3VolumeType.String(), + Default: GP2VolumeType.String(), }, Parser: func(str string) (interface{}, error) { return VolumeTypeFromString(str), nil @@ -946,7 +946,7 @@ func (ng *NodeGroup) validateNodeGroup(awsClient *aws.Client, region string) err } // throw error if IOPS defined for other storage than io1/gp3 - if ng.InstanceVolumeType != IO1VolumeType || ng.InstanceVolumeType != GP3VolumeType && ng.InstanceVolumeIOPS != nil { + if ng.InstanceVolumeType != IO1VolumeType && ng.InstanceVolumeType != GP3VolumeType && ng.InstanceVolumeIOPS != nil { return ErrorIOPSNotSupported(ng.InstanceVolumeType) } From 32ba84a7df6ff8e6419ef38d2559c940e4578a44 Mon Sep 17 00:00:00 2001 From: Robert Lucian Chiriac Date: Thu, 29 Apr 2021 01:02:50 +0300 Subject: [PATCH 06/13] Set default volume type to gp3 --- cli/cmd/cluster.go | 2 +- cli/cmd/lib_cluster_config.go | 2 +- manager/generate_eks.py | 3 ++ pkg/lib/aws/gen_resource_metadata.py | 5 +++ pkg/lib/aws/resource_metadata.go | 48 ++++++++++++----------- pkg/operator/operator/cron.go | 2 +- pkg/types/clusterconfig/cluster_config.go | 2 +- 7 files changed, 37 insertions(+), 27 deletions(-) diff --git a/cli/cmd/cluster.go b/cli/cmd/cluster.go index 0b784f4432..439d90b4ee 100644 --- a/cli/cmd/cluster.go +++ b/cli/cmd/cluster.go @@ -786,7 +786,7 @@ func getInfoOperatorResponse(operatorEndpoint string) (*schema.InfoResponse, err func printInfoPricing(infoResponse *schema.InfoResponse, clusterConfig clusterconfig.Config) { eksPrice := aws.EKSPrices[clusterConfig.Region] operatorInstancePrice := aws.InstanceMetadatas[clusterConfig.Region]["t3.medium"].Price - operatorEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp2"].PriceGB * 20 / 30 / 24 + operatorEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp3"].PriceGB * 20 / 30 / 24 metricsEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp2"].PriceGB * 40 / 30 / 24 nlbPrice := aws.NLBMetadatas[clusterConfig.Region].Price natUnitPrice := aws.NATMetadatas[clusterConfig.Region].Price diff --git a/cli/cmd/lib_cluster_config.go b/cli/cmd/lib_cluster_config.go index 16399c8024..c37fddbf40 100644 --- a/cli/cmd/lib_cluster_config.go +++ b/cli/cmd/lib_cluster_config.go @@ -149,7 +149,7 @@ func getInstallClusterConfig(awsClient *aws.Client, clusterConfigFile string, di func confirmInstallClusterConfig(clusterConfig *clusterconfig.Config, awsClient *aws.Client, disallowPrompt bool) { eksPrice := aws.EKSPrices[clusterConfig.Region] operatorInstancePrice := aws.InstanceMetadatas[clusterConfig.Region]["t3.medium"].Price - operatorEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp2"].PriceGB * 20 / 30 / 24 + operatorEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp3"].PriceGB * 20 / 30 / 24 metricsEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp2"].PriceGB * 40 / 30 / 24 nlbPrice := aws.NLBMetadatas[clusterConfig.Region].Price natUnitPrice := aws.NATMetadatas[clusterConfig.Region].Price diff --git a/manager/generate_eks.py b/manager/generate_eks.py index 81dc963871..0e86803ded 100644 --- a/manager/generate_eks.py +++ b/manager/generate_eks.py @@ -215,6 +215,9 @@ def generate_eks(cluster_config_path, ami_json_path): "minSize": 2, "maxSize": 2, "desiredCapacity": 2, + "volumeType": "gp3", + "volumeIOPS": 3000, + "volumeThroughput": 125, } operator_nodegroup = merge_override(operator_nodegroup, operator_settings) diff --git a/pkg/lib/aws/gen_resource_metadata.py b/pkg/lib/aws/gen_resource_metadata.py index 7fa0278682..e1650a91ae 100644 --- a/pkg/lib/aws/gen_resource_metadata.py +++ b/pkg/lib/aws/gen_resource_metadata.py @@ -183,6 +183,11 @@ def get_ebs_metadata(pricing): metadata["price_iops"] = price metadata["iops_configurable"] = "true" + elif product["attributes"].get("volumeApiName") == "gp3": + # not correct but will do for now + metadata["price_iops"] = 0 + metadata["iops_configurable"] = "true" + # set default values for all other storage types else: metadata["price_iops"] = 0 diff --git a/pkg/lib/aws/resource_metadata.go b/pkg/lib/aws/resource_metadata.go index cae7f047ab..5ccdba445c 100644 --- a/pkg/lib/aws/resource_metadata.go +++ b/pkg/lib/aws/resource_metadata.go @@ -943,6 +943,7 @@ var InstanceMetadatas = map[string]map[string]InstanceMetadata{ "i3.4xlarge": {Region: "ap-northeast-3", Type: "i3.4xlarge", Memory: kresource.MustParse("124928Mi"), CPU: kresource.MustParse("16"), GPU: 0, Inf: 0, Price: 1.464}, "i3.8xlarge": {Region: "ap-northeast-3", Type: "i3.8xlarge", Memory: kresource.MustParse("249856Mi"), CPU: kresource.MustParse("32"), GPU: 0, Inf: 0, Price: 2.928}, "i3.large": {Region: "ap-northeast-3", Type: "i3.large", Memory: kresource.MustParse("15616Mi"), CPU: kresource.MustParse("2"), GPU: 0, Inf: 0, Price: 0.183}, + "i3.metal": {Region: "ap-northeast-3", Type: "i3.metal", Memory: kresource.MustParse("524288Mi"), CPU: kresource.MustParse("64"), GPU: 0, Inf: 0, Price: 5.856}, "i3.xlarge": {Region: "ap-northeast-3", Type: "i3.xlarge", Memory: kresource.MustParse("31232Mi"), CPU: kresource.MustParse("4"), GPU: 0, Inf: 0, Price: 0.366}, "i3en.12xlarge": {Region: "ap-northeast-3", Type: "i3en.12xlarge", Memory: kresource.MustParse("393216Mi"), CPU: kresource.MustParse("48"), GPU: 0, Inf: 0, Price: 6.384}, "i3en.24xlarge": {Region: "ap-northeast-3", Type: "i3en.24xlarge", Memory: kresource.MustParse("786432Mi"), CPU: kresource.MustParse("96"), GPU: 0, Inf: 0, Price: 12.768}, @@ -4699,6 +4700,7 @@ var InstanceMetadatas = map[string]map[string]InstanceMetadata{ "i3.4xlarge": {Region: "us-gov-east-1", Type: "i3.4xlarge", Memory: kresource.MustParse("124928Mi"), CPU: kresource.MustParse("16"), GPU: 0, Inf: 0, Price: 1.504}, "i3.8xlarge": {Region: "us-gov-east-1", Type: "i3.8xlarge", Memory: kresource.MustParse("249856Mi"), CPU: kresource.MustParse("32"), GPU: 0, Inf: 0, Price: 3.008}, "i3.large": {Region: "us-gov-east-1", Type: "i3.large", Memory: kresource.MustParse("15616Mi"), CPU: kresource.MustParse("2"), GPU: 0, Inf: 0, Price: 0.188}, + "i3.metal": {Region: "us-gov-east-1", Type: "i3.metal", Memory: kresource.MustParse("524288Mi"), CPU: kresource.MustParse("64"), GPU: 0, Inf: 0, Price: 6.016}, "i3.xlarge": {Region: "us-gov-east-1", Type: "i3.xlarge", Memory: kresource.MustParse("31232Mi"), CPU: kresource.MustParse("4"), GPU: 0, Inf: 0, Price: 0.376}, "i3en.12xlarge": {Region: "us-gov-east-1", Type: "i3en.12xlarge", Memory: kresource.MustParse("393216Mi"), CPU: kresource.MustParse("48"), GPU: 0, Inf: 0, Price: 6.552}, "i3en.24xlarge": {Region: "us-gov-east-1", Type: "i3en.24xlarge", Memory: kresource.MustParse("786432Mi"), CPU: kresource.MustParse("96"), GPU: 0, Inf: 0, Price: 13.104}, @@ -5864,14 +5866,14 @@ var NATMetadatas = map[string]NATMetadata{ var EBSMetadatas = map[string]map[string]EBSMetadata{ "af-south-1": { "gp2": {Region: "af-south-1", Type: "gp2", PriceGB: 0.1309, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "af-south-1", Type: "gp3", PriceGB: 0.1047, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "af-south-1", Type: "gp3", PriceGB: 0.1047, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "af-south-1", Type: "io1", PriceGB: 0.16422, PriceIOPS: 0.0856800000, IOPSConfigurable: true}, "sc1": {Region: "af-south-1", Type: "sc1", PriceGB: 0.019992, PriceIOPS: 0, IOPSConfigurable: false}, "st1": {Region: "af-south-1", Type: "st1", PriceGB: 0.0595, PriceIOPS: 0, IOPSConfigurable: false}, }, "ap-east-1": { "gp2": {Region: "ap-east-1", Type: "gp2", PriceGB: 0.132, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "ap-east-1", Type: "gp3", PriceGB: 0.1056, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "ap-east-1", Type: "gp3", PriceGB: 0.1056, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "ap-east-1", Type: "io1", PriceGB: 0.1518, PriceIOPS: 0.0792000000, IOPSConfigurable: true}, "io2": {Region: "ap-east-1", Type: "io2", PriceGB: 0.1518, PriceIOPS: 0, IOPSConfigurable: false}, "sc1": {Region: "ap-east-1", Type: "sc1", PriceGB: 0.0198, PriceIOPS: 0, IOPSConfigurable: false}, @@ -5879,7 +5881,7 @@ var EBSMetadatas = map[string]map[string]EBSMetadata{ }, "ap-northeast-1": { "gp2": {Region: "ap-northeast-1", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "ap-northeast-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "ap-northeast-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "ap-northeast-1", Type: "io1", PriceGB: 0.142, PriceIOPS: 0.0740000000, IOPSConfigurable: true}, "io2": {Region: "ap-northeast-1", Type: "io2", PriceGB: 0.142, PriceIOPS: 0, IOPSConfigurable: false}, "sc1": {Region: "ap-northeast-1", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, IOPSConfigurable: false}, @@ -5887,7 +5889,7 @@ var EBSMetadatas = map[string]map[string]EBSMetadata{ }, "ap-northeast-2": { "gp2": {Region: "ap-northeast-2", Type: "gp2", PriceGB: 0.114, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "ap-northeast-2", Type: "gp3", PriceGB: 0.0912, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "ap-northeast-2", Type: "gp3", PriceGB: 0.0912, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "ap-northeast-2", Type: "io1", PriceGB: 0.1278, PriceIOPS: 0.0666000000, IOPSConfigurable: true}, "io2": {Region: "ap-northeast-2", Type: "io2", PriceGB: 0.1278, PriceIOPS: 0, IOPSConfigurable: false}, "sc1": {Region: "ap-northeast-2", Type: "sc1", PriceGB: 0.0174, PriceIOPS: 0, IOPSConfigurable: false}, @@ -5895,14 +5897,14 @@ var EBSMetadatas = map[string]map[string]EBSMetadata{ }, "ap-northeast-3": { "gp2": {Region: "ap-northeast-3", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "ap-northeast-3", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "ap-northeast-3", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "ap-northeast-3", Type: "io1", PriceGB: 0.142, PriceIOPS: 0.0740000000, IOPSConfigurable: true}, "sc1": {Region: "ap-northeast-3", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, IOPSConfigurable: false}, "st1": {Region: "ap-northeast-3", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, IOPSConfigurable: false}, }, "ap-south-1": { "gp2": {Region: "ap-south-1", Type: "gp2", PriceGB: 0.114, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "ap-south-1", Type: "gp3", PriceGB: 0.0912, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "ap-south-1", Type: "gp3", PriceGB: 0.0912, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "ap-south-1", Type: "io1", PriceGB: 0.131, PriceIOPS: 0.0680000000, IOPSConfigurable: true}, "io2": {Region: "ap-south-1", Type: "io2", PriceGB: 0.131, PriceIOPS: 0, IOPSConfigurable: false}, "sc1": {Region: "ap-south-1", Type: "sc1", PriceGB: 0.0174, PriceIOPS: 0, IOPSConfigurable: false}, @@ -5910,7 +5912,7 @@ var EBSMetadatas = map[string]map[string]EBSMetadata{ }, "ap-southeast-1": { "gp2": {Region: "ap-southeast-1", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "ap-southeast-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "ap-southeast-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "ap-southeast-1", Type: "io1", PriceGB: 0.138, PriceIOPS: 0.0720000000, IOPSConfigurable: true}, "io2": {Region: "ap-southeast-1", Type: "io2", PriceGB: 0.138, PriceIOPS: 0, IOPSConfigurable: false}, "sc1": {Region: "ap-southeast-1", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, IOPSConfigurable: false}, @@ -5918,7 +5920,7 @@ var EBSMetadatas = map[string]map[string]EBSMetadata{ }, "ap-southeast-2": { "gp2": {Region: "ap-southeast-2", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "ap-southeast-2", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "ap-southeast-2", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "ap-southeast-2", Type: "io1", PriceGB: 0.138, PriceIOPS: 0.0720000000, IOPSConfigurable: true}, "io2": {Region: "ap-southeast-2", Type: "io2", PriceGB: 0.138, PriceIOPS: 0, IOPSConfigurable: false}, "sc1": {Region: "ap-southeast-2", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, IOPSConfigurable: false}, @@ -5926,7 +5928,7 @@ var EBSMetadatas = map[string]map[string]EBSMetadata{ }, "ca-central-1": { "gp2": {Region: "ca-central-1", Type: "gp2", PriceGB: 0.11, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "ca-central-1", Type: "gp3", PriceGB: 0.088, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "ca-central-1", Type: "gp3", PriceGB: 0.088, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "ca-central-1", Type: "io1", PriceGB: 0.138, PriceIOPS: 0.0720000000, IOPSConfigurable: true}, "io2": {Region: "ca-central-1", Type: "io2", PriceGB: 0.138, PriceIOPS: 0, IOPSConfigurable: false}, "sc1": {Region: "ca-central-1", Type: "sc1", PriceGB: 0.0168, PriceIOPS: 0, IOPSConfigurable: false}, @@ -5934,7 +5936,7 @@ var EBSMetadatas = map[string]map[string]EBSMetadata{ }, "eu-central-1": { "gp2": {Region: "eu-central-1", Type: "gp2", PriceGB: 0.119, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "eu-central-1", Type: "gp3", PriceGB: 0.0952, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "eu-central-1", Type: "gp3", PriceGB: 0.0952, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "eu-central-1", Type: "io1", PriceGB: 0.149, PriceIOPS: 0.0780000000, IOPSConfigurable: true}, "io2": {Region: "eu-central-1", Type: "io2", PriceGB: 0.149, PriceIOPS: 0, IOPSConfigurable: false}, "sc1": {Region: "eu-central-1", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, IOPSConfigurable: false}, @@ -5942,7 +5944,7 @@ var EBSMetadatas = map[string]map[string]EBSMetadata{ }, "eu-north-1": { "gp2": {Region: "eu-north-1", Type: "gp2", PriceGB: 0.1045, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "eu-north-1", Type: "gp3", PriceGB: 0.0836, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "eu-north-1", Type: "gp3", PriceGB: 0.0836, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "eu-north-1", Type: "io1", PriceGB: 0.1311, PriceIOPS: 0.0684000000, IOPSConfigurable: true}, "io2": {Region: "eu-north-1", Type: "io2", PriceGB: 0.1311, PriceIOPS: 0, IOPSConfigurable: false}, "sc1": {Region: "eu-north-1", Type: "sc1", PriceGB: 0.01596, PriceIOPS: 0, IOPSConfigurable: false}, @@ -5950,14 +5952,14 @@ var EBSMetadatas = map[string]map[string]EBSMetadata{ }, "eu-south-1": { "gp2": {Region: "eu-south-1", Type: "gp2", PriceGB: 0.1155, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "eu-south-1", Type: "gp3", PriceGB: 0.0924, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "eu-south-1", Type: "gp3", PriceGB: 0.0924, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "eu-south-1", Type: "io1", PriceGB: 0.1449, PriceIOPS: 0.0756000000, IOPSConfigurable: true}, "sc1": {Region: "eu-south-1", Type: "sc1", PriceGB: 0.01764, PriceIOPS: 0, IOPSConfigurable: false}, "st1": {Region: "eu-south-1", Type: "st1", PriceGB: 0.0525, PriceIOPS: 0, IOPSConfigurable: false}, }, "eu-west-1": { "gp2": {Region: "eu-west-1", Type: "gp2", PriceGB: 0.11, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "eu-west-1", Type: "gp3", PriceGB: 0.088, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "eu-west-1", Type: "gp3", PriceGB: 0.088, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "eu-west-1", Type: "io1", PriceGB: 0.138, PriceIOPS: 0.0720000000, IOPSConfigurable: true}, "io2": {Region: "eu-west-1", Type: "io2", PriceGB: 0.138, PriceIOPS: 0, IOPSConfigurable: false}, "sc1": {Region: "eu-west-1", Type: "sc1", PriceGB: 0.0168, PriceIOPS: 0, IOPSConfigurable: false}, @@ -5965,7 +5967,7 @@ var EBSMetadatas = map[string]map[string]EBSMetadata{ }, "eu-west-2": { "gp2": {Region: "eu-west-2", Type: "gp2", PriceGB: 0.116, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "eu-west-2", Type: "gp3", PriceGB: 0.0928, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "eu-west-2", Type: "gp3", PriceGB: 0.0928, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "eu-west-2", Type: "io1", PriceGB: 0.145, PriceIOPS: 0.0760000000, IOPSConfigurable: true}, "io2": {Region: "eu-west-2", Type: "io2", PriceGB: 0.145, PriceIOPS: 0, IOPSConfigurable: false}, "sc1": {Region: "eu-west-2", Type: "sc1", PriceGB: 0.0174, PriceIOPS: 0, IOPSConfigurable: false}, @@ -5973,14 +5975,14 @@ var EBSMetadatas = map[string]map[string]EBSMetadata{ }, "eu-west-3": { "gp2": {Region: "eu-west-3", Type: "gp2", PriceGB: 0.116, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "eu-west-3", Type: "gp3", PriceGB: 0.0928, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "eu-west-3", Type: "gp3", PriceGB: 0.0928, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "eu-west-3", Type: "io1", PriceGB: 0.145, PriceIOPS: 0.0760000000, IOPSConfigurable: true}, "sc1": {Region: "eu-west-3", Type: "sc1", PriceGB: 0.0174, PriceIOPS: 0, IOPSConfigurable: false}, "st1": {Region: "eu-west-3", Type: "st1", PriceGB: 0.053, PriceIOPS: 0, IOPSConfigurable: false}, }, "me-south-1": { "gp2": {Region: "me-south-1", Type: "gp2", PriceGB: 0.121, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "me-south-1", Type: "gp3", PriceGB: 0.0968, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "me-south-1", Type: "gp3", PriceGB: 0.0968, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "me-south-1", Type: "io1", PriceGB: 0.1518, PriceIOPS: 0.0792000000, IOPSConfigurable: true}, "io2": {Region: "me-south-1", Type: "io2", PriceGB: 0.1518, PriceIOPS: 0, IOPSConfigurable: false}, "sc1": {Region: "me-south-1", Type: "sc1", PriceGB: 0.01848, PriceIOPS: 0, IOPSConfigurable: false}, @@ -5988,14 +5990,14 @@ var EBSMetadatas = map[string]map[string]EBSMetadata{ }, "sa-east-1": { "gp2": {Region: "sa-east-1", Type: "gp2", PriceGB: 0.19, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "sa-east-1", Type: "gp3", PriceGB: 0.152, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "sa-east-1", Type: "gp3", PriceGB: 0.152, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "sa-east-1", Type: "io1", PriceGB: 0.238, PriceIOPS: 0.0910000000, IOPSConfigurable: true}, "sc1": {Region: "sa-east-1", Type: "sc1", PriceGB: 0.0288, PriceIOPS: 0, IOPSConfigurable: false}, "st1": {Region: "sa-east-1", Type: "st1", PriceGB: 0.086, PriceIOPS: 0, IOPSConfigurable: false}, }, "us-east-1": { "gp2": {Region: "us-east-1", Type: "gp2", PriceGB: 0.1, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "us-east-1", Type: "gp3", PriceGB: 0.08, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "us-east-1", Type: "gp3", PriceGB: 0.08, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "us-east-1", Type: "io1", PriceGB: 0.125, PriceIOPS: 0.0650000000, IOPSConfigurable: true}, "io2": {Region: "us-east-1", Type: "io2", PriceGB: 0.125, PriceIOPS: 0, IOPSConfigurable: false}, "sc1": {Region: "us-east-1", Type: "sc1", PriceGB: 0.015, PriceIOPS: 0, IOPSConfigurable: false}, @@ -6003,7 +6005,7 @@ var EBSMetadatas = map[string]map[string]EBSMetadata{ }, "us-east-2": { "gp2": {Region: "us-east-2", Type: "gp2", PriceGB: 0.1, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "us-east-2", Type: "gp3", PriceGB: 0.08, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "us-east-2", Type: "gp3", PriceGB: 0.08, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "us-east-2", Type: "io1", PriceGB: 0.125, PriceIOPS: 0.0650000000, IOPSConfigurable: true}, "io2": {Region: "us-east-2", Type: "io2", PriceGB: 0.125, PriceIOPS: 0, IOPSConfigurable: false}, "sc1": {Region: "us-east-2", Type: "sc1", PriceGB: 0.015, PriceIOPS: 0, IOPSConfigurable: false}, @@ -6011,21 +6013,21 @@ var EBSMetadatas = map[string]map[string]EBSMetadata{ }, "us-gov-east-1": { "gp2": {Region: "us-gov-east-1", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "us-gov-east-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "us-gov-east-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "us-gov-east-1", Type: "io1", PriceGB: 0.15, PriceIOPS: 0.0780000000, IOPSConfigurable: true}, "sc1": {Region: "us-gov-east-1", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, IOPSConfigurable: false}, "st1": {Region: "us-gov-east-1", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, IOPSConfigurable: false}, }, "us-gov-west-1": { "gp2": {Region: "us-gov-west-1", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "us-gov-west-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "us-gov-west-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "us-gov-west-1", Type: "io1", PriceGB: 0.15, PriceIOPS: 0.0780000000, IOPSConfigurable: true}, "sc1": {Region: "us-gov-west-1", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, IOPSConfigurable: false}, "st1": {Region: "us-gov-west-1", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, IOPSConfigurable: false}, }, "us-west-1": { "gp2": {Region: "us-west-1", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "us-west-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "us-west-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "us-west-1", Type: "io1", PriceGB: 0.138, PriceIOPS: 0.0720000000, IOPSConfigurable: true}, "io2": {Region: "us-west-1", Type: "io2", PriceGB: 0.138, PriceIOPS: 0, IOPSConfigurable: false}, "sc1": {Region: "us-west-1", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, IOPSConfigurable: false}, @@ -6033,7 +6035,7 @@ var EBSMetadatas = map[string]map[string]EBSMetadata{ }, "us-west-2": { "gp2": {Region: "us-west-2", Type: "gp2", PriceGB: 0.1, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "us-west-2", Type: "gp3", PriceGB: 0.08, PriceIOPS: 0, IOPSConfigurable: false}, + "gp3": {Region: "us-west-2", Type: "gp3", PriceGB: 0.08, PriceIOPS: 0, IOPSConfigurable: true}, "io1": {Region: "us-west-2", Type: "io1", PriceGB: 0.125, PriceIOPS: 0.0650000000, IOPSConfigurable: true}, "io2": {Region: "us-west-2", Type: "io2", PriceGB: 0.125, PriceIOPS: 0, IOPSConfigurable: false}, "sc1": {Region: "us-west-2", Type: "sc1", PriceGB: 0.015, PriceIOPS: 0, IOPSConfigurable: false}, diff --git a/pkg/operator/operator/cron.go b/pkg/operator/operator/cron.go index 4344cca5b7..2c26e140ba 100644 --- a/pkg/operator/operator/cron.go +++ b/pkg/operator/operator/cron.go @@ -196,7 +196,7 @@ func getEBSPriceForNodeGroupInstance(ngs []*clusterconfig.NodeGroup, ngName stri func clusterFixedPrice() float64 { eksPrice := aws.EKSPrices[config.CoreConfig.Region] operatorInstancePrice := aws.InstanceMetadatas[config.CoreConfig.Region]["t3.medium"].Price - operatorEBSPrice := aws.EBSMetadatas[config.CoreConfig.Region]["gp2"].PriceGB * 20 / 30 / 24 + operatorEBSPrice := aws.EBSMetadatas[config.CoreConfig.Region]["gp3"].PriceGB * 20 / 30 / 24 metricsEBSPrice := aws.EBSMetadatas[config.CoreConfig.Region]["gp2"].PriceGB * 40 / 30 / 24 nlbPrice := aws.NLBMetadatas[config.CoreConfig.Region].Price natUnitPrice := aws.NATMetadatas[config.CoreConfig.Region].Price diff --git a/pkg/types/clusterconfig/cluster_config.go b/pkg/types/clusterconfig/cluster_config.go index bf57993ab5..66a5036a55 100644 --- a/pkg/types/clusterconfig/cluster_config.go +++ b/pkg/types/clusterconfig/cluster_config.go @@ -481,7 +481,7 @@ var ManagedConfigStructFieldValidations = []*cr.StructFieldValidation{ StructField: "InstanceVolumeType", StringValidation: &cr.StringValidation{ AllowedValues: VolumeTypesStrings(), - Default: GP2VolumeType.String(), + Default: GP3VolumeType.String(), }, Parser: func(str string) (interface{}, error) { return VolumeTypeFromString(str), nil From 625faa724bf4b21d5770a7d8f1aaefb0fa85bbfb Mon Sep 17 00:00:00 2001 From: Robert Lucian Chiriac Date: Thu, 29 Apr 2021 01:20:04 +0300 Subject: [PATCH 07/13] Remove volume-related line from cluster docs --- docs/clusters/management/create.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/clusters/management/create.md b/docs/clusters/management/create.md index a55abef1ad..fae989fbb3 100644 --- a/docs/clusters/management/create.md +++ b/docs/clusters/management/create.md @@ -47,7 +47,6 @@ node_groups: max_instances: 5 instance_volume_size: 50 instance_volume_type: gp3 - # instance_volume_iops: 3000 spot: false ... From 652252258a47178c936e48427ff0af2f77246933 Mon Sep 17 00:00:00 2001 From: Robert Lucian Chiriac Date: Thu, 29 Apr 2021 17:09:49 +0300 Subject: [PATCH 08/13] Address PR comments --- cli/cmd/cluster.go | 4 +- cli/cmd/lib_cluster_config.go | 4 +- docs/clusters/management/create.md | 2 +- manager/generate_eks.py | 1 + pkg/operator/operator/cron.go | 4 +- pkg/types/clusterconfig/cluster_config.go | 53 +++++++++++++++-------- pkg/types/clusterconfig/errors.go | 45 ++++++++++++++++--- 7 files changed, 81 insertions(+), 32 deletions(-) diff --git a/cli/cmd/cluster.go b/cli/cmd/cluster.go index 439d90b4ee..ae6c0f8cd4 100644 --- a/cli/cmd/cluster.go +++ b/cli/cmd/cluster.go @@ -787,7 +787,7 @@ func printInfoPricing(infoResponse *schema.InfoResponse, clusterConfig clusterco eksPrice := aws.EKSPrices[clusterConfig.Region] operatorInstancePrice := aws.InstanceMetadatas[clusterConfig.Region]["t3.medium"].Price operatorEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp3"].PriceGB * 20 / 30 / 24 - metricsEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp2"].PriceGB * 40 / 30 / 24 + metricsEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp2"].PriceGB * (40 + 2) / 30 / 24 nlbPrice := aws.NLBMetadatas[clusterConfig.Region].Price natUnitPrice := aws.NATMetadatas[clusterConfig.Region].Price @@ -833,7 +833,7 @@ func printInfoPricing(infoResponse *schema.InfoResponse, clusterConfig clusterco } else if clusterConfig.NATGateway == clusterconfig.HighlyAvailableNATGateway { natTotalPrice = natUnitPrice * float64(len(clusterConfig.AvailabilityZones)) } - totalPrice := eksPrice + totalNodeGroupsPrice + operatorInstancePrice*2 + operatorEBSPrice + metricsEBSPrice + nlbPrice*2 + natTotalPrice + totalPrice := eksPrice + totalNodeGroupsPrice + 2*(operatorInstancePrice+operatorEBSPrice) + metricsEBSPrice + nlbPrice*2 + natTotalPrice fmt.Printf(console.Bold("\nyour cluster currently costs %s per hour\n\n"), s.DollarsAndCents(totalPrice)) rows = append(rows, []interface{}{"2 t3.medium instances for cortex", s.DollarsMaxPrecision(operatorInstancePrice * 2)}) diff --git a/cli/cmd/lib_cluster_config.go b/cli/cmd/lib_cluster_config.go index f2e8f02f5f..a356624791 100644 --- a/cli/cmd/lib_cluster_config.go +++ b/cli/cmd/lib_cluster_config.go @@ -150,7 +150,7 @@ func confirmInstallClusterConfig(clusterConfig *clusterconfig.Config, awsClient eksPrice := aws.EKSPrices[clusterConfig.Region] operatorInstancePrice := aws.InstanceMetadatas[clusterConfig.Region]["t3.medium"].Price operatorEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp3"].PriceGB * 20 / 30 / 24 - metricsEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp2"].PriceGB * 40 / 30 / 24 + metricsEBSPrice := aws.EBSMetadatas[clusterConfig.Region]["gp2"].PriceGB * (40 + 2) / 30 / 24 nlbPrice := aws.NLBMetadatas[clusterConfig.Region].Price natUnitPrice := aws.NATMetadatas[clusterConfig.Region].Price @@ -170,7 +170,7 @@ func confirmInstallClusterConfig(clusterConfig *clusterconfig.Config, awsClient rows = append(rows, []interface{}{"1 eks cluster", s.DollarsMaxPrecision(eksPrice)}) ngNameToSpotInstancesUsed := map[string]int{} - fixedPrice := eksPrice + 2*operatorInstancePrice + operatorEBSPrice + metricsEBSPrice + 2*nlbPrice + natTotalPrice + fixedPrice := eksPrice + 2*(operatorInstancePrice+operatorEBSPrice) + metricsEBSPrice + 2*nlbPrice + natTotalPrice totalMinPrice := fixedPrice totalMaxPrice := fixedPrice for _, ng := range clusterConfig.NodeGroups { diff --git a/docs/clusters/management/create.md b/docs/clusters/management/create.md index fae989fbb3..b6c7e90505 100644 --- a/docs/clusters/management/create.md +++ b/docs/clusters/management/create.md @@ -36,7 +36,7 @@ node_groups: min_instances: 1 # minimum number of instances max_instances: 5 # maximum number of instances instance_volume_size: 50 # disk storage size per instance (GB) - instance_volume_type: gp2 # instance volume type [gp2 | gp3 | io1 | st1 | sc1] + instance_volume_type: gp3 # instance volume type [gp2 | gp3 | io1 | st1 | sc1] # instance_volume_iops: 3000 # instance volume iops (only applicable to io1/gp3) # instance_volume_throughput: 125 # instance volume throughput (only applicable to gp3) spot: false # whether to use spot instances diff --git a/manager/generate_eks.py b/manager/generate_eks.py index 0e86803ded..141e79d915 100644 --- a/manager/generate_eks.py +++ b/manager/generate_eks.py @@ -216,6 +216,7 @@ def generate_eks(cluster_config_path, ami_json_path): "maxSize": 2, "desiredCapacity": 2, "volumeType": "gp3", + "volumeSize": 20, "volumeIOPS": 3000, "volumeThroughput": 125, } diff --git a/pkg/operator/operator/cron.go b/pkg/operator/operator/cron.go index 2c26e140ba..4047ea7e6f 100644 --- a/pkg/operator/operator/cron.go +++ b/pkg/operator/operator/cron.go @@ -197,7 +197,7 @@ func clusterFixedPrice() float64 { eksPrice := aws.EKSPrices[config.CoreConfig.Region] operatorInstancePrice := aws.InstanceMetadatas[config.CoreConfig.Region]["t3.medium"].Price operatorEBSPrice := aws.EBSMetadatas[config.CoreConfig.Region]["gp3"].PriceGB * 20 / 30 / 24 - metricsEBSPrice := aws.EBSMetadatas[config.CoreConfig.Region]["gp2"].PriceGB * 40 / 30 / 24 + metricsEBSPrice := aws.EBSMetadatas[config.CoreConfig.Region]["gp2"].PriceGB * (40 + 2) / 30 / 24 nlbPrice := aws.NLBMetadatas[config.CoreConfig.Region].Price natUnitPrice := aws.NATMetadatas[config.CoreConfig.Region].Price var natTotalPrice float64 @@ -208,7 +208,7 @@ func clusterFixedPrice() float64 { natTotalPrice = natUnitPrice * float64(len(config.ManagedConfig.AvailabilityZones)) } - return eksPrice + 2*operatorInstancePrice + operatorEBSPrice + metricsEBSPrice + 2*nlbPrice + natTotalPrice + return eksPrice + 2*(operatorInstancePrice+operatorEBSPrice) + metricsEBSPrice + 2*nlbPrice + natTotalPrice } func ErrorHandler(cronName string) func(error) { diff --git a/pkg/types/clusterconfig/cluster_config.go b/pkg/types/clusterconfig/cluster_config.go index b27e3a2eac..e100307f45 100644 --- a/pkg/types/clusterconfig/cluster_config.go +++ b/pkg/types/clusterconfig/cluster_config.go @@ -60,8 +60,16 @@ var ( _cachedCNISupportedInstances *string _defaultIAMPolicies = []string{"arn:aws:iam::aws:policy/AmazonS3FullAccess"} _invalidTagPrefixes = []string{"kubernetes.io/", "k8s.io/", "eksctl.", "alpha.eksctl.", "beta.eksctl.", "aws:", "Aws:", "aWs:", "awS:", "aWS:", "AwS:", "aWS:", "AWS:"} + + _smallestIOPSForIO1VolumeType = int64(100) _highestIOPSForIO1VolumeType = int64(64000) + _smallestIOPSForGP3VolumeType = int64(3000) _highestIOPSForGP3VolumeType = int64(16000) + + _maxIOPSToVolumeSizeRatioForIO1 = int64(50) + _maxIOPSToVolumeSizeRatioForGP3 = int64(500) + _maxIOPSToThroughputRatioForGP3 = int64(4) + // This regex is stricter than the actual S3 rules _strictS3BucketRegex = regexp.MustCompile(`^([a-z0-9])+(-[a-z0-9]+)*$`) ) @@ -490,14 +498,13 @@ var ManagedConfigStructFieldValidations = []*cr.StructFieldValidation{ { StructField: "InstanceVolumeIOPS", Int64PtrValidation: &cr.Int64PtrValidation{ - GreaterThanOrEqualTo: pointer.Int64(100), - AllowExplicitNull: true, + AllowExplicitNull: true, }, }, { StructField: "InstanceVolumeThroughput", Int64PtrValidation: &cr.Int64PtrValidation{ - GreaterThanOrEqualTo: pointer.Int64(100), + GreaterThanOrEqualTo: pointer.Int64(125), LessThanOrEqualTo: pointer.Int64(1000), AllowExplicitNull: true, }, @@ -952,31 +959,41 @@ func (ng *NodeGroup) validateNodeGroup(awsClient *aws.Client, region string) err return ErrorThroughputNotSupported(ng.InstanceVolumeType) } + if ng.InstanceVolumeType == GP3VolumeType && ((ng.InstanceVolumeIOPS != nil && ng.InstanceVolumeThroughput == nil) || (ng.InstanceVolumeIOPS == nil && ng.InstanceVolumeThroughput != nil)) { + return ErrorSpecifyTwoOrNone(InstanceVolumeIOPSKey, InstanceVolumeThroughputKey) + } + if ng.InstanceVolumeIOPS != nil { if ng.InstanceVolumeType == IO1VolumeType { + if *ng.InstanceVolumeIOPS < _smallestIOPSForIO1VolumeType { + return ErrorIOPSTooSmall(ng.InstanceVolumeType, *ng.InstanceVolumeIOPS, _smallestIOPSForIO1VolumeType) + } if *ng.InstanceVolumeIOPS > _highestIOPSForIO1VolumeType { - return ErrorIOPSTooLarge(*ng.InstanceVolumeIOPS, _highestIOPSForIO1VolumeType) + return ErrorIOPSTooLarge(ng.InstanceVolumeType, *ng.InstanceVolumeIOPS, _highestIOPSForIO1VolumeType) } - if *ng.InstanceVolumeIOPS > ng.InstanceVolumeSize*50 { - return ErrorIOPSTooLargeDueToVolumeSize(*ng.InstanceVolumeIOPS, ng.InstanceVolumeSize) + if *ng.InstanceVolumeIOPS > ng.InstanceVolumeSize*_maxIOPSToVolumeSizeRatioForIO1 { + return ErrorIOPSToVolumeSizeRatio(ng.InstanceVolumeType, _maxIOPSToVolumeSizeRatioForIO1, *ng.InstanceVolumeIOPS, ng.InstanceVolumeSize) } } else { + if *ng.InstanceVolumeIOPS < _smallestIOPSForGP3VolumeType { + return ErrorIOPSTooSmall(ng.InstanceVolumeType, *ng.InstanceVolumeIOPS, _smallestIOPSForGP3VolumeType) + } if *ng.InstanceVolumeIOPS > _highestIOPSForGP3VolumeType { - return ErrorIOPSTooLarge(*ng.InstanceVolumeIOPS, _highestIOPSForGP3VolumeType) + return ErrorIOPSTooLarge(ng.InstanceVolumeType, *ng.InstanceVolumeIOPS, _highestIOPSForGP3VolumeType) + } + if *ng.InstanceVolumeIOPS > ng.InstanceVolumeSize*_maxIOPSToVolumeSizeRatioForGP3 { + return ErrorIOPSToVolumeSizeRatio(ng.InstanceVolumeType, _maxIOPSToVolumeSizeRatioForGP3, *ng.InstanceVolumeIOPS, ng.InstanceVolumeSize) + } + iopsToThroughputRatio := float64(*ng.InstanceVolumeIOPS) / float64(*ng.InstanceVolumeThroughput) + if iopsToThroughputRatio > float64(_maxIOPSToThroughputRatioForGP3) { + return ErrorIOPSToThroughputRatio(ng.InstanceVolumeType, iopsToThroughputRatio, *ng.InstanceVolumeIOPS, *ng.InstanceVolumeThroughput) } } - } - - if aws.EBSMetadatas[region][ng.InstanceVolumeType.String()].IOPSConfigurable && ng.InstanceVolumeIOPS == nil { - if ng.InstanceVolumeType == GP3VolumeType { - ng.InstanceVolumeIOPS = pointer.Int64(3000) - } else { - ng.InstanceVolumeIOPS = pointer.Int64(libmath.MinInt64(ng.InstanceVolumeSize*50, 3000)) - } - } - - if ng.InstanceVolumeType == GP3VolumeType && ng.InstanceVolumeThroughput == nil { + } else if ng.InstanceVolumeType == GP3VolumeType && aws.EBSMetadatas[region][ng.InstanceVolumeType.String()].IOPSConfigurable { + ng.InstanceVolumeIOPS = pointer.Int64(3000) ng.InstanceVolumeThroughput = pointer.Int64(125) + } else if ng.InstanceVolumeType == IO1VolumeType && aws.EBSMetadatas[region][ng.InstanceVolumeType.String()].IOPSConfigurable { + ng.InstanceVolumeIOPS = pointer.Int64(libmath.MinInt64(ng.InstanceVolumeSize*_maxIOPSToVolumeSizeRatioForIO1, 3000)) } if ng.Spot { diff --git a/pkg/types/clusterconfig/errors.go b/pkg/types/clusterconfig/errors.go index acb94fbb9f..46f51c8154 100644 --- a/pkg/types/clusterconfig/errors.go +++ b/pkg/types/clusterconfig/errors.go @@ -56,6 +56,7 @@ const ( ErrNotEnoughValidDefaultAvailibilityZones = "clusterconfig.not_enough_valid_default_availability_zones" ErrNoNATGatewayWithSubnets = "clusterconfig.no_nat_gateway_with_subnets" ErrSpecifyOneOrNone = "clusterconfig.specify_one_or_none" + ErrSpecifyTwoOrNone = "clusterconfig.specify_two_or_none" ErrDependentFieldMustBeSpecified = "clusterconfig.dependent_field_must_be_specified" ErrFieldConfigurationDependentOnCondition = "clusterconfig.field_configuration_dependent_on_condition" ErrDidNotMatchStrictS3Regex = "clusterconfig.did_not_match_strict_s3_regex" @@ -64,8 +65,10 @@ const ( ErrInvalidInstanceType = "clusterconfig.invalid_instance_type" ErrIOPSNotSupported = "clusterconfig.iops_not_supported" ErrThroughputNotSupported = "clusterconfig.throughput_not_supported" + ErrIOPSTooSmall = "clusterconfig.iops_too_small" ErrIOPSTooLarge = "clusterconfig.iops_too_large" - ErrIOPSTooLargeDueToVolumeSize = "clusterconfig.iops_too_large_due_to_volume_siz" + ErrIOPSToVolumeSizeRatio = "clusterconfig.iops_to_volume_size_ratio" + ErrIOPSToThroughputRatio = "clusterconfig.iops_to_throughput_ratio" ErrCantOverrideDefaultTag = "clusterconfig.cant_override_default_tag" ErrSSLCertificateARNNotFound = "clusterconfig.ssl_certificate_arn_not_found" ErrIAMPolicyARNNotFound = "clusterconfig.iam_policy_arn_not_found" @@ -279,6 +282,20 @@ func ErrorSpecifyOneOrNone(fieldName1 string, fieldName2 string, fieldNames ...s }) } +func ErrorSpecifyTwoOrNone(fieldName1 string, fieldName2 string, fieldNames ...string) error { + fieldNames = append([]string{fieldName1, fieldName2}, fieldNames...) + + message := fmt.Sprintf("specify exactly two or none of the following fields: %s", s.StrsAnd(fieldNames)) + if len(fieldNames) == 1 { + message = fmt.Sprintf("cannot have a single field (%s) to choose from)", fieldNames[0]) + } + + return errors.WithStack(&errors.Error{ + Kind: ErrSpecifyTwoOrNone, + Message: message, + }) +} + func ErrorDependentFieldMustBeSpecified(configuredField string, dependencyField string) error { return errors.WithStack(&errors.Error{ Kind: ErrDependentFieldMustBeSpecified, @@ -324,7 +341,7 @@ func ErrorInvalidInstanceType(instanceType string) error { func ErrorIOPSNotSupported(volumeType VolumeType) error { return errors.WithStack(&errors.Error{ Kind: ErrIOPSNotSupported, - Message: fmt.Sprintf("IOPS cannot be configured for volume type %s; set `%s: %s`, `%s: %s` or remove `%s` from your cluster configuration file", volumeType, InstanceVolumeTypeKey, IO1VolumeType, InstanceVolumeTypeKey, GP3VolumeType, InstanceVolumeIOPSKey), + Message: fmt.Sprintf("IOPS cannot be configured for volume type %s; set `%s: %s`, `%s: %s`, or remove `%s` from your cluster configuration file", volumeType, InstanceVolumeTypeKey, IO1VolumeType, InstanceVolumeTypeKey, GP3VolumeType, InstanceVolumeIOPSKey), }) } @@ -335,17 +352,31 @@ func ErrorThroughputNotSupported(volumeType VolumeType) error { }) } -func ErrorIOPSTooLarge(iops, maxIOPS int64) error { +func ErrorIOPSTooSmall(volumeType VolumeType, iops, minIOPS int64) error { + return errors.WithStack(&errors.Error{ + Kind: ErrIOPSTooSmall, + Message: fmt.Sprintf("for %s volume type, %s (%d) cannot be smaller than %d", volumeType, InstanceVolumeIOPSKey, iops, minIOPS), + }) +} + +func ErrorIOPSTooLarge(volumeType VolumeType, iops, maxIOPS int64) error { return errors.WithStack(&errors.Error{ Kind: ErrIOPSTooLarge, - Message: fmt.Sprintf("%s (%d) cannot be larger than %d", InstanceVolumeIOPSKey, iops, maxIOPS), + Message: fmt.Sprintf("for %s volume type, %s (%d) cannot be larger than %d", volumeType, InstanceVolumeIOPSKey, iops, maxIOPS), + }) +} + +func ErrorIOPSToVolumeSizeRatio(volumeType VolumeType, ratio, iops int64, volumeSize int64) error { + return errors.WithStack(&errors.Error{ + Kind: ErrIOPSToVolumeSizeRatio, + Message: fmt.Sprintf("for %s volume type, %s (%d) cannot be more than %d times larger than %s (%d); increase `%s` or decrease `%s` in your cluster configuration file", volumeType, InstanceVolumeIOPSKey, iops, ratio, InstanceVolumeSizeKey, volumeSize, InstanceVolumeSizeKey, InstanceVolumeIOPSKey), }) } -func ErrorIOPSTooLargeDueToVolumeSize(iops int64, volumeSize int64) error { +func ErrorIOPSToThroughputRatio(volumeType VolumeType, ratio float64, throughput int64, iops int64) error { return errors.WithStack(&errors.Error{ - Kind: ErrIOPSTooLargeDueToVolumeSize, - Message: fmt.Sprintf("%s (%d) cannot be more than 50 times larger than %s (%d); increase `%s` or decrease `%s` in your cluster configuration file", InstanceVolumeIOPSKey, iops, InstanceVolumeSizeKey, volumeSize, InstanceVolumeSizeKey, InstanceVolumeIOPSKey), + Kind: ErrIOPSToThroughputRatio, + Message: fmt.Sprintf("for %s volume type, %s (%d) cannot be more than %f times larger than %s (%d); increase `%s` or decrease `%s` in your cluster configuration file", volumeType, InstanceVolumeIOPSKey, iops, ratio, InstanceVolumeThroughputKey, throughput, InstanceVolumeThroughputKey, InstanceVolumeIOPSKey), }) } From a3f6d6a6e6cb5c977dc73adb9f60f28920023a6f Mon Sep 17 00:00:00 2001 From: Robert Lucian Chiriac Date: Thu, 29 Apr 2021 22:36:17 +0300 Subject: [PATCH 09/13] Add pricing to gp3 volume types --- cli/cmd/cluster.go | 6 +- cli/cmd/lib_cluster_config.go | 6 +- pkg/lib/aws/gen_resource_metadata.py | 41 +++- pkg/lib/aws/resource_metadata.go | 274 ++++++++++++++------------- pkg/operator/operator/cron.go | 6 +- 5 files changed, 191 insertions(+), 142 deletions(-) diff --git a/cli/cmd/cluster.go b/cli/cmd/cluster.go index ae6c0f8cd4..06463332ca 100644 --- a/cli/cmd/cluster.go +++ b/cli/cmd/cluster.go @@ -811,9 +811,13 @@ func printInfoPricing(infoResponse *schema.InfoResponse, clusterConfig clusterco numInstances := len(nodesInfo) ebsPrice := aws.EBSMetadatas[clusterConfig.Region][ng.InstanceVolumeType.String()].PriceGB * float64(ng.InstanceVolumeSize) / 30 / 24 - if ng.InstanceVolumeType.String() == "io1" && ng.InstanceVolumeIOPS != nil { + if ng.InstanceVolumeType == clusterconfig.IO1VolumeType && ng.InstanceVolumeIOPS != nil { ebsPrice += aws.EBSMetadatas[clusterConfig.Region][ng.InstanceVolumeType.String()].PriceIOPS * float64(*ng.InstanceVolumeIOPS) / 30 / 24 } + if ng.InstanceVolumeType == clusterconfig.GP3VolumeType && ng.InstanceVolumeIOPS != nil && ng.InstanceVolumeThroughput != nil { + ebsPrice += aws.EBSMetadatas[clusterConfig.Region][ng.InstanceVolumeType.String()].PriceIOPS * float64(*ng.InstanceVolumeIOPS) / 30 / 24 + ebsPrice += aws.EBSMetadatas[clusterConfig.Region][ng.InstanceVolumeType.String()].PriceThroughput * float64(*ng.InstanceVolumeThroughput) / 30 / 24 + } totalEBSPrice := ebsPrice * float64(numInstances) totalInstancePrice := float64(0) diff --git a/cli/cmd/lib_cluster_config.go b/cli/cmd/lib_cluster_config.go index a356624791..7534b56824 100644 --- a/cli/cmd/lib_cluster_config.go +++ b/cli/cmd/lib_cluster_config.go @@ -176,9 +176,13 @@ func confirmInstallClusterConfig(clusterConfig *clusterconfig.Config, awsClient for _, ng := range clusterConfig.NodeGroups { apiInstancePrice := aws.InstanceMetadatas[clusterConfig.Region][ng.InstanceType].Price apiEBSPrice := aws.EBSMetadatas[clusterConfig.Region][ng.InstanceVolumeType.String()].PriceGB * float64(ng.InstanceVolumeSize) / 30 / 24 - if ng.InstanceVolumeType.String() == "io1" && ng.InstanceVolumeIOPS != nil { + if ng.InstanceVolumeType == clusterconfig.IO1VolumeType && ng.InstanceVolumeIOPS != nil { apiEBSPrice += aws.EBSMetadatas[clusterConfig.Region][ng.InstanceVolumeType.String()].PriceIOPS * float64(*ng.InstanceVolumeIOPS) / 30 / 24 } + if ng.InstanceVolumeType == clusterconfig.GP3VolumeType && ng.InstanceVolumeIOPS != nil && ng.InstanceVolumeThroughput != nil { + apiEBSPrice += aws.EBSMetadatas[clusterConfig.Region][ng.InstanceVolumeType.String()].PriceIOPS * float64(*ng.InstanceVolumeIOPS) / 30 / 24 + apiEBSPrice += aws.EBSMetadatas[clusterConfig.Region][ng.InstanceVolumeType.String()].PriceThroughput * float64(*ng.InstanceVolumeThroughput) / 30 / 24 + } totalMinPrice += float64(ng.MinInstances) * (apiInstancePrice + apiEBSPrice) totalMaxPrice += float64(ng.MaxInstances) * (apiInstancePrice + apiEBSPrice) diff --git a/pkg/lib/aws/gen_resource_metadata.py b/pkg/lib/aws/gen_resource_metadata.py index e1650a91ae..84c7197bf2 100644 --- a/pkg/lib/aws/gen_resource_metadata.py +++ b/pkg/lib/aws/gen_resource_metadata.py @@ -181,17 +181,48 @@ def get_ebs_metadata(pricing): price = list(price_dimensions.values())[0]["pricePerUnit"]["USD"] metadata["price_iops"] = price + metadata["price_throughput"] = 0 metadata["iops_configurable"] = "true" + metadata["throughput_configurable"] = "false" elif product["attributes"].get("volumeApiName") == "gp3": - # not correct but will do for now - metadata["price_iops"] = 0 + # go through pricing data until found data about IOPS and throughput pricing + for _, product_iops in pricing["products"].items(): + if product_iops.get("attributes") is None: + continue + if product_iops.get("productFamily") not in [ + "System Operation", + "Provisioned Throughput", + ]: + continue + if product_iops["attributes"].get("volumeApiName") != "gp3": + continue + if product_iops["attributes"].get("group") not in ["EBS IOPS", "EBS Throughput"]: + continue + if product_iops["attributes"].get("provisioned") != "Yes": + continue + + price_dimensions = list(pricing["terms"]["OnDemand"][product_iops["sku"]].values())[ + 0 + ]["priceDimensions"] + if product_iops["attributes"].get("group") == "EBS IOPS": + price_iops = list(price_dimensions.values())[0]["pricePerUnit"]["USD"] + else: + price_throughput = ( + float(list(price_dimensions.values())[0]["pricePerUnit"]["USD"]) / 1000 + ) + + metadata["price_iops"] = price_iops + metadata["price_throughput"] = price_throughput + metadata["throughput_configurable"] = "true" metadata["iops_configurable"] = "true" # set default values for all other storage types else: metadata["price_iops"] = 0 + metadata["price_throughput"] = 0 metadata["iops_configurable"] = "false" + metadata["throughput_configurable"] = "false" storage_mapping[product["attributes"]["volumeApiName"]] = metadata @@ -270,7 +301,9 @@ def get_eks_price(region): Region string `json:"region"` PriceGB float64 `json:"price_gb"` PriceIOPS float64 `json:"price_iops"` + PriceThroughput float64 `json:"price_throughput"` IOPSConfigurable bool `json:"iops_configurable"` + ThroughputConfigurable bool `json:"throughput_configurable"` Type string `json:"type"` } @@ -331,7 +364,7 @@ def get_eks_price(region): ) ebs_type_map_template = Template( - """"${type}": {Region: "${region}",Type: "${type}", PriceGB: ${price_gb}, PriceIOPS: ${price_iops}, IOPSConfigurable: ${iops_configurable}}, + """"${type}": {Region: "${region}",Type: "${type}", PriceGB: ${price_gb}, PriceIOPS: ${price_iops}, PriceThroughput: ${price_throughput}, IOPSConfigurable: ${iops_configurable}, ThroughputConfigurable: ${throughput_configurable}}, """ ) @@ -386,7 +419,9 @@ def main(): "type": ebs_type, "price_gb": metadata["price_gb"], "price_iops": metadata["price_iops"], + "price_throughput": metadata["price_throughput"], "iops_configurable": metadata["iops_configurable"], + "throughput_configurable": metadata["throughput_configurable"], } ) diff --git a/pkg/lib/aws/resource_metadata.go b/pkg/lib/aws/resource_metadata.go index 5ccdba445c..80d976375b 100644 --- a/pkg/lib/aws/resource_metadata.go +++ b/pkg/lib/aws/resource_metadata.go @@ -43,11 +43,13 @@ type NATMetadata struct { } type EBSMetadata struct { - Region string `json:"region"` - PriceGB float64 `json:"price_gb"` - PriceIOPS float64 `json:"price_iops"` - IOPSConfigurable bool `json:"iops_configurable"` - Type string `json:"type"` + Region string `json:"region"` + PriceGB float64 `json:"price_gb"` + PriceIOPS float64 `json:"price_iops"` + PriceThroughput float64 `json:"price_throughput"` + IOPSConfigurable bool `json:"iops_configurable"` + ThroughputConfigurable bool `json:"throughput_configurable"` + Type string `json:"type"` } // region -> instance type -> instance metadata @@ -5865,181 +5867,181 @@ var NATMetadatas = map[string]NATMetadata{ // region -> EBS metadata var EBSMetadatas = map[string]map[string]EBSMetadata{ "af-south-1": { - "gp2": {Region: "af-south-1", Type: "gp2", PriceGB: 0.1309, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "af-south-1", Type: "gp3", PriceGB: 0.1047, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "af-south-1", Type: "io1", PriceGB: 0.16422, PriceIOPS: 0.0856800000, IOPSConfigurable: true}, - "sc1": {Region: "af-south-1", Type: "sc1", PriceGB: 0.019992, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "af-south-1", Type: "st1", PriceGB: 0.0595, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "af-south-1", Type: "gp2", PriceGB: 0.1309, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "af-south-1", Type: "gp3", PriceGB: 0.1047, PriceIOPS: 0.0065000000, PriceThroughput: 0.0536576, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "af-south-1", Type: "io1", PriceGB: 0.16422, PriceIOPS: 0.0856800000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "sc1": {Region: "af-south-1", Type: "sc1", PriceGB: 0.019992, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "af-south-1", Type: "st1", PriceGB: 0.0595, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "ap-east-1": { - "gp2": {Region: "ap-east-1", Type: "gp2", PriceGB: 0.132, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "ap-east-1", Type: "gp3", PriceGB: 0.1056, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "ap-east-1", Type: "io1", PriceGB: 0.1518, PriceIOPS: 0.0792000000, IOPSConfigurable: true}, - "io2": {Region: "ap-east-1", Type: "io2", PriceGB: 0.1518, PriceIOPS: 0, IOPSConfigurable: false}, - "sc1": {Region: "ap-east-1", Type: "sc1", PriceGB: 0.0198, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "ap-east-1", Type: "st1", PriceGB: 0.0594, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "ap-east-1", Type: "gp2", PriceGB: 0.132, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "ap-east-1", Type: "gp3", PriceGB: 0.1056, PriceIOPS: 0.0066000000, PriceThroughput: 0.0540672, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "ap-east-1", Type: "io1", PriceGB: 0.1518, PriceIOPS: 0.0792000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "io2": {Region: "ap-east-1", Type: "io2", PriceGB: 0.1518, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "sc1": {Region: "ap-east-1", Type: "sc1", PriceGB: 0.0198, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "ap-east-1", Type: "st1", PriceGB: 0.0594, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "ap-northeast-1": { - "gp2": {Region: "ap-northeast-1", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "ap-northeast-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "ap-northeast-1", Type: "io1", PriceGB: 0.142, PriceIOPS: 0.0740000000, IOPSConfigurable: true}, - "io2": {Region: "ap-northeast-1", Type: "io2", PriceGB: 0.142, PriceIOPS: 0, IOPSConfigurable: false}, - "sc1": {Region: "ap-northeast-1", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "ap-northeast-1", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "ap-northeast-1", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "ap-northeast-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0.0060000000, PriceThroughput: 0.049152, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "ap-northeast-1", Type: "io1", PriceGB: 0.142, PriceIOPS: 0.0740000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "io2": {Region: "ap-northeast-1", Type: "io2", PriceGB: 0.142, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "sc1": {Region: "ap-northeast-1", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "ap-northeast-1", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "ap-northeast-2": { - "gp2": {Region: "ap-northeast-2", Type: "gp2", PriceGB: 0.114, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "ap-northeast-2", Type: "gp3", PriceGB: 0.0912, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "ap-northeast-2", Type: "io1", PriceGB: 0.1278, PriceIOPS: 0.0666000000, IOPSConfigurable: true}, - "io2": {Region: "ap-northeast-2", Type: "io2", PriceGB: 0.1278, PriceIOPS: 0, IOPSConfigurable: false}, - "sc1": {Region: "ap-northeast-2", Type: "sc1", PriceGB: 0.0174, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "ap-northeast-2", Type: "st1", PriceGB: 0.051, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "ap-northeast-2", Type: "gp2", PriceGB: 0.114, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "ap-northeast-2", Type: "gp3", PriceGB: 0.0912, PriceIOPS: 0.0057000000, PriceThroughput: 0.046694400000000004, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "ap-northeast-2", Type: "io1", PriceGB: 0.1278, PriceIOPS: 0.0666000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "io2": {Region: "ap-northeast-2", Type: "io2", PriceGB: 0.1278, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "sc1": {Region: "ap-northeast-2", Type: "sc1", PriceGB: 0.0174, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "ap-northeast-2", Type: "st1", PriceGB: 0.051, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "ap-northeast-3": { - "gp2": {Region: "ap-northeast-3", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "ap-northeast-3", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "ap-northeast-3", Type: "io1", PriceGB: 0.142, PriceIOPS: 0.0740000000, IOPSConfigurable: true}, - "sc1": {Region: "ap-northeast-3", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "ap-northeast-3", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "ap-northeast-3", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "ap-northeast-3", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0.0060000000, PriceThroughput: 0.049152, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "ap-northeast-3", Type: "io1", PriceGB: 0.142, PriceIOPS: 0.0740000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "sc1": {Region: "ap-northeast-3", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "ap-northeast-3", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "ap-south-1": { - "gp2": {Region: "ap-south-1", Type: "gp2", PriceGB: 0.114, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "ap-south-1", Type: "gp3", PriceGB: 0.0912, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "ap-south-1", Type: "io1", PriceGB: 0.131, PriceIOPS: 0.0680000000, IOPSConfigurable: true}, - "io2": {Region: "ap-south-1", Type: "io2", PriceGB: 0.131, PriceIOPS: 0, IOPSConfigurable: false}, - "sc1": {Region: "ap-south-1", Type: "sc1", PriceGB: 0.0174, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "ap-south-1", Type: "st1", PriceGB: 0.051, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "ap-south-1", Type: "gp2", PriceGB: 0.114, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "ap-south-1", Type: "gp3", PriceGB: 0.0912, PriceIOPS: 0.0057000000, PriceThroughput: 0.046694400000000004, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "ap-south-1", Type: "io1", PriceGB: 0.131, PriceIOPS: 0.0680000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "io2": {Region: "ap-south-1", Type: "io2", PriceGB: 0.131, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "sc1": {Region: "ap-south-1", Type: "sc1", PriceGB: 0.0174, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "ap-south-1", Type: "st1", PriceGB: 0.051, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "ap-southeast-1": { - "gp2": {Region: "ap-southeast-1", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "ap-southeast-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "ap-southeast-1", Type: "io1", PriceGB: 0.138, PriceIOPS: 0.0720000000, IOPSConfigurable: true}, - "io2": {Region: "ap-southeast-1", Type: "io2", PriceGB: 0.138, PriceIOPS: 0, IOPSConfigurable: false}, - "sc1": {Region: "ap-southeast-1", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "ap-southeast-1", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "ap-southeast-1", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "ap-southeast-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0.0060000000, PriceThroughput: 0.049152, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "ap-southeast-1", Type: "io1", PriceGB: 0.138, PriceIOPS: 0.0720000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "io2": {Region: "ap-southeast-1", Type: "io2", PriceGB: 0.138, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "sc1": {Region: "ap-southeast-1", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "ap-southeast-1", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "ap-southeast-2": { - "gp2": {Region: "ap-southeast-2", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "ap-southeast-2", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "ap-southeast-2", Type: "io1", PriceGB: 0.138, PriceIOPS: 0.0720000000, IOPSConfigurable: true}, - "io2": {Region: "ap-southeast-2", Type: "io2", PriceGB: 0.138, PriceIOPS: 0, IOPSConfigurable: false}, - "sc1": {Region: "ap-southeast-2", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "ap-southeast-2", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "ap-southeast-2", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "ap-southeast-2", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0.0060000000, PriceThroughput: 0.049152, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "ap-southeast-2", Type: "io1", PriceGB: 0.138, PriceIOPS: 0.0720000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "io2": {Region: "ap-southeast-2", Type: "io2", PriceGB: 0.138, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "sc1": {Region: "ap-southeast-2", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "ap-southeast-2", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "ca-central-1": { - "gp2": {Region: "ca-central-1", Type: "gp2", PriceGB: 0.11, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "ca-central-1", Type: "gp3", PriceGB: 0.088, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "ca-central-1", Type: "io1", PriceGB: 0.138, PriceIOPS: 0.0720000000, IOPSConfigurable: true}, - "io2": {Region: "ca-central-1", Type: "io2", PriceGB: 0.138, PriceIOPS: 0, IOPSConfigurable: false}, - "sc1": {Region: "ca-central-1", Type: "sc1", PriceGB: 0.0168, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "ca-central-1", Type: "st1", PriceGB: 0.05, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "ca-central-1", Type: "gp2", PriceGB: 0.11, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "ca-central-1", Type: "gp3", PriceGB: 0.088, PriceIOPS: 0.0055000000, PriceThroughput: 0.045056, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "ca-central-1", Type: "io1", PriceGB: 0.138, PriceIOPS: 0.0720000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "io2": {Region: "ca-central-1", Type: "io2", PriceGB: 0.138, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "sc1": {Region: "ca-central-1", Type: "sc1", PriceGB: 0.0168, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "ca-central-1", Type: "st1", PriceGB: 0.05, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "eu-central-1": { - "gp2": {Region: "eu-central-1", Type: "gp2", PriceGB: 0.119, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "eu-central-1", Type: "gp3", PriceGB: 0.0952, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "eu-central-1", Type: "io1", PriceGB: 0.149, PriceIOPS: 0.0780000000, IOPSConfigurable: true}, - "io2": {Region: "eu-central-1", Type: "io2", PriceGB: 0.149, PriceIOPS: 0, IOPSConfigurable: false}, - "sc1": {Region: "eu-central-1", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "eu-central-1", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "eu-central-1", Type: "gp2", PriceGB: 0.119, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "eu-central-1", Type: "gp3", PriceGB: 0.0952, PriceIOPS: 0.0060000000, PriceThroughput: 0.048742400000000005, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "eu-central-1", Type: "io1", PriceGB: 0.149, PriceIOPS: 0.0780000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "io2": {Region: "eu-central-1", Type: "io2", PriceGB: 0.149, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "sc1": {Region: "eu-central-1", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "eu-central-1", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "eu-north-1": { - "gp2": {Region: "eu-north-1", Type: "gp2", PriceGB: 0.1045, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "eu-north-1", Type: "gp3", PriceGB: 0.0836, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "eu-north-1", Type: "io1", PriceGB: 0.1311, PriceIOPS: 0.0684000000, IOPSConfigurable: true}, - "io2": {Region: "eu-north-1", Type: "io2", PriceGB: 0.1311, PriceIOPS: 0, IOPSConfigurable: false}, - "sc1": {Region: "eu-north-1", Type: "sc1", PriceGB: 0.01596, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "eu-north-1", Type: "st1", PriceGB: 0.0475, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "eu-north-1", Type: "gp2", PriceGB: 0.1045, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "eu-north-1", Type: "gp3", PriceGB: 0.0836, PriceIOPS: 0.0052000000, PriceThroughput: 0.0428032, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "eu-north-1", Type: "io1", PriceGB: 0.1311, PriceIOPS: 0.0684000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "io2": {Region: "eu-north-1", Type: "io2", PriceGB: 0.1311, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "sc1": {Region: "eu-north-1", Type: "sc1", PriceGB: 0.01596, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "eu-north-1", Type: "st1", PriceGB: 0.0475, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "eu-south-1": { - "gp2": {Region: "eu-south-1", Type: "gp2", PriceGB: 0.1155, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "eu-south-1", Type: "gp3", PriceGB: 0.0924, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "eu-south-1", Type: "io1", PriceGB: 0.1449, PriceIOPS: 0.0756000000, IOPSConfigurable: true}, - "sc1": {Region: "eu-south-1", Type: "sc1", PriceGB: 0.01764, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "eu-south-1", Type: "st1", PriceGB: 0.0525, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "eu-south-1", Type: "gp2", PriceGB: 0.1155, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "eu-south-1", Type: "gp3", PriceGB: 0.0924, PriceIOPS: 0.0058000000, PriceThroughput: 0.0473088, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "eu-south-1", Type: "io1", PriceGB: 0.1449, PriceIOPS: 0.0756000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "sc1": {Region: "eu-south-1", Type: "sc1", PriceGB: 0.01764, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "eu-south-1", Type: "st1", PriceGB: 0.0525, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "eu-west-1": { - "gp2": {Region: "eu-west-1", Type: "gp2", PriceGB: 0.11, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "eu-west-1", Type: "gp3", PriceGB: 0.088, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "eu-west-1", Type: "io1", PriceGB: 0.138, PriceIOPS: 0.0720000000, IOPSConfigurable: true}, - "io2": {Region: "eu-west-1", Type: "io2", PriceGB: 0.138, PriceIOPS: 0, IOPSConfigurable: false}, - "sc1": {Region: "eu-west-1", Type: "sc1", PriceGB: 0.0168, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "eu-west-1", Type: "st1", PriceGB: 0.05, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "eu-west-1", Type: "gp2", PriceGB: 0.11, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "eu-west-1", Type: "gp3", PriceGB: 0.088, PriceIOPS: 0.0055000000, PriceThroughput: 0.045056, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "eu-west-1", Type: "io1", PriceGB: 0.138, PriceIOPS: 0.0720000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "io2": {Region: "eu-west-1", Type: "io2", PriceGB: 0.138, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "sc1": {Region: "eu-west-1", Type: "sc1", PriceGB: 0.0168, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "eu-west-1", Type: "st1", PriceGB: 0.05, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "eu-west-2": { - "gp2": {Region: "eu-west-2", Type: "gp2", PriceGB: 0.116, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "eu-west-2", Type: "gp3", PriceGB: 0.0928, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "eu-west-2", Type: "io1", PriceGB: 0.145, PriceIOPS: 0.0760000000, IOPSConfigurable: true}, - "io2": {Region: "eu-west-2", Type: "io2", PriceGB: 0.145, PriceIOPS: 0, IOPSConfigurable: false}, - "sc1": {Region: "eu-west-2", Type: "sc1", PriceGB: 0.0174, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "eu-west-2", Type: "st1", PriceGB: 0.053, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "eu-west-2", Type: "gp2", PriceGB: 0.116, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "eu-west-2", Type: "gp3", PriceGB: 0.0928, PriceIOPS: 0.0058000000, PriceThroughput: 0.047513599999999996, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "eu-west-2", Type: "io1", PriceGB: 0.145, PriceIOPS: 0.0760000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "io2": {Region: "eu-west-2", Type: "io2", PriceGB: 0.145, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "sc1": {Region: "eu-west-2", Type: "sc1", PriceGB: 0.0174, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "eu-west-2", Type: "st1", PriceGB: 0.053, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "eu-west-3": { - "gp2": {Region: "eu-west-3", Type: "gp2", PriceGB: 0.116, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "eu-west-3", Type: "gp3", PriceGB: 0.0928, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "eu-west-3", Type: "io1", PriceGB: 0.145, PriceIOPS: 0.0760000000, IOPSConfigurable: true}, - "sc1": {Region: "eu-west-3", Type: "sc1", PriceGB: 0.0174, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "eu-west-3", Type: "st1", PriceGB: 0.053, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "eu-west-3", Type: "gp2", PriceGB: 0.116, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "eu-west-3", Type: "gp3", PriceGB: 0.0928, PriceIOPS: 0.0058000000, PriceThroughput: 0.047513599999999996, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "eu-west-3", Type: "io1", PriceGB: 0.145, PriceIOPS: 0.0760000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "sc1": {Region: "eu-west-3", Type: "sc1", PriceGB: 0.0174, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "eu-west-3", Type: "st1", PriceGB: 0.053, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "me-south-1": { - "gp2": {Region: "me-south-1", Type: "gp2", PriceGB: 0.121, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "me-south-1", Type: "gp3", PriceGB: 0.0968, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "me-south-1", Type: "io1", PriceGB: 0.1518, PriceIOPS: 0.0792000000, IOPSConfigurable: true}, - "io2": {Region: "me-south-1", Type: "io2", PriceGB: 0.1518, PriceIOPS: 0, IOPSConfigurable: false}, - "sc1": {Region: "me-south-1", Type: "sc1", PriceGB: 0.01848, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "me-south-1", Type: "st1", PriceGB: 0.055, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "me-south-1", Type: "gp2", PriceGB: 0.121, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "me-south-1", Type: "gp3", PriceGB: 0.0968, PriceIOPS: 0.0061000000, PriceThroughput: 0.0495616, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "me-south-1", Type: "io1", PriceGB: 0.1518, PriceIOPS: 0.0792000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "io2": {Region: "me-south-1", Type: "io2", PriceGB: 0.1518, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "sc1": {Region: "me-south-1", Type: "sc1", PriceGB: 0.01848, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "me-south-1", Type: "st1", PriceGB: 0.055, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "sa-east-1": { - "gp2": {Region: "sa-east-1", Type: "gp2", PriceGB: 0.19, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "sa-east-1", Type: "gp3", PriceGB: 0.152, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "sa-east-1", Type: "io1", PriceGB: 0.238, PriceIOPS: 0.0910000000, IOPSConfigurable: true}, - "sc1": {Region: "sa-east-1", Type: "sc1", PriceGB: 0.0288, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "sa-east-1", Type: "st1", PriceGB: 0.086, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "sa-east-1", Type: "gp2", PriceGB: 0.19, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "sa-east-1", Type: "gp3", PriceGB: 0.152, PriceIOPS: 0.0095000000, PriceThroughput: 0.077824, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "sa-east-1", Type: "io1", PriceGB: 0.238, PriceIOPS: 0.0910000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "sc1": {Region: "sa-east-1", Type: "sc1", PriceGB: 0.0288, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "sa-east-1", Type: "st1", PriceGB: 0.086, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "us-east-1": { - "gp2": {Region: "us-east-1", Type: "gp2", PriceGB: 0.1, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "us-east-1", Type: "gp3", PriceGB: 0.08, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "us-east-1", Type: "io1", PriceGB: 0.125, PriceIOPS: 0.0650000000, IOPSConfigurable: true}, - "io2": {Region: "us-east-1", Type: "io2", PriceGB: 0.125, PriceIOPS: 0, IOPSConfigurable: false}, - "sc1": {Region: "us-east-1", Type: "sc1", PriceGB: 0.015, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "us-east-1", Type: "st1", PriceGB: 0.045, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "us-east-1", Type: "gp2", PriceGB: 0.1, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "us-east-1", Type: "gp3", PriceGB: 0.08, PriceIOPS: 0.0050000000, PriceThroughput: 0.04096, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "us-east-1", Type: "io1", PriceGB: 0.125, PriceIOPS: 0.0650000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "io2": {Region: "us-east-1", Type: "io2", PriceGB: 0.125, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "sc1": {Region: "us-east-1", Type: "sc1", PriceGB: 0.015, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "us-east-1", Type: "st1", PriceGB: 0.045, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "us-east-2": { - "gp2": {Region: "us-east-2", Type: "gp2", PriceGB: 0.1, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "us-east-2", Type: "gp3", PriceGB: 0.08, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "us-east-2", Type: "io1", PriceGB: 0.125, PriceIOPS: 0.0650000000, IOPSConfigurable: true}, - "io2": {Region: "us-east-2", Type: "io2", PriceGB: 0.125, PriceIOPS: 0, IOPSConfigurable: false}, - "sc1": {Region: "us-east-2", Type: "sc1", PriceGB: 0.015, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "us-east-2", Type: "st1", PriceGB: 0.045, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "us-east-2", Type: "gp2", PriceGB: 0.1, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "us-east-2", Type: "gp3", PriceGB: 0.08, PriceIOPS: 0.0050000000, PriceThroughput: 0.04096, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "us-east-2", Type: "io1", PriceGB: 0.125, PriceIOPS: 0.0650000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "io2": {Region: "us-east-2", Type: "io2", PriceGB: 0.125, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "sc1": {Region: "us-east-2", Type: "sc1", PriceGB: 0.015, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "us-east-2", Type: "st1", PriceGB: 0.045, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "us-gov-east-1": { - "gp2": {Region: "us-gov-east-1", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "us-gov-east-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "us-gov-east-1", Type: "io1", PriceGB: 0.15, PriceIOPS: 0.0780000000, IOPSConfigurable: true}, - "sc1": {Region: "us-gov-east-1", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "us-gov-east-1", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "us-gov-east-1", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "us-gov-east-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0.0060000000, PriceThroughput: 0.049152, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "us-gov-east-1", Type: "io1", PriceGB: 0.15, PriceIOPS: 0.0780000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "sc1": {Region: "us-gov-east-1", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "us-gov-east-1", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "us-gov-west-1": { - "gp2": {Region: "us-gov-west-1", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "us-gov-west-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "us-gov-west-1", Type: "io1", PriceGB: 0.15, PriceIOPS: 0.0780000000, IOPSConfigurable: true}, - "sc1": {Region: "us-gov-west-1", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "us-gov-west-1", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "us-gov-west-1", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "us-gov-west-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0.0060000000, PriceThroughput: 0.049152, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "us-gov-west-1", Type: "io1", PriceGB: 0.15, PriceIOPS: 0.0780000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "sc1": {Region: "us-gov-west-1", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "us-gov-west-1", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "us-west-1": { - "gp2": {Region: "us-west-1", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "us-west-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "us-west-1", Type: "io1", PriceGB: 0.138, PriceIOPS: 0.0720000000, IOPSConfigurable: true}, - "io2": {Region: "us-west-1", Type: "io2", PriceGB: 0.138, PriceIOPS: 0, IOPSConfigurable: false}, - "sc1": {Region: "us-west-1", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "us-west-1", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "us-west-1", Type: "gp2", PriceGB: 0.12, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "us-west-1", Type: "gp3", PriceGB: 0.096, PriceIOPS: 0.0060000000, PriceThroughput: 0.049152, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "us-west-1", Type: "io1", PriceGB: 0.138, PriceIOPS: 0.0720000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "io2": {Region: "us-west-1", Type: "io2", PriceGB: 0.138, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "sc1": {Region: "us-west-1", Type: "sc1", PriceGB: 0.018, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "us-west-1", Type: "st1", PriceGB: 0.054, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, "us-west-2": { - "gp2": {Region: "us-west-2", Type: "gp2", PriceGB: 0.1, PriceIOPS: 0, IOPSConfigurable: false}, - "gp3": {Region: "us-west-2", Type: "gp3", PriceGB: 0.08, PriceIOPS: 0, IOPSConfigurable: true}, - "io1": {Region: "us-west-2", Type: "io1", PriceGB: 0.125, PriceIOPS: 0.0650000000, IOPSConfigurable: true}, - "io2": {Region: "us-west-2", Type: "io2", PriceGB: 0.125, PriceIOPS: 0, IOPSConfigurable: false}, - "sc1": {Region: "us-west-2", Type: "sc1", PriceGB: 0.015, PriceIOPS: 0, IOPSConfigurable: false}, - "st1": {Region: "us-west-2", Type: "st1", PriceGB: 0.045, PriceIOPS: 0, IOPSConfigurable: false}, + "gp2": {Region: "us-west-2", Type: "gp2", PriceGB: 0.1, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "gp3": {Region: "us-west-2", Type: "gp3", PriceGB: 0.08, PriceIOPS: 0.0050000000, PriceThroughput: 0.04096, IOPSConfigurable: true, ThroughputConfigurable: true}, + "io1": {Region: "us-west-2", Type: "io1", PriceGB: 0.125, PriceIOPS: 0.0650000000, PriceThroughput: 0, IOPSConfigurable: true, ThroughputConfigurable: false}, + "io2": {Region: "us-west-2", Type: "io2", PriceGB: 0.125, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "sc1": {Region: "us-west-2", Type: "sc1", PriceGB: 0.015, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, + "st1": {Region: "us-west-2", Type: "st1", PriceGB: 0.045, PriceIOPS: 0, PriceThroughput: 0, IOPSConfigurable: false, ThroughputConfigurable: false}, }, } diff --git a/pkg/operator/operator/cron.go b/pkg/operator/operator/cron.go index 4047ea7e6f..6e174436da 100644 --- a/pkg/operator/operator/cron.go +++ b/pkg/operator/operator/cron.go @@ -184,9 +184,13 @@ func getEBSPriceForNodeGroupInstance(ngs []*clusterconfig.NodeGroup, ngName stri } if ng.Name == ngNamePrefix+ngName { ebsPrice = aws.EBSMetadatas[config.CoreConfig.Region][ng.InstanceVolumeType.String()].PriceGB * float64(ng.InstanceVolumeSize) / 30 / 24 - if ng.InstanceVolumeType.String() == "io1" && ng.InstanceVolumeIOPS != nil { + if ng.InstanceVolumeType == clusterconfig.IO1VolumeType && ng.InstanceVolumeIOPS != nil { ebsPrice += aws.EBSMetadatas[config.CoreConfig.Region][ng.InstanceVolumeType.String()].PriceIOPS * float64(*ng.InstanceVolumeIOPS) / 30 / 24 } + if ng.InstanceVolumeType == clusterconfig.GP3VolumeType && ng.InstanceVolumeIOPS != nil && ng.InstanceVolumeThroughput != nil { + ebsPrice += aws.EBSMetadatas[config.CoreConfig.Region][ng.InstanceVolumeType.String()].PriceIOPS * float64(*ng.InstanceVolumeIOPS) / 30 / 24 + ebsPrice += aws.EBSMetadatas[config.CoreConfig.Region][ng.InstanceVolumeType.String()].PriceThroughput * float64(*ng.InstanceVolumeThroughput) / 30 / 24 + } break } } From c94336814dc0601a678aa4a513faf7e1052533db Mon Sep 17 00:00:00 2001 From: Robert Lucian Chiriac Date: Thu, 29 Apr 2021 22:54:21 +0300 Subject: [PATCH 10/13] Fixes --- pkg/types/clusterconfig/cluster_config.go | 4 ++-- pkg/types/clusterconfig/errors.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/types/clusterconfig/cluster_config.go b/pkg/types/clusterconfig/cluster_config.go index e100307f45..7ede61d8e5 100644 --- a/pkg/types/clusterconfig/cluster_config.go +++ b/pkg/types/clusterconfig/cluster_config.go @@ -985,8 +985,8 @@ func (ng *NodeGroup) validateNodeGroup(awsClient *aws.Client, region string) err return ErrorIOPSToVolumeSizeRatio(ng.InstanceVolumeType, _maxIOPSToVolumeSizeRatioForGP3, *ng.InstanceVolumeIOPS, ng.InstanceVolumeSize) } iopsToThroughputRatio := float64(*ng.InstanceVolumeIOPS) / float64(*ng.InstanceVolumeThroughput) - if iopsToThroughputRatio > float64(_maxIOPSToThroughputRatioForGP3) { - return ErrorIOPSToThroughputRatio(ng.InstanceVolumeType, iopsToThroughputRatio, *ng.InstanceVolumeIOPS, *ng.InstanceVolumeThroughput) + if iopsToThroughputRatio < float64(_maxIOPSToThroughputRatioForGP3) { + return ErrorIOPSToThroughputRatio(ng.InstanceVolumeType, _maxIOPSToThroughputRatioForGP3, *ng.InstanceVolumeIOPS, *ng.InstanceVolumeThroughput) } } } else if ng.InstanceVolumeType == GP3VolumeType && aws.EBSMetadatas[region][ng.InstanceVolumeType.String()].IOPSConfigurable { diff --git a/pkg/types/clusterconfig/errors.go b/pkg/types/clusterconfig/errors.go index 46f51c8154..f80bb0c01c 100644 --- a/pkg/types/clusterconfig/errors.go +++ b/pkg/types/clusterconfig/errors.go @@ -373,10 +373,10 @@ func ErrorIOPSToVolumeSizeRatio(volumeType VolumeType, ratio, iops int64, volume }) } -func ErrorIOPSToThroughputRatio(volumeType VolumeType, ratio float64, throughput int64, iops int64) error { +func ErrorIOPSToThroughputRatio(volumeType VolumeType, ratio, throughput int64, iops int64) error { return errors.WithStack(&errors.Error{ Kind: ErrIOPSToThroughputRatio, - Message: fmt.Sprintf("for %s volume type, %s (%d) cannot be more than %f times larger than %s (%d); increase `%s` or decrease `%s` in your cluster configuration file", volumeType, InstanceVolumeIOPSKey, iops, ratio, InstanceVolumeThroughputKey, throughput, InstanceVolumeThroughputKey, InstanceVolumeIOPSKey), + Message: fmt.Sprintf("for %s volume type, %s (%d) cannot be less than %d times smaller than %s (%d); increase `%s` or decrease `%s` in your cluster configuration file", volumeType, InstanceVolumeIOPSKey, iops, ratio, InstanceVolumeThroughputKey, throughput, InstanceVolumeThroughputKey, InstanceVolumeIOPSKey), }) } From 8d2c0ec733a165a0cb1b3c331f622dc8c572dfd4 Mon Sep 17 00:00:00 2001 From: Robert Lucian Chiriac Date: Thu, 29 Apr 2021 23:07:27 +0300 Subject: [PATCH 11/13] Further pricing fixes --- cli/cmd/cluster.go | 7 ++++--- cli/cmd/lib_cluster_config.go | 7 ++++--- pkg/operator/operator/cron.go | 5 +++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/cli/cmd/cluster.go b/cli/cmd/cluster.go index 06463332ca..27c878854a 100644 --- a/cli/cmd/cluster.go +++ b/cli/cmd/cluster.go @@ -39,6 +39,7 @@ import ( "github.com/cortexlabs/cortex/pkg/lib/exit" "github.com/cortexlabs/cortex/pkg/lib/files" libjson "github.com/cortexlabs/cortex/pkg/lib/json" + libmath "github.com/cortexlabs/cortex/pkg/lib/math" "github.com/cortexlabs/cortex/pkg/lib/pointer" "github.com/cortexlabs/cortex/pkg/lib/prompt" s "github.com/cortexlabs/cortex/pkg/lib/strings" @@ -815,8 +816,8 @@ func printInfoPricing(infoResponse *schema.InfoResponse, clusterConfig clusterco ebsPrice += aws.EBSMetadatas[clusterConfig.Region][ng.InstanceVolumeType.String()].PriceIOPS * float64(*ng.InstanceVolumeIOPS) / 30 / 24 } if ng.InstanceVolumeType == clusterconfig.GP3VolumeType && ng.InstanceVolumeIOPS != nil && ng.InstanceVolumeThroughput != nil { - ebsPrice += aws.EBSMetadatas[clusterConfig.Region][ng.InstanceVolumeType.String()].PriceIOPS * float64(*ng.InstanceVolumeIOPS) / 30 / 24 - ebsPrice += aws.EBSMetadatas[clusterConfig.Region][ng.InstanceVolumeType.String()].PriceThroughput * float64(*ng.InstanceVolumeThroughput) / 30 / 24 + ebsPrice += libmath.MaxFloat64(0, (aws.EBSMetadatas[clusterConfig.Region][ng.InstanceVolumeType.String()].PriceIOPS-3000)*float64(*ng.InstanceVolumeIOPS)/30/24) + ebsPrice += libmath.MaxFloat64(0, (aws.EBSMetadatas[clusterConfig.Region][ng.InstanceVolumeType.String()].PriceThroughput-125)*float64(*ng.InstanceVolumeThroughput)/30/24) } totalEBSPrice := ebsPrice * float64(numInstances) @@ -842,7 +843,7 @@ func printInfoPricing(infoResponse *schema.InfoResponse, clusterConfig clusterco rows = append(rows, []interface{}{"2 t3.medium instances for cortex", s.DollarsMaxPrecision(operatorInstancePrice * 2)}) rows = append(rows, []interface{}{"1 20gb ebs volume for the operator", s.DollarsAndTenthsOfCents(operatorEBSPrice)}) - rows = append(rows, []interface{}{"1 40gb ebs volume for prometheus", s.DollarsAndTenthsOfCents(metricsEBSPrice)}) + rows = append(rows, []interface{}{"1 40+2gb ebs volumes for metrics (prometheus and grafana)", s.DollarsAndTenthsOfCents(metricsEBSPrice)}) rows = append(rows, []interface{}{"2 network load balancers", s.DollarsMaxPrecision(nlbPrice*2) + " total"}) if clusterConfig.NATGateway == clusterconfig.SingleNATGateway { diff --git a/cli/cmd/lib_cluster_config.go b/cli/cmd/lib_cluster_config.go index 7534b56824..d2732acd49 100644 --- a/cli/cmd/lib_cluster_config.go +++ b/cli/cmd/lib_cluster_config.go @@ -28,6 +28,7 @@ import ( "github.com/cortexlabs/cortex/pkg/lib/errors" "github.com/cortexlabs/cortex/pkg/lib/files" "github.com/cortexlabs/cortex/pkg/lib/maps" + libmath "github.com/cortexlabs/cortex/pkg/lib/math" "github.com/cortexlabs/cortex/pkg/lib/pointer" "github.com/cortexlabs/cortex/pkg/lib/prompt" s "github.com/cortexlabs/cortex/pkg/lib/strings" @@ -180,8 +181,8 @@ func confirmInstallClusterConfig(clusterConfig *clusterconfig.Config, awsClient apiEBSPrice += aws.EBSMetadatas[clusterConfig.Region][ng.InstanceVolumeType.String()].PriceIOPS * float64(*ng.InstanceVolumeIOPS) / 30 / 24 } if ng.InstanceVolumeType == clusterconfig.GP3VolumeType && ng.InstanceVolumeIOPS != nil && ng.InstanceVolumeThroughput != nil { - apiEBSPrice += aws.EBSMetadatas[clusterConfig.Region][ng.InstanceVolumeType.String()].PriceIOPS * float64(*ng.InstanceVolumeIOPS) / 30 / 24 - apiEBSPrice += aws.EBSMetadatas[clusterConfig.Region][ng.InstanceVolumeType.String()].PriceThroughput * float64(*ng.InstanceVolumeThroughput) / 30 / 24 + apiEBSPrice += libmath.MaxFloat64(0, (aws.EBSMetadatas[clusterConfig.Region][ng.InstanceVolumeType.String()].PriceIOPS-3000)*float64(*ng.InstanceVolumeIOPS)/30/24) + apiEBSPrice += libmath.MaxFloat64(0, (aws.EBSMetadatas[clusterConfig.Region][ng.InstanceVolumeType.String()].PriceThroughput-125)*float64(*ng.InstanceVolumeThroughput)/30/24) } totalMinPrice += float64(ng.MinInstances) * (apiInstancePrice + apiEBSPrice) @@ -217,7 +218,7 @@ func confirmInstallClusterConfig(clusterConfig *clusterconfig.Config, awsClient rows = append(rows, []interface{}{"2 t3.medium instances for cortex", s.DollarsMaxPrecision(operatorInstancePrice * 2)}) rows = append(rows, []interface{}{"1 20gb ebs volume for the operator", s.DollarsAndTenthsOfCents(operatorEBSPrice)}) - rows = append(rows, []interface{}{"1 40gb ebs volume for prometheus", s.DollarsAndTenthsOfCents(metricsEBSPrice)}) + rows = append(rows, []interface{}{"1 40+2gb ebs volumes for metrics (prometheus and grafana)", s.DollarsAndTenthsOfCents(metricsEBSPrice)}) rows = append(rows, []interface{}{"2 network load balancers", s.DollarsMaxPrecision(nlbPrice) + " each"}) if clusterConfig.NATGateway == clusterconfig.SingleNATGateway { diff --git a/pkg/operator/operator/cron.go b/pkg/operator/operator/cron.go index 6e174436da..223b8f409e 100644 --- a/pkg/operator/operator/cron.go +++ b/pkg/operator/operator/cron.go @@ -22,6 +22,7 @@ import ( "github.com/cortexlabs/cortex/pkg/lib/aws" "github.com/cortexlabs/cortex/pkg/lib/errors" "github.com/cortexlabs/cortex/pkg/lib/k8s" + libmath "github.com/cortexlabs/cortex/pkg/lib/math" "github.com/cortexlabs/cortex/pkg/lib/sets/strset" "github.com/cortexlabs/cortex/pkg/lib/telemetry" "github.com/cortexlabs/cortex/pkg/operator/config" @@ -188,8 +189,8 @@ func getEBSPriceForNodeGroupInstance(ngs []*clusterconfig.NodeGroup, ngName stri ebsPrice += aws.EBSMetadatas[config.CoreConfig.Region][ng.InstanceVolumeType.String()].PriceIOPS * float64(*ng.InstanceVolumeIOPS) / 30 / 24 } if ng.InstanceVolumeType == clusterconfig.GP3VolumeType && ng.InstanceVolumeIOPS != nil && ng.InstanceVolumeThroughput != nil { - ebsPrice += aws.EBSMetadatas[config.CoreConfig.Region][ng.InstanceVolumeType.String()].PriceIOPS * float64(*ng.InstanceVolumeIOPS) / 30 / 24 - ebsPrice += aws.EBSMetadatas[config.CoreConfig.Region][ng.InstanceVolumeType.String()].PriceThroughput * float64(*ng.InstanceVolumeThroughput) / 30 / 24 + ebsPrice += libmath.MaxFloat64(0, (aws.EBSMetadatas[config.CoreConfig.Region][ng.InstanceVolumeType.String()].PriceIOPS-3000)*float64(*ng.InstanceVolumeIOPS)/30/24) + ebsPrice += libmath.MaxFloat64(0, (aws.EBSMetadatas[config.CoreConfig.Region][ng.InstanceVolumeType.String()].PriceThroughput-125)*float64(*ng.InstanceVolumeThroughput)/30/24) } break } From 666eaef84af8479c1e392205fa639004b725c482 Mon Sep 17 00:00:00 2001 From: Robert Lucian Chiriac Date: Fri, 30 Apr 2021 00:49:37 +0300 Subject: [PATCH 12/13] Further cortex cluster info fixes --- cli/cmd/cluster.go | 2 +- cli/cmd/lib_cluster_config.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/cmd/cluster.go b/cli/cmd/cluster.go index 27c878854a..8a2e3ba1f0 100644 --- a/cli/cmd/cluster.go +++ b/cli/cmd/cluster.go @@ -842,7 +842,7 @@ func printInfoPricing(infoResponse *schema.InfoResponse, clusterConfig clusterco fmt.Printf(console.Bold("\nyour cluster currently costs %s per hour\n\n"), s.DollarsAndCents(totalPrice)) rows = append(rows, []interface{}{"2 t3.medium instances for cortex", s.DollarsMaxPrecision(operatorInstancePrice * 2)}) - rows = append(rows, []interface{}{"1 20gb ebs volume for the operator", s.DollarsAndTenthsOfCents(operatorEBSPrice)}) + rows = append(rows, []interface{}{"2 20gb ebs volumes for the operator", s.DollarsAndTenthsOfCents(operatorEBSPrice * 2)}) rows = append(rows, []interface{}{"1 40+2gb ebs volumes for metrics (prometheus and grafana)", s.DollarsAndTenthsOfCents(metricsEBSPrice)}) rows = append(rows, []interface{}{"2 network load balancers", s.DollarsMaxPrecision(nlbPrice*2) + " total"}) diff --git a/cli/cmd/lib_cluster_config.go b/cli/cmd/lib_cluster_config.go index d2732acd49..2f4c8df22b 100644 --- a/cli/cmd/lib_cluster_config.go +++ b/cli/cmd/lib_cluster_config.go @@ -217,7 +217,7 @@ func confirmInstallClusterConfig(clusterConfig *clusterconfig.Config, awsClient } rows = append(rows, []interface{}{"2 t3.medium instances for cortex", s.DollarsMaxPrecision(operatorInstancePrice * 2)}) - rows = append(rows, []interface{}{"1 20gb ebs volume for the operator", s.DollarsAndTenthsOfCents(operatorEBSPrice)}) + rows = append(rows, []interface{}{"2 20gb ebs volumes for the operator", s.DollarsAndTenthsOfCents(operatorEBSPrice * 2)}) rows = append(rows, []interface{}{"1 40+2gb ebs volumes for metrics (prometheus and grafana)", s.DollarsAndTenthsOfCents(metricsEBSPrice)}) rows = append(rows, []interface{}{"2 network load balancers", s.DollarsMaxPrecision(nlbPrice) + " each"}) From cb7cf2809d10700518b57a93eac43ad442c2b58c Mon Sep 17 00:00:00 2001 From: Robert Lucian Chiriac Date: Fri, 30 Apr 2021 03:20:07 +0300 Subject: [PATCH 13/13] Address PR comments --- pkg/lib/aws/gen_resource_metadata.py | 4 ++-- pkg/types/clusterconfig/cluster_config.go | 10 +++++----- pkg/types/clusterconfig/errors.go | 12 +++--------- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/pkg/lib/aws/gen_resource_metadata.py b/pkg/lib/aws/gen_resource_metadata.py index 84c7197bf2..9e74ed739d 100644 --- a/pkg/lib/aws/gen_resource_metadata.py +++ b/pkg/lib/aws/gen_resource_metadata.py @@ -301,9 +301,9 @@ def get_eks_price(region): Region string `json:"region"` PriceGB float64 `json:"price_gb"` PriceIOPS float64 `json:"price_iops"` - PriceThroughput float64 `json:"price_throughput"` + PriceThroughput float64 `json:"price_throughput"` IOPSConfigurable bool `json:"iops_configurable"` - ThroughputConfigurable bool `json:"throughput_configurable"` + ThroughputConfigurable bool `json:"throughput_configurable"` Type string `json:"type"` } diff --git a/pkg/types/clusterconfig/cluster_config.go b/pkg/types/clusterconfig/cluster_config.go index 7ede61d8e5..5bcf323a41 100644 --- a/pkg/types/clusterconfig/cluster_config.go +++ b/pkg/types/clusterconfig/cluster_config.go @@ -68,7 +68,7 @@ var ( _maxIOPSToVolumeSizeRatioForIO1 = int64(50) _maxIOPSToVolumeSizeRatioForGP3 = int64(500) - _maxIOPSToThroughputRatioForGP3 = int64(4) + _minIOPSToThroughputRatioForGP3 = int64(4) // This regex is stricter than the actual S3 rules _strictS3BucketRegex = regexp.MustCompile(`^([a-z0-9])+(-[a-z0-9]+)*$`) @@ -985,14 +985,14 @@ func (ng *NodeGroup) validateNodeGroup(awsClient *aws.Client, region string) err return ErrorIOPSToVolumeSizeRatio(ng.InstanceVolumeType, _maxIOPSToVolumeSizeRatioForGP3, *ng.InstanceVolumeIOPS, ng.InstanceVolumeSize) } iopsToThroughputRatio := float64(*ng.InstanceVolumeIOPS) / float64(*ng.InstanceVolumeThroughput) - if iopsToThroughputRatio < float64(_maxIOPSToThroughputRatioForGP3) { - return ErrorIOPSToThroughputRatio(ng.InstanceVolumeType, _maxIOPSToThroughputRatioForGP3, *ng.InstanceVolumeIOPS, *ng.InstanceVolumeThroughput) + if iopsToThroughputRatio < float64(_minIOPSToThroughputRatioForGP3) { + return ErrorIOPSToThroughputRatio(ng.InstanceVolumeType, _minIOPSToThroughputRatioForGP3, *ng.InstanceVolumeIOPS, *ng.InstanceVolumeThroughput) } } - } else if ng.InstanceVolumeType == GP3VolumeType && aws.EBSMetadatas[region][ng.InstanceVolumeType.String()].IOPSConfigurable { + } else if ng.InstanceVolumeType == GP3VolumeType { ng.InstanceVolumeIOPS = pointer.Int64(3000) ng.InstanceVolumeThroughput = pointer.Int64(125) - } else if ng.InstanceVolumeType == IO1VolumeType && aws.EBSMetadatas[region][ng.InstanceVolumeType.String()].IOPSConfigurable { + } else if ng.InstanceVolumeType == IO1VolumeType { ng.InstanceVolumeIOPS = pointer.Int64(libmath.MinInt64(ng.InstanceVolumeSize*_maxIOPSToVolumeSizeRatioForIO1, 3000)) } diff --git a/pkg/types/clusterconfig/errors.go b/pkg/types/clusterconfig/errors.go index f80bb0c01c..dc22215fbd 100644 --- a/pkg/types/clusterconfig/errors.go +++ b/pkg/types/clusterconfig/errors.go @@ -284,15 +284,9 @@ func ErrorSpecifyOneOrNone(fieldName1 string, fieldName2 string, fieldNames ...s func ErrorSpecifyTwoOrNone(fieldName1 string, fieldName2 string, fieldNames ...string) error { fieldNames = append([]string{fieldName1, fieldName2}, fieldNames...) - - message := fmt.Sprintf("specify exactly two or none of the following fields: %s", s.StrsAnd(fieldNames)) - if len(fieldNames) == 1 { - message = fmt.Sprintf("cannot have a single field (%s) to choose from)", fieldNames[0]) - } - return errors.WithStack(&errors.Error{ Kind: ErrSpecifyTwoOrNone, - Message: message, + Message: fmt.Sprintf("specify exactly two or none of the following fields: %s", s.StrsAnd(fieldNames)), }) } @@ -373,10 +367,10 @@ func ErrorIOPSToVolumeSizeRatio(volumeType VolumeType, ratio, iops int64, volume }) } -func ErrorIOPSToThroughputRatio(volumeType VolumeType, ratio, throughput int64, iops int64) error { +func ErrorIOPSToThroughputRatio(volumeType VolumeType, ratio, iops, throughput int64) error { return errors.WithStack(&errors.Error{ Kind: ErrIOPSToThroughputRatio, - Message: fmt.Sprintf("for %s volume type, %s (%d) cannot be less than %d times smaller than %s (%d); increase `%s` or decrease `%s` in your cluster configuration file", volumeType, InstanceVolumeIOPSKey, iops, ratio, InstanceVolumeThroughputKey, throughput, InstanceVolumeThroughputKey, InstanceVolumeIOPSKey), + Message: fmt.Sprintf("for %s volume type, %s (%d) must be at least %d times larger than %s (%d); decrease `%s` or increase `%s` in your cluster configuration file", volumeType, InstanceVolumeIOPSKey, iops, ratio, InstanceVolumeThroughputKey, throughput, InstanceVolumeThroughputKey, InstanceVolumeIOPSKey), }) }