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
This commit is contained in:
baude
2018-07-04 10:51:20 -05:00
committed by Atomic Bot
parent 33870ea2c3
commit cc6f0e85f9
22 changed files with 681 additions and 514 deletions

View File

@ -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

View File

@ -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())

View File

@ -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())

View File

@ -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
}

View File

@ -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
}

View File

@ -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()

View File

@ -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 {

View File

@ -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
}

View File

@ -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
}

View File

@ -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 ""
}

View File

@ -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 ""
}

View File

@ -1,4 +1,4 @@
// +build !arm,!386
// +build !arm,!386,linux
package libpod

View File

@ -0,0 +1,12 @@
// +build darwin,!linux
package libpod
import (
"os"
"time"
)
func getFinishedTime(fi os.FileInfo) time.Time {
return time.Time{}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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")
}

View File

@ -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