Skip to content

Commit

Permalink
Add support for Amazon VPC CNI plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
aledbf committed Dec 17, 2017
1 parent 922a0d3 commit 2e05dd1
Show file tree
Hide file tree
Showing 24 changed files with 462 additions and 11 deletions.
8 changes: 5 additions & 3 deletions cmd/kops/create_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ func NewCmdCreateCluster(f *util.Factory, out io.Writer) *cobra.Command {

cmd.Flags().StringVar(&options.Image, "image", options.Image, "Image to use for all instances.")

cmd.Flags().StringVar(&options.Networking, "networking", "kubenet", "Networking mode to use. kubenet (default), classic, external, kopeio-vxlan (or kopeio), weave, flannel-vxlan (or flannel), flannel-udp, calico, canal, kube-router, romana.")
cmd.Flags().StringVar(&options.Networking, "networking", "kubenet", "Networking mode to use. kubenet (default), classic, external, kopeio-vxlan (or kopeio), weave, flannel-vxlan (or flannel), flannel-udp, calico, canal, kube-router, romana, amazon-vpc-routed-eni.")

cmd.Flags().StringVar(&options.DNSZone, "dns-zone", options.DNSZone, "DNS hosted zone to use (defaults to longest matching zone)")
cmd.Flags().StringVar(&options.OutDir, "out", options.OutDir, "Path to write any local output")
Expand Down Expand Up @@ -811,6 +811,8 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e
cluster.Spec.Networking.Kuberouter = &api.KuberouterNetworkingSpec{}
case "romana":
cluster.Spec.Networking.Romana = &api.RomanaNetworkingSpec{}
case "amazonvpc", "amazon-vpc-routed-eni":
cluster.Spec.Networking.AmazonVPC = &api.AmazonVPCNetworkingSpec{}
default:
return fmt.Errorf("unknown networking mode %q", c.Networking)
}
Expand Down Expand Up @@ -848,7 +850,7 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e

