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
|
// TestMinimalIPv6 runs the test on a minimum IPv6 configuration
|
||||||
func TestMinimalIPv6Private(t *testing.T) {
|
func TestMinimalIPv6Private(t *testing.T) {
|
||||||
newIntegrationTest("minimal-ipv6.example.com", "minimal-ipv6-private").
|
newIntegrationTest("minimal-ipv6.example.com", "minimal-ipv6-private").
|
||||||
withAddons(awsCCMAddon, awsEBSCSIAddon, dnsControllerAddon).
|
withAddons(awsCCMAddon, awsEBSCSIAddon, dnsControllerAddon, leaderElectionAddon).
|
||||||
runTestTerraformAWS(t)
|
runTestTerraformAWS(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -338,7 +338,11 @@ func ValidateCluster(c *kops.Cluster, strict bool) field.ErrorList {
|
||||||
fieldSubnet := fieldSpec.Child("subnets").Index(i)
|
fieldSubnet := fieldSpec.Child("subnets").Index(i)
|
||||||
if s.CIDR == "" {
|
if s.CIDR == "" {
|
||||||
if requiresSubnetCIDR && strict {
|
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 {
|
} else {
|
||||||
_, subnetCIDR, err := net.ParseCIDR(s.CIDR)
|
_, subnetCIDR, err := net.ParseCIDR(s.CIDR)
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ func validateClusterSpec(spec *kops.ClusterSpec, c *kops.Cluster, fieldPath *fie
|
||||||
}
|
}
|
||||||
|
|
||||||
if spec.Topology != nil {
|
if spec.Topology != nil {
|
||||||
allErrs = append(allErrs, validateTopology(spec.Topology, fieldPath.Child("topology"))...)
|
allErrs = append(allErrs, validateTopology(c, spec.Topology, fieldPath.Child("topology"))...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePolicy
|
// UpdatePolicy
|
||||||
|
|
@ -360,7 +360,7 @@ func validateIPv6CIDR(cidr string, fieldPath *field.Path) field.ErrorList {
|
||||||
return allErrs
|
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{}
|
allErrs := field.ErrorList{}
|
||||||
|
|
||||||
if topology.Masters == "" {
|
if topology.Masters == "" {
|
||||||
|
|
@ -373,6 +373,10 @@ func validateTopology(topology *kops.TopologySpec, fieldPath *field.Path) field.
|
||||||
allErrs = append(allErrs, field.Required(fieldPath.Child("nodes"), ""))
|
allErrs = append(allErrs, field.Required(fieldPath.Child("nodes"), ""))
|
||||||
} else {
|
} else {
|
||||||
allErrs = append(allErrs, IsValidValue(fieldPath.Child("nodes"), &topology.Nodes, kops.SupportedTopologies)...)
|
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 {
|
if topology.Bastion != nil {
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,6 @@ func (b *NetworkModelBuilder) Build(c *fi.ModelBuilderContext) error {
|
||||||
Lifecycle: b.Lifecycle,
|
Lifecycle: b.Lifecycle,
|
||||||
VPC: b.LinkToVPC(),
|
VPC: b.LinkToVPC(),
|
||||||
AvailabilityZone: fi.String(subnetSpec.Zone),
|
AvailabilityZone: fi.String(subnetSpec.Zone),
|
||||||
CIDR: fi.String(subnetSpec.CIDR),
|
|
||||||
Shared: fi.Bool(sharedSubnet),
|
Shared: fi.Bool(sharedSubnet),
|
||||||
Tags: tags,
|
Tags: tags,
|
||||||
}
|
}
|
||||||
|
|
@ -263,6 +262,10 @@ func (b *NetworkModelBuilder) Build(c *fi.ModelBuilderContext) error {
|
||||||
subnet.ResourceBasedNaming = fi.Bool(true)
|
subnet.ResourceBasedNaming = fi.Bool(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if subnetSpec.CIDR != "" {
|
||||||
|
subnet.CIDR = fi.String(subnetSpec.CIDR)
|
||||||
|
}
|
||||||
|
|
||||||
if subnetSpec.IPv6CIDR != "" {
|
if subnetSpec.IPv6CIDR != "" {
|
||||||
if !sharedVPC {
|
if !sharedVPC {
|
||||||
subnet.AmazonIPv6CIDR = b.LinkToAmazonVPCIPv6CIDR()
|
subnet.AmazonIPv6CIDR = b.LinkToAmazonVPCIPv6CIDR()
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ spec:
|
||||||
iam: {}
|
iam: {}
|
||||||
kubelet:
|
kubelet:
|
||||||
anonymousAuth: false
|
anonymousAuth: false
|
||||||
kubernetesVersion: v1.21.0
|
kubernetesVersion: v1.23.0
|
||||||
masterInternalName: api.internal.minimal-ipv6.example.com
|
masterInternalName: api.internal.minimal-ipv6.example.com
|
||||||
masterPublicName: api.minimal-ipv6.example.com
|
masterPublicName: api.minimal-ipv6.example.com
|
||||||
networkCIDR: 172.20.0.0/16
|
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)
|
actual.ResourceBasedNaming = fi.Bool(aws.StringValue(subnet.PrivateDnsNameOptionsOnLaunch.HostnameType) == ec2.HostnameTypeResourceName)
|
||||||
if *actual.ResourceBasedNaming {
|
if *actual.ResourceBasedNaming {
|
||||||
if !aws.BoolValue(subnet.PrivateDnsNameOptionsOnLaunch.EnableResourceNameDnsARecord) {
|
if fi.StringValue(actual.CIDR) != "" && !aws.BoolValue(subnet.PrivateDnsNameOptionsOnLaunch.EnableResourceNameDnsARecord) {
|
||||||
actual.ResourceBasedNaming = nil
|
actual.ResourceBasedNaming = nil
|
||||||
}
|
}
|
||||||
if fi.StringValue(actual.IPv6CIDR) != "" && !aws.BoolValue(subnet.PrivateDnsNameOptionsOnLaunch.EnableResourceNameDnsAAAARecord) {
|
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"))
|
errors = append(errors, field.Required(fieldPath.Child("VPC"), "must specify a VPC"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.CIDR == nil {
|
if e.CIDR == nil && e.IPv6CIDR == nil {
|
||||||
// TODO: Auto-assign CIDR?
|
errors = append(errors, field.Required(fieldPath.Child("CIDR"), "must specify a CIDR or IPv6CIDR"))
|
||||||
errors = append(errors, field.Required(fieldPath.Child("CIDR"), "must specify a CIDR"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,7 +255,7 @@ func (_ *Subnet) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Subnet) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if a == nil {
|
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{
|
request := &ec2.CreateSubnetInput{
|
||||||
CidrBlock: e.CIDR,
|
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),
|
TagSpecifications: awsup.EC2TagSpecification(ec2.ResourceTypeSubnet, e.Tags),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if e.CIDR == nil {
|
||||||
|
request.Ipv6Native = aws.Bool(true)
|
||||||
|
}
|
||||||
|
|
||||||
response, err := t.Cloud.EC2().CreateSubnet(request)
|
response, err := t.Cloud.EC2().CreateSubnet(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error creating subnet: %v", err)
|
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)
|
return fmt.Errorf("error modifying hostname type: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
request = &ec2.ModifySubnetAttributeInput{
|
if fi.StringValue(e.CIDR) == "" {
|
||||||
SubnetId: e.ID,
|
request = &ec2.ModifySubnetAttributeInput{
|
||||||
EnableResourceNameDnsARecordOnLaunch: &ec2.AttributeBooleanValue{Value: changes.ResourceBasedNaming},
|
SubnetId: e.ID,
|
||||||
}
|
EnableDns64: &ec2.AttributeBooleanValue{Value: aws.Bool(true)},
|
||||||
_, err = t.Cloud.EC2().ModifySubnetAttribute(request)
|
}
|
||||||
if err != nil {
|
_, err = t.Cloud.EC2().ModifySubnetAttribute(request)
|
||||||
return fmt.Errorf("error modifying A records: %w", err)
|
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) != "" {
|
if fi.StringValue(e.IPv6CIDR) != "" {
|
||||||
|
|
|
||||||
|
|
@ -174,6 +174,10 @@ func assignCIDRsToSubnets(c *kops.Cluster, cloud fi.Cloud) error {
|
||||||
if subnet.CIDR != "" {
|
if subnet.CIDR != "" {
|
||||||
continue
|
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 {
|
if len(bigCIDRs) == 0 {
|
||||||
return fmt.Errorf("insufficient (big) CIDRs remaining for automatic CIDR allocation to subnet %q", subnet.Name)
|
return fmt.Errorf("insufficient (big) CIDRs remaining for automatic CIDR allocation to subnet %q", subnet.Name)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue