cluster/executor: check mounts at start
While it is important to not create controllers for an invalid task, certain properties should only be checked immediately before use. Early host validation of mounts prevents resolution of the task Executor when the mounts are not relevant to execution flow. In this case, we have a check for the existence of a bind mount path in a creation function that prevents a task controller from being resolved. Such early validation prevents one from interacting directly with a controller and result in unnecessary error reporting. In accordance with the above, we move the validation of the existence of host bind mount paths to the `Controller.Start` phase. We also call these "checks", as they are valid mounts but reference non-existent paths. Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
parent
e07c392c49
commit
92899ffac8
5 changed files with 31 additions and 9 deletions
|
@ -6,6 +6,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
@ -259,7 +260,28 @@ func (c *containerAdapter) create(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkMounts ensures that the provided mounts won't have any host-specific
|
||||||
|
// problems at start up. For example, we disallow bind mounts without an
|
||||||
|
// existing path, which slightly different from the container API.
|
||||||
|
func (c *containerAdapter) checkMounts() error {
|
||||||
|
spec := c.container.spec()
|
||||||
|
for _, mount := range spec.Mounts {
|
||||||
|
switch mount.Type {
|
||||||
|
case api.MountTypeBind:
|
||||||
|
if _, err := os.Stat(mount.Source); os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("invalid bind mount source, source path not found: %s", mount.Source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *containerAdapter) start(ctx context.Context) error {
|
func (c *containerAdapter) start(ctx context.Context) error {
|
||||||
|
if err := c.checkMounts(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return c.backend.ContainerStart(c.container.name(), nil, "", "")
|
return c.backend.ContainerStart(c.container.name(), nil, "", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ package container
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/docker/swarmkit/api"
|
"github.com/docker/swarmkit/api"
|
||||||
|
@ -25,9 +24,6 @@ func validateMounts(mounts []api.Mount) error {
|
||||||
if !filepath.IsAbs(mount.Source) {
|
if !filepath.IsAbs(mount.Source) {
|
||||||
return fmt.Errorf("invalid bind mount source, must be an absolute path: %s", mount.Source)
|
return fmt.Errorf("invalid bind mount source, must be an absolute path: %s", mount.Source)
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(mount.Source); os.IsNotExist(err) {
|
|
||||||
return fmt.Errorf("invalid bind mount source, source path not found: %s", mount.Source)
|
|
||||||
}
|
|
||||||
case api.MountTypeVolume:
|
case api.MountTypeVolume:
|
||||||
if filepath.IsAbs(mount.Source) {
|
if filepath.IsAbs(mount.Source) {
|
||||||
return fmt.Errorf("invalid volume mount source, must not be an absolute path: %s", mount.Source)
|
return fmt.Errorf("invalid volume mount source, must not be an absolute path: %s", mount.Source)
|
||||||
|
|
|
@ -42,10 +42,10 @@ func TestControllerValidateMountBind(t *testing.T) {
|
||||||
// with non-existing source
|
// with non-existing source
|
||||||
if _, err := newTestControllerWithMount(api.Mount{
|
if _, err := newTestControllerWithMount(api.Mount{
|
||||||
Type: api.MountTypeBind,
|
Type: api.MountTypeBind,
|
||||||
Source: "/some-non-existing-host-path/",
|
Source: testAbsNonExistent,
|
||||||
Target: testAbsPath,
|
Target: testAbsPath,
|
||||||
}); err == nil || !strings.Contains(err.Error(), "invalid bind mount source") {
|
}); err != nil {
|
||||||
t.Fatalf("expected error, got: %v", err)
|
t.Fatalf("controller should not error at creation: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// with proper source
|
// with proper source
|
||||||
|
|
|
@ -3,5 +3,6 @@
|
||||||
package container
|
package container
|
||||||
|
|
||||||
const (
|
const (
|
||||||
testAbsPath = "/foo"
|
testAbsPath = "/foo"
|
||||||
|
testAbsNonExistent = "/some-non-existing-host-path/"
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
// +build windows
|
||||||
|
|
||||||
package container
|
package container
|
||||||
|
|
||||||
const (
|
const (
|
||||||
testAbsPath = `c:\foo`
|
testAbsPath = `c:\foo`
|
||||||
|
testAbsNonExistent = `c:\some-non-existing-host-path\`
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue