Skip to content

Commit

Permalink
fix: handle ancient empty docker layers
Browse files Browse the repository at this point in the history
Earlier versions of docker images had empty layers of 1024 zero-valued
octets.

moby/moby#20917 (comment)

Signed-off-by: Ramkumar Chinchani <[email protected]>
  • Loading branch information
rchincha committed Oct 25, 2023
1 parent 0cf2d70 commit e761a50
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 3 deletions.
4 changes: 4 additions & 0 deletions pkg/log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ func Infof(msg string, v ...interface{}) {
addStackerLogSentinel(log.NewEntry(log.Log.(*log.Logger))).Infof(msg, v...)
}

func Warnf(msg string, v ...interface{}) {
addStackerLogSentinel(log.NewEntry(log.Log.(*log.Logger))).Warnf(msg, v...)

Check warning on line 50 in pkg/log/log.go

View check run for this annotation

Codecov / codecov/patch

pkg/log/log.go#L49-L50

Added lines #L49 - L50 were not covered by tests
}

func Errorf(msg string, v ...interface{}) {
addStackerLogSentinel(log.NewEntry(log.Log.(*log.Logger))).Errorf(msg, v...)
}
Expand Down
11 changes: 10 additions & 1 deletion pkg/overlay/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package overlay
import (
"bytes"
"encoding/json"
"io/fs"
"os"
"path"

Expand Down Expand Up @@ -117,7 +118,15 @@ func (ovl overlayMetadata) lxcRootfsString(config types.StackerConfig, tag strin
for _, layer := range manifest.Layers {
contents := overlayPath(config.RootFSDir, layer.Digest, "overlay")
if _, err := os.Stat(contents); err != nil {
return "", errors.Wrapf(err, "%s does not exist", contents)
if errors.Is(err, fs.ErrNotExist) {
// some docker layers may be empty tars, so ignore these
// https://github.com/moby/moby/issues/20917#issuecomment-191901912
log.Warnf("%s skipping empty tar layer", layer.Digest)

continue

Check warning on line 126 in pkg/overlay/metadata.go

View check run for this annotation

Codecov / codecov/patch

pkg/overlay/metadata.go#L121-L126

Added lines #L121 - L126 were not covered by tests
}

return "", errors.Wrapf(err, "%s unable to stat", contents)

Check warning on line 129 in pkg/overlay/metadata.go

View check run for this annotation

Codecov / codecov/patch

pkg/overlay/metadata.go#L129

Added line #L129 was not covered by tests
}
lowerdirs = append(lowerdirs, contents)
}
Expand Down
6 changes: 5 additions & 1 deletion pkg/stacker/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,11 @@ func SetupRootfs(o BaseLayerOpts) error {
case types.OCILayer:
fallthrough
case types.DockerLayer:
return setupContainersImageRootfs(o)
err := setupContainersImageRootfs(o)
if err != nil && errors.Is(err, types.ErrEmptyLayers) {
return o.Storage.SetupEmptyRootfs(o.Name)
}
return err

Check warning on line 94 in pkg/stacker/base.go

View check run for this annotation

Codecov / codecov/patch

pkg/stacker/base.go#L90-L94

Added lines #L90 - L94 were not covered by tests
default:
return errors.Errorf("unknown layer type: %v", o.Layer.From.Type)
}
Expand Down
4 changes: 3 additions & 1 deletion pkg/types/layer_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"stackerbuild.io/stacker/pkg/squashfs"
)

var ErrEmptyLayers = errors.New("empty layers")

type LayerType struct {
Type string
Verity squashfs.VerityMetadata
Expand Down Expand Up @@ -60,7 +62,7 @@ func NewLayerType(lt string, verity squashfs.VerityMetadata) (LayerType, error)

func NewLayerTypeManifest(manifest ispec.Manifest) (LayerType, error) {
if len(manifest.Layers) == 0 {
return LayerType{}, errors.Errorf("no existing layers to determine layer type")
return NewLayerType("tar", squashfs.VerityMetadataMissing)

Check warning on line 65 in pkg/types/layer_type.go

View check run for this annotation

Codecov / codecov/patch

pkg/types/layer_type.go#L65

Added line #L65 was not covered by tests
}

switch manifest.Layers[0].MediaType {
Expand Down
25 changes: 25 additions & 0 deletions test/empty-layers.bats
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,28 @@ EOF

[ "$layers0" = "$layers1" ]
}

@test "an image with empty layers" {
umoci init --layout oci
umoci new --image oci:emptylayer
chmod -R a+rw oci

cat > stacker.yaml <<EOF
test_empty_layer:
from:
type: oci
url: oci:emptylayer
EOF
stacker build
}

@test "a real-world docker image with empty/filler layer" {
cat > stacker.yaml <<EOF
image:
from:
type: docker
url: docker://ghcr.io/project-stacker/grafana-oss:10.1.2-ubuntu
EOF
stacker build
}

0 comments on commit e761a50

Please sign in to comment.