@@ -102,71 +102,13 @@ func (c *convergence) apply(ctx context.Context, project *types.Project, options
102
102
if utils .StringContains (options .Services , name ) {
103
103
strategy = options .Recreate
104
104
}
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 )
112
106
})(ctx )
113
107
})
114
108
}
115
109
116
110
var mu sync.Mutex
117
111
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
-
170
112
func (c * convergence ) ensureService (ctx context.Context , project * types.Project , service types.ServiceConfig , recreate string , inherit bool , timeout * time.Duration ) error {
171
113
expected , err := getScale (service )
172
114
if err != nil {
@@ -178,7 +120,7 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
178
120
179
121
eg , _ := errgroup .WithContext (ctx )
180
122
181
- err = c .resolveVolumeFrom (& service )
123
+ err = c .resolveServiceReferences (& service )
182
124
if err != nil {
183
125
return err
184
126
}
@@ -263,6 +205,20 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
263
205
return err
264
206
}
265
207
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
+
266
222
func (c * convergence ) resolveVolumeFrom (service * types.ServiceConfig ) error {
267
223
for i , vol := range service .VolumesFrom {
268
224
spec := strings .Split (vol , ":" )
@@ -283,6 +239,37 @@ func (c *convergence) resolveVolumeFrom(service *types.ServiceConfig) error {
283
239
return nil
284
240
}
285
241
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
+
286
273
func mustRecreate (expected types.ServiceConfig , actual moby.Container , policy string ) (bool , error ) {
287
274
if policy == api .RecreateNever {
288
275
return false , nil
0 commit comments