diff options
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/podman/common.go | 4 | ||||
-rw-r--r-- | cmd/podman/create.go | 6 | ||||
-rw-r--r-- | cmd/podman/create_cli.go | 90 |
3 files changed, 100 insertions, 0 deletions
diff --git a/cmd/podman/common.go b/cmd/podman/common.go index 8d20081f6..9ab0e57e5 100644 --- a/cmd/podman/common.go +++ b/cmd/podman/common.go @@ -418,6 +418,10 @@ var createFlags = []cli.Flag{ Usage: "UTS namespace to use", }, cli.StringSliceFlag{ + Name: "mount", + Usage: "Attach a filesystem mount to the container (default [])", + }, + cli.StringSliceFlag{ Name: "volume, v", Usage: "Bind mount a volume into the container (default [])", }, diff --git a/cmd/podman/create.go b/cmd/podman/create.go index ff912560b..fc0c71536 100644 --- a/cmd/podman/create.go +++ b/cmd/podman/create.go @@ -24,6 +24,7 @@ import ( "github.com/docker/docker/pkg/signal" "github.com/docker/go-connections/nat" "github.com/docker/go-units" + spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/selinux/go-selinux/label" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -459,6 +460,10 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim } blkioWeight = uint16(u) } + var mountList []spec.Mount + if mountList, err = parseMounts(c.StringSlice("mount")); err != nil { + return nil, err + } if err = parseVolumes(c.StringSlice("volume")); err != nil { return nil, err @@ -772,6 +777,7 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim Tty: tty, User: user, UsernsMode: usernsMode, + Mounts: mountList, Volumes: c.StringSlice("volume"), WorkDir: workDir, Rootfs: rootfs, diff --git a/cmd/podman/create_cli.go b/cmd/podman/create_cli.go index 812b62058..218e9b806 100644 --- a/cmd/podman/create_cli.go +++ b/cmd/podman/create_cli.go @@ -8,6 +8,8 @@ import ( cc "github.com/containers/libpod/pkg/spec" "github.com/docker/docker/pkg/sysinfo" + "github.com/docker/go-units" + spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -74,6 +76,94 @@ func addWarning(warnings []string, msg string) []string { return append(warnings, msg) } +// Format supported. +// podman run --mount type=bind,src=/etc/resolv.conf,target=/etc/resolv.conf ... +// podman run --mount type=tmpfs,target=/dev/shm .. +func parseMounts(mounts []string) ([]spec.Mount, error) { + var mountList []spec.Mount + errInvalidSyntax := errors.Errorf("incorrect mount format : should be --mount type=<bind|tmpfs>,[src=<host-dir>,]target=<ctr-dir>,[options]") + for _, mount := range mounts { + var tokenCount int + var mountInfo spec.Mount + + arr := strings.SplitN(mount, ",", 2) + if len(arr) < 2 { + return nil, errInvalidSyntax + } + kv := strings.Split(arr[0], "=") + if kv[0] != "type" { + return nil, errInvalidSyntax + } + switch kv[1] { + case "bind": + mountInfo.Type = string(cc.TypeBind) + case "tmpfs": + mountInfo.Type = string(cc.TypeTmpfs) + mountInfo.Source = string(cc.TypeTmpfs) + mountInfo.Options = append(mountInfo.Options, []string{"rprivate", "noexec", "nosuid", "nodev", "size=65536k"}...) + + default: + return nil, errors.Errorf("invalid filesystem type %q", kv[1]) + } + + tokens := strings.Split(arr[1], ",") + for i, val := range tokens { + if i == (tokenCount - 1) { + //Parse tokens before options. + break + } + kv := strings.Split(val, "=") + switch kv[0] { + case "ro", "nosuid", "nodev", "noexec": + mountInfo.Options = append(mountInfo.Options, kv[0]) + case "shared", "rshared", "private", "rprivate", "slave", "rslave", "Z", "z": + if mountInfo.Type != "bind" { + return nil, errors.Errorf("%s can only be used with bind mounts", kv[0]) + } + mountInfo.Options = append(mountInfo.Options, kv[0]) + case "tmpfs-mode": + if mountInfo.Type != "tmpfs" { + return nil, errors.Errorf("%s can only be used with tmpfs mounts", kv[0]) + } + mountInfo.Options = append(mountInfo.Options, fmt.Sprintf("mode=%s", kv[1])) + case "tmpfs-size": + if mountInfo.Type != "tmpfs" { + return nil, errors.Errorf("%s can only be used with tmpfs mounts", kv[0]) + } + shmSize, err := units.FromHumanSize(kv[1]) + if err != nil { + return nil, errors.Wrapf(err, "unable to translate tmpfs-size") + } + + mountInfo.Options = append(mountInfo.Options, fmt.Sprintf("size=%d", shmSize)) + + case "bind-propagation": + if mountInfo.Type != "bind" { + return nil, errors.Errorf("%s can only be used with bind mounts", kv[0]) + } + mountInfo.Options = append(mountInfo.Options, kv[1]) + case "src", "source": + if mountInfo.Type == "tmpfs" { + return nil, errors.Errorf("can not use src= on a tmpfs file system") + } + if err := validateVolumeHostDir(kv[1]); err != nil { + return nil, err + } + mountInfo.Source = kv[1] + case "target", "dst", "destination": + if err := validateVolumeCtrDir(kv[1]); err != nil { + return nil, err + } + mountInfo.Destination = kv[1] + default: + return nil, errors.Errorf("incorrect mount option : %s", kv[0]) + } + } + mountList = append(mountList, mountInfo) + } + return mountList, nil +} + func parseVolumes(volumes []string) error { for _, volume := range volumes { arr := strings.SplitN(volume, ":", 3) |