Skip to content

Commit

Permalink
refactor(docker): Reducing complexity of main loop
Browse files Browse the repository at this point in the history
Closes None

Signed-off-by: Vincent Boutour <[email protected]>
  • Loading branch information
ViBiOh committed May 29, 2021
1 parent e90bde1 commit 19b4f69
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 51 deletions.
4 changes: 2 additions & 2 deletions pkg/model/ketchup.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,10 @@ func (a KetchupByPriority) Swap(i, j int) { a[i], a[j] = a[j], a[i] }

// Release is when new version is out
type Release struct {
Repository Repository `json:"repository"`
Pattern string `json:"pattern"`
Version semver.Version `json:"version"`
URL string `json:"url"`
Repository Repository `json:"repository"`
Version semver.Version `json:"version"`
}

// NewRelease creates a new version from its objects
Expand Down
107 changes: 58 additions & 49 deletions pkg/provider/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"flag"
"fmt"
"io"
"net/http"
"net/url"
"runtime"
Expand Down Expand Up @@ -66,7 +67,7 @@ func (a app) LatestVersions(repository string, patterns []string) (map[string]se
return nil, fmt.Errorf("unable to prepare pattern matching: %s", err)
}

registry, repository, bearerToken, err := a.getImageDetails(ctx, repository)
registry, repository, auth, err := a.getImageDetails(ctx, repository)
if err != nil {
return nil, fmt.Errorf("unable to compute image details: %s", err)
}
Expand All @@ -76,39 +77,19 @@ func (a app) LatestVersions(repository string, patterns []string) (map[string]se
for len(url) != 0 {
req := request.New().Get(url)

if registry == registryURL {
req.Header("Authorization", fmt.Sprintf("Bearer %s", bearerToken))
if len(auth) != 0 {
req.Header("Authorization", auth)
}

resp, err := req.Send(ctx, nil)
if err != nil {
return nil, fmt.Errorf("unable to fetch tags: %s", err)
}

done := make(chan struct{})
versionsStream := make(chan interface{}, runtime.NumCPU())

go func() {
defer close(done)

for tag := range versionsStream {
tagVersion, err := semver.Parse(*(tag.(*string)))
if err != nil {
continue
}

model.CheckPatternsMatching(versions, compiledPatterns, tagVersion)
}
}()

if err := httpjson.Stream(resp.Body, func() interface{} {
return new(string)
}, versionsStream, "tags"); err != nil {
return nil, fmt.Errorf("unable to read tags: %s", err)
if err := browseRegistryTagsList(resp.Body, versions, compiledPatterns); err != nil {
return nil, err
}

<-done

url = getNextURL(resp.Header, registry)
}

Expand All @@ -125,12 +106,62 @@ func (a app) getImageDetails(ctx context.Context, repository string) (string, st
repository = fmt.Sprintf("library/%s", repository)
}

token, err := a.login(ctx, repository)
bearerToken, err := a.login(ctx, repository)
if err != nil {
return "", "", "", fmt.Errorf("unable to authenticate to docker hub: %s", err)
}

return registryURL, repository, token, nil
return registryURL, repository, fmt.Sprintf("Bearer %s", bearerToken), nil
}

func (a app) login(ctx context.Context, repository string) (string, error) {
values := url.Values{}
values.Set("grant_type", "password")
values.Set("service", "registry.docker.io")
values.Set("client_id", "ketchup")
values.Set("scope", fmt.Sprintf("repository:%s:pull", repository))
values.Set("username", a.username)
values.Set("password", a.password)

resp, err := request.New().Post(authURL).Form(ctx, values)
if err != nil {
return "", fmt.Errorf("unable to authenticate to `%s`: %s", authURL, err)
}

var authContent authResponse
if err := httpjson.Read(resp, &authContent); err != nil {
return "", fmt.Errorf("unable to read auth token: %s", err)
}

return authContent.AccessToken, nil
}

func browseRegistryTagsList(body io.ReadCloser, versions map[string]semver.Version, patterns map[string]semver.Pattern) error {
done := make(chan struct{})
versionsStream := make(chan interface{}, runtime.NumCPU())

go func() {
defer close(done)

for tag := range versionsStream {
tagVersion, err := semver.Parse(*(tag.(*string)))
if err != nil {
continue
}

model.CheckPatternsMatching(versions, patterns, tagVersion)
}
}()

if err := httpjson.Stream(body, func() interface{} {
return new(string)
}, versionsStream, "tags"); err != nil {
return fmt.Errorf("unable to read tags: %s", err)
}

<-done

return nil
}

func getNextURL(headers http.Header, registry string) string {
Expand All @@ -155,25 +186,3 @@ func getNextURL(headers http.Header, registry string) string {

return ""
}

func (a app) login(ctx context.Context, repository string) (string, error) {
values := url.Values{}
values.Set("grant_type", "password")
values.Set("service", "registry.docker.io")
values.Set("client_id", "ketchup")
values.Set("scope", fmt.Sprintf("repository:%s:pull", repository))
values.Set("username", a.username)
values.Set("password", a.password)

resp, err := request.New().Post(authURL).Form(ctx, values)
if err != nil {
return "", fmt.Errorf("unable to authenticate to `%s`: %s", authURL, err)
}

var authContent authResponse
if err := httpjson.Read(resp, &authContent); err != nil {
return "", fmt.Errorf("unable to read auth token: %s", err)
}

return authContent.AccessToken, nil
}

0 comments on commit 19b4f69

Please sign in to comment.