Skip to content

Commit

Permalink
Feature kubernetes-sigs#4784: SubnetSchema support
Browse files Browse the repository at this point in the history
  • Loading branch information
krasoffski committed May 7, 2024
1 parent a17f2ba commit 4c74e82
Show file tree
Hide file tree
Showing 13 changed files with 885 additions and 12 deletions.
1 change: 1 addition & 0 deletions api/v1beta1/awscluster_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ func (src *AWSCluster) ConvertTo(dstRaw conversion.Hub) error {
dst.Spec.NetworkSpec.VPC.EmptyRoutesDefaultVPCSecurityGroup = restored.Spec.NetworkSpec.VPC.EmptyRoutesDefaultVPCSecurityGroup
dst.Spec.NetworkSpec.VPC.PrivateDNSHostnameTypeOnLaunch = restored.Spec.NetworkSpec.VPC.PrivateDNSHostnameTypeOnLaunch
dst.Spec.NetworkSpec.VPC.CarrierGatewayID = restored.Spec.NetworkSpec.VPC.CarrierGatewayID
dst.Spec.NetworkSpec.VPC.SubnetSchema = restored.Spec.NetworkSpec.VPC.SubnetSchema

// Restore SubnetSpec.ResourceID, SubnetSpec.ParentZoneName, and SubnetSpec.ZoneType fields, if any.
for _, subnet := range restored.Spec.NetworkSpec.Subnets {
Expand Down
11 changes: 11 additions & 0 deletions api/v1beta1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,3 +291,14 @@ const (
// AmazonLinuxGPU is the AmazonLinux GPU AMI type.
AmazonLinuxGPU EKSAMILookupType = "AmazonLinuxGPU"
)

// SubnetSchemaType specifies how given network should be divided on subnets
// in the VPC depending on the number of AZs.
type SubnetSchemaType string

var (
// SubnetSchemaPreferPrivate allocates more subnets in the VPC to private subnets.
SubnetSchemaPreferPrivate = SubnetSchemaType("PreferPrivate")
// SubnetSchemaPreferPublic allocates more subnets in the VPC to public subnets.
SubnetSchemaPreferPublic = SubnetSchemaType("PreferPublic")
)
1 change: 1 addition & 0 deletions api/v1beta1/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions api/v1beta2/awscluster_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -993,6 +993,7 @@ func TestAWSClusterDefaultCNIIngressRules(t *testing.T) {
defaultVPCSpec := VPCSpec{
AvailabilityZoneUsageLimit: &AZUsageLimit,
AvailabilityZoneSelection: &AZSelectionSchemeOrdered,
SubnetSchema: &SubnetSchemaPreferPrivate,
}
g := NewWithT(t)
tests := []struct {
Expand Down
9 changes: 9 additions & 0 deletions api/v1beta2/network_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,15 @@ type VPCSpec struct {
// +optional
// +kubebuilder:validation:Enum:=ip-name;resource-name
PrivateDNSHostnameTypeOnLaunch *string `json:"privateDnsHostnameTypeOnLaunch,omitempty"`

// SubnetSchema specifies how CidrBlock should be divided on subnets in the VPC depending on the number of AZs.
// PreferPrivate - one private subnet for each AZ plus one other subnet that will be further sub-divided for the public subnets.
// PreferPublic - have the reverse logic of PreferPrivate, one public subnet for each AZ plus one other subnet
// that will be further sub-divided for the private subnets.
// Defaults to PreferPrivate
// +kubebuilder:default=PreferPrivate
// +kubebuilder:validation:Enum=PreferPrivate;PreferPublic
SubnetSchema *SubnetSchemaType `json:"subnetSchema,omitempty"`
}

// String returns a string representation of the VPC.
Expand Down
17 changes: 17 additions & 0 deletions api/v1beta2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ limitations under the License.
package v1beta2

import (
"strings"

"k8s.io/apimachinery/pkg/util/sets"

clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
Expand Down Expand Up @@ -439,3 +441,18 @@ type PrivateDNSName struct {
// +kubebuilder:validation:Enum:=ip-name;resource-name
HostnameType *string `json:"hostnameType,omitempty"`
}

// SubnetSchemaType specifies how given network should be divided on subnets
// in the VPC depending on the number of AZs.
type SubnetSchemaType string

func (s *SubnetSchemaType) Name() string {
return strings.ToLower(strings.TrimPrefix(string(*s), "Prefer"))
}

var (
// SubnetSchemaPreferPrivate allocates more subnets in the VPC to private subnets.
SubnetSchemaPreferPrivate = SubnetSchemaType("PreferPrivate")
// SubnetSchemaPreferPublic allocates more subnets in the VPC to public subnets.
SubnetSchemaPreferPublic = SubnetSchemaType("PreferPublic")
)
5 changes: 5 additions & 0 deletions api/v1beta2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,18 @@ spec:
- ip-name
- resource-name
type: string
subnetSchema:
default: PreferPrivate
description: |-
SubnetSchema specifies how CidrBlock should be divided on subnets in the VPC depending on the number of AZs.
PreferPrivate - one private subnet for each AZ plus one other subnet that will be further sub-divided for the public subnets.
PreferPublic - have the reverse logic of PreferPrivate, one public subnet for each AZ plus one other subnet
that will be further sub-divided for the private subnets.
Defaults to PreferPrivate
enum:
- PreferPrivate
- PreferPublic
type: string
tags:
additionalProperties:
type: string
Expand Down Expand Up @@ -2672,6 +2684,18 @@ spec:
- ip-name
- resource-name
type: string
subnetSchema:
default: PreferPrivate
description: |-
SubnetSchema specifies how CidrBlock should be divided on subnets in the VPC depending on the number of AZs.
PreferPrivate - one private subnet for each AZ plus one other subnet that will be further sub-divided for the public subnets.
PreferPublic - have the reverse logic of PreferPrivate, one public subnet for each AZ plus one other subnet
that will be further sub-divided for the private subnets.
Defaults to PreferPrivate
enum:
- PreferPrivate
- PreferPublic
type: string
tags:
additionalProperties:
type: string
Expand Down
12 changes: 12 additions & 0 deletions config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1658,6 +1658,18 @@ spec:
- ip-name
- resource-name
type: string
subnetSchema:
default: PreferPrivate
description: |-
SubnetSchema specifies how CidrBlock should be divided on subnets in the VPC depending on the number of AZs.
PreferPrivate - one private subnet for each AZ plus one other subnet that will be further sub-divided for the public subnets.
PreferPublic - have the reverse logic of PreferPrivate, one public subnet for each AZ plus one other subnet
that will be further sub-divided for the private subnets.
Defaults to PreferPrivate
enum:
- PreferPrivate
- PreferPublic
type: string
tags:
additionalProperties:
type: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1257,6 +1257,18 @@ spec:
- ip-name
- resource-name
type: string
subnetSchema:
default: PreferPrivate
description: |-
SubnetSchema specifies how CidrBlock should be divided on subnets in the VPC depending on the number of AZs.
PreferPrivate - one private subnet for each AZ plus one other subnet that will be further sub-divided for the public subnets.
PreferPublic - have the reverse logic of PreferPrivate, one public subnet for each AZ plus one other subnet
that will be further sub-divided for the private subnets.
Defaults to PreferPrivate
enum:
- PreferPrivate
- PreferPublic
type: string
tags:
additionalProperties:
type: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func TestDefaultingWebhook(t *testing.T) {
defaultVPCSpec := infrav1.VPCSpec{
AvailabilityZoneUsageLimit: &AZUsageLimit,
AvailabilityZoneSelection: &infrav1.AZSelectionSchemeOrdered,
SubnetSchema: &infrav1.SubnetSchemaPreferPrivate,
}
defaultIdentityRef := &infrav1.AWSIdentityReference{
Kind: infrav1.ControllerIdentityKind,
Expand Down
47 changes: 35 additions & 12 deletions pkg/cloud/services/network/subnets.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,26 +274,38 @@ func (s *Service) getDefaultSubnets() (infrav1.Subnets, error) {
s.scope.Debug("zones selected", "region", s.scope.Region(), "zones", zones)
}

// 1 private subnet for each AZ plus 1 other subnet that will be further sub-divided for the public subnets
// 1 private subnet for each AZ plus 1 other subnet that will be further sub-divided for the public subnets or vice versa if
// the subnet schema is set to prefer public subnets.
// All subnets will have an ipv4 address for now as well. We aren't supporting ipv6-only yet.
numSubnets := len(zones) + 1
var (
subnetCIDRs []*net.IPNet
publicSubnetCIDRs []*net.IPNet
ipv6SubnetCIDRs []*net.IPNet
publicIPv6SubnetCIDRs []*net.IPNet
privateIPv6SubnetCIDRs []*net.IPNet
subnetCIDRs []*net.IPNet
preferredSubnetCIDRs []*net.IPNet
residualSubnetCIDRs []*net.IPNet
ipv6SubnetCIDRs []*net.IPNet
preferredIPv6SubnetCIDRs []*net.IPNet
residualIPv6SubnetCIDRs []*net.IPNet
)
subnetScheme := infrav1.SubnetSchemaPreferPrivate
if s.scope.VPC().SubnetSchema != nil {
subnetScheme = *s.scope.VPC().SubnetSchema
}

residualSubnetsName := infrav1.SubnetSchemaPreferPublic.Name()
if subnetScheme == infrav1.SubnetSchemaPreferPublic {
residualSubnetsName = infrav1.SubnetSchemaPreferPrivate.Name()
}

subnetCIDRs, err = cidr.SplitIntoSubnetsIPv4(s.scope.VPC().CidrBlock, numSubnets)
if err != nil {
return nil, errors.Wrapf(err, "failed splitting VPC CIDR %q into subnets", s.scope.VPC().CidrBlock)
}

publicSubnetCIDRs, err = cidr.SplitIntoSubnetsIPv4(subnetCIDRs[0].String(), len(zones))
residualSubnetCIDRs, err = cidr.SplitIntoSubnetsIPv4(subnetCIDRs[0].String(), len(zones))
if err != nil {
return nil, errors.Wrapf(err, "failed splitting CIDR %q into public subnets", subnetCIDRs[0].String())
return nil, errors.Wrapf(err, "failed splitting CIDR %q into %s subnets", subnetCIDRs[0].String(), residualSubnetsName)
}
privateSubnetCIDRs := append(subnetCIDRs[:0], subnetCIDRs[1:]...)
preferredSubnetCIDRs = append(subnetCIDRs[:0], subnetCIDRs[1:]...)

if s.scope.VPC().IsIPv6Enabled() {
ipv6SubnetCIDRs, err = cidr.SplitIntoSubnetsIPv6(s.scope.VPC().IPv6.CidrBlock, numSubnets)
Expand All @@ -302,12 +314,23 @@ func (s *Service) getDefaultSubnets() (infrav1.Subnets, error) {
}

// We need to take the last, so it doesn't conflict with the rest. The subnetID is increment each time by 1.
publicIPv6SubnetCIDRs, err = cidr.SplitIntoSubnetsIPv6(ipv6SubnetCIDRs[len(ipv6SubnetCIDRs)-1].String(), len(zones))
ipv6SubnetCIDRsStr := ipv6SubnetCIDRs[len(ipv6SubnetCIDRs)-1].String()
residualIPv6SubnetCIDRs, err = cidr.SplitIntoSubnetsIPv6(ipv6SubnetCIDRsStr, len(zones))
if err != nil {
return nil, errors.Wrapf(err, "failed splitting IPv6 CIDR %q into public subnets", ipv6SubnetCIDRs[len(ipv6SubnetCIDRs)-1].String())
return nil, errors.Wrapf(err, "failed splitting IPv6 CIDR %q into %s subnets", ipv6SubnetCIDRsStr, residualSubnetsName)
}
// TODO: this might need to be the last instead of the first..
privateIPv6SubnetCIDRs = append(ipv6SubnetCIDRs[:0], ipv6SubnetCIDRs[1:]...)
preferredIPv6SubnetCIDRs = append(ipv6SubnetCIDRs[:0], ipv6SubnetCIDRs[1:]...)
}

// By default, the preferred subnets are the private subnets and the residual subnets are the public subnets.
privateSubnetCIDRs, publicSubnetCIDRs := preferredSubnetCIDRs, residualSubnetCIDRs
privateIPv6SubnetCIDRs, publicIPv6SubnetCIDRs := preferredIPv6SubnetCIDRs, residualIPv6SubnetCIDRs

// If the subnet schema is set to prefer public, we need to swap the private and public subnets.
if subnetScheme == infrav1.SubnetSchemaPreferPublic {
privateSubnetCIDRs, publicSubnetCIDRs = residualSubnetCIDRs, preferredSubnetCIDRs
privateIPv6SubnetCIDRs, publicIPv6SubnetCIDRs = residualIPv6SubnetCIDRs, preferredIPv6SubnetCIDRs
}

subnets := infrav1.Subnets{}
Expand Down
Loading

0 comments on commit 4c74e82

Please sign in to comment.