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

Check trunk support before enabling trunk at port level #1014

Merged
merged 1 commit into from
Nov 1, 2021

Conversation

Xenwar
Copy link

@Xenwar Xenwar commented Sep 28, 2021

This PR adds a check on trunk support before enabling trunk at port level.

Fixes: #1013

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Sep 28, 2021
@netlify
Copy link

netlify bot commented Sep 28, 2021

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

🔨 Explore the source changes: c125a4a

🔍 Inspect the deploy log: https://app.netlify.com/sites/kubernetes-sigs-cluster-api-openstack/deploys/617a644bc136ff00071bd2f7

😎 Browse the preview: https://deploy-preview-1014--kubernetes-sigs-cluster-api-openstack.netlify.app

@k8s-ci-robot
Copy link
Contributor

Hi @Xenwar. Thanks for your PR.

I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@k8s-ci-robot k8s-ci-robot added the needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. label Sep 28, 2021
@k8s-ci-robot k8s-ci-robot added the size/S Denotes a PR that changes 10-29 lines, ignoring generated files. label Sep 28, 2021
@Xenwar Xenwar force-pushed the port_level_trunk_check branch from 140bc24 to ed8a592 Compare September 28, 2021 14:15
@k8s-ci-robot k8s-ci-robot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. and removed size/S Denotes a PR that changes 10-29 lines, ignoring generated files. labels Sep 28, 2021
Copy link

@namnx228 namnx228 left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@macaptain macaptain left a comment

Choose a reason for hiding this comment

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

Extracting the function will help keep the error messages for trunk support checking consistent in the code, but I think as it stands, instance deletion will be broken by this change. Additionally, I think the function naming could be made clearer.

@@ -582,3 +584,14 @@ func getTimeout(name string, timeout int) time.Duration {
}
return time.Duration(timeout)
}

