Fix network_mode "service:x"

Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
This commit is contained in:
Ulysses Souza 2021-10-13 12:20:24 +02:00
parent ef786f9245
commit c2dd40c161
3 changed files with 69 additions and 41 deletions

View File

@ -109,56 +109,61 @@ func (c *convergence) apply(ctx context.Context, project *types.Project, options
var mu sync.Mutex
// updateProject updates project after service converged, so dependent services relying on `service:xx` can refer to actual containers.
func (c *convergence) updateProject(project *types.Project, service string) {
containers := c.getObservedState(service)
if len(containers) == 0 {
return
}
container := containers[0]
func (c *convergence) updateProject(project *types.Project, serviceName string) {
// operation is protected by a Mutex so that we can safely update project.Services while running concurrent convergence on services
mu.Lock()
defer mu.Unlock()
cnts := c.getObservedState(serviceName)
for i, s := range project.Services {
if d := getDependentServiceFromMode(s.NetworkMode); d == service {
s.NetworkMode = types.NetworkModeContainerPrefix + container.ID
}
if d := getDependentServiceFromMode(s.Ipc); d == service {
s.Ipc = types.NetworkModeContainerPrefix + container.ID
}
if d := getDependentServiceFromMode(s.Pid); d == service {
s.Pid = types.NetworkModeContainerPrefix + container.ID
}
var links []string
for _, serviceLink := range s.Links {
parts := strings.Split(serviceLink, ":")
serviceName := serviceLink
serviceAlias := ""
if len(parts) == 2 {
serviceName = parts[0]
serviceAlias = parts[1]
}
if serviceName != service {
links = append(links, serviceLink)
continue
}
for _, container := range containers {
name := getCanonicalContainerName(container)
if serviceAlias != "" {
links = append(links,
fmt.Sprintf("%s:%s", name, serviceAlias))
}
links = append(links,
fmt.Sprintf("%s:%s", name, name),
fmt.Sprintf("%s:%s", name, getContainerNameWithoutProject(container)))
}
s.Links = links
}
updateServices(&s, cnts)
project.Services[i] = s
}
}
func updateServices(service *types.ServiceConfig, cnts Containers) {
if len(cnts) == 0 {
return
}
cnt := cnts[0]
serviceName := cnt.Labels[api.ServiceLabel]
if d := getDependentServiceFromMode(service.NetworkMode); d == serviceName {
service.NetworkMode = types.NetworkModeContainerPrefix + cnt.ID
}
if d := getDependentServiceFromMode(service.Ipc); d == serviceName {
service.Ipc = types.NetworkModeContainerPrefix + cnt.ID
}
if d := getDependentServiceFromMode(service.Pid); d == serviceName {
service.Pid = types.NetworkModeContainerPrefix + cnt.ID
}
var links []string
for _, serviceLink := range service.Links {
parts := strings.Split(serviceLink, ":")
serviceName := serviceLink
serviceAlias := ""
if len(parts) == 2 {
serviceName = parts[0]
serviceAlias = parts[1]
}
if serviceName != service.Name {
links = append(links, serviceLink)
continue
}
for _, container := range cnts {
name := getCanonicalContainerName(container)
if serviceAlias != "" {
links = append(links,
fmt.Sprintf("%s:%s", name, serviceAlias))
}
links = append(links,
fmt.Sprintf("%s:%s", name, name),
fmt.Sprintf("%s:%s", name, getContainerNameWithoutProject(container)))
}
service.Links = links
}
}
func (c *convergence) ensureService(ctx context.Context, project *types.Project, service types.ServiceConfig, recreate string, inherit bool, timeout *time.Duration) error {
expected, err := getScale(service)
if err != nil {

View File

@ -164,6 +164,13 @@ func (s *composeService) prepareRun(ctx context.Context, project *types.Project,
return "", err
}
}
observedState, err := s.getContainers(ctx, project.Name, oneOffInclude, true)
if err != nil {
return "", err
}
updateServices(&service, observedState)
created, err := s.createContainer(ctx, project, service, service.ContainerName, 1, opts.Detach && opts.AutoRemove, opts.UseNetworkAliases, true)
if err != nil {
return "", err

View File

@ -115,3 +115,19 @@ func TestIPAMConfig(t *testing.T) {
_ = c.RunDockerCmd("compose", "--project-name", projectName, "down")
})
}
func TestNetworkModes(t *testing.T) {
c := NewParallelE2eCLI(t, binDir)
const projectName = "network_mode_service_run"
t.Run("run with service mode dependency", func(t *testing.T) {
res := c.RunDockerOrExitError("compose", "-f", "./fixtures/network-test/compose.yaml", "--project-name", projectName, "run", "mydb", "echo", "success")
res.Assert(t, icmd.Expected{Out: "success"})
})
t.Run("down", func(t *testing.T) {
_ = c.RunDockerCmd("compose", "--project-name", projectName, "down")
})
}