Skip to content

Commit 7bd8bcf

Browse files
committed
image: Refactor to use cas/ref engines instead of walkers
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. This replaces the simpler interface from image/reader.go with something more robust. 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). Also replace the old methods like: func (d *descriptor) validateContent(r io.Reader) error with functions like: validateContent(ctx context.Context, descriptor *specs.Descriptor, r io.Reader) error to avoid local types that duplicate the image-spec types. This saves an extra instantiation for folks who want to validate (or whatever) a specs.Descriptor they have obtained elsewhere. I'd prefer casLayout and refsLayout for the imported packages, but Stephen doesn't want camelCase for package names [1]. [1]: opencontainers/image-spec#159 (comment) Signed-off-by: W. Trevor King <[email protected]>
1 parent 5c748c9 commit 7bd8bcf

File tree

15 files changed

+341
-735
lines changed

15 files changed

+341
-735
lines changed

cmd/oci-create-runtime-bundle/main.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
specs "github.com/opencontainers/image-spec/specs-go"
2424
"github.com/opencontainers/image-tools/image"
2525
"github.com/spf13/cobra"
26+
"golang.org/x/net/context"
2627
)
2728

2829
// gitCommit will be the hash that the binary was built from
@@ -31,7 +32,6 @@ var gitCommit = ""
3132

3233
// supported bundle types
3334
var bundleTypes = []string{
34-
image.TypeImageLayout,
3535
image.TypeImage,
3636
}
3737

@@ -109,6 +109,8 @@ func (v *bundleCmd) Run(cmd *cobra.Command, args []string) {
109109
os.Exit(1)
110110
}
111111

