mirror of https://github.com/kubernetes/kops.git
Allow IPv6-only subnets
This commit is contained in:
parent
6b2cd12d6e
commit
f9071dd0d5
|
|
@ -299,7 +299,7 @@ func TestMinimalIPv6(t *testing.T) {
|
|||
// TestMinimalIPv6 runs the test on a minimum IPv6 configuration
|
||||
func TestMinimalIPv6Private(t *testing.T) {
|
||||
newIntegrationTest("minimal-ipv6.example.com", "minimal-ipv6-private").
|
||||
withAddons(awsCCMAddon, awsEBSCSIAddon, dnsControllerAddon).
|
||||
withAddons(awsCCMAddon, awsEBSCSIAddon, dnsControllerAddon, leaderElectionAddon).
|
||||
runTestTerraformAWS(t)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -338,7 +338,11 @@ func ValidateCluster(c *kops.Cluster, strict bool) field.ErrorList {
|
|||
fieldSubnet := fieldSpec.Child("subnets").Index(i)
|
||||
if s.CIDR == "" {
|
||||
if requiresSubnetCIDR && strict {
|
||||
allErrs = append(allErrs, field.Required(fieldSubnet.Child("cidr"), "subnet did not have a cidr set"))
|
||||
if !strings.Contains(c.Spec.NonMasqueradeCIDR, ":") || s.IPv6CIDR == "" {
|
||||
allErrs = append(allErrs, field.Required(fieldSubnet.Child("cidr"), "subnet did not have a cidr set"))
|
||||
} else if c.IsKubernetesLT("1.23") {
|
||||
allErrs = append(allErrs, field.Required(fieldSubnet.Child("cidr"), "IPv6-only subnets require Kubernetes 1.23+"))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_, subnetCIDR, err := net.ParseCIDR(s.CIDR)
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ func validateClusterSpec(spec *kops.ClusterSpec, c *kops.Cluster, fieldPath *fie
|
|||
}
|
||||
|
||||
if spec.Topology != nil {
|
||||
allErrs = append(allErrs, validateTopology(spec.Topology, fieldPath.Child("topology"))...)
|
||||
allErrs = append(allErrs, validateTopology(c, spec.Topology, fieldPath.Child("topology"))...)
|
||||
}
|
||||
|
||||
// UpdatePolicy
|
||||
|
|
@ -360,7 +360,7 @@ func validateIPv6CIDR(cidr string, fieldPath *field.Path) field.ErrorList {
|
|||
return allErrs
|
||||
}
|
||||
|
||||
func validateTopology(topology *kops.TopologySpec, fieldPath *field.Path) field.ErrorList {
|
||||
func validateTopology(c *kops.Cluster, topology *kops.TopologySpec, fieldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if topology.Masters == "" {
|
||||
|
|
@ -373,6 +373,10 @@ func validateTopology(topology *kops.TopologySpec, fieldPath *field.Path) field.
|
|||
allErrs = append(allErrs, field.Required(fieldPath.Child("nodes"), ""))
|
||||
} else {
|
||||
allErrs = append(allErrs, IsValidValue(fieldPath.Child("nodes"), &topology.Nodes, kops.SupportedTopologies)...)
|
||||
|
||||
if topology.Nodes == "private" && c.Spec.IsIPv6Only() && c.IsKubernetesLT("1.23") {
|
||||
allErrs = append(allErrs, field.Forbidden(fieldPath.Child("nodes"), "private topology in IPv6 clusters requires Kubernetes 1.23+"))
|
||||
}
|
||||
}
|
||||
|
||||
if topology.Bastion != nil {
|
||||
|
|
|
|||
|
|
@ -254,7 +254,6 @@ func (b *NetworkModelBuilder) Build(c *fi.ModelBuilderContext) error {
|
|||
Lifecycle: b.Lifecycle,
|
||||
VPC: b.LinkToVPC(),
|
||||
AvailabilityZone: fi.String(subnetSpec.Zone),
|
||||
CIDR: fi.String(subnetSpec.CIDR),
|
||||
Shared: fi.Bool(sharedSubnet),
|
||||
Tags: tags,
|
||||
}
|
||||
|
|
@ -263,6 +262,10 @@ func (b *NetworkModelBuilder) Build(c *fi.ModelBuilderContext) error {
|
|||
subnet.ResourceBasedNaming = fi.Bool(true)
|
||||
}
|
||||
|
||||
if subnetSpec.CIDR != "" {
|
||||
subnet.CIDR = fi.String(subnetSpec.CIDR)
|
||||
}
|
||||
|
||||
if subnetSpec.IPv6CIDR != "" {
|
||||
if !sharedVPC {
|
||||
subnet.AmazonIPv6CIDR = b.LinkToAmazonVPCIPv6CIDR()
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ spec:
|
|||
iam: {}
|
||||
kubelet:
|
||||
anonymousAuth: false
|
||||
kubernetesVersion: v1.21.0
|
||||
kubernetesVersion: v1.23.0
|
||||
masterInternalName: api.internal.minimal-ipv6.example.com
|
||||
masterPublicName: api.minimal-ipv6.example.com
|
||||
networkCIDR: 172.20.0.0/16
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ func (e *Subnet) Find(c *fi.Context) (*Subnet, error) {
|
|||
|
||||
actual.ResourceBasedNaming = fi.Bool(aws.StringValue(subnet.PrivateDnsNameOptionsOnLaunch.HostnameType) == ec2.HostnameTypeResourceName)
|
||||
if *actual.ResourceBasedNaming {
|
||||
if !aws.BoolValue(subnet.PrivateDnsNameOptionsOnLaunch.EnableResourceNameDnsARecord) {
|
||||
if fi.StringValue(actual.CIDR) != "" && !aws.BoolValue(subnet.PrivateDnsNameOptionsOnLaunch.EnableResourceNameDnsARecord) {
|
||||
actual.ResourceBasedNaming = nil
|
||||
}
|
||||
if fi.StringValue(actual.IPv6CIDR) != "" && !aws.BoolValue(subnet.PrivateDnsNameOptionsOnLaunch.EnableResourceNameDnsAAAARecord) {
|
||||
|
|
@ -175,9 +175,8 @@ func (s *Subnet) CheckChanges(a, e, changes *Subnet) error {
|
|||
errors = append(errors, field.Required(fieldPath.Child("VPC"), "must specify a VPC"))
|
||||
}
|
||||
|
||||
if e.CIDR == nil {
|
||||
// TODO: Auto-assign CIDR?
|
||||
errors = append(errors, field.Required(fieldPath.Child("CIDR"), "must specify a CIDR"))
|
||||
if e.CIDR == nil && e.IPv6CIDR == nil {
|
||||
errors = append(errors, field.Required(fieldPath.Child("CIDR"), "must specify a CIDR or IPv6CIDR"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -256,7 +255,7 @@ func (_ *Subnet) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Subnet) error {
|
|||
}
|
||||
|
||||
if a == nil {
|
||||
klog.V(2).Infof("Creating Subnet with CIDR: %q", *e.CIDR)
|
||||
klog.V(2).Infof("Creating Subnet with CIDR: %q IPv6CIDR: %q", fi.StringValue(e.CIDR), fi.StringValue(e.IPv6CIDR))
|
||||
|
||||
request := &ec2.CreateSubnetInput{
|
||||
CidrBlock: e.CIDR,
|
||||
|
|
@ -266,6 +265,10 @@ func (_ *Subnet) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Subnet) error {
|
|||
TagSpecifications: awsup.EC2TagSpecification(ec2.ResourceTypeSubnet, e.Tags),
|
||||
}
|
||||
|
||||
if e.CIDR == nil {
|
||||
request.Ipv6Native = aws.Bool(true)
|
||||
}
|
||||
|
||||
response, err := t.Cloud.EC2().CreateSubnet(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating subnet: %v", err)
|
||||
|
|
@ -300,13 +303,24 @@ func (_ *Subnet) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Subnet) error {
|
|||
return fmt.Errorf("error modifying hostname type: %w", err)
|
||||
}
|
||||
|
||||
request = &ec2.ModifySubnetAttributeInput{
|
||||
SubnetId: e.ID,
|
||||
EnableResourceNameDnsARecordOnLaunch: &ec2.AttributeBooleanValue{Value: changes.ResourceBasedNaming},
|
||||
}
|
||||
_, err = t.Cloud.EC2().ModifySubnetAttribute(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error modifying A records: %w", err)
|
||||
if fi.StringValue(e.CIDR) == "" {
|
||||
request = &ec2.ModifySubnetAttributeInput{
|
||||
SubnetId: e.ID,
|
||||
EnableDns64: &ec2.AttributeBooleanValue{Value: aws.Bool(true)},
|
||||
}
|
||||
_, err = t.Cloud.EC2().ModifySubnetAttribute(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error enabling DNS64: %w", err)
|
||||
}
|
||||
} else {
|
||||
request = &ec2.ModifySubnetAttributeInput{
|
||||
SubnetId: e.ID,
|
||||
EnableResourceNameDnsARecordOnLaunch: &ec2.AttributeBooleanValue{Value: changes.ResourceBasedNaming},
|
||||
}
|
||||
_, err = t.Cloud.EC2().ModifySubnetAttribute(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error modifying A records: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if fi.StringValue(e.IPv6CIDR) != "" {
|
||||
|
|
|
|||
|
|
@ -174,6 +174,10 @@ func assignCIDRsToSubnets(c *kops.Cluster, cloud fi.Cloud) error {
|
|||
if subnet.CIDR != "" {
|
||||
continue
|
||||
}
|
||||
// TODO: Replace this with a check against type "dualstack" if has IPv6CIDR
|
||||
if subnet.IPv6CIDR != "" && subnet.Name != subnet.Zone {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(bigCIDRs) == 0 {
|
||||
return fmt.Errorf("insufficient (big) CIDRs remaining for automatic CIDR allocation to subnet %q", subnet.Name)
|
||||
|
|
|
|||
Loading…
Reference in New Issue