@@ -18,20 +18,24 @@ package osclients
1818
1919import (
2020 "context"
21+ "errors"
2122 "fmt"
2223 "iter"
2324
25+ tokens3 "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens"
26+
2427 "github.com/gophercloud/gophercloud/v2"
2528 "github.com/gophercloud/gophercloud/v2/openstack"
2629 "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/applicationcredentials"
30+ "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/users"
2731 "github.com/gophercloud/utils/v2/openstack/clientconfig"
2832)
2933
3034type ApplicationCredentialClient interface {
3135 ListApplicationCredentials (ctx context.Context , userID string , listOpts applicationcredentials.ListOptsBuilder ) iter.Seq2 [* applicationcredentials.ApplicationCredential , error ]
3236 CreateApplicationCredential (ctx context.Context , userID string , opts applicationcredentials.CreateOptsBuilder ) (* applicationcredentials.ApplicationCredential , error )
3337 DeleteApplicationCredential (ctx context.Context , userID string , resourceID string ) error
34- GetApplicationCredential (ctx context.Context , userID string , resourceID string ) (* applicationcredentials.ApplicationCredential , error )
38+ GetApplicationCredential (ctx context.Context , resourceID string ) (* applicationcredentials.ApplicationCredential , error )
3539}
3640
3741type applicationcredentialClient struct { client * gophercloud.ServiceClient }
@@ -65,8 +69,65 @@ func (c applicationcredentialClient) DeleteApplicationCredential(ctx context.Con
6569 return applicationcredentials .Delete (ctx , c .client , userID , resourceID ).ExtractErr ()
6670}
6771
68- func (c applicationcredentialClient ) GetApplicationCredential (ctx context.Context , userID string , resourceID string ) (* applicationcredentials.ApplicationCredential , error ) {
69- return applicationcredentials .Get (ctx , c .client , userID , resourceID ).Extract ()
72+ func (c applicationcredentialClient ) GetApplicationCredential (ctx context.Context , resourceID string ) (* applicationcredentials.ApplicationCredential , error ) {
73+ // The unique ID of an application credential is not enough to query it from OpenStack
74+ // OpenStack actually also requires a unique user ID.
75+ // We can not provide the user ID here, as the function signatures of ORC interfaces
76+ // expect us to return an OpenStack resource based on a single string.
77+
78+ // To work around this, we first query ApplicationCredentials for the currently
79+ // authenticated user which ORC is connected as. If that fails, we iterate over
80+ // all users we have access to and query their ApplicationCredentials.
81+
82+ // Currently authenticated user
83+ userID , err := GetAuthenticatedUserID (c .client .ProviderClient )
84+ if err == nil {
85+ appCred , appCredErr := applicationcredentials .Get (ctx , c .client , userID , resourceID ).Extract ()
86+
87+ if appCred != nil {
88+ return appCred , appCredErr
89+ }
90+ }
91+
92+ // If not found in currently authenticated user, try iterating over all users
93+ userPager := users .List (c .client , nil )
94+ userIterator := func (yield func (* users.User , error ) bool ) {
95+ _ = userPager .EachPage (ctx , yieldPage (users .ExtractUsers , yield ))
96+ }
97+
98+ for user , userErr := range userIterator {
99+ if userErr != nil {
100+ continue
101+ }
102+
103+ appCred , appCredErr := applicationcredentials .Get (ctx , c .client , user .ID , resourceID ).Extract ()
104+
105+ if appCred != nil {
106+ return appCred , appCredErr
107+ }
108+ }
109+
110+ return nil , gophercloud.ErrResourceNotFound {
111+ Name : resourceID ,
112+ ResourceType : "ApplicationCredential" ,
113+ }
114+ }
115+
116+ func GetAuthenticatedUserID (providerClient * gophercloud.ProviderClient ) (string , error ) {
117+ r := providerClient .GetAuthResult ()
118+ if r == nil {
119+ return "" , errors .New ("no AuthResult available" )
120+ }
121+ switch r := r .(type ) {
122+ case tokens3.CreateResult :
123+ u , err := r .ExtractUser ()
124+ if err != nil {
125+ return "" , err
126+ }
127+ return u .ID , nil
128+ default :
129+ return "" , errors .New ("wrong AuthResult version" )
130+ }
70131}
71132
72133type applicationcredentialErrorClient struct { error }
@@ -90,6 +151,6 @@ func (e applicationcredentialErrorClient) DeleteApplicationCredential(_ context.
90151 return e .error
91152}
92153
93- func (e applicationcredentialErrorClient ) GetApplicationCredential (_ context.Context , _ string , _ string ) (* applicationcredentials.ApplicationCredential , error ) {
154+ func (e applicationcredentialErrorClient ) GetApplicationCredential (_ context.Context , _ string ) (* applicationcredentials.ApplicationCredential , error ) {
94155 return nil , e .error
95156}
0 commit comments