152 lines
2.9 KiB
Go
152 lines
2.9 KiB
Go
|
package controller
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"context"
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"net/http"
|
||
|
"net/url"
|
||
|
|
||
|
"nf-repo/internal/interfaces"
|
||
|
"nf-repo/internal/model"
|
||
|
"nf-repo/internal/opt"
|
||
|
|
||
|
"github.com/google/go-containerregistry/pkg/name"
|
||
|
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||
|
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||
|
)
|
||
|
|
||
|
func PullRepo(ctx context.Context, repo string, tag string, proxy string,
|
||
|
mh interfaces.ManifestHandler, bh interfaces.BlobHandler,
|
||
|
) (*v1.Manifest, error) {
|
||
|
if repo == "" || tag == "" {
|
||
|
return nil, fmt.Errorf("invalid repo or tag")
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
err error
|
||
|
transport = &http.Transport{}
|
||
|
puller *remote.Puller
|
||
|
tn name.Tag
|
||
|
des *remote.Descriptor
|
||
|
img v1.Image
|
||
|
manifest *v1.Manifest
|
||
|
bs []byte
|
||
|
mhash model.Hash
|
||
|
target = fmt.Sprintf("%s:%s", repo, tag)
|
||
|
)
|
||
|
|
||
|
if opt.Proxy != nil {
|
||
|
transport.Proxy = http.ProxyURL(opt.Proxy)
|
||
|
}
|
||
|
|
||
|
if proxy != "" {
|
||
|
var pu *url.URL
|
||
|
if pu, err = url.Parse(proxy); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
transport.Proxy = http.ProxyURL(pu)
|
||
|
}
|
||
|
|
||
|
if puller, err = remote.NewPuller(
|
||
|
remote.WithTransport(transport),
|
||
|
); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if tn, err = name.NewTag(target); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if des, err = puller.Get(ctx, tn); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if img, err = des.Image(); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if manifest, err = img.Manifest(); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
total := model.ManifestCountSize(manifest)
|
||
|
size := 0
|
||
|
_ = total
|
||
|
|
||
|
var (
|
||
|
tly v1.Layer
|
||
|
tdigest v1.Hash
|
||
|
treader io.ReadCloser
|
||
|
)
|
||
|
|
||
|
if tly, err = img.LayerByDigest(manifest.Config.Digest); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if tdigest, err = tly.Digest(); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if treader, err = tly.Uncompressed(); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
defer treader.Close()
|
||
|
|
||
|
if err = bh.Put(
|
||
|
ctx,
|
||
|
target,
|
||
|
model.Hash{Algorithm: tdigest.Algorithm, Hex: tdigest.Hex},
|
||
|
treader,
|
||
|
); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
size = size + int(manifest.Config.Size)
|
||
|
|
||
|
if bs, err = json.Marshal(manifest); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if mhash, _, err = model.SHA256(bytes.NewReader(bs)); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
for idx := range manifest.Layers {
|
||
|
var (
|
||
|
reader io.ReadCloser
|
||
|
lyHash v1.Hash
|
||
|
ly v1.Layer
|
||
|
)
|
||
|
|
||
|
lyHash = manifest.Layers[idx].Digest
|
||
|
|
||
|
if ly, err = img.LayerByDigest(manifest.Layers[idx].Digest); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if reader, err = ly.Compressed(); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
defer reader.Close()
|
||
|
|
||
|
if err = bh.Put(ctx, repo, model.Hash{Algorithm: lyHash.Algorithm, Hex: lyHash.Hex}, reader); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
size = size + int(manifest.Layers[idx].Size)
|
||
|
}
|
||
|
|
||
|
if re := mh.Put(ctx, repo, tag, mhash.String(), &model.RepoSimpleManifest{
|
||
|
ContentType: string(manifest.MediaType),
|
||
|
Blob: bs,
|
||
|
}); re != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return manifest, nil
|
||
|
}
|