mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Add support for init
on services
It's already supported by `swarmkit`, and act the same as `HostConfig.Init` on container creation. Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
parent
1fe0e49d20
commit
e401b88e59
8 changed files with 104 additions and 1 deletions
|
@ -2721,6 +2721,10 @@ definitions:
|
|||
- "default"
|
||||
- "process"
|
||||
- "hyperv"
|
||||
Init:
|
||||
description: "Run an init inside the container that forwards signals and reaps processes. This field is omitted if empty, and the default (as configured on the daemon) is used."
|
||||
type: "boolean"
|
||||
x-nullable: true
|
||||
NetworkAttachmentSpec:
|
||||
description: |
|
||||
Read-only spec type for non-swarm containers attached to swarm overlay
|
||||
|
|
|
@ -55,6 +55,7 @@ type ContainerSpec struct {
|
|||
User string `json:",omitempty"`
|
||||
Groups []string `json:",omitempty"`
|
||||
Privileges *Privileges `json:",omitempty"`
|
||||
Init *bool `json:",omitempty"`
|
||||
StopSignal string `json:",omitempty"`
|
||||
TTY bool `json:",omitempty"`
|
||||
OpenStdin bool `json:",omitempty"`
|
||||
|
|
|
@ -35,6 +35,7 @@ func containerSpecFromGRPC(c *swarmapi.ContainerSpec) *types.ContainerSpec {
|
|||
Secrets: secretReferencesFromGRPC(c.Secrets),
|
||||
Configs: configReferencesFromGRPC(c.Configs),
|
||||
Isolation: IsolationFromGRPC(c.Isolation),
|
||||
Init: initFromGRPC(c.Init),
|
||||
}
|
||||
|
||||
if c.DNSConfig != nil {
|
||||
|
@ -119,6 +120,21 @@ func containerSpecFromGRPC(c *swarmapi.ContainerSpec) *types.ContainerSpec {
|
|||
return containerSpec
|
||||
}
|
||||
|
||||
func initFromGRPC(v *gogotypes.BoolValue) *bool {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
value := v.GetValue()
|
||||
return &value
|
||||
}
|
||||
|
||||
func initToGRPC(v *bool) *gogotypes.BoolValue {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
return &gogotypes.BoolValue{Value: *v}
|
||||
}
|
||||
|
||||
func secretReferencesToGRPC(sr []*types.SecretReference) []*swarmapi.SecretReference {
|
||||
refs := make([]*swarmapi.SecretReference, 0, len(sr))
|
||||
for _, s := range sr {
|
||||
|
@ -234,6 +250,7 @@ func containerToGRPC(c *types.ContainerSpec) (*swarmapi.ContainerSpec, error) {
|
|||
Secrets: secretReferencesToGRPC(c.Secrets),
|
||||
Configs: configReferencesToGRPC(c.Configs),
|
||||
Isolation: isolationToGRPC(c.Isolation),
|
||||
Init: initToGRPC(c.Init),
|
||||
}
|
||||
|
||||
if c.DNSConfig != nil {
|
||||
|
|
|
@ -172,6 +172,14 @@ func (c *containerConfig) isolation() enginecontainer.Isolation {
|
|||
return convert.IsolationFromGRPC(c.spec().Isolation)
|
||||
}
|
||||
|
||||
func (c *containerConfig) init() *bool {
|
||||
if c.spec().Init == nil {
|
||||
return nil
|
||||
}
|
||||
init := c.spec().Init.GetValue()
|
||||
return &init
|
||||
}
|
||||
|
||||
func (c *containerConfig) exposedPorts() map[nat.Port]struct{} {
|
||||
exposedPorts := make(map[nat.Port]struct{})
|
||||
if c.task.Endpoint == nil {
|
||||
|
@ -355,6 +363,7 @@ func (c *containerConfig) hostConfig() *enginecontainer.HostConfig {
|
|||
Mounts: c.mounts(),
|
||||
ReadonlyRootfs: c.spec().ReadOnly,
|
||||
Isolation: c.isolation(),
|
||||
Init: c.init(),
|
||||
}
|
||||
|
||||
if c.spec().DNSConfig != nil {
|
||||
|
|
|
@ -86,6 +86,14 @@ func defaultServiceSpec() swarmtypes.ServiceSpec {
|
|||
return spec
|
||||
}
|
||||
|
||||
// ServiceWithInit sets whether the service should use init or not
|
||||
func ServiceWithInit(b *bool) func(*swarmtypes.ServiceSpec) {
|
||||
return func(spec *swarmtypes.ServiceSpec) {
|
||||
ensureContainerSpec(spec)
|
||||
spec.TaskTemplate.ContainerSpec.Init = b
|
||||
}
|
||||
}
|
||||
|
||||
// ServiceWithImage sets the image to use for the service
|
||||
func ServiceWithImage(image string) func(*swarmtypes.ServiceSpec) {
|
||||
return func(spec *swarmtypes.ServiceSpec) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package service // import "github.com/docker/docker/integration/service"
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -11,11 +12,64 @@ import (
|
|||
swarmtypes "github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration/internal/swarm"
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"github.com/gotestyourself/gotestyourself/assert"
|
||||
is "github.com/gotestyourself/gotestyourself/assert/cmp"
|
||||
"github.com/gotestyourself/gotestyourself/poll"
|
||||
)
|
||||
|
||||
func TestServiceCreateInit(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
t.Run("daemonInitDisabled", testServiceCreateInit(false))
|
||||
t.Run("daemonInitEnabled", testServiceCreateInit(true))
|
||||
}
|
||||
|
||||
func testServiceCreateInit(daemonEnabled bool) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
var ops = []func(*daemon.Daemon){}
|
||||
|
||||
if daemonEnabled {
|
||||
ops = append(ops, daemon.WithInit)
|
||||
}
|
||||
d := swarm.NewSwarm(t, testEnv, ops...)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
booleanTrue := true
|
||||
booleanFalse := false
|
||||
|
||||
serviceID := swarm.CreateService(t, d)
|
||||
poll.WaitOn(t, serviceRunningTasksCount(client, serviceID, 1), swarm.ServicePoll)
|
||||
i := inspectServiceContainer(t, client, serviceID)
|
||||
// HostConfig.Init == nil means that it delegates to daemon configuration
|
||||
assert.Check(t, i.HostConfig.Init == nil)
|
||||
|
||||
serviceID = swarm.CreateService(t, d, swarm.ServiceWithInit(&booleanTrue))
|
||||
poll.WaitOn(t, serviceRunningTasksCount(client, serviceID, 1), swarm.ServicePoll)
|
||||
i = inspectServiceContainer(t, client, serviceID)
|
||||
assert.Check(t, is.Equal(true, *i.HostConfig.Init))
|
||||
|
||||
serviceID = swarm.CreateService(t, d, swarm.ServiceWithInit(&booleanFalse))
|
||||
poll.WaitOn(t, serviceRunningTasksCount(client, serviceID, 1), swarm.ServicePoll)
|
||||
i = inspectServiceContainer(t, client, serviceID)
|
||||
assert.Check(t, is.Equal(false, *i.HostConfig.Init))
|
||||
}
|
||||
}
|
||||
|
||||
func inspectServiceContainer(t *testing.T, client client.APIClient, serviceID string) types.ContainerJSON {
|
||||
t.Helper()
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("label", fmt.Sprintf("com.docker.swarm.service.id=%s", serviceID))
|
||||
containers, err := client.ContainerList(context.Background(), types.ContainerListOptions{Filters: filter})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Len(containers, 1))
|
||||
|
||||
i, err := client.ContainerInspect(context.Background(), containers[0].ID)
|
||||
assert.NilError(t, err)
|
||||
return i
|
||||
}
|
||||
|
||||
func TestCreateServiceMultipleTimes(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
|
|
|
@ -66,6 +66,7 @@ type Daemon struct {
|
|||
userlandProxy bool
|
||||
execRoot string
|
||||
experimental bool
|
||||
init bool
|
||||
dockerdBinary string
|
||||
log logT
|
||||
|
||||
|
@ -229,7 +230,10 @@ func (d *Daemon) StartWithLogFile(out *os.File, providedArgs ...string) error {
|
|||
fmt.Sprintf("--userland-proxy=%t", d.userlandProxy),
|
||||
)
|
||||
if d.experimental {
|
||||
args = append(args, "--experimental", "--init")
|
||||
args = append(args, "--experimental")
|
||||
}
|
||||
if d.init {
|
||||
args = append(args, "--init")
|
||||
}
|
||||
if !(d.UseDefaultHost || d.UseDefaultTLSHost) {
|
||||
args = append(args, []string{"--host", d.Sock()}...)
|
||||
|
|
|
@ -5,6 +5,12 @@ import "github.com/docker/docker/internal/test/environment"
|
|||
// WithExperimental sets the daemon in experimental mode
|
||||
func WithExperimental(d *Daemon) {
|
||||
d.experimental = true
|
||||
d.init = true
|
||||
}
|
||||
|
||||
// WithInit sets the daemon init
|
||||
func WithInit(d *Daemon) {
|
||||
d.init = true
|
||||
}
|
||||
|
||||
// WithDockerdBinary sets the dockerd binary to the specified one
|
||||
|
|
Loading…
Reference in a new issue