-
Notifications
You must be signed in to change notification settings - Fork 261
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
✨ Allow Trunk configuration at a Port level #934
Conversation
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 Once the patch is verified, the new status will be reflected by the 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. |
/hidekazuna |
/ok-to-test |
This is awesome, I'm just interested if the logic here is fine. I'd expect that |
True. At the moment, instance level overrides all ports if it is set to false. |
We can remove the conditional here https://github.com/kubernetes-sigs/cluster-api-provider-openstack/pull/934/files#diff-5e7dbfd52305a21a11fb94fab201062ae2c7b851db93c2a8443a1d82d7aa7936R506 |
Thank you, this seems more logical to me. The main reason here is that I'm looking at this from Kuryr perspective which requires you to have trunk set only on the main port of the instance. This means that I can now set instance's |
/retest |
/test pull-cluster-api-provider-openstack-e2e-test |
iTags := []string{} | ||
if len(instance.Tags) > 0 { | ||
iTags = instance.Tags | ||
} |
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.
Why is iTags necessary here? Why can't we just pass instance.Tags in all cases? We were previously passing it to replaceAllAttributeTags as-is.
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.
Tried to pass the instance.Tags as is. However, it is not always passed to the createInstance
. line 195 is a guard against that.
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.
I don't understand. What breaks?
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.
Will try to get more specific data on this.
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.
Got some logs.
Cause: When no tag is provided OpenStackMachineTemplate.spec.template.spec.template.spec.tags
, the following error occurs.
logs:
E0716 20:27:52.384885 846 openstackmachine_controller.go:389] controller-runtime/manager/controller/openstackmachine
"msg"="OpenStack instance cannot be created: error creating Openstack instance:
Missing input for argument [Tags]" "error"="UpdateError" "cluster"="basic-1"
"machine"="basic-1-control-plane-wsrg7" "name"="basic-1-control-plane-4p2jc"
"namespace"="default" "openStackCluster"="basic-1"
"openStackMachine"="basic-1-control-plane-4p2jc" "reconciler group"="infrastructure.cluster.x-k8s.io" "reconciler kind"="OpenStackMachine"
The problem does not occur for all ports when user specified multiple ports. It only occurs to some of them. Which is the reason why I added that check.
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.
Any particular reason why it's part of the loop? I would expect the block to be moved up, before you loop over instance networks.
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.
The ports are created in that loop and trying to make use of that.
|
||
if portOpts.Trunk { | ||
trunkDescription := names.GetDescription(clusterName) | ||
trunk, err := s.getOrCreateTrunk(eventObject, trunkDescription, port.Name, port.ID) |
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.
This doesn't look right to me. This looks like it's creating a new trunk for every trunked port. My understanding was that all trunked ports would use the same trunk on a single instance. I understood that the change here was that some ports can now optionally not use that trunk, not that we would have multiple trunks.
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.
Yes, this PR is creating a new trunk for every port marked as trunked.
However, it is configurable as is shown in the description of this PR.
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.
Please ignore this because it's out of scope for your change and consistent with the previous behaviour. However, now that I've seen it I don't understand why trunks are used this way. That could just be because I don't properly understand trunks, though.
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.
@mdbooth: It's a Neutron trunk, which might be a bit confusing. In Neutron a port can have a trunk created and then you add other ports as subports in that trunk. In Kuryr we use that to dynamically add subports which serve as pods interfaces. What you're proposing is doable, but I'm not sure if I see value in subports added statically. Anyway if we'd want to implement that, I'd rather add a subports
field in PortOpts
and get subports defined there.
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.
@dulek is the name of the trunk singinificant to kuryr? Does kuryr look up trunks per port (parent port.name for example), or by instance
@@ -508,10 +504,22 @@ func (s *Service) getOrCreatePort(eventObject runtime.Object, clusterName string | |||
} | |||
|
|||
record.Eventf(eventObject, "SuccessfulCreatePort", "Created port %s with id %s", port.Name, port.ID) | |||
|
|||
if portOpts.Trunk { |
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.
This is a problem.
Previously if we specified trunk on the instance and a number of ports without any trunk setting, those ports would inherit the trunk setting of the instance. Here we're always using the trunk setting of the port, which now defaults to False rather than inheriting the trunk setting of the instance. This will cause a change of behaviour.
I think we want the following behaviour:
- instance=true, port=undefined, trunk=true
- instance=true, port=true, trunk=true
- instance=true, port=false, trunk=false
- instance=false, port=undefined, trunk=false
- instance=false, port=true, trunk=true
- instance=false, port=false, trunk=false
If we define port=undefined to be false (the behaviour here), that breaks case 1.
If we define port=undefined to be true, that breaks case 4.
IOW think we need to make portOpts.Trunk a *bool instead of a bool.
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.
We are not inheriting instance level setting. As discussed with @dulek above, each port makes its own decision, regardless of what the instance says.
for (1) and (4), the check was on if a port is specified via Portopts
, if not it is set to the instance level
Trunk: openStackMachine.Spec.Trunk, |
Is it so that there are other ways of specifying multiple ports ?
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.
However, I think we previously did inherit the instance setting. Let's take a specific example:
trunk: true
ports:
- description: "primary 1"
foo: bar
- description: "primary 2"
foo: baz
Without this change, both of these ports will be trunked. With this change these ports are no longer trunked because trunk
is not specified on the port (because it did not previously exist), and being a bool
it will default to false
. IOW this change causes a change in previously defined behaviour. I think that would be a regression.
I think the fix is simple: if we make trunk
on the port a *bool
instead of a bool
we can define a third behaviour for the undefined case which is compatible with the previous behaviour.
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.
Thanks. Now, I understood the consequence of not making it a pointer.
Making changes to address it. Will also update the PR description accordingly.
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.
Done.
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.
Thanks @mdbooth, I missed this detail.
Also, where are we on testing this kind of functionality? |
I was waiting for the merge of #935 before adding tests, but add a test for it. |
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.
I still think this change would introduce a regression without changing portopts.trunk
from bool
to *bool
.
iTags := []string{} | ||
if len(instance.Tags) > 0 { | ||
iTags = instance.Tags | ||
} |
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.
I don't understand. What breaks?
@@ -508,10 +504,22 @@ func (s *Service) getOrCreatePort(eventObject runtime.Object, clusterName string | |||
} | |||
|
|||
record.Eventf(eventObject, "SuccessfulCreatePort", "Created port %s with id %s", port.Name, port.ID) | |||
|
|||
if portOpts.Trunk { |
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.
However, I think we previously did inherit the instance setting. Let's take a specific example:
trunk: true
ports:
- description: "primary 1"
foo: bar
- description: "primary 2"
foo: baz
Without this change, both of these ports will be trunked. With this change these ports are no longer trunked because trunk
is not specified on the port (because it did not previously exist), and being a bool
it will default to false
. IOW this change causes a change in previously defined behaviour. I think that would be a regression.
I think the fix is simple: if we make trunk
on the port a *bool
instead of a bool
we can define a third behaviour for the undefined case which is compatible with the previous behaviour.
|
||
if portOpts.Trunk { | ||
trunkDescription := names.GetDescription(clusterName) | ||
trunk, err := s.getOrCreateTrunk(eventObject, trunkDescription, port.Name, port.ID) |
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.
Please ignore this because it's out of scope for your change and consistent with the previous behaviour. However, now that I've seen it I don't understand why trunks are used this way. That could just be because I don't properly understand trunks, though.
c563f2a
to
2908576
Compare
a314d3a
to
d8fe11c
Compare
0b64323
to
dd8dc0e
Compare
Once trunk is supported, a test for trunk with the following content can be added https://gist.github.com/Xenwar/d2a9a120531aef09f7670b57d43e0857 |
The trunk feature is tested on separate openstack environment with trunk support. Once it supports trunk, the following test can be added, PortSecurity is also tested |
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.
two nits
pOpts := &openStackMachine.Spec.Ports[i] | ||
// No Trunk field specified for the port, inherits openStackMachine.Spec.Trunk. | ||
if pOpts.Trunk == nil { | ||
pOpts.Trunk = &openStackMachine.Spec.Trunk | ||
} |
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.
You have to create the variable pOpts
to not override port.Trunk
, correct?
Or can we do sth like this? And pass PortOpts: &port
in l.164 and l.172
pOpts := &openStackMachine.Spec.Ports[i] | |
// No Trunk field specified for the port, inherits openStackMachine.Spec.Trunk. | |
if pOpts.Trunk == nil { | |
pOpts.Trunk = &openStackMachine.Spec.Trunk | |
} | |
// No Trunk field specified for the port, inherits openStackMachine.Spec.Trunk. | |
if port.Trunk == nil { | |
port.Trunk = &openStackMachine.Spec.Trunk | |
} |
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.
pOpts is created to avoid code duplication.
The check needs to be done for each Port over the loop.
return port, nil | ||
} | ||
|
||
func (s *Service) getOrCreateTrunk(eventObject runtime.Object, clusterName, trunkName, portID string) (*trunks.Trunk, error) { | ||
func (s *Service) getOrCreateTrunk(eventObject runtime.Object, description, trunkName, portID string) (*trunks.Trunk, error) { |
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.
I would keep consistent to the other methods and stay with clusterName
as an argument. We're doing this several times like this
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.
Thanks. done.
thanks for the info, let's merge this after review comments done, I agree we can track the issue and fix later on |
bfa84f4
to
44240bd
Compare
Signed-off-by: Anwar Hassen <[email protected]>
I have addressed on the of the comments. @tobiasgiese would you please check again to see if I have addresses the issues. |
/lgtm |
@jichenjc |
/approve thanks a lot for your help~ |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: jichenjc, 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 |
Allow Trunk configuration at a Port level
This PR enables and disables port level trunk setting as follows.
Example spec:
Output:
Signed-off-by: Anwar Hassen [email protected]