2014-07-31 20:36:42 +00:00
|
|
|
package daemon
|
|
|
|
|
|
|
|
import (
|
2014-11-10 21:14:17 +00:00
|
|
|
"fmt"
|
2015-03-16 07:07:33 +00:00
|
|
|
"strings"
|
2014-11-10 21:14:17 +00:00
|
|
|
|
2014-07-31 20:36:42 +00:00
|
|
|
"github.com/docker/docker/graph"
|
2014-10-28 21:06:23 +00:00
|
|
|
"github.com/docker/docker/image"
|
2014-07-31 20:36:42 +00:00
|
|
|
"github.com/docker/docker/pkg/parsers"
|
|
|
|
"github.com/docker/docker/runconfig"
|
2014-11-10 21:14:17 +00:00
|
|
|
"github.com/docker/libcontainer/label"
|
2014-07-31 20:36:42 +00:00
|
|
|
)
|
|
|
|
|
2015-04-11 00:05:21 +00:00
|
|
|
func (daemon *Daemon) ContainerCreate(name string, config *runconfig.Config, hostConfig *runconfig.HostConfig) (string, []string, error) {
|
2015-04-09 21:49:22 +00:00
|
|
|
var warnings []string
|
move resources from Config to HostConfig
Cgroup resources are host dependent, they should be in hostConfig.
For backward compatibility, we just copy it to hostConfig, and leave it in
Config for now, so there is no regressions, but the right way to use this
throught json is to put it in HostConfig, like:
{
"Hostname": "",
...
"HostConfig": {
"CpuShares": 512,
"Memory": 314572800,
...
}
}
As we will add CpusetMems, CpusetCpus is definitely a better name, but some
users are already using Cpuset in their http APIs, we also make it compatible.
The main idea is keep using Cpuset in Config Struct, and make it has the same
value as CpusetCpus, but not always, some scenarios:
- Users use --cpuset in docker command, it can setup cpuset.cpus and can
get Cpuset field from docker inspect or other http API which will get
config info.
- Users use --cpuset-cpus in docker command, ditto.
- Users use Cpuset field in their http APIs, ditto.
- Users use CpusetCpus field in their http APIs, they won't get Cpuset field
in Config info, because by then, they should already know what happens
to Cpuset.
Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
2015-03-11 01:31:18 +00:00
|
|
|
|
2015-04-11 00:05:21 +00:00
|
|
|
if hostConfig.LxcConf.Len() > 0 && !strings.Contains(daemon.ExecutionDriver().Name(), "lxc") {
|
2015-04-09 21:49:22 +00:00
|
|
|
return "", warnings, fmt.Errorf("Cannot use --lxc-conf with execdriver: %s", daemon.ExecutionDriver().Name())
|
2015-03-16 07:07:33 +00:00
|
|
|
}
|
move resources from Config to HostConfig
Cgroup resources are host dependent, they should be in hostConfig.
For backward compatibility, we just copy it to hostConfig, and leave it in
Config for now, so there is no regressions, but the right way to use this
throught json is to put it in HostConfig, like:
{
"Hostname": "",
...
"HostConfig": {
"CpuShares": 512,
"Memory": 314572800,
...
}
}
As we will add CpusetMems, CpusetCpus is definitely a better name, but some
users are already using Cpuset in their http APIs, we also make it compatible.
The main idea is keep using Cpuset in Config Struct, and make it has the same
value as CpusetCpus, but not always, some scenarios:
- Users use --cpuset in docker command, it can setup cpuset.cpus and can
get Cpuset field from docker inspect or other http API which will get
config info.
- Users use --cpuset-cpus in docker command, ditto.
- Users use Cpuset field in their http APIs, ditto.
- Users use CpusetCpus field in their http APIs, they won't get Cpuset field
in Config info, because by then, they should already know what happens
to Cpuset.
Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
2015-03-11 01:31:18 +00:00
|
|
|
if hostConfig.Memory != 0 && hostConfig.Memory < 4194304 {
|
2015-04-09 21:49:22 +00:00
|
|
|
return "", warnings, fmt.Errorf("Minimum memory limit allowed is 4MB")
|
2014-07-31 20:36:42 +00:00
|
|
|
}
|
move resources from Config to HostConfig
Cgroup resources are host dependent, they should be in hostConfig.
For backward compatibility, we just copy it to hostConfig, and leave it in
Config for now, so there is no regressions, but the right way to use this
throught json is to put it in HostConfig, like:
{
"Hostname": "",
...
"HostConfig": {
"CpuShares": 512,
"Memory": 314572800,
...
}
}
As we will add CpusetMems, CpusetCpus is definitely a better name, but some
users are already using Cpuset in their http APIs, we also make it compatible.
The main idea is keep using Cpuset in Config Struct, and make it has the same
value as CpusetCpus, but not always, some scenarios:
- Users use --cpuset in docker command, it can setup cpuset.cpus and can
get Cpuset field from docker inspect or other http API which will get
config info.
- Users use --cpuset-cpus in docker command, ditto.
- Users use Cpuset field in their http APIs, ditto.
- Users use CpusetCpus field in their http APIs, they won't get Cpuset field
in Config info, because by then, they should already know what happens
to Cpuset.
Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
2015-03-11 01:31:18 +00:00
|
|
|
if hostConfig.Memory > 0 && !daemon.SystemConfig().MemoryLimit {
|
2015-04-09 21:49:22 +00:00
|
|
|
warnings = append(warnings, "Your kernel does not support memory limit capabilities. Limitation discarded.\n")
|
move resources from Config to HostConfig
Cgroup resources are host dependent, they should be in hostConfig.
For backward compatibility, we just copy it to hostConfig, and leave it in
Config for now, so there is no regressions, but the right way to use this
throught json is to put it in HostConfig, like:
{
"Hostname": "",
...
"HostConfig": {
"CpuShares": 512,
"Memory": 314572800,
...
}
}
As we will add CpusetMems, CpusetCpus is definitely a better name, but some
users are already using Cpuset in their http APIs, we also make it compatible.
The main idea is keep using Cpuset in Config Struct, and make it has the same
value as CpusetCpus, but not always, some scenarios:
- Users use --cpuset in docker command, it can setup cpuset.cpus and can
get Cpuset field from docker inspect or other http API which will get
config info.
- Users use --cpuset-cpus in docker command, ditto.
- Users use Cpuset field in their http APIs, ditto.
- Users use CpusetCpus field in their http APIs, they won't get Cpuset field
in Config info, because by then, they should already know what happens
to Cpuset.
Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
2015-03-11 01:31:18 +00:00
|
|
|
hostConfig.Memory = 0
|
2014-07-31 20:36:42 +00:00
|
|
|
}
|
2015-03-18 02:08:17 +00:00
|
|
|
if hostConfig.Memory > 0 && hostConfig.MemorySwap != -1 && !daemon.SystemConfig().SwapLimit {
|
2015-04-09 21:49:22 +00:00
|
|
|
warnings = append(warnings, "Your kernel does not support swap limit capabilities. Limitation discarded.\n")
|
move resources from Config to HostConfig
Cgroup resources are host dependent, they should be in hostConfig.
For backward compatibility, we just copy it to hostConfig, and leave it in
Config for now, so there is no regressions, but the right way to use this
throught json is to put it in HostConfig, like:
{
"Hostname": "",
...
"HostConfig": {
"CpuShares": 512,
"Memory": 314572800,
...
}
}
As we will add CpusetMems, CpusetCpus is definitely a better name, but some
users are already using Cpuset in their http APIs, we also make it compatible.
The main idea is keep using Cpuset in Config Struct, and make it has the same
value as CpusetCpus, but not always, some scenarios:
- Users use --cpuset in docker command, it can setup cpuset.cpus and can
get Cpuset field from docker inspect or other http API which will get
config info.
- Users use --cpuset-cpus in docker command, ditto.
- Users use Cpuset field in their http APIs, ditto.
- Users use CpusetCpus field in their http APIs, they won't get Cpuset field
in Config info, because by then, they should already know what happens
to Cpuset.
Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
2015-03-11 01:31:18 +00:00
|
|
|
hostConfig.MemorySwap = -1
|
2014-07-31 20:36:42 +00:00
|
|
|
}
|
move resources from Config to HostConfig
Cgroup resources are host dependent, they should be in hostConfig.
For backward compatibility, we just copy it to hostConfig, and leave it in
Config for now, so there is no regressions, but the right way to use this
throught json is to put it in HostConfig, like:
{
"Hostname": "",
...
"HostConfig": {
"CpuShares": 512,
"Memory": 314572800,
...
}
}
As we will add CpusetMems, CpusetCpus is definitely a better name, but some
users are already using Cpuset in their http APIs, we also make it compatible.
The main idea is keep using Cpuset in Config Struct, and make it has the same
value as CpusetCpus, but not always, some scenarios:
- Users use --cpuset in docker command, it can setup cpuset.cpus and can
get Cpuset field from docker inspect or other http API which will get
config info.
- Users use --cpuset-cpus in docker command, ditto.
- Users use Cpuset field in their http APIs, ditto.
- Users use CpusetCpus field in their http APIs, they won't get Cpuset field
in Config info, because by then, they should already know what happens
to Cpuset.
Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
2015-03-11 01:31:18 +00:00
|
|
|
if hostConfig.Memory > 0 && hostConfig.MemorySwap > 0 && hostConfig.MemorySwap < hostConfig.Memory {
|
2015-04-09 21:49:22 +00:00
|
|
|
return "", warnings, fmt.Errorf("Minimum memoryswap limit should be larger than memory limit, see usage.\n")
|
2014-12-11 00:53:43 +00:00
|
|
|
}
|
move resources from Config to HostConfig
Cgroup resources are host dependent, they should be in hostConfig.
For backward compatibility, we just copy it to hostConfig, and leave it in
Config for now, so there is no regressions, but the right way to use this
throught json is to put it in HostConfig, like:
{
"Hostname": "",
...
"HostConfig": {
"CpuShares": 512,
"Memory": 314572800,
...
}
}
As we will add CpusetMems, CpusetCpus is definitely a better name, but some
users are already using Cpuset in their http APIs, we also make it compatible.
The main idea is keep using Cpuset in Config Struct, and make it has the same
value as CpusetCpus, but not always, some scenarios:
- Users use --cpuset in docker command, it can setup cpuset.cpus and can
get Cpuset field from docker inspect or other http API which will get
config info.
- Users use --cpuset-cpus in docker command, ditto.
- Users use Cpuset field in their http APIs, ditto.
- Users use CpusetCpus field in their http APIs, they won't get Cpuset field
in Config info, because by then, they should already know what happens
to Cpuset.
Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
2015-03-11 01:31:18 +00:00
|
|
|
if hostConfig.Memory == 0 && hostConfig.MemorySwap > 0 {
|
2015-04-09 21:49:22 +00:00
|
|
|
return "", warnings, fmt.Errorf("You should always set the Memory limit when using Memoryswap limit, see usage.\n")
|
2015-01-23 03:29:21 +00:00
|
|
|
}
|
2014-09-25 21:23:59 +00:00
|
|
|
|
|
|
|
container, buildWarnings, err := daemon.Create(config, hostConfig, name)
|
2014-07-31 20:36:42 +00:00
|
|
|
if err != nil {
|
2015-03-28 01:07:20 +00:00
|
|
|
if daemon.Graph().IsNotExist(err, config.Image) {
|
2014-07-31 20:36:42 +00:00
|
|
|
_, tag := parsers.ParseRepositoryTag(config.Image)
|
|
|
|
if tag == "" {
|
|
|
|
tag = graph.DEFAULTTAG
|
|
|
|
}
|
2015-04-09 21:49:22 +00:00
|
|
|
return "", warnings, fmt.Errorf("No such image: %s (tag: %s)", config.Image, tag)
|
2014-07-31 20:36:42 +00:00
|
|
|
}
|
2015-04-09 21:49:22 +00:00
|
|
|
return "", warnings, err
|
2014-07-31 20:36:42 +00:00
|
|
|
}
|
|
|
|
if !container.Config.NetworkDisabled && daemon.SystemConfig().IPv4ForwardingDisabled {
|
2015-04-09 21:49:22 +00:00
|
|
|
warnings = append(warnings, "IPv4 forwarding is disabled.\n")
|
2014-07-31 20:36:42 +00:00
|
|
|
}
|
2014-12-01 16:44:13 +00:00
|
|
|
|
2015-04-09 21:49:22 +00:00
|
|
|
container.LogEvent("create")
|
|
|
|
warnings = append(warnings, buildWarnings...)
|
2014-03-10 13:11:23 +00:00
|
|
|
|
2015-04-09 21:49:22 +00:00
|
|
|
return container.ID, warnings, nil
|
2014-07-31 20:36:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create creates a new container from the given configuration with a given name.
|
2014-09-25 21:23:59 +00:00
|
|
|
func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.HostConfig, name string) (*Container, []string, error) {
|
2014-07-31 20:36:42 +00:00
|
|
|
var (
|
|
|
|
container *Container
|
|
|
|
warnings []string
|
2014-10-28 21:06:23 +00:00
|
|
|
img *image.Image
|
|
|
|
imgID string
|
|
|
|
err error
|
2014-07-31 20:36:42 +00:00
|
|
|
)
|
|
|
|
|
2014-10-28 21:06:23 +00:00
|
|
|
if config.Image != "" {
|
|
|
|
img, err = daemon.repositories.LookupImage(config.Image)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
if err = img.CheckDepth(); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
imgID = img.ID
|
2014-07-31 20:36:42 +00:00
|
|
|
}
|
2014-10-28 21:06:23 +00:00
|
|
|
|
2014-07-31 20:36:42 +00:00
|
|
|
if warnings, err = daemon.mergeAndVerifyConfig(config, img); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2015-01-19 17:09:02 +00:00
|
|
|
if hostConfig == nil {
|
|
|
|
hostConfig = &runconfig.HostConfig{}
|
|
|
|
}
|
|
|
|
if hostConfig.SecurityOpt == nil {
|
2014-11-25 20:10:53 +00:00
|
|
|
hostConfig.SecurityOpt, err = daemon.GenerateSecurityOpt(hostConfig.IpcMode, hostConfig.PidMode)
|
2014-11-10 21:14:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
}
|
2014-10-28 21:06:23 +00:00
|
|
|
if container, err = daemon.newContainer(name, config, imgID); err != nil {
|
2014-07-31 20:36:42 +00:00
|
|
|
return nil, nil, err
|
|
|
|
}
|
2014-09-30 00:06:26 +00:00
|
|
|
if err := daemon.Register(container); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2014-10-28 21:06:23 +00:00
|
|
|
if err := daemon.createRootfs(container); err != nil {
|
2014-07-31 20:36:42 +00:00
|
|
|
return nil, nil, err
|
|
|
|
}
|
2014-09-25 21:23:59 +00:00
|
|
|
if hostConfig != nil {
|
|
|
|
if err := daemon.setHostConfig(container, hostConfig); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
}
|
2014-11-11 16:17:33 +00:00
|
|
|
if err := container.Mount(); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
defer container.Unmount()
|
|
|
|
if err := container.prepareVolumes(); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2014-07-31 20:36:42 +00:00
|
|
|
if err := container.ToDisk(); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
return container, warnings, nil
|
|
|
|
}
|
2014-12-01 16:44:13 +00:00
|
|
|
|
2014-11-25 20:10:53 +00:00
|
|
|
func (daemon *Daemon) GenerateSecurityOpt(ipcMode runconfig.IpcMode, pidMode runconfig.PidMode) ([]string, error) {
|
|
|
|
if ipcMode.IsHost() || pidMode.IsHost() {
|
2014-11-10 21:14:17 +00:00
|
|
|
return label.DisableSecOpt(), nil
|
|
|
|
}
|
|
|
|
if ipcContainer := ipcMode.Container(); ipcContainer != "" {
|
2014-12-16 23:06:35 +00:00
|
|
|
c, err := daemon.Get(ipcContainer)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2014-11-10 21:14:17 +00:00
|
|
|
}
|
|
|
|
if !c.IsRunning() {
|
|
|
|
return nil, fmt.Errorf("cannot join IPC of a non running container: %s", ipcContainer)
|
|
|
|
}
|
|
|
|
|
|
|
|
return label.DupSecOpt(c.ProcessLabel), nil
|
|
|
|
}
|
|
|
|
return nil, nil
|
|
|
|
}
|