summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Heon <matthew.heon@gmail.com>2018-03-07 14:10:19 -0500
committerAtomic Bot <atomic-devel@projectatomic.io>2018-03-08 16:40:21 +0000
commit54f32f2cc024090c3f284f7b0b6832f2b19a6660 (patch)
treef3a221a9d1fe522afa9f43cb72b4cb94552788d0
parentc657511bce7bc1c5da4b5554a4850aa4046711b0 (diff)
downloadpodman-54f32f2cc024090c3f284f7b0b6832f2b19a6660.tar.gz
podman-54f32f2cc024090c3f284f7b0b6832f2b19a6660.tar.bz2
podman-54f32f2cc024090c3f284f7b0b6832f2b19a6660.zip
Convert bind mounts to use DB field
Refactors creation of bind mounts into a separate function that can be called from elsewhere (e.g. pod start or container restart). This function stores the mounts in the DB using the field established last commit. Spec generation now relies upon this field in the DB instead of manually enumerating files to be bind mounted in. Signed-off-by: Matthew Heon <matthew.heon@gmail.com> Closes: #462 Approved by: baude
-rw-r--r--libpod/boltdb_state.go1
-rw-r--r--libpod/container.go29
-rw-r--r--libpod/container_api.go17
-rw-r--r--libpod/container_inspect.go25
-rw-r--r--libpod/container_internal.go111
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