2018-02-05 21:05:59 +00:00
package container // import "github.com/docker/docker/container"
2013-01-19 00:13:39 +00:00
import (
2017-04-06 17:43:10 +00:00
"bytes"
2018-04-19 22:30:59 +00:00
"context"
2013-01-19 00:13:39 +00:00
"encoding/json"
2013-03-21 07:25:00 +00:00
"fmt"
2014-04-28 21:36:04 +00:00
"io"
"os"
2014-05-11 20:49:46 +00:00
"path/filepath"
2017-05-16 21:19:19 +00:00
"runtime"
2016-03-10 04:33:21 +00:00
"strings"
2015-05-05 20:25:05 +00:00
"sync"
2014-04-28 21:36:04 +00:00
"syscall"
"time"
2017-11-30 00:15:20 +00:00
"github.com/containerd/containerd/cio"
2016-09-06 18:18:12 +00:00
containertypes "github.com/docker/docker/api/types/container"
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
mounttypes "github.com/docker/docker/api/types/mount"
2016-11-15 15:04:36 +00:00
swarmtypes "github.com/docker/docker/api/types/swarm"
2016-11-14 20:15:09 +00:00
"github.com/docker/docker/container/stream"
2015-11-20 22:35:16 +00:00
"github.com/docker/docker/daemon/exec"
2015-02-04 19:04:58 +00:00
"github.com/docker/docker/daemon/logger"
"github.com/docker/docker/daemon/logger/jsonfilelog"
2018-04-05 16:41:35 +00:00
"github.com/docker/docker/daemon/logger/local"
2018-04-05 16:42:31 +00:00
"github.com/docker/docker/daemon/logger/loggerutils/cache"
2015-04-04 04:06:48 +00:00
"github.com/docker/docker/daemon/network"
2018-04-05 16:41:35 +00:00
"github.com/docker/docker/errdefs"
2015-11-18 22:20:54 +00:00
"github.com/docker/docker/image"
"github.com/docker/docker/layer"
2017-08-04 00:22:00 +00:00
"github.com/docker/docker/pkg/containerfs"
2016-03-08 15:40:30 +00:00
"github.com/docker/docker/pkg/idtools"
2016-04-21 00:08:47 +00:00
"github.com/docker/docker/pkg/ioutils"
2015-08-04 20:51:48 +00:00
"github.com/docker/docker/pkg/signal"
2017-05-26 23:14:18 +00:00
"github.com/docker/docker/pkg/system"
2016-03-18 18:50:19 +00:00
"github.com/docker/docker/restartmanager"
2015-05-19 20:05:25 +00:00
"github.com/docker/docker/volume"
2018-04-17 20:50:28 +00:00
volumemounts "github.com/docker/docker/volume/mounts"
2019-08-05 14:37:47 +00:00
units "github.com/docker/go-units"
2016-11-15 15:04:36 +00:00
agentexec "github.com/docker/swarmkit/agent/exec"
2020-10-29 23:54:10 +00:00
"github.com/moby/sys/symlink"
2017-07-19 14:20:13 +00:00
"github.com/pkg/errors"
2017-07-26 21:42:13 +00:00
"github.com/sirupsen/logrus"
2013-01-19 00:13:39 +00:00
)
2015-11-18 22:20:54 +00:00
const configFileName = "config.v2.json"
2017-09-22 13:52:41 +00:00
// ExitStatus provides exit reasons for a container.
type ExitStatus struct {
// The exit code with which the container exited.
ExitCode int
// Whether the container encountered an OOM.
OOMKilled bool
// Time at which the container died
ExitedAt time . Time
}
2017-04-25 19:03:45 +00:00
// Container holds the structure defining a container object.
type Container struct {
2016-11-14 20:15:09 +00:00
StreamConfig * stream . Config
2015-07-30 21:01:53 +00:00
// embed for Container to support states directly.
2017-08-04 00:22:00 +00:00
* State ` json:"State" ` // Needed for Engine API version <= 1.11
Root string ` json:"-" ` // Path to the "home" of the container, including metadata.
BaseFS containerfs . ContainerFS ` json:"-" ` // interface containing graphdriver mount
RWLayer layer . RWLayer ` json:"-" `
2015-07-30 21:01:53 +00:00
ID string
Created time . Time
2016-06-14 02:52:49 +00:00
Managed bool
2015-07-30 21:01:53 +00:00
Path string
Args [ ] string
2015-12-18 18:36:17 +00:00
Config * containertypes . Config
2015-11-18 22:20:54 +00:00
ImageID image . ID ` json:"Image" `
2015-07-30 21:01:53 +00:00
NetworkSettings * network . Settings
LogPath string
Name string
Driver string
2017-08-08 19:43:48 +00:00
OS string
2015-07-30 21:01:53 +00:00
// MountLabel contains the options for the 'mount' command
MountLabel string
ProcessLabel string
RestartCount int
HasBeenStartedBefore bool
HasBeenManuallyStopped bool // used for unless-stopped restart policy
2018-04-17 20:50:28 +00:00
MountPoints map [ string ] * volumemounts . MountPoint
2016-11-15 15:04:36 +00:00
HostConfig * containertypes . HostConfig ` json:"-" ` // do not serialize the host config in the json, otherwise we'll make the container unportable
ExecCommands * exec . Store ` json:"-" `
2017-03-16 21:23:33 +00:00
DependencyStore agentexec . DependencyGetter ` json:"-" `
2016-11-15 15:04:36 +00:00
SecretReferences [ ] * swarmtypes . SecretReference
2018-01-17 15:49:58 +00:00
ConfigReferences [ ] * swarmtypes . ConfigReference
2015-02-04 19:04:58 +00:00
// logDriver for closing
2016-03-18 18:50:19 +00:00
LogDriver logger . Logger ` json:"-" `
LogCopier * logger . Copier ` json:"-" `
restartManager restartmanager . RestartManager
attachContext * attachContext
2017-04-25 19:03:45 +00:00
// Fields here are specific to Unix platforms
AppArmorProfile string
HostnamePath string
HostsPath string
ShmPath string
ResolvConfPath string
SeccompProfile string
NoNewPrivileges bool
// Fields here are specific to Windows
2018-04-05 16:42:31 +00:00
NetworkSharedContainerID string ` json:"-" `
SharedEndpointList [ ] string ` json:"-" `
LocalLogCacheMeta localLogCacheMeta ` json:",omitempty" `
}
type localLogCacheMeta struct {
HaveNotifyEnabled bool
2013-01-19 00:13:39 +00:00
}
2015-11-12 19:55:17 +00:00
// NewBaseContainer creates a new container with its
2015-11-18 10:04:23 +00:00
// basic configuration.
2015-11-12 19:55:17 +00:00
func NewBaseContainer ( id , root string ) * Container {
2015-11-18 10:04:23 +00:00
return & Container {
2017-04-25 19:03:45 +00:00
ID : id ,
State : NewState ( ) ,
ExecCommands : exec . NewStore ( ) ,
Root : root ,
2018-04-17 20:50:28 +00:00
MountPoints : make ( map [ string ] * volumemounts . MountPoint ) ,
2017-04-25 19:03:45 +00:00
StreamConfig : stream . NewConfig ( ) ,
attachContext : & attachContext { } ,
2015-11-18 10:04:23 +00:00
}
}
2015-11-12 19:55:17 +00:00
// FromDisk loads the container configuration stored in the host.
func ( container * Container ) FromDisk ( ) error {
pth , err := container . ConfigPath ( )
2014-05-28 02:15:42 +00:00
if err != nil {
return err
}
2014-11-04 13:43:58 +00:00
jsonSource , err := os . Open ( pth )
2013-01-25 22:39:02 +00:00
if err != nil {
return err
}
2014-11-04 13:43:58 +00:00
defer jsonSource . Close ( )
dec := json . NewDecoder ( jsonSource )
2013-03-21 07:25:00 +00:00
// Load container settings
2015-09-03 09:01:55 +00:00
if err := dec . Decode ( container ) ; err != nil {
2013-01-25 22:39:02 +00:00
return err
}
2014-04-28 21:36:04 +00:00
2017-08-08 19:43:48 +00:00
// Ensure the operating system is set if blank. Assume it is the OS of the
// host OS if not, to ensure containers created before multiple-OS
2017-05-16 21:19:19 +00:00
// support are migrated
2017-08-08 19:43:48 +00:00
if container . OS == "" {
container . OS = runtime . GOOS
2017-05-16 21:19:19 +00:00
}
2013-10-31 21:58:43 +00:00
return container . readHostConfig ( )
2013-01-25 22:39:02 +00:00
}
2017-04-06 17:43:10 +00:00
// toDisk saves the container configuration on disk and returns a deep copy.
func ( container * Container ) toDisk ( ) ( * Container , error ) {
var (
buf bytes . Buffer
deepCopy Container
)
2015-11-12 19:55:17 +00:00
pth , err := container . ConfigPath ( )
2013-01-19 00:13:39 +00:00
if err != nil {
2017-04-06 17:43:10 +00:00
return nil , err
2013-01-19 00:13:39 +00:00
}
2014-05-28 02:15:42 +00:00
2017-04-06 17:43:10 +00:00
// Save container settings
2017-08-07 10:10:08 +00:00
f , err := ioutils . NewAtomicFileWriter ( pth , 0600 )
2013-10-31 21:58:43 +00:00
if err != nil {
2017-04-06 17:43:10 +00:00
return nil , err
2014-05-28 02:15:42 +00:00
}
2017-04-06 17:43:10 +00:00
defer f . Close ( )
2015-10-30 16:04:25 +00:00
2017-04-06 17:43:10 +00:00
w := io . MultiWriter ( & buf , f )
if err := json . NewEncoder ( w ) . Encode ( container ) ; err != nil {
return nil , err
}
2014-05-28 02:15:42 +00:00
2017-04-06 17:43:10 +00:00
if err := json . NewDecoder ( & buf ) . Decode ( & deepCopy ) ; err != nil {
return nil , err
}
deepCopy . HostConfig , err = container . WriteHostConfig ( )
if err != nil {
return nil , err
2013-10-31 21:58:43 +00:00
}
2014-05-28 02:15:42 +00:00
2017-04-06 17:43:10 +00:00
return & deepCopy , nil
2013-01-19 00:13:39 +00:00
}
2017-03-27 17:18:53 +00:00
// CheckpointTo makes the Container's current state visible to queries, and persists state.
2017-02-23 23:12:18 +00:00
// Callers must hold a Container lock.
func ( container * Container ) CheckpointTo ( store ViewDB ) error {
2017-04-06 17:43:10 +00:00
deepCopy , err := container . toDisk ( )
if err != nil {
2017-02-23 23:12:18 +00:00
return err
}
2017-04-06 17:43:10 +00:00
return store . Save ( deepCopy )
2017-02-23 23:12:18 +00:00
}
2015-11-12 19:55:17 +00:00
// readHostConfig reads the host configuration from disk for the container.
2013-10-31 21:58:43 +00:00
func ( container * Container ) readHostConfig ( ) error {
2015-12-18 18:36:17 +00:00
container . HostConfig = & containertypes . HostConfig { }
2013-10-31 21:58:43 +00:00
// If the hostconfig file does not exist, do not read it.
2015-11-12 19:55:17 +00:00
// (We still have to initialize container.HostConfig,
2013-10-31 21:58:43 +00:00
// but that's OK, since we just did that above.)
2015-11-12 19:55:17 +00:00
pth , err := container . HostConfigPath ( )
2014-05-28 02:15:42 +00:00
if err != nil {
return err
}
2015-04-21 19:59:59 +00:00
f , err := os . Open ( pth )
2013-07-02 12:19:25 +00:00
if err != nil {
2015-10-30 21:54:09 +00:00
if os . IsNotExist ( err ) {
return nil
}
2013-10-31 21:58:43 +00:00
return err
2013-07-02 12:19:25 +00:00
}
2015-04-21 19:59:59 +00:00
defer f . Close ( )
2015-11-12 19:55:17 +00:00
if err := json . NewDecoder ( f ) . Decode ( & container . HostConfig ) ; err != nil {
2015-11-06 22:22:48 +00:00
return err
}
2015-11-12 19:55:17 +00:00
container . InitDNSHostConfig ( )
2015-11-06 22:22:48 +00:00
return nil
2013-07-02 12:19:25 +00:00
}
2017-04-06 17:43:10 +00:00
// WriteHostConfig saves the host configuration on disk for the container,
// and returns a deep copy of the saved object. Callers must hold a Container lock.
func ( container * Container ) WriteHostConfig ( ) ( * containertypes . HostConfig , error ) {
var (
buf bytes . Buffer
deepCopy containertypes . HostConfig
)
2015-11-12 19:55:17 +00:00
pth , err := container . HostConfigPath ( )
2013-07-02 12:19:25 +00:00
if err != nil {
2017-04-06 17:43:10 +00:00
return nil , err
2013-07-02 12:19:25 +00:00
}
2014-05-28 02:15:42 +00:00
2016-11-01 20:00:17 +00:00
f , err := ioutils . NewAtomicFileWriter ( pth , 0644 )
2014-05-28 02:15:42 +00:00
if err != nil {
2017-04-06 17:43:10 +00:00
return nil , err
2014-05-28 02:15:42 +00:00
}
2015-10-30 21:45:35 +00:00
defer f . Close ( )
2014-05-28 02:15:42 +00:00
2017-04-06 17:43:10 +00:00
w := io . MultiWriter ( & buf , f )
if err := json . NewEncoder ( w ) . Encode ( & container . HostConfig ) ; err != nil {
return nil , err
}
if err := json . NewDecoder ( & buf ) . Decode ( & deepCopy ) ; err != nil {
return nil , err
}
return & deepCopy , nil
2013-07-02 12:19:25 +00:00
}
2016-01-27 21:03:09 +00:00
// SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir
2017-11-16 06:20:33 +00:00
func ( container * Container ) SetupWorkingDirectory ( rootIdentity idtools . Identity ) error {
2019-09-25 17:51:18 +00:00
// TODO: LCOW Support. This will need revisiting.
2017-08-04 18:39:23 +00:00
// We will need to do remote filesystem operations here.
2017-08-08 19:43:48 +00:00
if container . OS != runtime . GOOS {
2017-08-04 18:39:23 +00:00
return nil
}
2016-01-27 21:03:09 +00:00
if container . Config . WorkingDir == "" {
return nil
}
2016-03-01 18:23:43 +00:00
2016-05-26 20:24:22 +00:00
container . Config . WorkingDir = filepath . Clean ( container . Config . WorkingDir )
2016-01-27 21:03:09 +00:00
pth , err := container . GetResourcePath ( container . Config . WorkingDir )
if err != nil {
return err
}
2017-11-16 06:20:33 +00:00
if err := idtools . MkdirAllAndChownNew ( pth , 0755 , rootIdentity ) ; err != nil {
2016-01-27 21:03:09 +00:00
pthInfo , err2 := os . Stat ( pth )
if err2 == nil && pthInfo != nil && ! pthInfo . IsDir ( ) {
2017-07-19 14:20:13 +00:00
return errors . Errorf ( "Cannot mkdir: %s is not a directory" , container . Config . WorkingDir )
2016-01-27 21:03:09 +00:00
}
return err
}
return nil
}
2015-11-12 19:55:17 +00:00
// GetResourcePath evaluates `path` in the scope of the container's BaseFS, with proper path
// sanitisation. Symlinks are all scoped to the BaseFS of the container, as
// though the container's BaseFS was `/`.
2015-03-06 01:53:06 +00:00
//
2015-11-12 19:55:17 +00:00
// The BaseFS of a container is the host-facing path which is bind-mounted as
2015-03-06 01:53:06 +00:00
// `/` inside the container. This method is essentially used to access a
// particular path inside the container as though you were a process in that
// container.
//
2015-11-12 19:55:17 +00:00
// NOTE: The returned path is *only* safely scoped inside the container's BaseFS
2015-03-06 01:53:06 +00:00
// if no component of the returned path changes (such as a component
// symlinking to a different path) between using this method and using the
// path. See symlink.FollowSymlinkInScope for more details.
func ( container * Container ) GetResourcePath ( path string ) ( string , error ) {
2018-03-14 02:45:21 +00:00
if container . BaseFS == nil {
return "" , errors . New ( "GetResourcePath: BaseFS of container " + container . ID + " is unexpectedly nil" )
}
2015-06-01 23:42:27 +00:00
// IMPORTANT - These are paths on the OS where the daemon is running, hence
// any filepath operations must be done in an OS agnostic way.
2017-08-04 00:22:00 +00:00
r , e := container . BaseFS . ResolveScopedPath ( path , false )
2016-04-20 03:55:30 +00:00
// Log this here on the daemon side as there's otherwise no indication apart
// from the error being propagated all the way back to the client. This makes
// debugging significantly easier and clearly indicates the error comes from the daemon.
if e != nil {
2017-08-04 00:22:00 +00:00
logrus . Errorf ( "Failed to ResolveScopedPath BaseFS %s path %s %s\n" , container . BaseFS . Path ( ) , path , e )
2016-04-20 03:55:30 +00:00
}
2015-06-01 23:42:27 +00:00
return r , e
2014-05-11 20:49:46 +00:00
}
2015-11-12 19:55:17 +00:00
// GetRootResourcePath evaluates `path` in the scope of the container's root, with proper path
2015-03-06 01:53:06 +00:00
// sanitisation. Symlinks are all scoped to the root of the container, as
// though the container's root was `/`.
//
// The root of a container is the host-facing configuration metadata directory.
// Only use this method to safely access the container's `container.json` or
// other metadata files. If in doubt, use container.GetResourcePath.
//
// NOTE: The returned path is *only* safely scoped inside the container's root
// if no component of the returned path changes (such as a component
// symlinking to a different path) between using this method and using the
// path. See symlink.FollowSymlinkInScope for more details.
2015-11-12 19:55:17 +00:00
func ( container * Container ) GetRootResourcePath ( path string ) ( string , error ) {
2015-06-01 23:42:27 +00:00
// IMPORTANT - These are paths on the OS where the daemon is running, hence
// any filepath operations must be done in an OS agnostic way.
cleanPath := filepath . Join ( string ( os . PathSeparator ) , path )
2015-11-12 19:55:17 +00:00
return symlink . FollowSymlinkInScope ( filepath . Join ( container . Root , cleanPath ) , container . Root )
2014-05-11 20:49:46 +00:00
}
2015-11-02 23:25:26 +00:00
// ExitOnNext signals to the monitor that it should not restart the container
// after we send the kill signal.
func ( container * Container ) ExitOnNext ( ) {
2016-10-05 20:29:56 +00:00
container . RestartManager ( ) . Cancel ( )
2013-05-24 02:33:28 +00:00
}
2015-11-12 19:55:17 +00:00
// HostConfigPath returns the path to the container's JSON hostconfig
func ( container * Container ) HostConfigPath ( ) ( string , error ) {
return container . GetRootResourcePath ( "hostconfig.json" )
2013-03-21 07:25:00 +00:00
}
2015-11-12 19:55:17 +00:00
// ConfigPath returns the path to the container's JSON config
func ( container * Container ) ConfigPath ( ) ( string , error ) {
return container . GetRootResourcePath ( configFileName )
2013-03-21 07:25:00 +00:00
}
2016-05-12 14:52:00 +00:00
// CheckpointDir returns the directory checkpoints are stored in
func ( container * Container ) CheckpointDir ( ) string {
return filepath . Join ( container . Root , "checkpoints" )
}
2015-11-03 18:45:12 +00:00
// StartLogger starts a new logger driver for the container.
2016-11-22 11:40:54 +00:00
func ( container * Container ) StartLogger ( ) ( logger . Logger , error ) {
cfg := container . HostConfig . LogConfig
2016-11-23 02:55:27 +00:00
initDriver , err := logger . GetLogDriver ( cfg . Type )
2015-04-09 04:23:30 +00:00
if err != nil {
2017-07-19 14:20:13 +00:00
return nil , errors . Wrap ( err , "failed to get logging factory" )
2015-04-09 04:23:30 +00:00
}
2016-11-26 05:08:34 +00:00
info := logger . Info {
2015-05-29 21:00:46 +00:00
Config : cfg . Config ,
ContainerID : container . ID ,
ContainerName : container . Name ,
ContainerEntrypoint : container . Path ,
ContainerArgs : container . Args ,
2015-11-18 22:20:54 +00:00
ContainerImageID : container . ImageID . String ( ) ,
2015-05-29 21:00:46 +00:00
ContainerImageName : container . Config . Image ,
ContainerCreated : container . Created ,
2015-08-11 11:27:19 +00:00
ContainerEnv : container . Config . Env ,
ContainerLabels : container . Config . Labels ,
2016-04-28 02:46:54 +00:00
DaemonName : "docker" ,
2015-04-09 04:23:30 +00:00
}
// Set logging file for "json-logger"
2018-04-05 16:41:35 +00:00
// TODO(@cpuguy83): Setup here based on log driver is a little weird.
switch cfg . Type {
case jsonfilelog . Name :
2016-11-26 05:08:34 +00:00
info . LogPath , err = container . GetRootResourcePath ( fmt . Sprintf ( "%s-json.log" , container . ID ) )
2015-04-20 18:26:39 +00:00
if err != nil {
2015-04-09 04:23:30 +00:00
return nil , err
2015-04-20 18:26:39 +00:00
}
2018-02-10 00:03:47 +00:00
container . LogPath = info . LogPath
2018-04-05 16:41:35 +00:00
case local . Name :
// Do not set container.LogPath for the local driver
// This would expose the value to the API, which should not be done as it means
// that the log file implementation would become a stable API that cannot change.
logDir , err := container . GetRootResourcePath ( "local-logs" )
if err != nil {
return nil , err
}
if err := os . MkdirAll ( logDir , 0700 ) ; err != nil {
return nil , errdefs . System ( errors . Wrap ( err , "error creating local logs dir" ) )
}
info . LogPath = filepath . Join ( logDir , "container.log" )
2015-04-09 04:23:30 +00:00
}
2016-11-23 02:55:27 +00:00
l , err := initDriver ( info )
if err != nil {
return nil , err
}
if containertypes . LogMode ( cfg . Config [ "mode" ] ) == containertypes . LogModeNonBlock {
bufferSize := int64 ( - 1 )
if s , exists := cfg . Config [ "max-buffer-size" ] ; exists {
bufferSize , err = units . RAMInBytes ( s )
if err != nil {
return nil , err
}
}
l = logger . NewRingLogger ( l , info , bufferSize )
}
2018-04-05 16:42:31 +00:00
if _ , ok := l . ( logger . LogReader ) ; ! ok {
2018-04-09 19:35:24 +00:00
if cache . ShouldUseCache ( cfg . Config ) {
logPath , err := container . GetRootResourcePath ( "container-cached.log" )
if err != nil {
return nil , err
}
2018-04-05 16:42:31 +00:00
2018-04-09 19:35:24 +00:00
if ! container . LocalLogCacheMeta . HaveNotifyEnabled {
logrus . WithField ( "container" , container . ID ) . WithField ( "driver" , container . HostConfig . LogConfig . Type ) . Info ( "Configured log driver does not support reads, enabling local file cache for container logs" )
container . LocalLogCacheMeta . HaveNotifyEnabled = true
}
info . LogPath = logPath
l , err = cache . WithLocalCache ( l , info )
if err != nil {
return nil , errors . Wrap ( err , "error setting up local container log cache" )
}
2018-04-05 16:42:31 +00:00
}
}
2016-11-23 02:55:27 +00:00
return l , nil
2015-04-09 04:23:30 +00:00
}
2015-11-12 19:55:17 +00:00
// GetProcessLabel returns the process label for the container.
func ( container * Container ) GetProcessLabel ( ) string {
2014-04-29 08:08:19 +00:00
// even if we have a process label return "" if we are running
// in privileged mode
2015-11-12 19:55:17 +00:00
if container . HostConfig . Privileged {
2014-04-29 08:08:19 +00:00
return ""
}
return container . ProcessLabel
}
2015-11-12 19:55:17 +00:00
// GetMountLabel returns the mounting label for the container.
// This label is empty if the container is privileged.
func ( container * Container ) GetMountLabel ( ) string {
2014-04-29 08:08:19 +00:00
return container . MountLabel
}
2014-05-02 23:59:28 +00:00
2015-11-12 19:55:17 +00:00
// GetExecIDs returns the list of exec commands running on the container.
func ( container * Container ) GetExecIDs ( ) [ ] string {
return container . ExecCommands . List ( )
2015-05-04 12:39:51 +00:00
}
2015-11-12 19:55:17 +00:00
// ShouldRestart decides whether the daemon should restart the container or not.
// This is based on the container's restart policy.
func ( container * Container ) ShouldRestart ( ) bool {
2016-10-05 20:29:56 +00:00
shouldRestart , _ , _ := container . RestartManager ( ) . ShouldRestart ( uint32 ( container . ExitCode ( ) ) , container . HasBeenManuallyStopped , container . FinishedAt . Sub ( container . StartedAt ) )
2016-03-22 15:46:40 +00:00
return shouldRestart
2015-05-19 20:05:25 +00:00
}
2015-05-22 17:37:00 +00:00
2015-11-12 19:55:17 +00:00
// AddMountPointWithVolume adds a new mount point configured with a volume to the container.
func ( container * Container ) AddMountPointWithVolume ( destination string , vol volume . Volume , rw bool ) {
2017-08-08 19:43:48 +00:00
operatingSystem := container . OS
2017-08-01 17:32:44 +00:00
if operatingSystem == "" {
operatingSystem = runtime . GOOS
}
2018-04-17 20:50:28 +00:00
volumeParser := volumemounts . NewParser ( operatingSystem )
container . MountPoints [ destination ] = & volumemounts . MountPoint {
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
Type : mounttypes . TypeVolume ,
2015-09-10 02:23:06 +00:00
Name : vol . Name ( ) ,
Driver : vol . DriverName ( ) ,
Destination : destination ,
RW : rw ,
Volume : vol ,
2017-08-01 17:32:44 +00:00
CopyData : volumeParser . DefaultCopyMode ( ) ,
2015-09-10 02:23:06 +00:00
}
}
2016-10-03 17:53:06 +00:00
// UnmountVolumes unmounts all volumes
func ( container * Container ) UnmountVolumes ( volumeEventLog func ( name , action string , attributes map [ string ] string ) ) error {
var errors [ ] string
for _ , volumeMount := range container . MountPoints {
2017-04-28 03:33:33 +00:00
if volumeMount . Volume == nil {
continue
}
2016-10-03 17:53:06 +00:00
2017-04-28 03:33:33 +00:00
if err := volumeMount . Cleanup ( ) ; err != nil {
errors = append ( errors , err . Error ( ) )
continue
}
attributes := map [ string ] string {
"driver" : volumeMount . Volume . DriverName ( ) ,
"container" : container . ID ,
2016-10-03 17:53:06 +00:00
}
2017-04-28 03:33:33 +00:00
volumeEventLog ( volumeMount . Volume . Name ( ) , "unmount" , attributes )
2016-10-03 17:53:06 +00:00
}
if len ( errors ) > 0 {
return fmt . Errorf ( "error while unmounting volumes for container %s: %s" , container . ID , strings . Join ( errors , "; " ) )
}
return nil
}
2015-12-13 16:00:39 +00:00
// IsDestinationMounted checks whether a path is mounted on the container or not.
2015-11-12 19:55:17 +00:00
func ( container * Container ) IsDestinationMounted ( destination string ) bool {
2015-09-10 02:23:06 +00:00
return container . MountPoints [ destination ] != nil
2015-05-22 17:37:00 +00:00
}
2015-08-04 20:51:48 +00:00
2015-11-12 19:55:17 +00:00
// StopSignal returns the signal used to stop the container.
func ( container * Container ) StopSignal ( ) int {
2015-08-04 20:51:48 +00:00
var stopSignal syscall . Signal
if container . Config . StopSignal != "" {
stopSignal , _ = signal . ParseSignal ( container . Config . StopSignal )
}
if int ( stopSignal ) == 0 {
stopSignal , _ = signal . ParseSignal ( signal . DefaultStopSignal )
}
return int ( stopSignal )
}
2015-11-30 22:44:34 +00:00
2016-05-26 20:34:48 +00:00
// StopTimeout returns the timeout (in seconds) used to stop the container.
func ( container * Container ) StopTimeout ( ) int {
if container . Config . StopTimeout != nil {
return * container . Config . StopTimeout
}
2016-06-07 03:29:05 +00:00
return DefaultStopTimeout
2016-05-26 20:34:48 +00:00
}
2015-11-12 19:55:17 +00:00
// InitDNSHostConfig ensures that the dns fields are never nil.
2015-11-30 22:44:34 +00:00
// New containers don't ever have those fields nil,
// but pre created containers can still have those nil values.
// The non-recommended host configuration in the start api can
// make these fields nil again, this corrects that issue until
// we remove that behavior for good.
// See https://github.com/docker/docker/pull/17779
// for a more detailed explanation on why we don't want that.
2015-11-12 19:55:17 +00:00
func ( container * Container ) InitDNSHostConfig ( ) {
2015-12-11 02:33:13 +00:00
container . Lock ( )
defer container . Unlock ( )
2015-11-12 19:55:17 +00:00
if container . HostConfig . DNS == nil {
container . HostConfig . DNS = make ( [ ] string , 0 )
2015-11-30 22:44:34 +00:00
}
2015-11-12 19:55:17 +00:00
if container . HostConfig . DNSSearch == nil {
container . HostConfig . DNSSearch = make ( [ ] string , 0 )
2015-11-30 22:44:34 +00:00
}
2015-11-12 19:55:17 +00:00
if container . HostConfig . DNSOptions == nil {
container . HostConfig . DNSOptions = make ( [ ] string , 0 )
2015-11-30 22:44:34 +00:00
}
}
2016-01-04 15:58:20 +00:00
// UpdateMonitor updates monitor configure for running container
func ( container * Container ) UpdateMonitor ( restartPolicy containertypes . RestartPolicy ) {
2016-03-18 18:50:19 +00:00
type policySetter interface {
SetPolicy ( containertypes . RestartPolicy )
}
2016-10-05 20:29:56 +00:00
if rm , ok := container . RestartManager ( ) . ( policySetter ) ; ok {
2016-03-18 18:50:19 +00:00
rm . SetPolicy ( restartPolicy )
}
}
// FullHostname returns hostname and optional domain appended to it.
func ( container * Container ) FullHostname ( ) string {
fullHostname := container . Config . Hostname
if container . Config . Domainname != "" {
fullHostname = fmt . Sprintf ( "%s.%s" , fullHostname , container . Config . Domainname )
2016-01-04 15:58:20 +00:00
}
2016-03-18 18:50:19 +00:00
return fullHostname
}
2016-01-04 15:58:20 +00:00
2016-04-08 14:08:58 +00:00
// RestartManager returns the current restartmanager instance connected to container.
2016-10-05 20:29:56 +00:00
func ( container * Container ) RestartManager ( ) restartmanager . RestartManager {
2016-03-18 18:50:19 +00:00
if container . restartManager == nil {
2016-03-22 15:46:40 +00:00
container . restartManager = restartmanager . New ( container . HostConfig . RestartPolicy , container . RestartCount )
2016-01-04 15:58:20 +00:00
}
2016-03-18 18:50:19 +00:00
return container . restartManager
2016-01-04 15:58:20 +00:00
}
2016-03-09 00:54:33 +00:00
2016-10-05 20:29:56 +00:00
// ResetRestartManager initializes new restartmanager based on container config
func ( container * Container ) ResetRestartManager ( resetCount bool ) {
if container . restartManager != nil {
container . restartManager . Cancel ( )
}
if resetCount {
container . RestartCount = 0
}
container . restartManager = nil
}
2016-03-09 00:54:33 +00:00
type attachContext struct {
ctx context . Context
cancel context . CancelFunc
mu sync . Mutex
}
2016-09-04 07:17:58 +00:00
// InitAttachContext initializes or returns existing context for attach calls to
2016-03-09 00:54:33 +00:00
// track container liveness.
func ( container * Container ) InitAttachContext ( ) context . Context {
container . attachContext . mu . Lock ( )
defer container . attachContext . mu . Unlock ( )
if container . attachContext . ctx == nil {
container . attachContext . ctx , container . attachContext . cancel = context . WithCancel ( context . Background ( ) )
}
return container . attachContext . ctx
}
2016-09-04 07:17:58 +00:00
// CancelAttachContext cancels attach context. All attach calls should detach
2016-03-09 00:54:33 +00:00
// after this call.
func ( container * Container ) CancelAttachContext ( ) {
container . attachContext . mu . Lock ( )
if container . attachContext . ctx != nil {
container . attachContext . cancel ( )
container . attachContext . ctx = nil
}
container . attachContext . mu . Unlock ( )
}
2016-10-17 21:39:52 +00:00
func ( container * Container ) startLogging ( ) error {
if container . HostConfig . LogConfig . Type == "none" {
return nil // do not start logging routines
}
2016-11-22 11:40:54 +00:00
l , err := container . StartLogger ( )
2016-10-17 21:39:52 +00:00
if err != nil {
2016-11-22 11:40:54 +00:00
return fmt . Errorf ( "failed to initialize logging driver: %v" , err )
2016-10-17 21:39:52 +00:00
}
copier := logger . NewCopier ( map [ string ] io . Reader { "stdout" : container . StdoutPipe ( ) , "stderr" : container . StderrPipe ( ) } , l )
container . LogCopier = copier
copier . Run ( )
container . LogDriver = l
return nil
}
2016-11-14 20:15:09 +00:00
// StdinPipe gets the stdin stream of the container
func ( container * Container ) StdinPipe ( ) io . WriteCloser {
return container . StreamConfig . StdinPipe ( )
}
// StdoutPipe gets the stdout stream of the container
func ( container * Container ) StdoutPipe ( ) io . ReadCloser {
return container . StreamConfig . StdoutPipe ( )
}
// StderrPipe gets the stderr stream of the container
func ( container * Container ) StderrPipe ( ) io . ReadCloser {
return container . StreamConfig . StderrPipe ( )
}
// CloseStreams closes the container's stdio streams
func ( container * Container ) CloseStreams ( ) error {
return container . StreamConfig . CloseStreams ( )
}
2016-10-17 21:39:52 +00:00
// InitializeStdio is called by libcontainerd to connect the stdio.
2017-12-07 19:26:27 +00:00
func ( container * Container ) InitializeStdio ( iop * cio . DirectIO ) ( cio . IO , error ) {
2016-10-17 21:39:52 +00:00
if err := container . startLogging ( ) ; err != nil {
container . Reset ( false )
2017-09-22 13:52:41 +00:00
return nil , err
2016-10-17 21:39:52 +00:00
}
container . StreamConfig . CopyToPipe ( iop )
2016-11-14 20:15:09 +00:00
if container . StreamConfig . Stdin ( ) == nil && ! container . Config . Tty {
2016-10-17 21:39:52 +00:00
if iop . Stdin != nil {
if err := iop . Stdin . Close ( ) ; err != nil {
2016-10-26 01:34:35 +00:00
logrus . Warnf ( "error closing stdin: %+v" , err )
2016-10-17 21:39:52 +00:00
}
}
}
2017-11-30 00:15:20 +00:00
return & rio { IO : iop , sc : container . StreamConfig } , nil
2016-10-17 21:39:52 +00:00
}
2017-04-11 17:34:19 +00:00
2017-12-18 21:02:23 +00:00
// MountsResourcePath returns the path where mounts are stored for the given mount
func ( container * Container ) MountsResourcePath ( mount string ) ( string , error ) {
return container . GetRootResourcePath ( filepath . Join ( "mounts" , mount ) )
}
2017-04-11 17:34:19 +00:00
// SecretMountPath returns the path of the secret mount for the container
2017-12-18 21:02:23 +00:00
func ( container * Container ) SecretMountPath ( ) ( string , error ) {
return container . MountsResourcePath ( "secrets" )
2017-04-11 17:34:19 +00:00
}
2017-04-28 18:48:52 +00:00
// SecretFilePath returns the path to the location of a secret on the host.
2017-12-18 21:02:23 +00:00
func ( container * Container ) SecretFilePath ( secretRef swarmtypes . SecretReference ) ( string , error ) {
secrets , err := container . SecretMountPath ( )
if err != nil {
return "" , err
}
return filepath . Join ( secrets , secretRef . SecretID ) , nil
2017-04-11 17:34:19 +00:00
}
func getSecretTargetPath ( r * swarmtypes . SecretReference ) string {
if filepath . IsAbs ( r . File . Name ) {
return r . File . Name
}
return filepath . Join ( containerSecretMountPath , r . File . Name )
}
2017-03-16 21:23:33 +00:00
2017-05-26 23:14:18 +00:00
// CreateDaemonEnvironment creates a new environment variable slice for this container.
func ( container * Container ) CreateDaemonEnvironment ( tty bool , linkedEnv [ ] string ) [ ] string {
// Setup environment
2017-08-08 19:43:48 +00:00
os := container . OS
if os == "" {
os = runtime . GOOS
2017-05-26 23:14:18 +00:00
}
2020-04-22 17:51:03 +00:00
// Figure out what size slice we need so we can allocate this all at once.
envSize := len ( container . Config . Env )
2017-08-08 19:43:48 +00:00
if runtime . GOOS != "windows" || ( runtime . GOOS == "windows" && os == "linux" ) {
2020-04-22 17:51:03 +00:00
envSize += 2 + len ( linkedEnv )
}
if tty {
envSize ++
}
env := make ( [ ] string , 0 , envSize )
if runtime . GOOS != "windows" || ( runtime . GOOS == "windows" && os == "linux" ) {
env = append ( env , "PATH=" + system . DefaultPathEnv ( os ) )
env = append ( env , "HOSTNAME=" + container . Config . Hostname )
2017-05-26 23:14:18 +00:00
if tty {
env = append ( env , "TERM=xterm" )
}
env = append ( env , linkedEnv ... )
}
// because the env on the container can override certain default values
// we need to replace the 'env' keys where they match and append anything
// else.
2017-06-26 16:11:54 +00:00
env = ReplaceOrAppendEnvValues ( env , container . Config . Env )
return env
2017-05-26 23:14:18 +00:00
}
2017-09-22 13:52:41 +00:00
2017-11-30 00:15:20 +00:00
type rio struct {
cio . IO
2017-09-22 13:52:41 +00:00
sc * stream . Config
}
2017-11-30 00:15:20 +00:00
func ( i * rio ) Close ( ) error {
2017-09-22 13:52:41 +00:00
i . IO . Close ( )
return i . sc . CloseStreams ( )
}
2017-11-30 00:15:20 +00:00
func ( i * rio ) Wait ( ) {
2019-06-20 20:21:42 +00:00
i . sc . Wait ( context . Background ( ) )
2017-09-22 13:52:41 +00:00
i . IO . Wait ( )
}