Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion api/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2680,7 +2680,13 @@ definitions:
ConfigName is the name of the config that this references, but this is just provided for
lookup/display purposes. The config in the reference will be identified by its ID.
type: "string"

Isolation:
Copy link
Copy Markdown
Member

@thaJeztah thaJeztah Aug 8, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this go into TaskTemplate.ContainerSpec?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is the case :)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh boy, you're right; It looked as if it was at the wrong indentation level, but you're right. Sorry, my mistake ha!

type: "string"
description: "Isolation technology of the containers running the service. (Windows only)"
enum:
- "default"
- "process"
- "hyperv"
Resources:
description: "Resource requirements which apply to each individual container created as part of the service."
type: "object"
Expand Down
21 changes: 21 additions & 0 deletions api/types/container/host_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,27 @@ func (i Isolation) IsDefault() bool {
return strings.ToLower(string(i)) == "default" || string(i) == ""
}

// IsHyperV indicates the use of a Hyper-V partition for isolation
func (i Isolation) IsHyperV() bool {
return strings.ToLower(string(i)) == "hyperv"
}

// IsProcess indicates the use of process isolation
func (i Isolation) IsProcess() bool {
return strings.ToLower(string(i)) == "process"
}

const (
// IsolationEmpty is unspecified (same behavior as default)
IsolationEmpty = Isolation("")
// IsolationDefault is the default isolation mode on current daemon
IsolationDefault = Isolation("default")
// IsolationProcess is process isolation mode
IsolationProcess = Isolation("process")
// IsolationHyperV is HyperV isolation mode
IsolationHyperV = Isolation("hyperv")
)

// IpcMode represents the container ipc stack.
type IpcMode string

Expand Down
14 changes: 0 additions & 14 deletions api/types/container/hostconfig_windows.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package container

import (
"strings"
)