case api.TopologyPrivate:
if !supportsPrivateTopology(cluster.Spec.Networking) {
return fmt.Errorf("Invalid networking option %s. Currently only '--networking kopeio-vxlan (or kopeio)', '--networking weave', '--networking flannel', '--networking calico', '--networking canal', '--networking kube-router', '--networking romana' are supported for private topologies", c.Networking)
return fmt.Errorf("Invalid networking option %s. Currently only '--networking kopeio-vxlan (or kopeio)', '--networking weave', '--networking flannel', '--networking calico', '--networking canal', '--networking kube-router', '--networking romana', '--networking amazon-vpc-routed-eni' are supported for private topologies", c.Networking)
}
cluster.Spec.Topology = &api.TopologySpec{
Masters: api.TopologyPrivate,
Expand Down Expand Up @@ -1130,7 +1132,7 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e

func supportsPrivateTopology(n *api.NetworkingSpec) bool {

if n.CNI != nil || n.Kopeio != nil || n.Weave != nil || n.Flannel != nil || n.Calico != nil || n.Canal != nil || n.Kuberouter != nil || n.Romana != nil {
if n.CNI != nil || n.Kopeio != nil || n.Weave != nil || n.Flannel != nil || n.Calico != nil || n.Canal != nil || n.Kuberouter != nil || n.Romana != nil || n.AmazonVPC != nil {
return true
}
return false
Expand Down
2 changes: 1 addition & 1 deletion docs/cli/kops_create_cluster.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ kops create cluster
--master-zones stringSlice Zones in which to run masters (must be an odd number)
--model string Models to apply (separate multiple models with commas) (default "config,proto,cloudup")
--network-cidr string Set to override the default network CIDR
--networking string Networking mode to use. kubenet (default), classic, external, kopeio-vxlan (or kopeio), weave, flannel-vxlan (or flannel), flannel-udp, calico, canal, kube-router, romana. (default "kubenet")
--networking string Networking mode to use. kubenet (default), classic, external, kopeio-vxlan (or kopeio), weave, flannel-vxlan (or flannel), flannel-udp, calico, canal, kube-router, romana, amazon-vpc-routed-eni. (default "kubenet")
--node-count int32 Set the number of nodes
--node-security-groups stringSlice Add precreated additional security groups to nodes.
--node-size string Set instance size for nodes
Expand Down
33 changes: 33 additions & 0 deletions docs/networking.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Several different CNI providers are currently built into kops:
* [kube-router](./networking.md#kube-router-example-for-cni-ipvs-based-service-proxy-and-network-policy-enforcer)
* [romana](https://github.com/romana/romana)
* [weave](https://github.com/weaveworks/weave-kube)
* [amazon-vpc-routed-eni](./networking.md#amazon-vpc-backend)

The manifests for the providers are included with kops, and you simply use `--networking provider-name`.
Replace the provider name with the names listed above with you `kops cluster create`. For instance
Expand Down Expand Up @@ -290,6 +291,38 @@ Romana uses the cluster's etcd as a backend for storing information about routes
This does not affect normal etcd operations or require special treatment when upgrading etcd.
The etcd port (4001) is opened between masters and nodes when using this networking option.

#### Amazon VPC Backend

The [Amazon VPC CNI](https://github.com/aws/amazon-vpc-cni-k8s) plugin
requires no additional configurations to be done by user.

**Important:** the pods uses the VPC CIDR, i.e. there is no isolation between the master, node/s and the internal k8s network.

**Note:** The following permissions are added to all nodes by kops to run the provider:

```json
{
"Sid": "kopsK8sEC2NodeAmazonVPCPerms",
"Effect": "Allow",
"Action": [
"ec2:CreateNetworkInterface",
"ec2:AttachNetworkInterface",
"ec2:DeleteNetworkInterface",
"ec2:DetachNetworkInterface",
"ec2:DescribeNetworkInterfaces",
"ec2:DescribeInstances",
"ec2:ModifyNetworkInterfaceAttribute",
"ec2:AssignPrivateIpAddresses",
"tag:TagResources"
],
"Resource": [
"*"
]
}
```

In case of any issues the directory `/var/log/aws-routed-eni` contains the log files of the CNI plugin. This directory is located in all the nodes in the cluster.

### Validating CNI Installation

You will notice that `kube-dns` fails to start properly until you deploy your CNI provider.
Expand Down
2 changes: 1 addition & 1 deletion nodeup/pkg/model/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (b *NetworkBuilder) Build(c *fi.ModelBuilderContext) error {
} else if networking.External != nil {
// external is based on kubenet
assetNames = append(assetNames, "bridge", "host-local", "loopback")
} else if networking.CNI != nil || networking.Weave != nil || networking.Flannel != nil || networking.Calico != nil || networking.Canal != nil || networking.Kuberouter != nil || networking.Romana != nil {
} else if networking.CNI != nil || networking.Weave != nil || networking.Flannel != nil || networking.Calico != nil || networking.Canal != nil || networking.Kuberouter != nil || networking.Romana != nil || networking.AmazonVPC != nil {
assetNames = append(assetNames, "bridge", "host-local", "loopback", "ptp")
// Do we need tuning?

Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/kops/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@ func (c *Cluster) FillDefaults() error {
// OK
} else if c.Spec.Networking.Romana != nil {
// OK
} else if c.Spec.Networking.AmazonVPC != nil {
// OK
} else {
// No networking model selected; choose Kubenet
c.Spec.Networking.Kubenet = &KubenetNetworkingSpec{}
Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/kops/networking.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type NetworkingSpec struct {
Canal *CanalNetworkingSpec `json:"canal,omitempty"`
Kuberouter *KuberouterNetworkingSpec `json:"kuberouter,omitempty"`
Romana *RomanaNetworkingSpec `json:"romana,omitempty"`
AmazonVPC *AmazonVPCNetworkingSpec `json:"amazonvpc,omitempty"`
}

// ClassicNetworkingSpec is the specification of classic networking mode, integrated into kubernetes
Expand Down Expand Up @@ -103,3 +104,7 @@ type RomanaNetworkingSpec struct {
// EtcdServiceIP is the Kubernetes Service IP for the etcd backend used by Romana
EtcdServiceIP string `json:"etcdServiceIP,omitempty"`
}

// AmazonVPCNetworkingSpec declares that we want Amazon VPC CNI networking
type AmazonVPCNetworkingSpec struct {
}
4 changes: 4 additions & 0 deletions pkg/apis/kops/v1alpha1/networking.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type NetworkingSpec struct {
Canal *CanalNetworkingSpec `json:"canal,omitempty"`
Kuberouter *KuberouterNetworkingSpec `json:"kuberouter,omitempty"`
Romana *RomanaNetworkingSpec `json:"romana,omitempty"`
AmazonVPC *AmazonVPCNetworkingSpec `json:"amazonvpc,omitempty"`
}

// ClassicNetworkingSpec is the specification of classic networking mode, integrated into kubernetes
Expand Down Expand Up @@ -103,3 +104,6 @@ type RomanaNetworkingSpec struct {
// EtcdServiceIP is the Kubernetes Service IP for the etcd backend used by Romana
EtcdServiceIP string `json:"etcdServiceIP,omitempty"`
}

// AmazonVPCNetworkingSpec declares that we want Amazon VPC CNI networking
type AmazonVPCNetworkingSpec struct{}
38 changes: 38 additions & 0 deletions pkg/apis/kops/v1alpha1/zz_generated.conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
Convert_kops_AccessSpec_To_v1alpha1_AccessSpec,
Convert_v1alpha1_AlwaysAllowAuthorizationSpec_To_kops_AlwaysAllowAuthorizationSpec,
Convert_kops_AlwaysAllowAuthorizationSpec_To_v1alpha1_AlwaysAllowAuthorizationSpec,
Convert_v1alpha1_AmazonVPCNetworkingSpec_To_kops_AmazonVPCNetworkingSpec,
Convert_kops_AmazonVPCNetworkingSpec_To_v1alpha1_AmazonVPCNetworkingSpec,
Convert_v1alpha1_Assets_To_kops_Assets,
Convert_kops_Assets_To_v1alpha1_Assets,
Convert_v1alpha1_AuthenticationSpec_To_kops_AuthenticationSpec,
Expand Down Expand Up @@ -218,6 +220,24 @@ func Convert_kops_AlwaysAllowAuthorizationSpec_To_v1alpha1_AlwaysAllowAuthorizat
return autoConvert_kops_AlwaysAllowAuthorizationSpec_To_v1alpha1_AlwaysAllowAuthorizationSpec(in, out, s)
}

func autoConvert_v1alpha1_AmazonVPCNetworkingSpec_To_kops_AmazonVPCNetworkingSpec(in *AmazonVPCNetworkingSpec, out *kops.AmazonVPCNetworkingSpec, s conversion.Scope) error {
return nil
}

// Convert_v1alpha1_AmazonVPCNetworkingSpec_To_kops_AmazonVPCNetworkingSpec is an autogenerated conversion function.
func Convert_v1alpha1_AmazonVPCNetworkingSpec_To_kops_AmazonVPCNetworkingSpec(in *AmazonVPCNetworkingSpec, out *kops.AmazonVPCNetworkingSpec, s conversion.Scope) error {
return autoConvert_v1alpha1_AmazonVPCNetworkingSpec_To_kops_AmazonVPCNetworkingSpec(in, out, s)
}

func autoConvert_kops_AmazonVPCNetworkingSpec_To_v1alpha1_AmazonVPCNetworkingSpec(in *kops.AmazonVPCNetworkingSpec, out *AmazonVPCNetworkingSpec, s conversion.Scope) error {
return nil
}

// Convert_kops_AmazonVPCNetworkingSpec_To_v1alpha1_AmazonVPCNetworkingSpec is an autogenerated conversion function.
func Convert_kops_AmazonVPCNetworkingSpec_To_v1alpha1_AmazonVPCNetworkingSpec(in *kops.AmazonVPCNetworkingSpec, out *AmazonVPCNetworkingSpec, s conversion.Scope) error {
return autoConvert_kops_AmazonVPCNetworkingSpec_To_v1alpha1_AmazonVPCNetworkingSpec(in, out, s)
}

func autoConvert_v1alpha1_Assets_To_kops_Assets(in *Assets, out *kops.Assets, s conversion.Scope) error {
out.ContainerRegistry = in.ContainerRegistry
out.FileRepository = in.FileRepository
Expand Down Expand Up @@ -2404,6 +2424,15 @@ func autoConvert_v1alpha1_NetworkingSpec_To_kops_NetworkingSpec(in *NetworkingSp
} else {
out.Romana = nil
}
if in.AmazonVPC != nil {
in, out := &in.AmazonVPC, &out.AmazonVPC
*out = new(kops.AmazonVPCNetworkingSpec)
if err := Convert_v1alpha1_AmazonVPCNetworkingSpec_To_kops_AmazonVPCNetworkingSpec(*in, *out, s); err != nil {
return err
}
} else {
out.AmazonVPC = nil
}
return nil
}

Expand Down Expand Up @@ -2512,6 +2541,15 @@ func autoConvert_kops_NetworkingSpec_To_v1alpha1_NetworkingSpec(in *kops.Network
} else {
out.Romana = nil
}
if in.AmazonVPC != nil {
in, out := &in.AmazonVPC, &out.AmazonVPC
*out = new(AmazonVPCNetworkingSpec)
if err := Convert_kops_AmazonVPCNetworkingSpec_To_v1alpha1_AmazonVPCNetworkingSpec(*in, *out, s); err != nil {
return err
}
} else {
out.AmazonVPC = nil
}
return nil
}

Expand Down
29 changes: 29 additions & 0 deletions pkg/apis/kops/v1alpha1/zz_generated.deepcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
in.(*AlwaysAllowAuthorizationSpec).DeepCopyInto(out.(*AlwaysAllowAuthorizationSpec))
return nil
}, InType: reflect.TypeOf(&AlwaysAllowAuthorizationSpec{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*AmazonVPCNetworkingSpec).DeepCopyInto(out.(*AmazonVPCNetworkingSpec))
return nil
}, InType: reflect.TypeOf(&AmazonVPCNetworkingSpec{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*Assets).DeepCopyInto(out.(*Assets))
return nil
Expand Down Expand Up @@ -319,6 +323,22 @@ func (in *AlwaysAllowAuthorizationSpec) DeepCopy() *AlwaysAllowAuthorizationSpec
return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AmazonVPCNetworkingSpec) DeepCopyInto(out *AmazonVPCNetworkingSpec) {
*out = *in
return
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AmazonVPCNetworkingSpec.
func (in *AmazonVPCNetworkingSpec) DeepCopy() *AmazonVPCNetworkingSpec {
if in == nil {
return nil
}
out := new(AmazonVPCNetworkingSpec)
in.DeepCopyInto(out)
return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Assets) DeepCopyInto(out *Assets) {
*out = *in
Expand Down Expand Up @@ -2742,6 +2762,15 @@ func (in *NetworkingSpec) DeepCopyInto(out *NetworkingSpec) {
**out = **in
}
}
if in.AmazonVPC != nil {
in, out := &in.AmazonVPC, &out.AmazonVPC
if *in == nil {
*out = nil
} else {
*out = new(AmazonVPCNetworkingSpec)
**out = **in
}
}
return
}

Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/kops/v1alpha2/networking.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type NetworkingSpec struct {
Canal *CanalNetworkingSpec `json:"canal,omitempty"`
Kuberouter *KuberouterNetworkingSpec `json:"kuberouter,omitempty"`
Romana *RomanaNetworkingSpec `json:"romana,omitempty"`
AmazonVPC *AmazonVPCNetworkingSpec `json:"amazonvpc,omitempty"`
}

// ClassicNetworkingSpec is the specification of classic networking mode, integrated into kubernetes
Expand Down Expand Up @@ -103,3 +104,6 @@ type RomanaNetworkingSpec struct {
// EtcdServiceIP is the Kubernetes Service IP for the etcd backend used by Romana
EtcdServiceIP string `json:"etcdServiceIP,omitempty"`
}

// AmazonVPCNetworkingSpec declares that we want Amazon VPC CNI networking
type AmazonVPCNetworkingSpec struct{}
38 changes: 38 additions & 0 deletions pkg/apis/kops/v1alpha2/zz_generated.conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
Convert_kops_AccessSpec_To_v1alpha2_AccessSpec,
Convert_v1alpha2_AlwaysAllowAuthorizationSpec_To_kops_AlwaysAllowAuthorizationSpec,
Convert_kops_AlwaysAllowAuthorizationSpec_To_v1alpha2_AlwaysAllowAuthorizationSpec,
Convert_v1alpha2_AmazonVPCNetworkingSpec_To_kops_AmazonVPCNetworkingSpec,
Convert_kops_AmazonVPCNetworkingSpec_To_v1alpha2_AmazonVPCNetworkingSpec,
Convert_v1alpha2_Assets_To_kops_Assets,
Convert_kops_Assets_To_v1alpha2_Assets,
Convert_v1alpha2_AuthenticationSpec_To_kops_AuthenticationSpec,
Expand Down Expand Up @@ -232,6 +234,24 @@ func Convert_kops_AlwaysAllowAuthorizationSpec_To_v1alpha2_AlwaysAllowAuthorizat
return autoConvert_kops_AlwaysAllowAuthorizationSpec_To_v1alpha2_AlwaysAllowAuthorizationSpec(in, out, s)
}

func autoConvert_v1alpha2_AmazonVPCNetworkingSpec_To_kops_AmazonVPCNetworkingSpec(in *AmazonVPCNetworkingSpec, out *kops.AmazonVPCNetworkingSpec, s conversion.Scope) error {
return nil
}

// Convert_v1alpha2_AmazonVPCNetworkingSpec_To_kops_AmazonVPCNetworkingSpec is an autogenerated conversion function.
func Convert_v1alpha2_AmazonVPCNetworkingSpec_To_kops_AmazonVPCNetworkingSpec(in *AmazonVPCNetworkingSpec, out *kops.AmazonVPCNetworkingSpec, s conversion.Scope) error {
return autoConvert_v1alpha2_AmazonVPCNetworkingSpec_To_kops_AmazonVPCNetworkingSpec(in, out, s)
}

func autoConvert_kops_AmazonVPCNetworkingSpec_To_v1alpha2_AmazonVPCNetworkingSpec(in *kops.AmazonVPCNetworkingSpec, out *AmazonVPCNetworkingSpec, s conversion.Scope) error {
return nil
}

// Convert_kops_AmazonVPCNetworkingSpec_To_v1alpha2_AmazonVPCNetworkingSpec is an autogenerated conversion function.
func Convert_kops_AmazonVPCNetworkingSpec_To_v1alpha2_AmazonVPCNetworkingSpec(in *kops.AmazonVPCNetworkingSpec, out *AmazonVPCNetworkingSpec, s conversion.Scope) error {
return autoConvert_kops_AmazonVPCNetworkingSpec_To_v1alpha2_AmazonVPCNetworkingSpec(in, out, s)
}

func autoConvert_v1alpha2_Assets_To_kops_Assets(in *Assets, out *kops.Assets, s conversion.Scope) error {
out.ContainerRegistry = in.ContainerRegistry
out.FileRepository = in.FileRepository
Expand Down Expand Up @@ -2666,6 +2686,15 @@ func autoConvert_v1alpha2_NetworkingSpec_To_kops_NetworkingSpec(in *NetworkingSp
} else {
out.Romana = nil
}
if in.AmazonVPC != nil {
in, out := &in.AmazonVPC, &out.AmazonVPC
*out = new(kops.AmazonVPCNetworkingSpec)
if err := Convert_v1alpha2_AmazonVPCNetworkingSpec_To_kops_AmazonVPCNetworkingSpec(*in, *out, s); err != nil {
return err
}
} else {
out.AmazonVPC = nil
}
return nil
}

Expand Down Expand Up @@ -2774,6 +2803,15 @@ func autoConvert_kops_NetworkingSpec_To_v1alpha2_NetworkingSpec(in *kops.Network
} else {
out.Romana = nil
}
if in.AmazonVPC != nil {
in, out := &in.AmazonVPC, &out.AmazonVPC
*out = new(AmazonVPCNetworkingSpec)
if err := Convert_kops_AmazonVPCNetworkingSpec_To_v1alpha2_AmazonVPCNetworkingSpec(*in, *out, s); err != nil {
return err
}
} else {
out.AmazonVPC = nil
}
return nil
}

Expand Down
29 changes: 29 additions & 0 deletions pkg/apis/kops/v1alpha2/zz_generated.deepcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
in.(*AlwaysAllowAuthorizationSpec).DeepCopyInto(out.(*AlwaysAllowAuthorizationSpec))
return nil
}, InType: reflect.TypeOf(&AlwaysAllowAuthorizationSpec{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*AmazonVPCNetworkingSpec).DeepCopyInto(out.(*AmazonVPCNetworkingSpec))
return nil
}, InType: reflect.TypeOf(&AmazonVPCNetworkingSpec{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*Assets).DeepCopyInto(out.(*Assets))
return nil
Expand Down Expand Up @@ -335,6 +339,22 @@ func (in *AlwaysAllowAuthorizationSpec) DeepCopy() *AlwaysAllowAuthorizationSpec
return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AmazonVPCNetworkingSpec) DeepCopyInto(out *AmazonVPCNetworkingSpec) {
*out = *in
return
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AmazonVPCNetworkingSpec.
func (in *AmazonVPCNetworkingSpec) DeepCopy() *AmazonVPCNetworkingSpec {
if in == nil {
return nil
}
out := new(AmazonVPCNetworkingSpec)
in.DeepCopyInto(out)
return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Assets) DeepCopyInto(out *Assets) {
*out = *in
Expand Down Expand Up @@ -2868,6 +2888,15 @@ func (in *NetworkingSpec) DeepCopyInto(out *NetworkingSpec) {
**out = **in
}
}
if in.AmazonVPC != nil {
in, out := &in.AmazonVPC, &out.AmazonVPC
if *in == nil {
*out = nil
} else {
*out = new(AmazonVPCNetworkingSpec)
**out = **in
}
}
return
}

Expand Down
Loading

0 comments on commit 2e05dd1

Please sign in to comment.