Skip to content

Implement ApplicationCredentials#671

Open
gndrmnn wants to merge 10 commits intok-orc:mainfrom
gndrmnn:implement_appcred
Open

Implement ApplicationCredentials#671
gndrmnn wants to merge 10 commits intok-orc:mainfrom
gndrmnn:implement_appcred

Conversation

@gndrmnn
Copy link
Contributor

@gndrmnn gndrmnn commented Feb 4, 2026

Adds ApplicationCredential support

Due to the nature of the OpenStack API, we have to work around addressing application credentials not only by their unique ID, but also a UserRef.

Closes #670

@github-actions github-actions bot added the semver:major Breaking change label Feb 4, 2026
@github-actions github-actions bot removed the semver:major Breaking change label Feb 5, 2026
@github-actions
Copy link

github-actions bot commented Feb 5, 2026

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

@github-actions
Copy link

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

@github-actions
Copy link

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

@github-actions
Copy link

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

@github-actions
Copy link

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

@github-actions github-actions bot added the semver:major Breaking change label Feb 24, 2026
@gndrmnn gndrmnn force-pushed the implement_appcred branch 7 times, most recently from b05fcb5 to ba588f7 Compare February 26, 2026 09:58
Copy link
Collaborator

@mandre mandre left a comment

Choose a reason for hiding this comment

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

This is a great start! There's a bit more work to do around dependency management and handling of the secret, but hopefully nothing blocking.

It's annoying that the openstack API doesn't allow retrieving an app cred directly via its UUID, forcing us to pass it a user ID as well. I don't think there's a magic solution for it, and we'll have to document the tradeoff we've made, and explain how managing app creds for other user might increase the load on OpenStack API.

Again, really good work.

var filters []osclients.ResourceFilter[osResourceT]

// Add client-side filters
if resourceSpec.Description != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Looks like the keystone API allows filtering app creds via description but this is missing from gophercloud.

Would you like to contribute this to gophercloud?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I could address this at some point. But I would like to get this PR merged in the foreseeable future. Would you mind, if we open a new issue for this instead?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Clearly not something I expect you to fix in gophercloud before this PR lands :)
It was just an observation for something I noticed during review.

@gndrmnn gndrmnn force-pushed the implement_appcred branch 2 times, most recently from ac1c351 to b991cc7 Compare March 5, 2026 11:52
gndrmnn added 4 commits March 17, 2026 16:02
$ go run ./cmd/scaffold-controller -interactive=false \
    -kind=ApplicationCredential \
    -gophercloud-client=NewIdentityV3 \
    -gophercloud-module=github.com/gophercloud/gophercloud/v2/openstack/identity/v3/applicationcredentials \
    -gophercloud-type=ApplicationCredential \
    -openstack-json-object=application_credentials \
    -required-create-dependency=User \
    -import-dependency=User

On-behalf-of: SAP nils.gondermann@sap.com
Register with the resource generator

On-behalf-of: SAP nils.gondermann@sap.com
Add the OpenStack client to scope

On-behalf-of: SAP nils.gondermann@sap.com
Register the controller

On-behalf-of: SAP nils.gondermann@sap.com
@gndrmnn gndrmnn force-pushed the implement_appcred branch 14 times, most recently from 3337480 to 3b6f422 Compare March 23, 2026 13:46
gndrmnn added 4 commits March 23, 2026 15:22
On-behalf-of: SAP nils.gondermann@sap.com
On-behalf-of: SAP nils.gondermann@sap.com
On-behalf-of: SAP nils.gondermann@sap.com
@gndrmnn gndrmnn force-pushed the implement_appcred branch from 3b6f422 to 9379fb5 Compare March 23, 2026 14:37
@gndrmnn gndrmnn requested a review from mandre March 23, 2026 14:40
gndrmnn added 2 commits March 24, 2026 11:22
On-behalf-of: SAP nils.gondermann@sap.com
On-behalf-of: SAP nils.gondermann@sap.com
@gndrmnn gndrmnn force-pushed the implement_appcred branch from 9379fb5 to 123212f Compare March 24, 2026 10:22
@gndrmnn gndrmnn marked this pull request as ready for review March 24, 2026 10:23
Copy link
Collaborator

@mandre mandre left a comment

Choose a reason for hiding this comment

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

A lot of changes since I last looked at it, I see there's now proper dependency handling. I've left a few comments, some that really need addressing before we merge, some less important. I also see you chose to make passing the password required, I think that's a fair first implementation, that we can change later.

unrestricted: true
secret:
secretRef: kubernetes-secret
roleRef:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
roleRef:
roleRefs:


// secret used to authenticate against the API
// +required
Secret ApplicationCredentialSecretSpec `json:"secret,omitempty,omitzero"`
Copy link
Collaborator

Choose a reason for hiding this comment

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

If there's no extra parameters associated with the secret, it's probably not necessary to wrap into a struct, is it?

Suggested change
Secret ApplicationCredentialSecretSpec `json:"secret,omitempty,omitzero"`
SecretRef KubernetesNameRef `json:"secretRef,omitempty"`

// +optional
Name *string `json:"name,omitempty"`

// id is the ID of an role
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit

Suggested change
// id is the ID of an role
// id is the ID of a role

unrestricted: true
secret:
secretRef: "application-credential-secret"
roleRef:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should be plurals. I suspect your test succeeds because you're getting default roles.

Suggested change
roleRef:
roleRefs:

kind: ApplicationCredential
name: applicationcredential-create-full
ref: applicationcredential
- apiVersion: openstack.k-orc.cloud/v1alpha1
Copy link
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 simply store the UserID in the resource status 🤔

This way, we could drop the hack that goes over all users.

return user.Status.ID, rs
}

func (actuator applicationcredentialActuator) ResolveUserIDDependency(ctx context.Context, orcObject orcObjectPT) (*string, progress.ReconcileStatus) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here, this function appears to not be needed?

// Programming error
return nil, progress.WrapError(fmt.Errorf("service %s was not returned by GetDependencies", serviceName))
}
accessRule.Service = *service.Status.ID
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should be the service type, and not id, right?


var secretData []byte

secret, secretReconcileStatus := dependency.FetchDependency(
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should move this dependency retrieval at the top of the function, where the other dependencies are retrieved.

func (actuator applicationcredentialActuator) DeleteResource(ctx context.Context, orcObject orcObjectPT, resource *osResourceT) progress.ReconcileStatus {
var reconcileStatus progress.ReconcileStatus

userID, userDepRS := actuator.ResolveUserIDDependency(ctx, orcObject)
Copy link
Collaborator

Choose a reason for hiding this comment

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

See my comment about storing the user ID in the resource status. This would make it easier to retrieve here.


services := make([]string, len(resource.AccessRules))
for i := range resource.AccessRules {
services[i] = string(*resource.AccessRules[i].ServiceRef)
Copy link
Collaborator

Choose a reason for hiding this comment

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

ServiceRef is optional, so we would need to check for nil, and only add service refs that are set.

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.

Keystone Application Credentials Controller

2 participants