Signed-off-by: John Howard <jhoward@microsoft.com>
| ... | ... |
@@ -387,7 +387,7 @@ func workdir(req dispatchRequest) error {
|
| 387 | 387 |
runConfig := req.state.runConfig |
| 388 | 388 |
// This is from the Dockerfile and will not necessarily be in platform |
| 389 | 389 |
// specific semantics, hence ensure it is converted. |
| 390 |
- runConfig.WorkingDir, err = normaliseWorkdir(runConfig.WorkingDir, req.args[0]) |
|
| 390 |
+ runConfig.WorkingDir, err = normaliseWorkdir(req.builder.platform, runConfig.WorkingDir, req.args[0]) |
|
| 391 | 391 |
if err != nil {
|
| 392 | 392 |
return err |
| 393 | 393 |
} |
| ... | ... |
@@ -11,7 +11,7 @@ import ( |
| 11 | 11 |
|
| 12 | 12 |
// normaliseWorkdir normalises a user requested working directory in a |
| 13 | 13 |
// platform semantically consistent way. |
| 14 |
-func normaliseWorkdir(current string, requested string) (string, error) {
|
|
| 14 |
+func normaliseWorkdir(_ string, current string, requested string) (string, error) {
|
|
| 15 | 15 |
if requested == "" {
|
| 16 | 16 |
return "", errors.New("cannot normalise nothing")
|
| 17 | 17 |
} |
| ... | ... |
@@ -3,6 +3,7 @@ |
| 3 | 3 |
package dockerfile |
| 4 | 4 |
|
| 5 | 5 |
import ( |
| 6 |
+ "runtime" |
|
| 6 | 7 |
"testing" |
| 7 | 8 |
) |
| 8 | 9 |
|
| ... | ... |
@@ -16,7 +17,7 @@ func TestNormaliseWorkdir(t *testing.T) {
|
| 16 | 16 |
} |
| 17 | 17 |
|
| 18 | 18 |
for _, test := range testCases {
|
| 19 |
- normalised, err := normaliseWorkdir(test.current, test.requested) |
|
| 19 |
+ normalised, err := normaliseWorkdir(runtime.GOOS, test.current, test.requested) |
|
| 20 | 20 |
|
| 21 | 21 |
if test.expectedError != "" && err == nil {
|
| 22 | 22 |
t.Fatalf("NormaliseWorkdir should return an error %s, got nil", test.expectedError)
|
| ... | ... |
@@ -4,6 +4,7 @@ import ( |
| 4 | 4 |
"errors" |
| 5 | 5 |
"fmt" |
| 6 | 6 |
"os" |
| 7 |
+ "path" |
|
| 7 | 8 |
"path/filepath" |
| 8 | 9 |
"regexp" |
| 9 | 10 |
"strings" |
| ... | ... |
@@ -15,7 +16,33 @@ var pattern = regexp.MustCompile(`^[a-zA-Z]:\.$`) |
| 15 | 15 |
|
| 16 | 16 |
// normaliseWorkdir normalises a user requested working directory in a |
| 17 | 17 |
// platform semantically consistent way. |
| 18 |
-func normaliseWorkdir(current string, requested string) (string, error) {
|
|
| 18 |
+func normaliseWorkdir(platform string, current string, requested string) (string, error) {
|
|
| 19 |
+ if platform == "" {
|
|
| 20 |
+ platform = "windows" |
|
| 21 |
+ } |
|
| 22 |
+ if platform == "windows" {
|
|
| 23 |
+ return normaliseWorkdirWindows(current, requested) |
|
| 24 |
+ } |
|
| 25 |
+ return normaliseWorkdirUnix(current, requested) |
|
| 26 |
+} |
|
| 27 |
+ |
|
| 28 |
+// normaliseWorkdirUnix normalises a user requested working directory in a |
|
| 29 |
+// platform semantically consistent way. |
|
| 30 |
+func normaliseWorkdirUnix(current string, requested string) (string, error) {
|
|
| 31 |
+ if requested == "" {
|
|
| 32 |
+ return "", errors.New("cannot normalise nothing")
|
|
| 33 |
+ } |
|
| 34 |
+ current = strings.Replace(current, string(os.PathSeparator), "/", -1) |
|
| 35 |
+ requested = strings.Replace(requested, string(os.PathSeparator), "/", -1) |
|
| 36 |
+ if !path.IsAbs(requested) {
|
|
| 37 |
+ return path.Join(`/`, current, requested), nil |
|
| 38 |
+ } |
|
| 39 |
+ return requested, nil |
|
| 40 |
+} |
|
| 41 |
+ |
|
| 42 |
+// normaliseWorkdirWindows normalises a user requested working directory in a |
|
| 43 |
+// platform semantically consistent way. |
|
| 44 |
+func normaliseWorkdirWindows(current string, requested string) (string, error) {
|
|
| 19 | 45 |
if requested == "" {
|
| 20 | 46 |
return "", errors.New("cannot normalise nothing")
|
| 21 | 47 |
} |
| ... | ... |
@@ -5,25 +5,31 @@ package dockerfile |
| 5 | 5 |
import "testing" |
| 6 | 6 |
|
| 7 | 7 |
func TestNormaliseWorkdir(t *testing.T) {
|
| 8 |
- tests := []struct{ current, requested, expected, etext string }{
|
|
| 9 |
- {``, ``, ``, `cannot normalise nothing`},
|
|
| 10 |
- {``, `C:`, ``, `C:. is not a directory. If you are specifying a drive letter, please add a trailing '\'`},
|
|
| 11 |
- {``, `C:.`, ``, `C:. is not a directory. If you are specifying a drive letter, please add a trailing '\'`},
|
|
| 12 |
- {`c:`, `\a`, ``, `c:. is not a directory. If you are specifying a drive letter, please add a trailing '\'`},
|
|
| 13 |
- {`c:.`, `\a`, ``, `c:. is not a directory. If you are specifying a drive letter, please add a trailing '\'`},
|
|
| 14 |
- {``, `a`, `C:\a`, ``},
|
|
| 15 |
- {``, `c:\foo`, `C:\foo`, ``},
|
|
| 16 |
- {``, `c:\\foo`, `C:\foo`, ``},
|
|
| 17 |
- {``, `\foo`, `C:\foo`, ``},
|
|
| 18 |
- {``, `\\foo`, `C:\foo`, ``},
|
|
| 19 |
- {``, `/foo`, `C:\foo`, ``},
|
|
| 20 |
- {``, `C:/foo`, `C:\foo`, ``},
|
|
| 21 |
- {`C:\foo`, `bar`, `C:\foo\bar`, ``},
|
|
| 22 |
- {`C:\foo`, `/bar`, `C:\bar`, ``},
|
|
| 23 |
- {`C:\foo`, `\bar`, `C:\bar`, ``},
|
|
| 8 |
+ tests := []struct{ platform, current, requested, expected, etext string }{
|
|
| 9 |
+ {"windows", ``, ``, ``, `cannot normalise nothing`},
|
|
| 10 |
+ {"windows", ``, `C:`, ``, `C:. is not a directory. If you are specifying a drive letter, please add a trailing '\'`},
|
|
| 11 |
+ {"windows", ``, `C:.`, ``, `C:. is not a directory. If you are specifying a drive letter, please add a trailing '\'`},
|
|
| 12 |
+ {"windows", `c:`, `\a`, ``, `c:. is not a directory. If you are specifying a drive letter, please add a trailing '\'`},
|
|
| 13 |
+ {"windows", `c:.`, `\a`, ``, `c:. is not a directory. If you are specifying a drive letter, please add a trailing '\'`},
|
|
| 14 |
+ {"windows", ``, `a`, `C:\a`, ``},
|
|
| 15 |
+ {"windows", ``, `c:\foo`, `C:\foo`, ``},
|
|
| 16 |
+ {"windows", ``, `c:\\foo`, `C:\foo`, ``},
|
|
| 17 |
+ {"windows", ``, `\foo`, `C:\foo`, ``},
|
|
| 18 |
+ {"windows", ``, `\\foo`, `C:\foo`, ``},
|
|
| 19 |
+ {"windows", ``, `/foo`, `C:\foo`, ``},
|
|
| 20 |
+ {"windows", ``, `C:/foo`, `C:\foo`, ``},
|
|
| 21 |
+ {"windows", `C:\foo`, `bar`, `C:\foo\bar`, ``},
|
|
| 22 |
+ {"windows", `C:\foo`, `/bar`, `C:\bar`, ``},
|
|
| 23 |
+ {"windows", `C:\foo`, `\bar`, `C:\bar`, ``},
|
|
| 24 |
+ {"linux", ``, ``, ``, `cannot normalise nothing`},
|
|
| 25 |
+ {"linux", ``, `foo`, `/foo`, ``},
|
|
| 26 |
+ {"linux", ``, `/foo`, `/foo`, ``},
|
|
| 27 |
+ {"linux", `/foo`, `bar`, `/foo/bar`, ``},
|
|
| 28 |
+ {"linux", `/foo`, `/bar`, `/bar`, ``},
|
|
| 29 |
+ {"linux", `\a`, `b\c`, `/a/b/c`, ``},
|
|
| 24 | 30 |
} |
| 25 | 31 |
for _, i := range tests {
|
| 26 |
- r, e := normaliseWorkdir(i.current, i.requested) |
|
| 32 |
+ r, e := normaliseWorkdir(i.platform, i.current, i.requested) |
|
| 27 | 33 |
|
| 28 | 34 |
if i.etext != "" && e == nil {
|
| 29 | 35 |
t.Fatalf("TestNormaliseWorkingDir Expected error %s for '%s' '%s', got no error", i.etext, i.current, i.requested)
|
| ... | ... |
@@ -261,12 +261,17 @@ func (container *Container) WriteHostConfig() (*containertypes.HostConfig, error |
| 261 | 261 |
|
| 262 | 262 |
// SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir |
| 263 | 263 |
func (container *Container) SetupWorkingDirectory(rootIDs idtools.IDPair) error {
|
| 264 |
+ // TODO @jhowardmsft, @gupta-ak LCOW Support. This will need revisiting. |
|
| 265 |
+ // We will need to do remote filesystem operations here. |
|
| 266 |
+ if container.Platform != runtime.GOOS {
|
|
| 267 |
+ return nil |
|
| 268 |
+ } |
|
| 269 |
+ |
|
| 264 | 270 |
if container.Config.WorkingDir == "" {
|
| 265 | 271 |
return nil |
| 266 | 272 |
} |
| 267 | 273 |
|
| 268 | 274 |
container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir) |
| 269 |
- |
|
| 270 | 275 |
pth, err := container.GetResourcePath(container.Config.WorkingDir) |
| 271 | 276 |
if err != nil {
|
| 272 | 277 |
return err |
| ... | ... |
@@ -3,7 +3,10 @@ package daemon |
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"os" |
| 6 |
+ "path" |
|
| 6 | 7 |
"path/filepath" |
| 8 |
+ "runtime" |
|
| 9 |
+ "strings" |
|
| 7 | 10 |
"time" |
| 8 | 11 |
|
| 9 | 12 |
containertypes "github.com/docker/docker/api/types/container" |
| ... | ... |
@@ -226,13 +229,24 @@ func (daemon *Daemon) setHostConfig(container *container.Container, hostConfig * |
| 226 | 226 |
|
| 227 | 227 |
// verifyContainerSettings performs validation of the hostconfig and config |
| 228 | 228 |
// structures. |
| 229 |
-func (daemon *Daemon) verifyContainerSettings(hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
|
|
| 230 |
- |
|
| 229 |
+func (daemon *Daemon) verifyContainerSettings(platform string, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
|
|
| 231 | 230 |
// First perform verification of settings common across all platforms. |
| 232 | 231 |
if config != nil {
|
| 233 | 232 |
if config.WorkingDir != "" {
|
| 234 |
- config.WorkingDir = filepath.FromSlash(config.WorkingDir) // Ensure in platform semantics |
|
| 235 |
- if !system.IsAbs(config.WorkingDir) {
|
|
| 233 |
+ wdInvalid := false |
|
| 234 |
+ if runtime.GOOS == platform {
|
|
| 235 |
+ config.WorkingDir = filepath.FromSlash(config.WorkingDir) // Ensure in platform semantics |
|
| 236 |
+ if !system.IsAbs(config.WorkingDir) {
|
|
| 237 |
+ wdInvalid = true |
|
| 238 |
+ } |
|
| 239 |
+ } else {
|
|
| 240 |
+ // LCOW. Force Unix semantics |
|
| 241 |
+ config.WorkingDir = strings.Replace(config.WorkingDir, string(os.PathSeparator), "/", -1) |
|
| 242 |
+ if !path.IsAbs(config.WorkingDir) {
|
|
| 243 |
+ wdInvalid = true |
|
| 244 |
+ } |
|
| 245 |
+ } |
|
| 246 |
+ if wdInvalid {
|
|
| 236 | 247 |
return nil, fmt.Errorf("the working directory '%s' is invalid, it needs to be an absolute path", config.WorkingDir)
|
| 237 | 248 |
} |
| 238 | 249 |
} |
| ... | ... |
@@ -39,7 +39,17 @@ func (daemon *Daemon) containerCreate(params types.ContainerCreateConfig, manage |
| 39 | 39 |
return containertypes.ContainerCreateCreatedBody{}, validationError{errors.New("Config cannot be empty in order to create a container")}
|
| 40 | 40 |
} |
| 41 | 41 |
|
| 42 |
- warnings, err := daemon.verifyContainerSettings(params.HostConfig, params.Config, false) |
|
| 42 |
+ // TODO: @jhowardmsft LCOW support - at a later point, can remove the hard-coding |
|
| 43 |
+ // to force the platform to be linux. |
|
| 44 |
+ // Default the platform if not supplied |
|
| 45 |
+ if params.Platform == "" {
|
|
| 46 |
+ params.Platform = runtime.GOOS |
|
| 47 |
+ } |
|
| 48 |
+ if system.LCOWSupported() {
|
|
| 49 |
+ params.Platform = "linux" |
|
| 50 |
+ } |
|
| 51 |
+ |
|
| 52 |
+ warnings, err := daemon.verifyContainerSettings(params.Platform, params.HostConfig, params.Config, false) |
|
| 43 | 53 |
if err != nil {
|
| 44 | 54 |
return containertypes.ContainerCreateCreatedBody{Warnings: warnings}, validationError{err}
|
| 45 | 55 |
} |
| ... | ... |
@@ -75,16 +85,6 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) ( |
| 75 | 75 |
err error |
| 76 | 76 |
) |
| 77 | 77 |
|
| 78 |
- // TODO: @jhowardmsft LCOW support - at a later point, can remove the hard-coding |
|
| 79 |
- // to force the platform to be linux. |
|
| 80 |
- // Default the platform if not supplied |
|
| 81 |
- if params.Platform == "" {
|
|
| 82 |
- params.Platform = runtime.GOOS |
|
| 83 |
- } |
|
| 84 |
- if system.LCOWSupported() {
|
|
| 85 |
- params.Platform = "linux" |
|
| 86 |
- } |
|
| 87 |
- |
|
| 88 | 78 |
if params.Config.Image != "" {
|
| 89 | 79 |
img, err = daemon.GetImage(params.Config.Image) |
| 90 | 80 |
if err != nil {
|
| ... | ... |
@@ -79,7 +79,7 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos |
| 79 | 79 |
|
| 80 | 80 |
// check if hostConfig is in line with the current system settings. |
| 81 | 81 |
// It may happen cgroups are umounted or the like. |
| 82 |
- if _, err = daemon.verifyContainerSettings(container.HostConfig, nil, false); err != nil {
|
|
| 82 |
+ if _, err = daemon.verifyContainerSettings(container.Platform, container.HostConfig, nil, false); err != nil {
|
|
| 83 | 83 |
return validationError{err}
|
| 84 | 84 |
} |
| 85 | 85 |
// Adapt for old containers in case we have updates in this function and |
| ... | ... |
@@ -11,7 +11,12 @@ import ( |
| 11 | 11 |
func (daemon *Daemon) ContainerUpdate(name string, hostConfig *container.HostConfig) (container.ContainerUpdateOKBody, error) {
|
| 12 | 12 |
var warnings []string |
| 13 | 13 |
|
| 14 |
- warnings, err := daemon.verifyContainerSettings(hostConfig, nil, true) |
|
| 14 |
+ c, err := daemon.GetContainer(name) |
|
| 15 |
+ if err != nil {
|
|
| 16 |
+ return container.ContainerUpdateOKBody{Warnings: warnings}, err
|
|
| 17 |
+ } |
|
| 18 |
+ |
|
| 19 |
+ warnings, err = daemon.verifyContainerSettings(c.Platform, hostConfig, nil, true) |
|
| 15 | 20 |
if err != nil {
|
| 16 | 21 |
return container.ContainerUpdateOKBody{Warnings: warnings}, validationError{err}
|
| 17 | 22 |
} |