From 4264d78839d743edb20af84e7e576c9f0f450e46 Mon Sep 17 00:00:00 2001 From: Ivan Volynkin Date: Thu, 23 Jun 2022 10:00:02 +0300 Subject: [PATCH] Adding GuestAccelerators to InstanceTemplate --- k8s/crds/kops.k8s.io_instancegroups.yaml | 12 +++++ pkg/apis/kops/instancegroup.go | 8 +++ pkg/apis/kops/v1alpha2/instancegroup.go | 8 +++ .../kops/v1alpha2/zz_generated.conversion.go | 54 +++++++++++++++++++ .../kops/v1alpha2/zz_generated.deepcopy.go | 21 ++++++++ pkg/apis/kops/v1alpha3/instancegroup.go | 8 +++ .../kops/v1alpha3/zz_generated.conversion.go | 54 +++++++++++++++++++ .../kops/v1alpha3/zz_generated.deepcopy.go | 21 ++++++++ pkg/apis/kops/zz_generated.deepcopy.go | 21 ++++++++ pkg/model/gcemodel/autoscalinggroup.go | 8 +++ .../fi/cloudup/gcetasks/accelerator_config.go | 47 ++++++++++++++++ .../fi/cloudup/gcetasks/instancetemplate.go | 44 +++++++++++++++ 12 files changed, 306 insertions(+) create mode 100644 upup/pkg/fi/cloudup/gcetasks/accelerator_config.go diff --git a/k8s/crds/kops.k8s.io_instancegroups.yaml b/k8s/crds/kops.k8s.io_instancegroups.yaml index 62cacbec47..8bb427a37b 100644 --- a/k8s/crds/kops.k8s.io_instancegroups.yaml +++ b/k8s/crds/kops.k8s.io_instancegroups.yaml @@ -222,6 +222,18 @@ spec: type: array type: object type: array + guestAccelerators: + description: GuestAccelerators configures additional accelerators + items: + description: AcceleratorConfig defines an accelerator config + properties: + acceleratorCount: + format: int64 + type: integer + acceleratorType: + type: string + type: object + type: array hooks: description: 'Hooks is a list of hooks for this instanceGroup, note: these can override the cluster wide ones if required' diff --git a/pkg/apis/kops/instancegroup.go b/pkg/apis/kops/instancegroup.go index 0625c69f3c..e43b10e506 100644 --- a/pkg/apis/kops/instancegroup.go +++ b/pkg/apis/kops/instancegroup.go @@ -194,6 +194,8 @@ type InstanceGroupSpec struct { Containerd *ContainerdConfig `json:"containerd,omitempty"` // Packages specifies additional packages to be installed. Packages []string `json:"packages,omitempty"` + // GuestAccelerators configures additional accelerators + GuestAccelerators []AcceleratorConfig `json:"guestAccelerators,omitempty"` } const ( @@ -363,3 +365,9 @@ type LoadBalancer struct { // TargetGroupARN to associate with this instance group (AWS ALB/NLB) TargetGroupARN *string `json:"targetGroupARN,omitempty"` } + +// AcceleratorConfig defines an accelerator config +type AcceleratorConfig struct { + AcceleratorCount int64 `json:"acceleratorCount,omitempty"` + AcceleratorType string `json:"acceleratorType,omitempty"` +} diff --git a/pkg/apis/kops/v1alpha2/instancegroup.go b/pkg/apis/kops/v1alpha2/instancegroup.go index d8d781dd3e..972d51016e 100644 --- a/pkg/apis/kops/v1alpha2/instancegroup.go +++ b/pkg/apis/kops/v1alpha2/instancegroup.go @@ -160,6 +160,8 @@ type InstanceGroupSpec struct { Containerd *ContainerdConfig `json:"containerd,omitempty"` // Packages specifies additional packages to be installed. Packages []string `json:"packages,omitempty"` + // GuestAccelerators configures additional accelerators + GuestAccelerators []AcceleratorConfig `json:"guestAccelerators,omitempty"` } // InstanceMetadataOptions defines the EC2 instance metadata service options (AWS Only) @@ -268,3 +270,9 @@ type LoadBalancer struct { // TargetGroupARN to associate with this instance group (AWS ALB/NLB) TargetGroupARN *string `json:"targetGroupArn,omitempty"` } + +// AcceleratorConfig defines an accelerator config +type AcceleratorConfig struct { + AcceleratorCount int64 `json:"acceleratorCount,omitempty"` + AcceleratorType string `json:"acceleratorType,omitempty"` +} diff --git a/pkg/apis/kops/v1alpha2/zz_generated.conversion.go b/pkg/apis/kops/v1alpha2/zz_generated.conversion.go index 91b24cdbc5..876cd59864 100644 --- a/pkg/apis/kops/v1alpha2/zz_generated.conversion.go +++ b/pkg/apis/kops/v1alpha2/zz_generated.conversion.go @@ -84,6 +84,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*AcceleratorConfig)(nil), (*kops.AcceleratorConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_AcceleratorConfig_To_kops_AcceleratorConfig(a.(*AcceleratorConfig), b.(*kops.AcceleratorConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*kops.AcceleratorConfig)(nil), (*AcceleratorConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_kops_AcceleratorConfig_To_v1alpha2_AcceleratorConfig(a.(*kops.AcceleratorConfig), b.(*AcceleratorConfig), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*AccessLogSpec)(nil), (*kops.AccessLogSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha2_AccessLogSpec_To_kops_AccessLogSpec(a.(*AccessLogSpec), b.(*kops.AccessLogSpec), scope) }); err != nil { @@ -1369,6 +1379,28 @@ func Convert_kops_AWSPermission_To_v1alpha2_AWSPermission(in *kops.AWSPermission return autoConvert_kops_AWSPermission_To_v1alpha2_AWSPermission(in, out, s) } +func autoConvert_v1alpha2_AcceleratorConfig_To_kops_AcceleratorConfig(in *AcceleratorConfig, out *kops.AcceleratorConfig, s conversion.Scope) error { + out.AcceleratorCount = in.AcceleratorCount + out.AcceleratorType = in.AcceleratorType + return nil +} + +// Convert_v1alpha2_AcceleratorConfig_To_kops_AcceleratorConfig is an autogenerated conversion function. +func Convert_v1alpha2_AcceleratorConfig_To_kops_AcceleratorConfig(in *AcceleratorConfig, out *kops.AcceleratorConfig, s conversion.Scope) error { + return autoConvert_v1alpha2_AcceleratorConfig_To_kops_AcceleratorConfig(in, out, s) +} + +func autoConvert_kops_AcceleratorConfig_To_v1alpha2_AcceleratorConfig(in *kops.AcceleratorConfig, out *AcceleratorConfig, s conversion.Scope) error { + out.AcceleratorCount = in.AcceleratorCount + out.AcceleratorType = in.AcceleratorType + return nil +} + +// Convert_kops_AcceleratorConfig_To_v1alpha2_AcceleratorConfig is an autogenerated conversion function. +func Convert_kops_AcceleratorConfig_To_v1alpha2_AcceleratorConfig(in *kops.AcceleratorConfig, out *AcceleratorConfig, s conversion.Scope) error { + return autoConvert_kops_AcceleratorConfig_To_v1alpha2_AcceleratorConfig(in, out, s) +} + func autoConvert_v1alpha2_AccessLogSpec_To_kops_AccessLogSpec(in *AccessLogSpec, out *kops.AccessLogSpec, s conversion.Scope) error { out.Interval = in.Interval out.Bucket = in.Bucket @@ -4426,6 +4458,17 @@ func autoConvert_v1alpha2_InstanceGroupSpec_To_kops_InstanceGroupSpec(in *Instan out.Containerd = nil } out.Packages = in.Packages + if in.GuestAccelerators != nil { + in, out := &in.GuestAccelerators, &out.GuestAccelerators + *out = make([]kops.AcceleratorConfig, len(*in)) + for i := range *in { + if err := Convert_v1alpha2_AcceleratorConfig_To_kops_AcceleratorConfig(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.GuestAccelerators = nil + } return nil } @@ -4598,6 +4641,17 @@ func autoConvert_kops_InstanceGroupSpec_To_v1alpha2_InstanceGroupSpec(in *kops.I out.Containerd = nil } out.Packages = in.Packages + if in.GuestAccelerators != nil { + in, out := &in.GuestAccelerators, &out.GuestAccelerators + *out = make([]AcceleratorConfig, len(*in)) + for i := range *in { + if err := Convert_kops_AcceleratorConfig_To_v1alpha2_AcceleratorConfig(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.GuestAccelerators = nil + } return nil } diff --git a/pkg/apis/kops/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/kops/v1alpha2/zz_generated.deepcopy.go index bf516eb66b..91a04183fc 100644 --- a/pkg/apis/kops/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/kops/v1alpha2/zz_generated.deepcopy.go @@ -177,6 +177,22 @@ func (in *AWSPermission) DeepCopy() *AWSPermission { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AcceleratorConfig) DeepCopyInto(out *AcceleratorConfig) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AcceleratorConfig. +func (in *AcceleratorConfig) DeepCopy() *AcceleratorConfig { + if in == nil { + return nil + } + out := new(AcceleratorConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AccessLogSpec) DeepCopyInto(out *AccessLogSpec) { *out = *in @@ -2513,6 +2529,11 @@ func (in *InstanceGroupSpec) DeepCopyInto(out *InstanceGroupSpec) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.GuestAccelerators != nil { + in, out := &in.GuestAccelerators, &out.GuestAccelerators + *out = make([]AcceleratorConfig, len(*in)) + copy(*out, *in) + } return } diff --git a/pkg/apis/kops/v1alpha3/instancegroup.go b/pkg/apis/kops/v1alpha3/instancegroup.go index c6cbcc0072..ed15dcbb3b 100644 --- a/pkg/apis/kops/v1alpha3/instancegroup.go +++ b/pkg/apis/kops/v1alpha3/instancegroup.go @@ -157,6 +157,8 @@ type InstanceGroupSpec struct { Containerd *ContainerdConfig `json:"containerd,omitempty"` // Packages specifies additional packages to be installed. Packages []string `json:"packages,omitempty"` + // GuestAccelerators configures additional accelerators + GuestAccelerators []AcceleratorConfig `json:"guestAccelerators,omitempty"` } // InstanceMetadataOptions defines the EC2 instance metadata service options (AWS Only) @@ -265,3 +267,9 @@ type LoadBalancer struct { // TargetGroupARN to associate with this instance group (AWS ALB/NLB) TargetGroupARN *string `json:"targetGroupARN,omitempty"` } + +// AcceleratorConfig defines an accelerator config +type AcceleratorConfig struct { + AcceleratorCount int64 `json:"acceleratorCount,omitempty"` + AcceleratorType string `json:"acceleratorType,omitempty"` +} diff --git a/pkg/apis/kops/v1alpha3/zz_generated.conversion.go b/pkg/apis/kops/v1alpha3/zz_generated.conversion.go index 09ceb4f6e4..4356f4a30b 100644 --- a/pkg/apis/kops/v1alpha3/zz_generated.conversion.go +++ b/pkg/apis/kops/v1alpha3/zz_generated.conversion.go @@ -94,6 +94,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*AcceleratorConfig)(nil), (*kops.AcceleratorConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha3_AcceleratorConfig_To_kops_AcceleratorConfig(a.(*AcceleratorConfig), b.(*kops.AcceleratorConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*kops.AcceleratorConfig)(nil), (*AcceleratorConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_kops_AcceleratorConfig_To_v1alpha3_AcceleratorConfig(a.(*kops.AcceleratorConfig), b.(*AcceleratorConfig), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*AccessLogSpec)(nil), (*kops.AccessLogSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha3_AccessLogSpec_To_kops_AccessLogSpec(a.(*AccessLogSpec), b.(*kops.AccessLogSpec), scope) }); err != nil { @@ -1387,6 +1397,28 @@ func Convert_kops_AWSSpec_To_v1alpha3_AWSSpec(in *kops.AWSSpec, out *AWSSpec, s return autoConvert_kops_AWSSpec_To_v1alpha3_AWSSpec(in, out, s) } +func autoConvert_v1alpha3_AcceleratorConfig_To_kops_AcceleratorConfig(in *AcceleratorConfig, out *kops.AcceleratorConfig, s conversion.Scope) error { + out.AcceleratorCount = in.AcceleratorCount + out.AcceleratorType = in.AcceleratorType + return nil +} + +// Convert_v1alpha3_AcceleratorConfig_To_kops_AcceleratorConfig is an autogenerated conversion function. +func Convert_v1alpha3_AcceleratorConfig_To_kops_AcceleratorConfig(in *AcceleratorConfig, out *kops.AcceleratorConfig, s conversion.Scope) error { + return autoConvert_v1alpha3_AcceleratorConfig_To_kops_AcceleratorConfig(in, out, s) +} + +func autoConvert_kops_AcceleratorConfig_To_v1alpha3_AcceleratorConfig(in *kops.AcceleratorConfig, out *AcceleratorConfig, s conversion.Scope) error { + out.AcceleratorCount = in.AcceleratorCount + out.AcceleratorType = in.AcceleratorType + return nil +} + +// Convert_kops_AcceleratorConfig_To_v1alpha3_AcceleratorConfig is an autogenerated conversion function. +func Convert_kops_AcceleratorConfig_To_v1alpha3_AcceleratorConfig(in *kops.AcceleratorConfig, out *AcceleratorConfig, s conversion.Scope) error { + return autoConvert_kops_AcceleratorConfig_To_v1alpha3_AcceleratorConfig(in, out, s) +} + func autoConvert_v1alpha3_AccessLogSpec_To_kops_AccessLogSpec(in *AccessLogSpec, out *kops.AccessLogSpec, s conversion.Scope) error { out.Interval = in.Interval out.Bucket = in.Bucket @@ -4565,6 +4597,17 @@ func autoConvert_v1alpha3_InstanceGroupSpec_To_kops_InstanceGroupSpec(in *Instan out.Containerd = nil } out.Packages = in.Packages + if in.GuestAccelerators != nil { + in, out := &in.GuestAccelerators, &out.GuestAccelerators + *out = make([]kops.AcceleratorConfig, len(*in)) + for i := range *in { + if err := Convert_v1alpha3_AcceleratorConfig_To_kops_AcceleratorConfig(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.GuestAccelerators = nil + } return nil } @@ -4737,6 +4780,17 @@ func autoConvert_kops_InstanceGroupSpec_To_v1alpha3_InstanceGroupSpec(in *kops.I out.Containerd = nil } out.Packages = in.Packages + if in.GuestAccelerators != nil { + in, out := &in.GuestAccelerators, &out.GuestAccelerators + *out = make([]AcceleratorConfig, len(*in)) + for i := range *in { + if err := Convert_kops_AcceleratorConfig_To_v1alpha3_AcceleratorConfig(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.GuestAccelerators = nil + } return nil } diff --git a/pkg/apis/kops/v1alpha3/zz_generated.deepcopy.go b/pkg/apis/kops/v1alpha3/zz_generated.deepcopy.go index 74f07dc695..213635c546 100644 --- a/pkg/apis/kops/v1alpha3/zz_generated.deepcopy.go +++ b/pkg/apis/kops/v1alpha3/zz_generated.deepcopy.go @@ -194,6 +194,22 @@ func (in *AWSSpec) DeepCopy() *AWSSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AcceleratorConfig) DeepCopyInto(out *AcceleratorConfig) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AcceleratorConfig. +func (in *AcceleratorConfig) DeepCopy() *AcceleratorConfig { + if in == nil { + return nil + } + out := new(AcceleratorConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AccessLogSpec) DeepCopyInto(out *AccessLogSpec) { *out = *in @@ -2519,6 +2535,11 @@ func (in *InstanceGroupSpec) DeepCopyInto(out *InstanceGroupSpec) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.GuestAccelerators != nil { + in, out := &in.GuestAccelerators, &out.GuestAccelerators + *out = make([]AcceleratorConfig, len(*in)) + copy(*out, *in) + } return } diff --git a/pkg/apis/kops/zz_generated.deepcopy.go b/pkg/apis/kops/zz_generated.deepcopy.go index a045413462..0ee6c18c15 100644 --- a/pkg/apis/kops/zz_generated.deepcopy.go +++ b/pkg/apis/kops/zz_generated.deepcopy.go @@ -193,6 +193,22 @@ func (in *AWSSpec) DeepCopy() *AWSSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AcceleratorConfig) DeepCopyInto(out *AcceleratorConfig) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AcceleratorConfig. +func (in *AcceleratorConfig) DeepCopy() *AcceleratorConfig { + if in == nil { + return nil + } + out := new(AcceleratorConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AccessLogSpec) DeepCopyInto(out *AccessLogSpec) { *out = *in @@ -2682,6 +2698,11 @@ func (in *InstanceGroupSpec) DeepCopyInto(out *InstanceGroupSpec) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.GuestAccelerators != nil { + in, out := &in.GuestAccelerators, &out.GuestAccelerators + *out = make([]AcceleratorConfig, len(*in)) + copy(*out, *in) + } return } diff --git a/pkg/model/gcemodel/autoscalinggroup.go b/pkg/model/gcemodel/autoscalinggroup.go index b75495cac6..7a824e4c32 100644 --- a/pkg/model/gcemodel/autoscalinggroup.go +++ b/pkg/model/gcemodel/autoscalinggroup.go @@ -168,6 +168,14 @@ func (b *AutoscalingGroupModelBuilder) buildInstanceTemplate(c *fi.ModelBuilderC //} //t.Labels = labels + t.GuestAccelerators = []gcetasks.AcceleratorConfig{} + for _, accelerator := range ig.Spec.GuestAccelerators { + t.GuestAccelerators = append(t.GuestAccelerators, gcetasks.AcceleratorConfig{ + AcceleratorCount: accelerator.AcceleratorCount, + AcceleratorType: accelerator.AcceleratorType, + }) + } + return t, nil } } diff --git a/upup/pkg/fi/cloudup/gcetasks/accelerator_config.go b/upup/pkg/fi/cloudup/gcetasks/accelerator_config.go new file mode 100644 index 0000000000..20b6fc98d9 --- /dev/null +++ b/upup/pkg/fi/cloudup/gcetasks/accelerator_config.go @@ -0,0 +1,47 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package gcetasks + +import ( + "fmt" + + "k8s.io/kops/upup/pkg/fi" +) + +// AcceleratorConfig defines an accelerator config +type AcceleratorConfig struct { + AcceleratorCount int64 `json:"acceleratorCount,omitempty"` + AcceleratorType string `json:"acceleratorType,omitempty"` +} + +var ( + _ fi.HasDependencies = &AcceleratorConfig{} +) + +func (a *AcceleratorConfig) GetDependencies(tasks map[string]fi.Task) []fi.Task { + return nil +} + +func (_ *AcceleratorConfig) ShouldCreate(a, e, changes *AcceleratorConfig) (bool, error) { + if e.AcceleratorCount < 0 { + return false, fmt.Errorf("acceleratorCount must be positive or 0") + } + if e.AcceleratorType == "" { + return false, fmt.Errorf("acceleratorType must not be empty") + } + return true, nil +} diff --git a/upup/pkg/fi/cloudup/gcetasks/instancetemplate.go b/upup/pkg/fi/cloudup/gcetasks/instancetemplate.go index b2c3b1d105..22b4307bdc 100644 --- a/upup/pkg/fi/cloudup/gcetasks/instancetemplate.go +++ b/upup/pkg/fi/cloudup/gcetasks/instancetemplate.go @@ -75,6 +75,8 @@ type InstanceTemplate struct { // ID is the actual name ID *string + + GuestAccelerators []AcceleratorConfig } var ( @@ -211,6 +213,14 @@ func (e *InstanceTemplate) Find(c *fi.Context) (*InstanceTemplate, error) { // System fields actual.Lifecycle = e.Lifecycle + actual.GuestAccelerators = []AcceleratorConfig{} + for _, accelerator := range p.GuestAccelerators { + actual.GuestAccelerators = append(actual.GuestAccelerators, AcceleratorConfig{ + AcceleratorCount: accelerator.AcceleratorCount, + AcceleratorType: accelerator.AcceleratorType, + }) + } + return actual, nil } @@ -250,6 +260,11 @@ func (e *InstanceTemplate) mapToGCE(project string, region string) (*compute.Ins } } + if len(e.GuestAccelerators) > 0 { + // Instances with accelerators cannot be migrated. + scheduling.OnHostMaintenance = "TERMINATE" + } + var disks []*compute.AttachedDisk disks = append(disks, &compute.AttachedDisk{ Kind: "compute#attachedDisk", @@ -335,6 +350,17 @@ func (e *InstanceTemplate) mapToGCE(project string, region string) (*compute.Ins }) } + var accelerators []*compute.AcceleratorConfig + if len(e.GuestAccelerators) > 0 { + accelerators = []*compute.AcceleratorConfig{} + for _, accelerator := range e.GuestAccelerators { + accelerators = append(accelerators, &compute.AcceleratorConfig{ + AcceleratorCount: accelerator.AcceleratorCount, + AcceleratorType: accelerator.AcceleratorType, + }) + } + } + i := &compute.InstanceTemplate{ Kind: "compute#instanceTemplate", Properties: &compute.InstanceProperties{ @@ -342,6 +368,8 @@ func (e *InstanceTemplate) mapToGCE(project string, region string) (*compute.Ins Disks: disks, + GuestAccelerators: accelerators, + MachineType: *e.MachineType, Metadata: &compute.Metadata{ @@ -459,6 +487,7 @@ type terraformInstanceTemplate struct { Metadata map[string]*terraformWriter.Literal `cty:"metadata"` MetadataStartupScript *terraformWriter.Literal `cty:"metadata_startup_script"` Tags []string `cty:"tags"` + GuestAccelerator []*terraformGuestAccelerator `cty:"guest_accelerator"` } type terraformTemplateServiceAccount struct { @@ -498,6 +527,11 @@ type terraformAccessConfig struct { NatIP *terraformWriter.Literal `cty:"nat_ip"` } +type terraformGuestAccelerator struct { + Type string `cty:"type"` + Count int64 `cty:"count"` +} + func addNetworks(network *Network, subnet *Subnet, networkInterfaces []*compute.NetworkInterface) []*terraformNetworkInterface { ni := make([]*terraformNetworkInterface, 0) for _, g := range networkInterfaces { @@ -616,6 +650,16 @@ func (_ *InstanceTemplate) RenderTerraform(t *terraform.TerraformTarget, a, e, c } } + if len(i.Properties.GuestAccelerators) > 0 { + tf.GuestAccelerator = []*terraformGuestAccelerator{} + for _, accelerator := range i.Properties.GuestAccelerators { + tf.GuestAccelerator = append(tf.GuestAccelerator, &terraformGuestAccelerator{ + Count: accelerator.AcceleratorCount, + Type: accelerator.AcceleratorType, + }) + } + } + return t.RenderResource("google_compute_instance_template", name, tf) }