diff --git a/pkg/log/log.go b/pkg/log/log.go index 553383f0..c8a8c280 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -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...) +} + func Errorf(msg string, v ...interface{}) { addStackerLogSentinel(log.NewEntry(log.Log.(*log.Logger))).Errorf(msg, v...) } diff --git a/pkg/overlay/metadata.go b/pkg/overlay/metadata.go index 3114dcf3..43906a2a 100644 --- a/pkg/overlay/metadata.go +++ b/pkg/overlay/metadata.go @@ -3,6 +3,7 @@ package overlay import ( "bytes" "encoding/json" + "io/fs" "os" "path" @@ -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 + } + + return "", errors.Wrapf(err, "%s unable to stat", contents) } lowerdirs = append(lowerdirs, contents) } diff --git a/pkg/stacker/base.go b/pkg/stacker/base.go index 34ec2e63..2a13ab7a 100644 --- a/pkg/stacker/base.go +++ b/pkg/stacker/base.go @@ -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 default: return errors.Errorf("unknown layer type: %v", o.Layer.From.Type) } diff --git a/pkg/types/layer_type.go b/pkg/types/layer_type.go index 652b2749..7404a7b2 100644 --- a/pkg/types/layer_type.go +++ b/pkg/types/layer_type.go @@ -10,6 +10,8 @@ import ( "stackerbuild.io/stacker/pkg/squashfs" ) +var ErrEmptyLayers = errors.New("empty layers") + type LayerType struct { Type string Verity squashfs.VerityMetadata @@ -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) } switch manifest.Layers[0].MediaType { diff --git a/test/empty-layers.bats b/test/empty-layers.bats index 940136fe..5e839af9 100644 --- a/test/empty-layers.bats +++ b/test/empty-layers.bats @@ -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 < stacker.yaml <