From 77e437e187ef088b5f2f3746bd16fe487b87bf54 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Thu, 16 Feb 2017 01:18:01 -0800 Subject: [PATCH 1/6] image/descriptor: Change validate argument from a walker to a reader Make it clear that this only needs the CAS-oriented Get and not the full walker. Signed-off-by: W. Trevor King --- image/descriptor.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/image/descriptor.go b/image/descriptor.go index f19642c..11238b0 100644 --- a/image/descriptor.go +++ b/image/descriptor.go @@ -93,7 +93,7 @@ func findDescriptor(w walker, name string) (*descriptor, error) { } } -func (d *descriptor) validate(w walker, mts []string) error { +func (d *descriptor) validate(get reader, mts []string) error { var found bool for _, mt := range mts { if d.MediaType == mt { @@ -105,7 +105,7 @@ func (d *descriptor) validate(w walker, mts []string) error { return fmt.Errorf("invalid descriptor MediaType %q", d.MediaType) } - rc, err := w.Get(*d) + rc, err := get.Get(*d) if err != nil { return err } From a52db4ac438ffa3ecbd2f212481943f6083d8cc1 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Thu, 16 Feb 2017 01:25:17 -0800 Subject: [PATCH 2/6] image/config: Port findConfig to reader Avoid locally implementing Get. Signed-off-by: W. Trevor King --- image/config.go | 45 +++++++++++++++++---------------------------- 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/image/config.go b/image/config.go index fba599c..ce0d5da 100644 --- a/image/config.go +++ b/image/config.go @@ -18,10 +18,7 @@ import ( "bytes" "encoding/json" "fmt" - "io" "io/ioutil" - "os" - "path/filepath" "strconv" "strings" @@ -33,36 +30,28 @@ import ( type config v1.Image -func findConfig(w walker, d *descriptor) (*config, error) { - var c config - cpath := filepath.Join("blobs", d.algo(), d.hash()) - - switch err := w.walk(func(path string, info os.FileInfo, r io.Reader) error { - if info.IsDir() || filepath.Clean(path) != cpath { - return nil - } - buf, err := ioutil.ReadAll(r) - if err != nil { - return errors.Wrapf(err, "%s: error reading config", path) - } +func findConfig(get reader, d *descriptor) (*config, error) { + reader, err := get.Get(*d) + if err != nil { + return nil, err + } + defer reader.Close() - if err := schema.MediaTypeImageConfig.Validate(bytes.NewReader(buf)); err != nil { - return errors.Wrapf(err, "%s: config validation failed", path) - } + buf, err := ioutil.ReadAll(reader) + if err != nil { + return nil, errors.Wrapf(err, "%s: error reading config", d.Digest) + } - if err := json.Unmarshal(buf, &c); err != nil { - return err - } + if err := schema.MediaTypeImageConfig.Validate(bytes.NewReader(buf)); err != nil { + return nil, errors.Wrapf(err, "%s: config validation failed", d.Digest) + } - return errEOW - }); err { - case nil: - return nil, fmt.Errorf("%s: config not found", cpath) - case errEOW: - return &c, nil - default: + var c config + if err := json.Unmarshal(buf, &c); err != nil { return nil, err } + + return &c, nil } func (c *config) runtimeSpec(rootfs string) (*specs.Spec, error) { From 2eed561478b0835b50ea381a206b7f1683b96a6e Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Thu, 16 Feb 2017 01:30:01 -0800 Subject: [PATCH 3/6] image/manifest: Port findManifest to reader Avoid locally implementing Get. Signed-off-by: W. Trevor King --- image/manifest.go | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/image/manifest.go b/image/manifest.go index 39d4395..2d83a7d 100644 --- a/image/manifest.go +++ b/image/manifest.go @@ -37,37 +37,27 @@ type manifest struct { Layers []descriptor `json:"layers"` } -func findManifest(w walker, d *descriptor) (*manifest, error) { - var m manifest - mpath := filepath.Join("blobs", d.algo(), d.hash()) - - switch err := w.walk(func(path string, info os.FileInfo, r io.Reader) error { - if info.IsDir() || filepath.Clean(path) != mpath { - return nil - } - - buf, err := ioutil.ReadAll(r) - if err != nil { - return errors.Wrapf(err, "%s: error reading manifest", path) - } +func findManifest(get reader, d *descriptor) (*manifest, error) { + reader, err := get.Get(*d) + if err != nil { + return nil, err + } + defer reader.Close() - if err := schema.MediaTypeManifest.Validate(bytes.NewReader(buf)); err != nil { - return errors.Wrapf(err, "%s: manifest validation failed", path) - } + buf, err := ioutil.ReadAll(reader) + if err != nil { + return nil, errors.Wrapf(err, "%s: error reading manifest", d.Digest) + } - if err := json.Unmarshal(buf, &m); err != nil { - return err - } + if err := schema.MediaTypeManifest.Validate(bytes.NewReader(buf)); err != nil { + return nil, errors.Wrapf(err, "%s: manifest validation failed", d.Digest) + } - return errEOW - }); err { - case nil: - return nil, fmt.Errorf("%s: manifest not found", mpath) - case errEOW: - return &m, nil - default: + var m manifest + if err := json.Unmarshal(buf, &m); err != nil { return nil, err } + return &m, nil } func (m *manifest) validate(w walker) error { From 5c2289c3d46882890b6f3c237336fe36f88f9f20 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Thu, 16 Feb 2017 01:32:30 -0800 Subject: [PATCH 4/6] image/manifest: Port validate to reader Both of these calls are to descriptor.validate(), which only needs a reader. Signed-off-by: W. Trevor King --- image/manifest.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/image/manifest.go b/image/manifest.go index 2d83a7d..e4c0b9e 100644 --- a/image/manifest.go +++ b/image/manifest.go @@ -60,8 +60,8 @@ func findManifest(get reader, d *descriptor) (*manifest, error) { return &m, nil } -func (m *manifest) validate(w walker) error { - if err := m.Config.validate(w, []string{v1.MediaTypeImageConfig}); err != nil { +func (m *manifest) validate(get reader) error { + if err := m.Config.validate(get, []string{v1.MediaTypeImageConfig}); err != nil { return errors.Wrap(err, "config validation failed") } @@ -73,7 +73,7 @@ func (m *manifest) validate(w walker) error { } for _, d := range m.Layers { - if err := d.validate(w, validLayerMediaTypes); err != nil { + if err := d.validate(get, validLayerMediaTypes); err != nil { return errors.Wrap(err, "layer validation failed") } } From 1de4774191b7ef2d911f42bd5cf83d68e67cb2dd Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Thu, 16 Feb 2017 01:35:11 -0800 Subject: [PATCH 5/6] image/manifest: Port unpack to reader This is only getting CAS blobs, so we only need a reader. And there's no need to locally implement Get. Signed-off-by: W. Trevor King --- image/manifest.go | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/image/manifest.go b/image/manifest.go index e4c0b9e..00368d0 100644 --- a/image/manifest.go +++ b/image/manifest.go @@ -81,7 +81,7 @@ func (m *manifest) validate(get reader) error { return nil } -func (m *manifest) unpack(w walker, dest string) (retErr error) { +func (m *manifest) unpack(get reader, dest string) (retErr error) { // error out if the dest directory is not empty s, err := ioutil.ReadDir(dest) if err != nil && !os.IsNotExist(err) { @@ -100,26 +100,18 @@ func (m *manifest) unpack(w walker, dest string) (retErr error) { } }() for _, d := range m.Layers { - switch err := w.walk(func(path string, info os.FileInfo, r io.Reader) error { - if info.IsDir() { - return nil - } - - dd, err := filepath.Rel(filepath.Join("blobs", d.algo()), filepath.Clean(path)) - if err != nil || d.hash() != dd { - return nil - } + reader, err := get.Get(d) + if err != nil { + return err + } + defer reader.Close() - if err := unpackLayer(dest, r); err != nil { - return errors.Wrap(err, "error extracting layer") - } + if err = unpackLayer(dest, reader); err != nil { + return errors.Wrap(err, "error extracting layer") + } - return errEOW - }); err { - case nil: - return fmt.Errorf("%s: layer not found", dest) - case errEOW: - default: + err = reader.Close() + if err != nil { return err } } From 27c98e07fc67a95dd052471bb5a8801fa47ccb9d Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Thu, 16 Feb 2017 01:39:50 -0800 Subject: [PATCH 6/6] image/manifest_test: Port from a walker to a reader Now that we've ported manifest.unpack over to reader, we can replace the more-complicated walker implementation (which also provides for mutable-ref access) with the more-basic reader (which only interacts with CAS blobs). Signed-off-by: W. Trevor King --- image/manifest_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/image/manifest_test.go b/image/manifest_test.go index b75ac0a..1fa3df0 100644 --- a/image/manifest_test.go +++ b/image/manifest_test.go @@ -111,7 +111,8 @@ func TestUnpackLayer(t *testing.T) { Digest: digester.Digest().String(), }}, } - err = testManifest.unpack(newPathWalker(tmp1), filepath.Join(tmp1, "rootfs")) + get := &layoutReader{root: tmp1} + err = testManifest.unpack(get, filepath.Join(tmp1, "rootfs")) if err != nil { t.Fatal(err) } @@ -171,7 +172,8 @@ func TestUnpackLayerRemovePartialyUnpackedFile(t *testing.T) { Digest: digester.Digest().String(), }}, } - err = testManifest.unpack(newPathWalker(tmp1), filepath.Join(tmp1, "rootfs")) + get := &layoutReader{root: tmp1} + err = testManifest.unpack(get, filepath.Join(tmp1, "rootfs")) if err != nil && !strings.Contains(err.Error(), "duplicate entry for") { t.Fatal(err) }