Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🌱 use http get to download files from GitHub in clusterctl #9236

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 57 additions & 8 deletions cmd/clusterctl/client/repository/repository_github.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func (g *gitHubRepository) GetVersions(ctx context.Context) ([]string, error) {
return versions, nil
}

goProxyClient, err := g.getGoproxyClient()
goProxyClient, err := g.getGoproxyClient(ctx)
if err != nil {
return nil, errors.Wrap(err, "get versions client")
}
Expand Down Expand Up @@ -156,6 +156,27 @@ func (g *gitHubRepository) ComponentsPath() string {

// GetFile returns a file for a given provider version.
func (g *gitHubRepository) GetFile(ctx context.Context, version, path string) ([]byte, error) {
log := logf.Log

cacheID := fmt.Sprintf("%s/%s:%s:%s", g.owner, g.repository, version, path)
if content, ok := cacheFiles[cacheID]; ok {
return content, nil
}

// Try to get the file using http get.
// NOTE: this can be disabled by setting GORPOXY to `direct` or `off` (same knobs used for skipping goproxy requests).
if goProxyClient, _ := g.getGoproxyClient(ctx); goProxyClient != nil {
sbueringer marked this conversation as resolved.
Show resolved Hide resolved
files, err := g.httpGetFilesFromRelease(ctx, version, path)
if err != nil {
log.V(5).Info("error using httpGet to get file from GitHub releases, falling back to github client", "owner", g.owner, "repository", g.repository, "version", version, "path", path, "error", err)
} else {
cacheFiles[cacheID] = files
return files, nil
}
sbueringer marked this conversation as resolved.
Show resolved Hide resolved
}

// If the http get request failed (or it is disabled) falls back on using the GITHUB api to download the file

release, err := g.getReleaseByTag(ctx, version)
if err != nil {
if errors.Is(err, errNotFound) {
Expand All @@ -172,6 +193,7 @@ func (g *gitHubRepository) GetFile(ctx context.Context, version, path string) ([
return nil, errors.Wrapf(err, "failed to download files from GitHub release %s", version)
}

cacheFiles[cacheID] = files
return files, nil
}

Expand Down Expand Up @@ -259,7 +281,7 @@ func (g *gitHubRepository) getClient() *github.Client {
// getGoproxyClient returns a go proxy client.
// It returns nil, nil if the environment variable is set to `direct` or `off`
// to skip goproxy requests.
func (g *gitHubRepository) getGoproxyClient() (*goproxy.Client, error) {
func (g *gitHubRepository) getGoproxyClient(_ context.Context) (*goproxy.Client, error) {
if g.injectGoproxyClient != nil {
return g.injectGoproxyClient, nil
}
Expand Down Expand Up @@ -379,13 +401,41 @@ func (g *gitHubRepository) getReleaseByTag(ctx context.Context, tag string) (*gi
return release, nil
}

// downloadFilesFromRelease download a file from release.
func (g *gitHubRepository) downloadFilesFromRelease(ctx context.Context, release *github.RepositoryRelease, fileName string) ([]byte, error) {
cacheID := fmt.Sprintf("%s/%s:%s:%s", g.owner, g.repository, *release.TagName, fileName)
if content, ok := cacheFiles[cacheID]; ok {
return content, nil
// httpGetFilesFromRelease gets a file from github using http get.
func (g *gitHubRepository) httpGetFilesFromRelease(ctx context.Context, version, fileName string) ([]byte, error) {
downloadURL := fmt.Sprintf("https://github.com/%s/%s/releases/download/%s/%s", g.owner, g.repository, version, fileName)
var retryError error
var content []byte
_ = wait.PollUntilContextTimeout(ctx, retryableOperationInterval, retryableOperationTimeout, true, func(ctx context.Context) (bool, error) {
resp, err := http.Get(downloadURL) //nolint:gosec,noctx
if err != nil {
retryError = errors.Wrap(err, "error sending request")
return false, nil
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
retryError = errors.Errorf("error getting file, status code: %d", resp.StatusCode)
return false, nil
}

content, err = io.ReadAll(resp.Body)
if err != nil {
retryError = errors.Wrap(err, "error reading response body")
return false, nil
}

retryError = nil
return true, nil
})
if retryError != nil {
fabriziopandini marked this conversation as resolved.
Show resolved Hide resolved
return nil, retryError
}
return content, nil
}

// downloadFilesFromRelease download a file from release.
func (g *gitHubRepository) downloadFilesFromRelease(ctx context.Context, release *github.RepositoryRelease, fileName string) ([]byte, error) {
client := g.getClient()
absoluteFileName := filepath.Join(g.rootPath, fileName)

Expand Down Expand Up @@ -439,7 +489,6 @@ func (g *gitHubRepository) downloadFilesFromRelease(ctx context.Context, release
return nil, retryError
}

cacheFiles[cacheID] = content
return content, nil
}

Expand Down