-
Notifications
You must be signed in to change notification settings - Fork 1.5k
OpenStack: Dual stack support with BYON #6797
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,13 +2,14 @@ package validation | |
|
|
||
| import ( | ||
| "bytes" | ||
| "errors" | ||
| "fmt" | ||
| "net" | ||
| "net/url" | ||
|
|
||
| "github.com/gophercloud/gophercloud/openstack/imageservice/v2/images" | ||
| "github.com/gophercloud/gophercloud/openstack/networking/v2/subnets" | ||
| "k8s.io/apimachinery/pkg/util/validation/field" | ||
| utilsslice "k8s.io/utils/strings/slices" | ||
|
|
||
| "github.com/openshift/installer/pkg/types" | ||
| "github.com/openshift/installer/pkg/types/openstack" | ||
|
|
@@ -19,8 +20,10 @@ func ValidatePlatform(p *openstack.Platform, n *types.Networking, ci *CloudInfo) | |
| var allErrs field.ErrorList | ||
| fldPath := field.NewPath("platform", "openstack") | ||
|
|
||
| // validate BYO machinesSubnet usage | ||
| allErrs = append(allErrs, validateMachinesSubnet(p, n, ci, fldPath)...) | ||
| // validate BYO controlPlanePort usage | ||
MaysaMacedo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if p.ControlPlanePort != nil { | ||
| allErrs = append(allErrs, validateControlPlanePort(p, n, ci, fldPath)...) | ||
| } | ||
|
|
||
| // validate the externalNetwork | ||
| allErrs = append(allErrs, validateExternalNetwork(p, ci, fldPath)...) | ||
|
|
@@ -37,26 +40,79 @@ func ValidatePlatform(p *openstack.Platform, n *types.Networking, ci *CloudInfo) | |
| return allErrs | ||
| } | ||
|
|
||
| // validateMachinesSubnet validates the machines subnet and enforces proper byo subnet usage and returns a list of all validation errors | ||
| func validateMachinesSubnet(p *openstack.Platform, n *types.Networking, ci *CloudInfo, fldPath *field.Path) (allErrs field.ErrorList) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This validation function is being removed because the machineSubnets config would be converted to controlPlanePort's network config before it is validated (i.e when the deprecated config is provided by the user and not the new config)?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. |
||
| if p.MachinesSubnet != "" { | ||
| if len(p.ExternalDNS) > 0 { | ||
| allErrs = append(allErrs, field.Invalid(fldPath.Child("externalDNS"), p.ExternalDNS, "externalDNS is set, externalDNS is not supported when machinesSubnet is set")) | ||
| } | ||
| if ci.MachinesSubnet == nil { | ||
| allErrs = append(allErrs, field.NotFound(fldPath.Child("machinesSubnet"), p.MachinesSubnet)) | ||
| } else if !validUUIDv4(p.MachinesSubnet) { | ||
| allErrs = append(allErrs, field.InternalError(fldPath.Child("machinesSubnet"), errors.New("invalid subnet ID"))) | ||
| // validateControlPlanePort validates the machines subnets and network, while enforcing proper byo subnets usage and returns a list of all validation errors. | ||
| func validateControlPlanePort(p *openstack.Platform, n *types.Networking, ci *CloudInfo, fldPath *field.Path) (allErrs field.ErrorList) { | ||
| networkID := "" | ||
| hasIPv4Subnet := false | ||
| hasIPv6Subnet := false | ||
| if len(p.ExternalDNS) > 0 { | ||
| allErrs = append(allErrs, field.Invalid(fldPath.Child("externalDNS"), p.ExternalDNS, "externalDNS is set, externalDNS is not supported when ControlPlanePort is set")) | ||
| return allErrs | ||
| } | ||
MaysaMacedo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| networkCIDRs := networksCIDRs(n.MachineNetwork) | ||
| for _, fixedIP := range p.ControlPlanePort.FixedIPs { | ||
| subnet := getSubnet(ci.ControlPlanePortSubnets, fixedIP.Subnet.ID, fixedIP.Subnet.Name) | ||
| if subnet == nil { | ||
| subnetDetail := fixedIP.Subnet.ID | ||
| if subnetDetail == "" { | ||
| subnetDetail = fixedIP.Subnet.Name | ||
| } | ||
| allErrs = append(allErrs, field.NotFound(fldPath.Child("controlPlanePort").Child("fixedIPs"), subnetDetail)) | ||
| } else { | ||
| if n.MachineNetwork[0].CIDR.String() != ci.MachinesSubnet.CIDR { | ||
| allErrs = append(allErrs, field.InternalError(fldPath.Child("machinesSubnet"), fmt.Errorf("the first CIDR in machineNetwork, %s, doesn't match the CIDR of the machineSubnet, %s", n.MachineNetwork[0].CIDR.String(), ci.MachinesSubnet.CIDR))) | ||
| if subnet.IPVersion == 6 { | ||
| hasIPv6Subnet = true | ||
| } else { | ||
| hasIPv4Subnet = true | ||
| } | ||
| if !utilsslice.Contains(networkCIDRs, subnet.CIDR) { | ||
| allErrs = append(allErrs, field.Invalid(fldPath.Child("controlPlanePort").Child("fixedIPs"), subnet.CIDR, "controlPlanePort CIDR does not match machineNetwork")) | ||
| } | ||
| if networkID != "" && networkID != subnet.NetworkID { | ||
| allErrs = append(allErrs, field.Invalid(fldPath.Child("controlPlanePort").Child("fixedIPs"), subnet.NetworkID, "fixedIPs subnets must be on the same Network")) | ||
| } | ||
| networkID = subnet.NetworkID | ||
| } | ||
| } | ||
| if !hasIPv4Subnet && hasIPv6Subnet { | ||
| allErrs = append(allErrs, field.InternalError(fldPath.Child("controlPlanePort").Child("fixedIPs"), fmt.Errorf("one IPv4 subnet must be specified"))) | ||
| } else if hasIPv4Subnet && !hasIPv6Subnet && len(p.ControlPlanePort.FixedIPs) == 2 { | ||
| allErrs = append(allErrs, field.InternalError(fldPath.Child("controlPlanePort").Child("fixedIPs"), fmt.Errorf("multiple IPv4 subnets is not supported"))) | ||
| } | ||
| controlPlaneNetwork := p.ControlPlanePort.Network | ||
| if controlPlaneNetwork.ID != "" || controlPlaneNetwork.Name != "" { | ||
| networkDetail := controlPlaneNetwork.ID | ||
| if networkDetail == "" { | ||
| networkDetail = controlPlaneNetwork.Name | ||
| } | ||
| // check if the networks does not exist. If it does, verifies if the network contains the subnets | ||
| if ci.ControlPlanePortNetwork == nil { | ||
| allErrs = append(allErrs, field.NotFound(fldPath.Child("controlPlanePort").Child("network"), networkDetail)) | ||
| } else if ci.ControlPlanePortNetwork.ID != networkID { | ||
| allErrs = append(allErrs, field.Invalid(fldPath.Child("controlPlanePort").Child("network"), networkDetail, "network must contain subnets")) | ||
| } | ||
| } | ||
|
|
||
| return allErrs | ||
| } | ||
|
|
||
| func networksCIDRs(machineNetwork []types.MachineNetworkEntry) []string { | ||
| networks := make([]string, 0, len(machineNetwork)) | ||
| for _, network := range machineNetwork { | ||
| networks = append(networks, network.CIDR.String()) | ||
| } | ||
| return networks | ||
| } | ||
|
|
||
| func getSubnet(controlPlaneSubnets []*subnets.Subnet, subnetID, subnetName string) *subnets.Subnet { | ||
| for _, subnet := range controlPlaneSubnets { | ||
| if subnet.ID == subnetID { | ||
| return subnet | ||
| } else if subnet.Name != "" && subnet.Name == subnetName { | ||
MaysaMacedo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return subnet | ||
| } | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // validateExternalNetwork validates the user's input for the externalNetwork and returns a list of all validation errors | ||
| func validateExternalNetwork(p *openstack.Platform, ci *CloudInfo, fldPath *field.Path) (allErrs field.ErrorList) { | ||
| // Return an error if external network was specified in the install config, but hasn't been found | ||
|
|
@@ -96,9 +152,10 @@ func validateFloatingIPs(p *openstack.Platform, ci *CloudInfo, fldPath *field.Pa | |
| // platform VIP validation is done in pkg/types/validation/installconfig.go, | ||
| // validateAPIAndIngressVIPs(). | ||
| func validateVIPs(p *openstack.Platform, ci *CloudInfo, fldPath *field.Path) (allErrs field.ErrorList) { | ||
| // If the subnet is not found in the CloudInfo object, abandon validation | ||
| if ci.MachinesSubnet != nil { | ||
| for _, allocationPool := range ci.MachinesSubnet.AllocationPools { | ||
| // If the subnet is not found in the CloudInfo object, abandon validation. | ||
| // For dual-stack the user needs to pre-create the Port for API and Ingress, so no need for validation. | ||
| if len(ci.ControlPlanePortSubnets) == 1 { | ||
| for _, allocationPool := range ci.ControlPlanePortSubnets[0].AllocationPools { | ||
| start := net.ParseIP(allocationPool.Start) | ||
| end := net.ParseIP(allocationPool.End) | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the network required here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, because
machinesSubnetonly contains info about the subnet and that would be the only info added tocontrolPlanePortduring conversion.