func (s *Service) trunkNotSupported() (notSupported bool, err error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This function is named a bit strangely:

  1. The logic would read more clearly if the name was a positive instead of a negative.
  2. I can't guess from the function name that it returns a boolean without side effect.

I think I would call this function isTrunkExtSupported or maybe better: isTrunkExtEnabled.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1 to make it positive case

Copy link
Author

Choose a reason for hiding this comment

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

done

func (s *Service) trunkNotSupported() (notSupported bool, err error) {
trunkSupport, err := s.networkingService.GetTrunkSupport()
if err != nil {
return true, fmt.Errorf("there was an issue verifying whether trunk support is available, please disable it: %v", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think the instruction to 'please disable it' is helpful. We don't know what the error is.

Copy link
Author

Choose a reason for hiding this comment

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

That was the original text. But, changing it based on the next comment.

return true, fmt.Errorf("there was an issue verifying whether trunk support is available, please disable it: %v", err)
}
if !trunkSupport {
return true, fmt.Errorf("there is no trunk support. Please disable it")
Copy link
Contributor

Choose a reason for hiding this comment

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

'Please disable it' isn't a clear instruction. The user has two options to proceed with their configuration: either they enable the trunk extension in their OpenStack deployment, or they give up on using trunking. I think a more helpful message would be "Please ensure that the trunk extension is enabled in your OpenStack deployment."

Copy link
Author

Choose a reason for hiding this comment

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

done

Comment on lines 418 to 420
trunkNotSupported, err := s.trunkNotSupported()
if trunkNotSupported {
return err
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this mean we return an error when trying to delete an instance whenever trunking is not enabled in the environment? I think you only want to return err here if s.trunkNotSupported() returned an error. If I have understood this code, this is broken and will break instance deletion in all environments without the trunk extension enabled.

Copy link
Contributor

Choose a reason for hiding this comment

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

yes, I think the delete we don't need check trunk support at all
it's weird that we can create trunk on openstack but not able to delete it ..
so delete the trunk if we enabled it , that's good enough:)

Copy link
Author

Choose a reason for hiding this comment

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

I haven't added this part. It was already there. see from the master branch

trunkSupport, err := s.networkingService.GetTrunkSupport()

Copy link
Contributor

Choose a reason for hiding this comment

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

It would be great to remove the check!

Copy link
Author

Choose a reason for hiding this comment

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

I think it is being used here

if trunkSupport {
if err = s.networkingService.DeleteTrunk(eventObject, port.PortID); err != nil {
return err
}
}
.
Should I remove both ?

@@ -135,6 +132,13 @@ func (s *Service) constructNetworks(openStackCluster *infrav1.OpenStackCluster,
if pOpts.Trunk == nil {
pOpts.Trunk = &openStackMachine.Spec.Trunk
}
// verify trunk support
if *pOpts.Trunk {
Copy link
Contributor

Choose a reason for hiding this comment

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

Since *pOpts.Trunk defaults to openstackMachine.Spec.Trunk, do we need to check trunk support for openstackMachine.Spec.Trunk explicitly in lines 75-79 above? This here looks like the correct place to check.

Copy link
Author

Choose a reason for hiding this comment

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

That assignment is conditional.

@jichenjc
Copy link
Contributor

/ok-to-test

@k8s-ci-robot k8s-ci-robot added ok-to-test Indicates a non-member PR verified by an org member that is safe to test. and removed needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Sep 29, 2021
@Xenwar Xenwar force-pushed the port_level_trunk_check branch 6 times, most recently from d59ad70 to aa2648d Compare September 29, 2021 12:54
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.

Some unit test coverage would also be really helpful here.

if port.Trunk == nil {
*port.Trunk = openStackMachine.Spec.Trunk
}
if openStackMachine.Spec.Trunk || *port.Trunk {
Copy link
Contributor

Choose a reason for hiding this comment

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

Given that you just set this above, you could simplify this to:

  if *port.Trunk {

Copy link
Author

Choose a reason for hiding this comment

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

There is nowhere else where openStackMachine.Spec.Trunk is checked. So, we need both.

Copy link
Contributor

Choose a reason for hiding this comment

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

What we're saying here is that if Trunk is set on the Machine it will be set on all ports, regardless of the explicit setting for that port. Is that correct?

Copy link
Author

Choose a reason for hiding this comment

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

The opposite:

  1. If set@port => take port level and ignore Machine level
  2. if not set@port => take Machine level

on verifying trunk support:
(a) No matter how trunk was setup via (1) or (2): check at port level (*port.Trunk)
(b) In case no port was supplied => check at instance level (openStackMachine.Spec.Trunk)

pkg/cloud/services/compute/instance.go Outdated Show resolved Hide resolved
Comment on lines 116 to 119
trunkSupported, err := s.isTrunkExtSupported()
if err != nil {
return nil, err
}
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 this outside the loop? This is adding an extra API call per port.

Copy link
Author

Choose a reason for hiding this comment

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

When it was outside, it was checking only instance level before instanceSpec.Trunk = openStackMachine.Spec.Trunk. Now, in the for loop, it is checking both instance level and port level.

I agree, in the current format, it is making API calls per port. I am trying to make it efficient by stopping at the first occurrence trunk-set port. I have not succeeded so far as combing return and break is not possible.

Note that making API calls per port is not avoidable. The other location where the check could be added is here. Both do iterate over the ports.

Copy link
Contributor

Choose a reason for hiding this comment

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

The only thing you need to move outside the loop is the code above which sets trunkSupported. The value of trunkSupported will never change during the loop. You can leave the code below, which generates the error, inside the loop.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks. Moving it out.

@Xenwar
Copy link
Author

Xenwar commented Sep 29, 2021

Some unit test coverage would also be really helpful here.

Thanks, there is an ongoing work by @macaptain on the tests. We needed to make the change on this PR in order to test the check.

@Xenwar Xenwar force-pushed the port_level_trunk_check branch from aa2648d to 06465a5 Compare September 29, 2021 16:42
if port.Trunk == nil {
*port.Trunk = openStackMachine.Spec.Trunk
}
if openStackMachine.Spec.Trunk || *port.Trunk {
Copy link
Contributor

Choose a reason for hiding this comment

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

What we're saying here is that if Trunk is set on the Machine it will be set on all ports, regardless of the explicit setting for that port. Is that correct?

Comment on lines 116 to 119
trunkSupported, err := s.isTrunkExtSupported()
if err != nil {
return nil, err
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The only thing you need to move outside the loop is the code above which sets trunkSupported. The value of trunkSupported will never change during the loop. You can leave the code below, which generates the error, inside the loop.

@@ -113,6 +104,25 @@ func (s *Service) CreateInstance(openStackCluster *infrav1.OpenStackCluster, mac
if err != nil {
return nil, err
}
// verify trunk support if trunk is set on at least one Port.
for _, net := range nets {
Copy link
Contributor

Choose a reason for hiding this comment

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

Here we're iterating over nets, which is the return value of constructNetworks(). constructNetworks returns nets generated from both Spec.Networks and Spec.Ports.

I believe this means we're now potentially trunking ports generated for both Spec.Networks and Spec.Ports, where previously we were only trunking Spec.Ports.

I'm not clear on the use case difference between these 2 fields, but I feel like this is a significant change which we should make deliberately. Perhaps @iamemilio or @dulek know?

Copy link
Author

Choose a reason for hiding this comment

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

I agree. To avoid that, one option is to move the inheriting logic to

if portOpts.Trunk != nil && *portOpts.Trunk {
trunk, err := s.getOrCreateTrunk(eventObject, clusterName, port.Name, port.ID)
if err != nil {
record.Warnf(eventObject, "FailedCreateTrunk", "Failed to create trunk for port %s: %v", portName, err)
return nil, err
}
if err = s.replaceAllAttributesTags(eventObject, trunk.ID, tags); err != nil {
record.Warnf(eventObject, "FailedReplaceTags", "Failed to replace trunk tags %s: %v", portName, err)
return nil, err
}
}
return port, nil
}

And, pass the openstackmachine resource to it.

Copy link
Contributor

Choose a reason for hiding this comment

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

I do think the inheriting logic belongs in constructNetworks() and we should make a separate PR if we need to address the inconsistency in inheriting the machine's trunk value between ports and networks. This location in CreateInstance is a good place to check if we need to make an API call to check for trunk support in OpenStack.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yep, lets leave the inheriting logic in constructNetworks(). I also think defaulting it there means we don't have to check it here and just look directly at the ports.

Due to the lack of map/reduce in Go, how about something like:

trunkingRequired := func() bool {
  for _, port := range ports {
    if *port.Trunk != nil && *port.Trunk {
      return true
    }
  }
  return false
}()
if trunkingRequired {
  if !s.isTrunkExtSupported() {
    ... err
  }
}

Or something more idiomatic if you know what that is 🙂

This means we only check trunk support once, and only if we actually need it.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks, done

@Xenwar Xenwar force-pushed the port_level_trunk_check branch from 06465a5 to 7525e1e Compare October 1, 2021 06:23
@@ -113,6 +104,25 @@ func (s *Service) CreateInstance(openStackCluster *infrav1.OpenStackCluster, mac
if err != nil {
return nil, err
}
// verify trunk support if trunk is set on at least one Port.
trunkSupported, err := s.isTrunkExtSupported()
Copy link
Contributor

Choose a reason for hiding this comment

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

👍, but you need to move the error checking (currently lines 117-119) up here, too.

Copy link
Author

Choose a reason for hiding this comment

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

At that point, the second par to the following (i.e. *port.Trunk) is not available outside of the loop. We can only check the instance level outside of the loop.
if openStackMachine.Spec.Trunk || *port.Trunk

As we have it now, the error checking detached from the actual api call, perhaps, we need to move 108 back inside ?

Copy link
Author

Choose a reason for hiding this comment

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

Thanks, done

@@ -113,6 +104,25 @@ func (s *Service) CreateInstance(openStackCluster *infrav1.OpenStackCluster, mac
if err != nil {
return nil, err
}
// verify trunk support if trunk is set on at least one Port.
for _, net := range nets {
Copy link
Contributor

Choose a reason for hiding this comment

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

Yep, lets leave the inheriting logic in constructNetworks(). I also think defaulting it there means we don't have to check it here and just look directly at the ports.

Due to the lack of map/reduce in Go, how about something like:

trunkingRequired := func() bool {
  for _, port := range ports {
    if *port.Trunk != nil && *port.Trunk {
      return true
    }
  }
  return false
}()
if trunkingRequired {
  if !s.isTrunkExtSupported() {
    ... err
  }
}

Or something more idiomatic if you know what that is 🙂

This means we only check trunk support once, and only if we actually need it.

@Xenwar
Copy link
Author

Xenwar commented Oct 10, 2021

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

@Xenwar Xenwar force-pushed the port_level_trunk_check branch 3 times, most recently from dc22b42 to ad1a7d3 Compare October 19, 2021 08:54
@Xenwar
Copy link
Author

Xenwar commented Oct 25, 2021

If there are no further comments on this issue, could this PR be approved ?

@hidekazuna
Copy link
Contributor

/approve

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Oct 26, 2021
@Xenwar Xenwar force-pushed the port_level_trunk_check branch from ad1a7d3 to b658554 Compare October 27, 2021 12:45
@Xenwar
Copy link
Author

Xenwar commented Oct 27, 2021

Made some changes based on a feedback received from slack.

@Xenwar Xenwar force-pushed the port_level_trunk_check branch 3 times, most recently from 4b079c6 to c125a4a Compare October 28, 2021 08:50
@macaptain
Copy link
Contributor

macaptain commented Oct 28, 2021

Now that the constructNetworks function isn't changed in this PR, this looks good to me. I think there is no change except that we run a trunk support check when trunk is enabled on at least one of the ports, or at the instance level. Now there are no changes to the existing inheritance behavior of trunking (which could be debated in a separate issue).

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Oct 28, 2021
@Xenwar
Copy link
Author

Xenwar commented Oct 28, 2021

@mdbooth, the PR is now approved and lgtm-ed
I am putting a hold to get your view on the current version.
/hold

@k8s-ci-robot k8s-ci-robot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Oct 28, 2021
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.

/lgtm

func (s *Service) isTrunkExtSupported() (trunknSupported bool, err error) {
trunkSupport, err := s.networkingService.GetTrunkSupport()
if err != nil {
return false, fmt.Errorf("there was an issue verifying whether trunk support is available, please disable trunk on your manifests: %v", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: please disable trunk on your manifests is probably the wrong advice here, as any error returned by this api call is unlikely to be related to trunk support. Please try again later would be better advice and we'll do that anyway, so probably just log it.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks, fixed.

@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: hidekazuna, macaptain, mdbooth, Xenwar

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

@jichenjc
Copy link
Contributor

jichenjc commented Nov 1, 2021

/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 Nov 1, 2021
@Xenwar Xenwar force-pushed the port_level_trunk_check branch from c125a4a to 74dfbf3 Compare November 1, 2021 10:06
@k8s-ci-robot k8s-ci-robot removed the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Nov 1, 2021
@macaptain
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 Nov 1, 2021
@k8s-ci-robot k8s-ci-robot merged commit 82bc42e into kubernetes-sigs:main Nov 1, 2021
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. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Verify trunk support before creating trunk for ports
7 participants