Skip to content

Commit b7014e3

Browse files
authored
Merge pull request #11792 from MaxRink/clusterctl-gitlab-auth
✨Add support for clusterctl gitlab auth
2 parents dc17a9b + 7b1ee0f commit b7014e3

File tree

4 files changed

+51
-33
lines changed

4 files changed

+51
-33
lines changed

cmd/clusterctl/client/config/variables_client.go

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ package config
1919
const (
2020
// GitHubTokenVariable defines a variable hosting the GitHub access token.
2121
GitHubTokenVariable = "github-token"
22+
// GitLabAccessTokenVariable defines a variable hosting the GitLab access token. This can be used with Personal and Project access tokens.
23+
GitLabAccessTokenVariable = "gitlab-access-token"
2224
)
2325

2426
// VariablesClient has methods to work with environment variables and with variables defined in the clusterctl configuration file.

cmd/clusterctl/client/repository/client.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ func repositoryFactory(ctx context.Context, providerConfig config.Provider, conf
187187

188188
// if the url is a GitLab repository
189189
if strings.HasPrefix(rURL.Host, gitlabHostPrefix) && strings.HasPrefix(rURL.EscapedPath(), gitlabPackagesAPIPrefix) {
190-
repo, err := NewGitLabRepository(providerConfig, configVariablesClient)
190+
repo, err := NewGitLabRepository(ctx, providerConfig, configVariablesClient)
191191
if err != nil {
192192
return nil, errors.Wrap(err, "error creating the GitLab repository client")
193193
}

cmd/clusterctl/client/repository/repository_gitlab.go

+36-20
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"time"
2727

2828
"github.com/pkg/errors"
29+
"golang.org/x/oauth2"
2930

3031
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
3132
)
@@ -42,21 +43,21 @@ const (
4243
// We support GitLab repositories that use the generic packages feature to publish artifacts and versions.
4344
// Repositories must use versioned releases.
4445
type gitLabRepository struct {
45-
providerConfig config.Provider
46-
configVariablesClient config.VariablesClient
47-
httpClient *http.Client
48-
host string
49-
projectSlug string
50-
packageName string
51-
defaultVersion string
52-
rootPath string
53-
componentsPath string
46+
providerConfig config.Provider
47+
configVariablesClient config.VariablesClient
48+
authenticatingHTTPClient *http.Client
49+
host string
50+
projectSlug string
51+
packageName string
52+
defaultVersion string
53+
rootPath string
54+
componentsPath string
5455
}
5556

5657
var _ Repository = &gitLabRepository{}
5758

5859
// NewGitLabRepository returns a gitLabRepository implementation.
59-
func NewGitLabRepository(providerConfig config.Provider, configVariablesClient config.VariablesClient) (Repository, error) {
60+
func NewGitLabRepository(ctx context.Context, providerConfig config.Provider, configVariablesClient config.VariablesClient) (Repository, error) {
6061
if configVariablesClient == nil {
6162
return nil, errors.New("invalid arguments: configVariablesClient can't be nil")
6263
}
@@ -87,20 +88,31 @@ func NewGitLabRepository(providerConfig config.Provider, configVariablesClient c
8788
componentsPath := urlSplit[8]
8889

8990
repo := &gitLabRepository{
90-
providerConfig: providerConfig,
91-
configVariablesClient: configVariablesClient,
92-
httpClient: httpClient,
93-
host: host,
94-
projectSlug: projectSlug,
95-
packageName: packageName,
96-
defaultVersion: defaultVersion,
97-
rootPath: rootPath,
98-
componentsPath: componentsPath,
91+
providerConfig: providerConfig,
92+
configVariablesClient: configVariablesClient,
93+
authenticatingHTTPClient: httpClient,
94+
host: host,
95+
projectSlug: projectSlug,
96+
packageName: packageName,
97+
defaultVersion: defaultVersion,
98+
rootPath: rootPath,
99+
componentsPath: componentsPath,
100+
}
101+
if token, err := configVariablesClient.Get(config.GitLabAccessTokenVariable); err == nil {
102+
repo.setClientToken(ctx, token)
99103
}
100104

101105
return repo, nil
102106
}
103107

108+
// setClientToken sets authenticatingHTTPClient field of gitLabRepository struct.
109+
func (g *gitLabRepository) setClientToken(ctx context.Context, token string) {
110+
ts := oauth2.StaticTokenSource(
111+
&oauth2.Token{AccessToken: token, TokenType: "Bearer"},
112+
)
113+
g.authenticatingHTTPClient = oauth2.NewClient(ctx, ts)
114+
}
115+
104116
// Host returns host field of gitLabRepository struct.
105117
func (g *gitLabRepository) Host() string {
106118
return g.host
@@ -154,14 +166,18 @@ func (g *gitLabRepository) GetFile(ctx context.Context, version, path string) ([
154166
return nil, errors.Wrapf(err, "failed to get file %q with version %q from %q: failed to create request", path, version, url)
155167
}
156168

157-
response, err := g.httpClient.Do(request)
169+
response, err := g.authenticatingHTTPClient.Do(request)
158170
if err != nil {
159171
return nil, errors.Wrapf(err, "failed to get file %q with version %q from %q", path, version, url)
160172
}
161173

162174
defer response.Body.Close()
163175

164176
if response.StatusCode != http.StatusOK {
177+
// explicitly check for 401 and return a more specific error
178+
if response.StatusCode == http.StatusUnauthorized {
179+
return nil, errors.Errorf("failed to get file %q with version %q from %q: unauthorized access, please check your credentials", path, version, url)
180+
}
165181
return nil, errors.Errorf("failed to get file %q with version %q from %q, got %d", path, version, url, response.StatusCode)
166182
}
167183

cmd/clusterctl/client/repository/repository_gitlab_test.go

+12-12
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,15 @@ func Test_gitLabRepository_newGitLabRepository(t *testing.T) {
4949
variableClient: test.NewFakeVariableClient(),
5050
},
5151
want: &gitLabRepository{
52-
providerConfig: config.NewProvider("test", "https://gitlab.example.org/api/v4/projects/group%2Fproject/packages/generic/my-package/v1.0/path", clusterctlv1.CoreProviderType),
53-
configVariablesClient: test.NewFakeVariableClient(),
54-
httpClient: http.DefaultClient,
55-
host: "gitlab.example.org",
56-
projectSlug: "group%2Fproject",
57-
packageName: "my-package",
58-
defaultVersion: "v1.0",
59-
rootPath: ".",
60-
componentsPath: "path",
52+
providerConfig: config.NewProvider("test", "https://gitlab.example.org/api/v4/projects/group%2Fproject/packages/generic/my-package/v1.0/path", clusterctlv1.CoreProviderType),
53+
configVariablesClient: test.NewFakeVariableClient(),
54+
authenticatingHTTPClient: http.DefaultClient,
55+
host: "gitlab.example.org",
56+
projectSlug: "group%2Fproject",
57+
packageName: "my-package",
58+
defaultVersion: "v1.0",
59+
rootPath: ".",
60+
componentsPath: "path",
6161
},
6262
wantedErr: "",
6363
},
@@ -131,7 +131,7 @@ func Test_gitLabRepository_newGitLabRepository(t *testing.T) {
131131
g := NewWithT(t)
132132
resetCaches()
133133

134-
gitLab, err := NewGitLabRepository(tt.field.providerConfig, tt.field.variableClient)
134+
gitLab, err := NewGitLabRepository(context.Background(), tt.field.providerConfig, tt.field.variableClient)
135135
if tt.wantedErr != "" {
136136
g.Expect(err).To(MatchError(tt.wantedErr))
137137
return
@@ -193,8 +193,8 @@ func Test_gitLabRepository_getFile(t *testing.T) {
193193
g := NewWithT(t)
194194
resetCaches()
195195

196-
gitLab, err := NewGitLabRepository(providerConfig, configVariablesClient)
197-
gitLab.(*gitLabRepository).httpClient = client
196+
gitLab, err := NewGitLabRepository(context.Background(), providerConfig, configVariablesClient)
197+
gitLab.(*gitLabRepository).authenticatingHTTPClient = client
198198
g.Expect(err).ToNot(HaveOccurred())
199199

200200
got, err := gitLab.GetFile(context.Background(), tt.version, tt.fileName)

0 commit comments

Comments
 (0)