Sitelet https://github.com/k-orc/openstack-resource-controller/pull/392
Skip to content

Feat/floatingip - #392

Merged
mandre merged 1 commit into
k-orc:mainfrom
ezeriver94:feat/floatingip
May 15, 2025
Merged

mandre merged 1 commit into
k-orc:mainfrom
ezeriver94:feat/floatingip

Conversation

@ezeriver94

Copy link
Copy Markdown
Contributor

Implement FloatingIP controller/actuator

@github-actions

github-actions Bot commented May 6, 2025

Copy link
Copy Markdown

Failed to assess the semver bump. See logs for details.

@mandre mandre left a comment

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.

Thanks for the PR! This is great.

Early feedback on the API for now. I haven't looked at the rest yet.

Comment thread api/v1alpha1/floatingip_types.go Outdated
Comment thread api/v1alpha1/floatingip_types.go Outdated
// portID is the ID of the port to which the floatingip is associated.
// +kubebuilder:validation:MaxLength=1024
// +optional
PortID *string `json:"portID,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.

This should be a reference to a port rather than an ID, we need to change it to portRef. This allows us to add a dependency on the port and wait for it to be created externally if needed.

We've documented this requirement in the General design considerations, however we should probably make it more obvious by adding it to the General API guidelines too.

// fixedIP is the IP address of the port to which the floatingip is associated.
// +optional
FixedIP *IPvAny `json:"fixedIP,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.

Just a note, not necessary to add it now, we'll need at some point to add a projectRef for the FloatingIP resource as I'm doing in #377.

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.

Ok, maybe for a next PR 😅

Comment thread api/v1alpha1/floatingip_types.go Outdated
Comment thread api/v1alpha1/floatingip_types.go
Comment thread api/v1alpha1/floatingip_types.go Outdated
Comment thread api/v1alpha1/floatingip_types.go
Comment thread api/v1alpha1/floatingip_types.go
Comment thread api/v1alpha1/floatingip_types.go
Comment thread cmd/resource-generator/main.go
@ezeriver94

Copy link
Copy Markdown
Contributor Author

Hi @mandre, thanks for the quick feedback. I was going to address the lint issues before I ask for review but I didn't have much time to look at it. I'll go over your comments and lint validations these days.
Regarding 'Label PR / semver' job, I'm not sure how to fix it, if you could give me some hints I would appreciate it.

@mandre

mandre commented May 7, 2025

Copy link
Copy Markdown
Collaborator

Hi @mandre, thanks for the quick feedback. I was going to address the lint issues before I ask for review but I didn't have much time to look at it. I'll go over your comments and lint validations these days. Regarding 'Label PR / semver' job, I'm not sure how to fix it, if you could give me some hints I would appreciate it.

It could not rebase your PR due to a conflict: https://github.com/k-orc/openstack-resource-controller/actions/runs/14848877163/job/41688586737?pr=392#step:3:11

You should rebase manually on top of main and fix the conflict.

@github-actions

github-actions Bot commented May 7, 2025

Copy link
Copy Markdown

Failed to assess the semver bump. See logs for details.

@mandre

mandre commented May 7, 2025

Copy link
Copy Markdown
Collaborator

You should do a rebase (and not a merge) because go-apidiff rebases your changes and is not able to apply one of them, you need to update it so it applies cleanly on top of main.

@github-actions github-actions Bot added the semver:major Breaking change label May 7, 2025
@ezeriver94

Copy link
Copy Markdown
Contributor Author

You should do a rebase (and not a merge) because go-apidiff rebases your changes and is not able to apply one of them, you need to update it so it applies cleanly on top of main.

Thanks, looks better now.
FYI I've just pushed a change into adapter.template to support non-named Openstack resources. Before I added Name into FloatingIP ResourceSpec but as there is no name in Openstack side, it was not really a good solution. Let me know if this does not make sense for you

@mandre mandre left a comment

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.

Still not finished with the review, but I wanted to leave my pending comments before my extended weekend 😃

cloudName: openstack-admin
secretName: openstack-clouds
managementPolicy: managed
resource:

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.

Typically, this test should set all of the fields that we defined in the resource spec to a non-default value. Looks like we're missing some of them.

metadata:
name: floating-ip-create-full
status:
resource:

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.

Please also make sure to check all the fields from status, in particular, we want to ensure we got a floating IP address.