112+
ctx := context.Background()
113+
112114
if _, err := os.Stat(args[1]); os.IsNotExist(err) {
113115
v.stderr.Printf("destination path %s does not exist", args[1])
114116
os.Exit(1)
@@ -125,11 +127,8 @@ func (v *bundleCmd) Run(cmd *cobra.Command, args []string) {
125127

126128
var err error
127129
switch v.typ {
128-
case image.TypeImageLayout:
129-
err = image.CreateRuntimeBundleLayout(args[0], args[1], v.ref, v.root)
130-
131130
case image.TypeImage:
132-
err = image.CreateRuntimeBundle(args[0], args[1], v.ref, v.root)
131+
err = image.CreateRuntimeBundle(ctx, args[0], args[1], v.ref, v.root)
133132
}
134133

135134
if err != nil {

cmd/oci-create-runtime-bundle/oci-create-runtime-bundle.1.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ runtime-spec-compatible `dest/config.json`.
2424
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")
2525

2626
**--type**
27-
Type of the file to unpack. If unset, oci-create-runtime-bundle will try to auto-detect the type. One of "imageLayout,image"
27+
Type of the file to unpack. If unset, oci-create-runtime-bundle will try to auto-detect the type. One of "image"
2828

2929
# EXAMPLES
3030
```

cmd/oci-image-validate/main.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/opencontainers/image-tools/image"
2626
"github.com/pkg/errors"
2727
"github.com/spf13/cobra"
28+
"golang.org/x/net/context"
2829
)
2930

3031
// gitCommit will be the hash that the binary was built from
@@ -33,7 +34,6 @@ var gitCommit = ""
3334

3435
// supported validation types
3536
var validateTypes = []string{
36-
image.TypeImageLayout,
3737
image.TypeImage,
3838
image.TypeManifest,
3939
image.TypeManifestList,
@@ -81,7 +81,7 @@ func newValidateCmd(stdout, stderr *log.Logger) *cobra.Command {
8181

8282
cmd.Flags().StringSliceVar(
8383
&v.refs, "ref", nil,
84-
`A set of refs pointing to the manifests to be validated. Each reference must be present in the "refs" subdirectory of the image. Only applicable if type is image or imageLayout.`,
84+
`A set of refs pointing to the manifests to be validated. Each reference must be present in the "refs" subdirectory of the image. Only applicable if type is image.`,
8585
)
8686

8787
cmd.Flags().BoolVar(
@@ -107,9 +107,11 @@ func (v *validateCmd) Run(cmd *cobra.Command, args []string) {
107107
os.Exit(1)
108108
}
109109

110+
ctx := context.Background()
111+
110112
var exitcode int
111113
for _, arg := range args {
112-
err := v.validatePath(arg)
114+
err := v.validatePath(ctx, arg)
113115

114116
if err == nil {
115117
v.stdout.Printf("%s: OK", arg)
@@ -139,7 +141,7 @@ func (v *validateCmd) Run(cmd *cobra.Command, args []string) {
139141
os.Exit(exitcode)
140142
}
141143

142-
func (v *validateCmd) validatePath(name string) error {
144+
func (v *validateCmd) validatePath(ctx context.Context, name string) error {
143145
var (
144146
err error
145147
typ = v.typ
@@ -152,10 +154,8 @@ func (v *validateCmd) validatePath(name string) error {
152154
}
153155

154156
switch typ {
155-
case image.TypeImageLayout:
156-
return image.ValidateLayout(name, v.refs, v.stdout)
157157
case image.TypeImage:
158-
return image.Validate(name, v.refs, v.stdout)
158+
return image.Validate(ctx, name, v.refs, v.stdout)
159159
}
160160

161161
f, err := os.Open(name)

cmd/oci-image-validate/oci-image-validate.1.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ oci-image-validate \- Validate one or more image files
2020
Can be specified multiple times to validate multiple references.
2121
`NAME` must be present in the `refs` subdirectory of the image.
2222
Defaults to `v1.0`.
23-
Only applicable if type is image or imageLayout.
23+
Only applicable if type is image.
2424

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

2828
# EXAMPLES
2929
```
3030
$ skopeo copy docker://busybox oci:busybox-oci
31-
$ oci-image-validate --type imageLayout --ref latest busybox-oci
31+
$ oci-image-validate --type image --ref latest busybox-oci
3232
busybox-oci: OK
3333
```
3434

cmd/oci-unpack/main.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
specs "github.com/opencontainers/image-spec/specs-go"
2424
"github.com/opencontainers/image-tools/image"
2525
"github.com/spf13/cobra"
26+
"golang.org/x/net/context"
2627
)
2728

2829
// gitCommit will be the hash that the binary was built from
@@ -31,7 +32,6 @@ var gitCommit = ""
3132

3233
// supported unpack types
3334
var unpackTypes = []string{
34-
image.TypeImageLayout,
3535
image.TypeImage,
3636
}
3737

@@ -62,8 +62,8 @@ func newUnpackCmd(stdout, stderr *log.Logger) *cobra.Command {
6262

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

@@ -101,6 +101,8 @@ func (v *unpackCmd) Run(cmd *cobra.Command, args []string) {
101101
os.Exit(1)
102102
}
103103

104+
ctx := context.Background()
105+
104106
if v.typ == "" {
105107
typ, err := image.Autodetect(args[0])
106108
if err != nil {
@@ -112,11 +114,8 @@ func (v *unpackCmd) Run(cmd *cobra.Command, args []string) {
112114

113115
var err error
114116
switch v.typ {
115-
case image.TypeImageLayout:
116-
err = image.UnpackLayout(args[0], args[1], v.ref)
117-
118117
case image.TypeImage:
119-
err = image.Unpack(args[0], args[1], v.ref)
118+
err = image.Unpack(ctx, args[0], args[1], v.ref)
120119
}
121120

122121
if err != nil {

cmd/oci-unpack/oci-unpack.1.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ oci-unpack \- Unpack an image or image source layout
1818
The ref pointing to the manifest to be unpacked. This must be present in the "refs" subdirectory of the image. (default "v1.0")
1919

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

2323
# EXAMPLES
2424
```

image/autodetect.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727

2828
// supported autodetection types
2929
const (
30-
TypeImageLayout = "imageLayout"
3130
TypeImage = "image"
3231
TypeManifest = "manifest"
3332
TypeManifestList = "manifestList"
@@ -43,7 +42,7 @@ func Autodetect(path string) (string, error) {
4342
}
4443

4544
if fi.IsDir() {
46-
return TypeImageLayout, nil
45+
return TypeImage, nil
4746
}
4847

4948
f, err := os.Open(path)

image/config.go

Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,63 +18,64 @@ import (
1818
"bytes"
1919
"encoding/json"
2020
"fmt"
21-
"io"
2221
"io/ioutil"
23-
"os"
24-
"path/filepath"
2522
"strconv"
2623
"strings"
2724

2825
"github.com/opencontainers/image-spec/schema"
26+
imagespecs "github.com/opencontainers/image-spec/specs-go"
2927
"github.com/opencontainers/image-spec/specs-go/v1"
30-
"github.com/opencontainers/runtime-spec/specs-go"
28+
"github.com/opencontainers/image-tools/image/cas"
29+
runtimespecs "github.com/opencontainers/runtime-spec/specs-go"
3130
"github.com/pkg/errors"
31+
"golang.org/x/net/context"
3232
)
3333

34-
type config v1.Image
34+
func findConfig(ctx context.Context, engine cas.Engine, descriptor *imagespecs.Descriptor) (config *v1.Image, err error) {
35+
err = validateMediaType(descriptor.MediaType, []string{v1.MediaTypeImageConfig})
36+
if err != nil {
37+
return nil, errors.Wrap(err, "invalid config media type")
38+
}
3539

36-
func findConfig(w walker, d *descriptor) (*config, error) {
37-
var c config
38-
cpath := filepath.Join("blobs", d.algo(), d.hash())
40+
err = validateDescriptor(ctx, engine, descriptor)
41+
if err != nil {
42+
return nil, errors.Wrap(err, "invalid config descriptor")
43+
}
3944

40-
switch err := w.walk(func(path string, info os.FileInfo, r io.Reader) error {
41-
if info.IsDir() || filepath.Clean(path) != cpath {
42-
return nil
43-
}
44-
buf, err := ioutil.ReadAll(r)
45-
if err != nil {
46-
return errors.Wrapf(err, "%s: error reading config", path)
47-
}
45+
reader, err := engine.Get(ctx, descriptor.Digest)
46+
if err != nil {
47+
return nil, errors.Wrapf(err, "failed to fetch %s", descriptor.Digest)
48+
}
4849

49-
if err := schema.MediaTypeImageConfig.Validate(bytes.NewReader(buf)); err != nil {
50-
return errors.Wrapf(err, "%s: config validation failed", path)
51-
}
50+
buf, err := ioutil.ReadAll(reader)
51+
if err != nil {
52+
return nil, errors.Wrapf(err, "%s: error reading manifest", descriptor.Digest)
53+
}
5254

53-
if err := json.Unmarshal(buf, &c); err != nil {
54-
return err
55-
}
56-
// check if the rootfs type is 'layers'
57-
if c.RootFS.Type != "layers" {
58-
return fmt.Errorf("%q is an unknown rootfs type, MUST be 'layers'", c.RootFS.Type)
59-
}
60-
return errEOW
61-
}); err {
62-
case nil:
63-
return nil, fmt.Errorf("%s: config not found", cpath)
64-
case errEOW:
65-
return &c, nil
66-
default:
55+
if err := schema.MediaTypeImageConfig.Validate(bytes.NewReader(buf)); err != nil {
56+
return nil, errors.Wrapf(err, "%s: config validation failed", descriptor.Digest)
57+
}
58+
59+
var c v1.Image
60+
if err := json.Unmarshal(buf, &c); err != nil {
6761
return nil, err
6862
}
63+
64+
// check if the rootfs type is 'layers'
65+
if c.RootFS.Type != "layers" {
66+
return nil, fmt.Errorf("%q is an unknown rootfs type, MUST be 'layers'", c.RootFS.Type)
67+
}
68+
69+
return &c, nil
6970
}
7071

71-
func (c *config) runtimeSpec(rootfs string) (*specs.Spec, error) {
72+
func runtimeSpec(c *v1.Image, rootfs string) (*runtimespecs.Spec, error) {
7273
if c.OS != "linux" {
7374
return nil, fmt.Errorf("%s: unsupported OS", c.OS)
7475
}
7576

76-
var s specs.Spec
77-
s.Version = specs.Version
77+
var s runtimespecs.Spec
78+
s.Version = runtimespecs.Version
7879
// we should at least apply the default spec, otherwise this is totally useless
7980
s.Process.Terminal = true
8081
s.Root.Path = rootfs
@@ -116,12 +117,12 @@ func (c *config) runtimeSpec(rootfs string) (*specs.Spec, error) {
116117
swap := uint64(c.Config.MemorySwap)
117118
shares := uint64(c.Config.CPUShares)
118119

119-
s.Linux.Resources = &specs.Resources{
120-
CPU: &specs.CPU{
120+
s.Linux.Resources = &runtimespecs.Resources{
121+
CPU: &runtimespecs.CPU{
121122
Shares: &shares,
122123
},
123124

124-
Memory: &specs.Memory{
125+
Memory: &runtimespecs.Memory{
125126
Limit: &mem,
126127
Reservation: &mem,
127128
Swap: &swap,
@@ -131,7 +132,7 @@ func (c *config) runtimeSpec(rootfs string) (*specs.Spec, error) {
131132
for vol := range c.Config.Volumes {
132133
s.Mounts = append(
133134
s.Mounts,
134-
specs.Mount{
135+
runtimespecs.Mount{
135136
Destination: vol,
136137
Type: "bind",
137138
Options: []string{"rbind"},

0 commit comments

Comments
 (0)