mirror of
https://github.com/docker/cli.git
synced 2026-01-23 15:21:32 +03:00
Move graph related functions in image to graph package. Consolidating graph functionality is the first step in refactoring graph into an image store model. Subsequent refactors will involve breaking up graph into multiple types with a strongly defined interface. Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan) Upstream-commit: 2b58b677a54950bc78c13760ef79fe6284154847 Component: engine
162 lines
4.4 KiB
Go
162 lines
4.4 KiB
Go
package daemon
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/docker/docker/graph"
|
|
"github.com/docker/docker/image"
|
|
"github.com/docker/docker/pkg/parsers"
|
|
"github.com/docker/docker/pkg/stringid"
|
|
"github.com/docker/docker/runconfig"
|
|
"github.com/docker/libcontainer/label"
|
|
)
|
|
|
|
func (daemon *Daemon) ContainerCreate(name string, config *runconfig.Config, hostConfig *runconfig.HostConfig) (string, []string, error) {
|
|
warnings, err := daemon.verifyHostConfig(hostConfig)
|
|
if err != nil {
|
|
return "", warnings, err
|
|
}
|
|
|
|
// The check for a valid workdir path is made on the server rather than in the
|
|
// client. This is because we don't know the type of path (Linux or Windows)
|
|
// to validate on the client.
|
|
if config.WorkingDir != "" && !filepath.IsAbs(config.WorkingDir) {
|
|
return "", warnings, fmt.Errorf("The working directory '%s' is invalid. It needs to be an absolute path.", config.WorkingDir)
|
|
}
|
|
|
|
container, buildWarnings, err := daemon.Create(config, hostConfig, name)
|
|
if err != nil {
|
|
if daemon.Graph().IsNotExist(err, config.Image) {
|
|
_, tag := parsers.ParseRepositoryTag(config.Image)
|
|
if tag == "" {
|
|
tag = graph.DEFAULTTAG
|
|
}
|
|
return "", warnings, fmt.Errorf("No such image: %s (tag: %s)", config.Image, tag)
|
|
}
|
|
return "", warnings, err
|
|
}
|
|
|
|
warnings = append(warnings, buildWarnings...)
|
|
|
|
return container.ID, warnings, nil
|
|
}
|
|
|
|
// Create creates a new container from the given configuration with a given name.
|
|
func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.HostConfig, name string) (*Container, []string, error) {
|
|
var (
|
|
container *Container
|
|
warnings []string
|
|
img *image.Image
|
|
imgID string
|
|
err error
|
|
)
|
|
|
|
if config.Image != "" {
|
|
img, err = daemon.repositories.LookupImage(config.Image)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err = daemon.graph.CheckDepth(img); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
imgID = img.ID
|
|
}
|
|
|
|
if err := daemon.mergeAndVerifyConfig(config, img); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if !config.NetworkDisabled && daemon.SystemConfig().IPv4ForwardingDisabled {
|
|
warnings = append(warnings, "IPv4 forwarding is disabled.")
|
|
}
|
|
if hostConfig == nil {
|
|
hostConfig = &runconfig.HostConfig{}
|
|
}
|
|
if hostConfig.SecurityOpt == nil {
|
|
hostConfig.SecurityOpt, err = daemon.GenerateSecurityOpt(hostConfig.IpcMode, hostConfig.PidMode)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
}
|
|
if container, err = daemon.newContainer(name, config, imgID); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err := daemon.Register(container); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err := daemon.createRootfs(container); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err := daemon.setHostConfig(container, hostConfig); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err := container.Mount(); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
defer container.Unmount()
|
|
|
|
for spec := range config.Volumes {
|
|
var (
|
|
name, destination string
|
|
parts = strings.Split(spec, ":")
|
|
)
|
|
switch len(parts) {
|
|
case 2:
|
|
name, destination = parts[0], filepath.Clean(parts[1])
|
|
default:
|
|
name = stringid.GenerateRandomID()
|
|
destination = filepath.Clean(parts[0])
|
|
}
|
|
// Skip volumes for which we already have something mounted on that
|
|
// destination because of a --volume-from.
|
|
if container.isDestinationMounted(destination) {
|
|
continue
|
|
}
|
|
path, err := container.GetResourcePath(destination)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
stat, err := os.Stat(path)
|
|
if err == nil && !stat.IsDir() {
|
|
return nil, nil, fmt.Errorf("cannot mount volume over existing file, file exists %s", path)
|
|
}
|
|
|
|
v, err := createVolume(name, config.VolumeDriver)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err := label.Relabel(v.Path(), container.MountLabel, "z"); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
if err := container.copyImagePathContent(v, destination); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
container.addMountPointWithVolume(destination, v, true)
|
|
}
|
|
if err := container.ToDisk(); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
container.LogEvent("create")
|
|
return container, warnings, nil
|
|
}
|
|
|
|
func (daemon *Daemon) GenerateSecurityOpt(ipcMode runconfig.IpcMode, pidMode runconfig.PidMode) ([]string, error) {
|
|
if ipcMode.IsHost() || pidMode.IsHost() {
|
|
return label.DisableSecOpt(), nil
|
|
}
|
|
if ipcContainer := ipcMode.Container(); ipcContainer != "" {
|
|
c, err := daemon.Get(ipcContainer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return label.DupSecOpt(c.ProcessLabel), nil
|
|
}
|
|
return nil, nil
|
|
}
|