1
0
mirror of https://github.com/openSUSE/umoci.git synced 2026-02-05 09:44:53 +01:00
Files
umoci/repack.go
Aleksa Sarai 01954f533c *: add copyright statement
Signed-off-by: Aleksa Sarai <asarai@suse.de>
2019-09-15 00:42:54 +10:00

147 lines
4.3 KiB
Go

/*
* umoci: Umoci Modifies Open Containers' Images
* Copyright (C) 2016-2019 SUSE LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package umoci
import (
"os"
"path/filepath"
"strings"
"github.com/apex/log"
"github.com/openSUSE/umoci/mutate"
"github.com/openSUSE/umoci/oci/casext"
"github.com/openSUSE/umoci/oci/layer"
"github.com/openSUSE/umoci/pkg/fseval"
"github.com/openSUSE/umoci/pkg/mtreefilter"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/vbatts/go-mtree"
"golang.org/x/net/context"
)
// Repack repacks a bundle into an image adding a new layer for the changed
// data in the bundle.
func Repack(engineExt casext.Engine, tagName string, bundlePath string, meta Meta, history *ispec.History, maskedPaths []string, refreshBundle bool, mutator *mutate.Mutator) error {
mtreeName := strings.Replace(meta.From.Descriptor().Digest.String(), ":", "_", 1)
mtreePath := filepath.Join(bundlePath, mtreeName+".mtree")
fullRootfsPath := filepath.Join(bundlePath, layer.RootfsName)
log.WithFields(log.Fields{
"bundle": bundlePath,
"rootfs": layer.RootfsName,
"mtree": mtreePath,
}).Debugf("umoci: repacking OCI image")
mfh, err := os.Open(mtreePath)
if err != nil {
return errors.Wrap(err, "open mtree")
}
defer mfh.Close()
spec, err := mtree.ParseSpec(mfh)
if err != nil {
return errors.Wrap(err, "parse mtree")
}
log.WithFields(log.Fields{
"keywords": MtreeKeywords,
}).Debugf("umoci: parsed mtree spec")
fsEval := fseval.DefaultFsEval
if meta.MapOptions.Rootless {
fsEval = fseval.RootlessFsEval
}
log.Info("computing filesystem diff ...")
diffs, err := mtree.Check(fullRootfsPath, spec, MtreeKeywords, fsEval)
if err != nil {
return errors.Wrap(err, "check mtree")
}
log.Info("... done")
log.WithFields(log.Fields{
"ndiff": len(diffs),
}).Debugf("umoci: checked mtree spec")
diffs = mtreefilter.FilterDeltas(diffs,
mtreefilter.MaskFilter(maskedPaths),
mtreefilter.SimplifyFilter(diffs))
if len(diffs) == 0 {
config, err := mutator.Config(context.Background())
if err != nil {
return err
}
imageMeta, err := mutator.Meta(context.Background())
if err != nil {
return err
}
annotations, err := mutator.Annotations(context.Background())
if err != nil {
return err
}
err = mutator.Set(context.Background(), config, imageMeta, annotations, history)
if err != nil {
return err
}
} else {
reader, err := layer.GenerateLayer(fullRootfsPath, diffs, &meta.MapOptions)
if err != nil {
return errors.Wrap(err, "generate diff layer")
}
defer reader.Close()
// TODO: We should add a flag to allow for a new layer to be made
// non-distributable.
if err := mutator.Add(context.Background(), reader, history); err != nil {
return errors.Wrap(err, "add diff layer")
}
}
newDescriptorPath, err := mutator.Commit(context.Background())
if err != nil {
return errors.Wrap(err, "commit mutated image")
}
log.Infof("new image manifest created: %s->%s", newDescriptorPath.Root().Digest, newDescriptorPath.Descriptor().Digest)
if err := engineExt.UpdateReference(context.Background(), tagName, newDescriptorPath.Root()); err != nil {
return errors.Wrap(err, "add new tag")
}
log.Infof("created new tag for image manifest: %s", tagName)
if refreshBundle {
newMtreeName := strings.Replace(newDescriptorPath.Descriptor().Digest.String(), ":", "_", 1)
if err := GenerateBundleManifest(newMtreeName, bundlePath, fsEval); err != nil {
return errors.Wrap(err, "write mtree metadata")
}
if err := os.Remove(mtreePath); err != nil {
return errors.Wrap(err, "remove old mtree metadata")
}
meta.From = newDescriptorPath
if err := WriteBundleMeta(bundlePath, meta); err != nil {
return errors.Wrap(err, "write umoci.json metadata")
}
}
return nil
}