summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/boltdb_state.go2
-rw-r--r--libpod/boltdb_state_internal.go11
-rw-r--r--libpod/container_internal_linux.go56
-rw-r--r--libpod/info.go1
-rw-r--r--libpod/options.go26
-rw-r--r--libpod/runtime.go45
-rw-r--r--libpod/runtime_ctr.go5
-rw-r--r--libpod/state.go1
-rw-r--r--libpod/volume.go18
9 files changed, 139 insertions, 26 deletions
diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go
index 25ef5cd0e..c226a0617 100644
--- a/libpod/boltdb_state.go
+++ b/libpod/boltdb_state.go
@@ -261,12 +261,14 @@ func (s *BoltState) GetDBConfig() (*DBConfig, error) {
storageRoot := configBucket.Get(graphRootKey)
storageTmp := configBucket.Get(runRootKey)
graphDriver := configBucket.Get(graphDriverKey)
+ volumePath := configBucket.Get(volPathKey)
cfg.LibpodRoot = string(libpodRoot)
cfg.LibpodTmp = string(libpodTmp)
cfg.StorageRoot = string(storageRoot)
cfg.StorageTmp = string(storageTmp)
cfg.GraphDriver = string(graphDriver)
+ cfg.VolumePath = string(volumePath)
return nil
})
diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go
index 3d749849d..936ccbf4c 100644
--- a/libpod/boltdb_state_internal.go
+++ b/libpod/boltdb_state_internal.go
@@ -38,6 +38,7 @@ const (
graphRootName = "graph-root"
graphDriverName = "graph-driver-name"
osName = "os"
+ volPathName = "volume-path"
)
var (
@@ -67,6 +68,7 @@ var (
graphRootKey = []byte(graphRootName)
graphDriverKey = []byte(graphDriverName)
osKey = []byte(osName)
+ volPathKey = []byte(volPathName)
)
// Check if the configuration of the database is compatible with the
@@ -105,10 +107,15 @@ func checkRuntimeConfig(db *bolt.DB, rt *Runtime) error {
return err
}
- return validateDBAgainstConfig(configBkt, "storage graph driver",
+ if err := validateDBAgainstConfig(configBkt, "storage graph driver",
rt.config.StorageConfig.GraphDriverName,
graphDriverKey,
- storage.DefaultStoreOptions.GraphDriverName)
+ storage.DefaultStoreOptions.GraphDriverName); err != nil {
+ return err
+ }
+
+ return validateDBAgainstConfig(configBkt, "volume path",
+ rt.config.VolumePath, volPathKey, "")
})
return err
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 86f94477e..b074efa3a 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -26,7 +26,6 @@ import (
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/secrets"
"github.com/containers/storage/pkg/idtools"
- "github.com/mrunalp/fileutils"
"github.com/opencontainers/runc/libcontainer/user"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
@@ -482,6 +481,19 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO
if c.state.State != ContainerStateRunning {
return errors.Wrapf(ErrCtrStateInvalid, "%q is not running, cannot checkpoint", c.state.State)
}
+
+ // Create the CRIU log file and label it
+ dumpLog := filepath.Join(c.bundlePath(), "dump.log")
+
+ logFile, err := os.OpenFile(dumpLog, os.O_CREATE, 0600)
+ if err != nil {
+ return errors.Wrapf(err, "failed to create CRIU log file %q", dumpLog)
+ }
+ logFile.Close()
+ if err = label.SetFileLabel(dumpLog, c.MountLabel()); err != nil {
+ return errors.Wrapf(err, "failed to label CRIU log file %q", dumpLog)
+ }
+
if err := c.runtime.ociRuntime.checkpointContainer(c, options); err != nil {
return err
}
@@ -677,20 +689,12 @@ func (c *Container) makeBindMounts() error {
// If it doesn't, don't copy them
resolvPath, exists := bindMounts["/etc/resolv.conf"]
if exists {
- resolvDest := filepath.Join(c.state.RunDir, "resolv.conf")
- if err := fileutils.CopyFile(resolvPath, resolvDest); err != nil {
- return errors.Wrapf(err, "error copying resolv.conf from dependency container %s of container %s", depCtr.ID(), c.ID())
- }
- c.state.BindMounts["/etc/resolv.conf"] = resolvDest
- }
+ c.state.BindMounts["/etc/resolv.conf"] = resolvPath
+ }
hostsPath, exists := bindMounts["/etc/hosts"]
if exists {
- hostsDest := filepath.Join(c.state.RunDir, "hosts")
- if err := fileutils.CopyFile(hostsPath, hostsDest); err != nil {
- return errors.Wrapf(err, "error copying hosts file from dependency container %s of container %s", depCtr.ID(), c.ID())
- }
- c.state.BindMounts["/etc/hosts"] = hostsDest
+ c.state.BindMounts["/etc/hosts"] = hostsPath
}
} else {
newResolv, err := c.generateResolvConf()
@@ -705,6 +709,14 @@ func (c *Container) makeBindMounts() error {
}
c.state.BindMounts["/etc/hosts"] = newHosts
}
+
+ if err := label.Relabel(c.state.BindMounts["/etc/hosts"], c.config.MountLabel, true); err != nil {
+ return err
+ }
+
+ if err := label.Relabel(c.state.BindMounts["/etc/resolv.conf"], c.config.MountLabel, true); err != nil {
+ return err
+ }
}
// SHM is always added when we mount the container
@@ -758,8 +770,24 @@ func (c *Container) makeBindMounts() error {
// generateResolvConf generates a containers resolv.conf
func (c *Container) generateResolvConf() (string, error) {
+ resolvConf := "/etc/resolv.conf"
+ for _, ns := range c.config.Spec.Linux.Namespaces {
+ if ns.Type == spec.NetworkNamespace {
+ if ns.Path != "" && !strings.HasPrefix(ns.Path, "/proc/") {
+ definedPath := filepath.Join("/etc/netns", filepath.Base(ns.Path), "resolv.conf")
+ _, err := os.Stat(definedPath)
+ if err == nil {
+ resolvConf = definedPath
+ } else if !os.IsNotExist(err) {
+ return "", errors.Wrapf(err, "failed to stat %s", definedPath)
+ }
+ }
+ break
+ }
+ }
+
// Determine the endpoint for resolv.conf in case it is a symlink
- resolvPath, err := filepath.EvalSymlinks("/etc/resolv.conf")
+ resolvPath, err := filepath.EvalSymlinks(resolvConf)
if err != nil {
return "", err
}
@@ -809,7 +837,7 @@ func (c *Container) generateResolvConf() (string, error) {
}
// Relabel resolv.conf for the container
- if err := label.Relabel(destPath, c.config.MountLabel, false); err != nil {
+ if err := label.Relabel(destPath, c.config.MountLabel, true); err != nil {
return "", err
}
diff --git a/libpod/info.go b/libpod/info.go
index 191ce6810..62088b730 100644
--- a/libpod/info.go
+++ b/libpod/info.go
@@ -121,6 +121,7 @@ func (r *Runtime) storeInfo() (map[string]interface{}, error) {
info["RunRoot"] = r.store.RunRoot()
info["GraphDriverName"] = r.store.GraphDriverName()
info["GraphOptions"] = r.store.GraphOptions()
+ info["VolumePath"] = r.config.VolumePath
statusPairs, err := r.store.Status()
if err != nil {
return nil, err
diff --git a/libpod/options.go b/libpod/options.go
index 9aa020b56..1e8592a25 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -47,6 +47,11 @@ func WithStorageConfig(config storage.StoreOptions) RuntimeOption {
rt.config.StaticDir = filepath.Join(config.GraphRoot, "libpod")
rt.configuredFrom.libpodStaticDirSet = true
+ // Also set libpod volume path, so we are a subdirectory
+ // of the c/storage store by default
+ rt.config.VolumePath = filepath.Join(config.GraphRoot, "volumes")
+ rt.configuredFrom.volPathSet = true
+
setField = true
}
@@ -359,6 +364,7 @@ func WithVolumePath(volPath string) RuntimeOption {
}
rt.config.VolumePath = volPath
+ rt.configuredFrom.volPathSet = true
return nil
}
@@ -904,10 +910,10 @@ func WithNetNS(portMappings []ocicni.PortMapping, postConfigureNetNS bool, netmo
}
ctr.config.PostConfigureNetNS = postConfigureNetNS
- ctr.config.CreateNetNS = true
+ ctr.config.NetMode = namespaces.NetworkMode(netmode)
+ ctr.config.CreateNetNS = !ctr.config.NetMode.IsUserDefined()
ctr.config.PortMappings = portMappings
ctr.config.Networks = networks
- ctr.config.NetMode = namespaces.NetworkMode(netmode)
return nil
}
@@ -1242,6 +1248,22 @@ func WithVolumeOptions(options map[string]string) VolumeCreateOption {
}
}
+// withSetCtrSpecific sets a bool notifying libpod that a volume was created
+// specifically for a container.
+// These volumes will be removed when the container is removed and volumes are
+// also specified for removal.
+func withSetCtrSpecific() VolumeCreateOption {
+ return func(volume *Volume) error {
+ if volume.valid {
+ return ErrVolumeFinalized
+ }
+
+ volume.config.IsCtrSpecific = true
+
+ return nil
+ }
+}
+
// Pod Creation Options
// WithPodName sets the name of the pod.
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 94dbf37dd..827c22f5b 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -123,7 +123,10 @@ type RuntimeConfig struct {
// Not included in on-disk config, use the dedicated containers/storage
// configuration file instead
StorageConfig storage.StoreOptions `toml:"-"`
- VolumePath string `toml:"volume_path"`
+ // VolumePath is the default location that named volumes will be created
+ // under. This convention is followed by the default volume driver, but
+ // may not be by other drivers.
+ VolumePath string `toml:"volume_path"`
// ImageDefaultTransport is the default transport method used to fetch
// images
ImageDefaultTransport string `toml:"image_default_transport"`
@@ -232,12 +235,14 @@ type runtimeConfiguredFrom struct {
storageRunRootSet bool
libpodStaticDirSet bool
libpodTmpDirSet bool
+ volPathSet bool
}
var (
defaultRuntimeConfig = RuntimeConfig{
// Leave this empty so containers/storage will use its defaults
StorageConfig: storage.StoreOptions{},
+ VolumePath: filepath.Join(storage.DefaultStoreOptions.GraphRoot, "volumes"),
ImageDefaultTransport: DefaultTransport,
StateType: BoltDBStateStore,
OCIRuntime: "runc",
@@ -400,6 +405,9 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
if tmpConfig.TmpDir != "" {
runtime.configuredFrom.libpodTmpDirSet = true
}
+ if tmpConfig.VolumePath != "" {
+ runtime.configuredFrom.volPathSet = true
+ }
if _, err := toml.Decode(string(contents), runtime.config); err != nil {
return nil, errors.Wrapf(err, "error decoding configuration file %s", configPath)
@@ -526,6 +534,16 @@ func makeRuntime(runtime *Runtime) (err error) {
if runtime.config.OCIRuntime != "" && runtime.config.OCIRuntime[0] == '/' {
foundRuntime = true
runtime.ociRuntimePath = OCIRuntimePath{Name: filepath.Base(runtime.config.OCIRuntime), Paths: []string{runtime.config.OCIRuntime}}
+ stat, err := os.Stat(runtime.config.OCIRuntime)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return errors.Wrapf(err, "the specified OCI runtime %s does not exist", runtime.config.OCIRuntime)
+ }
+ return errors.Wrapf(err, "cannot stat the OCI runtime path %s", runtime.config.OCIRuntime)
+ }
+ if !stat.Mode().IsRegular() {
+ return fmt.Errorf("the specified OCI runtime %s is not a valid file", runtime.config.OCIRuntime)
+ }
} else {
// If not, look it up in the configuration.
paths := runtime.config.OCIRuntimes[runtime.config.OCIRuntime]
@@ -614,29 +632,52 @@ func makeRuntime(runtime *Runtime) (err error) {
if !runtime.configuredFrom.storageGraphDriverSet && dbConfig.GraphDriver != "" {
if runtime.config.StorageConfig.GraphDriverName != dbConfig.GraphDriver &&
runtime.config.StorageConfig.GraphDriverName != "" {
- logrus.Errorf("User-selected graph driver %s overwritten by graph driver %s from database - delete libpod local files to resolve",
+ logrus.Errorf("User-selected graph driver %q overwritten by graph driver %q from database - delete libpod local files to resolve",
runtime.config.StorageConfig.GraphDriverName, dbConfig.GraphDriver)
}
runtime.config.StorageConfig.GraphDriverName = dbConfig.GraphDriver
}
if !runtime.configuredFrom.storageGraphRootSet && dbConfig.StorageRoot != "" {
+ if runtime.config.StorageConfig.GraphRoot != dbConfig.StorageRoot &&
+ runtime.config.StorageConfig.GraphRoot != "" {
+ logrus.Debugf("Overriding graph root %q with %q from database",
+ runtime.config.StorageConfig.GraphRoot, dbConfig.StorageRoot)
+ }
runtime.config.StorageConfig.GraphRoot = dbConfig.StorageRoot
}
if !runtime.configuredFrom.storageRunRootSet && dbConfig.StorageTmp != "" {
+ if runtime.config.StorageConfig.RunRoot != dbConfig.StorageTmp &&
+ runtime.config.StorageConfig.RunRoot != "" {
+ logrus.Debugf("Overriding run root %q with %q from database",
+ runtime.config.StorageConfig.RunRoot, dbConfig.StorageTmp)
+ }
runtime.config.StorageConfig.RunRoot = dbConfig.StorageTmp
}
if !runtime.configuredFrom.libpodStaticDirSet && dbConfig.LibpodRoot != "" {
+ if runtime.config.StaticDir != dbConfig.LibpodRoot && runtime.config.StaticDir != "" {
+ logrus.Debugf("Overriding static dir %q with %q from database", runtime.config.StaticDir, dbConfig.LibpodRoot)
+ }
runtime.config.StaticDir = dbConfig.LibpodRoot
}
if !runtime.configuredFrom.libpodTmpDirSet && dbConfig.LibpodTmp != "" {
+ if runtime.config.TmpDir != dbConfig.LibpodTmp && runtime.config.TmpDir != "" {
+ logrus.Debugf("Overriding tmp dir %q with %q from database", runtime.config.TmpDir, dbConfig.LibpodTmp)
+ }
runtime.config.TmpDir = dbConfig.LibpodTmp
}
+ if !runtime.configuredFrom.volPathSet && dbConfig.VolumePath != "" {
+ if runtime.config.VolumePath != dbConfig.VolumePath && runtime.config.VolumePath != "" {
+ logrus.Debugf("Overriding volume path %q with %q from database", runtime.config.VolumePath, dbConfig.VolumePath)
+ }
+ runtime.config.VolumePath = dbConfig.VolumePath
+ }
logrus.Debugf("Using graph driver %s", runtime.config.StorageConfig.GraphDriverName)
logrus.Debugf("Using graph root %s", runtime.config.StorageConfig.GraphRoot)
logrus.Debugf("Using run root %s", runtime.config.StorageConfig.RunRoot)
logrus.Debugf("Using static dir %s", runtime.config.StaticDir)
logrus.Debugf("Using tmp dir %s", runtime.config.TmpDir)
+ logrus.Debugf("Using volume path %s", runtime.config.VolumePath)
// Validate our config against the database, now that we've set our
// final storage configuration
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 2ec8d0795..cfa4f9654 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -180,7 +180,7 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
if vol.Source[0] != '/' && isNamedVolume(vol.Source) {
volInfo, err := r.state.Volume(vol.Source)
if err != nil {
- newVol, err := r.newVolume(ctx, WithVolumeName(vol.Source))
+ newVol, err := r.newVolume(ctx, WithVolumeName(vol.Source), withSetCtrSpecific())
if err != nil {
return nil, errors.Wrapf(err, "error creating named volume %q", vol.Source)
}
@@ -421,6 +421,9 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
for _, v := range volumes {
if volume, err := runtime.state.Volume(v); err == nil {
+ if !volume.IsCtrSpecific() {
+ continue
+ }
if err := runtime.removeVolume(ctx, volume, false); err != nil && err != ErrNoSuchVolume && err != ErrVolumeBeingUsed {
logrus.Errorf("cleanup volume (%s): %v", v, err)
}
diff --git a/libpod/state.go b/libpod/state.go
index 98282fc83..4296fc3cd 100644
--- a/libpod/state.go
+++ b/libpod/state.go
@@ -8,6 +8,7 @@ type DBConfig struct {
StorageRoot string
StorageTmp string
GraphDriver string
+ VolumePath string
}
// State is a storage backend for libpod's current state.
diff --git a/libpod/volume.go b/libpod/volume.go
index 74878b6a4..0c7618841 100644
--- a/libpod/volume.go
+++ b/libpod/volume.go
@@ -15,11 +15,12 @@ type VolumeConfig struct {
// Name of the volume
Name string `json:"name"`
- Labels map[string]string `json:"labels"`
- MountPoint string `json:"mountPoint"`
- Driver string `json:"driver"`
- Options map[string]string `json:"options"`
- Scope string `json:"scope"`
+ Labels map[string]string `json:"labels"`
+ MountPoint string `json:"mountPoint"`
+ Driver string `json:"driver"`
+ Options map[string]string `json:"options"`
+ Scope string `json:"scope"`
+ IsCtrSpecific bool `json:"ctrSpecific"`
}
// Name retrieves the volume's name
@@ -60,3 +61,10 @@ func (v *Volume) Options() map[string]string {
func (v *Volume) Scope() string {
return v.config.Scope
}
+
+// IsCtrSpecific returns whether this volume was created specifically for a
+// given container. Images with this set to true will be removed when the
+// container is removed with the Volumes parameter set to true.
+func (v *Volume) IsCtrSpecific() bool {
+ return v.config.IsCtrSpecific
+}