Skip to content

Commit 233405d

Browse files
committed
WIP: Workaround for OpenStack API requirement for userIDs
1 parent 79bb495 commit 233405d

2 files changed

Lines changed: 67 additions & 6 deletions

File tree

internal/osclients/applicationcredential.go

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,24 @@ package osclients
1818

1919
import (
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

3034
type 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

3741
type 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

72133
type 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
}

internal/osclients/mock/applicationcredential.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)