@@ -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
116110var 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-
170112func (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+
266222func (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+
286273func mustRecreate (expected types.ServiceConfig , actual moby.Container , policy string ) (bool , error ) {
287274 if policy == api .RecreateNever {
288275 return false , nil
0 commit comments