diff --git a/executors/docker/executor_docker.go b/executors/docker/executor_docker.go index 71d97e870e321e031328d4a5d4044753fd7cc25c..ba81c3e30871cda218d0429aed6e6fec4ac72995 100644 --- a/executors/docker/executor_docker.go +++ b/executors/docker/executor_docker.go @@ -553,7 +553,7 @@ func (s *executor) splitServiceAndVersion(serviceDescription string) (service, v return } -func (s *executor) createService(service, version, image string, serviceDefinition common.Image) (*types.Container, error) { +func (s *executor) createService(serviceIndex int, service, version, image string, serviceDefinition common.Image) (*types.Container, error) { if len(service) == 0 { return nil, errors.New("invalid service name") } @@ -566,7 +566,8 @@ func (s *executor) createService(service, version, image string, serviceDefiniti s.printUsedDockerImageID(image, serviceImage.ID, "service", service) - containerName := s.Build.ProjectUniqueName() + "-" + strings.Replace(service, "/", "__", -1) + serviceSlug := strings.Replace(service, "/", "__", -1) + containerName := fmt.Sprintf("%s-%s-%d", s.Build.ProjectUniqueName(), serviceSlug, serviceIndex) // this will fail potentially some builds if there's name collision s.removeContainer(s.Context, containerName) @@ -668,7 +669,7 @@ func (s *executor) buildServiceLinks(linksMap map[string]*types.Container) (link return } -func (s *executor) createFromServiceDefinition(serviceDefinition common.Image, linksMap map[string]*types.Container) (err error) { +func (s *executor) createFromServiceDefinition(serviceIndex int, serviceDefinition common.Image, linksMap map[string]*types.Container) (err error) { var container *types.Container service, version, imageName, linkNames := s.splitServiceAndVersion(serviceDefinition.Name) @@ -685,7 +686,7 @@ func (s *executor) createFromServiceDefinition(serviceDefinition common.Image, l // Create service if not yet created if container == nil { - container, err = s.createService(service, version, imageName, serviceDefinition) + container, err = s.createService(serviceIndex, service, version, imageName, serviceDefinition) if err != nil { return } @@ -705,8 +706,8 @@ func (s *executor) createServices() (err error) { linksMap := make(map[string]*types.Container) - for _, serviceDefinition := range servicesDefinitions { - err = s.createFromServiceDefinition(serviceDefinition, linksMap) + for index, serviceDefinition := range servicesDefinitions { + err = s.createFromServiceDefinition(index, serviceDefinition, linksMap) if err != nil { return } diff --git a/executors/docker/executor_docker_command_test.go b/executors/docker/executor_docker_command_test.go index 6071cfe252396e7433690aef625339deb59665a0..024a506ac6312d3aa27882dec00194d4436fef70 100644 --- a/executors/docker/executor_docker_command_test.go +++ b/executors/docker/executor_docker_command_test.go @@ -222,6 +222,41 @@ func TestDockerCommandBuildCancel(t *testing.T) { assert.EqualError(t, err, "canceled") } +func TestDockerCommandTwoServicesFromOneImage(t *testing.T) { + if helpers.SkipIntegrationTests(t, "docker", "info") { + return + } + + successfulBuild, err := common.GetRemoteSuccessfulBuild() + successfulBuild.Services = common.Services{ + {Name: "alpine", Alias: "service-1"}, + {Name: "alpine", Alias: "service-2"}, + } + assert.NoError(t, err) + build := &common.Build{ + JobResponse: successfulBuild, + Runner: &common.RunnerConfig{ + RunnerSettings: common.RunnerSettings{ + Executor: "docker", + Docker: &common.DockerConfig{ + Image: "alpine", + }, + }, + }, + } + + var buf []byte + buffer := bytes.NewBuffer(buf) + + err = build.Run(&common.Config{}, &common.Trace{Writer: buffer}) + assert.NoError(t, err) + str := buffer.String() + + re, err := regexp.Compile("(?m)Conflict. The container name [^ ]+ is already in use by container") + require.NoError(t, err) + assert.NotRegexp(t, re, str, "Both service containers should be started and use different name") +} + func TestDockerCommandOutput(t *testing.T) { if helpers.SkipIntegrationTests(t, "docker", "info") { return diff --git a/executors/docker/executor_docker_test.go b/executors/docker/executor_docker_test.go index 90d540008e7fe9c272b3af94ca2304b9914b8e81..a13416a18b667f4ab727782889bb8940493846c0 100644 --- a/executors/docker/executor_docker_test.go +++ b/executors/docker/executor_docker_test.go @@ -128,7 +128,7 @@ func testServiceFromNamedImage(t *testing.T, description, imageName, serviceName var c docker_helpers.MockClient defer c.AssertExpectations(t) - containerName := fmt.Sprintf("runner-abcdef12-project-0-concurrent-0-%s", strings.Replace(serviceName, "/", "__", -1)) + containerName := fmt.Sprintf("runner-abcdef12-project-0-concurrent-0-%s-0", strings.Replace(serviceName, "/", "__", -1)) networkID := "network-id" e := executor{client: &c} @@ -176,7 +176,7 @@ func testServiceFromNamedImage(t *testing.T, description, imageName, serviceName Once() linksMap := make(map[string]*types.Container) - err := e.createFromServiceDefinition(common.Image{Name: description}, linksMap) + err := e.createFromServiceDefinition(0, common.Image{Name: description}, linksMap) assert.NoError(t, err) } @@ -882,7 +882,7 @@ func testDockerConfigurationWithServiceContainer(t *testing.T, dockerConfig *com c.On("ContainerStart", mock.Anything, "abc", mock.Anything). Return(nil).Once() - _, err := e.createService("build", "latest", "alpine", common.Image{Command: []string{"/bin/sh"}}) + _, err := e.createService(0, "build", "latest", "alpine", common.Image{Command: []string{"/bin/sh"}}) assert.NoError(t, err, "Should create service container without errors") }