Add --chown option to add/copy commands
Signed-off-by: Fabio Bertinatto <fbertina@redhat.com> Closes: #336 Approved by: rhatdan
This commit is contained in:
parent
77804bf256
commit
1fc5a49958
55
add.go
55
add.go
|
@ -12,10 +12,16 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/containers/storage/pkg/archive"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
//AddAndCopyOptions holds options for add and copy commands.
|
||||
type AddAndCopyOptions struct {
|
||||
Chown string
|
||||
}
|
||||
|
||||
// addURL copies the contents of the source URL to the destination. This is
|
||||
// its own function so that deferred closes happen after we're done pulling
|
||||
// down each item of potentially many.
|
||||
|
@ -58,7 +64,7 @@ func addURL(destination, srcurl string) error {
|
|||
// Add copies the contents of the specified sources into the container's root
|
||||
// filesystem, optionally extracting contents of local files that look like
|
||||
// non-empty archives.
|
||||
func (b *Builder) Add(destination string, extract bool, source ...string) error {
|
||||
func (b *Builder) Add(destination string, extract bool, options AddAndCopyOptions, source ...string) error {
|
||||
mountPoint, err := b.Mount(b.MountLabel)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -100,6 +106,11 @@ func (b *Builder) Add(destination string, extract bool, source ...string) error
|
|||
if len(source) > 1 && (destfi == nil || !destfi.IsDir()) {
|
||||
return errors.Errorf("destination %q is not a directory", dest)
|
||||
}
|
||||
// Find out which user (and group) the destination should belong to.
|
||||
user, err := b.user(mountPoint, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, src := range source {
|
||||
if strings.HasPrefix(src, "http://") || strings.HasPrefix(src, "https://") {
|
||||
// We assume that source is a file, and we're copying
|
||||
|
@ -118,6 +129,9 @@ func (b *Builder) Add(destination string, extract bool, source ...string) error
|
|||
if err := addURL(d, src); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setOwner(d, user); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -146,6 +160,9 @@ func (b *Builder) Add(destination string, extract bool, source ...string) error
|
|||
if err := copyWithTar(gsrc, d); err != nil {
|
||||
return errors.Wrapf(err, "error copying %q to %q", gsrc, d)
|
||||
}
|
||||
if err := setOwner(d, user); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !extract || !archive.IsArchivePath(gsrc) {
|
||||
|
@ -161,6 +178,9 @@ func (b *Builder) Add(destination string, extract bool, source ...string) error
|
|||
if err := copyFileWithTar(gsrc, d); err != nil {
|
||||
return errors.Wrapf(err, "error copying %q to %q", gsrc, d)
|
||||
}
|
||||
if err := setOwner(d, user); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
// We're extracting an archive into the destination directory.
|
||||
|
@ -172,3 +192,36 @@ func (b *Builder) Add(destination string, extract bool, source ...string) error
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// user returns the user (and group) information which the destination should belong to.
|
||||
func (b *Builder) user(mountPoint string, options AddAndCopyOptions) (specs.User, error) {
|
||||
if options.Chown != "" {
|
||||
return getUser(mountPoint, options.Chown)
|
||||
}
|
||||
return getUser(mountPoint, b.User())
|
||||
}
|
||||
|
||||
// setOwner sets the uid and gid owners of a given path.
|
||||
// If path is a directory, recursively changes the owner.
|
||||
func setOwner(path string, user specs.User) error {
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error reading %q", path)
|
||||
}
|
||||
if fi.IsDir() {
|
||||
err2 := filepath.Walk(path, func(p string, info os.FileInfo, we error) error {
|
||||
if err3 := os.Lchown(p, int(user.UID), int(user.GID)); err3 != nil {
|
||||
return errors.Wrapf(err3, "error setting ownership of %q", p)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err2 != nil {
|
||||
return errors.Wrapf(err2, "error walking dir %q to set ownership", path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := os.Lchown(path, int(user.UID), int(user.GID)); err != nil {
|
||||
return errors.Wrapf(err, "error setting ownership of %q", path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -2,10 +2,17 @@ package main
|
|||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/projectatomic/buildah"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
addAndCopyFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "chown",
|
||||
Usage: "Set the user and group ownership of the destination content",
|
||||
},
|
||||
}
|
||||
addDescription = "Adds the contents of a file, URL, or directory to a container's working\n directory. If a local file appears to be an archive, its contents are\n extracted and added instead of the archive file itself."
|
||||
copyDescription = "Copies the contents of a file, URL, or directory into a container's working\n directory"
|
||||
|
||||
|
@ -13,6 +20,7 @@ var (
|
|||
Name: "add",
|
||||
Usage: "Add content to the container",
|
||||
Description: addDescription,
|
||||
Flags: addAndCopyFlags,
|
||||
Action: addCmd,
|
||||
ArgsUsage: "CONTAINER-NAME-OR-ID [[FILE | DIRECTORY | URL] ...] [DESTINATION]",
|
||||
}
|
||||
|
@ -21,6 +29,7 @@ var (
|
|||
Name: "copy",
|
||||
Usage: "Copy content into the container",
|
||||
Description: copyDescription,
|
||||
Flags: addAndCopyFlags,
|
||||
Action: copyCmd,
|
||||
ArgsUsage: "CONTAINER-NAME-OR-ID [[FILE | DIRECTORY | URL] ...] [DESTINATION]",
|
||||
}
|
||||
|
@ -34,6 +43,10 @@ func addAndCopyCmd(c *cli.Context, extractLocalArchives bool) error {
|
|||
name := args[0]
|
||||
args = args.Tail()
|
||||
|
||||
if err := validateFlags(c, addAndCopyFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If list is greater then one, the last item is the destination
|
||||
dest := ""
|
||||
size := len(args)
|
||||
|
@ -52,8 +65,11 @@ func addAndCopyCmd(c *cli.Context, extractLocalArchives bool) error {
|
|||
return errors.Wrapf(err, "error reading build container %q", name)
|
||||
}
|
||||
|
||||
err = builder.Add(dest, extractLocalArchives, args...)
|
||||
if err != nil {
|
||||
options := buildah.AddAndCopyOptions{
|
||||
Chown: c.String("chown"),
|
||||
}
|
||||
|
||||
if err := builder.Add(dest, extractLocalArchives, options, args...); err != nil {
|
||||
return errors.Wrapf(err, "error adding content to container %q", builder.Container)
|
||||
}
|
||||
|
||||
|
|
|
@ -13,10 +13,18 @@ appears to be an archive, its contents are extracted and added instead of the
|
|||
archive file itself. If a local directory is specified as a source, its
|
||||
*contents* are copied to the destination.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
**--chown** *owner*:*group*
|
||||
|
||||
Sets the user and group ownership of the destination content.
|
||||
|
||||
## EXAMPLE
|
||||
|
||||
buildah add containerID '/myapp/app.conf' '/myapp/app.conf'
|
||||
|
||||
buildah add --chown myuser:mygroup containerID '/myapp/app.conf' '/myapp/app.conf'
|
||||
|
||||
buildah add containerID '/home/myuser/myproject.go'
|
||||
|
||||
buildah add containerID '/home/myuser/myfiles.tar' '/tmp'
|
||||
|
|
|
@ -11,10 +11,18 @@ Copies the contents of a file, URL, or a directory to a container's working
|
|||
directory or a specified location in the container. If a local directory is
|
||||
specified as a source, its *contents* are copied to the destination.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
**--chown** *owner*:*group*
|
||||
|
||||
Sets the user and group ownership of the destination content.
|
||||
|
||||
## EXAMPLE
|
||||
|
||||
buildah copy containerID '/myapp/app.conf' '/myapp/app.conf'
|
||||
|
||||
buildah copy --chown myuser:mygroup containerID '/myapp/app.conf' '/myapp/app.conf'
|
||||
|
||||
buildah copy containerID '/home/myuser/myproject.go'
|
||||
|
||||
buildah copy containerID '/home/myuser/myfiles.tar' '/tmp'
|
||||
|
|
|
@ -341,7 +341,7 @@ func (b *Executor) Copy(excludes []string, copies ...imagebuilder.Copy) error {
|
|||
sources = append(sources, filepath.Join(b.contextDir, src))
|
||||
}
|
||||
}
|
||||
if err := b.builder.Add(copy.Dest, copy.Download, sources...); err != nil {
|
||||
if err := b.builder.Add(copy.Dest, copy.Download, buildah.AddAndCopyOptions{}, sources...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,3 +111,23 @@ load helpers
|
|||
[ "$status" -ne 0 ]
|
||||
buildah rm $cid
|
||||
}
|
||||
|
||||
@test "copy --chown" {
|
||||
mkdir -p ${TESTDIR}/subdir
|
||||
createrandom ${TESTDIR}/randomfile
|
||||
createrandom ${TESTDIR}/subdir/randomfile
|
||||
createrandom ${TESTDIR}/subdir/other-randomfile
|
||||
|
||||
cid=$(buildah from --pull --signature-policy ${TESTSDIR}/policy.json alpine)
|
||||
root=$(buildah mount $cid)
|
||||
buildah config --workingdir / $cid
|
||||
buildah copy --chown 1:1 $cid ${TESTDIR}/randomfile
|
||||
buildah copy --chown root:1 $cid ${TESTDIR}/randomfile /randomfile2
|
||||
buildah copy --chown nobody $cid ${TESTDIR}/randomfile /randomfile3
|
||||
buildah copy --chown nobody:root $cid ${TESTDIR}/subdir /subdir
|
||||
test $(stat -c "%u:%g" $root/randomfile) = "1:1"
|
||||
test $(stat -c "%U:%g" $root/randomfile2) = "root:1"
|
||||
test $(stat -c "%U" $root/randomfile3) = "nobody"
|
||||
(cd $root/subdir/; for i in *; do test $(stat -c "%U:%G" $i) = "nobody:root"; done)
|
||||
buildah rm $cid
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue