Skip to content
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

✨ Modify OpenStackCluster.Spec.Network API #1836

Merged

Conversation

MaysaMacedo
Copy link
Contributor

@MaysaMacedo MaysaMacedo commented Jan 19, 2024

For the BYO scenario, when the OpenStackCluster.Spec.Network
is not specified the query to OpenStack will return all the
Networks available in the cloud and fail the reconciliation.
To avoid this, if any Subnets were specified under
OpenStackCluster.Spec.Subnets this can used to identify
which Network to use.

Note, this pattern to infer a field based on another field has already been used by the
OpenStackCluster.Spec.Subnets and also when no Network is defined in a Port.

TODOs:

  • includes documentation
  • adds unit tests

/hold

@k8s-ci-robot k8s-ci-robot added do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. labels Jan 19, 2024
Copy link

netlify bot commented Jan 19, 2024

Deploy Preview for kubernetes-sigs-cluster-api-openstack ready!

Name Link
🔨 Latest commit 2e4ca73
🔍 Latest deploy log https://app.netlify.com/sites/kubernetes-sigs-cluster-api-openstack/deploys/65d62bd380815e0008207d05
😎 Deploy Preview https://deploy-preview-1836--kubernetes-sigs-cluster-api-openstack.netlify.app/print
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@k8s-ci-robot k8s-ci-robot added the size/M Denotes a PR that changes 30-99 lines, ignoring generated files. label Jan 19, 2024
@MaysaMacedo MaysaMacedo changed the title ✨ Modify OpenStackCluster.Spec.Network API ✨ WIP Modify OpenStackCluster.Spec.Network API Jan 19, 2024
@MaysaMacedo MaysaMacedo marked this pull request as draft January 19, 2024 22:07
@k8s-ci-robot k8s-ci-robot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jan 19, 2024
@MaysaMacedo MaysaMacedo force-pushed the find-network-by-subnet branch from b347263 to 43d8f89 Compare January 22, 2024 19:42
@MaysaMacedo MaysaMacedo changed the title ✨ WIP Modify OpenStackCluster.Spec.Network API ✨ Modify OpenStackCluster.Spec.Network API Jan 22, 2024
@k8s-ci-robot k8s-ci-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Jan 22, 2024
@MaysaMacedo MaysaMacedo marked this pull request as ready for review January 22, 2024 19:42
@k8s-ci-robot k8s-ci-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jan 22, 2024
@k8s-ci-robot k8s-ci-robot requested a review from lentzi90 January 22, 2024 19:42
@MaysaMacedo MaysaMacedo force-pushed the find-network-by-subnet branch from 43d8f89 to c48fa08 Compare January 23, 2024 13:30
@MaysaMacedo MaysaMacedo force-pushed the find-network-by-subnet branch from c48fa08 to 380f8d2 Compare January 26, 2024 12:54
@MaysaMacedo
Copy link
Contributor Author

/test pull-cluster-api-provider-openstack-e2e-test

@EmilienM
Copy link
Contributor

/test pull-cluster-api-provider-openstack-e2e-full-test

