mirror of https://github.com/kubernetes/kops.git
Merge pull request #8856 from rifelpet/machine-types-2
Use ec2.DescribeInstanceTypes for machine type info
This commit is contained in:
commit
d5b8e6c90f
7
Makefile
7
Makefile
|
|
@ -829,13 +829,6 @@ build-docs-netlify:
|
|||
pip install -r ${KOPS_ROOT}/images/mkdocs/requirements.txt
|
||||
mkdocs build
|
||||
|
||||
# Update machine_types.go
|
||||
.PHONY: update-machine-types
|
||||
update-machine-types:
|
||||
go build -o hack/machine_types/machine_types ${KOPS_ROOT}/hack/machine_types/
|
||||
hack/machine_types/machine_types --out upup/pkg/fi/cloudup/awsup/machine_types.go
|
||||
go fmt upup/pkg/fi/cloudup/awsup/machine_types.go
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# development targets
|
||||
|
||||
|
|
|
|||
|
|
@ -49,3 +49,8 @@ func (m *MockEC2) DescribeInstancesPages(request *ec2.DescribeInstancesInput, ca
|
|||
func (m *MockEC2) DescribeInstancesPagesWithContext(aws.Context, *ec2.DescribeInstancesInput, func(*ec2.DescribeInstancesOutput, bool) bool, ...request.Option) error {
|
||||
panic("Not implemented")
|
||||
}
|
||||
|
||||
func (m *MockEC2) DescribeInstanceTypes(*ec2.DescribeInstanceTypesInput) (*ec2.DescribeInstanceTypesOutput, error) {
|
||||
klog.Warningf("MockEc2::DescribeInstanceTypes is stub-implemented")
|
||||
return &ec2.DescribeInstanceTypesOutput{}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1231,7 +1231,7 @@ func RunCreateCluster(ctx context.Context, f *util.Factory, out io.Writer, c *Cr
|
|||
}
|
||||
|
||||
strict := false
|
||||
err = validation.DeepValidate(cluster, instanceGroups, strict)
|
||||
err = validation.DeepValidate(cluster, instanceGroups, strict, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -1255,7 +1255,7 @@ func RunCreateCluster(ctx context.Context, f *util.Factory, out io.Writer, c *Cr
|
|||
fullInstanceGroups = append(fullInstanceGroups, fullGroup)
|
||||
}
|
||||
|
||||
err = validation.DeepValidate(fullCluster, fullInstanceGroups, true)
|
||||
err = validation.DeepValidate(fullCluster, fullInstanceGroups, true, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -228,7 +228,12 @@ func RunCreateInstanceGroup(ctx context.Context, f *util.Factory, cmd *cobra.Com
|
|||
return fmt.Errorf("unexpected object type: %T", obj)
|
||||
}
|
||||
|
||||
err = validation.CrossValidateInstanceGroup(group, cluster).ToAggregate()
|
||||
cloud, err := cloudup.BuildCloud(cluster)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = validation.CrossValidateInstanceGroup(group, cluster, cloud).ToAggregate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -222,7 +222,12 @@ func RunEditCluster(ctx context.Context, f *util.Factory, cmd *cobra.Command, ar
|
|||
continue
|
||||
}
|
||||
|
||||
err = validation.DeepValidate(fullCluster, instanceGroups, true)
|
||||
cloud, err := cloudup.BuildCloud(fullCluster)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = validation.DeepValidate(fullCluster, instanceGroups, true, cloud)
|
||||
if err != nil {
|
||||
results = editResults{
|
||||
file: file,
|
||||
|
|
|
|||
|
|
@ -173,7 +173,12 @@ func RunEditInstanceGroup(ctx context.Context, f *util.Factory, cmd *cobra.Comma
|
|||
return err
|
||||
}
|
||||
|
||||
err = validation.CrossValidateInstanceGroup(fullGroup, fullCluster).ToAggregate()
|
||||
cloud, err := cloudup.BuildCloud(fullCluster)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = validation.CrossValidateInstanceGroup(fullGroup, fullCluster, cloud).ToAggregate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
# Significant changes
|
||||
|
||||
* Clusters using the Amazon VPC CNI provider now perform an `ec2.DescribeInstanceTypes` call at instance launch time. In large clusters or AWS accounts this may lead to API throttling which could delay node readiness. If this becomes a problem please open a GitHub issue.
|
||||
|
||||
# Breaking changes
|
||||
|
||||
* Support for Kubernetes 1.9 and 1.10 has been removed.
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ k8s.io/kops/dnsprovider/pkg/dnsprovider/providers/openstack/designate
|
|||
k8s.io/kops/dnsprovider/pkg/dnsprovider/rrstype
|
||||
k8s.io/kops/dnsprovider/pkg/dnsprovider/tests
|
||||
k8s.io/kops/examples/kops-api-example
|
||||
k8s.io/kops/hack/machine_types
|
||||
k8s.io/kops/kube-discovery/cmd/kube-discovery
|
||||
k8s.io/kops/node-authorizer/cmd/node-authorizer
|
||||
k8s.io/kops/node-authorizer/pkg/authorizers/alwaysallow
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
machine_types
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["machine_types.go"],
|
||||
importpath = "k8s.io/kops/hack/machine_types",
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
"//upup/pkg/fi/cloudup/awsup:go_default_library",
|
||||
"//vendor/github.com/aws/aws-sdk-go/aws:go_default_library",
|
||||
"//vendor/github.com/aws/aws-sdk-go/aws/session:go_default_library",
|
||||
"//vendor/github.com/aws/aws-sdk-go/service/ec2:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_binary(
|
||||
name = "machinetypes",
|
||||
embed = [":go_default_library"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
Machine Types Generator
|
||||
=======================
|
||||
|
||||
To prevent errors or lagging updates, we use this generator to update the known aws machine types
|
||||
that are [hard coded in kops](https://github.com/kubernetes/kops/blob/7d7112c1e9a52d4f677db6bd98943d308ec9f581/upup/pkg/fi/cloudup/awsup/machine_types.go#L76).
|
||||
|
||||
This generator uses the AWS Pricing API to get most of it's info on what instance types are supported.
|
||||
|
||||
Usage
|
||||
-----
|
||||
```
|
||||
make update-machine-types
|
||||
git add .
|
||||
git commit -am "Updated machine types"
|
||||
```
|
||||
|
||||
TODO:
|
||||
-----
|
||||
* Cross reference other regions besides us-east-1. Currently we just look at one region to determine instance types.
|
||||
|
|
@ -1,328 +0,0 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
|
||||
)
|
||||
|
||||
var outputPath = ""
|
||||
|
||||
func main() {
|
||||
flag.StringVar(&outputPath, "out", outputPath, "file to write")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if err := run(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func run() error {
|
||||
if outputPath == "" {
|
||||
return fmt.Errorf("must specify output file with --out")
|
||||
}
|
||||
|
||||
klog.Info("Beginning AWS Machine Refresh")
|
||||
|
||||
// These are instance types not available in every account
|
||||
// If they're not available, they wont be in the ec2.DescribeInstanceTypes response
|
||||
// so they are hardcoded here for reference.
|
||||
// Note that the m6g instances do not have ENI or IP information
|
||||
machines := []awsup.AWSMachineTypeInfo{
|
||||
{
|
||||
Name: "cr1.8xlarge",
|
||||
MemoryGB: 244,
|
||||
Cores: 32,
|
||||
InstanceENIs: 8,
|
||||
InstanceIPsPerENI: 30,
|
||||
EphemeralDisks: []int{120, 120},
|
||||
},
|
||||
{
|
||||
Name: "hs1.8xlarge",
|
||||
MemoryGB: 117,
|
||||
Cores: 16,
|
||||
InstanceENIs: 8,
|
||||
InstanceIPsPerENI: 30,
|
||||
EphemeralDisks: []int{2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000},
|
||||
},
|
||||
{
|
||||
Name: "m6g.medium",
|
||||
MemoryGB: 4,
|
||||
Cores: 1,
|
||||
InstanceENIs: 0,
|
||||
InstanceIPsPerENI: 0,
|
||||
EphemeralDisks: nil,
|
||||
},
|
||||
|
||||
{
|
||||
Name: "m6g.large",
|
||||
MemoryGB: 8,
|
||||
Cores: 2,
|
||||
InstanceENIs: 0,
|
||||
InstanceIPsPerENI: 0,
|
||||
EphemeralDisks: nil,
|
||||
},
|
||||
|
||||
{
|
||||
Name: "m6g.xlarge",
|
||||
MemoryGB: 16,
|
||||
Cores: 4,
|
||||
InstanceENIs: 0,
|
||||
InstanceIPsPerENI: 0,
|
||||
EphemeralDisks: nil,
|
||||
},
|
||||
|
||||
{
|
||||
Name: "m6g.2xlarge",
|
||||
MemoryGB: 32,
|
||||
Cores: 8,
|
||||
InstanceENIs: 0,
|
||||
InstanceIPsPerENI: 0,
|
||||
EphemeralDisks: nil,
|
||||
},
|
||||
|
||||
{
|
||||
Name: "m6g.4xlarge",
|
||||
MemoryGB: 64,
|
||||
Cores: 16,
|
||||
InstanceENIs: 0,
|
||||
InstanceIPsPerENI: 0,
|
||||
EphemeralDisks: nil,
|
||||
},
|
||||
|
||||
{
|
||||
Name: "m6g.8xlarge",
|
||||
MemoryGB: 128,
|
||||
Cores: 32,
|
||||
InstanceENIs: 0,
|
||||
InstanceIPsPerENI: 0,
|
||||
EphemeralDisks: nil,
|
||||
},
|
||||
|
||||
{
|
||||
Name: "m6g.12xlarge",
|
||||
MemoryGB: 192,
|
||||
Cores: 48,
|
||||
InstanceENIs: 0,
|
||||
InstanceIPsPerENI: 0,
|
||||
EphemeralDisks: nil,
|
||||
},
|
||||
|
||||
{
|
||||
Name: "m6g.16xlarge",
|
||||
MemoryGB: 256,
|
||||
Cores: 64,
|
||||
InstanceENIs: 0,
|
||||
InstanceIPsPerENI: 0,
|
||||
EphemeralDisks: nil,
|
||||
},
|
||||
}
|
||||
families := map[string]struct{}{
|
||||
"cr1": {},
|
||||
"hs1": {},
|
||||
"m6g": {},
|
||||
}
|
||||
|
||||
config := aws.NewConfig()
|
||||
// Give verbose errors on auth problems
|
||||
config = config.WithCredentialsChainVerboseErrors(true)
|
||||
// Default to us-east-1
|
||||
config = config.WithRegion("us-east-1")
|
||||
|
||||
sess, err := session.NewSession()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client := ec2.New(sess, config)
|
||||
instanceTypes := make([]*ec2.InstanceTypeInfo, 0)
|
||||
err = client.DescribeInstanceTypesPages(&ec2.DescribeInstanceTypesInput{},
|
||||
func(page *ec2.DescribeInstanceTypesOutput, lastPage bool) bool {
|
||||
instanceTypes = append(instanceTypes, page.InstanceTypes...)
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var warnings []string
|
||||
|
||||
seen := map[string]bool{}
|
||||
for _, typeInfo := range instanceTypes {
|
||||
instanceType := *typeInfo.InstanceType
|
||||
|
||||
if _, ok := seen[instanceType]; ok {
|
||||
continue
|
||||
}
|
||||
seen[instanceType] = true
|
||||
machine := awsup.AWSMachineTypeInfo{
|
||||
Name: instanceType,
|
||||
GPU: typeInfo.GpuInfo != nil,
|
||||
InstanceENIs: intValue(typeInfo.NetworkInfo.MaximumNetworkInterfaces),
|
||||
InstanceIPsPerENI: intValue(typeInfo.NetworkInfo.Ipv4AddressesPerInterface),
|
||||
}
|
||||
memoryGB := float64(intValue(typeInfo.MemoryInfo.SizeInMiB)) / 1024
|
||||
machine.MemoryGB = float32(math.Round(memoryGB*100) / 100)
|
||||
|
||||
if typeInfo.VCpuInfo != nil && typeInfo.VCpuInfo.DefaultVCpus != nil {
|
||||
machine.Cores = intValue(typeInfo.VCpuInfo.DefaultVCpus)
|
||||
}
|
||||
if typeInfo.InstanceStorageInfo != nil && len(typeInfo.InstanceStorageInfo.Disks) > 0 {
|
||||
disks := make([]int, 0)
|
||||
for _, disk := range typeInfo.InstanceStorageInfo.Disks {
|
||||
for i := 0; i < intValue(disk.Count); i++ {
|
||||
disks = append(disks, intValue(disk.SizeInGB))
|
||||
}
|
||||
}
|
||||
machine.EphemeralDisks = disks
|
||||
}
|
||||
|
||||
machines = append(machines, machine)
|
||||
|
||||
family := strings.Split(instanceType, ".")[0]
|
||||
families[family] = struct{}{}
|
||||
|
||||
}
|
||||
|
||||
sortedFamilies := []string{}
|
||||
for f := range families {
|
||||
sortedFamilies = append(sortedFamilies, f)
|
||||
}
|
||||
sort.Strings(sortedFamilies)
|
||||
|
||||
sort.Slice(machines, func(i, j int) bool {
|
||||
// Sort first by family
|
||||
tokensI := strings.Split(machines[i].Name, ".")
|
||||
tokensJ := strings.Split(machines[j].Name, ".")
|
||||
|
||||
if tokensI[0] != tokensJ[0] {
|
||||
return tokensI[0] < tokensJ[0]
|
||||
}
|
||||
|
||||
// Then sort by size within the family
|
||||
if machines[i].MemoryGB != machines[j].MemoryGB {
|
||||
return machines[i].MemoryGB < machines[j].MemoryGB
|
||||
}
|
||||
|
||||
// Fallback: sort by name
|
||||
return machines[i].Name < machines[j].Name
|
||||
})
|
||||
|
||||
var output string
|
||||
|
||||
if len(warnings) != 0 {
|
||||
output = output + "\n"
|
||||
for _, warning := range warnings {
|
||||
output = output + "// WARNING: " + warning + "\n"
|
||||
}
|
||||
output = output + "\n"
|
||||
}
|
||||
|
||||
for _, f := range sortedFamilies {
|
||||
output = output + fmt.Sprintf("\n// %s family", f)
|
||||
for _, m := range machines {
|
||||
if family := strings.Split(m.Name, ".")[0]; family == f {
|
||||
|
||||
body := fmt.Sprintf(`
|
||||
{
|
||||
Name: "%s",
|
||||
MemoryGB: %v,
|
||||
Cores: %v,
|
||||
InstanceENIs: %v,
|
||||
InstanceIPsPerENI: %v,
|
||||
`, m.Name, m.MemoryGB, m.Cores, m.InstanceENIs, m.InstanceIPsPerENI)
|
||||
output = output + body
|
||||
|
||||
// Avoid awkward []int(nil) syntax
|
||||
if len(m.EphemeralDisks) == 0 {
|
||||
output = output + "EphemeralDisks: nil,\n"
|
||||
} else {
|
||||
output = output + fmt.Sprintf("EphemeralDisks: %#v,\n", m.EphemeralDisks)
|
||||
}
|
||||
|
||||
if m.GPU {
|
||||
output = output + "GPU: true,\n"
|
||||
}
|
||||
|
||||
output = output + "},\n"
|
||||
}
|
||||
}
|
||||
output = output + "\n"
|
||||
}
|
||||
|
||||
klog.Infof("Writing changes to %v", outputPath)
|
||||
|
||||
fileInput, err := ioutil.ReadFile(outputPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading %s: %v", outputPath, err)
|
||||
}
|
||||
scanner := bufio.NewScanner(bytes.NewReader(fileInput))
|
||||
|
||||
scanner.Split(bufio.ScanLines)
|
||||
|
||||
var newfile string
|
||||
flag := false
|
||||
done := false
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
if strings.Contains(line, "END GENERATED CONTENT") {
|
||||
flag = false
|
||||
done = true
|
||||
}
|
||||
if !flag {
|
||||
newfile = newfile + line + "\n"
|
||||
}
|
||||
if strings.Contains(line, "BEGIN GENERATED CONTENT") {
|
||||
flag = true
|
||||
newfile = newfile + output
|
||||
}
|
||||
}
|
||||
|
||||
if !done {
|
||||
return fmt.Errorf("BEGIN GENERATED CONTENT / END GENERATED CONTENT markers not found")
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(outputPath, []byte(newfile), 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error writing %s: %v", outputPath, err)
|
||||
}
|
||||
|
||||
klog.Info("Done.")
|
||||
klog.Flush()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func intValue(v *int64) int {
|
||||
return int(aws.Int64Value(v))
|
||||
}
|
||||
|
|
@ -452,8 +452,16 @@ func (b *KubeletBuilder) buildKubeletConfigSpec() (*kops.KubeletConfigSpec, erro
|
|||
instanceTypeName = strings.Split(b.InstanceGroup.Spec.MachineType, ",")[0]
|
||||
}
|
||||
|
||||
region, err := awsup.FindRegion(b.Cluster)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
awsCloud, err := awsup.NewAWSCloud(region, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Get the instance type's detailed information.
|
||||
instanceType, err := awsup.GetMachineTypeInfo(instanceTypeName)
|
||||
instanceType, err := awsup.GetMachineTypeInfo(awsCloud, instanceTypeName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ go_test(
|
|||
deps = [
|
||||
"//pkg/apis/kops:go_default_library",
|
||||
"//upup/pkg/fi:go_default_library",
|
||||
"//upup/pkg/fi/cloudup/awsup:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/kops/pkg/apis/kops"
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
|
||||
)
|
||||
|
||||
|
|
@ -38,17 +39,21 @@ func awsValidateCluster(c *kops.Cluster) field.ErrorList {
|
|||
return allErrs
|
||||
}
|
||||
|
||||
func awsValidateInstanceGroup(ig *kops.InstanceGroup) field.ErrorList {
|
||||
func awsValidateInstanceGroup(ig *kops.InstanceGroup, cloud awsup.AWSCloud) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
allErrs = append(allErrs, awsValidateAdditionalSecurityGroups(field.NewPath("spec", "additionalSecurityGroups"), ig.Spec.AdditionalSecurityGroups)...)
|
||||
|
||||
allErrs = append(allErrs, awsValidateMachineType(field.NewPath(ig.GetName(), "spec", "machineType"), ig.Spec.MachineType)...)
|
||||
allErrs = append(allErrs, awsValidateInstanceType(field.NewPath(ig.GetName(), "spec", "machineType"), ig.Spec.MachineType, cloud)...)
|
||||
|
||||
allErrs = append(allErrs, awsValidateSpotDurationInMinute(field.NewPath(ig.GetName(), "spec", "spotDurationInMinutes"), ig)...)
|
||||
|
||||
allErrs = append(allErrs, awsValidateInstanceInterruptionBehavior(field.NewPath(ig.GetName(), "spec", "instanceInterruptionBehavior"), ig)...)
|
||||
|
||||
if ig.Spec.MixedInstancesPolicy != nil {
|
||||
allErrs = append(allErrs, awsValidateMixedInstancesPolicy(field.NewPath("spec", "mixedInstancesPolicy"), ig.Spec.MixedInstancesPolicy, ig, cloud)...)
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
|
|
@ -73,12 +78,11 @@ func awsValidateAdditionalSecurityGroups(fieldPath *field.Path, groups []string)
|
|||
return allErrs
|
||||
}
|
||||
|
||||
func awsValidateMachineType(fieldPath *field.Path, machineType string) field.ErrorList {
|
||||
func awsValidateInstanceType(fieldPath *field.Path, instanceType string, cloud awsup.AWSCloud) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if machineType != "" {
|
||||
for _, typ := range strings.Split(machineType, ",") {
|
||||
if _, err := awsup.GetMachineTypeInfo(typ); err != nil {
|
||||
if instanceType != "" && cloud != nil {
|
||||
for _, typ := range strings.Split(instanceType, ",") {
|
||||
if _, err := cloud.DescribeInstanceType(typ); err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fieldPath, typ, "machine type specified is invalid"))
|
||||
}
|
||||
}
|
||||
|
|
@ -106,3 +110,35 @@ func awsValidateInstanceInterruptionBehavior(fieldPath *field.Path, ig *kops.Ins
|
|||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// awsValidateMixedInstancesPolicy is responsible for validating the user input of a mixed instance policy
|
||||
func awsValidateMixedInstancesPolicy(path *field.Path, spec *kops.MixedInstancesPolicySpec, ig *kops.InstanceGroup, cloud awsup.AWSCloud) field.ErrorList {
|
||||
var errs field.ErrorList
|
||||
|
||||
// @step: check the instance types are valid
|
||||
for i, x := range spec.Instances {
|
||||
errs = append(errs, awsValidateInstanceType(path.Child("instances").Index(i), x, cloud)...)
|
||||
}
|
||||
|
||||
if spec.OnDemandBase != nil {
|
||||
if fi.Int64Value(spec.OnDemandBase) < 0 {
|
||||
errs = append(errs, field.Invalid(path.Child("onDemandBase"), spec.OnDemandBase, "cannot be less than zero"))
|
||||
}
|
||||
if fi.Int64Value(spec.OnDemandBase) > int64(fi.Int32Value(ig.Spec.MaxSize)) {
|
||||
errs = append(errs, field.Invalid(path.Child("onDemandBase"), spec.OnDemandBase, "cannot be greater than max size"))
|
||||
}
|
||||
}
|
||||
|
||||
if spec.OnDemandAboveBase != nil {
|
||||
if fi.Int64Value(spec.OnDemandAboveBase) < 0 {
|
||||
errs = append(errs, field.Invalid(path.Child("onDemandAboveBase"), spec.OnDemandAboveBase, "cannot be less than 0"))
|
||||
}
|
||||
if fi.Int64Value(spec.OnDemandAboveBase) > 100 {
|
||||
errs = append(errs, field.Invalid(path.Child("onDemandAboveBase"), spec.OnDemandAboveBase, "cannot be greater than 100"))
|
||||
}
|
||||
}
|
||||
|
||||
errs = append(errs, IsValidValue(path.Child("spotAllocationStrategy"), spec.SpotAllocationStrategy, kops.SpotAllocationStrategies)...)
|
||||
|
||||
return errs
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
|
||||
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kops/pkg/apis/kops"
|
||||
|
|
@ -143,6 +144,7 @@ func TestValidateInstanceGroupSpec(t *testing.T) {
|
|||
ExpectedErrors: []string{},
|
||||
},
|
||||
}
|
||||
cloud := awsup.BuildMockAWSCloud("us-east-1", "abc")
|
||||
for _, g := range grid {
|
||||
ig := &kops.InstanceGroup{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
|
|
@ -150,7 +152,7 @@ func TestValidateInstanceGroupSpec(t *testing.T) {
|
|||
},
|
||||
Spec: g.Input,
|
||||
}
|
||||
errs := awsValidateInstanceGroup(ig)
|
||||
errs := awsValidateInstanceGroup(ig, cloud)
|
||||
|
||||
testErrors(t, g.Input, errs, g.ExpectedErrors)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,10 +24,11 @@ import (
|
|||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/kops/pkg/apis/kops"
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
|
||||
)
|
||||
|
||||
// ValidateInstanceGroup is responsible for validating the configuration of a instancegroup
|
||||
func ValidateInstanceGroup(g *kops.InstanceGroup) field.ErrorList {
|
||||
func ValidateInstanceGroup(g *kops.InstanceGroup, cloud fi.Cloud) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if g.ObjectMeta.Name == "" {
|
||||
|
|
@ -75,10 +76,6 @@ func ValidateInstanceGroup(g *kops.InstanceGroup) field.ErrorList {
|
|||
allErrs = append(allErrs, validateFileAssetSpec(&g.Spec.FileAssets[i], field.NewPath("spec", "fileAssets").Index(i))...)
|
||||
}
|
||||
|
||||
if g.Spec.MixedInstancesPolicy != nil {
|
||||
allErrs = append(allErrs, validatedMixedInstancesPolicy(field.NewPath("spec", "mixedInstancesPolicy"), g.Spec.MixedInstancesPolicy, g)...)
|
||||
}
|
||||
|
||||
for _, UserDataInfo := range g.Spec.AdditionalUserData {
|
||||
allErrs = append(allErrs, validateExtraUserData(&UserDataInfo)...)
|
||||
}
|
||||
|
|
@ -118,41 +115,13 @@ func ValidateInstanceGroup(g *kops.InstanceGroup) field.ErrorList {
|
|||
allErrs = append(allErrs, validateRollingUpdate(g.Spec.RollingUpdate, field.NewPath("spec", "rollingUpdate"), g.Spec.Role == kops.InstanceGroupRoleMaster)...)
|
||||
}
|
||||
|
||||
if cloud != nil && cloud.ProviderID() == kops.CloudProviderAWS {
|
||||
allErrs = append(allErrs, awsValidateInstanceGroup(g, cloud.(awsup.AWSCloud))...)
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validatedMixedInstancesPolicy is responsible for validating the user input of a mixed instance policy
|
||||
func validatedMixedInstancesPolicy(path *field.Path, spec *kops.MixedInstancesPolicySpec, ig *kops.InstanceGroup) field.ErrorList {
|
||||
var errs field.ErrorList
|
||||
|
||||
// @step: check the instances are validate
|
||||
for i, x := range spec.Instances {
|
||||
errs = append(errs, awsValidateMachineType(path.Child("instances").Index(i).Child("instanceType"), x)...)
|
||||
}
|
||||
|
||||
if spec.OnDemandBase != nil {
|
||||
if fi.Int64Value(spec.OnDemandBase) < 0 {
|
||||
errs = append(errs, field.Invalid(path.Child("onDemandBase"), spec.OnDemandBase, "cannot be less than zero"))
|
||||
}
|
||||
if fi.Int64Value(spec.OnDemandBase) > int64(fi.Int32Value(ig.Spec.MaxSize)) {
|
||||
errs = append(errs, field.Invalid(path.Child("onDemandBase"), spec.OnDemandBase, "cannot be greater than max size"))
|
||||
}
|
||||
}
|
||||
|
||||
if spec.OnDemandAboveBase != nil {
|
||||
if fi.Int64Value(spec.OnDemandAboveBase) < 0 {
|
||||
errs = append(errs, field.Invalid(path.Child("onDemandAboveBase"), spec.OnDemandAboveBase, "cannot be less than 0"))
|
||||
}
|
||||
if fi.Int64Value(spec.OnDemandAboveBase) > 100 {
|
||||
errs = append(errs, field.Invalid(path.Child("onDemandAboveBase"), spec.OnDemandAboveBase, "cannot be greater than 100"))
|
||||
}
|
||||
}
|
||||
|
||||
errs = append(errs, IsValidValue(path.Child("spotAllocationStrategy"), spec.SpotAllocationStrategy, kops.SpotAllocationStrategies)...)
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// validateVolumeSpec is responsible for checking a volume spec is ok
|
||||
func validateVolumeSpec(path *field.Path, v *kops.VolumeSpec) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
|
@ -187,8 +156,8 @@ func validateVolumeMountSpec(path *field.Path, spec *kops.VolumeMountSpec) field
|
|||
|
||||
// CrossValidateInstanceGroup performs validation of the instance group, including that it is consistent with the Cluster
|
||||
// It calls ValidateInstanceGroup, so all that validation is included.
|
||||
func CrossValidateInstanceGroup(g *kops.InstanceGroup, cluster *kops.Cluster) field.ErrorList {
|
||||
allErrs := ValidateInstanceGroup(g)
|
||||
func CrossValidateInstanceGroup(g *kops.InstanceGroup, cluster *kops.Cluster, cloud fi.Cloud) field.ErrorList {
|
||||
allErrs := ValidateInstanceGroup(g, cloud)
|
||||
|
||||
if g.Spec.Role == kops.InstanceGroupRoleMaster {
|
||||
allErrs = append(allErrs, ValidateMasterInstanceGroup(g, cluster)...)
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ func TestValidBootDevice(t *testing.T) {
|
|||
RootVolumeType: fi.String(g.volumeType),
|
||||
},
|
||||
}
|
||||
errs := CrossValidateInstanceGroup(ig, cluster)
|
||||
errs := CrossValidateInstanceGroup(ig, cluster, nil)
|
||||
testErrors(t, g.volumeType, errs, g.expected)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -507,7 +507,7 @@ func validateSubnetCIDR(networkCIDR *net.IPNet, additionalNetworkCIDRs []*net.IP
|
|||
}
|
||||
|
||||
// DeepValidate is responsible for validating the instancegroups within the cluster spec
|
||||
func DeepValidate(c *kops.Cluster, groups []*kops.InstanceGroup, strict bool) error {
|
||||
func DeepValidate(c *kops.Cluster, groups []*kops.InstanceGroup, strict bool, cloud fi.Cloud) error {
|
||||
if errs := ValidateCluster(c, strict); len(errs) != 0 {
|
||||
return errs.ToAggregate()
|
||||
}
|
||||
|
|
@ -535,17 +535,11 @@ func DeepValidate(c *kops.Cluster, groups []*kops.InstanceGroup, strict bool) er
|
|||
}
|
||||
|
||||
for _, g := range groups {
|
||||
errs := CrossValidateInstanceGroup(g, c)
|
||||
errs := CrossValidateInstanceGroup(g, c, cloud)
|
||||
|
||||
// Additional cloud-specific validation rules,
|
||||
// such as making sure that identifiers match the expected formats for the given cloud
|
||||
switch kops.CloudProviderID(c.Spec.CloudProvider) {
|
||||
case kops.CloudProviderAWS:
|
||||
errs = append(errs, awsValidateInstanceGroup(g)...)
|
||||
default:
|
||||
if len(g.Spec.Volumes) > 0 {
|
||||
errs = append(errs, field.Forbidden(field.NewPath("spec", "volumes"), "instancegroup volumes are only available with aws at present"))
|
||||
}
|
||||
// Additional cloud-specific validation rules
|
||||
if kops.CloudProviderID(c.Spec.CloudProvider) != kops.CloudProviderAWS && len(g.Spec.Volumes) > 0 {
|
||||
errs = append(errs, field.Forbidden(field.NewPath("spec", "volumes"), "instancegroup volumes are only available with aws at present"))
|
||||
}
|
||||
|
||||
if len(errs) != 0 {
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ func NewInstanceGroupMirror(cluster *kopsapi.Cluster, configBase vfs.Path) Insta
|
|||
}
|
||||
r.init(kind, configBase.Join("instancegroup"), StoreVersion)
|
||||
r.validate = func(o runtime.Object) error {
|
||||
return validation.ValidateInstanceGroup(o.(*kopsapi.InstanceGroup)).ToAggregate()
|
||||
return validation.ValidateInstanceGroup(o.(*kopsapi.InstanceGroup), nil).ToAggregate()
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
|
@ -80,7 +80,7 @@ func newInstanceGroupVFS(c *VFSClientset, cluster *kopsapi.Cluster) *InstanceGro
|
|||
}
|
||||
r.init(kind, c.basePath.Join(clusterName, "instancegroup"), StoreVersion)
|
||||
r.validate = func(o runtime.Object) error {
|
||||
return validation.ValidateInstanceGroup(o.(*kopsapi.InstanceGroup)).ToAggregate()
|
||||
return validation.ValidateInstanceGroup(o.(*kopsapi.InstanceGroup), nil).ToAggregate()
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ func UpdateCluster(ctx context.Context, clientset simple.Clientset, cluster *kop
|
|||
return err
|
||||
}
|
||||
|
||||
err = validation.DeepValidate(fullCluster, instanceGroups, true)
|
||||
err = validation.DeepValidate(fullCluster, instanceGroups, true, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -232,12 +232,17 @@ func (c *ApplyClusterCmd) Run(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
err = validation.DeepValidate(c.Cluster, c.InstanceGroups, true)
|
||||
cluster := c.Cluster
|
||||
|
||||
cloud, err := BuildCloud(cluster)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cluster := c.Cluster
|
||||
err = validation.DeepValidate(c.Cluster, c.InstanceGroups, true, cloud)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cluster.Spec.KubernetesVersion == "" {
|
||||
return fmt.Errorf("KubernetesVersion not set")
|
||||
|
|
@ -323,11 +328,6 @@ func (c *ApplyClusterCmd) Run(ctx context.Context) error {
|
|||
"mirrorSecrets": &fitasks.MirrorSecrets{},
|
||||
})
|
||||
|
||||
cloud, err := BuildCloud(cluster)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
region := ""
|
||||
project := ""
|
||||
|
||||
|
|
@ -446,8 +446,6 @@ func (c *ApplyClusterCmd) Run(ctx context.Context) error {
|
|||
if len(sshPublicKeys) > 1 {
|
||||
return fmt.Errorf("exactly one 'admin' SSH public key can be specified when running with AWS; please delete a key using `kops delete secret`")
|
||||
}
|
||||
|
||||
l.TemplateFunctions["MachineTypeInfo"] = awsup.GetMachineTypeInfo
|
||||
}
|
||||
|
||||
case kops.CloudProviderALI:
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import (
|
|||
|
||||
// buildEphemeralDevices looks up the machine type and discovery any ephemeral device mappings
|
||||
func buildEphemeralDevices(cloud awsup.AWSCloud, machineType string) (map[string]*BlockDeviceMapping, error) {
|
||||
mt, err := awsup.GetMachineTypeInfo(machineType)
|
||||
mt, err := awsup.GetMachineTypeInfo(cloud, machineType)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find instance type details on: %s, error: %s", machineType, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,6 +155,9 @@ type AWSCloud interface {
|
|||
// DefaultInstanceType determines a suitable instance type for the specified instance group
|
||||
DefaultInstanceType(cluster *kops.Cluster, ig *kops.InstanceGroup) (string, error)
|
||||
|
||||
// DescribeInstanceType calls ec2.DescribeInstanceType to get information for a particular instance type
|
||||
DescribeInstanceType(instanceType string) (*ec2.InstanceTypeInfo, error)
|
||||
|
||||
// FindClusterStatus gets the status of the cluster as it exists in AWS, inferred from volumes
|
||||
FindClusterStatus(cluster *kops.Cluster) (*kops.ClusterStatus, error)
|
||||
}
|
||||
|
|
@ -174,6 +177,8 @@ type awsCloudImplementation struct {
|
|||
tags map[string]string
|
||||
|
||||
regionDelayers *RegionDelayers
|
||||
|
||||
instanceTypes *instanceTypes
|
||||
}
|
||||
|
||||
type RegionDelayers struct {
|
||||
|
|
@ -181,6 +186,11 @@ type RegionDelayers struct {
|
|||
delayerMap map[string]*k8s_aws.CrossRequestRetryDelay
|
||||
}
|
||||
|
||||
type instanceTypes struct {
|
||||
mutex sync.Mutex
|
||||
typeMap map[string]*ec2.InstanceTypeInfo
|
||||
}
|
||||
|
||||
var _ fi.Cloud = &awsCloudImplementation{}
|
||||
|
||||
func (c *awsCloudImplementation) ProviderID() kops.CloudProviderID {
|
||||
|
|
@ -201,6 +211,9 @@ func NewAWSCloud(region string, tags map[string]string) (AWSCloud, error) {
|
|||
regionDelayers: &RegionDelayers{
|
||||
delayerMap: make(map[string]*k8s_aws.CrossRequestRetryDelay),
|
||||
},
|
||||
instanceTypes: &instanceTypes{
|
||||
typeMap: make(map[string]*ec2.InstanceTypeInfo),
|
||||
},
|
||||
}
|
||||
|
||||
config := aws.NewConfig().WithRegion(region)
|
||||
|
|
@ -1537,3 +1550,33 @@ func (c *awsCloudImplementation) zonesWithInstanceType(instanceType string) (set
|
|||
|
||||
return zones, nil
|
||||
}
|
||||
|
||||
// DescribeInstanceType calls ec2.DescribeInstanceType to get information for a particular instance type
|
||||
func (c *awsCloudImplementation) DescribeInstanceType(instanceType string) (*ec2.InstanceTypeInfo, error) {
|
||||
if info, ok := c.instanceTypes.typeMap[instanceType]; ok {
|
||||
return info, nil
|
||||
}
|
||||
c.instanceTypes.mutex.Lock()
|
||||
defer c.instanceTypes.mutex.Unlock()
|
||||
|
||||
info, err := describeInstanceType(c, instanceType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.instanceTypes.typeMap[instanceType] = info
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func describeInstanceType(c AWSCloud, instanceType string) (*ec2.InstanceTypeInfo, error) {
|
||||
req := &ec2.DescribeInstanceTypesInput{
|
||||
InstanceTypes: aws.StringSlice([]string{instanceType}),
|
||||
}
|
||||
resp, err := c.EC2().DescribeInstanceTypes(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(resp.InstanceTypes) != 1 {
|
||||
return nil, fmt.Errorf("invalid instance type specified: %v", instanceType)
|
||||
}
|
||||
return resp.InstanceTypes[0], nil
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -270,3 +270,33 @@ func (c *MockAWSCloud) DefaultInstanceType(cluster *kops.Cluster, ig *kops.Insta
|
|||
return "", fmt.Errorf("MockAWSCloud DefaultInstanceType does not handle %s", ig.Spec.Role)
|
||||
}
|
||||
}
|
||||
|
||||
// DescribeInstanceType calls ec2.DescribeInstanceType to get information for a particular instance type
|
||||
func (c *MockAWSCloud) DescribeInstanceType(instanceType string) (*ec2.InstanceTypeInfo, error) {
|
||||
if instanceType == "t2.invalidType" {
|
||||
return nil, fmt.Errorf("invalid instance type specified: t2.invalidType")
|
||||
}
|
||||
info := &ec2.InstanceTypeInfo{
|
||||
NetworkInfo: &ec2.NetworkInfo{
|
||||
MaximumNetworkInterfaces: aws.Int64(1),
|
||||
Ipv4AddressesPerInterface: aws.Int64(1),
|
||||
},
|
||||
MemoryInfo: &ec2.MemoryInfo{
|
||||
SizeInMiB: aws.Int64(1024),
|
||||
},
|
||||
VCpuInfo: &ec2.VCpuInfo{
|
||||
DefaultVCpus: aws.Int64(2),
|
||||
},
|
||||
}
|
||||
if instanceType == "m3.medium" {
|
||||
info.InstanceStorageInfo = &ec2.InstanceStorageInfo{
|
||||
Disks: []*ec2.DiskInfo{
|
||||
{
|
||||
Count: aws.Int64(1),
|
||||
SizeInGB: aws.Int64(1024),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ func TestDeepValidate_OK(t *testing.T) {
|
|||
var groups []*kopsapi.InstanceGroup
|
||||
groups = append(groups, buildMinimalMasterInstanceGroup("subnet-us-mock-1a"))
|
||||
groups = append(groups, buildMinimalNodeInstanceGroup("subnet-us-mock-1a"))
|
||||
err := validation.DeepValidate(c, groups, true)
|
||||
err := validation.DeepValidate(c, groups, true, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error from DeepValidate, got %v", err)
|
||||
}
|
||||
|
|
@ -172,7 +172,7 @@ func TestDeepValidate_MissingEtcdMember(t *testing.T) {
|
|||
}
|
||||
|
||||
func expectErrorFromDeepValidate(t *testing.T, c *kopsapi.Cluster, groups []*kopsapi.InstanceGroup, message string) {
|
||||
err := validation.DeepValidate(c, groups, true)
|
||||
err := validation.DeepValidate(c, groups, true, nil)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error %q from DeepValidate (strict=true), not no error raised", message)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ const (
|
|||
defaultALINodeImage = "centos_7_04_64_20G_alibase_201701015.vhd"
|
||||
)
|
||||
|
||||
// TODO: this hardcoded list can be replaced with DescribeInstanceTypes' DedicatedHostsSupported field
|
||||
var awsDedicatedInstanceExceptions = map[string]bool{
|
||||
"t2.nano": true,
|
||||
"t2.micro": true,
|
||||
|
|
@ -60,7 +61,7 @@ var awsDedicatedInstanceExceptions = map[string]bool{
|
|||
// The InstanceGroup is simpler than the cluster spec, so we just populate in place (like the rest of k8s)
|
||||
func PopulateInstanceGroupSpec(cluster *kops.Cluster, input *kops.InstanceGroup, channel *kops.Channel) (*kops.InstanceGroup, error) {
|
||||
var err error
|
||||
err = validation.ValidateInstanceGroup(input).ToAggregate()
|
||||
err = validation.ValidateInstanceGroup(input, nil).ToAggregate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -528,7 +528,7 @@ func (_ *Elastigroup) create(cloud awsup.AWSCloud, a, e, changes *Elastigroup) e
|
|||
return err
|
||||
}
|
||||
|
||||
ephemeralDevices, err := e.buildEphemeralDevices(e.OnDemandInstanceType)
|
||||
ephemeralDevices, err := e.buildEphemeralDevices(cloud, e.OnDemandInstanceType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -956,7 +956,7 @@ func (_ *Elastigroup) update(cloud awsup.AWSCloud, a, e, changes *Elastigroup) e
|
|||
return err
|
||||
}
|
||||
|
||||
ephemeralDevices, err := e.buildEphemeralDevices(e.OnDemandInstanceType)
|
||||
ephemeralDevices, err := e.buildEphemeralDevices(cloud, e.OnDemandInstanceType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -1494,7 +1494,7 @@ func (_ *Elastigroup) RenderTerraform(t *terraform.TerraformTarget, a, e, change
|
|||
return err
|
||||
}
|
||||
|
||||
ephemeralDevices, err := e.buildEphemeralDevices(e.OnDemandInstanceType)
|
||||
ephemeralDevices, err := e.buildEphemeralDevices(cloud, e.OnDemandInstanceType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -1638,12 +1638,12 @@ func (e *Elastigroup) buildAutoScaleLabels(labelsMap map[string]string) []*aws.A
|
|||
return labels
|
||||
}
|
||||
|
||||
func (e *Elastigroup) buildEphemeralDevices(instanceTypeName *string) (map[string]*awstasks.BlockDeviceMapping, error) {
|
||||
func (e *Elastigroup) buildEphemeralDevices(c awsup.AWSCloud, instanceTypeName *string) (map[string]*awstasks.BlockDeviceMapping, error) {
|
||||
if instanceTypeName == nil {
|
||||
return nil, fi.RequiredField("InstanceType")
|
||||
}
|
||||
|
||||
instanceType, err := awsup.GetMachineTypeInfo(*instanceTypeName)
|
||||
instanceType, err := awsup.GetMachineTypeInfo(c, *instanceTypeName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue