@@ -29,7 +29,6 @@ import (
2929 orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1"
3030 "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces"
3131 "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress"
32- "github.com/k-orc/openstack-resource-controller/v2/internal/logging"
3332 "github.com/k-orc/openstack-resource-controller/v2/internal/osclients"
3433 orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors"
3534)
@@ -70,30 +69,42 @@ func (actuator applicationcredentialActuator) ListOSResourcesForAdoption(ctx con
7069 return nil , false
7170 }
7271
73- // TODO(scaffolding) If you need to filter resources on fields that the List() function
74- // of gophercloud does not support, it's possible to perform client-side filtering.
75- // Check osclients.ResourceFilter
72+ var filters []osclients.ResourceFilter [osResourceT ]
73+
74+ // Add client-side filters
75+ if resourceSpec .Description != nil {
76+ filters = append (filters , func (f * applicationcredentials.ApplicationCredential ) bool {
77+ return f .Description == * resourceSpec .Description
78+ })
79+ }
7680
7781 listOpts := applicationcredentials.ListOpts {
78- Name : getResourceName (orcObject ),
79- Description : ptr .Deref (resourceSpec .Description , "" ),
82+ Name : getResourceName (orcObject ),
8083 }
8184
82- return actuator .osClient . ListApplicationCredentials (ctx , listOpts ), true
85+ return actuator .listOSResources (ctx , resourceSpec . UserID , filters , listOpts ), true
8386}
8487
8588func (actuator applicationcredentialActuator ) ListOSResourcesForImport (ctx context.Context , obj orcObjectPT , filter filterT ) (iter.Seq2 [* osResourceT , error ], progress.ReconcileStatus ) {
86- // TODO(scaffolding) If you need to filter resources on fields that the List() function
87- // of gophercloud does not support, it's possible to perform client-side filtering.
88- // Check osclients.ResourceFilter
89+ var filters []osclients.ResourceFilter [osResourceT ]
90+
91+ // Add client-side filters
92+ if filter .Description != nil {
93+ filters = append (filters , func (f * applicationcredentials.ApplicationCredential ) bool {
94+ return f .Description == * filter .Description
95+ })
96+ }
8997
9098 listOpts := applicationcredentials.ListOpts {
91- Name : string (ptr .Deref (filter .Name , "" )),
92- Description : string (ptr .Deref (filter .Description , "" )),
93- // TODO(scaffolding): Add more import filters
99+ Name : string (ptr .Deref (filter .Name , "" )),
94100 }
95101
96- return actuator .osClient .ListApplicationCredentials (ctx , listOpts ), nil
102+ return actuator .listOSResources (ctx , filter .UserID , filters , listOpts ), nil
103+ }
104+
105+ func (actuator applicationcredentialActuator ) listOSResources (ctx context.Context , userID string , filters []osclients.ResourceFilter [osResourceT ], listOpts applicationcredentials.ListOptsBuilder ) iter.Seq2 [* applicationcredentials.ApplicationCredential , error ] {
106+ applicationCredentials := actuator .osClient .ListApplicationCredentials (ctx , userID , listOpts )
107+ return osclients .Filter (applicationCredentials , filters ... )
97108}
98109
99110func (actuator applicationcredentialActuator ) CreateResource (ctx context.Context , obj orcObjectPT ) (* osResourceT , progress.ReconcileStatus ) {
@@ -104,100 +115,71 @@ func (actuator applicationcredentialActuator) CreateResource(ctx context.Context
104115 return nil , progress .WrapError (
105116 orcerrors .Terminal (orcv1alpha1 .ConditionReasonInvalidConfiguration , "Creation requested, but spec.resource is not set" ))
106117 }
107- createOpts := applicationcredentials.CreateOpts {
108- Name : getResourceName (obj ),
109- Description : ptr .Deref (resource .Description , "" ),
110- // TODO(scaffolding): Add more fields
111- }
112-
113- osResource , err := actuator .osClient .CreateApplicationCredential (ctx , createOpts )
114- if err != nil {
115- // We should require the spec to be updated before retrying a create which returned a conflict
116- if ! orcerrors .IsRetryable (err ) {
117- err = orcerrors .Terminal (orcv1alpha1 .ConditionReasonInvalidConfiguration , "invalid configuration creating resource: " + err .Error (), err )
118- }
119- return nil , progress .WrapError (err )
120- }
121118
122- return osResource , nil
123- }
119+ roleList := make ([]applicationcredentials.Role , len (resource .Roles ))
120+ for i := range resource .Roles {
121+ roleSpec := & resource .Roles [i ]
122+ role := & roleList [i ]
124123
125- func ( actuator applicationcredentialActuator ) DeleteResource ( ctx context. Context , _ orcObjectPT , resource * osResourceT ) progress. ReconcileStatus {
126- return progress . WrapError ( actuator . osClient . DeleteApplicationCredential ( ctx , resource .ID ))
127- }
124+ if roleSpec . ID != nil {
125+ role . ID = * roleSpec .ID
126+ }
128127
129- func (actuator applicationcredentialActuator ) updateResource (ctx context.Context , obj orcObjectPT , osResource * osResourceT ) progress.ReconcileStatus {
130- log := ctrl .LoggerFrom (ctx )
131- resource := obj .Spec .Resource
132- if resource == nil {
133- // Should have been caught by API validation
134- return progress .WrapError (
135- orcerrors .Terminal (orcv1alpha1 .ConditionReasonInvalidConfiguration , "Update requested, but spec.resource is not set" ))
128+ if roleSpec .Name != nil {
129+ role .Name = string (* roleSpec .Name )
130+ }
136131 }
137132
138- updateOpts := applicationcredentials.UpdateOpts {}
133+ accessRuleList := make ([]applicationcredentials.AccessRule , len (resource .AccessRules ))
134+ for i := range resource .AccessRules {
135+ accessRuleSpec := & resource .AccessRules [i ]
136+ accessRule := & accessRuleList [i ]
139137
140- handleNameUpdate (& updateOpts , obj , osResource )
141- handleDescriptionUpdate (& updateOpts , resource , osResource )
138+ if accessRuleSpec .Path != nil {
139+ accessRule .Path = * accessRuleSpec .Path
140+ }
142141
143- // TODO(scaffolding): add handler for all fields supporting mutability
142+ if accessRuleSpec .Service != nil {
143+ accessRule .Service = * accessRuleSpec .Service
144+ }
144145
145- needsUpdate , err := needsUpdate (updateOpts )
146- if err != nil {
147- return progress .WrapError (
148- orcerrors .Terminal (orcv1alpha1 .ConditionReasonInvalidConfiguration , "invalid configuration updating resource: " + err .Error (), err ))
149- }
150- if ! needsUpdate {
151- log .V (logging .Debug ).Info ("No changes" )
152- return nil
146+ if accessRuleSpec .Method != nil {
147+ accessRule .Method = string (* accessRuleSpec .Method )
148+ }
153149 }
154150
155- _ , err = actuator .osClient .UpdateApplicationCredential (ctx , osResource .ID , updateOpts )
156-
157- // We should require the spec to be updated before retrying an update which returned a conflict
158- if orcerrors .IsConflict (err ) {
159- err = orcerrors .Terminal (orcv1alpha1 .ConditionReasonInvalidConfiguration , "invalid configuration updating resource: " + err .Error (), err )
151+ createOpts := applicationcredentials.CreateOpts {
152+ Name : getResourceName (obj ),
153+ Description : ptr .Deref (resource .Description , "" ),
154+ Unrestricted : ptr .Deref (resource .Unrestricted , false ),
155+ Secret : ptr .Deref (resource .Secret , "" ),
156+ Roles : roleList ,
157+ AccessRules : accessRuleList ,
160158 }
161159
162- if err != nil {
163- return progress . WrapError ( err )
160+ if resource . ExpiresAt != nil {
161+ createOpts . ExpiresAt = & resource . ExpiresAt . Time
164162 }
165163
166- return progress .NeedsRefresh ()
167- }
168-
169- func needsUpdate (updateOpts applicationcredentials.UpdateOpts ) (bool , error ) {
170- updateOptsMap , err := updateOpts .ToApplicationCredentialUpdateMap ()
164+ osResource , err := actuator .osClient .CreateApplicationCredential (ctx , resource .UserID , createOpts )
171165 if err != nil {
172- return false , err
173- }
174-
175- updateMap , ok := updateOptsMap ["application_credentials" ].(map [string ]any )
176- if ! ok {
177- updateMap = make (map [string ]any )
166+ // We should require the spec to be updated before retrying a create which returned a conflict
167+ if ! orcerrors .IsRetryable (err ) {
168+ err = orcerrors .Terminal (orcv1alpha1 .ConditionReasonInvalidConfiguration , "invalid configuration creating resource: " + err .Error (), err )
169+ }
170+ return nil , progress .WrapError (err )
178171 }
179172
180- return len (updateMap ) > 0 , nil
181- }
182-
183- func handleNameUpdate (updateOpts * applicationcredentials.UpdateOpts , obj orcObjectPT , osResource * osResourceT ) {
184- name := getResourceName (obj )
185- if osResource .Name != name {
186- updateOpts .Name = & name
187- }
173+ return osResource , nil
188174}
189175
190- func handleDescriptionUpdate (updateOpts * applicationcredentials.UpdateOpts , resource * resourceSpecT , osResource * osResourceT ) {
191- description := ptr .Deref (resource .Description , "" )
192- if osResource .Description != description {
193- updateOpts .Description = & description
194- }
176+ func (actuator applicationcredentialActuator ) DeleteResource (ctx context.Context , orcObject orcObjectPT , resource * osResourceT ) progress.ReconcileStatus {
177+ return progress .WrapError (actuator .osClient .DeleteApplicationCredential (ctx , orcObject .Spec .Resource .UserID , resource .ID ))
195178}
196179
197180func (actuator applicationcredentialActuator ) GetResourceReconcilers (ctx context.Context , orcObject orcObjectPT , osResource * osResourceT , controller interfaces.ResourceController ) ([]resourceReconciler , progress.ReconcileStatus ) {
198- return []resourceReconciler {
199- actuator .updateResource ,
200- }, nil
181+ // ApplicationCredentials are immutable - no update reconcilers needed
182+ return []resourceReconciler {}, nil
201183}
202184
203185type applicationcredentialHelperFactory struct {}
0 commit comments