From 9295e2e6189c87ad8e840e8e4052efc82138fe37 Mon Sep 17 00:00:00 2001 From: Eric Ace <24485843+aceeric@users.noreply.github.com> Date: Fri, 17 Jan 2025 15:18:46 -0500 Subject: [PATCH] experiment --- cmd/imgpull/main.go | 2 +- pkg/imgpull/dopull.go | 28 +++++++++++++++++++--------- pkg/imgpull/puller.go | 35 ++++++++++++++++++++++++++++------- pkg/imgpull/puller_test.go | 2 +- 4 files changed, 49 insertions(+), 18 deletions(-) diff --git a/cmd/imgpull/main.go b/cmd/imgpull/main.go index d742241..ea7f2b9 100644 --- a/cmd/imgpull/main.go +++ b/cmd/imgpull/main.go @@ -36,6 +36,6 @@ func pullTar(p imgpull.Puller, tarFile string) { if err := p.PullTar(tarFile); err != nil { fmt.Println(err) } else { - fmt.Printf("image %q saved to %q in %s\n", p.ImgRef.Url(), tarFile, time.Since(start)) + fmt.Printf("image %q saved to %q in %s\n", p.GetUrl(), tarFile, time.Since(start)) } } diff --git a/pkg/imgpull/dopull.go b/pkg/imgpull/dopull.go index 97da8e6..97261b4 100644 --- a/pkg/imgpull/dopull.go +++ b/pkg/imgpull/dopull.go @@ -22,7 +22,7 @@ var unauth = []int{http.StatusUnauthorized, http.StatusForbidden} // PullTar pulls an image tarball from a registry based on the configuration // options in the receiver and writes it to the path/file name specified in the // 'dest' arg. -func (p *Puller) PullTar(dest string) error { +func (p *puller) PullTar(dest string) error { if dest == "" { return fmt.Errorf("no destination specified for pull of %q", p.Opts.Url) } @@ -41,7 +41,7 @@ func (p *Puller) PullTar(dest string) error { // PullManifest pulls an image manifest or an image list manifest based on the value // of the 'mpt' arg. -func (p *Puller) PullManifest(mpt ManifestPullType) (ManifestHolder, error) { +func (p *puller) PullManifest(mpt ManifestPullType) (ManifestHolder, error) { if err := p.connect(); err != nil { return ManifestHolder{}, err } @@ -82,7 +82,7 @@ func (p *Puller) PullManifest(mpt ManifestPullType) (ManifestHolder, error) { } // PullBlobs pulls the blobs for an image, writing them into 'blobDir'. -func (p *Puller) PullBlobs(mh ManifestHolder, blobDir string) error { +func (p *puller) PullBlobs(mh ManifestHolder, blobDir string) error { if err := p.connect(); err != nil { return err } @@ -99,7 +99,7 @@ func (p *Puller) PullBlobs(mh ManifestHolder, blobDir string) error { // 'ManifestDescriptor' returned to the caller contains the image digest, // media type and manifest size, as provided by the upstream distribution // server. -func (p *Puller) HeadManifest() (types.ManifestDescriptor, error) { +func (p *puller) HeadManifest() (types.ManifestDescriptor, error) { if err := p.connect(); err != nil { return types.ManifestDescriptor{}, err } @@ -112,7 +112,7 @@ func (p *Puller) HeadManifest() (types.ManifestDescriptor, error) { // the registry. If no image list manifest is available then an image manifest // will be provided by the registry if available. Whatever the registry provides // is returned in a 'ManifestHolder' which holds all four supported manifest types. -func (p *Puller) GetManifest() (ManifestHolder, error) { +func (p *puller) GetManifest() (ManifestHolder, error) { if err := p.connect(); err != nil { return ManifestHolder{}, err } @@ -124,6 +124,16 @@ func (p *Puller) GetManifest() (ManifestHolder, error) { return newManifestHolder(mr.MediaType, mr.ManifestBytes, mr.ManifestDigest, rc.ImgRef.Url()) } +// GetUrl returns the image ref from the receiver +func (p *puller) GetUrl() string { + return p.ImgRef.Url() +} + +// GetOpts returns puller options +func (p *puller) GetOpts() PullerOpts { + return p.Opts +} + // pull pulls the image specified in the receiver, saving blobs to the passed 'blobDir'. // An 'imageTarball' struct is returned that describes the pulled image. The directory // specfied by 'blobDir' will be populated with: @@ -132,7 +142,7 @@ func (p *Puller) GetManifest() (ManifestHolder, error) { // 2. The layer blobs. // // All blobs are saved into this directory with filenames consisting of 64-character digests. -func (p *Puller) pull(blobDir string) (tar.ImageTarball, error) { +func (p *puller) pull(blobDir string) (tar.ImageTarball, error) { if err := p.connect(); err != nil { return tar.ImageTarball{}, err } @@ -176,7 +186,7 @@ func (p *Puller) pull(blobDir string) (tar.ImageTarball, error) { // // If the function has already been called on the receiver, it immediately // returns taking no action. -func (p *Puller) connect() error { +func (p *puller) connect() error { if p.Connected { return nil } @@ -204,7 +214,7 @@ func (p *Puller) connect() error { // struct so that it is available to be used for all subsequent API calls to the // distribution server. For example if 'bearer' then the token received from the // remote registry will be added to the receiver. -func (p *Puller) authenticate(auth []string) error { +func (p *puller) authenticate(auth []string) error { rc := p.regCliFrom() for _, hdr := range auth { if strings.HasPrefix(strings.ToLower(hdr), "bearer") { @@ -237,7 +247,7 @@ func (p *Puller) authenticate(auth []string) error { // headers, then the Connect function must previously have been called on the receiver so // that the auth struct in the receiver is initialized by virtue of that call. The auth // struct is copied into the returned regClient struct which is used to set auth headers. -func (p *Puller) regCliFrom() methods.RegClient { +func (p *puller) regCliFrom() methods.RegClient { rc := methods.RegClient{ ImgRef: p.ImgRef, Client: p.Client, diff --git a/pkg/imgpull/puller.go b/pkg/imgpull/puller.go index 856784e..ed0491b 100644 --- a/pkg/imgpull/puller.go +++ b/pkg/imgpull/puller.go @@ -4,12 +4,33 @@ import ( "net/http" "github.com/aceeric/imgpull/internal/imgref" + "github.com/aceeric/imgpull/internal/methods" + "github.com/aceeric/imgpull/internal/tar" "github.com/aceeric/imgpull/pkg/imgpull/types" ) -// Puller is the top-level abstraction. It carries everything that is needed to pull +type Puller interface { + PullTar(dest string) error + PullManifest(mpt ManifestPullType) (ManifestHolder, error) + PullBlobs(mh ManifestHolder, blobDir string) error + HeadManifest() (types.ManifestDescriptor, error) + GetManifest() (ManifestHolder, error) + GetUrl() string + GetOpts() PullerOpts + pull(blobDir string) (tar.ImageTarball, error) + authHdr() (string, string) + connect() error + authenticate(auth []string) error + regCliFrom() methods.RegClient +} + +func NewPullerZ() Puller { + return &puller{} +} + +// puller is the top-level abstraction. It carries everything that is needed to pull // an OCI image from an upstream OCI distribution server. -type Puller struct { +type puller struct { // Opts defines all the configurable behaviors of the puller. Opts PullerOpts // ImgRef is the parsed image url, e.g.: 'docker.io/hello-world:latest' @@ -56,20 +77,20 @@ func NewPuller(url string, opts ...PullOpt) (Puller, error) { // not inferred - and cannot be inferred - by the function. func NewPullerWith(o PullerOpts) (Puller, error) { if err := o.validate(); err != nil { - return Puller{}, err + return &puller{}, err } if ir, err := imgref.NewImageRef(o.Url, o.Scheme, o.Namespace); err != nil { - return Puller{}, err + return &puller{}, err } else { c := &http.Client{} if cfg, err := o.configureTls(); err != nil { - return Puller{}, err + return &puller{}, err } else if cfg != nil { c.Transport = &http.Transport{ TLSClientConfig: cfg, } } - return Puller{ + return &puller{ ImgRef: ir, Client: c, Opts: o, @@ -79,7 +100,7 @@ func NewPullerWith(o PullerOpts) (Puller, error) { // authHdr returns a key/value pair to set an auth header based on whether // the receiver is configured for bearer or basic auth. -func (p *Puller) authHdr() (string, string) { +func (p *puller) authHdr() (string, string) { if p.Token != (types.BearerToken{}) { return "Authorization", "Bearer " + p.Token.Token } else if p.Opts.Username != "" { diff --git a/pkg/imgpull/puller_test.go b/pkg/imgpull/puller_test.go index 23e08fe..2a199a5 100644 --- a/pkg/imgpull/puller_test.go +++ b/pkg/imgpull/puller_test.go @@ -29,7 +29,7 @@ func TestPullerOptfunc(t *testing.T) { if err != nil { t.Fail() } - if p.Opts.Url != url || p.Opts.Scheme != scheme || p.Opts.OStype != ostype || p.Opts.ArchType != archtype { + if p.GetOpts().Url != url || p.GetOpts().Scheme != scheme || p.GetOpts().OStype != ostype || p.GetOpts().ArchType != archtype { t.Fail() } }