mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 19:13:34 +00:00
volumes: error when using relative volumes sources in compose (#353)
Signed-off-by: Miek Gieben <miek@miek.nl> Co-authored-by: Pasha Sviderski <me@psviderski.name>
This commit is contained in:
co-authored by
Pasha Sviderski
parent
73d515bb40
commit
cffa03007b
@@ -22,6 +22,7 @@ var registerComposeOverrides sync.Once
|
|||||||
func LoadProject(ctx context.Context, paths []string, opts ...composecli.ProjectOptionsFn) (*types.Project, error) {
|
func LoadProject(ctx context.Context, paths []string, opts ...composecli.ProjectOptionsFn) (*types.Project, error) {
|
||||||
registerComposeOverrides.Do(func() {
|
registerComposeOverrides.Do(func() {
|
||||||
transform.RegisterDefaultValue("services.*.deploy.update_config", setUpdateConfigDefaults)
|
transform.RegisterDefaultValue("services.*.deploy.update_config", setUpdateConfigDefaults)
|
||||||
|
transform.RegisterDefaultValue("services.*.volumes.*.source", checkRelativeVolumeMount)
|
||||||
})
|
})
|
||||||
|
|
||||||
defaultOpts := []composecli.ProjectOptionsFn{
|
defaultOpts := []composecli.ProjectOptionsFn{
|
||||||
@@ -119,3 +120,20 @@ func setUpdateConfigDefaults(data any, _ tree.Path, _ bool) (any, error) {
|
|||||||
}
|
}
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkRelativeVolumeMount check if a volume mount uses a relative path.
|
||||||
|
func checkRelativeVolumeMount(data any, _ tree.Path, _ bool) (any, error) {
|
||||||
|
source, ok := data.(string)
|
||||||
|
if !ok || filepath.IsAbs(source) {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
// Only check actual paths, not volumes _names_
|
||||||
|
if strings.HasPrefix(source, ".") || strings.HasPrefix(source, "~") {
|
||||||
|
// uc run also warns against this
|
||||||
|
return nil, fmt.Errorf("invalid volume mount: bind mount source '%s' is relative. If you intended to pass a host "+
|
||||||
|
"directory or file, use absolute path, or configs might be better suited for this use case. "+
|
||||||
|
"See https://uncloud.run/docs/concepts/configs", source)
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ REDIS_URL=redis://localhost:6379
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestLoadProject_Unsupported checks that unsupported features lead to warnings.
|
// TestLoadProject_Unsupported checks that unsupported features lead to warnings or errors.
|
||||||
func TestLoadProject_Unsupported(t *testing.T) {
|
func TestLoadProject_Unsupported(t *testing.T) {
|
||||||
// captureStderr runs fn while capturing stderr output and returns what was written.
|
// captureStderr runs fn while capturing stderr output and returns what was written.
|
||||||
captureStderr := func(t *testing.T, fn func()) string {
|
captureStderr := func(t *testing.T, fn func()) string {
|
||||||
@@ -214,6 +214,7 @@ func TestLoadProject_Unsupported(t *testing.T) {
|
|||||||
composeYAML string
|
composeYAML string
|
||||||
warnCount int
|
warnCount int
|
||||||
warnContains []string
|
warnContains []string
|
||||||
|
shouldErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "unsupported dns",
|
name: "unsupported dns",
|
||||||
@@ -296,12 +297,40 @@ networks:
|
|||||||
`,
|
`,
|
||||||
warnCount: 0,
|
warnCount: 0,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "relative volume sources",
|
||||||
|
composeYAML: `services:
|
||||||
|
app:
|
||||||
|
image: myapp:latest
|
||||||
|
volumes:
|
||||||
|
- ./mypath/conf:/conf:ro
|
||||||
|
- data:/var/lib/data
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
data:
|
||||||
|
`,
|
||||||
|
shouldErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "home-relative volume source",
|
||||||
|
composeYAML: `services:
|
||||||
|
app:
|
||||||
|
image: myapp:latest
|
||||||
|
volumes:
|
||||||
|
- ~/conf:/conf:ro
|
||||||
|
`,
|
||||||
|
shouldErr: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
stderr := captureStderr(t, func() {
|
stderr := captureStderr(t, func() {
|
||||||
_, err := LoadProjectFromContent(context.Background(), tt.composeYAML)
|
_, err := LoadProjectFromContent(context.Background(), tt.composeYAML)
|
||||||
|
if tt.shouldErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user