Skip to content

Commit be29ed5

Browse files
ndeloofclaude
andcommitted
Cleanup: remove convergence struct, extract resolveServiceReferences
- Remove the `convergence` struct and `newConvergence` constructor - Extract `resolveServiceReferences` as a standalone function taking `map[string]Containers` instead of a method on convergence - Add `getContainersByService` helper on composeService - Update run.go and executor.go to use the new standalone function - Remove dead code: `getObservedState`, `setObservedState` Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
1 parent 33cba46 commit be29ed5

4 files changed

Lines changed: 55 additions & 62 deletions

File tree

pkg/compose/containers.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,20 @@ func (s *composeService) getContainers(ctx context.Context, project string, oneO
5757
return containers, nil
5858
}
5959

60+
// getContainersByService returns all non-oneoff containers for the project, grouped by service name.
61+
func (s *composeService) getContainersByService(ctx context.Context, projectName string) (map[string]Containers, error) {
62+
all, err := s.getContainers(ctx, projectName, oneOffExclude, true)
63+
if err != nil {
64+
return nil, err
65+
}
66+
result := map[string]Containers{}
67+
for _, c := range all.filter(isNotOneOff) {
68+
svc := c.Labels[api.ServiceLabel]
69+
result[svc] = append(result[svc], c)
70+
}
71+
return result, nil
72+
}
73+
6074
func getDefaultFilters(projectName string, oneOff oneOff, selectedServices ...string) client.Filters {
6175
f := projectFilter(projectName)
6276
if len(selectedServices) == 1 {

pkg/compose/convergence.go

Lines changed: 30 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -49,37 +49,6 @@ const (
4949
// re-creating container, adding or removing replicas, or starting stopped containers.
5050
// Cross services dependencies are managed by creating services in expected order and updating `service:xx` reference
5151
// when a service has converged, so dependent ones can be managed with resolved containers references.
52-
type convergence struct {
53-
compose *composeService
54-
services map[string]Containers
55-
networks map[string]string
56-
volumes map[string]string
57-
stateMutex sync.Mutex
58-
}
59-
60-
func (c *convergence) getObservedState(serviceName string) Containers {
61-
c.stateMutex.Lock()
62-
defer c.stateMutex.Unlock()
63-
return c.services[serviceName]
64-
}
65-
66-
func newConvergence(services []string, state Containers, networks map[string]string, volumes map[string]string, s *composeService) *convergence {
67-
observedState := map[string]Containers{}
68-
for _, s := range services {
69-
observedState[s] = Containers{}
70-
}
71-
for _, c := range state.filter(isNotOneOff) {
72-
service := c.Labels[api.ServiceLabel]
73-
observedState[service] = append(observedState[service], c)
74-
}
75-
return &convergence{
76-
compose: s,
77-
services: observedState,
78-
networks: networks,
79-
volumes: volumes,
80-
}
81-
}
82-
8352
func getScale(config types.ServiceConfig) (int, error) {
8453
scale := config.GetScale()
8554
if scale > 1 && config.ContainerName != "" {
@@ -90,21 +59,18 @@ func getScale(config types.ServiceConfig) (int, error) {
9059
return scale, nil
9160
}
9261

93-
// resolveServiceReferences replaces reference to another service with reference to an actual container
94-
func (c *convergence) resolveServiceReferences(service *types.ServiceConfig) error {
95-
err := c.resolveVolumeFrom(service)
96-
if err != nil {
97-
return err
98-
}
99-
100-
err = c.resolveSharedNamespaces(service)
101-
if err != nil {
62+
// resolveServiceReferences replaces references to other services with references
63+
// to actual container IDs. It resolves VolumesFrom, NetworkMode, IPC and PID
64+
// shared namespaces. The containersByService map provides the observed containers
65+
// grouped by service name.
66+
func resolveServiceReferences(service *types.ServiceConfig, containersByService map[string]Containers) error {
67+
if err := resolveVolumeFrom(service, containersByService); err != nil {
10268
return err
10369
}
104-
return nil
70+
return resolveSharedNamespaces(service, containersByService)
10571
}
10672

107-
func (c *convergence) resolveVolumeFrom(service *types.ServiceConfig) error {
73+
func resolveVolumeFrom(service *types.ServiceConfig, containersByService map[string]Containers) error {
10874
for i, vol := range service.VolumesFrom {
10975
spec := strings.Split(vol, ":")
11076
if len(spec) == 0 {
@@ -115,7 +81,7 @@ func (c *convergence) resolveVolumeFrom(service *types.ServiceConfig) error {
11581
continue
11682
}
11783
name := spec[0]
118-
dependencies := c.getObservedState(name)
84+
dependencies := containersByService[name]
11985
if len(dependencies) == 0 {
12086
return fmt.Errorf("cannot share volume with service %s: container missing", name)
12187
}
@@ -124,25 +90,32 @@ func (c *convergence) resolveVolumeFrom(service *types.ServiceConfig) error {
12490
return nil
12591
}
12692

127-
func (c *convergence) resolveSharedNamespaces(service *types.ServiceConfig) error {
128-
resolve := func(field *string, noun string) error {
129-
if name := getDependentServiceFromMode(*field); name != "" {
130-
dependencies := c.getObservedState(name)
131-
if len(dependencies) == 0 {
132-
return fmt.Errorf("cannot share %s namespace with service %s: container missing", noun, name)
133-
}
134-
*field = types.ContainerPrefix + dependencies.sorted()[0].ID
93+
func resolveSharedNamespaces(service *types.ServiceConfig, containersByService map[string]Containers) error {
94+
if name := getDependentServiceFromMode(service.NetworkMode); name != "" {
95+
dependencies := containersByService[name]
96+
if len(dependencies) == 0 {
97+
return fmt.Errorf("cannot share network namespace with service %s: container missing", name)
13598
}
136-
return nil
99+
service.NetworkMode = types.ContainerPrefix + dependencies.sorted()[0].ID
137100
}
138101

139-
if err := resolve(&service.NetworkMode, "network"); err != nil {
140-
return err
102+
if name := getDependentServiceFromMode(service.Ipc); name != "" {
103+
dependencies := containersByService[name]
104+
if len(dependencies) == 0 {
105+
return fmt.Errorf("cannot share IPC namespace with service %s: container missing", name)
106+
}
107+
service.Ipc = types.ContainerPrefix + dependencies.sorted()[0].ID
141108
}
142-
if err := resolve(&service.Ipc, "IPC"); err != nil {
143-
return err
109+
110+
if name := getDependentServiceFromMode(service.Pid); name != "" {
111+
dependencies := containersByService[name]
112+
if len(dependencies) == 0 {
113+
return fmt.Errorf("cannot share PID namespace with service %s: container missing", name)
114+
}
115+
service.Pid = types.ContainerPrefix + dependencies.sorted()[0].ID
144116
}
145-
return resolve(&service.Pid, "PID")
117+
118+
return nil
146119
}
147120

148121
func getContainerName(projectName string, service types.ServiceConfig, number int) string {

pkg/compose/executor.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,12 +198,11 @@ func (exec *planExecutor) execCreateContainer(ctx context.Context, node *PlanNod
198198
// Resolve service references (network_mode, ipc, pid, volumes_from) to actual
199199
// container IDs. This must happen at execution time because the referenced
200200
// containers may have just been created by earlier plan nodes.
201-
observedState, err := exec.compose.getContainers(ctx, exec.project.Name, oneOffExclude, true)
201+
containersByService, err := exec.compose.getContainersByService(ctx, exec.project.Name)
202202
if err != nil {
203203
return err
204204
}
205-
conv := newConvergence(exec.project.ServiceNames(), observedState, nil, nil, exec.compose)
206-
if err := conv.resolveServiceReferences(&service); err != nil {
205+
if err := resolveServiceReferences(&service, containersByService); err != nil {
207206
return err
208207
}
209208

pkg/compose/run.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,7 @@ func (s *composeService) prepareRun(ctx context.Context, project *types.Project,
181181
Labels: mergeLabels(service.Labels, service.CustomLabels),
182182
}
183183

184-
err = newConvergence(project.ServiceNames(), observedState, nil, nil, s).resolveServiceReferences(&service)
185-
if err != nil {
184+
if err := s.resolveRunServiceReferences(ctx, project.Name, &service); err != nil {
186185
return prepareRunResult{}, err
187186
}
188187

@@ -269,6 +268,14 @@ func applyRunOptions(project *types.Project, service *types.ServiceConfig, opts
269268
}
270269
}
271270

271+
func (s *composeService) resolveRunServiceReferences(ctx context.Context, projectName string, service *types.ServiceConfig) error {
272+
containersByService, err := s.getContainersByService(ctx, projectName)
273+
if err != nil {
274+
return err
275+
}
276+
return resolveServiceReferences(service, containersByService)
277+
}
278+
272279
func (s *composeService) startDependencies(ctx context.Context, project *types.Project, options api.RunOptions) error {
273280
project = project.WithServicesDisabled(options.Service)
274281

0 commit comments

Comments
 (0)