Merge pull request #2033 from rhatdan/devices

Allow users to specify a directory for additonal devices
This commit is contained in:
OpenShift Merge Robot
2018-12-21 12:09:46 -08:00
committed by GitHub
9 changed files with 62 additions and 12 deletions

View File

@ -106,7 +106,7 @@ to be long lived. While Buildah containers are really just created to allow con
to be added back to the container image. An easy way to think of it is the
`buildah run` command emulates the RUN command in a Dockerfile while the `podman run`
command emulates the `docker run` command in functionality. Because of this and their underlying
storage differences, you can not see Podman containers from within Buildah or vice versa.
storage differences, you cannot see Podman containers from within Buildah or vice versa.
In short Buildah is an efficient way to create OCI images while Podman allows
you to manage and maintain those images and containers in a production environment using

View File

@ -462,7 +462,7 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
tty := c.Bool("tty")
if c.Bool("detach") && c.Bool("rm") {
return nil, errors.Errorf("--rm and --detach can not be specified together")
return nil, errors.Errorf("--rm and --detach cannot be specified together")
}
if c.Int64("cpu-period") != 0 && c.Float64("cpus") > 0 {
return nil, errors.Errorf("--cpu-period and --cpus cannot be set together")

View File

@ -144,7 +144,7 @@ func parseMounts(mounts []string) ([]spec.Mount, error) {
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")
return nil, errors.Errorf("cannot use src= on a tmpfs file system")
}
if err := validateVolumeHostDir(kv[1]); err != nil {
return nil, err
@ -288,7 +288,7 @@ func verifyContainerResources(config *cc.CreateConfig, update bool) ([]string, e
return warnings, fmt.Errorf("minimum memory reservation allowed is 4MB")
}
if config.Resources.Memory > 0 && config.Resources.MemoryReservation > 0 && config.Resources.Memory < config.Resources.MemoryReservation {
return warnings, fmt.Errorf("minimum memory limit can not be less than memory reservation limit, see usage")
return warnings, fmt.Errorf("minimum memory limit cannot be less than memory reservation limit, see usage")
}
if config.Resources.KernelMemory > 0 && !sysInfo.KernelMemory {
warnings = addWarning(warnings, "Your kernel does not support kernel memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
@ -318,14 +318,14 @@ func verifyContainerResources(config *cc.CreateConfig, update bool) ([]string, e
config.Resources.CPUPeriod = 0
}
if config.Resources.CPUPeriod != 0 && (config.Resources.CPUPeriod < 1000 || config.Resources.CPUPeriod > 1000000) {
return warnings, fmt.Errorf("CPU cfs period can not be less than 1ms (i.e. 1000) or larger than 1s (i.e. 1000000)")
return warnings, fmt.Errorf("CPU cfs period cannot be less than 1ms (i.e. 1000) or larger than 1s (i.e. 1000000)")
}
if config.Resources.CPUQuota > 0 && !sysInfo.CPUCfsQuota {
warnings = addWarning(warnings, "Your kernel does not support CPU cfs quota or the cgroup is not mounted. Quota discarded.")
config.Resources.CPUQuota = 0
}
if config.Resources.CPUQuota > 0 && config.Resources.CPUQuota < 1000 {
return warnings, fmt.Errorf("CPU cfs quota can not be less than 1ms (i.e. 1000)")
return warnings, fmt.Errorf("CPU cfs quota cannot be less than 1ms (i.e. 1000)")
}
// cpuset subsystem checks and adjustments
if (config.Resources.CPUsetCPUs != "" || config.Resources.CPUsetMems != "") && !sysInfo.Cpuset {

View File

@ -84,7 +84,7 @@ func (n UTSMode) Valid() bool {
// IpcMode represents the container ipc stack.
type IpcMode string
// IsPrivate indicates whether the container uses its own private ipc namespace which can not be shared.
// IsPrivate indicates whether the container uses its own private ipc namespace which cannot be shared.
func (n IpcMode) IsPrivate() bool {
return n == "private"
}

View File

@ -3,7 +3,11 @@
package createconfig
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/docker/docker/profiles/seccomp"
"github.com/opencontainers/runc/libcontainer/configs"
@ -27,6 +31,52 @@ func Device(d *configs.Device) spec.LinuxDevice {
}
}
// devicesFromPath computes a list of devices
func devicesFromPath(g *generate.Generator, devicePath string) error {
devs := strings.Split(devicePath, ":")
resolvedDevicePath := devs[0]
// check if it is a symbolic link
if src, err := os.Lstat(resolvedDevicePath); err == nil && src.Mode()&os.ModeSymlink == os.ModeSymlink {
if linkedPathOnHost, err := filepath.EvalSymlinks(resolvedDevicePath); err == nil {
resolvedDevicePath = linkedPathOnHost
}
}
st, err := os.Stat(resolvedDevicePath)
if err != nil {
return errors.Wrapf(err, "cannot stat %s", devicePath)
}
if st.IsDir() {
if len(devs) > 2 {
return errors.Wrapf(unix.EINVAL, "not allowed to specify destination with a directory %s", devicePath)
}
found := false
// mount the internal devices recursively
if err := filepath.Walk(resolvedDevicePath, func(dpath string, f os.FileInfo, e error) error {
if f.Mode()&os.ModeDevice == os.ModeDevice {
found = true
device := dpath
if len(devs) > 1 {
device = fmt.Sprintf("%s:%s", dpath, devs[1])
}
if err := addDevice(g, device); err != nil {
return errors.Wrapf(err, "failed to add %s device", dpath)
}
}
return nil
}); err != nil {
return err
}
if !found {
return errors.Wrapf(unix.EINVAL, "no devices found in %s", devicePath)
}
return nil
}
return addDevice(g, devicePath)
}
func addDevice(g *generate.Generator, device string) error {
src, dst, permissions, err := ParseDevice(device)
if err != nil {

View File

@ -166,7 +166,7 @@ func ParseDevice(device string) (string, string, string, error) { //nolint
permissions = arr[1]
} else {
if arr[1][0] != '/' {
return "", "", "", fmt.Errorf("invalid device mode: %s", arr[2])
return "", "", "", fmt.Errorf("invalid device mode: %s", arr[1])
}
dst = arr[1]
}

View File

@ -235,8 +235,8 @@ func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint
}
}
} else {
for _, device := range config.Devices {
if err := addDevice(&g, device); err != nil {
for _, devicePath := range config.Devices {
if err := devicesFromPath(&g, devicePath); err != nil {
return nil, err
}
}

View File

@ -36,7 +36,7 @@ var _ = Describe("Common functions test", func() {
It("Test SystemExec", func() {
session := SystemExec(GoechoPath, []string{})
Expect(session.Command.Process).ShouldNot(BeNil(), "SystemExec can not start a process")
Expect(session.Command.Process).ShouldNot(BeNil(), "SystemExec cannot start a process")
})
It("Test StringInSlice", func() {

View File

@ -18,7 +18,7 @@ and retry your command before reporting the issue.
---
### 2) No such image or Bare keys cannot contain ':'
When doing a `podman pull` or `podman build` command and a "common" image can not be pulled,
When doing a `podman pull` or `podman build` command and a "common" image cannot be pulled,
it is likely that the `/etc/containers/registries.conf` file is either not installed or possibly
misconfigured.