Implement same_tag versioning mode
This commit is contained in:
@ -1,31 +1,35 @@
|
||||
package registry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
l "hulthe.net/lookbuilding/internal/pkg/logging"
|
||||
"hulthe.net/lookbuilding/internal/pkg/semver"
|
||||
|
||||
"github.com/heroku/docker-registry-client/registry"
|
||||
"github.com/opencontainers/go-digest"
|
||||
d "github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type tagListReq struct {
|
||||
repository string
|
||||
responder chan<- tagListResp
|
||||
responder chan<- tagListResp
|
||||
}
|
||||
|
||||
type tagListResp struct {
|
||||
Data []Tag
|
||||
Data []Tag
|
||||
Error error
|
||||
}
|
||||
|
||||
type digestReq struct {
|
||||
repository string
|
||||
tag string
|
||||
responder chan<- digestResp
|
||||
tag string
|
||||
responder chan<- digestResp
|
||||
}
|
||||
|
||||
type digestResp struct {
|
||||
Data digest.Digest
|
||||
Data d.Digest
|
||||
Error error
|
||||
}
|
||||
|
||||
@ -33,23 +37,68 @@ type repoCache struct {
|
||||
Tags []Tag
|
||||
|
||||
// Map tags to digests
|
||||
Digests map[string]digest.Digest
|
||||
Digests map[string]d.Digest
|
||||
}
|
||||
|
||||
type cache struct {
|
||||
TagListReq chan<- tagListReq
|
||||
DigestReq chan<- digestReq
|
||||
DigestReq chan<- digestReq
|
||||
}
|
||||
|
||||
func newCache(registry registry.Registry) cache {
|
||||
tagListReq := make(chan tagListReq)
|
||||
digestReq := make(chan digestReq)
|
||||
cache := cache{
|
||||
tagListReq,
|
||||
digestReq,
|
||||
}
|
||||
|
||||
store := map[string]repoCache{}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case req := <-digestReq:
|
||||
repo, isPresent := store[req.repository]
|
||||
if !isPresent {
|
||||
req.responder <- digestResp{Error: errors.Errorf(
|
||||
`repo "%s" not present in cache, can't fetch digest'`, req.repository,
|
||||
)}
|
||||
}
|
||||
|
||||
digest, isPresent := repo.Digests[req.tag]
|
||||
if isPresent {
|
||||
req.responder <- digestResp{Data: digest}
|
||||
} else {
|
||||
url := fmt.Sprintf("%s/v2/%s/manifests/%s", registry.URL, req.repository, req.tag)
|
||||
l.Logger.Infof("registry.manifest.head url=%s repository=%s reference=%s", url, req.repository, req.tag)
|
||||
|
||||
httpReq, _ := http.NewRequest("HEAD", url, nil)
|
||||
httpReq.Header.Add("Accept", "application/vnd.docker.distribution.manifest.v2+json")
|
||||
resp, err := registry.Client.Do(httpReq)
|
||||
if resp != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
if err != nil {
|
||||
req.responder <- digestResp{Error: errors.Wrapf(
|
||||
err, "failed to get digest for repo=%s tag=%s", req.repository, req.tag,
|
||||
)}
|
||||
}
|
||||
digest, err := d.Parse(resp.Header.Get("Docker-Content-Digest"))
|
||||
|
||||
/*
|
||||
digest, err := registry.ManifestDigest(req.repository, req.tag)
|
||||
if err != nil {
|
||||
req.responder <- digestResp{Error: errors.Wrapf(
|
||||
err, `failed to get digest for repo=%s tag=%s`, req.repository, req.tag,
|
||||
)}
|
||||
}
|
||||
*/
|
||||
|
||||
repo.Digests[req.tag] = digest
|
||||
req.responder <- digestResp{Data: digest}
|
||||
}
|
||||
|
||||
case req := <-tagListReq:
|
||||
repo, isPresent := store[req.repository]
|
||||
|
||||
@ -71,50 +120,26 @@ func newCache(registry registry.Registry) cache {
|
||||
var tags []Tag
|
||||
for _, tagName := range tagNames {
|
||||
tags = append(tags, Tag{
|
||||
Name: tagName,
|
||||
SemVer: semver.ParseTagAsSemVer(tagName),
|
||||
Name: tagName,
|
||||
SemVer: semver.ParseTagAsSemVer(tagName),
|
||||
repository: req.repository,
|
||||
cache: cache,
|
||||
})
|
||||
}
|
||||
|
||||
// store result in cache
|
||||
store[req.repository] = repoCache{
|
||||
Tags: tags,
|
||||
Digests: map[string]digest.Digest{},
|
||||
Digests: map[string]d.Digest{},
|
||||
}
|
||||
|
||||
req.responder <- tagListResp{
|
||||
Data: tags,
|
||||
}
|
||||
}
|
||||
|
||||
case req := <-digestReq:
|
||||
repo, isPresent := store[req.repository]
|
||||
if !isPresent {
|
||||
req.responder <- digestResp{Error: errors.Errorf(
|
||||
`repo "%s" not present in cache, can't fetch digest'`, req.repository,
|
||||
)}
|
||||
}
|
||||
|
||||
digest, isPresent := repo.Digests[req.tag]
|
||||
if isPresent {
|
||||
req.responder <- digestResp{Data: digest}
|
||||
} else {
|
||||
digest, err := registry.ManifestDigest(req.repository, req.tag)
|
||||
if err != nil {
|
||||
req.responder <- digestResp{Error: errors.Wrapf(
|
||||
err, `failed to get digest for repo=%s tag=%s`, req.repository, req.tag,
|
||||
)}
|
||||
}
|
||||
|
||||
repo.Digests[req.tag] = digest
|
||||
req.responder <- digestResp{Data: digest}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return cache {
|
||||
tagListReq,
|
||||
digestReq,
|
||||
}
|
||||
}
|
||||
return cache
|
||||
}
|
||||
|
||||
@ -11,10 +11,10 @@ import (
|
||||
)
|
||||
|
||||
type Tag struct {
|
||||
Name string
|
||||
SemVer *semver.Tag
|
||||
Name string
|
||||
SemVer *semver.Tag
|
||||
repository string
|
||||
cache cache
|
||||
cache cache
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
@ -23,7 +23,7 @@ type Client struct {
|
||||
|
||||
func (tag Tag) GetDigest() (digest.Digest, error) {
|
||||
responseCh := make(chan digestResp)
|
||||
tag.cache.DigestReq <- digestReq{ tag.repository, tag.Name, responseCh }
|
||||
tag.cache.DigestReq <- digestReq{tag.repository, tag.Name, responseCh}
|
||||
resp := <-responseCh
|
||||
return resp.Data, resp.Error
|
||||
}
|
||||
@ -34,9 +34,8 @@ func (client Client) GetRepoTags(maybeOwner *string, repository string) ([]Tag,
|
||||
}
|
||||
|
||||
responseCh := make(chan tagListResp)
|
||||
client.cache.TagListReq <- tagListReq { repository, responseCh }
|
||||
client.cache.TagListReq <- tagListReq{repository, responseCh}
|
||||
resp := <-responseCh
|
||||
|
||||
return resp.Data, resp.Error
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user