// IsBridge indicates whether container uses the bridge network stack
// in windows it is given the name NAT
func (n NetworkMode) IsBridge() bool {
Expand All @@ -21,16 +17,6 @@ func (n NetworkMode) IsUserDefined() bool {
return !n.IsDefault() && !n.IsNone() && !n.IsBridge() && !n.IsContainer()
}

// IsHyperV indicates the use of a Hyper-V partition for isolation
func (i Isolation) IsHyperV() bool {
return strings.ToLower(string(i)) == "hyperv"
}

// IsProcess indicates the use of process isolation
func (i Isolation) IsProcess() bool {
return strings.ToLower(string(i)) == "process"
}

// IsValid indicates if an isolation technology is valid
func (i Isolation) IsValid() bool {
return i.IsDefault() || i.IsHyperV() || i.IsProcess()
Expand Down
9 changes: 5 additions & 4 deletions api/types/swarm/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,9 @@ type ContainerSpec struct {
// The format of extra hosts on swarmkit is specified in:
// http://man7.org/linux/man-pages/man5/hosts.5.html
// IP_address canonical_hostname [aliases...]
Hosts []string `json:",omitempty"`
DNSConfig *DNSConfig `json:",omitempty"`
Secrets []*SecretReference `json:",omitempty"`
Configs []*ConfigReference `json:",omitempty"`
Hosts []string `json:",omitempty"`
DNSConfig *DNSConfig `json:",omitempty"`
Secrets []*SecretReference `json:",omitempty"`
Configs []*ConfigReference `json:",omitempty"`
Isolation container.Isolation `json:",omitempty"`
}
25 changes: 25 additions & 0 deletions daemon/cluster/convert/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func containerSpecFromGRPC(c *swarmapi.ContainerSpec) *types.ContainerSpec {
Hosts: c.Hosts,
Secrets: secretReferencesFromGRPC(c.Secrets),
Configs: configReferencesFromGRPC(c.Configs),
Isolation: IsolationFromGRPC(c.Isolation),
}

if c.DNSConfig != nil {
Expand Down Expand Up @@ -232,6 +233,7 @@ func containerToGRPC(c *types.ContainerSpec) (*swarmapi.ContainerSpec, error) {
Hosts: c.Hosts,
Secrets: secretReferencesToGRPC(c.Secrets),
Configs: configReferencesToGRPC(c.Configs),
Isolation: isolationToGRPC(c.Isolation),
}

if c.DNSConfig != nil {
Expand Down Expand Up @@ -354,3 +356,26 @@ func healthConfigToGRPC(h *container.HealthConfig) *swarmapi.HealthConfig {
StartPeriod: gogotypes.DurationProto(h.StartPeriod),
}
}

// IsolationFromGRPC converts a swarm api container isolation to a moby isolation representation
func IsolationFromGRPC(i swarmapi.ContainerSpec_Isolation) container.Isolation {
switch i {
case swarmapi.ContainerIsolationHyperV:
return container.IsolationHyperV
case swarmapi.ContainerIsolationProcess:
return container.IsolationProcess
case swarmapi.ContainerIsolationDefault:
return container.IsolationDefault
}
return container.IsolationEmpty
}

func isolationToGRPC(i container.Isolation) swarmapi.ContainerSpec_Isolation {
if i.IsHyperV() {
return swarmapi.ContainerIsolationHyperV
}
if i.IsProcess() {
return swarmapi.ContainerIsolationProcess
}
return swarmapi.ContainerIsolationDefault
}
84 changes: 84 additions & 0 deletions daemon/cluster/convert/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package convert
import (
"testing"

containertypes "github.com/docker/docker/api/types/container"
swarmtypes "github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/swarm/runtime"
swarmapi "github.com/docker/swarmkit/api"
google_protobuf3 "github.com/gogo/protobuf/types"
"github.com/stretchr/testify/require"
)

func TestServiceConvertFromGRPCRuntimeContainer(t *testing.T) {
Expand Down Expand Up @@ -148,3 +150,85 @@ func TestServiceConvertToGRPCGenericRuntimeCustom(t *testing.T) {
t.Fatal(err)
}
}

func TestServiceConvertToGRPCIsolation(t *testing.T) {
cases := []struct {
name string
from containertypes.Isolation
to swarmapi.ContainerSpec_Isolation
}{
{name: "empty", from: containertypes.IsolationEmpty, to: swarmapi.ContainerIsolationDefault},
{name: "default", from: containertypes.IsolationDefault, to: swarmapi.ContainerIsolationDefault},
{name: "process", from: containertypes.IsolationProcess, to: swarmapi.ContainerIsolationProcess},
{name: "hyperv", from: containertypes.IsolationHyperV, to: swarmapi.ContainerIsolationHyperV},
{name: "proCess", from: containertypes.Isolation("proCess"), to: swarmapi.ContainerIsolationProcess},
{name: "hypErv", from: containertypes.Isolation("hypErv"), to: swarmapi.ContainerIsolationHyperV},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
s := swarmtypes.ServiceSpec{
TaskTemplate: swarmtypes.TaskSpec{
ContainerSpec: &swarmtypes.ContainerSpec{
Image: "alpine:latest",
Isolation: c.from,
},
},
Mode: swarmtypes.ServiceMode{
Global: &swarmtypes.GlobalService{},
},
}
res, err := ServiceSpecToGRPC(s)
require.NoError(t, err)
v, ok := res.Task.Runtime.(*swarmapi.TaskSpec_Container)
if !ok {
t.Fatal("expected type swarmapi.TaskSpec_Container")
}
require.Equal(t, c.to, v.Container.Isolation)
})
}
}

func TestServiceConvertFromGRPCIsolation(t *testing.T) {
cases := []struct {
name string
from swarmapi.ContainerSpec_Isolation
to containertypes.Isolation
}{
{name: "default", to: containertypes.IsolationDefault, from: swarmapi.ContainerIsolationDefault},
{name: "process", to: containertypes.IsolationProcess, from: swarmapi.ContainerIsolationProcess},
{name: "hyperv", to: containertypes.IsolationHyperV, from: swarmapi.ContainerIsolationHyperV},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
gs := swarmapi.Service{
Meta: swarmapi.Meta{
Version: swarmapi.Version{
Index: 1,
},
CreatedAt: nil,
UpdatedAt: nil,
},
SpecVersion: &swarmapi.Version{
Index: 1,
},
Spec: swarmapi.ServiceSpec{
Task: swarmapi.TaskSpec{
Runtime: &swarmapi.TaskSpec_Container{
Container: &swarmapi.ContainerSpec{
Image: "alpine:latest",
Isolation: c.from,
},
},
},
},
}

svc, err := ServiceFromGRPC(gs)
if err != nil {
t.Fatal(err)
}

require.Equal(t, c.to, svc.Spec.TaskTemplate.ContainerSpec.Isolation)
})
}
}
5 changes: 5 additions & 0 deletions daemon/cluster/executor/container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ func (c *containerConfig) portBindings() nat.PortMap {
return portBindings
}

func (c *containerConfig) isolation() enginecontainer.Isolation {
return convert.IsolationFromGRPC(c.spec().Isolation)
}