@EmilienM
Copy link
Contributor

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Jan 26, 2024
// It returns an error in case it failed to retrieve the network.
func (s *Service) PopulateCAPONetworkFromSubnet(subnets []subnets.Subnet, openStackCluster *infrav1.OpenStackCluster) error {
if openStackCluster.Status.Network.ID == "" && len(subnets) > 0 {
if len(subnets) > 1 && subnets[0].NetworkID != subnets[1].NetworkID {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just curious why this has subnet[0] and [1] ? some case we have 2 subnets and only 2 subnet?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case a dual-stack cluster is desired, one IPv4 and IPv6 subnet needs to be specified. The API already enforces the max number of subnets to be 2.

@MaysaMacedo
Copy link
Contributor Author

/hold cancel

@k8s-ci-robot k8s-ci-robot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jan 29, 2024
Copy link
Contributor

@mdbooth mdbooth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're doing a very similar dance in normalizePortTarget: we are getting a network a subnets from a NetworkFilter and []SubnetFilter and we infer the network from the subnets if it's not specified. Is there any opportunity to refactor that code to be used in both places?

if err != nil {
return err
}

var subnets []infrav1.Subnet
for subnet := range filteredSubnets {
subnets = networking.ConvertOpenStackSubnetToCAPOSubnet(subnets, &filteredSubnets[subnet])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please could you rename this function to something like AppendOpenStackSubnetToCAPOSubnets. I had to double-take this in review because without checking the implementation it looks like it overwrites previous subnets on each iteration.

if len(networkList) > 1 {
handleUpdateOSCError(openStackCluster, fmt.Errorf("found multiple networks (result: %v)", networkList))
return fmt.Errorf("found multiple networks (result: %v)", networkList)
}
if openStackCluster.Status.Network == nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A potential issue here is that we're now telling people they can omit the network section, but we're still executing an empty list operation above. This is going to list all networks. I know how long this takes on PSI, and we should probably avoid it.

I wonder if we should not execute the network query if the network spec is empty.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack, I added a condition checking if the filter is empty.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack, I added a condition checking if the filter is empty.

Where?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please can you move all of these functions, including the existing ConvertOpenStackSubnetToCAPOSubnet, to unexported functions in the cluster controller. They're not really service methods and with them having side-effects (they modify their arguments) they're not really independent library functions. Having them in a different file just breaks up readability.

If any have only a single caller you might consider inlining them at the point of use, tbh.

@MaysaMacedo
Copy link
Contributor Author

We're doing a very similar dance in normalizePortTarget: we are getting a network a subnets from a NetworkFilter and []SubnetFilter and we infer the network from the subnets if it's not specified. Is there any opportunity to refactor that code to be used in both places?

The scenario I'm handling is a bit different because I need the hole Network and not just the ID in order to populate the OpenStackCluster.status. Also, the way we filter the subnets is also a bit different because we need to account for when there is no subnets or various subnets. So the end goal for Ports and Network is the same, but there are restrictions that IMHO make the refactor not feasible.

@MaysaMacedo MaysaMacedo force-pushed the find-network-by-subnet branch from 380f8d2 to 14ecbda Compare February 1, 2024 14:24
@k8s-ci-robot k8s-ci-robot removed the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Feb 1, 2024
func populateCAPONetworkFromSubnet(networkingService *networking.Service, subnets []subnets.Subnet, openStackCluster *infrav1.OpenStackCluster) error {
if openStackCluster.Status.Network.ID == "" && len(subnets) > 0 {
if len(subnets) > 1 && subnets[0].NetworkID != subnets[1].NetworkID {
return fmt.Errorf("unable to identify the Network to use. NetworkID from Subnets differ: %s, %s", subnets[0].NetworkID, subnets[1].NetworkID)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we improve the logging maybe? Here is an example (can be improved):

Suggested change
return fmt.Errorf("unable to identify the Network to use. NetworkID from Subnets differ: %s, %s", subnets[0].NetworkID, subnets[1].NetworkID)
return fmt.Errorf("unable to identify the Network to use. NetworkID %s from subnet %s does not match NetworkID %s from subnet %s", subnets[0].NetworkID, subnets[0].ID, subnets[1].NetworkID, subnets[1].ID)

return nil
}

// getCAPONetwork gets a network based on a filter.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add a bit more doc into this function. Yes indeed, we get a network based on the filter and return errors if not found. But if found, we will update the status (by calling convertOpenStackNetworkToCAPONetwork). Also we return no error if Spec.Network is empty because we now try to find the Network specs by the Subnets field.

handleUpdateOSCError(openStackCluster, fmt.Errorf("failed to find any network"))
return fmt.Errorf("failed to find any network")
}
if len(networkList) == 1 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll like to see a switch probably, and return an error if more than one network is found maybe?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My proposal is intentional. If multiple networks are found, we won't fail and will give another chance to look up the network by the subnet later on on populateCAPONetworkFromSubnet.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧠 💥

return filteredSubnets, nil
}

// convertOpenStackNetworkToCAPONetwork converts an OpenStack network to a capo network.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more of an code architecture question (ping @mdbooth / @lentzi90), I would have put these functions into network.go instead, as I've seen it elsewhere. However I'm not sure if we have a clear line on that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still convinced that we want to move these new functions into network.go.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pure API manipulation. I think it's best done here, but it's not a hill I would die on.

@MaysaMacedo MaysaMacedo force-pushed the find-network-by-subnet branch from 14ecbda to 9709a58 Compare February 9, 2024 18:31
func populateCAPONetworkFromSubnet(networkingService *networking.Service, subnets []subnets.Subnet, openStackCluster *infrav1.OpenStackCluster) error {
if openStackCluster.Status.Network.ID == "" && len(subnets) > 0 {
if len(subnets) > 1 && subnets[0].NetworkID != subnets[1].NetworkID {
return fmt.Errorf("unable to identify the Network to use. NetworkID %s from subnet %s does not match NetworkID %s from subnet %s", subnets[0].NetworkID, subnets[0].ID, subnets[1].NetworkID, subnets[1].ID)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the error message can be improved a little bit, because we also check for the length of subnets.
also please s/Network/network/ to be consistent with subnet.

@k8s-ci-robot k8s-ci-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Feb 15, 2024
@MaysaMacedo MaysaMacedo force-pushed the find-network-by-subnet branch from 9709a58 to 0efefe8 Compare February 15, 2024 18:54
@k8s-ci-robot k8s-ci-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Feb 15, 2024
return filteredSubnets, nil
}

// convertOpenStackNetworkToCAPONetwork converts an OpenStack network to a capo network.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pure API manipulation. I think it's best done here, but it's not a hill I would die on.

@@ -544,6 +546,45 @@ var _ = Describe("OpenStackCluster controller", func() {
Expect(err).To(BeNil())
Expect(len(testCluster.Status.Network.Subnets)).To(Equal(2))
})

It("should allow fetch network by subnet", func() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great test, thanks.

@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: MaysaMacedo, mdbooth

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added approved Indicates a PR has been approved by an approver from all required OWNERS files. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. labels Feb 21, 2024
For the BYO scenario, when the `OpenStackCluster.Spec.Network`
is not specified the query to OpenStack would return all the
Networks available in the cloud and fail the reconciliation.
To avoid this, if any Subnets were specified under
`OpenStackCluster.Spec.Subnets` this can be used to identify
which Network to use.
@MaysaMacedo MaysaMacedo force-pushed the find-network-by-subnet branch from 0efefe8 to 2e4ca73 Compare February 21, 2024 16:58
@k8s-ci-robot k8s-ci-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Feb 21, 2024
@EmilienM
Copy link
Contributor

/test pull-cluster-api-provider-openstack-e2e-full-test
/lgtm
/hold for CI

@k8s-ci-robot k8s-ci-robot added do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. lgtm "Looks good to me", indicates that a PR is ready to be merged. labels Feb 21, 2024
@MaysaMacedo
Copy link
Contributor Author

/hold cancel
CI passed

@k8s-ci-robot k8s-ci-robot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Feb 21, 2024
@k8s-ci-robot k8s-ci-robot merged commit 029d643 into kubernetes-sigs:main Feb 21, 2024
10 checks passed
@MaysaMacedo MaysaMacedo deleted the find-network-by-subnet branch February 21, 2024 19:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants