diff options
author | baude <bbaude@redhat.com> | 2018-07-04 10:51:20 -0500 |
---|---|---|
committer | Atomic Bot <atomic-devel@projectatomic.io> | 2018-07-05 16:05:12 +0000 |
commit | cc6f0e85f994cab66fb63c4dd8b77b4332151748 (patch) | |
tree | 6b54655b66a8571945ccda1601533717c8375906 | |
parent | 33870ea2c3a3aa4e2bd3da3d84b21820c75eaf23 (diff) | |
download | podman-cc6f0e85f994cab66fb63c4dd8b77b4332151748.tar.gz podman-cc6f0e85f994cab66fb63c4dd8b77b4332151748.tar.bz2 podman-cc6f0e85f994cab66fb63c4dd8b77b4332151748.zip |
more changes to compile darwin
this should represent the last major changes to get darwin to **compile**. again,
the purpose here is to get darwin to compile so that we can eventually implement a
ci task that would protect against regressions for darwin compilation.
i have left the manual darwin compilation largely static still and in fact now only
interject (manually) two build tags to assist with the build. trevor king has great
ideas on how to make this better and i will defer final implementation of those
to him.
Signed-off-by: baude <bbaude@redhat.com>
Closes: #1047
Approved by: rhatdan
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | libpod/boltdb_state.go | 33 | ||||
-rw-r--r-- | libpod/boltdb_state_internal.go | 60 | ||||
-rw-r--r-- | libpod/boltdb_state_linux.go | 67 | ||||
-rw-r--r-- | libpod/boltdb_state_unsupported.go | 11 | ||||
-rw-r--r-- | libpod/container_inspect.go | 31 | ||||
-rw-r--r-- | libpod/container_internal.go | 249 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 265 | ||||
-rw-r--r-- | libpod/container_internal_unsupported.go | 26 | ||||
-rw-r--r-- | libpod/container_linux.go | 38 | ||||
-rw-r--r-- | libpod/container_unsupported.go | 8 | ||||
-rw-r--r-- | libpod/finished_64.go | 2 | ||||
-rw-r--r-- | libpod/finished_unsupported.go | 12 | ||||
-rw-r--r-- | libpod/networking_linux.go | 33 | ||||
-rw-r--r-- | libpod/networking_unsupported.go | 27 | ||||
-rw-r--r-- | libpod/oci.go | 61 | ||||
-rw-r--r-- | libpod/oci_linux.go | 63 | ||||
-rw-r--r-- | libpod/oci_unsupported.go | 15 | ||||
-rw-r--r-- | pkg/rootless/rootless_unsupported.go | 5 | ||||
-rw-r--r-- | pkg/spec/config_linux.go | 85 | ||||
-rw-r--r-- | pkg/spec/config_unsupported.go | 16 | ||||
-rw-r--r-- | pkg/spec/createconfig.go | 84 |
22 files changed, 681 insertions, 514 deletions
@@ -18,7 +18,7 @@ ETCDIR_LIBPOD ?= ${ETCDIR}/crio TMPFILESDIR ?= ${PREFIX}/lib/tmpfiles.d SYSTEMDDIR ?= ${PREFIX}/lib/systemd/system BUILDTAGS ?= seccomp $(shell hack/btrfs_tag.sh) $(shell hack/libdm_tag.sh) $(shell hack/btrfs_installed_tag.sh) $(shell hack/ostree_tag.sh) $(shell hack/selinux_tag.sh) varlink - +BUILDTAGS_DARWIN ?= containers_image_ostree_stub containers_image_openpgp ifneq (,$(findstring varlink,$(BUILDTAGS))) PODMAN_VARLINK_DEPENDENCIES = cmd/podman/varlink/ioprojectatomicpodman.go endif @@ -99,7 +99,7 @@ podman: .gopathok $(PODMAN_VARLINK_DEPENDENCIES) $(GO) build -i -ldflags '$(LDFLAGS_PODMAN)' -tags "$(BUILDTAGS)" -o bin/$@ $(PROJECT)/cmd/podman darwin: - GOOS=darwin $(GO) build -ldflags '$(LDFLAGS_PODMAN)' -tags "$(BUILDTAGS)" -o bin/darwin$@ $(PROJECT)/cmd/podman + GOOS=darwin $(GO) build -ldflags '$(LDFLAGS_PODMAN)' -tags "$(BUILDTAGS_DARWIN)" -o bin/podman.$@ $(PROJECT)/cmd/podman python-podman: ifdef HAS_PYTHON3 diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go index d7c950fa0..45d09348e 100644 --- a/libpod/boltdb_state.go +++ b/libpod/boltdb_state.go @@ -7,7 +7,6 @@ import ( "github.com/boltdb/bolt" "github.com/pkg/errors" - "github.com/sirupsen/logrus" ) // BoltState is a state implementation backed by a Bolt DB @@ -443,32 +442,7 @@ func (s *BoltState) UpdateContainer(ctr *Container) error { } // Do we need to replace the container's netns? - if netNSPath != "" { - // Check if the container's old state has a good netns - if ctr.state.NetNS != nil && netNSPath == ctr.state.NetNS.Path() { - newState.NetNS = ctr.state.NetNS - } else { - // Tear down the existing namespace - if err := s.runtime.teardownNetNS(ctr); err != nil { - logrus.Warnf(err.Error()) - } - - // Open the new network namespace - ns, err := joinNetNS(netNSPath) - if err == nil { - newState.NetNS = ns - } else { - logrus.Errorf("error joining network namespace for container %s", ctr.ID()) - ctr.valid = false - } - } - } else { - // The container no longer has a network namespace - // Tear down the old one - if err := s.runtime.teardownNetNS(ctr); err != nil { - logrus.Warnf(err.Error()) - } - } + ctr.setNamespace(netNSPath, newState) // New state compiled successfully, swap it into the current state ctr.state = newState @@ -490,10 +464,7 @@ func (s *BoltState) SaveContainer(ctr *Container) error { if err != nil { return errors.Wrapf(err, "error marshalling container %s state to JSON", ctr.ID()) } - netNSPath := "" - if ctr.state.NetNS != nil { - netNSPath = ctr.state.NetNS.Path() - } + netNSPath := ctr.setNamespaceStatePath() ctrID := []byte(ctr.ID()) diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go index e8aa6860b..69e7bee21 100644 --- a/libpod/boltdb_state_internal.go +++ b/libpod/boltdb_state_internal.go @@ -205,60 +205,6 @@ func getRuntimeConfigBucket(tx *bolt.Tx) (*bolt.Bucket, error) { return bkt, nil } -func (s *BoltState) getContainerFromDB(id []byte, ctr *Container, ctrsBkt *bolt.Bucket) error { - valid := true - ctrBkt := ctrsBkt.Bucket(id) - if ctrBkt == nil { - return errors.Wrapf(ErrNoSuchCtr, "container %s not found in DB", string(id)) - } - - configBytes := ctrBkt.Get(configKey) - if configBytes == nil { - return errors.Wrapf(ErrInternal, "container %s missing config key in DB", string(id)) - } - - stateBytes := ctrBkt.Get(stateKey) - if stateBytes == nil { - return errors.Wrapf(ErrInternal, "container %s missing state key in DB", string(id)) - } - - netNSBytes := ctrBkt.Get(netNSKey) - - if err := json.Unmarshal(configBytes, ctr.config); err != nil { - return errors.Wrapf(err, "error unmarshalling container %s config", string(id)) - } - - if err := json.Unmarshal(stateBytes, ctr.state); err != nil { - return errors.Wrapf(err, "error unmarshalling container %s state", string(id)) - } - - // The container may not have a network namespace, so it's OK if this is - // nil - if netNSBytes != nil { - nsPath := string(netNSBytes) - netNS, err := joinNetNS(nsPath) - if err == nil { - ctr.state.NetNS = netNS - } else { - logrus.Errorf("error joining network namespace for container %s", ctr.ID()) - valid = false - } - } - - // Get the lock - lockPath := filepath.Join(s.lockDir, string(id)) - lock, err := storage.GetLockfile(lockPath) - if err != nil { - return errors.Wrapf(err, "error retrieving lockfile for container %s", string(id)) - } - ctr.lock = lock - - ctr.runtime = s.runtime - ctr.valid = valid - - return nil -} - func (s *BoltState) getPodFromDB(id []byte, pod *Pod, podBkt *bolt.Bucket) error { podDB := podBkt.Bucket(id) if podDB == nil { @@ -310,11 +256,7 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error { if err != nil { return errors.Wrapf(err, "error marshalling container %s state to JSON", ctr.ID()) } - netNSPath := "" - if ctr.state.NetNS != nil { - netNSPath = ctr.state.NetNS.Path() - } - + netNSPath := ctr.setNamespaceStatePath() dependsCtrs := ctr.Dependencies() ctrID := []byte(ctr.ID()) diff --git a/libpod/boltdb_state_linux.go b/libpod/boltdb_state_linux.go new file mode 100644 index 000000000..ceea955bd --- /dev/null +++ b/libpod/boltdb_state_linux.go @@ -0,0 +1,67 @@ +// +build linux + +package libpod + +import ( + "encoding/json" + "path/filepath" + + "github.com/boltdb/bolt" + "github.com/containers/storage" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +func (s *BoltState) getContainerFromDB(id []byte, ctr *Container, ctrsBkt *bolt.Bucket) error { + valid := true + ctrBkt := ctrsBkt.Bucket(id) + if ctrBkt == nil { + return errors.Wrapf(ErrNoSuchCtr, "container %s not found in DB", string(id)) + } + + configBytes := ctrBkt.Get(configKey) + if configBytes == nil { + return errors.Wrapf(ErrInternal, "container %s missing config key in DB", string(id)) + } + + stateBytes := ctrBkt.Get(stateKey) + if stateBytes == nil { + return errors.Wrapf(ErrInternal, "container %s missing state key in DB", string(id)) + } + + netNSBytes := ctrBkt.Get(netNSKey) + + if err := json.Unmarshal(configBytes, ctr.config); err != nil { + return errors.Wrapf(err, "error unmarshalling container %s config", string(id)) + } + + if err := json.Unmarshal(stateBytes, ctr.state); err != nil { + return errors.Wrapf(err, "error unmarshalling container %s state", string(id)) + } + + // The container may not have a network namespace, so it's OK if this is + // nil + if netNSBytes != nil { + nsPath := string(netNSBytes) + netNS, err := joinNetNS(nsPath) + if err == nil { + ctr.state.NetNS = netNS + } else { + logrus.Errorf("error joining network namespace for container %s", ctr.ID()) + valid = false + } + } + + // Get the lock + lockPath := filepath.Join(s.lockDir, string(id)) + lock, err := storage.GetLockfile(lockPath) + if err != nil { + return errors.Wrapf(err, "error retrieving lockfile for container %s", string(id)) + } + ctr.lock = lock + + ctr.runtime = s.runtime + ctr.valid = valid + + return nil +} diff --git a/libpod/boltdb_state_unsupported.go b/libpod/boltdb_state_unsupported.go new file mode 100644 index 000000000..8d3749881 --- /dev/null +++ b/libpod/boltdb_state_unsupported.go @@ -0,0 +1,11 @@ +// +build !linux + +package libpod + +import ( + "github.com/boltdb/bolt" +) + +func (s *BoltState) getContainerFromDB(id []byte, ctr *Container, ctrsBkt *bolt.Bucket) error { + return ErrNotImplemented +} diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go index 1381341c2..a1070cf99 100644 --- a/libpod/container_inspect.go +++ b/libpod/container_inspect.go @@ -1,9 +1,6 @@ package libpod import ( - "strconv" - "strings" - "github.com/cri-o/ocicni/pkg/ocicni" "github.com/projectatomic/libpod/pkg/inspect" "github.com/sirupsen/logrus" @@ -114,33 +111,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *inspect.Data) } // Get information on the container's network namespace (if present) - if runtimeInfo.NetNS != nil { - // Go through our IP addresses - for _, ctrIP := range c.state.IPs { - ipWithMask := ctrIP.Address.String() - splitIP := strings.Split(ipWithMask, "/") - mask, _ := strconv.Atoi(splitIP[1]) - if ctrIP.Version == "4" { - data.NetworkSettings.IPAddress = splitIP[0] - data.NetworkSettings.IPPrefixLen = mask - data.NetworkSettings.Gateway = ctrIP.Gateway.String() - } else { - data.NetworkSettings.GlobalIPv6Address = splitIP[0] - data.NetworkSettings.GlobalIPv6PrefixLen = mask - data.NetworkSettings.IPv6Gateway = ctrIP.Gateway.String() - } - } - - // Set network namespace path - data.NetworkSettings.SandboxKey = runtimeInfo.NetNS.Path() - - // Set MAC address of interface linked with network namespace path - for _, i := range c.state.Interfaces { - if i.Sandbox == data.NetworkSettings.SandboxKey { - data.NetworkSettings.MacAddress = i.Mac - } - } - } + data = c.getContainerNetworkInfo(data) if size { rootFsSize, err := c.rootFsSize() diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 22b398709..452be176c 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -8,7 +8,6 @@ import ( "io" "io/ioutil" "os" - "path" "path/filepath" "strings" "syscall" @@ -17,14 +16,12 @@ import ( "github.com/containers/storage" "github.com/containers/storage/pkg/archive" "github.com/containers/storage/pkg/chrootarchive" - "github.com/containers/storage/pkg/idtools" "github.com/docker/docker/pkg/mount" "github.com/docker/docker/pkg/stringid" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate" "github.com/opencontainers/selinux/go-selinux/label" "github.com/pkg/errors" - crioAnnotations "github.com/projectatomic/libpod/pkg/annotations" "github.com/projectatomic/libpod/pkg/chrootuser" "github.com/projectatomic/libpod/pkg/hooks" "github.com/projectatomic/libpod/pkg/hooks/exec" @@ -33,7 +30,6 @@ import ( "github.com/projectatomic/libpod/pkg/util" "github.com/sirupsen/logrus" "github.com/ulule/deepcopier" - "golang.org/x/sys/unix" "golang.org/x/text/language" ) @@ -748,9 +744,8 @@ func (c *Container) mountStorage() (err error) { if !mounted { shmOptions := fmt.Sprintf("mode=1777,size=%d", c.config.ShmSize) - if err := unix.Mount("shm", c.config.ShmDir, "tmpfs", unix.MS_NOEXEC|unix.MS_NOSUID|unix.MS_NODEV, - label.FormatMountLabel(shmOptions, c.config.MountLabel)); err != nil { - return errors.Wrapf(err, "failed to mount shm tmpfs %q", c.config.ShmDir) + if err := c.mountSHM(shmOptions); err != nil { + return err } if err := os.Chown(c.config.ShmDir, c.RootUID(), c.RootGID()); err != nil { return errors.Wrapf(err, "failed to chown %s", c.config.ShmDir) @@ -786,53 +781,6 @@ func (c *Container) mountStorage() (err error) { return c.save() } -// prepare mounts the container and sets up other required resources like net -// namespaces -func (c *Container) prepare() (err error) { - // Mount storage if not mounted - if err := c.mountStorage(); err != nil { - return err - } - - // Set up network namespace if not already set up - if c.config.CreateNetNS && c.state.NetNS == nil && !c.config.PostConfigureNetNS { - if err := c.runtime.createNetNS(c); err != nil { - // Tear down storage before exiting to make sure we - // don't leak mounts - if err2 := c.cleanupStorage(); err2 != nil { - logrus.Errorf("Error cleaning up storage for container %s: %v", c.ID(), err2) - } - return err - } - } - - return nil -} - -// cleanupNetwork unmounts and cleans up the container's network -func (c *Container) cleanupNetwork() error { - if c.state.NetNS == nil { - logrus.Debugf("Network is already cleaned up, skipping...") - return nil - } - - // Stop the container's network namespace (if it has one) - if err := c.runtime.teardownNetNS(c); err != nil { - logrus.Errorf("unable to cleanup network for container %s: %q", c.ID(), err) - } - - c.state.NetNS = nil - c.state.IPs = nil - c.state.Interfaces = nil - c.state.Routes = nil - - if c.valid { - return c.save() - } - - return nil -} - // cleanupStorage unmounts and cleans up the container's root filesystem func (c *Container) cleanupStorage() error { if !c.state.Mounted { @@ -842,10 +790,8 @@ func (c *Container) cleanupStorage() error { } for _, mount := range c.config.Mounts { - if err := unix.Unmount(mount, unix.MNT_DETACH); err != nil { - if err != syscall.EINVAL { - logrus.Warnf("container %s failed to unmount %s : %v", c.ID(), mount, err) - } + if err := c.unmountSHM(mount); err != nil { + return err } } if c.config.Rootfs != "" { @@ -1178,193 +1124,6 @@ func (c *Container) generateHosts() (string, error) { return c.writeStringToRundir("hosts", hosts) } -// Generate spec for a container -// Accepts a map of the container's dependencies -func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { - g := generate.NewFromSpec(c.config.Spec) - - // If network namespace was requested, add it now - if c.config.CreateNetNS { - if c.config.PostConfigureNetNS { - g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, "") - } else { - g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, c.state.NetNS.Path()) - } - } - - // Remove the default /dev/shm mount to ensure we overwrite it - g.RemoveMount("/dev/shm") - - // Add bind mounts to container - for dstPath, srcPath := range c.state.BindMounts { - newMount := spec.Mount{ - Type: "bind", - Source: srcPath, - Destination: dstPath, - Options: []string{"rw", "bind"}, - } - if !MountExists(g.Mounts(), dstPath) { - g.AddMount(newMount) - } else { - logrus.Warnf("User mount overriding libpod mount at %q", dstPath) - } - } - - var err error - if !rootless.IsRootless() { - if c.state.ExtensionStageHooks, err = c.setupOCIHooks(ctx, g.Config); err != nil { - return nil, errors.Wrapf(err, "error setting up OCI Hooks") - } - } - - // Bind builtin image volumes - if c.config.Rootfs == "" && c.config.ImageVolumes { - if err := c.addImageVolumes(ctx, &g); err != nil { - return nil, errors.Wrapf(err, "error mounting image volumes") - } - } - - if c.config.User != "" { - if !c.state.Mounted { - return nil, errors.Wrapf(ErrCtrStateInvalid, "container %s must be mounted in order to translate User field", c.ID()) - } - uid, gid, err := chrootuser.GetUser(c.state.Mountpoint, c.config.User) - if err != nil { - return nil, err - } - // User and Group must go together - g.SetProcessUID(uid) - g.SetProcessGID(gid) - } - - // Add addition groups if c.config.GroupAdd is not empty - if len(c.config.Groups) > 0 { - if !c.state.Mounted { - return nil, errors.Wrapf(ErrCtrStateInvalid, "container %s must be mounted in order to add additional groups", c.ID()) - } - for _, group := range c.config.Groups { - gid, err := chrootuser.GetGroup(c.state.Mountpoint, group) - if err != nil { - return nil, err - } - g.AddProcessAdditionalGid(gid) - } - } - - // Look up and add groups the user belongs to, if a group wasn't directly specified - if !rootless.IsRootless() && !strings.Contains(c.config.User, ":") { - groups, err := chrootuser.GetAdditionalGroupsForUser(c.state.Mountpoint, uint64(g.Config.Process.User.UID)) - if err != nil && errors.Cause(err) != chrootuser.ErrNoSuchUser { - return nil, err - } - for _, gid := range groups { - g.AddProcessAdditionalGid(gid) - } - } - - // Add shared namespaces from other containers - if c.config.IPCNsCtr != "" { - if err := c.addNamespaceContainer(&g, IPCNS, c.config.IPCNsCtr, spec.IPCNamespace); err != nil { - return nil, err - } - } - if c.config.MountNsCtr != "" { - if err := c.addNamespaceContainer(&g, MountNS, c.config.MountNsCtr, spec.MountNamespace); err != nil { - return nil, err - } - } - if c.config.NetNsCtr != "" { - if err := c.addNamespaceContainer(&g, NetNS, c.config.NetNsCtr, spec.NetworkNamespace); err != nil { - return nil, err - } - } - if c.config.PIDNsCtr != "" { - if err := c.addNamespaceContainer(&g, PIDNS, c.config.PIDNsCtr, string(spec.PIDNamespace)); err != nil { - return nil, err - } - } - if c.config.UserNsCtr != "" { - if err := c.addNamespaceContainer(&g, UserNS, c.config.UserNsCtr, spec.UserNamespace); err != nil { - return nil, err - } - } - if c.config.UTSNsCtr != "" { - if err := c.addNamespaceContainer(&g, UTSNS, c.config.UTSNsCtr, spec.UTSNamespace); err != nil { - return nil, err - } - } - if c.config.CgroupNsCtr != "" { - if err := c.addNamespaceContainer(&g, CgroupNS, c.config.CgroupNsCtr, spec.CgroupNamespace); err != nil { - return nil, err - } - } - - if c.config.Rootfs == "" { - if err := idtools.MkdirAllAs(c.state.RealMountpoint, 0700, c.RootUID(), c.RootGID()); err != nil { - return nil, err - } - } - - g.SetRootPath(c.state.RealMountpoint) - g.AddAnnotation(crioAnnotations.Created, c.config.CreatedTime.Format(time.RFC3339Nano)) - g.AddAnnotation("org.opencontainers.image.stopSignal", fmt.Sprintf("%d", c.config.StopSignal)) - - g.SetHostname(c.Hostname()) - g.AddProcessEnv("HOSTNAME", g.Config.Hostname) - - // Only add container environment variable if not already present - foundContainerEnv := false - for _, env := range g.Config.Process.Env { - if strings.HasPrefix(env, "container=") { - foundContainerEnv = true - break - } - } - if !foundContainerEnv { - g.AddProcessEnv("container", "libpod") - } - - if rootless.IsRootless() { - g.SetLinuxCgroupsPath("") - } else if c.runtime.config.CgroupManager == SystemdCgroupsManager { - // When runc is set to use Systemd as a cgroup manager, it - // expects cgroups to be passed as follows: - // slice:prefix:name - systemdCgroups := fmt.Sprintf("%s:libpod:%s", path.Base(c.config.CgroupParent), c.ID()) - logrus.Debugf("Setting CGroups for container %s to %s", c.ID(), systemdCgroups) - g.SetLinuxCgroupsPath(systemdCgroups) - } else { - cgroupPath, err := c.CGroupPath() - if err != nil { - return nil, err - } - logrus.Debugf("Setting CGroup path for container %s to %s", c.ID(), cgroupPath) - g.SetLinuxCgroupsPath(cgroupPath) - } - - return g.Config, nil -} - -// Add an existing container's namespace to the spec -func (c *Container) addNamespaceContainer(g *generate.Generator, ns LinuxNS, ctr string, specNS string) error { - nsCtr, err := c.runtime.state.Container(ctr) - if err != nil { - return errors.Wrapf(err, "error retrieving dependency %s of container %s from state", ctr, c.ID()) - } - - // TODO need unlocked version of this for use in pods - nsPath, err := nsCtr.NamespacePath(ns) - if err != nil { - return err - } - - if err := g.AddOrReplaceLinuxNamespace(specNS, nsPath); err != nil { - return err - } - - return nil -} - func (c *Container) addImageVolumes(ctx context.Context, g *generate.Generator) error { mountPoint := c.state.Mountpoint if !c.state.Mounted { diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 41b8a86fc..327c78045 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -3,11 +3,25 @@ package libpod import ( + "context" "fmt" + "path" "path/filepath" + "strings" + "syscall" + "time" "github.com/containerd/cgroups" + "github.com/containers/storage/pkg/idtools" + spec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/runtime-tools/generate" + "github.com/opencontainers/selinux/go-selinux/label" + "github.com/pkg/errors" + crioAnnotations "github.com/projectatomic/libpod/pkg/annotations" + "github.com/projectatomic/libpod/pkg/chrootuser" + "github.com/projectatomic/libpod/pkg/rootless" "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" ) // cleanupCgroup cleans up residual CGroups after container execution @@ -50,3 +64,254 @@ func (c *Container) cleanupCgroups() error { return nil } + +func (c *Container) mountSHM(shmOptions string) error { + if err := unix.Mount("shm", c.config.ShmDir, "tmpfs", unix.MS_NOEXEC|unix.MS_NOSUID|unix.MS_NODEV, + label.FormatMountLabel(shmOptions, c.config.MountLabel)); err != nil { + return errors.Wrapf(err, "failed to mount shm tmpfs %q", c.config.ShmDir) + } + return nil +} + +func (c *Container) unmountSHM(mount string) error { + if err := unix.Unmount(mount, unix.MNT_DETACH); err != nil { + if err != syscall.EINVAL { + logrus.Warnf("container %s failed to unmount %s : %v", c.ID(), mount, err) + } + } + return nil +} + +// prepare mounts the container and sets up other required resources like net +// namespaces +func (c *Container) prepare() (err error) { + // Mount storage if not mounted + if err := c.mountStorage(); err != nil { + return err + } + + // Set up network namespace if not already set up + if c.config.CreateNetNS && c.state.NetNS == nil && !c.config.PostConfigureNetNS { + if err := c.runtime.createNetNS(c); err != nil { + // Tear down storage before exiting to make sure we + // don't leak mounts + if err2 := c.cleanupStorage(); err2 != nil { + logrus.Errorf("Error cleaning up storage for container %s: %v", c.ID(), err2) + } + return err + } + } + + return nil +} + +// cleanupNetwork unmounts and cleans up the container's network +func (c *Container) cleanupNetwork() error { + if c.state.NetNS == nil { + logrus.Debugf("Network is already cleaned up, skipping...") + return nil + } + + // Stop the container's network namespace (if it has one) + if err := c.runtime.teardownNetNS(c); err != nil { + logrus.Errorf("unable to cleanup network for container %s: %q", c.ID(), err) + } + + c.state.NetNS = nil + c.state.IPs = nil + c.state.Interfaces = nil + c.state.Routes = nil + + if c.valid { + return c.save() + } + + return nil +} + +// Generate spec for a container +// Accepts a map of the container's dependencies +func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { + g := generate.NewFromSpec(c.config.Spec) + + // If network namespace was requested, add it now + if c.config.CreateNetNS { + if c.config.PostConfigureNetNS { + g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, "") + } else { + g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, c.state.NetNS.Path()) + } + } + + // Remove the default /dev/shm mount to ensure we overwrite it + g.RemoveMount("/dev/shm") + + // Add bind mounts to container + for dstPath, srcPath := range c.state.BindMounts { + newMount := spec.Mount{ + Type: "bind", + Source: srcPath, + Destination: dstPath, + Options: []string{"rw", "bind"}, + } + if !MountExists(g.Mounts(), dstPath) { + g.AddMount(newMount) + } else { + logrus.Warnf("User mount overriding libpod mount at %q", dstPath) + } + } + + var err error + if !rootless.IsRootless() { + if c.state.ExtensionStageHooks, err = c.setupOCIHooks(ctx, g.Config); err != nil { + return nil, errors.Wrapf(err, "error setting up OCI Hooks") + } + } + + // Bind builtin image volumes + if c.config.Rootfs == "" && c.config.ImageVolumes { + if err := c.addImageVolumes(ctx, &g); err != nil { + return nil, errors.Wrapf(err, "error mounting image volumes") + } + } + + if c.config.User != "" { + if !c.state.Mounted { + return nil, errors.Wrapf(ErrCtrStateInvalid, "container %s must be mounted in order to translate User field", c.ID()) + } + uid, gid, err := chrootuser.GetUser(c.state.Mountpoint, c.config.User) + if err != nil { + return nil, err + } + // User and Group must go together + g.SetProcessUID(uid) + g.SetProcessGID(gid) + } + + // Add addition groups if c.config.GroupAdd is not empty + if len(c.config.Groups) > 0 { + if !c.state.Mounted { + return nil, errors.Wrapf(ErrCtrStateInvalid, "container %s must be mounted in order to add additional groups", c.ID()) + } + for _, group := range c.config.Groups { + gid, err := chrootuser.GetGroup(c.state.Mountpoint, group) + if err != nil { + return nil, err + } + g.AddProcessAdditionalGid(gid) + } + } + + // Look up and add groups the user belongs to, if a group wasn't directly specified + if !rootless.IsRootless() && !strings.Contains(c.config.User, ":") { + groups, err := chrootuser.GetAdditionalGroupsForUser(c.state.Mountpoint, uint64(g.Config.Process.User.UID)) + if err != nil && errors.Cause(err) != chrootuser.ErrNoSuchUser { + return nil, err + } + for _, gid := range groups { + g.AddProcessAdditionalGid(gid) + } + } + + // Add shared namespaces from other containers + if c.config.IPCNsCtr != "" { + if err := c.addNamespaceContainer(&g, IPCNS, c.config.IPCNsCtr, spec.IPCNamespace); err != nil { + return nil, err + } + } + if c.config.MountNsCtr != "" { + if err := c.addNamespaceContainer(&g, MountNS, c.config.MountNsCtr, spec.MountNamespace); err != nil { + return nil, err + } + } + if c.config.NetNsCtr != "" { + if err := c.addNamespaceContainer(&g, NetNS, c.config.NetNsCtr, spec.NetworkNamespace); err != nil { + return nil, err + } + } + if c.config.PIDNsCtr != "" { + if err := c.addNamespaceContainer(&g, PIDNS, c.config.PIDNsCtr, string(spec.PIDNamespace)); err != nil { + return nil, err + } + } + if c.config.UserNsCtr != "" { + if err := c.addNamespaceContainer(&g, UserNS, c.config.UserNsCtr, spec.UserNamespace); err != nil { + return nil, err + } + } + if c.config.UTSNsCtr != "" { + if err := c.addNamespaceContainer(&g, UTSNS, c.config.UTSNsCtr, spec.UTSNamespace); err != nil { + return nil, err + } + } + if c.config.CgroupNsCtr != "" { + if err := c.addNamespaceContainer(&g, CgroupNS, c.config.CgroupNsCtr, spec.CgroupNamespace); err != nil { + return nil, err + } + } + + if c.config.Rootfs == "" { + if err := idtools.MkdirAllAs(c.state.RealMountpoint, 0700, c.RootUID(), c.RootGID()); err != nil { + return nil, err + } + } + + g.SetRootPath(c.state.RealMountpoint) + g.AddAnnotation(crioAnnotations.Created, c.config.CreatedTime.Format(time.RFC3339Nano)) + g.AddAnnotation("org.opencontainers.image.stopSignal", fmt.Sprintf("%d", c.config.StopSignal)) + + g.SetHostname(c.Hostname()) + g.AddProcessEnv("HOSTNAME", g.Config.Hostname) + + // Only add container environment variable if not already present + foundContainerEnv := false + for _, env := range g.Config.Process.Env { + if strings.HasPrefix(env, "container=") { + foundContainerEnv = true + break + } + } + if !foundContainerEnv { + g.AddProcessEnv("container", "libpod") + } + + if rootless.IsRootless() { + g.SetLinuxCgroupsPath("") + } else if c.runtime.config.CgroupManager == SystemdCgroupsManager { + // When runc is set to use Systemd as a cgroup manager, it + // expects cgroups to be passed as follows: + // slice:prefix:name + systemdCgroups := fmt.Sprintf("%s:libpod:%s", path.Base(c.config.CgroupParent), c.ID()) + logrus.Debugf("Setting CGroups for container %s to %s", c.ID(), systemdCgroups) + g.SetLinuxCgroupsPath(systemdCgroups) + } else { + cgroupPath, err := c.CGroupPath() + if err != nil { + return nil, err + } + logrus.Debugf("Setting CGroup path for container %s to %s", c.ID(), cgroupPath) + g.SetLinuxCgroupsPath(cgroupPath) + } + + return g.Config, nil +} + +// Add an existing container's namespace to the spec +func (c *Container) addNamespaceContainer(g *generate.Generator, ns LinuxNS, ctr string, specNS string) error { + nsCtr, err := c.runtime.state.Container(ctr) + if err != nil { + return errors.Wrapf(err, "error retrieving dependency %s of container %s from state", ctr, c.ID()) + } + + // TODO need unlocked version of this for use in pods + nsPath, err := nsCtr.NamespacePath(ns) + if err != nil { + return err + } + + if err := g.AddOrReplaceLinuxNamespace(specNS, nsPath); err != nil { + return err + } + + return nil +} diff --git a/libpod/container_internal_unsupported.go b/libpod/container_internal_unsupported.go index 015536850..975d6d714 100644 --- a/libpod/container_internal_unsupported.go +++ b/libpod/container_internal_unsupported.go @@ -2,6 +2,32 @@ package libpod +import ( + "context" + + spec "github.com/opencontainers/runtime-spec/specs-go" +) + func (c *Container) cleanupCgroups() error { return ErrOSNotSupported } + +func (c *Container) mountSHM(shmOptions string) error { + return ErrNotImplemented +} + +func (c *Container) unmountSHM(mount string) error { + return ErrNotImplemented +} + +func (c *Container) prepare() (err error) { + return ErrNotImplemented +} + +func (c *Container) cleanupNetwork() error { + return ErrNotImplemented +} + +func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { + return nil, ErrNotImplemented +} diff --git a/libpod/container_linux.go b/libpod/container_linux.go index 823a590dd..2330f27a7 100644 --- a/libpod/container_linux.go +++ b/libpod/container_linux.go @@ -4,6 +4,7 @@ package libpod import ( "github.com/containernetworking/plugins/pkg/ns" + "github.com/sirupsen/logrus" ) type containerPlatformState struct { @@ -13,3 +14,40 @@ type containerPlatformState struct { // told to join another container's network namespace NetNS ns.NetNS `json:"-"` } + +func (ctr *Container) setNamespace(netNSPath string, newState *containerState) error { + if netNSPath != "" { + // Check if the container's old state has a good netns + if ctr.state.NetNS != nil && netNSPath == ctr.state.NetNS.Path() { + newState.NetNS = ctr.state.NetNS + } else { + // Tear down the existing namespace + if err := ctr.runtime.teardownNetNS(ctr); err != nil { + logrus.Warnf(err.Error()) + } + + // Open the new network namespace + ns, err := joinNetNS(netNSPath) + if err == nil { + newState.NetNS = ns + } else { + logrus.Errorf("error joining network namespace for container %s", ctr.ID()) + ctr.valid = false + } + } + } else { + // The container no longer has a network namespace + // Tear down the old one + if err := ctr.runtime.teardownNetNS(ctr); err != nil { + logrus.Warnf(err.Error()) + } + } + return nil +} + +func (ctr *Container) setNamespaceStatePath() string { + if ctr.state.NetNS != nil { + return ctr.state.NetNS.Path() + } + return "" +} diff --git a/libpod/container_unsupported.go b/libpod/container_unsupported.go index e214b9465..5b923b52a 100644 --- a/libpod/container_unsupported.go +++ b/libpod/container_unsupported.go @@ -3,3 +3,11 @@ package libpod type containerPlatformState struct{} + +func (ctr *Container) setNamespace(netNSPath string, newState *containerState) error { + return ErrNotImplemented +} + +func (ctr *Container) setNamespaceStatePath() string { + return "" +} diff --git a/libpod/finished_64.go b/libpod/finished_64.go index 11dbc9181..3688afa84 100644 --- a/libpod/finished_64.go +++ b/libpod/finished_64.go @@ -1,4 +1,4 @@ -// +build !arm,!386 +// +build !arm,!386,linux package libpod diff --git a/libpod/finished_unsupported.go b/libpod/finished_unsupported.go new file mode 100644 index 000000000..a893d668c --- /dev/null +++ b/libpod/finished_unsupported.go @@ -0,0 +1,12 @@ +// +build darwin,!linux + +package libpod + +import ( + "os" + "time" +) + +func getFinishedTime(fi os.FileInfo) time.Time { + return time.Time{} +} diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index ee90b765c..59666b534 100644 --- a/libpod/networking_linux.go +++ b/libpod/networking_linux.go @@ -8,6 +8,7 @@ import ( "net" "os" "path/filepath" + "strconv" "strings" "syscall" @@ -15,6 +16,7 @@ import ( "github.com/containernetworking/plugins/pkg/ns" "github.com/cri-o/ocicni/pkg/ocicni" "github.com/pkg/errors" + "github.com/projectatomic/libpod/pkg/inspect" "github.com/projectatomic/libpod/utils" "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" @@ -228,3 +230,34 @@ func getContainerNetIO(ctr *Container) (*netlink.LinkStatistics, error) { }) return netStats, err } + +func (c *Container) getContainerNetworkInfo(data *inspect.ContainerInspectData) *inspect.ContainerInspectData { + if c.state.NetNS != nil { + // Go through our IP addresses + for _, ctrIP := range c.state.IPs { + ipWithMask := ctrIP.Address.String() + splitIP := strings.Split(ipWithMask, "/") + mask, _ := strconv.Atoi(splitIP[1]) + if ctrIP.Version == "4" { + data.NetworkSettings.IPAddress = splitIP[0] + data.NetworkSettings.IPPrefixLen = mask + data.NetworkSettings.Gateway = ctrIP.Gateway.String() + } else { + data.NetworkSettings.GlobalIPv6Address = splitIP[0] + data.NetworkSettings.GlobalIPv6PrefixLen = mask + data.NetworkSettings.IPv6Gateway = ctrIP.Gateway.String() + } + } + + // Set network namespace path + data.NetworkSettings.SandboxKey = c.state.NetNS.Path() + + // Set MAC address of interface linked with network namespace path + for _, i := range c.state.Interfaces { + if i.Sandbox == data.NetworkSettings.SandboxKey { + data.NetworkSettings.MacAddress = i.Mac + } + } + } + return data +} diff --git a/libpod/networking_unsupported.go b/libpod/networking_unsupported.go new file mode 100644 index 000000000..4ff8ecd62 --- /dev/null +++ b/libpod/networking_unsupported.go @@ -0,0 +1,27 @@ +// +build !linux + +package libpod + +import ( + "github.com/projectatomic/libpod/pkg/inspect" +) + +func JoinNetworkNameSpace(netNSBytes []byte) (*Container, bool, error) { + return nil, false, ErrNotImplemented +} + +func (r *Runtime) setupNetNS(ctr *Container) (err error) { + return ErrNotImplemented +} + +func (r *Runtime) teardownNetNS(ctr *Container) error { + return ErrNotImplemented +} + +func (r *Runtime) createNetNS(ctr *Container) (err error) { + return ErrNotImplemented +} + +func (c *Container) getContainerNetworkInfo(data *inspect.ContainerInspectData) *inspect.ContainerInspectData { + return nil +} diff --git a/libpod/oci.go b/libpod/oci.go index 20d533726..fcb36241b 100644 --- a/libpod/oci.go +++ b/libpod/oci.go @@ -11,11 +11,9 @@ import ( "runtime" "strconv" "strings" - "sync" "syscall" "time" - "github.com/containers/storage/pkg/idtools" "github.com/coreos/go-systemd/activation" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/selinux/go-selinux" @@ -110,15 +108,6 @@ func newOCIRuntime(name string, path string, conmonPath string, conmonEnv []stri return runtime, nil } -// newPipe creates a unix socket pair for communication -func newPipe() (parent *os.File, child *os.File, err error) { - fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0) - if err != nil { - return nil, nil, err - } - return os.NewFile(uintptr(fds[1]), "parent"), os.NewFile(uintptr(fds[0]), "child"), nil -} - // Create systemd unit name for cgroup scopes func createUnitName(prefix string, name string) string { return fmt.Sprintf("%s-%s.scope", prefix, name) @@ -187,56 +176,6 @@ func waitPidsStop(pids []int, timeout time.Duration) error { } } -// CreateContainer creates a container in the OCI runtime -// TODO terminal support for container -// Presently just ignoring conmon opts related to it -func (r *OCIRuntime) createContainer(ctr *Container, cgroupParent string) (err error) { - if ctr.state.UserNSRoot == "" { - // no need of an intermediate mount ns - return r.createOCIContainer(ctr, cgroupParent) - } - var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() - runtime.LockOSThread() - - fd, err := os.Open(fmt.Sprintf("/proc/%d/task/%d/ns/mnt", os.Getpid(), unix.Gettid())) - if err != nil { - return - } - defer fd.Close() - - // create a new mountns on the current thread - if err = unix.Unshare(unix.CLONE_NEWNS); err != nil { - return - } - defer unix.Setns(int(fd.Fd()), unix.CLONE_NEWNS) - - // don't spread our mounts around - err = unix.Mount("/", "/", "none", unix.MS_REC|unix.MS_SLAVE, "") - if err != nil { - return - } - err = unix.Mount(ctr.state.Mountpoint, ctr.state.RealMountpoint, "none", unix.MS_BIND, "") - if err != nil { - return - } - if err := idtools.MkdirAllAs(ctr.state.DestinationRunDir, 0700, ctr.RootUID(), ctr.RootGID()); err != nil { - return - } - - err = unix.Mount(ctr.state.RunDir, ctr.state.DestinationRunDir, "none", unix.MS_BIND, "") - if err != nil { - return - } - err = r.createOCIContainer(ctr, cgroupParent) - }() - wg.Wait() - - return err -} - func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string) (err error) { var stderrBuf bytes.Buffer diff --git a/libpod/oci_linux.go b/libpod/oci_linux.go index 14373cbb2..2128b7481 100644 --- a/libpod/oci_linux.go +++ b/libpod/oci_linux.go @@ -7,11 +7,15 @@ import ( "os" "os/exec" "path/filepath" + "runtime" + "sync" "github.com/containerd/cgroups" + "github.com/containers/storage/pkg/idtools" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/projectatomic/libpod/utils" "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" ) func (r *OCIRuntime) moveConmonToCgroup(ctr *Container, cgroupParent string, cmd *exec.Cmd) error { @@ -39,3 +43,62 @@ func (r *OCIRuntime) moveConmonToCgroup(ctr *Container, cgroupParent string, cmd } return nil } + +// newPipe creates a unix socket pair for communication +func newPipe() (parent *os.File, child *os.File, err error) { + fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0) + if err != nil { + return nil, nil, err + } + return os.NewFile(uintptr(fds[1]), "parent"), os.NewFile(uintptr(fds[0]), "child"), nil +} + +// CreateContainer creates a container in the OCI runtime +// TODO terminal support for container +// Presently just ignoring conmon opts related to it +func (r *OCIRuntime) createContainer(ctr *Container, cgroupParent string) (err error) { + if ctr.state.UserNSRoot == "" { + // no need of an intermediate mount ns + return r.createOCIContainer(ctr, cgroupParent) + } + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + runtime.LockOSThread() + + fd, err := os.Open(fmt.Sprintf("/proc/%d/task/%d/ns/mnt", os.Getpid(), unix.Gettid())) + if err != nil { + return + } + defer fd.Close() + + // create a new mountns on the current thread + if err = unix.Unshare(unix.CLONE_NEWNS); err != nil { + return + } + defer unix.Setns(int(fd.Fd()), unix.CLONE_NEWNS) + + // don't spread our mounts around + err = unix.Mount("/", "/", "none", unix.MS_REC|unix.MS_SLAVE, "") + if err != nil { + return + } + err = unix.Mount(ctr.state.Mountpoint, ctr.state.RealMountpoint, "none", unix.MS_BIND, "") + if err != nil { + return + } + if err := idtools.MkdirAllAs(ctr.state.DestinationRunDir, 0700, ctr.RootUID(), ctr.RootGID()); err != nil { + return + } + + err = unix.Mount(ctr.state.RunDir, ctr.state.DestinationRunDir, "none", unix.MS_BIND, "") + if err != nil { + return + } + err = r.createOCIContainer(ctr, cgroupParent) + }() + wg.Wait() + + return err +} diff --git a/libpod/oci_unsupported.go b/libpod/oci_unsupported.go index 6e5601eac..409bb117e 100644 --- a/libpod/oci_unsupported.go +++ b/libpod/oci_unsupported.go @@ -2,6 +2,19 @@ package libpod -func moveConmonToCgroup() error { +import ( + "os" + "os/exec" +) + +func (r *OCIRuntime) moveConmonToCgroup(ctr *Container, cgroupParent string, cmd *exec.Cmd) error { return ErrOSNotSupported } + +func newPipe() (parent *os.File, child *os.File, err error) { + return nil, nil, ErrNotImplemented +} + +func (r *OCIRuntime) createContainer(ctr *Container, cgroupParent string) (err error) { + return ErrNotImplemented +} diff --git a/pkg/rootless/rootless_unsupported.go b/pkg/rootless/rootless_unsupported.go index e4067a764..a6efa73f5 100644 --- a/pkg/rootless/rootless_unsupported.go +++ b/pkg/rootless/rootless_unsupported.go @@ -16,3 +16,8 @@ func IsRootless() bool { func BecomeRootInUserNS() (bool, error) { return false, errors.New("this function is not supported on this os") } + +// GetRootlessUID returns the UID of the user in the parent userNS +func GetRootlessUID() int { + return -1 +} diff --git a/pkg/spec/config_linux.go b/pkg/spec/config_linux.go index 69b99232f..0f1d670b5 100644 --- a/pkg/spec/config_linux.go +++ b/pkg/spec/config_linux.go @@ -11,6 +11,7 @@ import ( spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate" "github.com/pkg/errors" + "golang.org/x/sys/unix" ) // Device transforms a libcontainer configs.Device to a specs.LinuxDevice object. @@ -82,3 +83,87 @@ func getSeccompConfig(config *CreateConfig, configSpec *spec.Spec) (*spec.LinuxS return seccompConfig, nil } + +// CreateBlockIO returns a LinuxBlockIO struct from a CreateConfig +func (c *CreateConfig) CreateBlockIO() (*spec.LinuxBlockIO, error) { + bio := &spec.LinuxBlockIO{} + bio.Weight = &c.Resources.BlkioWeight + if len(c.Resources.BlkioWeightDevice) > 0 { + var lwds []spec.LinuxWeightDevice + for _, i := range c.Resources.BlkioWeightDevice { + wd, err := validateweightDevice(i) + if err != nil { + return bio, errors.Wrapf(err, "invalid values for blkio-weight-device") + } + wdStat, err := getStatFromPath(wd.path) + if err != nil { + return bio, errors.Wrapf(err, "error getting stat from path %q", wd.path) + } + lwd := spec.LinuxWeightDevice{ + Weight: &wd.weight, + } + lwd.Major = int64(unix.Major(wdStat.Rdev)) + lwd.Minor = int64(unix.Minor(wdStat.Rdev)) + lwds = append(lwds, lwd) + } + bio.WeightDevice = lwds + } + if len(c.Resources.DeviceReadBps) > 0 { + readBps, err := makeThrottleArray(c.Resources.DeviceReadBps, bps) + if err != nil { + return bio, err + } + bio.ThrottleReadBpsDevice = readBps + } + if len(c.Resources.DeviceWriteBps) > 0 { + writeBpds, err := makeThrottleArray(c.Resources.DeviceWriteBps, bps) + if err != nil { + return bio, err + } + bio.ThrottleWriteBpsDevice = writeBpds + } + if len(c.Resources.DeviceReadIOps) > 0 { + readIOps, err := makeThrottleArray(c.Resources.DeviceReadIOps, iops) + if err != nil { + return bio, err + } + bio.ThrottleReadIOPSDevice = readIOps + } + if len(c.Resources.DeviceWriteIOps) > 0 { + writeIOps, err := makeThrottleArray(c.Resources.DeviceWriteIOps, iops) + if err != nil { + return bio, err + } + bio.ThrottleWriteIOPSDevice = writeIOps + } + return bio, nil +} + +func makeThrottleArray(throttleInput []string, rateType int) ([]spec.LinuxThrottleDevice, error) { + var ( + ltds []spec.LinuxThrottleDevice + t *throttleDevice + err error + ) + for _, i := range throttleInput { + if rateType == bps { + t, err = validateBpsDevice(i) + } else { + t, err = validateIOpsDevice(i) + } + if err != nil { + return []spec.LinuxThrottleDevice{}, err + } + ltdStat, err := getStatFromPath(t.path) + if err != nil { + return ltds, errors.Wrapf(err, "error getting stat from path %q", t.path) + } + ltd := spec.LinuxThrottleDevice{ + Rate: t.rate, + } + ltd.Major = int64(unix.Major(ltdStat.Rdev)) + ltd.Minor = int64(unix.Minor(ltdStat.Rdev)) + ltds = append(ltds, ltd) + } + return ltds, nil +} diff --git a/pkg/spec/config_unsupported.go b/pkg/spec/config_unsupported.go index b3b05acea..310c2e204 100644 --- a/pkg/spec/config_unsupported.go +++ b/pkg/spec/config_unsupported.go @@ -4,9 +4,25 @@ package createconfig import ( spec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/runtime-tools/generate" "github.com/pkg/errors" ) func getSeccompConfig(config *CreateConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) { return nil, errors.New("function not supported on non-linux OS's") } +func addDevice(g *generate.Generator, device string) error { + return errors.New("function not implemented") +} + +func (c *CreateConfig) AddPrivilegedDevices(g *generate.Generator) error { + return errors.New("function not implemented") +} + +func (c *CreateConfig) CreateBlockIO() (*spec.LinuxBlockIO, error) { + return nil, errors.New("function not implemented") +} + +func makeThrottleArray(throttleInput []string, rateType int) ([]spec.LinuxThrottleDevice, error) { + return nil, errors.New("function not implemented") +} diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go index 451c09eb3..56b648508 100644 --- a/pkg/spec/createconfig.go +++ b/pkg/spec/createconfig.go @@ -135,90 +135,6 @@ type CreateConfig struct { func u32Ptr(i int64) *uint32 { u := uint32(i); return &u } func fmPtr(i int64) *os.FileMode { fm := os.FileMode(i); return &fm } -// CreateBlockIO returns a LinuxBlockIO struct from a CreateConfig -func (c *CreateConfig) CreateBlockIO() (*spec.LinuxBlockIO, error) { - bio := &spec.LinuxBlockIO{} - bio.Weight = &c.Resources.BlkioWeight - if len(c.Resources.BlkioWeightDevice) > 0 { - var lwds []spec.LinuxWeightDevice - for _, i := range c.Resources.BlkioWeightDevice { - wd, err := validateweightDevice(i) - if err != nil { - return bio, errors.Wrapf(err, "invalid values for blkio-weight-device") - } - wdStat, err := getStatFromPath(wd.path) - if err != nil { - return bio, errors.Wrapf(err, "error getting stat from path %q", wd.path) - } - lwd := spec.LinuxWeightDevice{ - Weight: &wd.weight, - } - lwd.Major = int64(unix.Major(wdStat.Rdev)) - lwd.Minor = int64(unix.Minor(wdStat.Rdev)) - lwds = append(lwds, lwd) - } - bio.WeightDevice = lwds - } - if len(c.Resources.DeviceReadBps) > 0 { - readBps, err := makeThrottleArray(c.Resources.DeviceReadBps, bps) - if err != nil { - return bio, err - } - bio.ThrottleReadBpsDevice = readBps - } - if len(c.Resources.DeviceWriteBps) > 0 { - writeBpds, err := makeThrottleArray(c.Resources.DeviceWriteBps, bps) - if err != nil { - return bio, err - } - bio.ThrottleWriteBpsDevice = writeBpds - } - if len(c.Resources.DeviceReadIOps) > 0 { - readIOps, err := makeThrottleArray(c.Resources.DeviceReadIOps, iops) - if err != nil { - return bio, err - } - bio.ThrottleReadIOPSDevice = readIOps - } - if len(c.Resources.DeviceWriteIOps) > 0 { - writeIOps, err := makeThrottleArray(c.Resources.DeviceWriteIOps, iops) - if err != nil { - return bio, err - } - bio.ThrottleWriteIOPSDevice = writeIOps - } - return bio, nil -} - -func makeThrottleArray(throttleInput []string, rateType int) ([]spec.LinuxThrottleDevice, error) { - var ( - ltds []spec.LinuxThrottleDevice - t *throttleDevice - err error - ) - for _, i := range throttleInput { - if rateType == bps { - t, err = validateBpsDevice(i) - } else { - t, err = validateIOpsDevice(i) - } - if err != nil { - return []spec.LinuxThrottleDevice{}, err - } - ltdStat, err := getStatFromPath(t.path) - if err != nil { - return ltds, errors.Wrapf(err, "error getting stat from path %q", t.path) - } - ltd := spec.LinuxThrottleDevice{ - Rate: t.rate, - } - ltd.Major = int64(unix.Major(ltdStat.Rdev)) - ltd.Minor = int64(unix.Minor(ltdStat.Rdev)) - ltds = append(ltds, ltd) - } - return ltds, nil -} - //GetVolumeMounts takes user provided input for bind mounts and creates Mount structs func (c *CreateConfig) GetVolumeMounts(specMounts []spec.Mount) ([]spec.Mount, error) { var m []spec.Mount |