Change:
t.Errorf("%v: payload and observed payload do not match.", tcName) } } <ins> func TestValidatePayload(t *testing.T) { maxPath := strings.Repeat("a", maxPathLength+1) cases := []struct { name     string payload  map[string]FileProjection expected sets.String valid    bool }{ { name: "valid payload", payload: map[string]FileProjection{ "foo": {}, "bar": {}, }, valid:    true, expected: sets.NewString("foo", "bar"), }, { name: "payload with path length > 4096 is invalid", payload: map[string]FileProjection{ maxPath: {}, }, valid: false, }, { name: "payload with absolute path is invalid", payload: map[string]FileProjection{ "/dev/null": {}, }, valid: false, }, { name: "payload with reserved path is invalid", payload: map[string]FileProjection{ "..sneaky.txt": {}, }, valid: false, }, { name: "payload with doubledot path is invalid", payload: map[string]FileProjection{ "foo/../etc/password": {}, }, valid: false, }, { name: "payload with empty path is invalid", payload: map[string]FileProjection{ "": {}, }, valid: false, }, { name: "payload with unclean path should be cleaned", payload: map[string]FileProjection{ "foo////bar": {}, }, valid:    true, expected: sets.NewString("foo/bar"), }, } getPayloadPaths := func(payload map[string]FileProjection) sets.String { paths := sets.NewString() for path := range payload { paths.Insert(path) } return paths } for _, tc := range cases { real, err := validatePayload(tc.payload) if !tc.valid && err == nil { t.Errorf("%v: unexpected success", tc.name) } if tc.valid { if err != nil { t.Errorf("%v: unexpected failure: %v", tc.name, err) continue } realPaths := getPayloadPaths(real) if !realPaths.Equal(tc.expected) { t.Errorf("%v: unexpected payload paths: %v is not equal to %v", tc.name, realPaths, tc.expected) } } } } func TestCreateUserVisibleFiles(t *testing.T) { cases := []struct { name     string payload  map[string]FileProjection expected map[string]string }{ { name: "simple path", payload: map[string]FileProjection{ "foo": {}, "bar": {}, }, expected: map[string]string{ "foo": "..data/foo", "bar": "..data/bar", }, }, { name: "simple nested path", payload: map[string]FileProjection{ "foo/bar":     {}, "foo/bar/txt": {}, "bar/txt":     {}, }, expected: map[string]string{ "foo": "..data/foo", "bar": "..data/bar", }, }, { name: "unclean nested path", payload: map[string]FileProjection{ "./bar":     {}, "foo///bar": {}, }, expected: map[string]string{ "bar": "..data/bar", "foo": "..data/foo", }, }, } for _, tc := range cases { targetDir, err := utiltesting.MkTmpdir("atomic-write") if err != nil { t.Errorf("%v: unexpected error creating tmp dir: %v", tc.name, err) continue } defer os.RemoveAll(targetDir) dataDirPath := path.Join(targetDir, dataDirName) err = os.MkdirAll(dataDirPath, 0755) if err != nil { t.Fatalf("%v: unexpected error creating data path: %v", tc.name, err) } writer := &AtomicWriter{targetDir: targetDir, logContext: "-test-"} payload, err := validatePayload(tc.payload) if err != nil { t.Fatalf("%v: unexpected error validating payload: %v", tc.name, err) } err = writer.createUserVisibleFiles(payload) if err != nil { t.Fatalf("%v: unexpected error creating visible files: %v", tc.name, err) } for subpath, expectedDest := range tc.expected { visiblePath := path.Join(targetDir, subpath) destination, err := os.Readlink(visiblePath) if err != nil && os.IsNotExist(err) { t.Fatalf("%v: visible symlink does not exist: %v", tc.name, visiblePath) } else if err != nil { t.Fatalf("%v: unable to read symlink %v: %v", tc.name, dataDirPath, err) } if expectedDest != destination { t.Fatalf("%v: symlink destination %q not same with expected data dir %q", tc.name, destination, expectedDest) } } } } </ins>

Discussion:
<!-- This form is for bug reports and feature requests ONLY! If you're looking for help check and the . --Is this a BUG REPORT or FEATURE REQUEST?: /kind bug /sig windows What happened: Creating pods containing volumes with projected Secret keys to nested paths fails on Kubernetes using Windows nodes, they get stuck in the state. Additionally, this causes the Kubelet service on the Windows node to fully utilize a CPU indefinitely (even after the pod was deleted). Creating multiple pods will eventually cause the node to be inaccessible. This issue does not occur with simple paths. What you expected to happen: The pod should end up in state. How to reproduce it (as minimally and precisely as possible): echo "apiVersion: v1 kind: Secret metadata: name: my-special-secret type: Opaque data: data-1: aGVsbG8gdGhlcmUh " my- echo "apiVersion: v1 kind: Pod metadata: name: test-projected-volume spec: containers: name: test-projected-volume image: atuvenie/mounttest:1.0 args: ["--file_content=/projected-volume/new/path/data-1"] volumeMounts: name: all-in-one mountPath: "/projected-volume" readOnly: true volumes: name: all-in-one projected: sources: secret: name: my-special-secret items: key: "data-1" path: "new/path/data-1" " test-projected-volume- kubectl create -f ./my- kubectl create -f ./test-projected-volume- kubectl get --watch pod test-projected-volume Replacing ` State. Anything else we need to know?: Environment: Kubernetes version: Client Version: v1.9.3 Server Version: v1.8.4 Windows Kubelet Version: v1.8.4-20+ Cloud provider or hardware configuration: Azure Container Service OS (e.g. from /etc/os-release): Microsoft Windows Server Datacenter 10.0. N/A Build
is this an area you might be able to help with?
There is something wrong when setting up nested paths. Let me file a PR to fix this
Filed to fix this issue. Please note that symlink is used and it is only available on Windows 10 Insider & Windows Server Insider builds + (refer ).
will this help as well?
is the symlink issues, which requires Windows next release.