Skip to content

Commit

Permalink
image: Refactor to use cas/ref engines instead of walkers
Browse files Browse the repository at this point in the history
The validation/unpacking code doesn't really care what the reference
and CAS implemenations are.  And the new generic interfaces in
image/refs and image/cas will scale better as we add new backends than
the walker interface.

The old tar/directory distinction between image and imageLayout is
gone.  The new CAS/refs engines don't support directory backends yet
(I plan on adding them once the engine framework lands), but the new
framework will handle tar/directory/... detection inside
layout.NewEngine (and possibly inside a new (cas|refs).NewEngine when
we grow engine types that aren't based on image-layout).

I'd prefer casLayout and refsLayout for the imported packages, but
Stephen doesn't want camelCase for package names [1].

[1]: #159 (comment)

Signed-off-by: W. Trevor King <wking@tremily.us>
  • Loading branch information
wking committed Sep 2, 2016
1 parent 2d55583 commit f2dc0e2
Show file tree
Hide file tree
Showing 12 changed files with 157 additions and 367 deletions.
3 changes: 1 addition & 2 deletions cmd/oci-image-tool/autodetect.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (

// supported autodetection types
const (
typeImageLayout = "imageLayout"
typeImage = "image"
typeManifest = "manifest"
typeManifestList = "manifestList"
Expand All @@ -43,7 +42,7 @@ func autodetect(path string) (string, error) {
}

if fi.IsDir() {
return typeImageLayout, nil
return typeImage, nil
}

f, err := os.Open(path)
Expand Down
9 changes: 4 additions & 5 deletions cmd/oci-image-tool/create_runtime_bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ import (

"github.com/opencontainers/image-spec/image"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)

// supported bundle types
var bundleTypes = []string{
typeImageLayout,
typeImage,
}

Expand Down Expand Up @@ -82,6 +82,8 @@ func (v *bundleCmd) Run(cmd *cobra.Command, args []string) {
os.Exit(1)
}

ctx := context.Background()

if _, err := os.Stat(args[1]); os.IsNotExist(err) {
v.stderr.Printf("destination path %s does not exist", args[1])
os.Exit(1)
Expand All @@ -98,11 +100,8 @@ func (v *bundleCmd) Run(cmd *cobra.Command, args []string) {

var err error
switch v.typ {
case typeImageLayout:
err = image.CreateRuntimeBundleLayout(args[0], args[1], v.ref, v.root)

case typeImage:
err = image.CreateRuntimeBundle(args[0], args[1], v.ref, v.root)
err = image.CreateRuntimeBundle(ctx, args[0], args[1], v.ref, v.root)
}

if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ oci-image-tool-create-runtime-bundle \- Create an OCI image runtime bundle
A directory representing the root filesystem of the container in the OCI runtime bundle. It is strongly recommended to keep the default value. (default "rootfs")

**--type**
Type of the file to unpack. If unset, oci-image-tool will try to auto-detect the type. One of "imageLayout,image"
Type of the file to unpack. If unset, oci-image-tool will try to auto-detect the type. One of "image"

# EXAMPLES
```
Expand Down
2 changes: 1 addition & 1 deletion cmd/oci-image-tool/man/oci-image-tool-unpack.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ oci-image-tool-unpack \- Unpack an image or image source layout
The ref pointing to the manifest to be unpacked. This must be present in the "refs" subdirectory of the image. (default "v1.0")

**--type**
Type of the file to unpack. If unset, oci-image-tool will try to auto-detect the type. One of "imageLayout,image"
Type of the file to unpack. If unset, oci-image-tool will try to auto-detect the type. One of "image"

# EXAMPLES
```
Expand Down
6 changes: 3 additions & 3 deletions cmd/oci-image-tool/man/oci-image-tool-validate.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ oci-image-tool-validate \- Validate one or more image files
Print usage statement

**--ref**
The ref pointing to the manifest to be validated. This must be present in the "refs" subdirectory of the image. Only applicable if type is image or imageLayout. (default "v1.0")
The ref pointing to the manifest to be validated. This must be present in the "refs" subdirectory of the image. Only applicable if type is image. (default "v1.0")

**--type**
Type of the file to validate. If unset, oci-image-tool will try to auto-detect the type. One of "imageLayout,image,manifest,manifestList,config"
Type of the file to validate. If unset, oci-image-tool will try to auto-detect the type. One of "image,manifest,manifestList,config"

# EXAMPLES
```
$ skopeo copy docker://busybox oci:busybox-oci
$ oci-image-tool validate --type imageLayout --ref latest busybox-oci
$ oci-image-tool validate --type image --ref latest busybox-oci
busybox-oci: OK
```

Expand Down
13 changes: 6 additions & 7 deletions cmd/oci-image-tool/unpack.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ import (

"github.com/opencontainers/image-spec/image"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)

// supported unpack types
var unpackTypes = []string{
typeImageLayout,
typeImage,
}

Expand All @@ -45,8 +45,8 @@ func newUnpackCmd(stdout, stderr *log.Logger) *cobra.Command {

cmd := &cobra.Command{
Use: "unpack [src] [dest]",
Short: "Unpack an image or image source layout",
Long: `Unpack the OCI image .tar file or OCI image layout directory present at [src] to the destination directory [dest].`,
Short: "Unpack an image",
Long: `Unpack the OCI image present at [src] to the destination directory [dest].`,
Run: v.Run,
}

Expand Down Expand Up @@ -75,6 +75,8 @@ func (v *unpackCmd) Run(cmd *cobra.Command, args []string) {
os.Exit(1)
}

ctx := context.Background()

if v.typ == "" {
typ, err := autodetect(args[0])
if err != nil {
Expand All @@ -86,11 +88,8 @@ func (v *unpackCmd) Run(cmd *cobra.Command, args []string) {

var err error
switch v.typ {
case typeImageLayout:
err = image.UnpackLayout(args[0], args[1], v.ref)

case typeImage:
err = image.Unpack(args[0], args[1], v.ref)
err = image.Unpack(ctx, args[0], args[1], v.ref)
}

if err != nil {
Expand Down
14 changes: 7 additions & 7 deletions cmd/oci-image-tool/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ import (
"github.com/opencontainers/image-spec/schema"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)

// supported validation types
var validateTypes = []string{
typeImageLayout,
typeImage,
typeManifest,
typeManifestList,
Expand Down Expand Up @@ -64,7 +64,7 @@ func newValidateCmd(stdout, stderr *log.Logger) *cobra.Command {

cmd.Flags().StringVar(
&v.ref, "ref", "v1.0",
`The ref pointing to the manifest to be validated. This must be present in the "refs" subdirectory of the image. Only applicable if type is image or imageLayout.`,
`The ref pointing to the manifest to be validated. This must be present in the "refs" subdirectory of the image. Only applicable if type is image.`,
)

return cmd
Expand All @@ -79,9 +79,11 @@ func (v *validateCmd) Run(cmd *cobra.Command, args []string) {
os.Exit(1)
}

ctx := context.Background()

var exitcode int
for _, arg := range args {
err := v.validatePath(arg)
err := v.validatePath(ctx, arg)

if err == nil {
v.stdout.Printf("%s: OK", arg)
Expand Down Expand Up @@ -111,7 +113,7 @@ func (v *validateCmd) Run(cmd *cobra.Command, args []string) {
os.Exit(exitcode)
}

func (v *validateCmd) validatePath(name string) error {
func (v *validateCmd) validatePath(ctx context.Context, name string) error {
var err error
typ := v.typ

Expand All @@ -122,10 +124,8 @@ func (v *validateCmd) validatePath(name string) error {
}

switch typ {
case typeImageLayout:
return image.ValidateLayout(name, v.ref)
case typeImage:
return image.Validate(name, v.ref)
return image.Validate(ctx, name, v.ref)
}

f, err := os.Open(name)
Expand Down
60 changes: 26 additions & 34 deletions image/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"

"github.com/opencontainers/image-spec/image/cas"
"github.com/opencontainers/image-spec/schema"
"github.com/opencontainers/runtime-spec/specs-go"
imageSpecs "github.com/opencontainers/image-spec/specs-go"
runtimeSpecs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"golang.org/x/net/context"
)

type cfg struct {
Expand All @@ -49,43 +49,35 @@ type config struct {
Config cfg `json:"config"`
}

func findConfig(w walker, d *descriptor) (*config, error) {
var c config
cpath := filepath.Join("blobs", d.algo(), d.hash())
func findConfig(ctx context.Context, engine cas.Engine, descriptor *imageSpecs.Descriptor) (*config, error) {
reader, err := engine.Get(ctx, descriptor.Digest)
if err != nil {
return nil, err
}

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)
}
buf, err := ioutil.ReadAll(reader)
if err != nil {
return nil, errors.Wrapf(err, "%s: error reading manifest", descriptor.Digest)
}

if err := schema.MediaTypeImageConfig.Validate(bytes.NewReader(buf)); err != nil {
return errors.Wrapf(err, "%s: config validation failed", path)
}
if err := schema.MediaTypeImageConfig.Validate(bytes.NewReader(buf)); err != nil {
return nil, errors.Wrapf(err, "%s: config validation failed", descriptor.Digest)
}

if err := json.Unmarshal(buf, &c); err != nil {
return err
}
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) {
func (c *config) runtimeSpec(rootfs string) (*runtimeSpecs.Spec, error) {

This comment has been minimized.

Copy link
@runcom

runcom Sep 7, 2016

Member

This whole runtimeSpec is ugly and should/could be replaced by using the library in ocitools probably - it's so easy to get outdated and it's easy to forget something (I already made a PR which was fixing how this was generated)

This comment has been minimized.

Copy link
@wking

wking via email Sep 7, 2016

Author Contributor

This comment has been minimized.

Copy link
@runcom

runcom Sep 7, 2016

Member

nd this whole “image-spec even needing to generate config.json” is
ugly, and should be replaced by stand-alone tooling to localize a
received config [1] ;).

that's my dream as well :) it's awkward to have this config.json gen here...

if c.OS != "linux" {
return nil, fmt.Errorf("%s: unsupported OS", c.OS)
}

var s specs.Spec
var s runtimeSpecs.Spec
s.Version = "0.5.0"
// we should at least apply the default spec, otherwise this is totally useless
s.Process.Terminal = true
Expand Down Expand Up @@ -128,12 +120,12 @@ func (c *config) runtimeSpec(rootfs string) (*specs.Spec, error) {
swap := uint64(c.Config.MemorySwap)
shares := uint64(c.Config.CPUShares)

s.Linux.Resources = &specs.Resources{
CPU: &specs.CPU{
s.Linux.Resources = &runtimeSpecs.Resources{
CPU: &runtimeSpecs.CPU{
Shares: &shares,
},

Memory: &specs.Memory{
Memory: &runtimeSpecs.Memory{
Limit: &mem,
Reservation: &mem,
Swap: &swap,
Expand All @@ -143,7 +135,7 @@ func (c *config) runtimeSpec(rootfs string) (*specs.Spec, error) {
for vol := range c.Config.Volumes {
s.Mounts = append(
s.Mounts,
specs.Mount{
runtimeSpecs.Mount{
Destination: vol,
Type: "bind",
Options: []string{"rbind"},
Expand Down
Loading

0 comments on commit f2dc0e2

Please sign in to comment.