Merge pull request #13234 from spotinst/feat-ocean-template

Spotinst: Ocean as a template for VNGs
This commit is contained in:
Kubernetes Prow Robot 2022-03-19 00:45:08 -07:00 committed by GitHub
commit 65694b20b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 2935 additions and 601 deletions

View File

@ -14,6 +14,7 @@ The following experimental features are currently available:
* `+GoogleCloudBucketAcl` - Enables setting the ACL on the state store bucket when using GCS * `+GoogleCloudBucketAcl` - Enables setting the ACL on the state store bucket when using GCS
* `+Spotinst` - Enables the use of the Spot integration * `+Spotinst` - Enables the use of the Spot integration
* `+SpotinstOcean` - Enables the use of the Spot Ocean integration * `+SpotinstOcean` - Enables the use of the Spot Ocean integration
* `+SpotinstOceanTemplate` - Enables the use of Spot Ocean object as a template for Virtual Node Groups
* `+SpotinstHybrid` - Toggles between hybrid and full instance group implementations * `+SpotinstHybrid` - Toggles between hybrid and full instance group implementations
* `-SpotinstController` - Toggles the installation of the Spot controller addon off * `-SpotinstController` - Toggles the installation of the Spot controller addon off
* `+SkipEtcdVersionCheck` - Bypasses the check that etcd-manager is using a supported etcd version * `+SkipEtcdVersionCheck` - Bypasses the check that etcd-manager is using a supported etcd version

View File

