Skip to content

Port: add propagationUplinkStatus field#641

Open
winiciusallan wants to merge 5 commits intok-orc:mainfrom
winiciusallan:port-propagate-uplink-status
Open

Port: add propagationUplinkStatus field#641
winiciusallan wants to merge 5 commits intok-orc:mainfrom
winiciusallan:port-propagate-uplink-status

Conversation

@winiciusallan
Copy link
Copy Markdown
Contributor

@winiciusallan winiciusallan commented Jan 12, 2026

This PR introduces the propagationUplinkStatus

https://docs.openstack.org/api-ref/network/v2/index.html#uplink-status-propagation

Notes:

  • I've decided to keep the default value for that field as false, even if the doc says that the default value is true. The reason is that in environments where this extension is not enabled, we can't update that field and it always returns false, so if we enforce it as true, it may raise an error. So if the user wants to enable it, they must explicitly define it.

edit:

  • If the extension is enabled in the environment, the default value for this field is the Openstack default value, which is true. Otherwise, it'll be nil

Partial #616

@github-actions github-actions Bot added the semver:major Breaking change label Jan 12, 2026
@winiciusallan
Copy link
Copy Markdown
Contributor Author

weird... the uplink_status_propagation extension was not added to the devstack deployment. I tested locally and it only works by setting Q_ML2_PLUGIN_EXT_DRIVERS directly.

Has anyone ever seen something like this?

@winiciusallan winiciusallan force-pushed the port-propagate-uplink-status branch from 8cbef64 to 4d21547 Compare January 13, 2026 16:40
@winiciusallan
Copy link
Copy Markdown
Contributor Author

winiciusallan commented Jan 13, 2026

Ok, here we go. I needed to add the neutron plugin on CI so that devstack can run this line and enable uplink-status-propagation accordingly. However, it looks like that Dalmatian release doesn't enable the ability to update propagateUplinkStatus by default on Devstack like did in newer releases, so the CI ended up failing. I believe that adding a line explicitly enabling uplink_status_propagation_updatable extension should work.

About the job failing on Flamingo I really don't get the why. The E2E job has failed in domain-import-error tests.

cc. @mandre I'll wait for you feedback before making any additional change.

Comment thread api/v1alpha1/port_types.go Outdated
// propagateUplinkStatus represents the uplink status propagation of
// the port.
// +optional
PropagateUplinkStatus *bool `json:"propagateUplinkStatus,omitempty"`
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We've discussed this privately already, after you brought the issue to my attention: gophercloud implements the PropagateUplinkStatus in the response Port structure as a bool while it should really be a *bool with omitempty, and because of this we can't reliably know the status for PropagateUplinkStatus. I suggest that until the issue if fixed in gophercloud, we make that field immutable.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It's been a while and I don't remember all of the discussion. From reading the PR comments again, I believe we're past the gophercloud limitation (thanks to custom unmarshalling) but we still need to make the field immutable because dalmatien doesn't support updating the field. If that's effectively the case, we should add that as a comment so we know when we can change that behavior.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, you're absolutely right. I'll add this comment.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment thread .github/workflows/e2e.yaml Outdated
@mandre
Copy link
Copy Markdown
Collaborator

mandre commented Jan 15, 2026

About the job failing on Flamingo I really don't get the why. The E2E job has failed in domain-import-error tests.

I re-ran this job and the error is gone. I was most likely a flake (bound to happen as we add more tests).

@github-actions github-actions Bot added semver:minor Backwards-compatible change and removed semver:major Breaking change labels Jan 16, 2026
@winiciusallan
Copy link
Copy Markdown
Contributor Author

@mandre let me know when you think it is ready to go, I can squash the commits to make the PR cleaner. :)

Comment thread internal/osclients/networking.go Outdated
// propagateUplinkStatus represents the uplink status propagation of
// the port.
// +optional
PropagateUplinkStatus *bool `json:"propagateUplinkStatus,omitempty"`
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It's been a while and I don't remember all of the discussion. From reading the PR comments again, I believe we're past the gophercloud limitation (thanks to custom unmarshalling) but we still need to make the field immutable because dalmatien doesn't support updating the field. If that's effectively the case, we should add that as a comment so we know when we can change that behavior.

Comment thread internal/controllers/port/tests/port-create-minimal/00-assert.yaml
PropagateUplinkStatusPtr *bool `json:"propagate_uplink_status,omitempty"`
}

func (p *PortExt) UnmarshalJSON(b []byte) error {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This custom unmarshaller omits portsecurity.PortSecurityExt or portsbinding.PortsBindingExt meaning that they'll always have the zero value (it's weird that we do not detect this bug via the tests, don't we have coverage for those fields?).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is something that I was in doubt about... I'm not sure, and if you can correct me if I'm wrong, I'll appreciate it, but it looks like Gophercloud uses reflection to populate the result rather than simply using a json.Unmarshal, am I wrong?

https://github.com/gophercloud/gophercloud/blob/main/results.go#L70

You're right that they will always have the zero value, but maybe in the above phase, the fields are populated using reflection. I need to better understand this. Any initial thought?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

A well crafted test should give us the answer.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sorry for the late response.

The idea of this test is to show that using ports.Get(...).ExtractInto(&p), the fields are populated even though they're not explicitly set in the UnmarshalJSON function, as you highlighted in your initial comment, unlike using json.Unmarshal directly, which calls the custom Unmarshal and ignores the PortSecurityEnabled and PortBindings.

https://go.dev/play/p/iUMKGSjAFoo

Copy link
Copy Markdown
Contributor Author

@winiciusallan winiciusallan Apr 23, 2026

Choose a reason for hiding this comment

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

After understanding more about how the parse actually works, I've decided to add PortSecurityExt and PortsBindingExt to the Unmarshal function.

This helps us especially when listing ports because we are not using the default Gophercloud's Extract mechanisms, and we do need to populate fields using the unmarshaler function.

@@ -172,13 +191,30 @@ func (c networkClient) UpdateFloatingIP(ctx context.Context, id string, opts flo

func (c networkClient) ListPort(ctx context.Context, opts ports.ListOptsBuilder) iter.Seq2[*PortExt, error] {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We shouldn't have to update ListPort I believe.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

IIRC, there was a failing test, and the solution was to change the ListPort function, but I'll double-check this to confirm what exactly the error was.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

After discussion, we found a potential bug in Gophercloud, and a PR has been created. More information is there.

gophercloud/gophercloud#3726

@winiciusallan
Copy link
Copy Markdown
Contributor Author

@mandre I'm working again to have this PR merged. A lot of work has been done since the last commit, so I'll rebase and start addressing the comments.

@winiciusallan winiciusallan force-pushed the port-propagate-uplink-status branch from 87a3ecf to 0f1e900 Compare April 19, 2026 18:22
We have a missing pointer on Gophercloud, this is causing a misbehavior.
For workarouding purposes, was added a new struct to support a pointer
for that field. Tests were also fixed.
@winiciusallan winiciusallan force-pushed the port-propagate-uplink-status branch from 0f1e900 to 60786e3 Compare April 23, 2026 17:03
@winiciusallan
Copy link
Copy Markdown
Contributor Author

@mandre let me know when you think it is good. I'd like to squash the commits. keeping the history clear 🤌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

semver:minor Backwards-compatible change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants