Skip to content

Implement Limit controller - #868

Open
chenwng wants to merge 13 commits into
k-orc:mainfrom
chenwng:limit-controller
Open

Implement Limit controller#868
chenwng wants to merge 13 commits into
k-orc:mainfrom
chenwng:limit-controller

Conversation

@chenwng

@chenwng chenwng commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

This PR implements the controller for Limit in Keystone.

Region is not included in the spec as it is not available in ORC yet.

As Limit depends on RegisteredLimit which hasn't been merged yet, a setup deployment is used in e2e test cases to create required RegisteredLimits and remove them when tearing down cases. The deployment is also used to disable created Domains to facilitate the deletion of them.

Close #851

chenwng added 9 commits July 28, 2026 11:40
go run ./cmd/scaffold-controller -interactive=false \
    -kind=Limit \
    -gophercloud-client=NewIdentityV3 \
    -gophercloud-module=github.com/gophercloud/gophercloud/v2/openstack/identity/v3/limits \
    -gophercloud-type=Limit \
    -openstack-json-object=limit \
    -available-polling-period=0 \
    -deleting-polling-period=0 \
    -required-create-dependency=Service \
    -optional-create-dependency=Project \
    -optional-create-dependency=Domain \
    -import-dependency=Service \
    -import-dependency=Project \
    -import-dependency=Domain
@github-actions github-actions Bot added the semver:major Breaking change label Jul 28, 2026
@chenwng
chenwng force-pushed the limit-controller branch from c416088 to e556212 Compare July 28, 2026 14:22
Update generated resources to reflect the addition of description in Limit spec
Update the OLM bundle
@chenwng
chenwng force-pushed the limit-controller branch from e556212 to 0b8d70e Compare July 29, 2026 11:06
Comment thread internal/controllers/limit/actuator.go Outdated
Comment thread internal/controllers/limit/actuator.go Outdated

@dlaw4608 dlaw4608 left a comment

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.

Hey Winston, great job on the PR!! , I left a few comments after a quick first look, I am looking into it more but just to show you what I found so far WDYT?

Comment thread internal/controllers/limit/actuator.go Outdated
Comment thread internal/controllers/limit/actuator.go Outdated
Comment thread internal/controllers/limit/tests/utils/main.go Outdated
Fix parameters in dependencies in Limit actuator
Fix default name in test utils
@chenwng

chenwng commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @dlaw4608 for the review. I will fix them. At the same time, I am also trying to figure out the CI failures.

@chenwng
chenwng force-pushed the limit-controller branch from 0b8d70e to b41c2e4 Compare July 29, 2026 13:53
@chenwng

chenwng commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

After further debugging, I found two issues in the CI e2e failures.

  • The adhoc setup/teardown pod takes too long time to complete creating registered limit, and the long backoff of limit controller makes test cases unable to complete in time. Using prebuilt image will solve this issue, but this will bring in an image to build/maintain. So I will wait for the merge of registered limit controller and take advantage of it.
  • Keystone API list limit returns empty even though limits have been created successfully in OpenStack versions flamingo (stable/2025.2) and epoxy (stable/2025.1), and listing with limit id does return the limit. No such an issue was found in version gazpacho (stable/2026.1). Here is the test result in my local env with version flamingo.

Limits can be created successfully.

NAMESPACE   NAME                                               ID                                 AVAILABLE   RESOURCE             LIMIT   POLICY    MESSAGE
default     limit.openstack.k-orc.cloud/limit-import-error-1   578222e588f74fb4921d5d561c88b560   True        limit-import-error   50      managed   OpenStack resource is up to date
default     limit.openstack.k-orc.cloud/limit-import-error-2   aab77ebf7ce7447d85d12cac91526dcc   True        limit-import-error   60      managed   OpenStack resource is up to date

openstack limit list returns nothing. However, openstack limit show limit-id returns the limit correctly.

$openstack limit list 