@ -70,6 +70,7 @@ Make sure to set up [a dedicated IAM user](./aws.md#setup-iam-user), [DNS record
|---|---| |---|---|
| `+Spotinst` | Enables the use of the Spot integration. | | `+Spotinst` | Enables the use of the Spot integration. |
| `+SpotinstOcean` | Enables the use of the Spot Ocean integration. | | `+SpotinstOcean` | Enables the use of the Spot Ocean integration. |
| `+SpotinstOceanTemplate` - Enables the use of Spot Ocean object as a template for Virtual Node Groups. |
| `+SpotinstHybrid` | Toggles between hybrid and full instance group implementations. Allows you to gradually integrate with Spot Ocean by continuing to use instance groups through AWS Auto Scaling groups, except for specific instance groups labeled with a predefined [metadata label](#metadata-labels). | | `+SpotinstHybrid` | Toggles between hybrid and full instance group implementations. Allows you to gradually integrate with Spot Ocean by continuing to use instance groups through AWS Auto Scaling groups, except for specific instance groups labeled with a predefined [metadata label](#metadata-labels). |
| `-SpotinstController` | Toggles the installation of the Spot controller addon off. Please note that the feature flag must be prefixed with a minus (`-`) sign to set its value to `false`, which results in disabling the controller. | | `-SpotinstController` | Toggles the installation of the Spot controller addon off. Please note that the feature flag must be prefixed with a minus (`-`) sign to set its value to `false`, which results in disabling the controller. |
@ -79,7 +80,7 @@ You can add an Ocean instance group to new or existing clusters. To create a new
```bash ```bash
# configure the feature flags # configure the feature flags
export KOPS_FEATURE_FLAGS="Spotinst,SpotinstOcean" export KOPS_FEATURE_FLAGS="Spotinst,SpotinstOcean,SpotinstOceanTemplate"
# create the cluster # create the cluster
kops create cluster --zones=us-west-2a example kops create cluster --zones=us-west-2a example
@ -124,7 +125,7 @@ To create a new instance group, run:
```bash ```bash
# configure the feature flags # configure the feature flags
export KOPS_FEATURE_FLAGS="Spotinst,SpotinstOcean" export KOPS_FEATURE_FLAGS="Spotinst,SpotinstOcean,SpotinstOceanTemplate"
# create the instance group # create the instance group
kops create instancegroup --role=node --name=example kops create instancegroup --role=node --name=example

6
go.mod
View File

@ -70,7 +70,7 @@ require (
github.com/spf13/cobra v1.2.1 github.com/spf13/cobra v1.2.1
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.8.1 github.com/spf13/viper v1.8.1
github.com/spotinst/spotinst-sdk-go v1.85.0 github.com/spotinst/spotinst-sdk-go v1.110.0
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
github.com/weaveworks/mesh v0.0.0-20191105120815-58dbcc3e8e63 github.com/weaveworks/mesh v0.0.0-20191105120815-58dbcc3e8e63
github.com/zclconf/go-cty v1.8.2 github.com/zclconf/go-cty v1.8.2
@ -91,6 +91,7 @@ require (
k8s.io/client-go v0.23.1 k8s.io/client-go v0.23.1
k8s.io/component-base v0.23.1 k8s.io/component-base v0.23.1
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c
k8s.io/klog v1.0.0
k8s.io/klog/v2 v2.30.0 k8s.io/klog/v2 v2.30.0
k8s.io/kubectl v0.23.1 k8s.io/kubectl v0.23.1
k8s.io/kubelet v0.23.1 k8s.io/kubelet v0.23.1
@ -227,13 +228,12 @@ require (
google.golang.org/genproto v0.0.0-20211111162719-482062a4217b // indirect google.golang.org/genproto v0.0.0-20211111162719-482062a4217b // indirect
google.golang.org/grpc v1.42.0 // indirect google.golang.org/grpc v1.42.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/ini.v1 v1.66.3 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/apiextensions-apiserver v0.23.1 // indirect k8s.io/apiextensions-apiserver v0.23.1 // indirect
k8s.io/cloud-provider v0.23.1 // indirect k8s.io/cloud-provider v0.23.1 // indirect
k8s.io/csi-translation-lib v0.23.1 // indirect k8s.io/csi-translation-lib v0.23.1 // indirect
k8s.io/klog v1.0.0 // indirect
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
oras.land/oras-go v0.4.0 // indirect oras.land/oras-go v0.4.0 // indirect
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect

7
go.sum
View File

@ -1224,8 +1224,8 @@ github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/y
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44= github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/spotinst/spotinst-sdk-go v1.85.0 h1:tMXKhxfmU7BnqTnUpR2s/hEyTASfrxkgPb/3Tqn6tmM= github.com/spotinst/spotinst-sdk-go v1.110.0 h1:5dcaXu4rbqljRIckTiqo5tngUrLSHEZ/VYF4fNLtz54=
github.com/spotinst/spotinst-sdk-go v1.85.0/go.mod h1:RuKksd1/RyQogMCxKFI5B75NeFRcgl3W+26DVX6S4m0= github.com/spotinst/spotinst-sdk-go v1.110.0/go.mod h1:qIh4nc5hbkVEAdCG9QTf3EaFHX5cmkj8U37iZn2KpCE=
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/storageos/go-api v2.2.0+incompatible/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY= github.com/storageos/go-api v2.2.0+incompatible/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY=
@ -1976,8 +1976,9 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.3 h1:jRskFVxYaMGAMUbN0UZ7niA9gzL9B49DOqE78vg0k3w=
gopkg.in/ini.v1 v1.66.3/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=

View File

@ -62,6 +62,8 @@ var (
Spotinst = new("Spotinst", Bool(false)) Spotinst = new("Spotinst", Bool(false))
// SpotinstOcean toggles the use of Spotinst Ocean instance group implementation. // SpotinstOcean toggles the use of Spotinst Ocean instance group implementation.
SpotinstOcean = new("SpotinstOcean", Bool(false)) SpotinstOcean = new("SpotinstOcean", Bool(false))
// SpotinstOceanTemplate toggles the use of Spotinst Ocean object as a template for Virtual Node Groups.
SpotinstOceanTemplate = new("SpotinstOceanTemplate", Bool(false))
// SpotinstHybrid toggles between hybrid and full instance group implementations. // SpotinstHybrid toggles between hybrid and full instance group implementations.
SpotinstHybrid = new("SpotinstHybrid", Bool(false)) SpotinstHybrid = new("SpotinstHybrid", Bool(false))
// SpotinstController toggles the installation of the Spotinst controller addon. // SpotinstController toggles the installation of the Spotinst controller addon.

View File

@ -292,7 +292,7 @@ func (b *SpotInstanceGroupModelBuilder) buildElastigroup(c *fi.ModelBuilderConte
} }
// Public IP. // Public IP.
group.AssociatePublicIP, err = b.buildPublicIpOpts(ig) group.AssociatePublicIPAddress, err = b.buildPublicIPOpts(ig)
if err != nil { if err != nil {
return fmt.Errorf("error building public ip options: %v", err) return fmt.Errorf("error building public ip options: %v", err)
} }
@ -337,15 +337,11 @@ func (b *SpotInstanceGroupModelBuilder) buildOcean(c *fi.ModelBuilderContext, ig
Name: fi.String("nodes." + b.ClusterName()), Name: fi.String("nodes." + b.ClusterName()),
} }
// Attempt to find the default LaunchSpec. if featureflag.SpotinstOceanTemplate.Enabled() {
var ig *kops.InstanceGroup ocean.UseAsTemplateOnly = fi.Bool(true)
{
// Single instance group.
if len(igs) == 1 {
ig = igs[0].DeepCopy()
} }
// Multiple instance groups. ig := igs[0].DeepCopy()
if len(igs) > 1 { if len(igs) > 1 {
for _, g := range igs { for _, g := range igs {
for k, v := range g.ObjectMeta.Labels { for k, v := range g.ObjectMeta.Labels {
@ -354,14 +350,12 @@ func (b *SpotInstanceGroupModelBuilder) buildOcean(c *fi.ModelBuilderContext, ig
if err != nil { if err != nil {
continue continue
} }
if fi.BoolValue(defaultLaunchSpec) { if fi.BoolValue(defaultLaunchSpec) {
if ig != nil { if ig != nil {
return fmt.Errorf("unable to detect default launch spec: "+ return fmt.Errorf("unable to detect default launch spec: "+
"multiple instance groups labeled with `%s: \"true\"`", "multiple instance groups labeled with `%s: \"true\"`",
SpotInstanceGroupLabelOceanDefaultLaunchSpec) SpotInstanceGroupLabelOceanDefaultLaunchSpec)
} }
ig = g.DeepCopy() ig = g.DeepCopy()
break break
} }
@ -369,12 +363,6 @@ func (b *SpotInstanceGroupModelBuilder) buildOcean(c *fi.ModelBuilderContext, ig
} }
} }
// No default instance group. Use the first one.
if ig == nil {
ig = igs[0].DeepCopy()
}
}
klog.V(4).Infof("Detected default launch spec: %q", b.AutoscalingGroupName(ig)) klog.V(4).Infof("Detected default launch spec: %q", b.AutoscalingGroupName(ig))
} }
@ -428,13 +416,43 @@ func (b *SpotInstanceGroupModelBuilder) buildOcean(c *fi.ModelBuilderContext, ig
} }
} }
// Monitoring.
ocean.Monitoring = ig.Spec.DetailedInstanceMonitoring
// Security groups.
ocean.SecurityGroups, err = b.buildSecurityGroups(c, ig)
if err != nil {
return fmt.Errorf("error building security groups: %v", err)
}
// SSH key.
ocean.SSHKey, err = b.LinkToSSHKey()
if err != nil {
return fmt.Errorf("error building ssh key: %v", err)
}
// Subnets.
ocean.Subnets, err = b.buildSubnets(ig)
if err != nil {
return fmt.Errorf("error building subnets: %v", err)
}
// Auto Scaler.
ocean.AutoScalerOpts, err = b.buildAutoScalerOpts(b.ClusterName(), ig)
if err != nil {
return fmt.Errorf("error building auto scaler options: %v", err)
}
if ocean.AutoScalerOpts != nil { // remove unsupported options
ocean.AutoScalerOpts.Labels = nil
ocean.AutoScalerOpts.Taints = nil
ocean.AutoScalerOpts.Headroom = nil
}
if !fi.BoolValue(ocean.UseAsTemplateOnly) {
// Capacity. // Capacity.
ocean.MinSize = fi.Int64(0) ocean.MinSize = fi.Int64(0)
ocean.MaxSize = fi.Int64(0) ocean.MaxSize = fi.Int64(0)
// Monitoring.
ocean.Monitoring = ig.Spec.DetailedInstanceMonitoring
// User data. // User data.
ocean.UserData, err = b.BootstrapScriptBuilder.ResourceNodeUp(c, ig) ocean.UserData, err = b.BootstrapScriptBuilder.ResourceNodeUp(c, ig)
if err != nil { if err != nil {
@ -457,45 +475,17 @@ func (b *SpotInstanceGroupModelBuilder) buildOcean(c *fi.ModelBuilderContext, ig
ocean.RootVolumeOpts.Type = nil // not supported in Ocean ocean.RootVolumeOpts.Type = nil // not supported in Ocean
} }
// Security groups.
ocean.SecurityGroups, err = b.buildSecurityGroups(c, ig)
if err != nil {
return fmt.Errorf("error building security groups: %v", err)
}
// SSH key.
ocean.SSHKey, err = b.LinkToSSHKey()
if err != nil {
return fmt.Errorf("error building ssh key: %v", err)
}
// Public IP. // Public IP.
ocean.AssociatePublicIP, err = b.buildPublicIpOpts(ig) ocean.AssociatePublicIPAddress, err = b.buildPublicIPOpts(ig)
if err != nil { if err != nil {
return fmt.Errorf("error building public ip options: %v", err) return fmt.Errorf("error building public ip options: %v", err)
} }
// Subnets.
ocean.Subnets, err = b.buildSubnets(ig)
if err != nil {
return fmt.Errorf("error building subnets: %v", err)
}
// Tags. // Tags.
ocean.Tags, err = b.buildTags(ig) ocean.Tags, err = b.buildTags(ig)
if err != nil { if err != nil {
return fmt.Errorf("error building cloud tags: %v", err) return fmt.Errorf("error building cloud tags: %v", err)
} }
// Auto Scaler.
ocean.AutoScalerOpts, err = b.buildAutoScalerOpts(b.ClusterName(), ig)
if err != nil {
return fmt.Errorf("error building auto scaler options: %v", err)
}
if ocean.AutoScalerOpts != nil { // remove unsupported options
ocean.AutoScalerOpts.Labels = nil
ocean.AutoScalerOpts.Taints = nil
ocean.AutoScalerOpts.Headroom = nil
} }
// Create a Launch Spec for each instance group. // Create a Launch Spec for each instance group.
@ -551,11 +541,16 @@ func (b *SpotInstanceGroupModelBuilder) buildLaunchSpec(c *fi.ModelBuilderContex
// Capacity. // Capacity.
minSize, maxSize := b.buildCapacity(ig) minSize, maxSize := b.buildCapacity(ig)
if fi.BoolValue(ocean.UseAsTemplateOnly) {
launchSpec.MinSize = minSize
launchSpec.MaxSize = maxSize
} else {
ocean.MinSize = fi.Int64(fi.Int64Value(ocean.MinSize) + fi.Int64Value(minSize)) ocean.MinSize = fi.Int64(fi.Int64Value(ocean.MinSize) + fi.Int64Value(minSize))
ocean.MaxSize = fi.Int64(fi.Int64Value(ocean.MaxSize) + fi.Int64Value(maxSize)) ocean.MaxSize = fi.Int64(fi.Int64Value(ocean.MaxSize) + fi.Int64Value(maxSize))
}
// User data. // User data.
if ig.Name == igOcean.Name { if ig.Name == igOcean.Name && !featureflag.SpotinstOceanTemplate.Enabled() {
launchSpec.UserData = ocean.UserData launchSpec.UserData = ocean.UserData
} else { } else {
launchSpec.UserData, err = b.BootstrapScriptBuilder.ResourceNodeUp(c, ig) launchSpec.UserData, err = b.BootstrapScriptBuilder.ResourceNodeUp(c, ig)
@ -580,6 +575,12 @@ func (b *SpotInstanceGroupModelBuilder) buildLaunchSpec(c *fi.ModelBuilderContex
launchSpec.RootVolumeOpts.Optimization = nil launchSpec.RootVolumeOpts.Optimization = nil
} }
// Public IP.
launchSpec.AssociatePublicIPAddress, err = b.buildPublicIPOpts(ig)
if err != nil {
return fmt.Errorf("error building public ip options: %v", err)
}
// Security groups. // Security groups.
launchSpec.SecurityGroups, err = b.buildSecurityGroups(c, ig) launchSpec.SecurityGroups, err = b.buildSecurityGroups(c, ig)
if err != nil { if err != nil {
@ -661,7 +662,7 @@ func (b *SpotInstanceGroupModelBuilder) buildSubnets(ig *kops.InstanceGroup) ([]
return out, nil return out, nil
} }
func (b *SpotInstanceGroupModelBuilder) buildPublicIpOpts(ig *kops.InstanceGroup) (*bool, error) { func (b *SpotInstanceGroupModelBuilder) buildPublicIPOpts(ig *kops.InstanceGroup) (*bool, error) {
subnetMap := make(map[string]*kops.ClusterSubnetSpec) subnetMap := make(map[string]*kops.ClusterSubnetSpec)
for i := range b.Cluster.Spec.Subnets { for i := range b.Cluster.Spec.Subnets {
subnet := &b.Cluster.Spec.Subnets[i] subnet := &b.Cluster.Spec.Subnets[i]
@ -691,7 +692,7 @@ func (b *SpotInstanceGroupModelBuilder) buildPublicIpOpts(ig *kops.InstanceGroup
associatePublicIP = false associatePublicIP = false
if ig.Spec.AssociatePublicIP != nil { if ig.Spec.AssociatePublicIP != nil {
if *ig.Spec.AssociatePublicIP { if *ig.Spec.AssociatePublicIP {
klog.Warningf("Ignoring AssociatePublicIP=true for private SpotInstanceGroup %q", ig.ObjectMeta.Name) klog.Warningf("Ignoring AssociatePublicIPAddress=true for private SpotInstanceGroup %q", ig.ObjectMeta.Name)
} }
} }
default: default:

View File

@ -1541,7 +1541,7 @@ github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfD
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM=
github.com/spotinst/spotinst-sdk-go v1.85.0/go.mod h1:RuKksd1/RyQogMCxKFI5B75NeFRcgl3W+26DVX6S4m0= github.com/spotinst/spotinst-sdk-go v1.110.0/go.mod h1:qIh4nc5hbkVEAdCG9QTf3EaFHX5cmkj8U37iZn2KpCE=
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
@ -2435,8 +2435,9 @@ gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.3 h1:jRskFVxYaMGAMUbN0UZ7niA9gzL9B49DOqE78vg0k3w=
gopkg.in/ini.v1 v1.66.3/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo=
gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q=
gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM=

View File

@ -26,6 +26,7 @@ go_library(
"//vendor/github.com/spotinst/spotinst-sdk-go/spotinst/client:go_default_library", "//vendor/github.com/spotinst/spotinst-sdk-go/spotinst/client:go_default_library",
"//vendor/github.com/spotinst/spotinst-sdk-go/spotinst/util/stringutil:go_default_library", "//vendor/github.com/spotinst/spotinst-sdk-go/spotinst/util/stringutil:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/klog/v2:go_default_library", "//vendor/k8s.io/klog/v2:go_default_library",
], ],
) )

View File

@ -44,7 +44,6 @@ type Elastigroup struct {
Name *string Name *string
Lifecycle fi.Lifecycle Lifecycle fi.Lifecycle
ID *string
Region *string Region *string
MinSize *int64 MinSize *int64
MaxSize *int64 MaxSize *int64
@ -68,7 +67,7 @@ type Elastigroup struct {
Subnets []*awstasks.Subnet Subnets []*awstasks.Subnet
SecurityGroups []*awstasks.SecurityGroup SecurityGroups []*awstasks.SecurityGroup
Monitoring *bool Monitoring *bool
AssociatePublicIP *bool AssociatePublicIPAddress *bool
Tenancy *string Tenancy *string
RootVolumeOpts *RootVolumeOpts RootVolumeOpts *RootVolumeOpts
AutoScalerOpts *AutoScalerOpts AutoScalerOpts *AutoScalerOpts
@ -164,26 +163,26 @@ func (e *Elastigroup) GetDependencies(tasks map[string]fi.Task) []fi.Task {
return deps return deps
} }
func (e *Elastigroup) find(svc spotinst.InstanceGroupService, name string) (*aws.Group, error) { func (e *Elastigroup) find(svc spotinst.InstanceGroupService) (*aws.Group, error) {
klog.V(4).Infof("Attempting to find Elastigroup: %q", name) klog.V(4).Infof("Attempting to find Elastigroup: %q", fi.StringValue(e.Name))
groups, err := svc.List(context.Background()) groups, err := svc.List(context.Background())
if err != nil { if err != nil {
return nil, fmt.Errorf("spotinst: failed to find elastigroup %s: %v", name, err) return nil, fmt.Errorf("spotinst: failed to find elastigroup %s: %v", fi.StringValue(e.Name), err)
} }
var out *aws.Group var out *aws.Group
for _, group := range groups { for _, group := range groups {
if group.Name() == name { if group.Name() == fi.StringValue(e.Name) {
out = group.Obj().(*aws.Group) out = group.Obj().(*aws.Group)
break break
} }
} }
if out == nil { if out == nil {
return nil, fmt.Errorf("spotinst: failed to find elastigroup %q", name) return nil, fmt.Errorf("spotinst: failed to find elastigroup %q", fi.StringValue(e.Name))
} }
klog.V(4).Infof("Elastigroup/%s: %s", name, stringutil.Stringify(out)) klog.V(4).Infof("Elastigroup/%s: %s", fi.StringValue(e.Name), stringutil.Stringify(out))
return out, nil return out, nil
} }
@ -192,13 +191,12 @@ var _ fi.HasCheckExisting = &Elastigroup{}
func (e *Elastigroup) Find(c *fi.Context) (*Elastigroup, error) { func (e *Elastigroup) Find(c *fi.Context) (*Elastigroup, error) {
cloud := c.Cloud.(awsup.AWSCloud) cloud := c.Cloud.(awsup.AWSCloud)
group, err := e.find(cloud.Spotinst().Elastigroup(), *e.Name) group, err := e.find(cloud.Spotinst().Elastigroup())
if err != nil { if err != nil {
return nil, err return nil, err
} }
actual := &Elastigroup{} actual := &Elastigroup{}
actual.ID = group.ID
actual.Name = group.Name actual.Name = group.Name
actual.Region = group.Region actual.Region = group.Region
@ -351,7 +349,7 @@ func (e *Elastigroup) Find(c *fi.Context) (*Elastigroup, error) {
} }
} }
actual.AssociatePublicIP = fi.Bool(associatePublicIP) actual.AssociatePublicIPAddress = fi.Bool(associatePublicIP)
} }
// Load balancers. // Load balancers.
@ -479,7 +477,7 @@ func (e *Elastigroup) Find(c *fi.Context) (*Elastigroup, error) {
func (e *Elastigroup) CheckExisting(c *fi.Context) bool { func (e *Elastigroup) CheckExisting(c *fi.Context) bool {
cloud := c.Cloud.(awsup.AWSCloud) cloud := c.Cloud.(awsup.AWSCloud)
group, err := e.find(cloud.Spotinst().Elastigroup(), *e.Name) group, err := e.find(cloud.Spotinst().Elastigroup())
return err == nil && group != nil return err == nil && group != nil
} }
@ -643,12 +641,12 @@ func (_ *Elastigroup) create(cloud awsup.AWSCloud, a, e, changes *Elastigroup) e
// Public IP. // Public IP.
{ {
if e.AssociatePublicIP != nil { if e.AssociatePublicIPAddress != nil {
iface := &aws.NetworkInterface{ iface := &aws.NetworkInterface{
Description: fi.String("eth0"), Description: fi.String("eth0"),
DeviceIndex: fi.Int(0), DeviceIndex: fi.Int(0),
DeleteOnTermination: fi.Bool(true), DeleteOnTermination: fi.Bool(true),
AssociatePublicIPAddress: e.AssociatePublicIP, AssociatePublicIPAddress: e.AssociatePublicIPAddress,
} }
group.Compute.LaunchSpecification.SetNetworkInterfaces([]*aws.NetworkInterface{iface}) group.Compute.LaunchSpecification.SetNetworkInterfaces([]*aws.NetworkInterface{iface})
@ -766,9 +764,8 @@ readyLoop:
} }
// Create the Elastigroup. // Create the Elastigroup.
id, err := cloud.Spotinst().Elastigroup().Create(context.Background(), eg) _, err = cloud.Spotinst().Elastigroup().Create(context.Background(), eg)
if err == nil { if err == nil {
e.ID = fi.String(id)
break break
} }
@ -795,7 +792,7 @@ readyLoop:
func (_ *Elastigroup) update(cloud awsup.AWSCloud, a, e, changes *Elastigroup) error { func (_ *Elastigroup) update(cloud awsup.AWSCloud, a, e, changes *Elastigroup) error {
klog.V(2).Infof("Updating Elastigroup %q", *e.Name) klog.V(2).Infof("Updating Elastigroup %q", *e.Name)
actual, err := e.find(cloud.Spotinst().Elastigroup(), *e.Name) actual, err := e.find(cloud.Spotinst().Elastigroup())
if err != nil { if err != nil {
klog.Errorf("Unable to resolve Elastigroup %q, error: %v", *e.Name, err) klog.Errorf("Unable to resolve Elastigroup %q, error: %v", *e.Name, err)
return err return err
@ -997,7 +994,7 @@ func (_ *Elastigroup) update(cloud awsup.AWSCloud, a, e, changes *Elastigroup) e
// Network interfaces. // Network interfaces.
{ {
if changes.AssociatePublicIP != nil { if changes.AssociatePublicIPAddress != nil {
if group.Compute == nil { if group.Compute == nil {
group.Compute = new(aws.Compute) group.Compute = new(aws.Compute)
} }
@ -1009,11 +1006,11 @@ func (_ *Elastigroup) update(cloud awsup.AWSCloud, a, e, changes *Elastigroup) e
Description: fi.String("eth0"), Description: fi.String("eth0"),
DeviceIndex: fi.Int(0), DeviceIndex: fi.Int(0),
DeleteOnTermination: fi.Bool(true), DeleteOnTermination: fi.Bool(true),
AssociatePublicIPAddress: changes.AssociatePublicIP, AssociatePublicIPAddress: changes.AssociatePublicIPAddress,
} }
group.Compute.LaunchSpecification.SetNetworkInterfaces([]*aws.NetworkInterface{iface}) group.Compute.LaunchSpecification.SetNetworkInterfaces([]*aws.NetworkInterface{iface})
changes.AssociatePublicIP = nil changes.AssociatePublicIPAddress = nil
changed = true changed = true
} }
} }
@ -1327,15 +1324,15 @@ func (_ *Elastigroup) update(cloud awsup.AWSCloud, a, e, changes *Elastigroup) e
empty := &Elastigroup{} empty := &Elastigroup{}
if !reflect.DeepEqual(empty, changes) { if !reflect.DeepEqual(empty, changes) {
klog.Warningf("Not all changes applied to Elastigroup %q: %v", *group.ID, changes) klog.Warningf("Not all changes applied to Elastigroup %q: %v", *e.Name, changes)
} }
if !changed { if !changed {
klog.V(2).Infof("No changes detected in Elastigroup %q", *group.ID) klog.V(2).Infof("No changes detected in Elastigroup %q", *e.Name)
return nil return nil
} }
klog.V(2).Infof("Updating Elastigroup %q (config: %s)", *group.ID, stringutil.Stringify(group)) klog.V(2).Infof("Updating Elastigroup %q (config: %s)", *e.Name, stringutil.Stringify(group))
// Wrap the raw object as an Elastigroup. // Wrap the raw object as an Elastigroup.
eg, err := spotinst.NewElastigroup(cloud.ProviderID(), group) eg, err := spotinst.NewElastigroup(cloud.ProviderID(), group)
@ -1572,12 +1569,12 @@ func (_ *Elastigroup) RenderTerraform(t *terraform.TerraformTarget, a, e, change
} }
// Public IP. // Public IP.
if e.AssociatePublicIP != nil { if e.AssociatePublicIPAddress != nil {
tf.NetworkInterfaces = append(tf.NetworkInterfaces, &terraformElastigroupNetworkInterface{ tf.NetworkInterfaces = append(tf.NetworkInterfaces, &terraformElastigroupNetworkInterface{
Description: fi.String("eth0"), Description: fi.String("eth0"),
DeviceIndex: fi.Int(0), DeviceIndex: fi.Int(0),
DeleteOnTermination: fi.Bool(true), DeleteOnTermination: fi.Bool(true),
AssociatePublicIPAddress: e.AssociatePublicIP, AssociatePublicIPAddress: e.AssociatePublicIPAddress,
}) })
} }

View File

@ -40,7 +40,6 @@ type LaunchSpec struct {
Name *string Name *string
Lifecycle fi.Lifecycle Lifecycle fi.Lifecycle
ID *string
SpotPercentage *int64 SpotPercentage *int64
UserData fi.Resource UserData fi.Resource
SecurityGroups []*awstasks.SecurityGroup SecurityGroups []*awstasks.SecurityGroup
@ -52,6 +51,9 @@ type LaunchSpec struct {
RootVolumeOpts *RootVolumeOpts RootVolumeOpts *RootVolumeOpts
AutoScalerOpts *AutoScalerOpts AutoScalerOpts *AutoScalerOpts
RestrictScaleDown *bool RestrictScaleDown *bool
AssociatePublicIPAddress *bool
MinSize *int64
MaxSize *int64
Ocean *Ocean Ocean *Ocean
} }
@ -127,7 +129,7 @@ var _ fi.HasCheckExisting = &LaunchSpec{}
func (o *LaunchSpec) Find(c *fi.Context) (*LaunchSpec, error) { func (o *LaunchSpec) Find(c *fi.Context) (*LaunchSpec, error) {
cloud := c.Cloud.(awsup.AWSCloud) cloud := c.Cloud.(awsup.AWSCloud)
ocean, err := o.Ocean.find(cloud.Spotinst().Ocean(), *o.Ocean.Name) ocean, err := o.Ocean.find(cloud.Spotinst().Ocean())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -138,14 +140,20 @@ func (o *LaunchSpec) Find(c *fi.Context) (*LaunchSpec, error) {
} }
actual := &LaunchSpec{} actual := &LaunchSpec{}
actual.ID = spec.ID
actual.Name = spec.Name actual.Name = spec.Name
actual.Ocean = &Ocean{ actual.Ocean = &Ocean{
ID: ocean.ID,
Name: ocean.Name, Name: ocean.Name,
} }
actual.RestrictScaleDown = spec.RestrictScaleDown actual.RestrictScaleDown = spec.RestrictScaleDown
// Capacity.
{
if spec.ResourceLimits != nil {
actual.MinSize = fi.Int64(int64(fi.IntValue(spec.ResourceLimits.MinInstanceCount)))
actual.MaxSize = fi.Int64(int64(fi.IntValue(spec.ResourceLimits.MaxInstanceCount)))
}
}
// Image. // Image.
{ {
actual.ImageID = spec.ImageID actual.ImageID = spec.ImageID
@ -164,17 +172,14 @@ func (o *LaunchSpec) Find(c *fi.Context) (*LaunchSpec, error) {
// User data. // User data.
{ {
var userData []byte
if spec.UserData != nil { if spec.UserData != nil {
userData, err = base64.StdEncoding.DecodeString(fi.StringValue(spec.UserData)) userData, err := base64.StdEncoding.DecodeString(fi.StringValue(spec.UserData))
if err != nil { if err != nil {
return nil, err return nil, err
} }
}
actual.UserData = fi.NewStringResource(string(userData)) actual.UserData = fi.NewStringResource(string(userData))
} }
}
// IAM instance profile. // IAM instance profile.
{ {
@ -243,6 +248,11 @@ func (o *LaunchSpec) Find(c *fi.Context) (*LaunchSpec, error) {
} }
} }
// Public IP.
if spec.AssociatePublicIPAddress != nil {
actual.AssociatePublicIPAddress = spec.AssociatePublicIPAddress
}
// Instance types. // Instance types.
{ {
if itypes := spec.InstanceTypes; itypes != nil { if itypes := spec.InstanceTypes; itypes != nil {
@ -308,9 +318,11 @@ func (o *LaunchSpec) Find(c *fi.Context) (*LaunchSpec, error) {
// Strategy. // Strategy.
{ {
if strategy := spec.Strategy; strategy != nil { if strategy := spec.Strategy; strategy != nil {
if strategy.SpotPercentage != nil {
actual.SpotPercentage = fi.Int64(int64(fi.IntValue(strategy.SpotPercentage))) actual.SpotPercentage = fi.Int64(int64(fi.IntValue(strategy.SpotPercentage)))
} }
} }
}
// Avoid spurious changes. // Avoid spurious changes.
actual.Lifecycle = o.Lifecycle actual.Lifecycle = o.Lifecycle
@ -347,7 +359,7 @@ func (o *LaunchSpec) createOrUpdate(cloud awsup.AWSCloud, a, e, changes *LaunchS
} }
func (_ *LaunchSpec) create(cloud awsup.AWSCloud, a, e, changes *LaunchSpec) error { func (_ *LaunchSpec) create(cloud awsup.AWSCloud, a, e, changes *LaunchSpec) error {
ocean, err := e.Ocean.find(cloud.Spotinst().Ocean(), *e.Ocean.Name) ocean, err := e.Ocean.find(cloud.Spotinst().Ocean())
if err != nil { if err != nil {
return err return err
} }
@ -361,6 +373,15 @@ func (_ *LaunchSpec) create(cloud awsup.AWSCloud, a, e, changes *LaunchSpec) err
spec.SetName(e.Name) spec.SetName(e.Name)
spec.SetOceanId(ocean.ID) spec.SetOceanId(ocean.ID)
// Capacity.
{
if e.MinSize != nil || e.MaxSize != nil {
spec.ResourceLimits = new(aws.ResourceLimits)
spec.ResourceLimits.SetMinInstanceCount(fi.Int(int(*e.MinSize)))
spec.ResourceLimits.SetMaxInstanceCount(fi.Int(int(*e.MaxSize)))
}
}
// Image. // Image.
{ {
if e.ImageID != nil { if e.ImageID != nil {
@ -432,6 +453,13 @@ func (_ *LaunchSpec) create(cloud awsup.AWSCloud, a, e, changes *LaunchSpec) err
} }
} }
// Public IP.
{
if e.AssociatePublicIPAddress != nil {
spec.SetAssociatePublicIPAddress(e.AssociatePublicIPAddress)
}
}
// Instance types. // Instance types.
{ {
if e.InstanceTypes != nil { if e.InstanceTypes != nil {
@ -511,19 +539,24 @@ func (_ *LaunchSpec) create(cloud awsup.AWSCloud, a, e, changes *LaunchSpec) err
} }
// Create a new LaunchSpec. // Create a new LaunchSpec.
id, err := cloud.Spotinst().LaunchSpec().Create(context.Background(), sp) _, err = cloud.Spotinst().LaunchSpec().Create(context.Background(), sp)
if err != nil { if err != nil {
return fmt.Errorf("spotinst: failed to create launch spec: %v", err) return fmt.Errorf("spotinst: failed to create launch spec: %v", err)
} }
e.ID = fi.String(id)
return nil return nil
} }
func (_ *LaunchSpec) update(cloud awsup.AWSCloud, a, e, changes *LaunchSpec) error { func (_ *LaunchSpec) update(cloud awsup.AWSCloud, a, e, changes *LaunchSpec) error {
klog.V(2).Infof("Updating Launch Spec for Ocean %q", *a.Ocean.ID) klog.V(2).Infof("Updating Launch Spec for Ocean %q", *a.Ocean.Name)
actual, err := e.find(cloud.Spotinst().LaunchSpec(), *a.Ocean.ID) ocean, err := a.Ocean.find(cloud.Spotinst().Ocean())
if err != nil {
klog.Errorf("Unable to resolve Ocean %q, error: %v", *a.Ocean.Name, err)
return err
}
actual, err := e.find(cloud.Spotinst().LaunchSpec(), *ocean.ID)
if err != nil { if err != nil {
klog.Errorf("Unable to resolve Launch Spec %q, error: %v", *e.Name, err) klog.Errorf("Unable to resolve Launch Spec %q, error: %v", *e.Name, err)
return err return err
@ -531,7 +564,29 @@ func (_ *LaunchSpec) update(cloud awsup.AWSCloud, a, e, changes *LaunchSpec) err
var changed bool var changed bool
spec := new(aws.LaunchSpec) spec := new(aws.LaunchSpec)
spec.SetId(a.ID) spec.SetId(actual.ID)
// Capacity.
{
if changes.MinSize != nil {
if spec.ResourceLimits == nil {
spec.ResourceLimits = new(aws.ResourceLimits)
}
spec.ResourceLimits.SetMinInstanceCount(fi.Int(int(*e.MinSize)))
changes.MinSize = nil
changed = true
}
if changes.MaxSize != nil {
if spec.ResourceLimits == nil {
spec.ResourceLimits = new(aws.ResourceLimits)
}
spec.ResourceLimits.SetMaxInstanceCount(fi.Int(int(*e.MaxSize)))
changes.MaxSize = nil
changed = true
}
}
// Image. // Image.
{ {
@ -625,6 +680,15 @@ func (_ *LaunchSpec) update(cloud awsup.AWSCloud, a, e, changes *LaunchSpec) err
} }
} }
// Public IP.
{
if changes.AssociatePublicIPAddress != nil {
spec.SetAssociatePublicIPAddress(e.AssociatePublicIPAddress)
changes.AssociatePublicIPAddress = nil
changed = true
}
}
// Instance types. // Instance types.
{ {
if changes.InstanceTypes != nil { if changes.InstanceTypes != nil {
@ -723,22 +787,17 @@ func (_ *LaunchSpec) update(cloud awsup.AWSCloud, a, e, changes *LaunchSpec) err
empty := &LaunchSpec{} empty := &LaunchSpec{}
if !reflect.DeepEqual(empty, changes) { if !reflect.DeepEqual(empty, changes) {
klog.Warningf("Not all changes applied to Launch Spec %q: %v", *spec.ID, changes) klog.Warningf("Not all changes applied to Launch Spec %q: %v", *e.Name, changes)
} }
if !changed { if !changed {
klog.V(2).Infof("No changes detected in Launch Spec %q", *spec.ID) klog.V(2).Infof("No changes detected in Launch Spec %q", *e.Name)
return nil return nil
} }
klog.V(2).Infof("Updating Launch Spec %q (config: %s)", *spec.ID, stringutil.Stringify(spec)) klog.V(2).Infof("Updating Launch Spec %q (config: %s)", *e.Name, stringutil.Stringify(spec))
ctx := context.Background() ctx := context.Background()
ocean, err := e.Ocean.find(cloud.Spotinst().Ocean(), *e.Ocean.Name)
if err != nil {
return err
}
// Reset the Spot percentage on the Cluster level. // Reset the Spot percentage on the Cluster level.
if spec.Strategy != nil && spec.Strategy.SpotPercentage != nil && if spec.Strategy != nil && spec.Strategy.SpotPercentage != nil &&
ocean.Strategy != nil && ocean.Strategy.SpotPercentage != nil { ocean.Strategy != nil && ocean.Strategy.SpotPercentage != nil {
@ -794,12 +853,18 @@ type terraformLaunchSpec struct {
Headrooms []*terraformAutoScalerHeadroom `cty:"autoscale_headrooms"` Headrooms []*terraformAutoScalerHeadroom `cty:"autoscale_headrooms"`
BlockDeviceMappings []*terraformBlockDeviceMapping `cty:"block_device_mappings"` BlockDeviceMappings []*terraformBlockDeviceMapping `cty:"block_device_mappings"`
Strategy *terraformLaunchSpecStrategy `cty:"strategy"` Strategy *terraformLaunchSpecStrategy `cty:"strategy"`
ResourceLimits *terraformLaunchSpecResourceLimits `cty:"resource_limits"`
} }
type terraformLaunchSpecStrategy struct { type terraformLaunchSpecStrategy struct {
SpotPercentage *int64 `cty:"spot_percentage"` SpotPercentage *int64 `cty:"spot_percentage"`
} }
type terraformLaunchSpecResourceLimits struct {
MinInstanceCount *int64 `cty:"min_instance_count"`
MaxInstanceCount *int64 `cty:"max_instance_count"`
}
type terraformBlockDeviceMapping struct { type terraformBlockDeviceMapping struct {
DeviceName *string `cty:"device_name"` DeviceName *string `cty:"device_name"`
EBS *terraformBlockDeviceMappingEBS `cty:"ebs"` EBS *terraformBlockDeviceMappingEBS `cty:"ebs"`
@ -821,6 +886,17 @@ func (_ *LaunchSpec) RenderTerraform(t *terraform.TerraformTarget, a, e, changes
Name: e.Name, Name: e.Name,
OceanID: e.Ocean.TerraformLink(), OceanID: e.Ocean.TerraformLink(),
InstanceTypes: e.InstanceTypes, InstanceTypes: e.InstanceTypes,
AssociatePublicIPAddress: e.AssociatePublicIPAddress,
}
// Capacity.
{
if e.MinSize != nil || e.MaxSize != nil {
tf.ResourceLimits = &terraformLaunchSpecResourceLimits{
MinInstanceCount: e.MinSize,
MaxInstanceCount: e.MaxSize,
}
}
} }
// Image. // Image.

View File

@ -24,10 +24,11 @@ import (
"strings" "strings"
"time" "time"
"k8s.io/klog"
"github.com/spotinst/spotinst-sdk-go/service/ocean/providers/aws" "github.com/spotinst/spotinst-sdk-go/service/ocean/providers/aws"
"github.com/spotinst/spotinst-sdk-go/spotinst/client" "github.com/spotinst/spotinst-sdk-go/spotinst/client"
"github.com/spotinst/spotinst-sdk-go/spotinst/util/stringutil" "github.com/spotinst/spotinst-sdk-go/spotinst/util/stringutil"
"k8s.io/klog/v2"
"k8s.io/kops/pkg/resources/spotinst" "k8s.io/kops/pkg/resources/spotinst"
"k8s.io/kops/upup/pkg/fi" "k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/awstasks" "k8s.io/kops/upup/pkg/fi/cloudup/awstasks"
@ -41,7 +42,6 @@ type Ocean struct {
Name *string Name *string
Lifecycle fi.Lifecycle Lifecycle fi.Lifecycle
ID *string
MinSize *int64 MinSize *int64
MaxSize *int64 MaxSize *int64
UtilizeReservedInstances *bool UtilizeReservedInstances *bool
@ -59,7 +59,8 @@ type Ocean struct {
Subnets []*awstasks.Subnet Subnets []*awstasks.Subnet
SecurityGroups []*awstasks.SecurityGroup SecurityGroups []*awstasks.SecurityGroup
Monitoring *bool Monitoring *bool
AssociatePublicIP *bool AssociatePublicIPAddress *bool
UseAsTemplateOnly *bool
RootVolumeOpts *RootVolumeOpts RootVolumeOpts *RootVolumeOpts
AutoScalerOpts *AutoScalerOpts AutoScalerOpts *AutoScalerOpts
} }
@ -104,26 +105,26 @@ func (o *Ocean) GetDependencies(tasks map[string]fi.Task) []fi.Task {
return deps return deps
} }
func (o *Ocean) find(svc spotinst.InstanceGroupService, name string) (*aws.Cluster, error) { func (o *Ocean) find(svc spotinst.InstanceGroupService) (*aws.Cluster, error) {
klog.V(4).Infof("Attempting to find Ocean: %q", name) klog.V(4).Infof("Attempting to find Ocean: %q", fi.StringValue(o.Name))
oceans, err := svc.List(context.Background()) oceans, err := svc.List(context.Background())
if err != nil { if err != nil {
return nil, fmt.Errorf("spotinst: failed to find ocean %q: %v", name, err) return nil, fmt.Errorf("spotinst: failed to find ocean %q: %v", fi.StringValue(o.Name), err)
} }
var out *aws.Cluster var out *aws.Cluster
for _, ocean := range oceans { for _, ocean := range oceans {
if ocean.Name() == name { if ocean.Name() == fi.StringValue(o.Name) {
out = ocean.Obj().(*aws.Cluster) out = ocean.Obj().(*aws.Cluster)
break break
} }
} }
if out == nil { if out == nil {
return nil, fmt.Errorf("spotinst: failed to find ocean %q", name) return nil, fmt.Errorf("spotinst: failed to find ocean %q", fi.StringValue(o.Name))
} }
klog.V(4).Infof("Ocean/%s: %s", name, stringutil.Stringify(out)) klog.V(4).Infof("Ocean/%s: %s", fi.StringValue(o.Name), stringutil.Stringify(out))
return out, nil return out, nil
} }
@ -132,20 +133,21 @@ var _ fi.HasCheckExisting = &Ocean{}
func (o *Ocean) Find(c *fi.Context) (*Ocean, error) { func (o *Ocean) Find(c *fi.Context) (*Ocean, error) {
cloud := c.Cloud.(awsup.AWSCloud) cloud := c.Cloud.(awsup.AWSCloud)
ocean, err := o.find(cloud.Spotinst().Ocean(), *o.Name) ocean, err := o.find(cloud.Spotinst().Ocean())
if err != nil { if err != nil {
return nil, err return nil, err
} }
actual := &Ocean{} actual := &Ocean{}
actual.ID = ocean.ID
actual.Name = ocean.Name actual.Name = ocean.Name
// Capacity. // Capacity.
{ {
if !fi.BoolValue(ocean.Compute.LaunchSpecification.UseAsTemplateOnly) {
actual.MinSize = fi.Int64(int64(fi.IntValue(ocean.Capacity.Minimum))) actual.MinSize = fi.Int64(int64(fi.IntValue(ocean.Capacity.Minimum)))
actual.MaxSize = fi.Int64(int64(fi.IntValue(ocean.Capacity.Maximum))) actual.MaxSize = fi.Int64(int64(fi.IntValue(ocean.Capacity.Maximum)))
} }
}
// Strategy. // Strategy.
{ {
@ -239,17 +241,14 @@ func (o *Ocean) Find(c *fi.Context) (*Ocean, error) {
// User data. // User data.
{ {
var userData []byte
if lc.UserData != nil { if lc.UserData != nil {
userData, err = base64.StdEncoding.DecodeString(fi.StringValue(lc.UserData)) userData, err := base64.StdEncoding.DecodeString(fi.StringValue(lc.UserData))
if err != nil { if err != nil {
return nil, err return nil, err
} }
}
actual.UserData = fi.NewStringResource(string(userData)) actual.UserData = fi.NewStringResource(string(userData))
} }
}
// EBS optimization. // EBS optimization.
{ {
@ -257,7 +256,6 @@ func (o *Ocean) Find(c *fi.Context) (*Ocean, error) {
if actual.RootVolumeOpts == nil { if actual.RootVolumeOpts == nil {
actual.RootVolumeOpts = new(RootVolumeOpts) actual.RootVolumeOpts = new(RootVolumeOpts)
} }
actual.RootVolumeOpts.Optimization = lc.EBSOptimized actual.RootVolumeOpts.Optimization = lc.EBSOptimized
} }
} }
@ -274,7 +272,7 @@ func (o *Ocean) Find(c *fi.Context) (*Ocean, error) {
// Public IP. // Public IP.
if lc.AssociatePublicIPAddress != nil { if lc.AssociatePublicIPAddress != nil {
actual.AssociatePublicIP = lc.AssociatePublicIPAddress actual.AssociatePublicIPAddress = lc.AssociatePublicIPAddress
} }
// Root volume options. // Root volume options.
@ -287,6 +285,11 @@ func (o *Ocean) Find(c *fi.Context) (*Ocean, error) {
if lc.Monitoring != nil { if lc.Monitoring != nil {
actual.Monitoring = lc.Monitoring actual.Monitoring = lc.Monitoring
} }
// Template.
if lc.UseAsTemplateOnly != nil {
actual.UseAsTemplateOnly = lc.UseAsTemplateOnly
}
} }
// Auto Scaler. // Auto Scaler.
@ -325,7 +328,7 @@ func (o *Ocean) Find(c *fi.Context) (*Ocean, error) {
func (o *Ocean) CheckExisting(c *fi.Context) bool { func (o *Ocean) CheckExisting(c *fi.Context) bool {
cloud := c.Cloud.(awsup.AWSCloud) cloud := c.Cloud.(awsup.AWSCloud)
ocean, err := o.find(cloud.Spotinst().Ocean(), *o.Name) ocean, err := o.find(cloud.Spotinst().Ocean())
return err == nil && ocean != nil return err == nil && ocean != nil
} }
@ -354,7 +357,6 @@ func (o *Ocean) createOrUpdate(cloud awsup.AWSCloud, a, e, changes *Ocean) error
func (_ *Ocean) create(cloud awsup.AWSCloud, a, e, changes *Ocean) error { func (_ *Ocean) create(cloud awsup.AWSCloud, a, e, changes *Ocean) error {
klog.V(2).Infof("Creating Ocean %q", *e.Name) klog.V(2).Infof("Creating Ocean %q", *e.Name)
e.applyDefaults()
ocean := &aws.Cluster{ ocean := &aws.Cluster{
Capacity: new(aws.Capacity), Capacity: new(aws.Capacity),
@ -372,10 +374,12 @@ func (_ *Ocean) create(cloud awsup.AWSCloud, a, e, changes *Ocean) error {
// Capacity. // Capacity.
{ {
if !fi.BoolValue(e.UseAsTemplateOnly) {
ocean.Capacity.SetTarget(fi.Int(int(*e.MinSize))) ocean.Capacity.SetTarget(fi.Int(int(*e.MinSize)))
ocean.Capacity.SetMinimum(fi.Int(int(*e.MinSize))) ocean.Capacity.SetMinimum(fi.Int(int(*e.MinSize)))
ocean.Capacity.SetMaximum(fi.Int(int(*e.MaxSize))) ocean.Capacity.SetMaximum(fi.Int(int(*e.MaxSize)))
} }
}
// Strategy. // Strategy.
{ {
@ -426,6 +430,7 @@ func (_ *Ocean) create(cloud awsup.AWSCloud, a, e, changes *Ocean) error {
// Launch specification. // Launch specification.
{ {
ocean.Compute.LaunchSpecification.SetUseAsTemplateOnly(e.UseAsTemplateOnly)
ocean.Compute.LaunchSpecification.SetMonitoring(e.Monitoring) ocean.Compute.LaunchSpecification.SetMonitoring(e.Monitoring)
ocean.Compute.LaunchSpecification.SetKeyPair(e.SSHKey.Name) ocean.Compute.LaunchSpecification.SetKeyPair(e.SSHKey.Name)
@ -440,6 +445,18 @@ func (_ *Ocean) create(cloud awsup.AWSCloud, a, e, changes *Ocean) error {
} }
} }
// Security groups.
{
if e.SecurityGroups != nil {
securityGroupIDs := make([]string, len(e.SecurityGroups))
for i, sg := range e.SecurityGroups {
securityGroupIDs[i] = *sg.ID
}
ocean.Compute.LaunchSpecification.SetSecurityGroupIDs(securityGroupIDs)
}
}
if !fi.BoolValue(e.UseAsTemplateOnly) {
// User data. // User data.
{ {
if e.UserData != nil { if e.UserData != nil {
@ -464,24 +481,6 @@ func (_ *Ocean) create(cloud awsup.AWSCloud, a, e, changes *Ocean) error {
} }
} }
// Security groups.
{
if e.SecurityGroups != nil {
securityGroupIDs := make([]string, len(e.SecurityGroups))
for i, sg := range e.SecurityGroups {
securityGroupIDs[i] = *sg.ID
}
ocean.Compute.LaunchSpecification.SetSecurityGroupIDs(securityGroupIDs)
}
}
// Public IP.
{
if e.AssociatePublicIP != nil {
ocean.Compute.LaunchSpecification.SetAssociatePublicIPAddress(e.AssociatePublicIP)
}
}
// Root volume options. // Root volume options.
{ {
if opts := e.RootVolumeOpts; opts != nil { if opts := e.RootVolumeOpts; opts != nil {
@ -498,6 +497,13 @@ func (_ *Ocean) create(cloud awsup.AWSCloud, a, e, changes *Ocean) error {
} }
} }
// Public IP.
{
if e.AssociatePublicIPAddress != nil {
ocean.Compute.LaunchSpecification.SetAssociatePublicIPAddress(e.AssociatePublicIPAddress)
}
}
// Tags. // Tags.
{ {
if e.Tags != nil { if e.Tags != nil {
@ -505,6 +511,8 @@ func (_ *Ocean) create(cloud awsup.AWSCloud, a, e, changes *Ocean) error {
} }
} }
} }
}
} }
// Auto Scaler. // Auto Scaler.
@ -559,9 +567,8 @@ readyLoop:
} }
// Create a new Ocean. // Create a new Ocean.
id, err := cloud.Spotinst().Ocean().Create(context.Background(), oc) _, err = cloud.Spotinst().Ocean().Create(context.Background(), oc)
if err == nil { if err == nil {
e.ID = fi.String(id)
break break
} }
@ -588,7 +595,7 @@ readyLoop:
func (_ *Ocean) update(cloud awsup.AWSCloud, a, e, changes *Ocean) error { func (_ *Ocean) update(cloud awsup.AWSCloud, a, e, changes *Ocean) error {
klog.V(2).Infof("Updating Ocean %q", *e.Name) klog.V(2).Infof("Updating Ocean %q", *e.Name)
actual, err := e.find(cloud.Spotinst().Ocean(), *e.Name) actual, err := e.find(cloud.Spotinst().Ocean())
if err != nil { if err != nil {
klog.Errorf("Unable to resolve Ocean %q, error: %s", *e.Name, err) klog.Errorf("Unable to resolve Ocean %q, error: %s", *e.Name, err)
return err return err
@ -734,6 +741,79 @@ func (_ *Ocean) update(cloud awsup.AWSCloud, a, e, changes *Ocean) error {
} }
} }
// Image.
{
if changes.ImageID != nil {
image, err := resolveImage(cloud, fi.StringValue(e.ImageID))
if err != nil {
return err
}
if *actual.Compute.LaunchSpecification.ImageID != *image.ImageId {
if ocean.Compute == nil {
ocean.Compute = new(aws.Compute)
}
if ocean.Compute.LaunchSpecification == nil {
ocean.Compute.LaunchSpecification = new(aws.LaunchSpecification)
}
ocean.Compute.LaunchSpecification.SetImageId(image.ImageId)
changed = true
}
changes.ImageID = nil
}
}
// Monitoring.
{
if changes.Monitoring != nil {
if ocean.Compute == nil {
ocean.Compute = new(aws.Compute)
}
if ocean.Compute.LaunchSpecification == nil {
ocean.Compute.LaunchSpecification = new(aws.LaunchSpecification)
}
ocean.Compute.LaunchSpecification.SetMonitoring(e.Monitoring)
changes.Monitoring = nil
changed = true
}
}
// Template.
{
if changes.UseAsTemplateOnly != nil {
if ocean.Compute == nil {
ocean.Compute = new(aws.Compute)
}
if ocean.Compute.LaunchSpecification == nil {
ocean.Compute.LaunchSpecification = new(aws.LaunchSpecification)
}
ocean.Compute.LaunchSpecification.SetUseAsTemplateOnly(e.UseAsTemplateOnly)
changes.UseAsTemplateOnly = nil
changed = true
}
}
// SSH key.
{
if changes.SSHKey != nil {
if ocean.Compute == nil {
ocean.Compute = new(aws.Compute)
}
if ocean.Compute.LaunchSpecification == nil {
ocean.Compute.LaunchSpecification = new(aws.LaunchSpecification)
}
ocean.Compute.LaunchSpecification.SetKeyPair(e.SSHKey.Name)
changes.SSHKey = nil
changed = true
}
}
if !fi.BoolValue(e.UseAsTemplateOnly) {
// User data. // User data.
{ {
if changes.UserData != nil { if changes.UserData != nil {
@ -759,30 +839,6 @@ func (_ *Ocean) update(cloud awsup.AWSCloud, a, e, changes *Ocean) error {
} }
} }
// Image.
{
if changes.ImageID != nil {
image, err := resolveImage(cloud, fi.StringValue(e.ImageID))
if err != nil {
return err
}
if *actual.Compute.LaunchSpecification.ImageID != *image.ImageId {
if ocean.Compute == nil {
ocean.Compute = new(aws.Compute)
}
if ocean.Compute.LaunchSpecification == nil {
ocean.Compute.LaunchSpecification = new(aws.LaunchSpecification)
}
ocean.Compute.LaunchSpecification.SetImageId(image.ImageId)
changed = true
}
changes.ImageID = nil
}
}
// Tags. // Tags.
{ {
if changes.Tags != nil { if changes.Tags != nil {
@ -818,41 +874,9 @@ func (_ *Ocean) update(cloud awsup.AWSCloud, a, e, changes *Ocean) error {
} }
} }
// Monitoring.
{
if changes.Monitoring != nil {
if ocean.Compute == nil {
ocean.Compute = new(aws.Compute)
}
if ocean.Compute.LaunchSpecification == nil {
ocean.Compute.LaunchSpecification = new(aws.LaunchSpecification)
}
ocean.Compute.LaunchSpecification.SetMonitoring(e.Monitoring)
changes.Monitoring = nil
changed = true
}
}
// SSH key.
{
if changes.SSHKey != nil {
if ocean.Compute == nil {
ocean.Compute = new(aws.Compute)
}
if ocean.Compute.LaunchSpecification == nil {
ocean.Compute.LaunchSpecification = new(aws.LaunchSpecification)
}
ocean.Compute.LaunchSpecification.SetKeyPair(e.SSHKey.Name)
changes.SSHKey = nil
changed = true
}
}
// Public IP. // Public IP.
{ {
if changes.AssociatePublicIP != nil { if changes.AssociatePublicIPAddress != nil {
if ocean.Compute == nil { if ocean.Compute == nil {
ocean.Compute = new(aws.Compute) ocean.Compute = new(aws.Compute)
} }
@ -860,8 +884,8 @@ func (_ *Ocean) update(cloud awsup.AWSCloud, a, e, changes *Ocean) error {
ocean.Compute.LaunchSpecification = new(aws.LaunchSpecification) ocean.Compute.LaunchSpecification = new(aws.LaunchSpecification)
} }
ocean.Compute.LaunchSpecification.SetAssociatePublicIPAddress(e.AssociatePublicIP) ocean.Compute.LaunchSpecification.SetAssociatePublicIPAddress(e.AssociatePublicIPAddress)
changes.AssociatePublicIP = nil changes.AssociatePublicIPAddress = nil
changed = true changed = true
} }
} }
@ -901,9 +925,11 @@ func (_ *Ocean) update(cloud awsup.AWSCloud, a, e, changes *Ocean) error {
} }
} }
} }
}
// Capacity. // Capacity.
{ {
if !fi.BoolValue(e.UseAsTemplateOnly) {
if changes.MinSize != nil { if changes.MinSize != nil {
if ocean.Capacity == nil { if ocean.Capacity == nil {
ocean.Capacity = new(aws.Capacity) ocean.Capacity = new(aws.Capacity)
@ -928,6 +954,7 @@ func (_ *Ocean) update(cloud awsup.AWSCloud, a, e, changes *Ocean) error {
changed = true changed = true
} }
} }
}
// Auto Scaler. // Auto Scaler.
{ {
@ -969,15 +996,15 @@ func (_ *Ocean) update(cloud awsup.AWSCloud, a, e, changes *Ocean) error {
empty := &Ocean{} empty := &Ocean{}
if !reflect.DeepEqual(empty, changes) { if !reflect.DeepEqual(empty, changes) {
klog.Warningf("Not all changes applied to Ocean %q: %v", *ocean.ID, changes) klog.Warningf("Not all changes applied to Ocean %q: %v", *e.Name, changes)
} }
if !changed { if !changed {
klog.V(2).Infof("No changes detected in Ocean %q", *ocean.ID) klog.V(2).Infof("No changes detected in Ocean %q", *e.Name)
return nil return nil
} }
klog.V(2).Infof("Updating Ocean %q (config: %s)", *ocean.ID, stringutil.Stringify(ocean)) klog.V(2).Infof("Updating Ocean %q (config: %s)", *e.Name, stringutil.Stringify(ocean))
// Wrap the raw object as an Ocean. // Wrap the raw object as an Ocean.
oc, err := spotinst.NewOcean(cloud.ProviderID(), ocean) oc, err := spotinst.NewOcean(cloud.ProviderID(), ocean)
@ -1013,6 +1040,7 @@ type terraformOcean struct {
DrainingTimeout *int64 `cty:"draining_timeout"` DrainingTimeout *int64 `cty:"draining_timeout"`
GracePeriod *int64 `cty:"grace_period"` GracePeriod *int64 `cty:"grace_period"`
UseAsTemplateOnly *bool `cty:"use_as_template_only"`
Monitoring *bool `cty:"monitoring"` Monitoring *bool `cty:"monitoring"`
EBSOptimized *bool `cty:"ebs_optimized"` EBSOptimized *bool `cty:"ebs_optimized"`
ImageID *string `cty:"image_id"` ImageID *string `cty:"image_id"`
@ -1026,16 +1054,11 @@ type terraformOcean struct {
func (_ *Ocean) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *Ocean) error { func (_ *Ocean) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *Ocean) error {
cloud := t.Cloud.(awsup.AWSCloud) cloud := t.Cloud.(awsup.AWSCloud)
e.applyDefaults()
tf := &terraformOcean{ tf := &terraformOcean{
Name: e.Name, Name: e.Name,
Region: fi.String(cloud.Region()), Region: fi.String(cloud.Region()),
UseAsTemplateOnly: e.UseAsTemplateOnly,
DesiredCapacity: e.MinSize,
MinSize: e.MinSize,
MaxSize: e.MaxSize,
FallbackToOnDemand: e.FallbackToOnDemand, FallbackToOnDemand: e.FallbackToOnDemand,
UtilizeReservedInstances: e.UtilizeReservedInstances, UtilizeReservedInstances: e.UtilizeReservedInstances,
UtilizeCommitments: e.UtilizeCommitments, UtilizeCommitments: e.UtilizeCommitments,
@ -1075,39 +1098,6 @@ func (_ *Ocean) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *Oce
} }
} }
// User data.
if e.UserData != nil {
var err error
tf.UserData, err = t.AddFileResource("spotinst_ocean_aws", *e.Name, "user_data", e.UserData, false)
if err != nil {
return err
}
}
// Public IP.
if e.AssociatePublicIP != nil {
tf.AssociatePublicIPAddress = e.AssociatePublicIP
}
// Root volume options.
if opts := e.RootVolumeOpts; opts != nil {
// Volume size.
if opts.Size != nil {
tf.RootVolumeSize = opts.Size
}
// EBS optimization.
if opts.Optimization != nil {
tf.EBSOptimized = opts.Optimization
}
}
// IAM instance profile.
if e.IAMInstanceProfile != nil {
tf.IAMInstanceProfile = e.IAMInstanceProfile.TerraformLink()
}
// Monitoring. // Monitoring.
if e.Monitoring != nil { if e.Monitoring != nil {
tf.Monitoring = e.Monitoring tf.Monitoring = e.Monitoring
@ -1175,8 +1165,46 @@ func (_ *Ocean) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *Oce
} }
} }
if !fi.BoolValue(tf.UseAsTemplateOnly) {
// Capacity.
tf.DesiredCapacity = e.MinSize
tf.MinSize = e.MinSize
tf.MaxSize = e.MaxSize
// Root volume options.
if opts := e.RootVolumeOpts; opts != nil {
// Volume size.
if opts.Size != nil {
tf.RootVolumeSize = opts.Size
}
// EBS optimization.
if opts.Optimization != nil {
tf.EBSOptimized = opts.Optimization
}
}
// IAM instance profile.
if e.IAMInstanceProfile != nil {
tf.IAMInstanceProfile = e.IAMInstanceProfile.TerraformLink()
}
// User data.
if e.UserData != nil {
var err error
tf.UserData, err = t.AddFileResource("spotinst_ocean_aws", *e.Name, "user_data", e.UserData, false)
if err != nil {
return err
}
}
// Public IP.
if e.AssociatePublicIPAddress != nil {
tf.AssociatePublicIPAddress = e.AssociatePublicIPAddress
}
// Tags. // Tags.
{
if e.Tags != nil { if e.Tags != nil {
for _, tag := range e.buildTags() { for _, tag := range e.buildTags() {
tf.Tags = append(tf.Tags, &terraformKV{ tf.Tags = append(tf.Tags, &terraformKV{
@ -1206,17 +1234,3 @@ func (o *Ocean) buildTags() []*aws.Tag {
return tags return tags
} }
func (o *Ocean) applyDefaults() {
if o.FallbackToOnDemand == nil {
o.FallbackToOnDemand = fi.Bool(true)
}
if o.UtilizeReservedInstances == nil {
o.UtilizeReservedInstances = fi.Bool(true)
}
if o.Monitoring == nil {
o.Monitoring = fi.Bool(false)
}
}

View File

@ -426,6 +426,15 @@ type Scaling struct {
Up []*ScalingPolicy `json:"up,omitempty"` Up []*ScalingPolicy `json:"up,omitempty"`
Down []*ScalingPolicy `json:"down,omitempty"` Down []*ScalingPolicy `json:"down,omitempty"`
Target []*ScalingPolicy `json:"target,omitempty"` Target []*ScalingPolicy `json:"target,omitempty"`
MultipleMetrics *MultipleMetrics `json:"multipleMetrics,omitempty"`
forceSendFields []string
nullFields []string
}
type MultipleMetrics struct {
Metrics []*Metrics `json:"metrics,omitempty"`
Expressions []*Expressions `json:"expressions,omitempty"`
forceSendFields []string forceSendFields []string
nullFields []string nullFields []string
@ -452,6 +461,28 @@ type ScalingPolicy struct {
IsEnabled *bool `json:"isEnabled,omitempty"` IsEnabled *bool `json:"isEnabled,omitempty"`
MaxCapacityPerScale *string `json:"maxCapacityPerScale,omitempty"` MaxCapacityPerScale *string `json:"maxCapacityPerScale,omitempty"`
Predictive *Predictive `json:"predictive,omitempty"` Predictive *Predictive `json:"predictive,omitempty"`
StepAdjustments []*StepAdjustment `json:"stepAdjustments,omitempty"`
forceSendFields []string
nullFields []string
}
type Metrics struct {
Name *string `json:"name,omitempty"`
MetricName *string `json:"metricName,omitempty"`
Namespace *string `json:"namespace,omitempty"`
Dimensions []*Dimension `json:"dimensions,omitempty"`
ExtendedStatistic *string `json:"extendedStatistic,omitempty"`
Statistic *string `json:"statistic,omitempty"`
Unit *string `json:"unit,omitempty"`
forceSendFields []string
nullFields []string
}
type Expressions struct {
Expression *string `json:"expression,omitempty"`
Name *string `json:"name,omitempty"`
forceSendFields []string forceSendFields []string
nullFields []string nullFields []string
@ -485,6 +516,14 @@ type Predictive struct {
nullFields []string nullFields []string
} }
type StepAdjustment struct {
Action *Action `json:"action,omitempty"`
Threshold *int `json:"threshold,omitempty"`
forceSendFields []string
nullFields []string
}
type Strategy struct { type Strategy struct {
Risk *float64 `json:"risk,omitempty"` Risk *float64 `json:"risk,omitempty"`
OnDemandCount *int `json:"onDemandCount,omitempty"` OnDemandCount *int `json:"onDemandCount,omitempty"`
@ -620,6 +659,71 @@ type LaunchSpecification struct {
Tags []*Tag `json:"tags,omitempty"` Tags []*Tag `json:"tags,omitempty"`
MetadataOptions *MetadataOptions `json:"metadataOptions,omitempty"` MetadataOptions *MetadataOptions `json:"metadataOptions,omitempty"`
CPUOptions *CPUOptions `json:"cpuOptions,omitempty"` CPUOptions *CPUOptions `json:"cpuOptions,omitempty"`
ResourceTagSpecification *ResourceTagSpecification `json:"resourceTagSpecification,omitempty"`
ITF *ITF `json:"itf,omitempty"`
forceSendFields []string
nullFields []string
}
type ITF struct {
LoadBalancers []*ITFLoadBalancer `json:"loadBalancers,omitempty"`
MigrationHealthinessThreshold *int `json:"migrationHealthinessThreshold,omitempty"`
FixedTargetGroups *bool `json:"fixedTargetGroups,omitempty"`
WeightStrategy *string `json:"weightStrategy,omitempty"`
TargetGroupConfig *TargetGroupConfig `json:"targetGroupConfig,omitempty"`
DefaultStaticTargetGroups []*StaticTargetGroup `json:"defaultStaticTargetGroups,omitempty"`
forceSendFields []string
nullFields []string
}
type ITFLoadBalancer struct {
ListenerRules []*ListenerRule `json:"listenerRules,omitempty"`
LoadBalancerARN *string `json:"loadBalancerArn,omitempty"`
forceSendFields []string
nullFields []string
}
type ListenerRule struct {
RuleARN *string `json:"ruleArn,omitempty"`
StaticTargetGroups []*StaticTargetGroup `json:"staticTargetGroups,omitempty"`
forceSendFields []string
nullFields []string
}
type StaticTargetGroup struct {
StaticTargetGroupARN *string `json:"arn,omitempty"`
Percentage *float64 `json:"percentage,omitempty"`
forceSendFields []string
nullFields []string
}
type TargetGroupConfig struct {
VPCID *string `json:"vpcId,omitempty"`
HealthCheckIntervalSeconds *int `json:"healthCheckIntervalSeconds,omitempty"`
HealthCheckPath *string `json:"healthCheckPath,omitempty"`
HealthCheckPort *string `json:"healthCheckPort,omitempty"`
HealthCheckProtocol *string `json:"healthCheckProtocol,omitempty"`
HealthCheckTimeoutSeconds *int `json:"healthCheckTimeoutSeconds,omitempty"`
HealthyThresholdCount *int `json:"healthyThresholdCount,omitempty"`
UnhealthyThresholdCount *int `json:"unhealthyThresholdCount,omitempty"`
Port *int `json:"port,omitempty"`
Protocol *string `json:"protocol,omitempty"`
ProtocolVersion *string `json:"protocolVersion,omitempty"`
Matcher *Matcher `json:"matcher,omitempty"`
Tags []*Tag `json:"tags,omitempty"`
forceSendFields []string
nullFields []string
}
type Matcher struct {
HTTPCode *string `json:"httpCode,omitempty"`
GRPCCode *string `json:"grpcCode,omitempty"`
forceSendFields []string forceSendFields []string
nullFields []string nullFields []string
@ -640,6 +744,44 @@ type CPUOptions struct {
nullFields []string nullFields []string
} }
type ResourceTagSpecification struct {
Volumes *Volumes `json:"volumes,omitempty"`
Snapshots *Snapshots `json:"snapshots,omitempty"`
ENIs *ENIs `json:"enis,omitempty"`
AMIs *AMIs `json:"amis,omitempty"`
forceSendFields []string
nullFields []string
}
type Volumes struct {
ShouldTag *bool `json:"shouldTag,omitempty"`
forceSendFields []string
nullFields []string
}
type Snapshots struct {
ShouldTag *bool `json:"shouldTag,omitempty"`
forceSendFields []string
nullFields []string
}
type ENIs struct {
ShouldTag *bool `json:"shouldTag,omitempty"`
forceSendFields []string
nullFields []string
}
type AMIs struct {
ShouldTag *bool `json:"shouldTag,omitempty"`
forceSendFields []string
nullFields []string
}
type LoadBalancersConfig struct { type LoadBalancersConfig struct {
LoadBalancers []*LoadBalancer `json:"loadBalancers,omitempty"` LoadBalancers []*LoadBalancer `json:"loadBalancers,omitempty"`
@ -2918,6 +3060,13 @@ func (o *Scaling) SetTarget(v []*ScalingPolicy) *Scaling {
return o return o
} }
func (o *Scaling) SetMultipleMetrics(v *MultipleMetrics) *Scaling {
if o.MultipleMetrics = v; o.MultipleMetrics == nil {
o.nullFields = append(o.nullFields, "MultipleMetrics")
}
return o
}
// endregion // endregion
// region ScalingPolicy // region ScalingPolicy
@ -3068,6 +3217,120 @@ func (o *ScalingPolicy) SetMaxCapacityPerScale(v *string) *ScalingPolicy {
return o return o
} }
func (o *ScalingPolicy) SetStepAdjustments(v []*StepAdjustment) *ScalingPolicy {
if o.StepAdjustments = v; o.StepAdjustments == nil {
o.nullFields = append(o.nullFields, "StepAdjustments")
}
return o
}
// endregion
// region MultipleMetrics
func (o MultipleMetrics) MarshalJSON() ([]byte, error) {
type noMethod MultipleMetrics
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *MultipleMetrics) SetExpressions(v []*Expressions) *MultipleMetrics {
if o.Expressions = v; o.Expressions == nil {
o.nullFields = append(o.nullFields, "Expressions")
}
return o
}
func (o *MultipleMetrics) SetMetrics(v []*Metrics) *MultipleMetrics {
if o.Metrics = v; o.Metrics == nil {
o.nullFields = append(o.nullFields, "Metrics")
}
return o
}
// endregion
// region Metrics
func (o Metrics) MarshalJSON() ([]byte, error) {
type noMethod Metrics
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *Metrics) SetMetricName(v *string) *Metrics {
if o.MetricName = v; o.MetricName == nil {
o.nullFields = append(o.nullFields, "MetricName")
}
return o
}
func (o *Metrics) SetNamespace(v *string) *Metrics {
if o.Namespace = v; o.Namespace == nil {
o.nullFields = append(o.nullFields, "Namespace")
}
return o
}
func (o *Metrics) SetDimensions(v []*Dimension) *Metrics {
if o.Dimensions = v; o.Dimensions == nil {
o.nullFields = append(o.nullFields, "Dimensions")
}
return o
}
func (o *Metrics) SetName(v *string) *Metrics {
if o.Name = v; o.Name == nil {
o.nullFields = append(o.nullFields, "Name")
}
return o
}
func (o *Metrics) SetExtendedStatistic(v *string) *Metrics {
if o.ExtendedStatistic = v; o.ExtendedStatistic == nil {
o.nullFields = append(o.nullFields, "ExtendedStatistic")
}
return o
}
func (o *Metrics) SetStatistic(v *string) *Metrics {
if o.Statistic = v; o.Statistic == nil {
o.nullFields = append(o.nullFields, "Statistic")
}
return o
}
func (o *Metrics) SetUnit(v *string) *Metrics {
if o.Unit = v; o.Unit == nil {
o.nullFields = append(o.nullFields, "Unit")
}
return o
}
// endregion
// region Expression
func (o Expressions) MarshalJSON() ([]byte, error) {
type noMethod Expressions
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *Expressions) SetExpression(v *string) *Expressions {
if o.Expression = v; o.Expression == nil {
o.nullFields = append(o.nullFields, "Expression")
}
return o
}
func (o *Expressions) SetName(v *string) *Expressions {
if o.Name = v; o.Name == nil {
o.nullFields = append(o.nullFields, "Name")
}
return o
}
// endregion // endregion
// region Action // region Action
@ -3170,6 +3433,30 @@ func (o *Predictive) SetMode(v *string) *Predictive {
// endregion // endregion
// region StepAdjustments
func (o StepAdjustment) MarshalJSON() ([]byte, error) {
type noMethod StepAdjustment
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *StepAdjustment) SetAction(v *Action) *StepAdjustment {
if o.Action = v; o.Action == nil {
o.nullFields = append(o.nullFields, "Action")
}
return o
}
func (o *StepAdjustment) SetThreshold(v *int) *StepAdjustment {
if o.Threshold = v; o.Threshold == nil {
o.nullFields = append(o.nullFields, "Threshold")
}
return o
}
// endregion
// region Strategy // region Strategy
func (o Strategy) MarshalJSON() ([]byte, error) { func (o Strategy) MarshalJSON() ([]byte, error) {
@ -3766,6 +4053,267 @@ func (o *LaunchSpecification) SetCPUOptions(v *CPUOptions) *LaunchSpecification
return o return o
} }
func (o *LaunchSpecification) SetResourceTagSpecification(v *ResourceTagSpecification) *LaunchSpecification {
if o.ResourceTagSpecification = v; o.ResourceTagSpecification == nil {
o.nullFields = append(o.nullFields, "ResourceTagSpecification")
}
return o
}
func (o *LaunchSpecification) SetITF(v *ITF) *LaunchSpecification {
if o.ITF = v; o.ITF == nil {
o.nullFields = append(o.nullFields, "ITF")
}
return o
}
// endregion
// region Matcher
func (o Matcher) MarshalJSON() ([]byte, error) {
type noMethod Matcher
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *Matcher) SetHTTPCode(v *string) *Matcher {
if o.HTTPCode = v; o.HTTPCode == nil {
o.nullFields = append(o.nullFields, "HTTPCode")
}
return o
}
func (o *Matcher) SetGRPCCode(v *string) *Matcher {
if o.GRPCCode = v; o.GRPCCode == nil {
o.nullFields = append(o.nullFields, "GRPCCode")
}
return o
}
// endregion
// region ITF
func (o ITF) MarshalJSON() ([]byte, error) {
type noMethod ITF
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *ITF) SetLoadBalancers(v []*ITFLoadBalancer) *ITF {
if o.LoadBalancers = v; o.LoadBalancers == nil {
o.nullFields = append(o.nullFields, "LoadBalancers")
}
return o
}
func (o *ITF) SetMigrationHealthinessThreshold(v *int) *ITF {
if o.MigrationHealthinessThreshold = v; o.MigrationHealthinessThreshold == nil {
o.nullFields = append(o.nullFields, "MigrationHealthinessThreshold")
}
return o
}
func (o *ITF) SetFixedTargetGroups(v *bool) *ITF {
if o.FixedTargetGroups = v; o.FixedTargetGroups == nil {
o.nullFields = append(o.nullFields, "FixedTargetGroups")
}
return o
}
func (o *ITF) SetWeightStrategy(v *string) *ITF {
if o.WeightStrategy = v; o.WeightStrategy == nil {
o.nullFields = append(o.nullFields, "WeightStrategy")
}
return o
}
func (o *ITF) SetTargetGroupConfig(v *TargetGroupConfig) *ITF {
if o.TargetGroupConfig = v; o.TargetGroupConfig == nil {
o.nullFields = append(o.nullFields, "TargetGroupConfig")
}
return o
}
func (o *ITF) SetDefaultStaticTargetGroups(v []*StaticTargetGroup) *ITF {
if o.DefaultStaticTargetGroups = v; o.DefaultStaticTargetGroups == nil {
o.nullFields = append(o.nullFields, "DefaultStaticTargetGroups")
}
return o
}
// endregion
// region ITFLoadBalancer
func (o ITFLoadBalancer) MarshalJSON() ([]byte, error) {
type noMethod ITFLoadBalancer
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *ITFLoadBalancer) SetListenerRules(v []*ListenerRule) *ITFLoadBalancer {
if o.ListenerRules = v; o.ListenerRules == nil {
o.nullFields = append(o.nullFields, "ListenerRules")
}
return o
}
func (o *ITFLoadBalancer) SetLoadBalancerARN(v *string) *ITFLoadBalancer {
if o.LoadBalancerARN = v; o.LoadBalancerARN == nil {
o.nullFields = append(o.nullFields, "LoadBalancerARN")
}
return o
}
// endregion
// region ListenerRule
func (o ListenerRule) MarshalJSON() ([]byte, error) {
type noMethod ListenerRule
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *ListenerRule) SetRuleARN(v *string) *ListenerRule {
if o.RuleARN = v; o.RuleARN == nil {
o.nullFields = append(o.nullFields, "RuleARN")
}
return o
}
func (o *ListenerRule) SetStaticTargetGroups(v []*StaticTargetGroup) *ListenerRule {
if o.StaticTargetGroups = v; o.StaticTargetGroups == nil {
o.nullFields = append(o.nullFields, "StaticTargetGroups")
}
return o
}
// endregion
// region StaticTargetGroup
func (o StaticTargetGroup) MarshalJSON() ([]byte, error) {
type noMethod StaticTargetGroup
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *StaticTargetGroup) SetStaticTargetGroupARN(v *string) *StaticTargetGroup {
if o.StaticTargetGroupARN = v; o.StaticTargetGroupARN == nil {
o.nullFields = append(o.nullFields, "StaticTargetGroupARN")
}
return o
}
func (o *StaticTargetGroup) SetPercentage(v *float64) *StaticTargetGroup {
if o.Percentage = v; o.Percentage == nil {
o.nullFields = append(o.nullFields, "Percentage")
}
return o
}
// region TargetGroupConfig
func (o TargetGroupConfig) MarshalJSON() ([]byte, error) {
type noMethod TargetGroupConfig
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *TargetGroupConfig) SetVPCId(v *string) *TargetGroupConfig {
if o.VPCID = v; o.VPCID == nil {
o.nullFields = append(o.nullFields, "VPCID")
}
return o
}
func (o *TargetGroupConfig) SetHealthCheckIntervalSeconds(v *int) *TargetGroupConfig {
if o.HealthCheckIntervalSeconds = v; o.HealthCheckIntervalSeconds == nil {
o.nullFields = append(o.nullFields, "HealthCheckIntervalSeconds")
}
return o
}
func (o *TargetGroupConfig) SetHealthCheckPath(v *string) *TargetGroupConfig {
if o.HealthCheckPath = v; o.HealthCheckPath == nil {
o.nullFields = append(o.nullFields, "HealthCheckPath")
}
return o
}
func (o *TargetGroupConfig) SetHealthCheckPort(v *string) *TargetGroupConfig {
if o.HealthCheckPort = v; o.HealthCheckPort == nil {
o.nullFields = append(o.nullFields, "HealthCheckPort")
}
return o
}
func (o *TargetGroupConfig) SetHealthCheckProtocol(v *string) *TargetGroupConfig {
if o.HealthCheckProtocol = v; o.HealthCheckProtocol == nil {
o.nullFields = append(o.nullFields, "HealthCheckProtocol")
}
return o
}
func (o *TargetGroupConfig) SetHealthyThresholdCount(v *int) *TargetGroupConfig {
if o.HealthyThresholdCount = v; o.HealthyThresholdCount == nil {
o.nullFields = append(o.nullFields, "HealthyThresholdCount")
}
return o
}
func (o *TargetGroupConfig) SetUnhealthyThresholdCount(v *int) *TargetGroupConfig {
if o.UnhealthyThresholdCount = v; o.UnhealthyThresholdCount == nil {
o.nullFields = append(o.nullFields, "UnhealthyThresholdCount")
}
return o
}
func (o *TargetGroupConfig) SetHealthCheckTimeoutSeconds(v *int) *TargetGroupConfig {
if o.HealthCheckTimeoutSeconds = v; o.HealthCheckTimeoutSeconds == nil {
o.nullFields = append(o.nullFields, "HealthCheckTimeoutSeconds")
}
return o
}
func (o *TargetGroupConfig) SetPort(v *int) *TargetGroupConfig {
if o.Port = v; o.Port == nil {
o.nullFields = append(o.nullFields, "Port")
}
return o
}
func (o *TargetGroupConfig) SetProtocol(v *string) *TargetGroupConfig {
if o.Protocol = v; o.Protocol == nil {
o.nullFields = append(o.nullFields, "Protocol")
}
return o
}
func (o *TargetGroupConfig) SetProtocolVersion(v *string) *TargetGroupConfig {
if o.ProtocolVersion = v; o.ProtocolVersion == nil {
o.nullFields = append(o.nullFields, "ProtocolVersion")
}
return o
}
func (o *TargetGroupConfig) SetMatcher(v *Matcher) *TargetGroupConfig {
if o.Matcher = v; o.Matcher == nil {
o.nullFields = append(o.nullFields, "Matcher")
}
return o
}
func (o *TargetGroupConfig) SetTags(v []*Tag) *TargetGroupConfig {
if o.Tags = v; o.Tags == nil {
o.nullFields = append(o.nullFields, "Tags")
}
return o
}
// endregion // endregion
// region LoadBalancersConfig // region LoadBalancersConfig
@ -4631,3 +5179,109 @@ func (o *Device) SetSnapshotID(v *string) *Device {
} }
// endregion // endregion
// region ResourceTagSpecification
func (o ResourceTagSpecification) MarshalJSON() ([]byte, error) {
type noMethod ResourceTagSpecification
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *ResourceTagSpecification) SetVolumes(v *Volumes) *ResourceTagSpecification {
if o.Volumes = v; o.Volumes == nil {
o.nullFields = append(o.nullFields, "Volumes")
}
return o
}
func (o *ResourceTagSpecification) SetSnapshots(v *Snapshots) *ResourceTagSpecification {
if o.Snapshots = v; o.Snapshots == nil {
o.nullFields = append(o.nullFields, "Snapshots")
}
return o
}
func (o *ResourceTagSpecification) SetENIs(v *ENIs) *ResourceTagSpecification {
if o.ENIs = v; o.ENIs == nil {
o.nullFields = append(o.nullFields, "ENIs")
}
return o
}
func (o *ResourceTagSpecification) SetAMIs(v *AMIs) *ResourceTagSpecification {
if o.AMIs = v; o.AMIs == nil {
o.nullFields = append(o.nullFields, "AMIs")
}
return o
}
// endregion
// region Volumes
func (o Volumes) MarshalJSON() ([]byte, error) {
type noMethod Volumes
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *Volumes) SetShouldTag(v *bool) *Volumes {
if o.ShouldTag = v; o.ShouldTag == nil {
o.nullFields = append(o.nullFields, "ShouldTag")
}
return o
}
// endregion
// region Snapshots
func (o Snapshots) MarshalJSON() ([]byte, error) {
type noMethod Snapshots
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *Snapshots) SetShouldTag(v *bool) *Snapshots {
if o.ShouldTag = v; o.ShouldTag == nil {
o.nullFields = append(o.nullFields, "ShouldTag")
}
return o
}
// endregion
// region ENIs
func (o ENIs) MarshalJSON() ([]byte, error) {
type noMethod ENIs
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *ENIs) SetShouldTag(v *bool) *ENIs {
if o.ShouldTag = v; o.ShouldTag == nil {
o.nullFields = append(o.nullFields, "ShouldTag")
}
return o
}
// endregion
// region AMIs
func (o AMIs) MarshalJSON() ([]byte, error) {
type noMethod AMIs
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *AMIs) SetShouldTag(v *bool) *AMIs {
if o.ShouldTag = v; o.ShouldTag == nil {
o.nullFields = append(o.nullFields, "ShouldTag")
}
return o
}
// endregion

View File

@ -83,6 +83,28 @@ type LaunchSpecification struct {
Image *Image `json:"image,omitempty"` Image *Image `json:"image,omitempty"`
Network *Network `json:"network,omitempty"` Network *Network `json:"network,omitempty"`
Login *Login `json:"login,omitempty"` Login *Login `json:"login,omitempty"`
CustomData *string `json:"customData,omitempty"`
ManagedServiceIdentities []*ManagedServiceIdentity `json:"managedServiceIdentities,omitempty"`
LoadBalancersConfig *LoadBalancersConfig `json:"loadBalancersConfig,omitempty"`
ShutdownScript *string `json:"shutdownScript,omitempty"`
forceSendFields []string
nullFields []string
}
type LoadBalancersConfig struct {
LoadBalancers []*LoadBalancer `json:"loadBalancers,omitempty"`
forceSendFields []string
nullFields []string
}
type LoadBalancer struct {
Type *string `json:"type,omitempty"`
ResourceGroupName *string `json:"resourceGroupName,omitempty"`
Name *string `json:"name,omitempty"`
SKU *string `json:"sku,omitempty"`
BackendPoolNames []string `json:"backendPoolNames,omitempty"`
forceSendFields []string forceSendFields []string
nullFields []string nullFields []string
@ -128,6 +150,7 @@ type NetworkInterface struct {
AssignPublicIP *bool `json:"assignPublicIp,omitempty"` AssignPublicIP *bool `json:"assignPublicIp,omitempty"`
IsPrimary *bool `json:"isPrimary,omitempty"` IsPrimary *bool `json:"isPrimary,omitempty"`
AdditionalIPConfigs []*AdditionalIPConfig `json:"additionalIpConfigurations,omitempty"` AdditionalIPConfigs []*AdditionalIPConfig `json:"additionalIpConfigurations,omitempty"`
ApplicationSecurityGroups []*ApplicationSecurityGroup `json:"applicationSecurityGroups,omitempty"`
forceSendFields []string forceSendFields []string
nullFields []string nullFields []string
@ -150,6 +173,22 @@ type Login struct {
nullFields []string nullFields []string
} }
type ApplicationSecurityGroup struct {
Name *string `json:"name,omitempty"`
ResourceGroupName *string `json:"resourceGroupName,omitempty"`
forceSendFields []string
nullFields []string
}
type ManagedServiceIdentity struct {
ResourceGroupName *string `json:"resourceGroupName,omitempty"`
Name *string `json:"name,omitempty"`
forceSendFields []string
nullFields []string
}
type CreateGroupInput struct { type CreateGroupInput struct {
Group *Group `json:"group,omitempty"` Group *Group `json:"group,omitempty"`
} }
@ -559,6 +598,35 @@ func (o *LaunchSpecification) SetLogin(v *Login) *LaunchSpecification {
return o return o
} }
func (o *LaunchSpecification) SetCustomData(v *string) *LaunchSpecification {
if o.CustomData = v; o.CustomData == nil {
o.nullFields = append(o.nullFields, "CustomData")
}
return o
}
func (o *LaunchSpecification) SetManagedServiceIdentities(v []*ManagedServiceIdentity) *LaunchSpecification {
if o.ManagedServiceIdentities = v; o.ManagedServiceIdentities == nil {
o.nullFields = append(o.nullFields, "ManagedServiceIdentities")
}
return o
}
func (o *LaunchSpecification) SetLoadBalancersConfig(v *LoadBalancersConfig) *LaunchSpecification {
if o.LoadBalancersConfig = v; o.LoadBalancersConfig == nil {
o.nullFields = append(o.nullFields, "LoadBalancersConfig")
}
return o
}
// SetShutdownScript sets the shutdown script used when draining instances
func (o *LaunchSpecification) SetShutdownScript(v *string) *LaunchSpecification {
if o.ShutdownScript = v; o.ShutdownScript == nil {
o.nullFields = append(o.nullFields, "ShutdownScript")
}
return o
}
// endregion // endregion
// region Image // region Image
@ -714,6 +782,13 @@ func (o *NetworkInterface) SetIsPrimary(v *bool) *NetworkInterface {
return o return o
} }
func (o *NetworkInterface) SetApplicationSecurityGroups(v []*ApplicationSecurityGroup) *NetworkInterface {
if o.ApplicationSecurityGroups = v; o.ApplicationSecurityGroups == nil {
o.nullFields = append(o.nullFields, "ApplicationSecurityGroups")
}
return o
}
// endregion // endregion
// region AdditionalIPConfig // region AdditionalIPConfig
@ -724,7 +799,6 @@ func (o AdditionalIPConfig) MarshalJSON() ([]byte, error) {
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields) return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
} }
// SetName sets the name
func (o *AdditionalIPConfig) SetName(v *string) *AdditionalIPConfig { func (o *AdditionalIPConfig) SetName(v *string) *AdditionalIPConfig {
if o.Name = v; o.Name == nil { if o.Name = v; o.Name == nil {
o.nullFields = append(o.nullFields, "Name") o.nullFields = append(o.nullFields, "Name")
@ -732,7 +806,6 @@ func (o *AdditionalIPConfig) SetName(v *string) *AdditionalIPConfig {
return o return o
} }
// SetPrivateIPAddressVersion sets the ip address version
func (o *AdditionalIPConfig) SetPrivateIPAddressVersion(v *string) *AdditionalIPConfig { func (o *AdditionalIPConfig) SetPrivateIPAddressVersion(v *string) *AdditionalIPConfig {
if o.PrivateIPAddressVersion = v; o.PrivateIPAddressVersion == nil { if o.PrivateIPAddressVersion = v; o.PrivateIPAddressVersion == nil {
o.nullFields = append(o.nullFields, "PrivateIPAddressVersion") o.nullFields = append(o.nullFields, "PrivateIPAddressVersion")
@ -772,3 +845,113 @@ func (o *Login) SetPassword(v *string) *Login {
} }
// endregion // endregion
// region ApplicationSecurityGroup
func (o ApplicationSecurityGroup) MarshalJSON() ([]byte, error) {
type noMethod ApplicationSecurityGroup
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *ApplicationSecurityGroup) SetName(v *string) *ApplicationSecurityGroup {
if o.Name = v; o.Name == nil {
o.nullFields = append(o.nullFields, "Name")
}
return o
}
func (o *ApplicationSecurityGroup) SetResourceGroupName(v *string) *ApplicationSecurityGroup {
if o.ResourceGroupName = v; o.ResourceGroupName == nil {
o.nullFields = append(o.nullFields, "ResourceGroupName")
}
return o
}
// endregion
// region ManagedServiceIdentity
func (o ManagedServiceIdentity) MarshalJSON() ([]byte, error) {
type noMethod ManagedServiceIdentity
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *ManagedServiceIdentity) SetResourceGroupName(v *string) *ManagedServiceIdentity {
if o.ResourceGroupName = v; o.ResourceGroupName == nil {
o.nullFields = append(o.nullFields, "ResourceGroupName")
}
return o
}
func (o *ManagedServiceIdentity) SetName(v *string) *ManagedServiceIdentity {
if o.Name = v; o.Name == nil {
o.nullFields = append(o.nullFields, "Name")
}
return o
}
// endregion
// region LoadBalancersConfig
func (o LoadBalancersConfig) MarshalJSON() ([]byte, error) {
type noMethod LoadBalancersConfig
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *LoadBalancersConfig) SetLoadBalancers(v []*LoadBalancer) *LoadBalancersConfig {
if o.LoadBalancers = v; o.LoadBalancers == nil {
o.nullFields = append(o.nullFields, "LoadBalancers")
}
return o
}
// endregion
// region LoadBalancer
func (o LoadBalancer) MarshalJSON() ([]byte, error) {
type noMethod LoadBalancer
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *LoadBalancer) SetType(v *string) *LoadBalancer {
if o.Type = v; o.Type == nil {
o.nullFields = append(o.nullFields, "Type")
}
return o
}
func (o *LoadBalancer) SetResourceGroupName(v *string) *LoadBalancer {
if o.ResourceGroupName = v; o.ResourceGroupName == nil {
o.nullFields = append(o.nullFields, "ResourceGroupName")
}
return o
}
func (o *LoadBalancer) SetName(v *string) *LoadBalancer {
if o.Name = v; o.Name == nil {
o.nullFields = append(o.nullFields, "Name")
}
return o
}
func (o *LoadBalancer) SetSKU(v *string) *LoadBalancer {
if o.SKU = v; o.SKU == nil {
o.nullFields = append(o.nullFields, "SKU")
}
return o
}
func (o *LoadBalancer) SeBackendPoolNames(v []string) *LoadBalancer {
if o.BackendPoolNames = v; o.BackendPoolNames == nil {
o.nullFields = append(o.nullFields, "BackendPoolNames")
}
return o
}
// endregion

View File

@ -374,6 +374,7 @@ type Strategy struct {
FallbackToOnDemand *bool `json:"fallbackToOd,omitempty"` FallbackToOnDemand *bool `json:"fallbackToOd,omitempty"`
PreemptiblePercentage *int `json:"preemptiblePercentage,omitempty"` PreemptiblePercentage *int `json:"preemptiblePercentage,omitempty"`
OnDemandCount *int `json:"onDemandCount,omitempty"` OnDemandCount *int `json:"onDemandCount,omitempty"`
ProvisioningModel *string `json:"provisioningModel,omitempty"`
forceSendFields []string forceSendFields []string
nullFields []string nullFields []string
@ -2164,4 +2165,11 @@ func (o *Strategy) SetOnDemandCount(v *int) *Strategy {
return o return o
} }
func (o *Strategy) SetProvisioningModel(v *string) *Strategy {
if o.ProvisioningModel = v; o.ProvisioningModel == nil {
o.nullFields = append(o.nullFields, "ProvisioningModel")
}
return o
}
// endregion // endregion

View File

@ -24,6 +24,7 @@ type Cluster struct {
Compute *Compute `json:"compute,omitempty"` Compute *Compute `json:"compute,omitempty"`
Scheduling *Scheduling `json:"scheduling,omitempty"` Scheduling *Scheduling `json:"scheduling,omitempty"`
AutoScaler *AutoScaler `json:"autoScaler,omitempty"` AutoScaler *AutoScaler `json:"autoScaler,omitempty"`
Logging *Logging `json:"logging,omitempty"`
// Read-only fields. // Read-only fields.
CreatedAt *time.Time `json:"createdAt,omitempty"` CreatedAt *time.Time `json:"createdAt,omitempty"`
@ -122,6 +123,7 @@ type LaunchSpecification struct {
Monitoring *bool `json:"monitoring,omitempty"` Monitoring *bool `json:"monitoring,omitempty"`
EBSOptimized *bool `json:"ebsOptimized,omitempty"` EBSOptimized *bool `json:"ebsOptimized,omitempty"`
UseAsTemplateOnly *bool `json:"useAsTemplateOnly,omitempty"` UseAsTemplateOnly *bool `json:"useAsTemplateOnly,omitempty"`
InstanceMetadataOptions *InstanceMetadataOptions `json:"instanceMetadataOptions,omitempty"`
forceSendFields []string forceSendFields []string
nullFields []string nullFields []string
@ -152,6 +154,8 @@ type AutoScaler struct {
Headroom *AutoScalerHeadroom `json:"headroom,omitempty"` Headroom *AutoScalerHeadroom `json:"headroom,omitempty"`
ResourceLimits *AutoScalerResourceLimits `json:"resourceLimits,omitempty"` ResourceLimits *AutoScalerResourceLimits `json:"resourceLimits,omitempty"`
Down *AutoScalerDown `json:"down,omitempty"` Down *AutoScalerDown `json:"down,omitempty"`
EnableAutomaticAndManualHeadroom *bool `json:"enableAutomaticAndManualHeadroom,omitempty"`
ExtendedResourceDefinitions []string `json:"extendedResourceDefinitions,omitempty"`
forceSendFields []string forceSendFields []string
nullFields []string nullFields []string
@ -183,6 +187,35 @@ type AutoScalerDown struct {
nullFields []string nullFields []string
} }
type InstanceMetadataOptions struct {
HTTPTokens *string `json:"httpTokens,omitempty"`
HTTPPutResponseHopLimit *int `json:"httpPutResponseHopLimit,omitempty"`
forceSendFields []string
nullFields []string
}
type Logging struct {
Export *Export `json:"export,omitempty"`
forceSendFields []string
nullFields []string
}
type Export struct {
S3 *S3 `json:"s3,omitempty"`
forceSendFields []string
nullFields []string
}
type S3 struct {
ID *string `json:"id,omitempty"`
forceSendFields []string
nullFields []string
}
type ListClustersInput struct{} type ListClustersInput struct{}
type ListClustersOutput struct { type ListClustersOutput struct {
@ -872,6 +905,13 @@ func (o *Cluster) SetAutoScaler(v *AutoScaler) *Cluster {
return o return o
} }
func (o *Cluster) SetLogging(v *Logging) *Cluster {
if o.Logging = v; o.Logging == nil {
o.nullFields = append(o.nullFields, "Logging")
}
return o
}
// endregion // endregion
// region Strategy // region Strategy
@ -1183,6 +1223,13 @@ func (o *LaunchSpecification) SetUseAsTemplateOnly(v *bool) *LaunchSpecification
return o return o
} }
func (o *LaunchSpecification) SetInstanceMetadataOptions(v *InstanceMetadataOptions) *LaunchSpecification {
if o.InstanceMetadataOptions = v; o.InstanceMetadataOptions == nil {
o.nullFields = append(o.nullFields, "InstanceMetadataOptions")
}
return o
}
// endregion // endregion
// region LoadBalancer // region LoadBalancer
@ -1291,6 +1338,20 @@ func (o *AutoScaler) SetDown(v *AutoScalerDown) *AutoScaler {
return o return o
} }
func (o *AutoScaler) SetEnableAutomaticAndManualHeadroom(v *bool) *AutoScaler {
if o.EnableAutomaticAndManualHeadroom = v; o.EnableAutomaticAndManualHeadroom == nil {
o.nullFields = append(o.nullFields, "EnableAutomaticAndManualHeadroom")
}
return o
}
func (o *AutoScaler) SetExtendedResourceDefinitions(v []string) *AutoScaler {
if o.ExtendedResourceDefinitions = v; o.ExtendedResourceDefinitions == nil {
o.nullFields = append(o.nullFields, "ExtendedResourceDefinitions")
}
return o
}
// endregion // endregion
// region AutoScalerHeadroom // region AutoScalerHeadroom
@ -1475,3 +1536,78 @@ func (o *RollSpec) SetInstanceIDs(v []string) *RollSpec {
} }
// endregion // endregion
// region InstanceMetadataOptions
func (o InstanceMetadataOptions) MarshalJSON() ([]byte, error) {
type noMethod InstanceMetadataOptions
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *InstanceMetadataOptions) SetHTTPTokens(v *string) *InstanceMetadataOptions {
if o.HTTPTokens = v; o.HTTPTokens == nil {
o.nullFields = append(o.nullFields, "HTTPTokens")
}
return o
}
func (o *InstanceMetadataOptions) SetHTTPPutResponseHopLimit(v *int) *InstanceMetadataOptions {
if o.HTTPPutResponseHopLimit = v; o.HTTPPutResponseHopLimit == nil {
o.nullFields = append(o.nullFields, "HTTPPutResponseHopLimit")
}
return o
}
// endregion
// region Logging
func (o Logging) MarshalJSON() ([]byte, error) {
type noMethod Logging
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *Logging) SetExport(v *Export) *Logging {
if o.Export = v; o.Export == nil {
o.nullFields = append(o.nullFields, "Export")
}
return o
}
// endregion
// region Export
func (o Export) MarshalJSON() ([]byte, error) {
type noMethod Export
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *Export) SetS3(v *S3) *Export {
if o.S3 = v; o.S3 == nil {
o.nullFields = append(o.nullFields, "S3")
}
return o
}
// endregion
// region S3
func (o S3) MarshalJSON() ([]byte, error) {
type noMethod S3
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *S3) SetId(v *string) *S3 {
if o.ID = v; o.ID == nil {
o.nullFields = append(o.nullFields, "ID")
}
return o
}
// endregion

View File

@ -49,6 +49,7 @@ type ECSStrategy struct {
DrainingTimeout *int `json:"drainingTimeout,omitempty"` DrainingTimeout *int `json:"drainingTimeout,omitempty"`
UtilizeReservedInstances *bool `json:"utilizeReservedInstances,omitempty"` UtilizeReservedInstances *bool `json:"utilizeReservedInstances,omitempty"`
UtilizeCommitments *bool `json:"utilizeCommitments,omitempty"` UtilizeCommitments *bool `json:"utilizeCommitments,omitempty"`
SpotPercentage *int `json:"spotPercentage,omitempty"`
forceSendFields []string forceSendFields []string
nullFields []string nullFields []string
@ -116,6 +117,7 @@ type ECSLaunchSpecification struct {
Monitoring *bool `json:"monitoring,omitempty"` Monitoring *bool `json:"monitoring,omitempty"`
EBSOptimized *bool `json:"ebsOptimized,omitempty"` EBSOptimized *bool `json:"ebsOptimized,omitempty"`
BlockDeviceMappings []*ECSBlockDeviceMapping `json:"blockDeviceMappings,omitempty"` BlockDeviceMappings []*ECSBlockDeviceMapping `json:"blockDeviceMappings,omitempty"`
InstanceMetadataOptions *ECSInstanceMetadataOptions `json:"instanceMetadataOptions,omitempty"`
forceSendFields []string forceSendFields []string
nullFields []string nullFields []string
@ -145,6 +147,7 @@ type ECSAutoScaler struct {
Headroom *ECSAutoScalerHeadroom `json:"headroom,omitempty"` Headroom *ECSAutoScalerHeadroom `json:"headroom,omitempty"`
ResourceLimits *ECSAutoScalerResourceLimits `json:"resourceLimits,omitempty"` ResourceLimits *ECSAutoScalerResourceLimits `json:"resourceLimits,omitempty"`
Down *ECSAutoScalerDown `json:"down,omitempty"` Down *ECSAutoScalerDown `json:"down,omitempty"`
AutoHeadroomPercentage *int `json:"autoHeadroomPercentage,omitempty"`
forceSendFields []string forceSendFields []string
nullFields []string nullFields []string
@ -245,6 +248,14 @@ type ECSProgress struct {
Value *int `json:"value,omitempty"` Value *int `json:"value,omitempty"`
} }
type ECSInstanceMetadataOptions struct {
HTTPTokens *string `json:"httpTokens,omitempty"`
HTTPPutResponseHopLimit *int `json:"httpPutResponseHopLimit,omitempty"`
forceSendFields []string
nullFields []string
}
func ecsClusterFromJSON(in []byte) (*ECSCluster, error) { func ecsClusterFromJSON(in []byte) (*ECSCluster, error) {
b := new(ECSCluster) b := new(ECSCluster)
if err := json.Unmarshal(in, b); err != nil { if err := json.Unmarshal(in, b); err != nil {
@ -713,6 +724,13 @@ func (o *ECSStrategy) SetUtilizeCommitments(v *bool) *ECSStrategy {
return o return o
} }
func (o *ECSStrategy) SetSpotPercentage(v *int) *ECSStrategy {
if o.SpotPercentage = v; o.SpotPercentage == nil {
o.nullFields = append(o.nullFields, "SpotPercentage")
}
return o
}
// endregion // endregion
// region InstanceTypes // region InstanceTypes
@ -810,6 +828,13 @@ func (o *ECSLaunchSpecification) SetBlockDeviceMappings(v []*ECSBlockDeviceMappi
return o return o
} }
func (o *ECSLaunchSpecification) SetInstanceMetadataOptions(v *ECSInstanceMetadataOptions) *ECSLaunchSpecification {
if o.InstanceMetadataOptions = v; o.InstanceMetadataOptions == nil {
o.nullFields = append(o.nullFields, "InstanceMetadataOptions")
}
return o
}
// endregion // endregion
// region ECSOptimizeImages // region ECSOptimizeImages
@ -917,6 +942,13 @@ func (o *ECSAutoScaler) SetDown(v *ECSAutoScalerDown) *ECSAutoScaler {
return o return o
} }
func (o *ECSAutoScaler) SetAutoHeadroomPercentage(v *int) *ECSAutoScaler {
if o.AutoHeadroomPercentage = v; o.AutoHeadroomPercentage == nil {
o.nullFields = append(o.nullFields, "AutoHeadroomPercentage")
}
return o
}
// endregion // endregion
// region AutoScalerHeadroom // region AutoScalerHeadroom
@ -1028,3 +1060,27 @@ func (o *ECSRoll) SetInstanceIDs(v []string) *ECSRoll {
} }
// endregion // endregion
// region InstanceMetadataOptions
func (o ECSInstanceMetadataOptions) MarshalJSON() ([]byte, error) {
type noMethod ECSInstanceMetadataOptions
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *ECSInstanceMetadataOptions) SetHTTPTokens(v *string) *ECSInstanceMetadataOptions {
if o.HTTPTokens = v; o.HTTPTokens == nil {
o.nullFields = append(o.nullFields, "HTTPTokens")
}
return o
}
func (o *ECSInstanceMetadataOptions) SetHTTPPutResponseHopLimit(v *int) *ECSInstanceMetadataOptions {
if o.HTTPPutResponseHopLimit = v; o.HTTPPutResponseHopLimit == nil {
o.nullFields = append(o.nullFields, "HTTPPutResponseHopLimit")
}
return o
}
// endregion

View File

@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"strconv"
"time" "time"
"github.com/spotinst/spotinst-sdk-go/spotinst" "github.com/spotinst/spotinst-sdk-go/spotinst"
@ -23,6 +24,7 @@ type LaunchSpec struct {
SecurityGroupIDs []string `json:"securityGroupIds,omitempty"` SecurityGroupIDs []string `json:"securityGroupIds,omitempty"`
SubnetIDs []string `json:"subnetIds,omitempty"` SubnetIDs []string `json:"subnetIds,omitempty"`
InstanceTypes []string `json:"instanceTypes,omitempty"` InstanceTypes []string `json:"instanceTypes,omitempty"`
PreferredSpotTypes []string `json:"preferredSpotTypes,omitempty"`
Strategy *LaunchSpecStrategy `json:"strategy,omitempty"` Strategy *LaunchSpecStrategy `json:"strategy,omitempty"`
ResourceLimits *ResourceLimits `json:"resourceLimits,omitempty"` ResourceLimits *ResourceLimits `json:"resourceLimits,omitempty"`
IAMInstanceProfile *IAMInstanceProfile `json:"iamInstanceProfile,omitempty"` IAMInstanceProfile *IAMInstanceProfile `json:"iamInstanceProfile,omitempty"`
@ -34,6 +36,7 @@ type LaunchSpec struct {
Tags []*Tag `json:"tags,omitempty"` Tags []*Tag `json:"tags,omitempty"`
AssociatePublicIPAddress *bool `json:"associatePublicIpAddress,omitempty"` AssociatePublicIPAddress *bool `json:"associatePublicIpAddress,omitempty"`
RestrictScaleDown *bool `json:"restrictScaleDown,omitempty"` RestrictScaleDown *bool `json:"restrictScaleDown,omitempty"`
LaunchSpecScheduling *LaunchSpecScheduling `json:"scheduling,omitempty"`
// Read-only fields. // Read-only fields.
CreatedAt *time.Time `json:"createdAt,omitempty"` CreatedAt *time.Time `json:"createdAt,omitempty"`
@ -58,6 +61,7 @@ type LaunchSpec struct {
type ResourceLimits struct { type ResourceLimits struct {
MaxInstanceCount *int `json:"maxInstanceCount,omitempty"` MaxInstanceCount *int `json:"maxInstanceCount,omitempty"`
MinInstanceCount *int `json:"minInstanceCount,omitempty"`
forceSendFields []string forceSendFields []string
nullFields []string nullFields []string
@ -153,6 +157,49 @@ type LaunchSpecStrategy struct {
nullFields []string nullFields []string
} }
type LaunchSpecScheduling struct {
Tasks []*LaunchSpecTask `json:"tasks,omitempty"`
ShutdownHours *LaunchSpecShutdownHours `json:"shutdownHours,omitempty"`
forceSendFields []string
nullFields []string
}
type LaunchSpecTask struct {
IsEnabled *bool `json:"isEnabled,omitempty"`
CronExpression *string `json:"cronExpression,omitempty"`
TaskType *string `json:"taskType,omitempty"`
Config *TaskConfig `json:"config,omitempty"`
forceSendFields []string
nullFields []string
}
type LaunchSpecShutdownHours struct {
IsEnabled *bool `json:"isEnabled,omitempty"`
TimeWindows []string `json:"timeWindows,omitempty"`
forceSendFields []string
nullFields []string
}
type TaskConfig struct {
TaskHeadrooms []*LaunchSpecTaskHeadroom `json:"headrooms,omitempty"`
forceSendFields []string
nullFields []string
}
type LaunchSpecTaskHeadroom struct {
CPUPerUnit *int `json:"cpuPerUnit,omitempty"`
GPUPerUnit *int `json:"gpuPerUnit,omitempty"`
MemoryPerUnit *int `json:"memoryPerUnit,omitempty"`
NumOfUnits *int `json:"numOfUnits,omitempty"`
forceSendFields []string
nullFields []string
}
type ListLaunchSpecsInput struct { type ListLaunchSpecsInput struct {
OceanID *string `json:"oceanId,omitempty"` OceanID *string `json:"oceanId,omitempty"`
} }
@ -163,6 +210,7 @@ type ListLaunchSpecsOutput struct {
type CreateLaunchSpecInput struct { type CreateLaunchSpecInput struct {
LaunchSpec *LaunchSpec `json:"launchSpec,omitempty"` LaunchSpec *LaunchSpec `json:"launchSpec,omitempty"`
InitialNodes *int `json:"-"`
} }
type CreateLaunchSpecOutput struct { type CreateLaunchSpecOutput struct {
@ -187,6 +235,7 @@ type UpdateLaunchSpecOutput struct {
type DeleteLaunchSpecInput struct { type DeleteLaunchSpecInput struct {
LaunchSpecID *string `json:"launchSpecId,omitempty"` LaunchSpecID *string `json:"launchSpecId,omitempty"`
ForceDelete *bool `json:"-"`
} }
type DeleteLaunchSpecOutput struct{} type DeleteLaunchSpecOutput struct{}
@ -251,6 +300,10 @@ func (s *ServiceOp) CreateLaunchSpec(ctx context.Context, input *CreateLaunchSpe
r := client.NewRequest(http.MethodPost, "/ocean/aws/k8s/launchSpec") r := client.NewRequest(http.MethodPost, "/ocean/aws/k8s/launchSpec")
r.Obj = input r.Obj = input
if input.InitialNodes != nil {
r.Params.Set("initialNodes", strconv.Itoa(spotinst.IntValue(input.InitialNodes)))
}
resp, err := client.RequireOK(s.Client.Do(ctx, r)) resp, err := client.RequireOK(s.Client.Do(ctx, r))
if err != nil { if err != nil {
return nil, err return nil, err
@ -341,6 +394,10 @@ func (s *ServiceOp) DeleteLaunchSpec(ctx context.Context, input *DeleteLaunchSpe
r := client.NewRequest(http.MethodDelete, path) r := client.NewRequest(http.MethodDelete, path)
if input.ForceDelete != nil {
r.Params.Set("forceDelete", strconv.FormatBool(spotinst.BoolValue(input.ForceDelete)))
}
resp, err := client.RequireOK(s.Client.Do(ctx, r)) resp, err := client.RequireOK(s.Client.Do(ctx, r))
if err != nil { if err != nil {
return nil, err return nil, err
@ -416,6 +473,13 @@ func (o *LaunchSpec) SetInstanceTypes(v []string) *LaunchSpec {
return o return o
} }
func (o *LaunchSpec) SetPreferredSpotTypes(v []string) *LaunchSpec {
if o.PreferredSpotTypes = v; o.PreferredSpotTypes == nil {
o.nullFields = append(o.nullFields, "PreferredSpotTypes")
}
return o
}
func (o *LaunchSpec) SetRootVolumeSize(v *int) *LaunchSpec { func (o *LaunchSpec) SetRootVolumeSize(v *int) *LaunchSpec {
if o.RootVolumeSize = v; o.RootVolumeSize == nil { if o.RootVolumeSize = v; o.RootVolumeSize == nil {
o.nullFields = append(o.nullFields, "RootVolumeSize") o.nullFields = append(o.nullFields, "RootVolumeSize")
@ -500,6 +564,13 @@ func (o *LaunchSpec) SetRestrictScaleDown(v *bool) *LaunchSpec {
return o return o
} }
func (o *LaunchSpec) SetScheduling(v *LaunchSpecScheduling) *LaunchSpec {
if o.LaunchSpecScheduling = v; o.LaunchSpecScheduling == nil {
o.nullFields = append(o.nullFields, "LaunchSpecScheduling")
}
return o
}
// endregion // endregion
// region BlockDeviceMapping // region BlockDeviceMapping
@ -659,6 +730,13 @@ func (o *ResourceLimits) SetMaxInstanceCount(v *int) *ResourceLimits {
return o return o
} }
func (o *ResourceLimits) SetMinInstanceCount(v *int) *ResourceLimits {
if o.MinInstanceCount = v; o.MinInstanceCount == nil {
o.nullFields = append(o.nullFields, "MinInstanceCount")
}
return o
}
// endregion // endregion
// region Label // region Label
@ -828,3 +906,142 @@ func (o *LaunchSpecStrategy) SetSpotPercentage(v *int) *LaunchSpecStrategy {
} }
// endregion // endregion
//region Scheduling
func (o LaunchSpecScheduling) MarshalJSON() ([]byte, error) {
type noMethod LaunchSpecScheduling
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *LaunchSpecScheduling) SetTasks(v []*LaunchSpecTask) *LaunchSpecScheduling {
if o.Tasks = v; o.Tasks == nil {
o.nullFields = append(o.nullFields, "Tasks")
}
return o
}
func (o *LaunchSpecScheduling) SetShutdownHours(v *LaunchSpecShutdownHours) *LaunchSpecScheduling {
if o.ShutdownHours = v; o.ShutdownHours == nil {
o.nullFields = append(o.nullFields, "ShutdownHours")
}
return o
}
// endregion
//region LaunchSpecTask
func (o LaunchSpecTask) MarshalJSON() ([]byte, error) {
type noMethod LaunchSpecTask
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *LaunchSpecTask) SetIsEnabled(v *bool) *LaunchSpecTask {
if o.IsEnabled = v; o.IsEnabled == nil {
o.nullFields = append(o.nullFields, "IsEnabled")
}
return o
}
func (o *LaunchSpecTask) SetCronExpression(v *string) *LaunchSpecTask {
if o.CronExpression = v; o.CronExpression == nil {
o.nullFields = append(o.nullFields, "CronExpression")
}
return o
}
func (o *LaunchSpecTask) SetTaskType(v *string) *LaunchSpecTask {
if o.TaskType = v; o.TaskType == nil {
o.nullFields = append(o.nullFields, "TaskType")
}
return o
}
func (o *LaunchSpecTask) SetTaskConfig(v *TaskConfig) *LaunchSpecTask {
if o.Config = v; o.Config == nil {
o.nullFields = append(o.nullFields, "Config")
}
return o
}
// endregion
//region LaunchSpecShutdownHours
func (o LaunchSpecShutdownHours) MarshalJSON() ([]byte, error) {
type noMethod LaunchSpecShutdownHours
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *LaunchSpecShutdownHours) SetIsEnabled(v *bool) *LaunchSpecShutdownHours {
if o.IsEnabled = v; o.IsEnabled == nil {
o.nullFields = append(o.nullFields, "IsEnabled")
}
return o
}
func (o *LaunchSpecShutdownHours) SetTimeWindows(v []string) *LaunchSpecShutdownHours {
if o.TimeWindows = v; o.TimeWindows == nil {
o.nullFields = append(o.nullFields, "TimeWindows")
}
return o
}
//region TaskConfig
func (o TaskConfig) MarshalJSON() ([]byte, error) {
type noMethod TaskConfig
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *TaskConfig) SetHeadrooms(v []*LaunchSpecTaskHeadroom) *TaskConfig {
if o.TaskHeadrooms = v; o.TaskHeadrooms == nil {
o.nullFields = append(o.nullFields, "TaskHeadrooms")
}
return o
}
// endregion
// region LaunchSpecTaskHeadroom
func (o LaunchSpecTaskHeadroom) MarshalJSON() ([]byte, error) {
type noMethod LaunchSpecTaskHeadroom
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *LaunchSpecTaskHeadroom) SetCPUPerUnit(v *int) *LaunchSpecTaskHeadroom {
if o.CPUPerUnit = v; o.CPUPerUnit == nil {
o.nullFields = append(o.nullFields, "CPUPerUnit")
}
return o
}
func (o *LaunchSpecTaskHeadroom) SetGPUPerUnit(v *int) *LaunchSpecTaskHeadroom {
if o.GPUPerUnit = v; o.GPUPerUnit == nil {
o.nullFields = append(o.nullFields, "GPUPerUnit")
}
return o
}
func (o *LaunchSpecTaskHeadroom) SetMemoryPerUnit(v *int) *LaunchSpecTaskHeadroom {
if o.MemoryPerUnit = v; o.MemoryPerUnit == nil {
o.nullFields = append(o.nullFields, "MemoryPerUnit")
}
return o
}
func (o *LaunchSpecTaskHeadroom) SetNumOfUnits(v *int) *LaunchSpecTaskHeadroom {
if o.NumOfUnits = v; o.NumOfUnits == nil {
o.nullFields = append(o.nullFields, "NumOfUnits")
}
return o
}
// endregion

View File

@ -27,6 +27,8 @@ type ECSLaunchSpec struct {
Tags []*Tag `json:"tags,omitempty"` Tags []*Tag `json:"tags,omitempty"`
InstanceTypes []string `json:"instanceTypes,omitempty"` InstanceTypes []string `json:"instanceTypes,omitempty"`
RestrictScaleDown *bool `json:"restrictScaleDown,omitempty"` RestrictScaleDown *bool `json:"restrictScaleDown,omitempty"`
SubnetIDs []string `json:"subnetIds,omitempty"`
LaunchSpecScheduling *ECSLaunchSpecScheduling `json:"scheduling,omitempty"`
// Read-only fields. // Read-only fields.
CreatedAt *time.Time `json:"createdAt,omitempty"` CreatedAt *time.Time `json:"createdAt,omitempty"`
@ -107,6 +109,39 @@ type ECSDynamicVolumeSize struct {
nullFields []string nullFields []string
} }
type ECSLaunchSpecScheduling struct {
Tasks []*ECSLaunchSpecTask `json:"tasks,omitempty"`
forceSendFields []string
nullFields []string
}
type ECSLaunchSpecTask struct {
IsEnabled *bool `json:"isEnabled,omitempty"`
CronExpression *string `json:"cronExpression,omitempty"`
TaskType *string `json:"taskType,omitempty"`
Config *ECSTaskConfig `json:"config,omitempty"`
forceSendFields []string
nullFields []string
}
type ECSTaskConfig struct {
TaskHeadrooms []*ECSLaunchSpecTaskHeadroom `json:"headrooms,omitempty"`
forceSendFields []string
nullFields []string
}
type ECSLaunchSpecTaskHeadroom struct {
CPUPerUnit *int `json:"cpuPerUnit,omitempty"`
MemoryPerUnit *int `json:"memoryPerUnit,omitempty"`
NumOfUnits *int `json:"numOfUnits,omitempty"`
forceSendFields []string
nullFields []string
}
type ListECSLaunchSpecsInput struct { type ListECSLaunchSpecsInput struct {
OceanID *string `json:"oceanId,omitempty"` OceanID *string `json:"oceanId,omitempty"`
} }
@ -405,6 +440,20 @@ func (o *ECSLaunchSpec) SetRestrictScaleDown(v *bool) *ECSLaunchSpec {
return o return o
} }
func (o *ECSLaunchSpec) SetSubnetIDs(v []string) *ECSLaunchSpec {
if o.SubnetIDs = v; o.SubnetIDs == nil {
o.nullFields = append(o.nullFields, "SubnetIDs")
}
return o
}
func (o *ECSLaunchSpec) SetScheduling(v *ECSLaunchSpecScheduling) *ECSLaunchSpec {
if o.LaunchSpecScheduling = v; o.LaunchSpecScheduling == nil {
o.nullFields = append(o.nullFields, "ECSLaunchSpecScheduling")
}
return o
}
// endregion // endregion
// region Attributes // region Attributes
@ -620,3 +669,106 @@ func (o *ECSDynamicVolumeSize) SetSizePerResourceUnit(v *int) *ECSDynamicVolumeS
} }
// endregion // endregion
//region Scheduling
func (o ECSLaunchSpecScheduling) MarshalJSON() ([]byte, error) {
type noMethod ECSLaunchSpecScheduling
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *ECSLaunchSpecScheduling) SetTasks(v []*ECSLaunchSpecTask) *ECSLaunchSpecScheduling {
if o.Tasks = v; o.Tasks == nil {
o.nullFields = append(o.nullFields, "Tasks")
}
return o
}
// endregion
//region LaunchSpecTask
func (o ECSLaunchSpecTask) MarshalJSON() ([]byte, error) {
type noMethod ECSLaunchSpecTask
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *ECSLaunchSpecTask) SetIsEnabled(v *bool) *ECSLaunchSpecTask {
if o.IsEnabled = v; o.IsEnabled == nil {
o.nullFields = append(o.nullFields, "IsEnabled")
}
return o
}
func (o *ECSLaunchSpecTask) SetCronExpression(v *string) *ECSLaunchSpecTask {
if o.CronExpression = v; o.CronExpression == nil {
o.nullFields = append(o.nullFields, "CronExpression")
}
return o
}
func (o *ECSLaunchSpecTask) SetTaskType(v *string) *ECSLaunchSpecTask {
if o.TaskType = v; o.TaskType == nil {
o.nullFields = append(o.nullFields, "TaskType")
}
return o
}
func (o *ECSLaunchSpecTask) SetTaskConfig(v *ECSTaskConfig) *ECSLaunchSpecTask {
if o.Config = v; o.Config == nil {
o.nullFields = append(o.nullFields, "Config")
}
return o
}
// endregion
//region TaskConfig
func (o ECSTaskConfig) MarshalJSON() ([]byte, error) {
type noMethod ECSTaskConfig
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *ECSTaskConfig) SetHeadrooms(v []*ECSLaunchSpecTaskHeadroom) *ECSTaskConfig {
if o.TaskHeadrooms = v; o.TaskHeadrooms == nil {
o.nullFields = append(o.nullFields, "TaskHeadrooms")
}
return o
}
// endregion
// region LaunchSpecTaskHeadroom
func (o ECSLaunchSpecTaskHeadroom) MarshalJSON() ([]byte, error) {
type noMethod ECSLaunchSpecTaskHeadroom
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *ECSLaunchSpecTaskHeadroom) SetCPUPerUnit(v *int) *ECSLaunchSpecTaskHeadroom {
if o.CPUPerUnit = v; o.CPUPerUnit == nil {
o.nullFields = append(o.nullFields, "CPUPerUnit")
}
return o
}
func (o *ECSLaunchSpecTaskHeadroom) SetMemoryPerUnit(v *int) *ECSLaunchSpecTaskHeadroom {
if o.MemoryPerUnit = v; o.MemoryPerUnit == nil {
o.nullFields = append(o.nullFields, "MemoryPerUnit")
}
return o
}
func (o *ECSLaunchSpecTaskHeadroom) SetNumOfUnits(v *int) *ECSLaunchSpecTaskHeadroom {
if o.NumOfUnits = v; o.NumOfUnits == nil {
o.nullFields = append(o.nullFields, "NumOfUnits")
}
return o
}
// endregion

View File

@ -34,17 +34,46 @@ type ContainerResourceSuggestion struct {
RequestedMemory *float64 `json:"requestedMemory,omitempty"` RequestedMemory *float64 `json:"requestedMemory,omitempty"`
} }
// ListResourceSuggestionsInput represents the input of `ListResourceSuggestions` function. type Filter struct {
Attribute *Attribute `json:"attribute,omitempty"`
Namespaces []string `json:"namespaces,omitempty"`
forceSendFields []string
nullFields []string
}
type Attribute struct {
Key *string `json:"key,omitempty"`
Operator *string `json:"operator,omitempty"`
Type *string `json:"type,omitempty"`
Value *string `json:"value,omitempty"`
forceSendFields []string
nullFields []string
}
// Deprecated: Use ListOceanResourceSuggestionsInput instead.
type ListResourceSuggestionsInput struct { type ListResourceSuggestionsInput struct {
OceanID *string `json:"oceanId,omitempty"` OceanID *string `json:"oceanId,omitempty"`
Namespace *string `json:"namespace,omitempty"` Namespace *string `json:"namespace,omitempty"`
} }
// ListResourceSuggestionsOutput represents the output of `ListResourceSuggestions` function. // Deprecated: Use ListOceanResourceSuggestionsOutput instead.
type ListResourceSuggestionsOutput struct { type ListResourceSuggestionsOutput struct {
Suggestions []*ResourceSuggestion `json:"suggestions,omitempty"` Suggestions []*ResourceSuggestion `json:"suggestions,omitempty"`
} }
// ListOceanResourceSuggestionsInput represents the input of `ListOceanResourceSuggestions` function.
type ListOceanResourceSuggestionsInput struct {
OceanID *string `json:"oceanId,omitempty"`
Filter *Filter `json:"filter,omitempty"`
}
// ListOceanResourceSuggestionsOutput represents the output of `ListOceanResourceSuggestions` function.
type ListOceanResourceSuggestionsOutput struct {
Suggestions []*ResourceSuggestion `json:"suggestions,omitempty"`
}
func resourceSuggestionFromJSON(in []byte) (*ResourceSuggestion, error) { func resourceSuggestionFromJSON(in []byte) (*ResourceSuggestion, error) {
b := new(ResourceSuggestion) b := new(ResourceSuggestion)
if err := json.Unmarshal(in, b); err != nil { if err := json.Unmarshal(in, b); err != nil {
@ -77,8 +106,37 @@ func resourceSuggestionsFromHTTPResponse(resp *http.Response) ([]*ResourceSugges
return resourceSuggestionsFromJSON(body) return resourceSuggestionsFromJSON(body)
} }
// ListResourceSuggestions returns a list of right-sizing resource suggestions // ListOceanResourceSuggestions returns a list of right-sizing resource suggestions
// for an Ocean cluster. // for an Ocean cluster.
func (s *ServiceOp) ListOceanResourceSuggestions(ctx context.Context, input *ListOceanResourceSuggestionsInput) (*ListOceanResourceSuggestionsOutput, error) {
path, err := uritemplates.Expand("/ocean/aws/k8s/cluster/{oceanId}/rightSizing/suggestion", uritemplates.Values{
"oceanId": spotinst.StringValue(input.OceanID),
})
if err != nil {
return nil, err
}
r := client.NewRequest(http.MethodPost, path)
// We do NOT need the ID anymore, so let's drop it.
input.OceanID = nil
r.Obj = input
resp, err := client.RequireOK(s.Client.Do(ctx, r))
if err != nil {
return nil, err
}
defer resp.Body.Close()
rs, err := resourceSuggestionsFromHTTPResponse(resp)
if err != nil {
return nil, err
}
return &ListOceanResourceSuggestionsOutput{Suggestions: rs}, nil
}
// Deprecated: Use ListOceanResourceSuggestions instead.
func (s *ServiceOp) ListResourceSuggestions(ctx context.Context, input *ListResourceSuggestionsInput) (*ListResourceSuggestionsOutput, error) { func (s *ServiceOp) ListResourceSuggestions(ctx context.Context, input *ListResourceSuggestionsInput) (*ListResourceSuggestionsOutput, error) {
path, err := uritemplates.Expand("/ocean/aws/k8s/cluster/{oceanId}/rightSizing/resourceSuggestion", uritemplates.Values{ path, err := uritemplates.Expand("/ocean/aws/k8s/cluster/{oceanId}/rightSizing/resourceSuggestion", uritemplates.Values{
"oceanId": spotinst.StringValue(input.OceanID), "oceanId": spotinst.StringValue(input.OceanID),

View File

@ -62,6 +62,10 @@ type serviceECS interface {
} }
type serviceCommon interface { type serviceCommon interface {
ListOceanResourceSuggestions(context.Context, *ListOceanResourceSuggestionsInput) (*ListOceanResourceSuggestionsOutput, error)
// Deprecated: ListResourceSuggestions is obsolete, exists for backward compatibility only,
// and should not be used. Please use ListOceanResourceSuggestions instead.
ListResourceSuggestions(context.Context, *ListResourceSuggestionsInput) (*ListResourceSuggestionsOutput, error) ListResourceSuggestions(context.Context, *ListResourceSuggestionsInput) (*ListResourceSuggestionsOutput, error)
} }

View File

@ -6,6 +6,7 @@ go_library(
"cluster.go", "cluster.go",
"common.go", "common.go",
"nodegroup.go", "nodegroup.go",
"rightsizing.go",
"service.go", "service.go",
], ],
importmap = "k8s.io/kops/vendor/github.com/spotinst/spotinst-sdk-go/service/ocean/providers/azure", importmap = "k8s.io/kops/vendor/github.com/spotinst/spotinst-sdk-go/service/ocean/providers/azure",

View File

@ -73,7 +73,7 @@ type VirtualNodeGroupTemplate struct {
} }
type ResourceLimits struct { type ResourceLimits struct {
MaxVCPU *int `json:"maxVcpu,omitempty"` MaxVCPU *int `json:"maxVCpu,omitempty"`
MaxMemoryGib *int `json:"maxMemoryGib,omitempty"` MaxMemoryGib *int `json:"maxMemoryGib,omitempty"`
forceSendFields []string forceSendFields []string
@ -104,7 +104,7 @@ type Automatic struct {
} }
type VMSizes struct { type VMSizes struct {
Whitelist []*string `json:"whitelist,omitempty"` Whitelist []string `json:"whitelist,omitempty"`
forceSendFields []string forceSendFields []string
nullFields []string nullFields []string
@ -118,6 +118,7 @@ type LaunchSpecification struct {
OSDisk *OSDisk `json:"osDisk,omitempty"` OSDisk *OSDisk `json:"osDisk,omitempty"`
Login *Login `json:"login,omitempty"` Login *Login `json:"login,omitempty"`
LoadBalancersConfig *LoadBalancersConfig `json:"loadBalancersConfig,omitempty"` LoadBalancersConfig *LoadBalancersConfig `json:"loadBalancersConfig,omitempty"`
ManagedServiceIdentities []*ManagedServiceIdentity `json:"managedServiceIdentities,omitempty"`
Extensions []*Extension `json:"extensions,omitempty"` Extensions []*Extension `json:"extensions,omitempty"`
Tags []*Tag `json:"tags,omitempty"` Tags []*Tag `json:"tags,omitempty"`
@ -131,6 +132,8 @@ type Extension struct {
Name *string `json:"name,omitempty"` Name *string `json:"name,omitempty"`
Publisher *string `json:"publisher,omitempty"` Publisher *string `json:"publisher,omitempty"`
Type *string `json:"type,omitempty"` Type *string `json:"type,omitempty"`
ProtectedSettings interface{} `json:"protectedSettings,omitempty"`
PublicSettings interface{} `json:"publicSettings,omitempty"`
forceSendFields []string forceSendFields []string
nullFields []string nullFields []string
@ -178,7 +181,7 @@ type MarketplaceImage struct {
} }
type LoadBalancer struct { type LoadBalancer struct {
BackendPoolNames []*string `json:"backendPoolNames,omitempty"` BackendPoolNames []string `json:"backendPoolNames,omitempty"`
LoadBalancerSKU *string `json:"loadBalancerSku,omitempty"` LoadBalancerSKU *string `json:"loadBalancerSku,omitempty"`
Name *string `json:"name,omitempty"` Name *string `json:"name,omitempty"`
ResourceGroupName *string `json:"resourceGroupName,omitempty"` ResourceGroupName *string `json:"resourceGroupName,omitempty"`
@ -194,6 +197,7 @@ type NetworkInterface struct {
IsPrimary *bool `json:"isPrimary,omitempty"` IsPrimary *bool `json:"isPrimary,omitempty"`
EnableIPForwarding *bool `json:"enableIPForwarding,omitempty"` EnableIPForwarding *bool `json:"enableIPForwarding,omitempty"`
PublicIPSKU *string `json:"publicIpSku,omitempty"` PublicIPSKU *string `json:"publicIpSku,omitempty"`
SecurityGroup *SecurityGroup `json:"securityGroup,omitempty"`
AdditionalIPConfigs []*AdditionalIPConfig `json:"additionalIpConfigurations,omitempty"` AdditionalIPConfigs []*AdditionalIPConfig `json:"additionalIpConfigurations,omitempty"`
forceSendFields []string forceSendFields []string
@ -216,6 +220,14 @@ type SecurityGroup struct {
nullFields []string nullFields []string
} }
type ManagedServiceIdentity struct {
ResourceGroupName *string `json:"resourceGroupName,omitempty"`
Name *string `json:"name,omitempty"`
forceSendFields []string
nullFields []string
}
type ListClustersInput struct{} type ListClustersInput struct{}
type ListClustersOutput struct { type ListClustersOutput struct {
@ -793,7 +805,7 @@ func (o VMSizes) MarshalJSON() ([]byte, error) {
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields) return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
} }
func (o *VMSizes) SetWhitelist(v []*string) *VMSizes { func (o *VMSizes) SetWhitelist(v []string) *VMSizes {
if o.Whitelist = v; o.Whitelist == nil { if o.Whitelist = v; o.Whitelist == nil {
o.nullFields = append(o.nullFields, "Whitelist") o.nullFields = append(o.nullFields, "Whitelist")
} }
@ -845,6 +857,41 @@ func (o *LaunchSpecification) SetLogin(v *Login) *LaunchSpecification {
return o return o
} }
func (o *LaunchSpecification) SetManagedServiceIdentities(v []*ManagedServiceIdentity) *LaunchSpecification {
if o.ManagedServiceIdentities = v; o.ManagedServiceIdentities == nil {
o.nullFields = append(o.nullFields, "ManagedServiceIdentities")
}
return o
}
func (o *LaunchSpecification) SetExtensions(v []*Extension) *LaunchSpecification {
if o.Extensions = v; o.Extensions == nil {
o.nullFields = append(o.nullFields, "Extensions")
}
return o
}
func (o *LaunchSpecification) SetLoadBalancersConfig(v *LoadBalancersConfig) *LaunchSpecification {
if o.LoadBalancersConfig = v; o.LoadBalancersConfig == nil {
o.nullFields = append(o.nullFields, "LoadBalancersConfig")
}
return o
}
func (o *LaunchSpecification) SetOSDisk(v *OSDisk) *LaunchSpecification {
if o.OSDisk = v; o.OSDisk == nil {
o.nullFields = append(o.nullFields, "OSDisk")
}
return o
}
func (o *LaunchSpecification) SetTags(v []*Tag) *LaunchSpecification {
if o.Tags = v; o.Tags == nil {
o.nullFields = append(o.nullFields, "Tags")
}
return o
}
// endregion // endregion
// region Image // region Image
@ -983,6 +1030,13 @@ func (o *NetworkInterface) SetPublicIPSKU(v *string) *NetworkInterface {
return o return o
} }
func (o *NetworkInterface) SetSecurityGroup(v *SecurityGroup) *NetworkInterface {
if o.SecurityGroup = v; o.SecurityGroup == nil {
o.nullFields = append(o.nullFields, "SecurityGroup")
}
return o
}
// endregion // endregion
// region AdditionalIPConfig // region AdditionalIPConfig
@ -1078,6 +1132,20 @@ func (o *Extension) SetMinorVersionAutoUpgrade(v *bool) *Extension {
return o return o
} }
func (o *Extension) SetProtectedSettings(v interface{}) *Extension {
if o.ProtectedSettings = v; o.ProtectedSettings == nil {
o.nullFields = append(o.nullFields, "ProtectedSettings")
}
return o
}
func (o *Extension) SetPublicSettings(v interface{}) *Extension {
if o.PublicSettings = v; o.PublicSettings == nil {
o.nullFields = append(o.nullFields, "PublicSettings")
}
return o
}
// endregion // endregion
// region LoadBalancersConfig // region LoadBalancersConfig
@ -1088,7 +1156,7 @@ func (o LoadBalancersConfig) MarshalJSON() ([]byte, error) {
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields) return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
} }
func (o *LoadBalancersConfig) SetUserName(v []*LoadBalancer) *LoadBalancersConfig { func (o *LoadBalancersConfig) SetLoadBalancers(v []*LoadBalancer) *LoadBalancersConfig {
if o.LoadBalancers = v; o.LoadBalancers == nil { if o.LoadBalancers = v; o.LoadBalancers == nil {
o.nullFields = append(o.nullFields, "LoadBalancers") o.nullFields = append(o.nullFields, "LoadBalancers")
} }
@ -1133,7 +1201,7 @@ func (o *LoadBalancer) SetType(v *string) *LoadBalancer {
return o return o
} }
func (o *LoadBalancer) SeBackendPoolNames(v []*string) *LoadBalancer { func (o *LoadBalancer) SeBackendPoolNames(v []string) *LoadBalancer {
if o.BackendPoolNames = v; o.BackendPoolNames == nil { if o.BackendPoolNames = v; o.BackendPoolNames == nil {
o.nullFields = append(o.nullFields, "BackendPoolNames") o.nullFields = append(o.nullFields, "BackendPoolNames")
} }
@ -1165,3 +1233,27 @@ func (o *SecurityGroup) SetName(v *string) *SecurityGroup {
} }
// endregion // endregion
// region ManagedServiceIdentity
func (o ManagedServiceIdentity) MarshalJSON() ([]byte, error) {
type noMethod ManagedServiceIdentity
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *ManagedServiceIdentity) SetResourceGroupName(v *string) *ManagedServiceIdentity {
if o.ResourceGroupName = v; o.ResourceGroupName == nil {
o.nullFields = append(o.nullFields, "ResourceGroupName")
}
return o
}
func (o *ManagedServiceIdentity) SetName(v *string) *ManagedServiceIdentity {
if o.Name = v; o.Name == nil {
o.nullFields = append(o.nullFields, "Name")
}
return o
}
// endregion

View File

@ -0,0 +1,134 @@
package azure
import (
"context"
"encoding/json"
"io/ioutil"
"net/http"
"github.com/spotinst/spotinst-sdk-go/spotinst"
"github.com/spotinst/spotinst-sdk-go/spotinst/client"
"github.com/spotinst/spotinst-sdk-go/spotinst/util/uritemplates"
)
type Filter struct {
Attribute *Attribute `json:"attribute,omitempty"`
Namespaces []string `json:"namespaces,omitempty"`
forceSendFields []string
nullFields []string
}
type Attribute struct {
Key *string `json:"key,omitempty"`
Operator *string `json:"operator,omitempty"`
Type *string `json:"type,omitempty"`
Value *string `json:"value,omitempty"`
forceSendFields []string
nullFields []string
}
// ResourceSuggestion represents a single resource suggestion.
type ResourceSuggestion struct {
ResourceName *string `json:"resourceName,omitempty"`
ResourceType *string `json:"resourceType,omitempty"`
Namespace *string `json:"namespace,omitempty"`
SuggestedCPU *float64 `json:"suggestedCPU,omitempty"`
RequestedCPU *float64 `json:"requestedCPU,omitempty"`
SuggestedMemory *float64 `json:"suggestedMemory,omitempty"`
RequestedMemory *float64 `json:"requestedMemory,omitempty"`
Containers []*ContainerResourceSuggestion `json:"containers,omitempty"`
}
// ContainerResourceSuggestion represents a resource suggestion for a
// single container.
type ContainerResourceSuggestion struct {
Name *string `json:"name,omitempty"`
SuggestedCPU *float64 `json:"suggestedCpu,omitempty"`
RequestedCPU *float64 `json:"requestedCpu,omitempty"`
SuggestedMemory *float64 `json:"suggestedMemory,omitempty"`
RequestedMemory *float64 `json:"requestedMemory,omitempty"`
}
// ListResourceSuggestionsInput represents the input of `ListResourceSuggestions` function.
type ListResourceSuggestionsInput struct {
OceanID *string `json:"oceanId,omitempty"`
Namespace *string `json:"namespace,omitempty"`
Filter *Filter `json:"filter,omitempty"`
}
// ListResourceSuggestionsOutput represents the output of `ListResourceSuggestions` function.
type ListResourceSuggestionsOutput struct {
Suggestions []*ResourceSuggestion `json:"suggestions,omitempty"`
}
// region Unmarshallers
func resourceSuggestionFromJSON(in []byte) (*ResourceSuggestion, error) {
b := new(ResourceSuggestion)
if err := json.Unmarshal(in, b); err != nil {
return nil, err
}
return b, nil
}
func resourceSuggestionsFromJSON(in []byte) ([]*ResourceSuggestion, error) {
var rw client.Response
if err := json.Unmarshal(in, &rw); err != nil {
return nil, err
}
out := make([]*ResourceSuggestion, len(rw.Response.Items))
for i, rb := range rw.Response.Items {
b, err := resourceSuggestionFromJSON(rb)
if err != nil {
return nil, err
}
out[i] = b
}
return out, nil
}
func resourceSuggestionsFromHTTPResponse(resp *http.Response) ([]*ResourceSuggestion, error) {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return resourceSuggestionsFromJSON(body)
}
// endregion
// region API request
// ListResourceSuggestions returns a list of right-sizing resource suggestions
// for an Ocean cluster.
func (s *ServiceOp) ListResourceSuggestions(ctx context.Context, input *ListResourceSuggestionsInput) (*ListResourceSuggestionsOutput, error) {
path, err := uritemplates.Expand("/ocean/azure/k8s/cluster/{oceanId}/rightSizing/suggestion", uritemplates.Values{
"oceanId": spotinst.StringValue(input.OceanID),
})
if err != nil {
return nil, err
}
r := client.NewRequest(http.MethodPost, path)
// We do NOT need the ID anymore, so let's drop it.
input.OceanID = nil
r.Obj = input
resp, err := client.RequireOK(s.Client.Do(ctx, r))
if err != nil {
return nil, err
}
defer resp.Body.Close()
rs, err := resourceSuggestionsFromHTTPResponse(resp)
if err != nil {
return nil, err
}
return &ListResourceSuggestionsOutput{Suggestions: rs}, nil
}
//endregion

View File

@ -24,6 +24,7 @@ type Service interface {
ReadVirtualNodeGroup(context.Context, *ReadVirtualNodeGroupInput) (*ReadVirtualNodeGroupOutput, error) ReadVirtualNodeGroup(context.Context, *ReadVirtualNodeGroupInput) (*ReadVirtualNodeGroupOutput, error)
UpdateVirtualNodeGroup(context.Context, *UpdateVirtualNodeGroupInput) (*UpdateVirtualNodeGroupOutput, error) UpdateVirtualNodeGroup(context.Context, *UpdateVirtualNodeGroupInput) (*UpdateVirtualNodeGroupOutput, error)
DeleteVirtualNodeGroup(context.Context, *DeleteVirtualNodeGroupInput) (*DeleteVirtualNodeGroupOutput, error) DeleteVirtualNodeGroup(context.Context, *DeleteVirtualNodeGroupInput) (*DeleteVirtualNodeGroupOutput, error)
ListResourceSuggestions(context.Context, *ListResourceSuggestionsInput) (*ListResourceSuggestionsOutput, error)
} }
type ServiceOp struct { type ServiceOp struct {

View File

@ -60,6 +60,7 @@ type AutoScaler struct {
Headroom *AutoScalerHeadroom `json:"headroom,omitempty"` Headroom *AutoScalerHeadroom `json:"headroom,omitempty"`
ResourceLimits *AutoScalerResourceLimits `json:"resourceLimits,omitempty"` ResourceLimits *AutoScalerResourceLimits `json:"resourceLimits,omitempty"`
Down *AutoScalerDown `json:"down,omitempty"` Down *AutoScalerDown `json:"down,omitempty"`
EnableAutomaticAndManualHeadroom *bool `json:"enableAutomaticAndManualHeadroom,omitempty"`
forceSendFields []string forceSendFields []string
nullFields []string nullFields []string
@ -171,6 +172,7 @@ type LaunchSpecification struct {
ServiceAccount *string `json:"serviceAccount,omitempty"` ServiceAccount *string `json:"serviceAccount,omitempty"`
SourceImage *string `json:"sourceImage,omitempty"` SourceImage *string `json:"sourceImage,omitempty"`
Tags []string `json:"tags,omitempty"` Tags []string `json:"tags,omitempty"`
RootVolumeType *string `json:"rootVolumeType,omitempty"`
forceSendFields []string forceSendFields []string
nullFields []string nullFields []string
@ -254,6 +256,44 @@ type DeleteClusterInput struct {
type DeleteClusterOutput struct{} type DeleteClusterOutput struct{}
type RollSpec struct {
ClusterID *string `json:"clusterId,omitempty"`
Comment *string `json:"comment,omitempty"`
BatchSizePercentage *int `json:"batchSizePercentage,omitempty"`
LaunchSpecIDs []string `json:"launchSpecIds,omitempty"`
InstanceNames []string `json:"instanceNames,omitempty"`
forceSendFields []string
nullFields []string
}
type RollStatus struct {
RollID *string `json:"rollId,omitempty"`
ClusterID *string `json:"oceanId,omitempty"`
Comment *string `json:"comment,omitempty"`
Status *string `json:"status,omitempty"`
Progress *Progress `json:"progress,omitempty"`
BatchNumber *int `json:"batchNumber,omitempty"`
NumOfBatches *int `json:"numOfBatches,omitempty"`
LaunchSpecIDs []string `json:"launchSpecIds,omitempty"`
InstanceNames []string `json:"instanceNames,omitempty"`
CreatedAt *time.Time `json:"createdAt,omitempty"`
UpdatedAt *time.Time `json:"updatedAt,omitempty"`
}
type Progress struct {
Unit *string `json:"unit,omitempty"`
Value *float64 `json:"value,omitempty"`
}
type CreateRollInput struct {
Roll *RollSpec `json:"roll,omitempty"`
}
type CreateRollOutput struct {
Roll *RollStatus `json:"roll,omitempty"`
}
func clusterFromJSON(in []byte) (*Cluster, error) { func clusterFromJSON(in []byte) (*Cluster, error) {
b := new(Cluster) b := new(Cluster)
if err := json.Unmarshal(in, b); err != nil { if err := json.Unmarshal(in, b); err != nil {
@ -472,6 +512,73 @@ func (s *ServiceOp) ImportOceanGKECluster(ctx context.Context, input *ImportOcea
return output, nil return output, nil
} }
func rollStatusFromJSON(in []byte) (*RollStatus, error) {
b := new(RollStatus)
if err := json.Unmarshal(in, b); err != nil {
return nil, err
}
return b, nil
}
func rollStatusesFromJSON(in []byte) ([]*RollStatus, error) {
var rw client.Response
if err := json.Unmarshal(in, &rw); err != nil {
return nil, err
}
out := make([]*RollStatus, len(rw.Response.Items))
if len(out) == 0 {
return out, nil
}
for i, rb := range rw.Response.Items {
b, err := rollStatusFromJSON(rb)
if err != nil {
return nil, err
}
out[i] = b
}
return out, nil
}
func rollStatusesFromHttpResponse(resp *http.Response) ([]*RollStatus, error) {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return rollStatusesFromJSON(body)
}
func (s *ServiceOp) CreateRoll(ctx context.Context, input *CreateRollInput) (*CreateRollOutput, error) {
path, err := uritemplates.Expand("/ocean/gcp/k8s/cluster/{clusterId}/roll", uritemplates.Values{
"clusterId": spotinst.StringValue(input.Roll.ClusterID),
})
if err != nil {
return nil, err
}
input.Roll.ClusterID = nil
r := client.NewRequest(http.MethodPost, path)
r.Obj = input
resp, err := client.RequireOK(s.Client.Do(ctx, r))
if err != nil {
return nil, err
}
defer resp.Body.Close()
v, err := rollStatusesFromHttpResponse(resp)
if err != nil {
return nil, err
}
output := new(CreateRollOutput)
if len(v) > 0 {
output.Roll = v[0]
}
return output, nil
}
// region Cluster // region Cluster
func (o Cluster) MarshalJSON() ([]byte, error) { func (o Cluster) MarshalJSON() ([]byte, error) {
@ -853,6 +960,13 @@ func (o *LaunchSpecification) SetTags(v []string) *LaunchSpecification {
return o return o
} }
func (o *LaunchSpecification) SetRootVolumeType(v *string) *LaunchSpecification {
if o.RootVolumeType = v; o.RootVolumeType == nil {
o.nullFields = append(o.nullFields, "RootVolumeType")
}
return o
}
// endregion // endregion
// region BackendService // region BackendService
@ -1085,6 +1199,13 @@ func (o *AutoScaler) SetDown(v *AutoScalerDown) *AutoScaler {
return o return o
} }
func (o *AutoScaler) SetEnableAutomaticAndManualHeadroom(v *bool) *AutoScaler {
if o.EnableAutomaticAndManualHeadroom = v; o.EnableAutomaticAndManualHeadroom == nil {
o.nullFields = append(o.nullFields, "EnableAutomaticAndManualHeadroom")
}
return o
}
// endregion // endregion
// region AutoScalerHeadroom // region AutoScalerHeadroom
@ -1173,3 +1294,41 @@ func (o *AutoScalerDown) SetMaxScaleDownPercentage(v *float64) *AutoScalerDown {
} }
// endregion // endregion
// region RollSpec
func (o RollSpec) MarshalJSON() ([]byte, error) {
type noMethod RollSpec
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *RollSpec) SetComment(v *string) *RollSpec {
if o.Comment = v; o.Comment == nil {
o.nullFields = append(o.nullFields, "Comment")
}
return o
}
func (o *RollSpec) SetBatchSizePercentage(v *int) *RollSpec {
if o.BatchSizePercentage = v; o.BatchSizePercentage == nil {
o.nullFields = append(o.nullFields, "BatchSizePercentage")
}
return o
}
func (o *RollSpec) SetLaunchSpecIDs(v []string) *RollSpec {
if o.LaunchSpecIDs = v; o.LaunchSpecIDs == nil {
o.nullFields = append(o.nullFields, "LaunchSpecIDs")
}
return o
}
func (o *RollSpec) SetInstanceNames(v []string) *RollSpec {
if o.InstanceNames = v; o.InstanceNames == nil {
o.nullFields = append(o.nullFields, "InstanceNames")
}
return o
}
// endregion

View File

@ -14,6 +14,7 @@ import (
type LaunchSpec struct { type LaunchSpec struct {
ID *string `json:"id,omitempty"` ID *string `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
OceanID *string `json:"oceanId,omitempty"` OceanID *string `json:"oceanId,omitempty"`
SourceImage *string `json:"sourceImage,omitempty"` SourceImage *string `json:"sourceImage,omitempty"`
Metadata []*Metadata `json:"metadata,omitempty"` Metadata []*Metadata `json:"metadata,omitempty"`
@ -21,6 +22,16 @@ type LaunchSpec struct {
Taints []*Taint `json:"taints,omitempty"` Taints []*Taint `json:"taints,omitempty"`
AutoScale *AutoScale `json:"autoScale,omitempty"` AutoScale *AutoScale `json:"autoScale,omitempty"`
RestrictScaleDown *bool `json:"restrictScaleDown,omitempty"` RestrictScaleDown *bool `json:"restrictScaleDown,omitempty"`
Tags []*Tag `json:"tags,omitempty"`
Strategy *LaunchSpecStrategy `json:"strategy,omitempty"`
RootVolumeSizeInGB *int `json:"rootVolumeSizeInGb,omitempty"`
RootVolumeType *string `json:"rootVolumeType,omitempty"`
ShieldedInstanceConfig *ShieldedInstanceConfig `json:"shieldedInstanceConfig,omitempty"`
ServiceAccount *string `json:"serviceAccount,omitempty"`
InstanceTypes []string `json:"instanceTypes,omitempty"`
Storage *Storage `json:"storage,omitempty"`
ResourceLimits *ResourceLimits `json:"resourceLimits,omitempty"`
LaunchSpecScheduling *GKELaunchSpecScheduling `json:"scheduling,omitempty"`
// forceSendFields is a list of field names (e.g. "Keys") to // forceSendFields is a list of field names (e.g. "Keys") to
// unconditionally include in API requests. By default, fields with // unconditionally include in API requests. By default, fields with
@ -73,6 +84,70 @@ type AutoScaleHeadroom struct {
nullFields []string nullFields []string
} }
type LaunchSpecStrategy struct {
PreemptiblePercentage *int `json:"preemptiblePercentage,omitempty"`
forceSendFields []string
nullFields []string
}
type ShieldedInstanceConfig struct {
EnableSecureBoot *bool `json:"enableSecureBoot,omitempty"`
EnableIntegrityMonitoring *bool `json:"enableIntegrityMonitoring,omitempty"`
forceSendFields []string
nullFields []string
}
type Storage struct {
LocalSSDCount *int `json:"localSsdCount,omitempty"`
forceSendFields []string
nullFields []string
}
type ResourceLimits struct {
MaxInstanceCount *int `json:"maxInstanceCount,omitempty"`
MinInstanceCount *int `json:"minInstanceCount,omitempty"`
forceSendFields []string
nullFields []string
}
type GKELaunchSpecScheduling struct {
Tasks []*GKELaunchSpecTask `json:"tasks,omitempty"`
forceSendFields []string
nullFields []string
}
type GKELaunchSpecTask struct {
IsEnabled *bool `json:"isEnabled,omitempty"`
CronExpression *string `json:"cronExpression,omitempty"`
TaskType *string `json:"taskType,omitempty"`
Config *GKETaskConfig `json:"config,omitempty"`
forceSendFields []string
nullFields []string
}
type GKETaskConfig struct {
TaskHeadrooms []*GKELaunchSpecTaskHeadroom `json:"headrooms,omitempty"`
forceSendFields []string
nullFields []string
}
type GKELaunchSpecTaskHeadroom struct {
CPUPerUnit *int `json:"cpuPerUnit,omitempty"`
GPUPerUnit *int `json:"gpuPerUnit,omitempty"`
MemoryPerUnit *int `json:"memoryPerUnit,omitempty"`
NumOfUnits *int `json:"numOfUnits,omitempty"`
forceSendFields []string
nullFields []string
}
type ListLaunchSpecsInput struct { type ListLaunchSpecsInput struct {
OceanID *string `json:"oceanId,omitempty"` OceanID *string `json:"oceanId,omitempty"`
} }
@ -322,6 +397,13 @@ func (o *LaunchSpec) SetOceanId(v *string) *LaunchSpec {
return o return o
} }
func (o *LaunchSpec) SetName(v *string) *LaunchSpec {
if o.Name = v; o.Name == nil {
o.nullFields = append(o.nullFields, "Name")
}
return o
}
func (o *LaunchSpec) SetSourceImage(v *string) *LaunchSpec { func (o *LaunchSpec) SetSourceImage(v *string) *LaunchSpec {
if o.SourceImage = v; o.SourceImage == nil { if o.SourceImage = v; o.SourceImage == nil {
o.nullFields = append(o.nullFields, "SourceImage") o.nullFields = append(o.nullFields, "SourceImage")
@ -364,6 +446,76 @@ func (o *LaunchSpec) SetRestrictScaleDown(v *bool) *LaunchSpec {
return o return o
} }
func (o *LaunchSpec) SetStrategy(v *LaunchSpecStrategy) *LaunchSpec {
if o.Strategy = v; o.Strategy == nil {
o.nullFields = append(o.nullFields, "Strategy")
}
return o
}
func (o *LaunchSpec) SetRootVolumeSizeInGB(v *int) *LaunchSpec {
if o.RootVolumeSizeInGB = v; o.RootVolumeSizeInGB == nil {
o.nullFields = append(o.nullFields, "RootVolumeSizeInGB")
}
return o
}
func (o *LaunchSpec) SetRootVolumeType(v *string) *LaunchSpec {
if o.RootVolumeType = v; o.RootVolumeType == nil {
o.nullFields = append(o.nullFields, "RootVolumeType")
}
return o
}
func (o *LaunchSpec) SetServiceAccount(v *string) *LaunchSpec {
if o.ServiceAccount = v; o.ServiceAccount == nil {
o.nullFields = append(o.nullFields, "ServiceAccount")
}
return o
}
func (o *LaunchSpec) SetTags(v []*Tag) *LaunchSpec {
if o.Tags = v; o.Tags == nil {
o.nullFields = append(o.nullFields, "Tags")
}
return o
}
func (o *LaunchSpec) SetShieldedInstanceConfig(v *ShieldedInstanceConfig) *LaunchSpec {
if o.ShieldedInstanceConfig = v; o.ShieldedInstanceConfig == nil {
o.nullFields = append(o.nullFields, "ShieldedInstanceConfig")
}
return o
}
func (o *LaunchSpec) SetInstanceTypes(v []string) *LaunchSpec {
if o.InstanceTypes = v; o.InstanceTypes == nil {
o.nullFields = append(o.nullFields, "InstanceTypes")
}
return o
}
func (o *LaunchSpec) SetStorage(v *Storage) *LaunchSpec {
if o.Storage = v; o.Storage == nil {
o.nullFields = append(o.nullFields, "Storage")
}
return o
}
func (o *LaunchSpec) SetResourceLimits(v *ResourceLimits) *LaunchSpec {
if o.ResourceLimits = v; o.ResourceLimits == nil {
o.nullFields = append(o.nullFields, "ResourceLimits")
}
return o
}
func (o *LaunchSpec) SetScheduling(v *GKELaunchSpecScheduling) *LaunchSpec {
if o.LaunchSpecScheduling = v; o.LaunchSpecScheduling == nil {
o.nullFields = append(o.nullFields, "GKELaunchSpecScheduling")
}
return o
}
// endregion // endregion
// region Label // region Label
@ -489,3 +641,195 @@ func (o *AutoScaleHeadroom) SetNumOfUnits(v *int) *AutoScaleHeadroom {
} }
// endregion // endregion
// region Strategy
func (o LaunchSpecStrategy) MarshalJSON() ([]byte, error) {
type noMethod LaunchSpecStrategy
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *LaunchSpecStrategy) SetPreemptiblePercentage(v *int) *LaunchSpecStrategy {
if o.PreemptiblePercentage = v; o.PreemptiblePercentage == nil {
o.nullFields = append(o.nullFields, "PreemptiblePercentage")
}
return o
}
//endregion
// region ShieldedInstanceConfig
func (o ShieldedInstanceConfig) MarshalJSON() ([]byte, error) {
type noMethod ShieldedInstanceConfig
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *ShieldedInstanceConfig) SetEnableIntegrityMonitoring(v *bool) *ShieldedInstanceConfig {
if o.EnableIntegrityMonitoring = v; o.EnableIntegrityMonitoring == nil {
o.nullFields = append(o.nullFields, "EnableIntegrityMonitoring")
}
return o
}
func (o *ShieldedInstanceConfig) SetEnableSecureBoot(v *bool) *ShieldedInstanceConfig {
if o.EnableSecureBoot = v; o.EnableSecureBoot == nil {
o.nullFields = append(o.nullFields, "EnableSecureBoot")
}
return o
}
//endregion
// region Storage
func (o Storage) MarshalJSON() ([]byte, error) {
type noMethod Storage
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *Storage) SetLocalSSDCount(v *int) *Storage {
if o.LocalSSDCount = v; o.LocalSSDCount == nil {
o.nullFields = append(o.nullFields, "LocalSSDCount")
}
return o
}
//endregion
// region ResourceLimits
func (o ResourceLimits) MarshalJSON() ([]byte, error) {
type noMethod ResourceLimits
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *ResourceLimits) SetMaxInstanceCount(v *int) *ResourceLimits {
if o.MaxInstanceCount = v; o.MaxInstanceCount == nil {
o.nullFields = append(o.nullFields, "MaxInstanceCount")
}
return o
}
func (o *ResourceLimits) SetMinInstanceCount(v *int) *ResourceLimits {
if o.MinInstanceCount = v; o.MinInstanceCount == nil {
o.nullFields = append(o.nullFields, "MinInstanceCount")
}
return o
}
//endregion
//region Scheduling
func (o GKELaunchSpecScheduling) MarshalJSON() ([]byte, error) {
type noMethod GKELaunchSpecScheduling
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *GKELaunchSpecScheduling) SetTasks(v []*GKELaunchSpecTask) *GKELaunchSpecScheduling {
if o.Tasks = v; o.Tasks == nil {
o.nullFields = append(o.nullFields, "Tasks")
}
return o
}
// endregion
//region LaunchSpecTask
func (o GKELaunchSpecTask) MarshalJSON() ([]byte, error) {
type noMethod GKELaunchSpecTask
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *GKELaunchSpecTask) SetIsEnabled(v *bool) *GKELaunchSpecTask {
if o.IsEnabled = v; o.IsEnabled == nil {
o.nullFields = append(o.nullFields, "IsEnabled")
}
return o
}
func (o *GKELaunchSpecTask) SetCronExpression(v *string) *GKELaunchSpecTask {
if o.CronExpression = v; o.CronExpression == nil {
o.nullFields = append(o.nullFields, "CronExpression")
}
return o
}
func (o *GKELaunchSpecTask) SetTaskType(v *string) *GKELaunchSpecTask {
if o.TaskType = v; o.TaskType == nil {
o.nullFields = append(o.nullFields, "TaskType")
}
return o
}
func (o *GKELaunchSpecTask) SetTaskConfig(v *GKETaskConfig) *GKELaunchSpecTask {
if o.Config = v; o.Config == nil {
o.nullFields = append(o.nullFields, "Config")
}
return o
}
// endregion
//region TaskConfig
func (o GKETaskConfig) MarshalJSON() ([]byte, error) {
type noMethod GKETaskConfig
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *GKETaskConfig) SetHeadrooms(v []*GKELaunchSpecTaskHeadroom) *GKETaskConfig {
if o.TaskHeadrooms = v; o.TaskHeadrooms == nil {
o.nullFields = append(o.nullFields, "TaskHeadroom")
}
return o
}
// endregion
// region LaunchSpecTaskHeadroom
func (o GKELaunchSpecTaskHeadroom) MarshalJSON() ([]byte, error) {
type noMethod GKELaunchSpecTaskHeadroom
raw := noMethod(o)
return jsonutil.MarshalJSON(raw, o.forceSendFields, o.nullFields)
}
func (o *GKELaunchSpecTaskHeadroom) SetCPUPerUnit(v *int) *GKELaunchSpecTaskHeadroom {
if o.CPUPerUnit = v; o.CPUPerUnit == nil {
o.nullFields = append(o.nullFields, "CPUPerUnit")
}
return o
}
func (o *GKELaunchSpecTaskHeadroom) SetGPUPerUnit(v *int) *GKELaunchSpecTaskHeadroom {
if o.GPUPerUnit = v; o.GPUPerUnit == nil {
o.nullFields = append(o.nullFields, "GPUPerUnit")
}
return o
}
func (o *GKELaunchSpecTaskHeadroom) SetMemoryPerUnit(v *int) *GKELaunchSpecTaskHeadroom {
if o.MemoryPerUnit = v; o.MemoryPerUnit == nil {
o.nullFields = append(o.nullFields, "MemoryPerUnit")
}
return o
}
func (o *GKELaunchSpecTaskHeadroom) SetNumOfUnits(v *int) *GKELaunchSpecTaskHeadroom {
if o.NumOfUnits = v; o.NumOfUnits == nil {
o.nullFields = append(o.nullFields, "NumOfUnits")
}
return o
}
// endregion

View File

@ -26,6 +26,8 @@ type Service interface {
ImportOceanGKECluster(ctx context.Context, input *ImportOceanGKEClusterInput) (*ImportOceanGKEClusterOutput, error) ImportOceanGKECluster(ctx context.Context, input *ImportOceanGKEClusterInput) (*ImportOceanGKEClusterOutput, error)
ImportOceanGKELaunchSpec(ctx context.Context, input *ImportOceanGKELaunchSpecInput) (*ImportOceanGKELaunchSpecOutput, error) ImportOceanGKELaunchSpec(ctx context.Context, input *ImportOceanGKELaunchSpecInput) (*ImportOceanGKELaunchSpecOutput, error)
CreateRoll(context.Context, *CreateRollInput) (*CreateRollOutput, error)
} }
type ServiceOp struct { type ServiceOp struct {

View File

@ -1,7 +1,7 @@
package spotinst package spotinst
// SDKVersion is the current version of the SDK. // SDKVersion is the current version of the SDK.
const SDKVersion = "1.85.0" const SDKVersion = "1.110.0"
// SDKName is the name of the SDK. // SDKName is the name of the SDK.
const SDKName = "spotinst-sdk-go" const SDKName = "spotinst-sdk-go"

12
vendor/gopkg.in/ini.v1/.editorconfig generated vendored Normal file
View File

@ -0,0 +1,12 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*_test.go]
trim_trailing_whitespace = false

1
vendor/gopkg.in/ini.v1/.gitignore generated vendored
View File

@ -4,3 +4,4 @@ ini.sublime-workspace
testdata/conf_reflect.ini testdata/conf_reflect.ini
.idea .idea
/.vscode /.vscode
.DS_Store

21
vendor/gopkg.in/ini.v1/.golangci.yml generated vendored Normal file
View File

@ -0,0 +1,21 @@
linters-settings:
nakedret:
max-func-lines: 0 # Disallow any unnamed return statement
linters:
enable:
- deadcode
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- structcheck
- typecheck
- unused
- varcheck
- nakedret
- gofmt
- rowserrcheck
- unconvert
- goimports

2
vendor/gopkg.in/ini.v1/README.md generated vendored
View File

@ -24,7 +24,7 @@ Package ini provides INI file read and write functionality in Go.
## Installation ## Installation
The minimum requirement of Go is **1.6**. The minimum requirement of Go is **1.12**.
```sh ```sh
$ go get gopkg.in/ini.v1 $ go get gopkg.in/ini.v1

2
vendor/gopkg.in/ini.v1/codecov.yml generated vendored
View File

@ -6,4 +6,4 @@ coverage:
threshold: 1% threshold: 1%
comment: comment:
layout: 'diff, files' layout: 'diff'

34
vendor/gopkg.in/ini.v1/file.go generated vendored
View File

@ -142,6 +142,12 @@ func (f *File) GetSection(name string) (*Section, error) {
return secs[0], err return secs[0], err
} }
// HasSection returns true if the file contains a section with given name.
func (f *File) HasSection(name string) bool {
section, _ := f.GetSection(name)
return section != nil
}
// SectionsByName returns all sections with given name. // SectionsByName returns all sections with given name.
func (f *File) SectionsByName(name string) ([]*Section, error) { func (f *File) SectionsByName(name string) ([]*Section, error) {
if len(name) == 0 { if len(name) == 0 {
@ -168,8 +174,9 @@ func (f *File) SectionsByName(name string) ([]*Section, error) {
func (f *File) Section(name string) *Section { func (f *File) Section(name string) *Section {
sec, err := f.GetSection(name) sec, err := f.GetSection(name)
if err != nil { if err != nil {
// Note: It's OK here because the only possible error is empty section name, if name == "" {
// but if it's empty, this piece of code won't be executed. name = DefaultSection
}
sec, _ = f.NewSection(name) sec, _ = f.NewSection(name)
return sec return sec
} }
@ -435,16 +442,16 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
kname = `"""` + kname + `"""` kname = `"""` + kname + `"""`
} }
for _, val := range key.ValueWithShadows() { writeKeyValue := func(val string) (bool, error) {
if _, err := buf.WriteString(kname); err != nil { if _, err := buf.WriteString(kname); err != nil {
return nil, err return false, err
} }
if key.isBooleanType { if key.isBooleanType {
if kname != sec.keyList[len(sec.keyList)-1] { if kname != sec.keyList[len(sec.keyList)-1] {
buf.WriteString(LineBreak) buf.WriteString(LineBreak)
} }
continue KeyList return true, nil
} }
// Write out alignment spaces before "=" sign // Write out alignment spaces before "=" sign
@ -461,10 +468,27 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
val = `"` + val + `"` val = `"` + val + `"`
} }
if _, err := buf.WriteString(equalSign + val + LineBreak); err != nil { if _, err := buf.WriteString(equalSign + val + LineBreak); err != nil {
return false, err
}
return false, nil
}
shadows := key.ValueWithShadows()
if len(shadows) == 0 {
if _, err := writeKeyValue(""); err != nil {
return nil, err return nil, err
} }
} }
for _, val := range shadows {
exitLoop, err := writeKeyValue(val)
if err != nil {
return nil, err
} else if exitLoop {
continue KeyList
}
}
for _, val := range key.nestedValues { for _, val := range key.nestedValues {
if _, err := buf.WriteString(indent + " " + val + LineBreak); err != nil { if _, err := buf.WriteString(indent + " " + val + LineBreak); err != nil {
return nil, err return nil, err

4
vendor/gopkg.in/ini.v1/ini.go generated vendored
View File

@ -1,5 +1,3 @@
// +build go1.6
// Copyright 2014 Unknwon // Copyright 2014 Unknwon
// //
// Licensed under the Apache License, Version 2.0 (the "License"): you may // Licensed under the Apache License, Version 2.0 (the "License"): you may
@ -125,6 +123,8 @@ type LoadOptions struct {
ReaderBufferSize int ReaderBufferSize int
// AllowNonUniqueSections indicates whether to allow sections with the same name multiple times. // AllowNonUniqueSections indicates whether to allow sections with the same name multiple times.
AllowNonUniqueSections bool AllowNonUniqueSections bool
// AllowDuplicateShadowValues indicates whether values for shadowed keys should be deduplicated.
AllowDuplicateShadowValues bool
} }
// DebugFunc is the type of function called to log parse events. // DebugFunc is the type of function called to log parse events.

8
vendor/gopkg.in/ini.v1/key.go generated vendored
View File

@ -54,6 +54,7 @@ func (k *Key) addShadow(val string) error {
return errors.New("cannot add shadow to auto-increment or boolean key") return errors.New("cannot add shadow to auto-increment or boolean key")
} }
if !k.s.f.options.AllowDuplicateShadowValues {
// Deduplicate shadows based on their values. // Deduplicate shadows based on their values.
if k.value == val { if k.value == val {
return nil return nil
@ -63,6 +64,7 @@ func (k *Key) addShadow(val string) error {
return nil return nil
} }
} }
}
shadow := newKey(k.s, k.name, val) shadow := newKey(k.s, k.name, val)
shadow.isShadow = true shadow.isShadow = true
@ -111,6 +113,9 @@ func (k *Key) Value() string {
// ValueWithShadows returns raw values of key and its shadows if any. // ValueWithShadows returns raw values of key and its shadows if any.
func (k *Key) ValueWithShadows() []string { func (k *Key) ValueWithShadows() []string {
if len(k.shadows) == 0 { if len(k.shadows) == 0 {
if k.value == "" {
return []string{}
}
return []string{k.value} return []string{k.value}
} }
vals := make([]string, len(k.shadows)+1) vals := make([]string, len(k.shadows)+1)
@ -781,10 +786,8 @@ func (k *Key) parseUint64s(strs []string, addInvalid, returnOnInvalid bool) ([]u
return vals, err return vals, err
} }
type Parser func(str string) (interface{}, error) type Parser func(str string) (interface{}, error)
// parseTimesFormat transforms strings to times in given format. // parseTimesFormat transforms strings to times in given format.
func (k *Key) parseTimesFormat(format string, strs []string, addInvalid, returnOnInvalid bool) ([]time.Time, error) { func (k *Key) parseTimesFormat(format string, strs []string, addInvalid, returnOnInvalid bool) ([]time.Time, error) {
vals := make([]time.Time, 0, len(strs)) vals := make([]time.Time, 0, len(strs))
@ -801,7 +804,6 @@ func (k *Key) parseTimesFormat(format string, strs []string, addInvalid, returnO
return vals, err return vals, err
} }
// doParse transforms strings to different types // doParse transforms strings to different types
func (k *Key) doParse(strs []string, addInvalid, returnOnInvalid bool, parser Parser) ([]interface{}, error) { func (k *Key) doParse(strs []string, addInvalid, returnOnInvalid bool, parser Parser) ([]interface{}, error) {
vals := make([]interface{}, 0, len(strs)) vals := make([]interface{}, 0, len(strs))

38
vendor/gopkg.in/ini.v1/parser.go generated vendored
View File

@ -131,7 +131,7 @@ func readKeyName(delimiters string, in []byte) (string, int, error) {
// Check if key name surrounded by quotes. // Check if key name surrounded by quotes.
var keyQuote string var keyQuote string
if line[0] == '"' { if line[0] == '"' {
if len(line) > 6 && string(line[0:3]) == `"""` { if len(line) > 6 && line[0:3] == `"""` {
keyQuote = `"""` keyQuote = `"""`
} else { } else {
keyQuote = `"` keyQuote = `"`
@ -232,7 +232,7 @@ func (p *parser) readValue(in []byte, bufferSize int) (string, error) {
} }
var valQuote string var valQuote string
if len(line) > 3 && string(line[0:3]) == `"""` { if len(line) > 3 && line[0:3] == `"""` {
valQuote = `"""` valQuote = `"""`
} else if line[0] == '`' { } else if line[0] == '`' {
valQuote = "`" valQuote = "`"
@ -289,12 +289,8 @@ func (p *parser) readValue(in []byte, bufferSize int) (string, error) {
hasSurroundedQuote(line, '"')) && !p.options.PreserveSurroundedQuote { hasSurroundedQuote(line, '"')) && !p.options.PreserveSurroundedQuote {
line = line[1 : len(line)-1] line = line[1 : len(line)-1]
} else if len(valQuote) == 0 && p.options.UnescapeValueCommentSymbols { } else if len(valQuote) == 0 && p.options.UnescapeValueCommentSymbols {
if strings.Contains(line, `\;`) { line = strings.ReplaceAll(line, `\;`, ";")
line = strings.Replace(line, `\;`, ";", -1) line = strings.ReplaceAll(line, `\#`, "#")
}
if strings.Contains(line, `\#`) {
line = strings.Replace(line, `\#`, "#", -1)
}
} else if p.options.AllowPythonMultilineValues && lastChar == '\n' { } else if p.options.AllowPythonMultilineValues && lastChar == '\n' {
return p.readPythonMultilines(line, bufferSize) return p.readPythonMultilines(line, bufferSize)
} }
@ -306,15 +302,9 @@ func (p *parser) readPythonMultilines(line string, bufferSize int) (string, erro
parserBufferPeekResult, _ := p.buf.Peek(bufferSize) parserBufferPeekResult, _ := p.buf.Peek(bufferSize)
peekBuffer := bytes.NewBuffer(parserBufferPeekResult) peekBuffer := bytes.NewBuffer(parserBufferPeekResult)
indentSize := 0
for { for {
peekData, peekErr := peekBuffer.ReadBytes('\n') peekData, peekErr := peekBuffer.ReadBytes('\n')
if peekErr != nil { if peekErr != nil && peekErr != io.EOF {
if peekErr == io.EOF {
p.debug("readPythonMultilines: io.EOF, peekData: %q, line: %q", string(peekData), line)
return line, nil
}
p.debug("readPythonMultilines: failed to peek with error: %v", peekErr) p.debug("readPythonMultilines: failed to peek with error: %v", peekErr)
return "", peekErr return "", peekErr
} }
@ -333,19 +323,6 @@ func (p *parser) readPythonMultilines(line string, bufferSize int) (string, erro
return line, nil return line, nil
} }
// Determine indent size and line prefix.
currentIndentSize := len(peekMatches[1])
if indentSize < 1 {
indentSize = currentIndentSize
p.debug("readPythonMultilines: indent size is %d", indentSize)
}
// Make sure each line is indented at least as far as first line.
if currentIndentSize < indentSize {
p.debug("readPythonMultilines: end of value, current indent: %d, expected indent: %d, line: %q", currentIndentSize, indentSize, line)
return line, nil
}
// Advance the parser reader (buffer) in-sync with the peek buffer. // Advance the parser reader (buffer) in-sync with the peek buffer.
_, err := p.buf.Discard(len(peekData)) _, err := p.buf.Discard(len(peekData))
if err != nil { if err != nil {
@ -353,8 +330,7 @@ func (p *parser) readPythonMultilines(line string, bufferSize int) (string, erro
return "", err return "", err
} }
// Handle indented empty line. line += "\n" + peekMatches[0]
line += "\n" + peekMatches[1][indentSize:] + peekMatches[2]
} }
} }
@ -465,6 +441,8 @@ func (f *File) parse(reader io.Reader) (err error) {
// Reset auto-counter and comments // Reset auto-counter and comments
p.comment.Reset() p.comment.Reset()
p.count = 1 p.count = 1
// Nested values can't span sections
isLastValueEmpty = false
inUnparseableSection = false inUnparseableSection = false
for i := range f.options.UnparseableSections { for i := range f.options.UnparseableSections {

2
vendor/gopkg.in/ini.v1/section.go generated vendored
View File

@ -217,7 +217,7 @@ func (s *Section) KeysHash() map[string]string {
defer s.f.lock.RUnlock() defer s.f.lock.RUnlock()
} }
hash := map[string]string{} hash := make(map[string]string, len(s.keysHash))
for key, value := range s.keysHash { for key, value := range s.keysHash {
hash[key] = value hash[key] = value
} }

4
vendor/modules.txt generated vendored
View File

@ -709,7 +709,7 @@ github.com/spf13/pflag
# github.com/spf13/viper v1.8.1 # github.com/spf13/viper v1.8.1
## explicit; go 1.12 ## explicit; go 1.12
github.com/spf13/viper github.com/spf13/viper
# github.com/spotinst/spotinst-sdk-go v1.85.0 # github.com/spotinst/spotinst-sdk-go v1.110.0
## explicit; go 1.16 ## explicit; go 1.16
github.com/spotinst/spotinst-sdk-go/service/elastigroup github.com/spotinst/spotinst-sdk-go/service/elastigroup
github.com/spotinst/spotinst-sdk-go/service/elastigroup/providers/aws github.com/spotinst/spotinst-sdk-go/service/elastigroup/providers/aws
@ -1012,7 +1012,7 @@ gopkg.in/gcfg.v1/types
# gopkg.in/inf.v0 v0.9.1 # gopkg.in/inf.v0 v0.9.1
## explicit ## explicit
gopkg.in/inf.v0 gopkg.in/inf.v0
# gopkg.in/ini.v1 v1.62.0 # gopkg.in/ini.v1 v1.66.3
## explicit ## explicit
gopkg.in/ini.v1 gopkg.in/ini.v1
# gopkg.in/square/go-jose.v2 v2.5.1 # gopkg.in/square/go-jose.v2 v2.5.1