new "image" mount type

Add a new "image" mount type to `--mount`.  The source of the mount is
the name or ID of an image.  The destination is the path inside the
container.  Image mounts further support an optional `rw,readwrite`
parameter which if set to "true" will yield the mount writable inside
the container.  Note that no changes are propagated to the image mount
on the host (which in any case is read only).

Mounts are overlay mounts.  To support read-only overlay mounts, vendor
a non-release version of Buildah.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
Valentin Rothberg
2020-10-26 11:35:02 +01:00
parent cce6c6cd40
commit 65a618886e
168 changed files with 6143 additions and 10606 deletions

View File

@@ -208,7 +208,7 @@ func BuildDockerfiles(ctx context.Context, store storage.Store, options BuildOpt
logrus.Debugf("reading remote Dockerfile %q", dfile)
resp, err := http.Get(dfile)
if err != nil {
return "", nil, errors.Wrapf(err, "error getting %q", dfile)
return "", nil, err
}
if resp.ContentLength == 0 {
resp.Body.Close()
@@ -220,10 +220,14 @@ func BuildDockerfiles(ctx context.Context, store storage.Store, options BuildOpt
// context directory to it.
dinfo, err := os.Stat(dfile)
if os.IsNotExist(err) {
dfile = filepath.Join(options.ContextDirectory, dfile)
// If they are "/workDir/Dockerfile" and "/workDir"
// so don't joint it
if !strings.HasPrefix(dfile, options.ContextDirectory) {
dfile = filepath.Join(options.ContextDirectory, dfile)
}
dinfo, err = os.Stat(dfile)
if err != nil {
return "", nil, errors.Wrapf(err, "error reading info about %q", dfile)
return "", nil, err
}
}
// If given a directory, add '/Dockerfile' to it.
@@ -233,7 +237,7 @@ func BuildDockerfiles(ctx context.Context, store storage.Store, options BuildOpt
logrus.Debugf("reading local Dockerfile %q", dfile)
contents, err := os.Open(dfile)
if err != nil {
return "", nil, errors.Wrapf(err, "error reading %q", dfile)
return "", nil, err
}
dinfo, err = contents.Stat()
if err != nil {
@@ -242,7 +246,7 @@ func BuildDockerfiles(ctx context.Context, store storage.Store, options BuildOpt
}
if dinfo.Mode().IsRegular() && dinfo.Size() == 0 {
contents.Close()
return "", nil, errors.Wrapf(err, "no contents in %q", dfile)
return "", nil, errors.Errorf("no contents in %q", dfile)
}
data = contents
}
@@ -261,7 +265,7 @@ func BuildDockerfiles(ctx context.Context, store storage.Store, options BuildOpt
mainNode, err := imagebuilder.ParseDockerfile(dockerfiles[0])
if err != nil {
return "", nil, errors.Wrapf(err, "error parsing main Dockerfile")
return "", nil, errors.Wrapf(err, "error parsing main Dockerfile: %s", dockerfiles[0])
}
warnOnUnsetBuildArgs(mainNode, options.Args)
@@ -269,7 +273,7 @@ func BuildDockerfiles(ctx context.Context, store storage.Store, options BuildOpt
for _, d := range dockerfiles[1:] {
additionalNode, err := imagebuilder.ParseDockerfile(d)
if err != nil {
return "", nil, errors.Wrapf(err, "error parsing additional Dockerfile")
return "", nil, errors.Wrapf(err, "error parsing additional Dockerfile %s", d)
}
mainNode.Children = append(mainNode.Children, additionalNode.Children...)
}

View File

@@ -90,7 +90,7 @@ func getSymbolicLink(path string) (string, error) {
symPath = filepath.Join(symPath, p)
isSymlink, resolvedPath, err := hasSymlink(symPath)
if err != nil {
return "", errors.Wrapf(err, "error checking symlink for %q", symPath)
return "", err
}
// if isSymlink is true, check if resolvedPath is potentially another symlink
// keep doing this till resolvedPath is not a symlink and isSymlink is false
@@ -102,7 +102,7 @@ func getSymbolicLink(path string) (string, error) {
}
isSymlink, resolvedPath, err = hasSymlink(resolvedPath)
if err != nil {
return "", errors.Wrapf(err, "error checking symlink for %q", resolvedPath)
return "", err
}
symLinksResolved++
}
@@ -121,14 +121,14 @@ func hasSymlink(path string) (bool, string, error) {
if err != nil {
if os.IsNotExist(err) {
if err = os.MkdirAll(path, 0755); err != nil {
return false, "", errors.Wrapf(err, "error ensuring volume path %q exists", path)
return false, "", err
}
info, err = os.Lstat(path)
if err != nil {
return false, "", errors.Wrapf(err, "error running lstat on %q", path)
return false, "", err
}
} else {
return false, path, errors.Wrapf(err, "error get stat of path %q", path)
return false, path, err
}
}
@@ -140,7 +140,7 @@ func hasSymlink(path string) (bool, string, error) {
// Read the symlink to get what it points to
targetDir, err := os.Readlink(path)
if err != nil {
return false, "", errors.Wrapf(err, "error reading link %q", path)
return false, "", err
}
// if the symlink points to a relative path, prepend the path till now to the resolved path
if !filepath.IsAbs(targetDir) {

View File

@@ -26,7 +26,6 @@ import (
"github.com/containers/storage/pkg/archive"
digest "github.com/opencontainers/go-digest"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/openshift/imagebuilder"
"github.com/openshift/imagebuilder/dockerfile/parser"
"github.com/pkg/errors"
@@ -98,7 +97,7 @@ type Executor struct {
excludes []string
unusedArgs map[string]struct{}
capabilities []string
devices []configs.Device
devices buildah.ContainerDevices
signBy string
architecture string
timestamp *time.Time
@@ -130,7 +129,7 @@ func NewExecutor(store storage.Store, options BuildOptions, mainNode *parser.Nod
return nil, err
}
devices := []configs.Device{}
devices := buildah.ContainerDevices{}
for _, device := range append(defaultContainerConfig.Containers.Devices, options.Devices...) {
dev, err := parse.DeviceFromPath(device)
if err != nil {

View File

@@ -81,7 +81,7 @@ func (s *StageExecutor) Preserve(path string) error {
// except ensure that it exists.
archivedPath := filepath.Join(s.mountPoint, path)
if err := os.MkdirAll(archivedPath, 0755); err != nil {
return errors.Wrapf(err, "error ensuring volume path %q exists", archivedPath)
return errors.Wrapf(err, "error ensuring volume path exists")
}
if err := s.volumeCacheInvalidate(path); err != nil {
return errors.Wrapf(err, "error ensuring volume path %q is preserved", archivedPath)
@@ -110,13 +110,13 @@ func (s *StageExecutor) Preserve(path string) error {
st, err := os.Stat(archivedPath)
if os.IsNotExist(err) {
if err = os.MkdirAll(archivedPath, 0755); err != nil {
return errors.Wrapf(err, "error ensuring volume path %q exists", archivedPath)
return errors.Wrapf(err, "error ensuring volume path exists")
}
st, err = os.Stat(archivedPath)
}
if err != nil {
logrus.Debugf("error reading info about %q: %v", archivedPath, err)
return errors.Wrapf(err, "error reading info about volume path %q", archivedPath)
return err
}
s.volumeCacheInfo[path] = st
if !s.volumes.Add(path) {
@@ -152,7 +152,7 @@ func (s *StageExecutor) Preserve(path string) error {
if os.IsNotExist(err) {
continue
}
return errors.Wrapf(err, "error removing %q", s.volumeCache[cachedPath])
return err
}
delete(s.volumeCache, cachedPath)
}
@@ -173,7 +173,7 @@ func (s *StageExecutor) volumeCacheInvalidate(path string) error {
if os.IsNotExist(err) {
continue
}
return errors.Wrapf(err, "error removing volume cache %q", s.volumeCache[cachedPath])
return err
}
archivedPath := filepath.Join(s.mountPoint, cachedPath)
logrus.Debugf("invalidated volume cache for %q from %q", archivedPath, s.volumeCache[cachedPath])
@@ -193,15 +193,15 @@ func (s *StageExecutor) volumeCacheSave() error {
continue
}
if !os.IsNotExist(err) {
return errors.Wrapf(err, "error checking for cache of %q in %q", archivedPath, cacheFile)
return err
}
if err := os.MkdirAll(archivedPath, 0755); err != nil {
return errors.Wrapf(err, "error ensuring volume path %q exists", archivedPath)
return errors.Wrapf(err, "error ensuring volume path exists")
}
logrus.Debugf("caching contents of volume %q in %q", archivedPath, cacheFile)
cache, err := os.Create(cacheFile)
if err != nil {
return errors.Wrapf(err, "error creating archive at %q", cacheFile)
return err
}
defer cache.Close()
rc, err := archive.Tar(archivedPath, archive.Uncompressed)
@@ -224,14 +224,14 @@ func (s *StageExecutor) volumeCacheRestore() error {
logrus.Debugf("restoring contents of volume %q from %q", archivedPath, cacheFile)
cache, err := os.Open(cacheFile)
if err != nil {
return errors.Wrapf(err, "error opening archive at %q", cacheFile)
return err
}
defer cache.Close()
if err := os.RemoveAll(archivedPath); err != nil {
return errors.Wrapf(err, "error clearing volume path %q", archivedPath)
return err
}
if err := os.MkdirAll(archivedPath, 0755); err != nil {
return errors.Wrapf(err, "error recreating volume path %q", archivedPath)
return err
}
err = archive.Untar(cache, archivedPath, nil)
if err != nil {
@@ -239,7 +239,7 @@ func (s *StageExecutor) volumeCacheRestore() error {
}
if st, ok := s.volumeCacheInfo[cachedPath]; ok {
if err := os.Chmod(archivedPath, st.Mode()); err != nil {
return errors.Wrapf(err, "error restoring permissions on %q", archivedPath)
return err
}
uid := 0
gid := 0
@@ -248,10 +248,10 @@ func (s *StageExecutor) volumeCacheRestore() error {
gid = util.GID(st)
}
if err := os.Chown(archivedPath, uid, gid); err != nil {
return errors.Wrapf(err, "error setting ownership on %q", archivedPath)
return err
}
if err := os.Chtimes(archivedPath, st.ModTime(), st.ModTime()); err != nil {
return errors.Wrapf(err, "error restoring datestamps on %q", archivedPath)
return err
}
}
}
@@ -789,8 +789,11 @@ func (s *StageExecutor) Execute(ctx context.Context, base string) (imgID string,
// for this stage. Make a note of the
// instruction in the history that we'll write
// for the image when we eventually commit it.
now := time.Now()
s.builder.AddPrependedEmptyLayer(&now, s.getCreatedBy(node, addedContentSummary), "", "")
timestamp := time.Now().UTC()
if s.executor.timestamp != nil {
timestamp = *s.executor.timestamp
}
s.builder.AddPrependedEmptyLayer(&timestamp, s.getCreatedBy(node, addedContentSummary), "", "")
continue
} else {
// This is the last instruction for this stage,

View File

@@ -40,7 +40,7 @@ func downloadToDirectory(url, dir string) error {
logrus.Debugf("extracting %q to %q", url, dir)
resp, err := http.Get(url)
if err != nil {
return errors.Wrapf(err, "error getting %q", url)
return err
}
defer resp.Body.Close()
if resp.ContentLength == 0 {
@@ -49,12 +49,12 @@ func downloadToDirectory(url, dir string) error {
if err := chrootarchive.Untar(resp.Body, dir, nil); err != nil {
resp1, err := http.Get(url)
if err != nil {
return errors.Wrapf(err, "error getting %q", url)
return err
}
defer resp1.Body.Close()
body, err := ioutil.ReadAll(resp1.Body)
if err != nil {
return errors.Wrapf(err, "Failed to read %q", url)
return err
}
dockerfile := filepath.Join(dir, "Dockerfile")
// Assume this is a Dockerfile