Skip to content

Commit e2eab1f

Browse files
committed
remove restriction for extends to refer to another resource
Signed-off-by: Nicolas De Loof <[email protected]>
1 parent a0507e9 commit e2eab1f

File tree

5 files changed

+48
-52
lines changed

5 files changed

+48
-52
lines changed

loader/extends.go

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"context"
2121
"fmt"
2222
"path/filepath"
23-
"strings"
2423

2524
"github.com/compose-spec/compose-go/v2/consts"
2625
"github.com/compose-spec/compose-go/v2/override"
@@ -106,11 +105,6 @@ func applyServiceExtends(ctx context.Context, name string, services map[string]a
106105
}
107106
source := deepClone(base).(map[string]any)
108107

109-
err = validateExtendSource(source, ref)
110-
if err != nil {
111-
return nil, err
112-
}
113-
114108
for _, processor := range post {
115109
processor.Apply(map[string]any{
116110
"services": map[string]any{
@@ -127,30 +121,6 @@ func applyServiceExtends(ctx context.Context, name string, services map[string]a
127121
return merged, nil
128122
}
129123

130-
// validateExtendSource check the source for `extends` doesn't refer to another container/service
131-
func validateExtendSource(source map[string]any, ref string) error {
132-
forbidden := []string{"links", "volumes_from", "depends_on"}
133-
for _, key := range forbidden {
134-
if _, ok := source[key]; ok {
135-
return fmt.Errorf("service %q can't be used with `extends` as it declare `%s`", ref, key)
136-
}
137-
}
138-
139-
sharedNamespace := []string{"network_mode", "ipc", "pid", "net", "cgroup", "userns_mode", "uts"}
140-
for _, key := range sharedNamespace {
141-
if v, ok := source[key]; ok {
142-
val := v.(string)
143-
if strings.HasPrefix(val, types.ContainerPrefix) {
144-
return fmt.Errorf("service %q can't be used with `extends` as it shares `%s` with another container", ref, key)
145-
}
146-
if strings.HasPrefix(val, types.ServicePrefix) {
147-
return fmt.Errorf("service %q can't be used with `extends` as it shares `%s` with another service", ref, key)
148-
}
149-
}
150-
}
151-
return nil
152-
}
153-
154124
func getExtendsBaseFromFile(ctx context.Context, name string, path string, opts *Options, ct *cycleTracker) (map[string]any, error) {
155125
for _, loader := range opts.ResourceLoaders {
156126
if !loader.Accept(path) {

loader/extends_test.go

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ services:
306306
assert.Equal(t, extendsCount, 3)
307307
}
308308

309-
func TestRejectExtendsWithServiceRef(t *testing.T) {
309+
func TestExtendsWithServiceRef(t *testing.T) {
310310
tests := []struct {
311311
name string
312312
yaml string
@@ -317,54 +317,48 @@ func TestRejectExtendsWithServiceRef(t *testing.T) {
317317
yaml: `
318318
name: test-extends_with_volumes_from
319319
services:
320-
foo:
321-
volumes_from:
322-
- zot
323-
bar:
320+
bar:
324321
extends:
325-
service: foo
322+
file: ./testdata/extends/depends_on.yaml
323+
service: with_volumes_from
326324
`,
327-
wantErr: "service \"foo\" can't be used with `extends` as it declare `volumes_from`",
325+
wantErr: `service "bar" depends on undefined service "zot"`,
328326
},
329327
{
330328
name: "depends_on",
331329
yaml: `
332330
name: test-extends_with_depends_on
333331
services:
334-
foo:
335-
depends_on:
336-
- zot
337332
bar:
338333
extends:
339-
service: foo
334+
file: ./testdata/extends/depends_on.yaml
335+
service: with_depends_on
340336
`,
341-
wantErr: "service \"foo\" can't be used with `extends` as it declare `depends_on`",
337+
wantErr: `service "bar" depends on undefined service "zot"`,
342338
},
343339
{
344340
name: "shared ipc",
345341
yaml: `
346342
name: test-extends_with_shared_ipc
347343
services:
348-
foo:
349-
ipc: "service:zot"
350344
bar:
351345
extends:
352-
service: foo
346+
file: ./testdata/extends/depends_on.yaml
347+
service: with_ipc
353348
`,
354-
wantErr: "service \"foo\" can't be used with `extends` as it shares `ipc` with another service",
349+
wantErr: `service "bar" depends on undefined service "zot"`,
355350
},
356351
{
357352
name: "shared network_mode",
358353
yaml: `
359354
name: test-extends_with_shared_network_mode
360355
services:
361-
foo:
362-
network_mode: "container:123abc"
363356
bar:
364357
extends:
365-
service: foo
358+
file: ./testdata/extends/depends_on.yaml
359+
service: with_network_mode
366360
`,
367-
wantErr: "service \"foo\" can't be used with `extends` as it shares `network_mode` with another container",
361+
wantErr: `service "bar" depends on undefined service "zot"`,
368362
},
369363
}
370364

@@ -376,6 +370,17 @@ services:
376370
}},
377371
})
378372
assert.ErrorContains(t, err, tt.wantErr)
373+
374+
// Do the same but with a local `zot` service matching the imported reference
375+
_, err = LoadWithContext(context.Background(), types.ConfigDetails{
376+
ConfigFiles: []types.ConfigFile{{
377+
Content: []byte(tt.yaml + `
378+
zot:
379+
image: zot
380+
`),
381+
}},
382+
})
383+
assert.NilError(t, err)
379384
})
380385
}
381386
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
services:
2+
with_depends_on:
3+
image: foo
4+
depends_on:
5+
- zot
6+
7+
with_volumes_from:
8+
image: foo
9+
volumes_from:
10+
- zot
11+
12+
with_ipc:
13+
image: foo
14+
ipc: "service:zot"
15+
16+
with_network_mode:
17+
image: foo
18+
network_mode: "service:zot"
19+
20+
zot:
21+
image: hidden

loader/validate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func checkConsistency(project *types.Project) error {
7373

7474
for dependedService := range s.DependsOn {
7575
if _, err := project.GetService(dependedService); err != nil {
76-
return fmt.Errorf("service %q depends on undefined service %s: %w", s.Name, dependedService, errdefs.ErrInvalid)
76+
return fmt.Errorf("service %q depends on undefined service %q: %w", s.Name, dependedService, errdefs.ErrInvalid)
7777
}
7878
}
7979
// Check there isn't a cycle in depends_on declarations

loader/validate_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ func TestValidateDependsOn(t *testing.T) {
258258
},
259259
}
260260
err := checkConsistency(&project)
261-
assert.Error(t, err, `service "myservice" depends on undefined service missingservice: invalid compose project`)
261+
assert.Error(t, err, `service "myservice" depends on undefined service "missingservice": invalid compose project`)
262262
}
263263

264264
func TestValidateContainerName(t *testing.T) {

0 commit comments

Comments
 (0)