Skip to content

Commit 8af49ff

Browse files
committed
resolve service reference into container based on observed state
Signed-off-by: Nicolas De Loof <[email protected]>
1 parent f6e31db commit 8af49ff

File tree

4 files changed

+76
-61
lines changed

4 files changed

+76
-61
lines changed

pkg/compose/convergence.go

Lines changed: 47 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -102,71 +102,13 @@ func (c *convergence) apply(ctx context.Context, project *types.Project, options
102102
if utils.StringContains(options.Services, name) {
103103
strategy = options.Recreate
104104
}
105-
err = c.ensureService(ctx, project, service, strategy, options.Inherit, options.Timeout)
106-
if err != nil {
107-
return err
108-
}
109-
110-
c.updateProject(project, name)
111-
return nil
105+
return c.ensureService(ctx, project, service, strategy, options.Inherit, options.Timeout)
112106
})(ctx)
113107
})
114108
}
115109

116110
var mu sync.Mutex
117111

118-
// updateProject updates project after service converged, so dependent services relying on `service:xx` can refer to actual containers.
119-
func (c *convergence) updateProject(project *types.Project, serviceName string) {
120-
// operation is protected by a Mutex so that we can safely update project.Services while running concurrent convergence on services
121-
mu.Lock()
122-
defer mu.Unlock()
123-
124-
cnts := c.getObservedState(serviceName)
125-
for i, s := range project.Services {
126-
updateServices(&s, cnts)
127-
project.Services[i] = s
128-
}
129-
}
130-
131-
func updateServices(service *types.ServiceConfig, cnts Containers) {
132-
if len(cnts) == 0 {
133-
return
134-
}
135-
136-
for _, str := range []*string{&service.NetworkMode, &service.Ipc, &service.Pid} {
137-
if d := getDependentServiceFromMode(*str); d != "" {
138-
if serviceContainers := cnts.filter(isService(d)); len(serviceContainers) > 0 {
139-
*str = types.NetworkModeContainerPrefix + serviceContainers[0].ID
140-
}
141-
}
142-
}
143-
var links []string
144-
for _, serviceLink := range service.Links {
145-
parts := strings.Split(serviceLink, ":")
146-
serviceName := serviceLink
147-
serviceAlias := ""
148-
if len(parts) == 2 {
149-
serviceName = parts[0]
150-
serviceAlias = parts[1]
151-
}
152-
if serviceName != service.Name {
153-
links = append(links, serviceLink)
154-
continue
155-
}
156-
for _, container := range cnts {
157-
name := getCanonicalContainerName(container)
158-
if serviceAlias != "" {
159-
links = append(links,
160-
fmt.Sprintf("%s:%s", name, serviceAlias))
161-
}
162-
links = append(links,
163-
fmt.Sprintf("%s:%s", name, name),
164-
fmt.Sprintf("%s:%s", name, getContainerNameWithoutProject(container)))
165-
}
166-
service.Links = links
167-
}
168-
}
169-
170112
func (c *convergence) ensureService(ctx context.Context, project *types.Project, service types.ServiceConfig, recreate string, inherit bool, timeout *time.Duration) error {
171113
expected, err := getScale(service)
172114
if err != nil {
@@ -178,7 +120,7 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
178120

179121
eg, _ := errgroup.WithContext(ctx)
180122

181-
err = c.resolveVolumeFrom(&service)
123+
err = c.resolveServiceReferences(&service)
182124
if err != nil {
183125
return err
184126
}
@@ -263,6 +205,20 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
263205
return err
264206
}
265207

208+
// resolveServiceReferences replaces reference to another service with reference to an actual container
209+
func (c *convergence) resolveServiceReferences(service *types.ServiceConfig) error {
210+
err := c.resolveVolumeFrom(service)
211+
if err != nil {
212+
return err
213+
}
214+
215+
err = c.resolveSharedNamespaces(service)
216+
if err != nil {
217+
return err
218+
}
219+
return nil
220+
}
221+
266222
func (c *convergence) resolveVolumeFrom(service *types.ServiceConfig) error {
267223
for i, vol := range service.VolumesFrom {
268224
spec := strings.Split(vol, ":")
@@ -283,6 +239,37 @@ func (c *convergence) resolveVolumeFrom(service *types.ServiceConfig) error {
283239
return nil
284240
}
285241

242+
func (c *convergence) resolveSharedNamespaces(service *types.ServiceConfig) error {
243+
str := service.NetworkMode
244+
if name := getDependentServiceFromMode(str); name != "" {
245+
dependencies := c.getObservedState(name)
246+
if len(dependencies) == 0 {
247+
return fmt.Errorf("cannot share network namespace with service %s: container missing", name)
248+
}
249+
service.NetworkMode = types.ContainerPrefix + dependencies.sorted()[0].ID
250+
}
251+
252+
str = service.Ipc
253+
if name := getDependentServiceFromMode(str); name != "" {
254+
dependencies := c.getObservedState(name)
255+
if len(dependencies) == 0 {
256+
return fmt.Errorf("cannot share IPC namespace with service %s: container missing", name)
257+
}
258+
service.Ipc = types.ContainerPrefix + dependencies.sorted()[0].ID
259+
}
260+
261+
str = service.Pid
262+
if name := getDependentServiceFromMode(str); name != "" {
263+
dependencies := c.getObservedState(name)
264+
if len(dependencies) == 0 {
265+
return fmt.Errorf("cannot share PID namespace with service %s: container missing", name)
266+
}
267+
service.Pid = types.ContainerPrefix + dependencies.sorted()[0].ID
268+
}
269+
270+
return nil
271+
}
272+
286273
func mustRecreate(expected types.ServiceConfig, actual moby.Container, policy string) (bool, error) {
287274
if policy == api.RecreateNever {
288275
return false, nil

pkg/compose/run.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ func (s *composeService) prepareRun(ctx context.Context, project *types.Project,
9090
if err != nil {
9191
return "", err
9292
}
93-
updateServices(&service, observedState)
9493

9594
if !opts.NoDeps {
9695
if err := s.waitDependencies(ctx, project, service.DependsOn, observedState); err != nil {
@@ -104,6 +103,11 @@ func (s *composeService) prepareRun(ctx context.Context, project *types.Project,
104103
Labels: mergeLabels(service.Labels, service.CustomLabels),
105104
}
106105

106+
err = newConvergence(project.ServiceNames(), observedState, s).resolveServiceReferences(&service)
107+
if err != nil {
108+
return "", err
109+
}
110+
107111
created, err := s.createContainer(ctx, project, service, service.ContainerName, 1, createOpts)
108112
if err != nil {
109113
return "", err
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
services:
2+
app:
3+
image: nginx:alpine
4+
network_mode: service:db
5+
6+
db:
7+
image: nginx:alpine

pkg/e2e/noDeps_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,20 @@ func TestNoDepsVolumeFrom(t *testing.T) {
4242
res := c.RunDockerComposeCmdNoCheck(t, "-f", "fixtures/no-deps/volume-from.yaml", "--project-name", projectName, "up", "--no-deps", "-d", "app")
4343
res.Assert(t, icmd.Expected{ExitCode: 1, Err: "cannot share volume with service db: container missing"})
4444
}
45+
46+
func TestNoDepsNetworkMode(t *testing.T) {
47+
c := NewParallelCLI(t)
48+
const projectName = "e2e-no-deps-network-mode"
49+
t.Cleanup(func() {
50+
c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
51+
})
52+
53+
c.RunDockerComposeCmd(t, "-f", "fixtures/no-deps/network-mode.yaml", "--project-name", projectName, "up", "-d")
54+
55+
c.RunDockerComposeCmd(t, "-f", "fixtures/no-deps/network-mode.yaml", "--project-name", projectName, "up", "--no-deps", "-d", "app")
56+
57+
c.RunDockerCmd(t, "rm", "-f", fmt.Sprintf("%s-db-1", projectName))
58+
59+
res := c.RunDockerComposeCmdNoCheck(t, "-f", "fixtures/no-deps/network-mode.yaml", "--project-name", projectName, "up", "--no-deps", "-d", "app")
60+
res.Assert(t, icmd.Expected{ExitCode: 1, Err: "cannot share network namespace with service db: container missing"})
61+
}

0 commit comments

Comments
 (0)