Merge pull request #1463 from aiordache/ipc_support

Add IPC support
This commit is contained in:
Guillaume Tardif 2021-03-25 16:13:56 +01:00 committed by GitHub
commit d13bc958bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 120 additions and 33 deletions

View File

@ -100,7 +100,7 @@ func (s *composeService) Create(ctx context.Context, project *types.Project, opt
}
}
prepareNetworkMode(project)
prepareServicesDependsOn(project)
return InDependencyOrder(ctx, project, func(c context.Context, service types.ServiceConfig) error {
if utils.StringContains(opts.Services, service.Name) {
@ -142,18 +142,20 @@ func prepareNetworks(project *types.Project) {
}
}
func prepareNetworkMode(p *types.Project) {
func prepareServicesDependsOn(p *types.Project) {
outLoop:
for i := range p.Services {
dependency := getDependentServiceByNetwork(p.Services[i].NetworkMode)
if dependency == "" {
networkDependency := getDependentServiceFromMode(p.Services[i].NetworkMode)
ipcDependency := getDependentServiceFromMode(p.Services[i].Ipc)
if networkDependency == "" && ipcDependency == "" {
continue
}
if p.Services[i].DependsOn == nil {
p.Services[i].DependsOn = make(types.DependsOnConfig)
}
for _, service := range p.Services {
if service.Name == dependency {
if service.Name == networkDependency || service.Name == ipcDependency {
p.Services[i].DependsOn[service.Name] = types.ServiceDependency{
Condition: types.ServiceConditionStarted,
}
@ -269,7 +271,14 @@ func (s *composeService) getCreateOptions(ctx context.Context, p *types.Project,
resources := getDeployResources(service)
networkMode, err := getNetworkMode(ctx, p, service)
networkMode, err := getMode(ctx, service.Name, service.NetworkMode)
if err != nil {
return nil, nil, nil, err
}
if networkMode == "" {
networkMode = getDefaultNetworkMode(p, service)
}
ipcmode, err := getMode(ctx, service.Name, service.Ipc)
if err != nil {
return nil, nil, nil, err
}
@ -305,8 +314,9 @@ func (s *composeService) getCreateOptions(ctx context.Context, p *types.Project,
Mounts: mounts,
CapAdd: strslice.StrSlice(service.CapAdd),
CapDrop: strslice.StrSlice(service.CapDrop),
NetworkMode: networkMode,
NetworkMode: container.NetworkMode(networkMode),
Init: service.Init,
IpcMode: container.IpcMode(ipcmode),
ReadonlyRootfs: service.ReadOnly,
RestartPolicy: getRestartPolicy(service),
ShmSize: shmSize,
@ -328,10 +338,21 @@ func (s *composeService) getCreateOptions(ctx context.Context, p *types.Project,
LogConfig: logConfig,
}
networkConfig := buildDefaultNetworkConfig(service, networkMode, getContainerName(p.Name, service, number))
networkConfig := buildDefaultNetworkConfig(service, container.NetworkMode(networkMode), getContainerName(p.Name, service, number))
return &containerConfig, &hostConfig, networkConfig, nil
}
func getDefaultNetworkMode(project *types.Project, service types.ServiceConfig) string {
mode := "none"
if len(project.Networks) > 0 {
for name := range getNetworksForService(service) {
mode = project.Networks[name].Name
break
}
}
return mode
}
func getRestartPolicy(service types.ServiceConfig) container.RestartPolicy {
var restart container.RestartPolicy
if service.Restart != "" {
@ -470,12 +491,11 @@ func getVolumesFrom(project *types.Project, volumesFrom []string) ([]string, []s
}
func getDependentServiceByNetwork(networkMode string) string {
baseService := ""
if strings.HasPrefix(networkMode, types.NetworkModeServicePrefix) {
return networkMode[len(types.NetworkModeServicePrefix):]
func getDependentServiceFromMode(mode string) string {
if strings.HasPrefix(mode, types.NetworkModeServicePrefix) {
return mode[len(types.NetworkModeServicePrefix):]
}
return baseService
return ""
}
func (s *composeService) buildContainerVolumes(ctx context.Context, p types.Project, service types.ServiceConfig,
@ -745,33 +765,22 @@ func getAliases(s types.ServiceConfig, c *types.ServiceNetworkConfig) []string {
return aliases
}
func getNetworkMode(ctx context.Context, p *types.Project, service types.ServiceConfig) (container.NetworkMode, error) {
func getMode(ctx context.Context, serviceName string, mode string) (string, error) {
cState, err := GetContextContainerState(ctx)
if err != nil {
return container.NetworkMode("none"), nil
return "", nil
}
observedState := cState.GetContainers()
mode := service.NetworkMode
if mode == "" {
if len(p.Networks) > 0 {
for name := range getNetworksForService(service) {
return container.NetworkMode(p.Networks[name].Name), nil
}
}
return container.NetworkMode("none"), nil
}
depServiceNetworkMode := getDependentServiceByNetwork(service.NetworkMode)
if depServiceNetworkMode != "" {
depServiceContainers := observedState.filter(isService(depServiceNetworkMode))
depService := getDependentServiceFromMode(mode)
if depService != "" {
depServiceContainers := observedState.filter(isService(depService))
if len(depServiceContainers) > 0 {
return container.NetworkMode(types.NetworkModeContainerPrefix + depServiceContainers[0].ID), nil
return types.NetworkModeContainerPrefix + depServiceContainers[0].ID, nil
}
return container.NetworkMode("none"),
fmt.Errorf(`no containers started for network_mode %q in service %q -> %v`,
mode, service.Name, observedState)
return "", fmt.Errorf(`no containers started for %q in service %q -> %v`,
mode, serviceName, observedState)
}
return container.NetworkMode(mode), nil
return mode, nil
}
func getNetworksForService(s types.ServiceConfig) map[string]*types.ServiceNetworkConfig {

View File

@ -0,0 +1,13 @@
services:
service:
image: busybox
command: top
ipc: "service:shareable"
container:
image: busybox
command: top
ipc: "container:ipc_mode_container"
shareable:
image: busybox
command: top
ipc: shareable

View File

@ -0,0 +1,65 @@
/*
Copyright 2020 Docker Compose CLI authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package e2e
import (
"fmt"
"strings"
"testing"
"gotest.tools/v3/icmd"
. "github.com/docker/compose-cli/utils/e2e"
)
func TestIPC(t *testing.T) {
c := NewParallelE2eCLI(t, binDir)
const projectName = "ipc_e2e"
var cid string
t.Run("create ipc mode container", func(t *testing.T) {
res := c.RunDockerCmd("run", "-d", "--rm", "--ipc=shareable", "--name", "ipc_mode_container", "busybox", "top")
cid = strings.Trim(res.Stdout(), "\n")
})
t.Run("up", func(t *testing.T) {
c.RunDockerCmd("compose", "-f", "./fixtures/ipc-test/compose.yaml", "--project-name", projectName, "up", "-d")
})
t.Run("check running project", func(t *testing.T) {
res := c.RunDockerCmd("compose", "-p", projectName, "ps")
res.Assert(t, icmd.Expected{Out: `shareable`})
})
t.Run("check ipcmode in container inspect", func(t *testing.T) {
res := c.RunDockerCmd("inspect", projectName+"_shareable_1")
res.Assert(t, icmd.Expected{Out: `"IpcMode": "shareable",`})
res = c.RunDockerCmd("inspect", projectName+"_service_1")
res.Assert(t, icmd.Expected{Out: `"IpcMode": "container:`})
res = c.RunDockerCmd("inspect", projectName+"_container_1")
res.Assert(t, icmd.Expected{Out: fmt.Sprintf(`"IpcMode": "container:%s",`, cid)})
})
t.Run("down", func(t *testing.T) {
_ = c.RunDockerCmd("compose", "--project-name", projectName, "down")
})
t.Run("stop ipc mode container", func(t *testing.T) {
_ = c.RunDockerCmd("stop", "ipc_mode_container")
})
}