Comment thread internal/controllers/floatingip/tests/floatingip-create-full/00-assert.yaml Outdated
Comment thread internal/controllers/floatingip/tests/floatingip-create-full/00-assert.yaml Outdated
Comment thread internal/controllers/floatingip/tests/floatingip-create-minimal/00-assert.yaml Outdated
Comment thread internal/controllers/floatingip/tests/templates/import-external-floating-ip.yaml Outdated
Comment thread internal/controllers/floatingip/actuator.go Outdated
if resource.SubnetRef != nil {
{
// Fetch dependencies and ensure they have our finalizer
subnet, reconcileStatus := subnetDep.GetDependency(

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 should move the subnet dependency retrieval closer to the floating network one, and return a combined reconcileStatus for both dependencies, like I did here.

When both resources are missing, this allows to get better progress statuses, showing both deps as missing, as shown here.

@ezeriver94

Copy link
Copy Markdown
Contributor Author

I hope I addressed all the comments, although I haven't got time to test it on a real cluster/openstack site yet. I will try to find the time during these days and let you know so you don't review untested code. I will mark the PR as draft for now

@ezeriver94
ezeriver94 marked this pull request as draft May 7, 2025 23:41
@ezeriver94
ezeriver94 marked this pull request as ready for review May 10, 2025 13:00
@ezeriver94

Copy link
Copy Markdown
Contributor Author

Hi @mandre, after some struggle with e2e I believe it's ready for review again. Sorry for the commit spam, but I had to use the workflows you already have in place for deploying devstack as I don't have a local instance of it, and in the one I used for testing I don't have admin credentials.
There is one thing I wanted to hear your opinion about: SubnetRef and FloatingIP fields within spec.resource are both optional and you could use either one of them, but I was wondering if it makes sense to validate (only during resource creation) that if a FloatingIP is specified, the subnet should also be defined (even if it's not mandatory in gophercloud). My question relates to the fact that the IP must belong to a subnet in the network so it would be weird that you know which IP is valid without knowing if a proper subnet is part of the referenced network.

@mandre mandre left a comment

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 is really close, we should be able to merge soon. I've got a few more comments, the most important one being for the name of the network reference. I'm not sure if we should call it networkRef, as currently implemented, or floatingNetworkRef to be closer to neutron API.

Before we merge your patch, could you also squash the commits?

What happened to the floatingip-import-error test you had at some point? From what I recall, they were good.

Comment thread api/v1alpha1/floatingip_types.go Outdated
Comment thread internal/controllers/floatingip/actuator.go Outdated
Comment thread internal/controllers/floatingip/actuator.go Outdated
Comment thread api/v1alpha1/floatingip_types.go Outdated

// networkRef is a reference to the ORC Network which this resource is associated with.l
// +optional
NetworkRef KubernetesNameRef `json:"networkRef"`

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.

I wonder if we shouldn't call this field FloatingNetworkRef, to align better with the neutron API. @mdbooth, thoughts?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Agree. It will make it more obvious what it is.

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.

Also, please make it a pointer, with omitempty marker (wherever the field is optional). It was my mistake originally when I introduced these fields in #302. Changing them now would require a major bump, so let's try not to introduce more of them if we can avoid it.

Same goes for PortRef below.

Comment thread api/v1alpha1/floatingip_types.go
const controllerName = "floatingip"

var (
fieldOwner = orcstrings.GetSSAFieldOwner(controllerName)

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.

Please use externalObjectFieldOwner variable instead.

Comment thread internal/controllers/floatingip/controller.go Outdated
Comment thread internal/controllers/floatingip/controller.go Outdated
Comment thread internal/controllers/floatingip/controller.go Outdated
Year string
Name string
NameLower string
IsNotNamed bool

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.

I'm not a big fan of new field's name, but I can't come up with a better name. Perhaps we could just make getResourceName() gracefully handle the case where the spec does not have a name instead?

@ezeriver94

Copy link
Copy Markdown
Contributor Author

What happened to the floatingip-import-error test you had at some point? From what I recall, they were good.

I believe at some moment during the e2e nightmare I decided it was not useful, but now I can't recall why. I'll create it again

I'm not sure if we should call it networkRef, as currently implemented, or floatingNetworkRef to be closer to neutron API.

About that, I don't have a clear answer, I'm fine with naming it as you prefer.

I'm not a big fan of new field's name, but I can't come up with a better name. Perhaps we could just make getResourceName() gracefully handle the case where the spec does not have a name instead?

I can make getResourceName use reflection to detect if the ResourceSpec contains a name or not, I didn't do it this way before as it would be more disruptive, and I believe getResourceName should not be even defined for nameless resources, to make sure we don't use it during reconciliation (otherwise we would need to consider getResourceName to return empty string in multiple places, something that currently can't happen as all named resources will either have Resource.Name or Metadata.Name)

func getResourceName(orcObject orcObjectPT) string {
	if orcObject.Spec.Resource.Name != nil {
		return string(*orcObject.Spec.Resource.Name)
	}
	return orcObject.Name
}

@ezeriver94

Copy link
Copy Markdown
Contributor Author

Before we merge your patch, could you also squash the commits?

done 😄

@mandre mandre left a comment

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.

If you could also improve the commit message, trying to stick to the kubernetes guidelines as much as possible.

Comment thread api/v1alpha1/floatingip_types.go Outdated

// networkRef is a reference to the ORC Network which this resource is associated with.l
// +optional
NetworkRef KubernetesNameRef `json:"networkRef"`

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.

Also, please make it a pointer, with omitempty marker (wherever the field is optional). It was my mistake originally when I introduced these fields in #302. Changing them now would require a major bump, so let's try not to introduce more of them if we can avoid it.

Same goes for PortRef below.

Comment thread api/v1alpha1/floatingip_types.go Outdated
// +optional
Description *NeutronDescription `json:"description,omitempty"`

// networkRef is a reference to the ORC Network which this resource is associated with.l

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.

Nit: there's a trailing l.

Suggested change
// networkRef is a reference to the ORC Network which this resource is associated with.l
// networkRef is a reference to the ORC Network which this resource is associated with.

Comment thread api/v1alpha1/floatingip_types.go Outdated

// subnetRef references the subnet to which the floatingip is associated.
// +optional
SubnetRef *KubernetesNameRef `json:"subnetRef,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.

Indeed, after I it a bit more thoughts, I believe these fields should be called FloatingNetworkRef and FloatingSubnetRef.

Also, @mdbooth raised a good point yesterday. We should make FloatingNetworkRef and FloatingSubnetRef mutually exclusive, with exactly one being set, because a subnet always has a network, and letting users set a network at the same time as the subnet is only a potential source of error.

I think the following validation enforces it:

// +kubebuilder:validation:XValidation:rule="has(self.floatingNetworkRef) != has(self.floatingSubnetRef)",message="Exactly one of 'floatingNetworkRef' or 'floatingSubnetRef' must be set"

@ezeriver94

Copy link
Copy Markdown
Contributor Author

If you could also improve the commit message, trying to stick to the kubernetes guidelines as much as possible.

sorry, I didn't notice the squashed commits remained. Will do

@ezeriver94

Copy link
Copy Markdown
Contributor Author

@mandre I believe all comments were addressed (I hope I didn't miss anyone).
There is only one thing without a resolution:

I'm not a big fan of new field's name, but I can't come up with a better name. Perhaps we could just make getResourceName() gracefully handle the case where the spec does not have a name instead?

I can make getResourceName use reflection to detect if the ResourceSpec contains a name or not, I didn't do it this way before as it would be more disruptive, and I believe getResourceName should not be even defined for nameless resources, to make sure we don't use it during reconciliation (otherwise we would need to consider getResourceName to return empty string in multiple places, something that currently can't happen as all named resources will either have Resource.Name or Metadata.Name)

func getResourceName(orcObject orcObjectPT) string {
	if orcObject.Spec.Resource.Name != nil {
		return string(*orcObject.Spec.Resource.Name)
	}
	return orcObject.Name
}

Please let me know if you believe I should change something related to this template.

Related to

Also, @mdbooth raised a good point yesterday. We should make FloatingNetworkRef and FloatingSubnetRef mutually exclusive, with exactly one being set, because a subnet always has a network, and letting users set a network at the same time as the subnet is only a potential source of error.

I think the following validation enforces it:

// +kubebuilder:validation:XValidation:rule="has(self.floatingNetworkRef) != has(self.floatingSubnetRef)",message="Exactly one of 'floatingNetworkRef' or 'floatingSubnetRef' must be set"

I added one more test called floatingip-create-subnet-ref as now the create-full did not cover subnetRef (being mutually exclusive with networkRef)

@mandre

mandre commented May 15, 2025

Copy link
Copy Markdown
Collaborator

@mandre I believe all comments were addressed (I hope I didn't miss anyone). There is only one thing without a resolution:

I'm not a big fan of new field's name, but I can't come up with a better name. Perhaps we could just make getResourceName() gracefully handle the case where the spec does not have a name instead?

I can make getResourceName use reflection to detect if the ResourceSpec contains a name or not, I didn't do it this way before as it would be more disruptive, and I believe getResourceName should not be even defined for nameless resources, to make sure we don't use it during reconciliation (otherwise we would need to consider getResourceName to return empty string in multiple places, something that currently can't happen as all named resources will either have Resource.Name or Metadata.Name)

func getResourceName(orcObject orcObjectPT) string {
	if orcObject.Spec.Resource.Name != nil {
		return string(*orcObject.Spec.Resource.Name)
	}
	return orcObject.Name
}

Please let me know if you believe I should change something related to this template.

Nah, it's alright. We don't expose it as an API so we can easily change it later if we don't like it.

Related to

Also, @mdbooth raised a good point yesterday. We should make FloatingNetworkRef and FloatingSubnetRef mutually exclusive, with exactly one being set, because a subnet always has a network, and letting users set a network at the same time as the subnet is only a potential source of error.
I think the following validation enforces it:
// +kubebuilder:validation:XValidation:rule="has(self.floatingNetworkRef) != has(self.floatingSubnetRef)",message="Exactly one of 'floatingNetworkRef' or 'floatingSubnetRef' must be set"

I added one more test called floatingip-create-subnet-ref as now the create-full did not cover subnetRef (being mutually exclusive with networkRef)

Good call. Let's get this merged :)

@mandre mandre added semver:minor Backwards-compatible change and removed semver:major Breaking change labels May 15, 2025
@mandre
mandre merged commit 2a811eb into k-orc:main May 15, 2025
@ezeriver94
ezeriver94 deleted the feat/floatingip branch May 15, 2025 13:02
mandre added a commit to shiftstack/openstack-resource-controller that referenced this pull request May 19, 2025
Floating IP controller was implemented in
k-orc#392.
mandre added a commit to shiftstack/openstack-resource-controller that referenced this pull request May 19, 2025
Floating IP controller was implemented in
k-orc#392.
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.

4 participants