$openstack limit show 578222e588f74fb4921d5d561c88b560 
+----------------+-----------------------------------------------------------------+
| Field          | Value                                                           |
+----------------+-----------------------------------------------------------------+
| description    | Limit from "import error" test for project-limit-import-error-1 |
| domain_id      | None                                                            |
| id             | 578222e588f74fb4921d5d561c88b560                                |
| project_id     | ab9e509176894c408707611de07fb88c                                |
| region_id      | None                                                            |
| resource_limit | 50                                                              |
| resource_name  | limit-import-error                                              |
| service_id     | 5924b6f0c7c840faa46450ff73b1a1a2                                |
+----------------+-----------------------------------------------------------------+

$openstack limit show aab77ebf7ce7447d85d12cac91526dcc
+----------------+-----------------------------------------------------------------+
| Field          | Value                                                           |
+----------------+-----------------------------------------------------------------+
| description    | Limit from "import error" test for project-limit-import-error-2 |
| domain_id      | None                                                            |
| id             | aab77ebf7ce7447d85d12cac91526dcc                                |
| project_id     | 562d74e5088941068fd04c4e93da32e5                                |
| region_id      | None                                                            |
| resource_limit | 60                                                              |
| resource_name  | limit-import-error                                              |
| service_id     | 5924b6f0c7c840faa46450ff73b1a1a2                                |
+----------------+-----------------------------------------------------------------+

This makes all limit import related test cases unable to pass in flamingo and epoxy envs.

…to Keystone API issue

Use prebuilt image to avoid slow creation of registered limits
@chenwng
chenwng force-pushed the limit-controller branch from 3540f8b to 60bb5b3 Compare July 30, 2026 19:42
@chenwng

chenwng commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

I added a step in e2e workflow to skip the limit import test cases for openstack versions other than gazpacho.

@winiciusallan winiciusallan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hey @chenwng, I did a first round of review, but I need to take a look at the rest. Thanks for your PR.

Comment thread .github/workflows/e2e.yaml Outdated

// resourceLimit is the override value of the limit.
// +optional
ResourceLimit int32 `json:"resourceLimit,omitempty"`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this should be a pointer. If the ResourceLimit if set to 0, it will be omitted.

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.

Can you elaborate the part about it will be omitted? Do you mean it won't be shown in the yaml output or something else?

Here is a test I made. It was shown correctly in the status.resource

apiVersion: openstack.k-orc.cloud/v1alpha1
kind: Limit
metadata:
  annotations:
    ...
  creationTimestamp: "2026-08-04T10:08:32Z"
  finalizers:
  - openstack.k-orc.cloud/limit
  generation: 1
  name: limit-managed-domain
  namespace: default
  resourceVersion: "562155"
  uid: defec55e-42a9-4e8e-b1a1-54b59af42405
spec:
  cloudCredentialsRef:
    cloudName: openstack-admin
    secretName: openstack-clouds
  managementPolicy: managed
  resource:
    projectRef: project-admin
    resourceLimit: 0
    resourceName: servers
    serviceRef: nova
status:
  conditions:
  - lastTransitionTime: "2026-08-04T10:08:35Z"
    message: OpenStack resource is available
    observedGeneration: 1
    reason: Success
    status: "True"
    type: Available
  - lastTransitionTime: "2026-08-04T10:08:35Z"
    message: OpenStack resource is up to date
    observedGeneration: 1
    reason: Success
    status: "False"
    type: Progressing
  id: 22471bb8f6524711be117d40667c0bda
  lastSyncTime: "2026-08-04T10:08:35Z"
  resource:
    projectID: 6fd7df4cf061469ab27d39d6c91b25a0
    resourceLimit: 0
    resourceName: servers
    serviceID: b8e6f8f3a9264fcaa5dc99e34aea1e31

Comment thread README.md
| group | | ✔ | ✔ |
| image | ✔ | ✔ | ✔ |
| keypair | | ◐ | ◐ |
| limit | | | ◐ |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

When we have RegionRef on this controller, I believe we will be pretty much done.

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. After Region controller is merged, we can add the RegionRef field.

Comment thread internal/controllers/limit/controller.go Outdated
return nil, progress.WrapError(err)
}

logger.Info("limit created", "createOpts", createOpts)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's remove this. Maybe you have put for debug purposes.

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.

I added it during debugging the CI issue and it was because I wasn't able to tell if the limit actually was created. And after debugging, I thought given it is informational and helps understand whether the controller is working normally, so I left it.

I understand there are other general places printing logs which would tell whether a resource has been created successfully after reconciling, such as Reconcile successful, but I would argue some concret log confirming it would help better when checking the log for either information only or troubleshooting.

Comment on lines +278 to +283
// There seems to be a bug that keystone doesn't clear the description field when receiving a PATCH request with an empty description.
// This will cause the `Progressing` condition stuck with `Resource status will be refreshed`.
// Tested with `openstack limit set --description ""`
handleDescriptionUpdate(&updateOpts, resource, osResource)
// The same issue exists with resourceLimit. Updating resourceLimit with 0 doesn't work.
handleResourceLimitUpdate(&updateOpts, resource, osResource)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Indeed it looks like something on Keystone's side. Keystone doesn't differentiate description unset and empty string. I think this is something that we could address in upstream if you would like to give it a try.

https://github.com/openstack/keystone/blob/30ef2ffa65a3486ef882f00538e20f2253c57d4c/keystone/limit/backends/sql.py#L285-L292

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.

Thanks for pointing to the root cause. I am not quite familiar with the implementation of keystone. I will put it in low priority and probably give it a try in the future when I have time.

}

func handleDescriptionUpdate(updateOpts *limits.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) {
description := ptr.Deref(resource.Description, "")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If the user unset the description from spec, the controller will keep the description as-is and we will have a mismatch between spec and status (no description x some description).

Wdyt of having this field as immutable?

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.

If this field is set to immutable, then user would lose the capability to update the description completely. I am considering adding a note for description to warn user that clearing them doesn't work until the issue is fixed in upstream. What do you think?

Comment on lines +335 to +345
func validateUpdate(resource *resourceSpecT, osResource *osResourceT) error {
if resource.DomainRef != nil && osResource.ProjectID != "" {
return errInvalidDomainRefUpdate
}

if resource.ProjectRef != nil && osResource.DomainID != "" {
return errInvalidProjectRefUpdate
}

return nil
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What is your idea with this function? Are not these fields already immutable and checked during creation?

@chenwng chenwng Aug 4, 2026

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.

If user sets ProjectRef first, later he sets DomainRef and removes ProjectRef in the modifed yaml, this will not trigger the API validation of ProjectRef because ProjectRef is nil and not modified. Adding this validtion would block user to do such a change given we don't have a webhook avaiable.

Here is an example without this validation. After creating this Limit, I modifed the yaml with domianRef = default without projectRef. You can see below the spec and the status.resource don't match anymore.

apiVersion: openstack.k-orc.cloud/v1alpha1
kind: Limit
metadata:
  annotations:
    ...
  finalizers:
  - openstack.k-orc.cloud/limit
  generation: 2
  name: limit-managed-domain
  namespace: default
  resourceVersion: "557586"
  uid: 409c3ab1-91fa-4f29-b9c3-bba4e1353399
spec:
  cloudCredentialsRef:
    cloudName: openstack-admin
    secretName: openstack-clouds
  managementPolicy: managed
  resource:
    description: Managed limit
    domainRef: default
    resourceLimit: 50
    resourceName: servers
    serviceRef: nova
status:
  conditions:
  - lastTransitionTime: "2026-08-04T09:14:05Z"
    message: OpenStack resource is available
    observedGeneration: 2
    reason: Success
    status: "True"
    type: Available
  - lastTransitionTime: "2026-08-04T09:14:05Z"
    message: OpenStack resource is up to date
    observedGeneration: 2
    reason: Success
    status: "False"
    type: Progressing
  id: 56f2b0102ca1461dbf45e0c7558d90aa
  lastSyncTime: "2026-08-04T09:14:28Z"
  resource:
    description: Managed limit
    projectID: 6fd7df4cf061469ab27d39d6c91b25a0
    resourceLimit: 50
    resourceName: servers
    serviceID: b8e6f8f3a9264fcaa5dc99e34aea1e31

Add `resource.ServiceRef` check in the filter for serviceDependency creation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

semver:major Breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Limits Controller

3 participants