diff options
-rw-r--r-- | libpod/boltdb_state.go | 1 | ||||
-rw-r--r-- | libpod/container.go | 29 | ||||
-rw-r--r-- | libpod/container_api.go | 17 | ||||
-rw-r--r-- | libpod/container_inspect.go | 25 | ||||
-rw-r--r-- | libpod/container_internal.go | 111 |
5 files changed, 121 insertions, 62 deletions
diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go index 7db02d533..aeda94e50 100644 --- a/libpod/boltdb_state.go +++ b/libpod/boltdb_state.go @@ -143,6 +143,7 @@ func (s *BoltState) Refresh() error { state.ExecSessions = make(map[string]*ExecSession) state.IPs = nil state.Routes = nil + state.BindMounts = make(map[string]string) newStateBytes, err := json.Marshal(state) if err != nil { diff --git a/libpod/container.go b/libpod/container.go index 95db85b70..648dc821e 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -710,6 +710,35 @@ func (c *Container) Routes() ([]types.Route, error) { return routes, nil } +// BindMounts retrieves bind mounts that were created by libpod and will be +// added to the container +// All these mounts except /dev/shm are ignored if a mount in the given spec has +// the same destination +// These mounts include /etc/resolv.conf, /etc/hosts, and /etc/hostname +// The return is formatted as a map from destination (mountpoint in the +// container) to source (path of the file that will be mounted into the +// container) +// If the container has not been started yet, an empty map will be returned, as +// the files in question are only created when the container is started. +func (c *Container) BindMounts() (map[string]string, error) { + if !c.locked { + c.lock.Lock() + defer c.lock.Unlock() + + if err := c.syncContainer(); err != nil { + return nil, err + } + } + + newMap := make(map[string]string, len(c.state.BindMounts)) + + for key, val := range c.state.BindMounts { + newMap[key] = val + } + + return newMap, nil +} + // Misc Accessors // Most will require locking diff --git a/libpod/container_api.go b/libpod/container_api.go index 161cd938c..0a27da7c9 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -59,25 +59,12 @@ func (c *Container) Init() (err error) { } }() - // Copy /etc/resolv.conf to the container's rundir - runDirResolv, err := c.generateResolvConf() - if err != nil { + if err := c.makeBindMounts(); err != nil { return err } - // Copy /etc/hosts to the container's rundir - runDirHosts, err := c.generateHosts() - if err != nil { - return errors.Wrapf(err, "unable to copy /etc/hosts to container space") - } - - runDirHostname, err := c.generateEtcHostname(c.Hostname()) - if err != nil { - return errors.Wrapf(err, "unable to generate hostname file for container") - } - // Generate the OCI spec - spec, err := c.generateSpec(runDirResolv, runDirHosts, runDirHostname) + spec, err := c.generateSpec() if err != nil { return err } diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go index 3a1728826..bbfcd4446 100644 --- a/libpod/container_inspect.go +++ b/libpod/container_inspect.go @@ -25,6 +25,25 @@ func (c *Container) getContainerInspectData(size bool, driverData *inspect.Data) execIDs = append(execIDs, id) } + if c.state.BindMounts == nil { + c.state.BindMounts = make(map[string]string) + } + + resolvPath := "" + if path, ok := c.state.BindMounts["/etc/resolv.conf"]; ok { + resolvPath = path + } + + hostsPath := "" + if path, ok := c.state.BindMounts["/etc/hosts"]; ok { + hostsPath = path + } + + hostnamePath := "" + if path, ok := c.state.BindMounts["/etc/hostname"]; ok { + hostnamePath = path + } + data := &inspect.ContainerInspectData{ ID: config.ID, Created: config.CreatedTime, @@ -45,9 +64,9 @@ func (c *Container) getContainerInspectData(size bool, driverData *inspect.Data) }, ImageID: config.RootfsImageID, ImageName: config.RootfsImageName, - ResolvConfPath: "", // TODO get from networking path - HostnamePath: spec.Annotations["io.kubernetes.cri-o.HostnamePath"], // not sure - HostsPath: "", // can't get yet + ResolvConfPath: resolvPath, + HostnamePath: hostnamePath, + HostsPath: hostsPath, StaticDir: config.StaticDir, LogPath: config.LogPath, Name: config.Name, diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 736655f13..3c7637717 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -162,6 +162,8 @@ func newContainer(rspec *spec.Spec, lockDir string) (*Container, error) { ctr.config.ShmSize = DefaultShmSize ctr.config.CgroupParent = DefaultCgroupParent + ctr.state.BindMounts = make(map[string]string) + // Path our lock file will reside at lockPath := filepath.Join(lockDir, ctr.config.ID) // Grab a lockfile at the given path @@ -444,6 +446,56 @@ func (c *Container) cleanupStorage() error { return c.save() } +// Make standard bind mounts to include in the container +func (c *Container) makeBindMounts() error { + if c.state.BindMounts == nil { + c.state.BindMounts = make(map[string]string) + } + + // SHM is always added when we mount the container + c.state.BindMounts["/dev/shm"] = c.config.ShmDir + + // Make /etc/resolv.conf + if path, ok := c.state.BindMounts["/etc/resolv.conf"]; ok { + // If it already exists, delete so we can recreate + if err := os.Remove(path); err != nil { + return errors.Wrapf(err, "error removing resolv.conf for container %s", c.ID()) + } + delete(c.state.BindMounts, "/etc/resolv.conf") + } + newResolv, err := c.generateResolvConf() + if err != nil { + return errors.Wrapf(err, "error creating resolv.conf for container %s", c.ID()) + } + c.state.BindMounts["/etc/resolv.conf"] = newResolv + + // Make /etc/hosts + if path, ok := c.state.BindMounts["/etc/hosts"]; ok { + // If it already exists, delete so we can recreate + if err := os.Remove(path); err != nil { + return errors.Wrapf(err, "error removing hosts file for container %s", c.ID()) + } + delete(c.state.BindMounts, "/etc/hosts") + } + newHosts, err := c.generateHosts() + if err != nil { + return errors.Wrapf(err, "error creating hosts file for container %s", c.ID()) + } + c.state.BindMounts["/etc/hosts"] = newHosts + + // Make /etc/hostname + // This should never change, so no need to recreate if it exists + if _, ok := c.state.BindMounts["/etc/hostname"]; !ok { + hostnamePath, err := c.writeStringToRundir("hostname", c.Hostname()) + if err != nil { + return errors.Wrapf(err, "error creating hostname file for container %s", c.ID()) + } + c.state.BindMounts["/etc/hostname"] = hostnamePath + } + + return nil +} + // writeStringToRundir copies the provided file to the runtimedir func (c *Container) writeStringToRundir(destFile, output string) (string, error) { destFileName := filepath.Join(c.state.RunDir, destFile) @@ -579,58 +631,29 @@ func (c *Container) generateHosts() (string, error) { return c.writeStringToRundir("hosts", hosts) } -// generateEtcHostname creates a containers /etc/hostname -func (c *Container) generateEtcHostname(hostname string) (string, error) { - return c.writeStringToRundir("hostname", hostname) -} - // Generate spec for a container -func (c *Container) generateSpec(resolvPath, hostsPath, hostnamePath string) (*spec.Spec, error) { +func (c *Container) generateSpec() (*spec.Spec, error) { g := generate.NewFromSpec(c.config.Spec) // If network namespace was requested, add it now if c.config.CreateNetNS { g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, c.state.NetNS.Path()) } - // Remove default /etc/shm mount + + // Remove the default /dev/shm mount to ensure we overwrite it g.RemoveMount("/dev/shm") - // Mount ShmDir from host into container - shmMnt := spec.Mount{ - Type: "bind", - Source: c.config.ShmDir, - Destination: "/dev/shm", - Options: []string{"rw", "bind"}, - } - g.AddMount(shmMnt) - // Bind mount resolv.conf - resolvMnt := spec.Mount{ - Type: "bind", - Source: resolvPath, - Destination: "/etc/resolv.conf", - Options: []string{"rw", "bind"}, - } - if !MountExists(g.Mounts(), resolvMnt.Destination) { - g.AddMount(resolvMnt) - } - // Bind mount hosts - hostsMnt := spec.Mount{ - Type: "bind", - Source: hostsPath, - Destination: "/etc/hosts", - Options: []string{"rw", "bind"}, - } - if !MountExists(g.Mounts(), hostsMnt.Destination) { - g.AddMount(hostsMnt) - } - // Bind hostname - hostnameMnt := spec.Mount{ - Type: "bind", - Source: hostnamePath, - Destination: "/etc/hostname", - Options: []string{"rw", "bind"}, - } - if !MountExists(g.Mounts(), hostnameMnt.Destination) { - g.AddMount(hostnameMnt) + + // 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) + } } // Bind builtin image volumes |