func (c *containerConfig) exposedPorts() map[nat.Port]struct{} {
exposedPorts := make(map[nat.Port]struct{})
if c.task.Endpoint == nil {
Expand Down Expand Up @@ -350,6 +354,7 @@ func (c *containerConfig) hostConfig() *enginecontainer.HostConfig {
PortBindings: c.portBindings(),
Mounts: c.mounts(),
ReadonlyRootfs: c.spec().ReadOnly,
Isolation: c.isolation(),
}

if c.spec().DNSConfig != nil {
Expand Down
37 changes: 37 additions & 0 deletions daemon/cluster/executor/container/container_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package container

import (
"testing"

container "github.com/docker/docker/api/types/container"
swarmapi "github.com/docker/swarmkit/api"
"github.com/stretchr/testify/require"
)

func TestIsolationConversion(t *testing.T) {
cases := []struct {
name string
from swarmapi.ContainerSpec_Isolation
to container.Isolation
}{
{name: "default", from: swarmapi.ContainerIsolationDefault, to: container.IsolationDefault},
{name: "process", from: swarmapi.ContainerIsolationProcess, to: container.IsolationProcess},
{name: "hyperv", from: swarmapi.ContainerIsolationHyperV, to: container.IsolationHyperV},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
task := swarmapi.Task{
Spec: swarmapi.TaskSpec{
Runtime: &swarmapi.TaskSpec_Container{
Container: &swarmapi.ContainerSpec{
Image: "alpine:latest",
Isolation: c.from,
},
},
},
}
config := containerConfig{task: &task}
require.Equal(t, c.to, config.hostConfig().Isolation)
})
}
}
1 change: 1 addition & 0 deletions docs/api/version-history.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ keywords: "API, Docker, rcli, REST, documentation"
If `Error` is `null`, container removal has succeeded, otherwise
the test of an error message indicating why container removal has failed
is available from `Error.Message` field.
* `POST /services/create` and `POST /services/(id)/update` now accept an `Isolation` field on container spec

## v1.33 API changes

Expand Down
17 changes: 17 additions & 0 deletions integration-cli/daemon/daemon_swarm.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,23 @@ func (d *Swarm) CheckServiceTasksInState(service string, state swarm.TaskState,
}
}

// CheckServiceTasksInStateWithError returns the number of tasks with a matching state,
// and optional message substring.
func (d *Swarm) CheckServiceTasksInStateWithError(service string, state swarm.TaskState, errorMessage string) func(*check.C) (interface{}, check.CommentInterface) {
return func(c *check.C) (interface{}, check.CommentInterface) {
tasks := d.GetServiceTasks(c, service)
var count int
for _, task := range tasks {
if task.Status.State == state {
if errorMessage == "" || strings.Contains(task.Status.Err, errorMessage) {
count++
}
}
}
return count, nil
}
}

// CheckServiceRunningTasks returns the number of running tasks for the specified service
func (d *Swarm) CheckServiceRunningTasks(service string) func(*check.C) (interface{}, check.CommentInterface) {
return d.CheckServiceTasksInState(service, swarm.TaskStateRunning, "")
Expand Down
2 changes: 1 addition & 1 deletion integration-cli/docker_cli_swarm_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func (s *DockerSwarmSuite) TestSwarmVolumePlugin(c *check.C) {
c.Assert(err, checker.IsNil, check.Commentf(out))

// Make sure task stays pending before plugin is available
waitAndAssert(c, defaultReconciliationTimeout, d.CheckServiceTasksInState("top", swarm.TaskStatePending, "missing plugin on 1 node"), checker.Equals, 1)
waitAndAssert(c, defaultReconciliationTimeout, d.CheckServiceTasksInStateWithError("top", swarm.TaskStatePending, "missing plugin on 1 node"), checker.Equals, 1)

plugin := newVolumePlugin(c, "customvolumedriver")
defer plugin.Close()
Expand Down
2 changes: 2 additions & 0 deletions integration/service/inspect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"time"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
Expand Down Expand Up @@ -76,6 +77,7 @@ func fullSwarmServiceSpec(name string, replicas uint64) swarm.ServiceSpec {
Nameservers: []string{"8.8.8.8"},
Search: []string{"somedomain"},
},
Isolation: container.IsolationDefault,
},
RestartPolicy: &swarm.RestartPolicy{
Delay: &restartDelay,
Expand Down
3 changes: 1 addition & 2 deletions vendor.conf
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ github.com/googleapis/gax-go da06d194a00e19ce00d9011a13931c3f6f6887c7
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944

# containerd
github.com/stevvooe/continuity cd7a8e21e2b6f84799f5dd4b65faf49c8d3ee02d
github.com/containerd/containerd 992280e8e265f491f7a624ab82f3e238be086e49
github.com/containerd/fifo fbfb6a11ec671efbe94ad1c12c2e98773f19e1e6
github.com/containerd/continuity 35d55c5e8dd23b32037d56cf97174aff3efdfa83
Expand All @@ -114,7 +113,7 @@ github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788
github.com/dmcgowan/go-tar 2e2c51242e8993c50445dab7c03c8e7febddd0cf

# cluster
github.com/docker/swarmkit 872861d2ae46958af7ead1d5fffb092c73afbaf0
github.com/docker/swarmkit 28f91d87bd3f75fd039dbb9be49bfd2381019261
github.com/gogo/protobuf v0.4
github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a
github.com/google/certificate-transparency d90e65c3a07988180c5b1ece71791c0b6506826e
Expand Down
2 changes: 2 additions & 0 deletions vendor/github.com/docker/swarmkit/agent/exec/controller.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading