Skip to content

Commit

Permalink
add --mount for mounting path with colon
Browse files Browse the repository at this point in the history
close containers#1597

Enables to use path with colon when using `buildah run --volume` to bind a volume. Have the same functionality as --volume.

Signed-off-by: Qi Wang <[email protected]>
  • Loading branch information
QiWang19 committed Jun 14, 2019
1 parent 77fa9dd commit 5abc5f3
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 0 deletions.
16 changes: 16 additions & 0 deletions cmd/buildah/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type runInputOptions struct {
securityOption []string
terminal bool
volumes []string
mounts []string
*buildahcli.NameSpaceResults
}

Expand Down Expand Up @@ -69,6 +70,7 @@ func init() {
flags.BoolVar(&opts.terminal, "tty", false, "allocate a pseudo-TTY in the container")
flags.MarkHidden("tty")
flags.StringSliceVarP(&opts.volumes, "volume", "v", []string{}, "bind mount a host location into the container while running the command")
flags.StringArrayVar(&opts.mounts, "mount", []string{}, "Attach a filesystem mount to the container (default [])")

userFlags := getUserFlags()
namespaceFlags := buildahcli.GetNameSpaceFlags(&namespaceResults)
Expand Down Expand Up @@ -155,6 +157,20 @@ func runCmd(c *cobra.Command, args []string, iopts runInputOptions) error {
}
options.Mounts = append(options.Mounts, mount)
}

// validate mount paths
if err := parse.ParseMounts(iopts.mounts); err != nil {
return err
}

for _, mountSpec := range iopts.mounts {
mount, err := parse.ParseMount(mountSpec)
if err != nil {
return err
}
options.Mounts = append(options.Mounts, mount)
}

runerr := builder.Run(args, options)
if runerr != nil {
logrus.Debugf("error running %v in container %q: %v", args, builder.Container, runerr)
Expand Down
1 change: 1 addition & 0 deletions contrib/completions/bash/buildah
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ return 1
--hostname
--ipc
--isolation
--mount
--net
--network
--pid
Expand Down
24 changes: 24 additions & 0 deletions docs/buildah-run.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,28 @@ that leans more toward chroot(1) than container technology).
Note: You can also override the default isolation type by setting the
BUILDAH\_ISOLATION environment variable. `export BUILDAH_ISOLATION=oci`

**--mount**=*type=TYPE,TYPE-SPECIFIC-OPTION[,...]*

Attach a filesystem mount to the container

Current supported mount TYPE is bind.

e.g.

type=bind,source=/tmp/on:host,destionation=/path:in:container

The Options (see explanaitons in --volume) are a comma delimited list and can be :

· src, source: mount source spec for bind and volume. Mandatory for bind.

· dst, destination, target: mount destination spec.

· [rw|ro]

· [z|Z]

· [`[r]shared`|`[r]slave`|`[r]private`]

**--net** *how*
**--network** *how*

Expand Down Expand Up @@ -240,5 +262,7 @@ buildah run --tty=false containerID ls /

buildah run --volume /path/on/host:/path/in/container:ro,z containerID sh

buildah run --mount type=bind,src=/tmp/on:host,dst=/in:container,ro containerID sh

## SEE ALSO
buildah(1), namespaces(7), pid\_namespaces(7)
60 changes: 60 additions & 0 deletions pkg/parse/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,66 @@ func ParseVolumes(volumes []string) error {
return nil
}

// ParseMounts validates the host and container paths passed in to the --mount flag
func ParseMounts(mounts []string) error {
if len(mounts) == 0 {
return nil
}
for _, mount := range mounts {
if _, err := ParseMount(mount); err != nil {
return err
}
}
return nil
}

func ParseMount(mountStr string) (specs.Mount, error) {
mount := specs.Mount{
Type: "rbind",
}
arr := strings.SplitN(mountStr, ",", 2)
if len(arr) < 2 {
return mount, errors.Errorf("incorrect mount format %q, should be --mount type=<bind|tmpfs|volume>,[src=<host-dir|volume-name>,]target=<ctr-dir>[,options]", mountStr)
}
kv := strings.Split(arr[0], "=")
if len(kv) != 2 || kv[0] != "type" {
return mount, errors.Errorf("incorrect mount format %q, should be --mount type=<bind|tmpfs|volume>,[src=<host-dir|volume-name>,]target=<ctr-dir>[,options]", mountStr)
}

tokens := strings.Split(arr[1], ",")
if kv[1] != "bind" {
return mount, errors.Errorf("invalid filesystem type %q", kv[1])
}
for _, val := range tokens {
kv := strings.Split(val, "=")
switch kv[0] {
case "src", "source":
if len(kv) == 1 {
return mount, errors.Errorf("must provide an argument for option %q", kv[0])
}
if err := ValidateVolumeHostDir(kv[1]); err != nil {
return mount, err
}
mount.Source = kv[1]

case "target", "dst", "destination":
if len(kv) == 1 {
return mount, errors.Errorf("must provide an argument for option %q", kv[0])
}
if err := ValidateVolumeCtrDir(kv[1]); err != nil {
return mount, err
}
mount.Destination = kv[1]
default:
if err := ValidateVolumeOpts(val); err != nil {
return mount, err
}
mount.Options = append(mount.Options, val)
}
}
return mount, nil
}

func ValidateVolumeHostDir(hostDir string) error {
if !filepath.IsAbs(hostDir) {
return errors.Errorf("invalid host path, must be an absolute path %q", hostDir)
Expand Down
23 changes: 23 additions & 0 deletions tests/run.bats
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,29 @@ function configure_and_check_user() {
run_buildah --debug=false run -v ${TESTDIR}/was-empty/testfile:/var/different-multi-level/subdirectory/testfile $cid touch /var/different-multi-level/subdirectory/testfile
}

@test "run --mount" {
if ! which runc ; then
skip "no runc in PATH"
fi
zflag=
if which selinuxenabled > /dev/null 2> /dev/null ; then
if selinuxenabled ; then
zflag=z
fi
fi
runc --version
cid=$(buildah from --pull --signature-policy ${TESTSDIR}/policy.json alpine)
mkdir -p ${TESTDIR}/was:empty
# As a baseline, this should succeed.
run_buildah --debug=false run --mount type=bind,src=${TESTDIR}/was:empty,dst=/var/not-empty,${zflag:+:${zflag}} $cid touch /var/not-empty/testfile
# If we're parsing the options at all, this should be read-only, so it should fail.
run_buildah 1 --debug=false run --mount type=bind,src=${TESTDIR}/was:empty,dst=/var/not-empty,ro${zflag:+,${zflag}} $cid touch /var/not-empty/testfile
# Even if the parent directory doesn't exist yet, this should succeed.
run_buildah --debug=false run --mount type=bind,src=${TESTDIR}/was:empty,dst=/var/multi-level/subdirectory $cid touch /var/multi-level/subdirectory/testfile
# And check the same for file volumes.
run_buildah --debug=false run --mount type=bind,src=${TESTDIR}/was:empty/testfile,dst=/var/different-multi-level/subdirectory/testfile $cid touch /var/different-multi-level/subdirectory/testfile
}

@test "run symlinks" {
if ! which runc ; then
skip "no runc in PATH"
Expand Down

0 comments on commit 5abc5f3

Please sign in to comment.