Change:
return cs.CoreV1().Pods(ns).Create(context.TODO(), pod, metav1.CreateOptions{}) } <del> func checkPodLogs(ctx context.Context, getCalls func(ctx context.Context) ([]drivers.MockCSICall, error), pod *v1.Pod, expectPodInfo, ephemeralVolume, csiInlineVolumesEnabled, csiServiceAccountTokenEnabled bool, expectedNumNodePublish int) error { </del> <ins> // checkNodePublishVolume goes through all calls to the mock driver and checks that at least one NodePublishVolume call had expected attributes. // If a matched call is found but it has unexpected attributes, checkNodePublishVolume skips it and continues searching. func checkNodePublishVolume(ctx context.Context, getCalls func(ctx context.Context) ([]drivers.MockCSICall, error), pod *v1.Pod, expectPodInfo, ephemeralVolume, csiInlineVolumesEnabled, csiServiceAccountTokenEnabled bool) error { </ins> expectedAttributes := map[string]string{} <ins> unexpectedAttributeKeys := sets.New[string]() </ins> if expectPodInfo { expectedAttributes["csi.storage.k8s.io/pod.name"] = pod.Name expectedAttributes["csi.storage.k8s.io/pod.namespace"] = pod.Namespace expectedAttributes["csi.storage.k8s.io/pod.uid"] = string(pod.UID) expectedAttributes["csi.storage.k8s.io/serviceAccount.name"] = "default" <ins> } else { unexpectedAttributeKeys.Insert("csi.storage.k8s.io/pod.name") unexpectedAttributeKeys.Insert("csi.storage.k8s.io/pod.namespace") unexpectedAttributeKeys.Insert("csi.storage.k8s.io/pod.uid") unexpectedAttributeKeys.Insert("csi.storage.k8s.io/serviceAccount.name") </ins> } if csiInlineVolumesEnabled { // This is only passed in 1.15 when the CSIInlineVolume feature gate is set. expectedAttributes["csi.storage.k8s.io/ephemeral"] = strconv.FormatBool(ephemeralVolume) <ins> } else { unexpectedAttributeKeys.Insert("csi.storage.k8s.io/ephemeral") </ins> } if csiServiceAccountTokenEnabled { expectedAttributes["csi.storage.k8s.io/serviceAccount.tokens"] = "<nonempty>" <ins> } else { unexpectedAttributeKeys.Insert("csi.storage.k8s.io/serviceAccount.tokens") </ins> } <del> // Find NodePublish in the GRPC calls. foundAttributes := sets.NewString() numNodePublishVolume := 0 numNodeUnpublishVolume := 0 </del> calls, err := getCalls(ctx) if err != nil { return err } <ins> var volumeContexts []map[string]string </ins> for _, call := range calls { <del> switch call.Method { case "NodePublishVolume": numNodePublishVolume++ if numNodePublishVolume == expectedNumNodePublish { // Check that NodePublish had expected attributes for last of expected volume for k, v := range expectedAttributes { vv, found := call.Request.VolumeContext[k] if found && (v == vv || (v == "<nonempty>" && len(vv) != 0)) { foundAttributes.Insert(k) framework.Logf("Found volume attribute %s: %s", k, vv) } } </del> <ins> if call.Method != "NodePublishVolume" { continue } volumeCtx := call.Request.VolumeContext // Check that NodePublish had expected attributes foundAttributes := sets.NewString() for k, v := range expectedAttributes { vv, found := volumeCtx[k] if found && (v == vv || (v == "<nonempty>" && len(vv) != 0)) { foundAttributes.Insert(k) </ins> } <del> case "NodeUnpublishVolume": framework.Logf("Found NodeUnpublishVolume: %+v", call) numNodeUnpublishVolume++ </del> } <del> } if numNodePublishVolume < expectedNumNodePublish { return fmt.Errorf("NodePublish should be called at least %d", expectedNumNodePublish) } </del> <ins> if foundAttributes.Len() != len(expectedAttributes) { framework.Logf("Skipping the NodePublishVolume call: expected attribute %+v, got %+v", format.Object(expectedAttributes, 1), format.Object(volumeCtx, 1)) continue } </ins> <del> if numNodeUnpublishVolume == 0 { return fmt.Errorf("NodeUnpublish was never called") </del> <ins> // Check that NodePublish had no unexpected attributes unexpectedAttributes := make(map[string]string) for k := range volumeCtx { if unexpectedAttributeKeys.Has(k) { unexpectedAttributes[k] = volumeCtx[k] } } if len(unexpectedAttributes) != 0 { framework.Logf("Skipping the NodePublishVolume call because it contains unexpected attributes %+v", format.Object(unexpectedAttributes, 1)) continue } return nil </ins> } <del> if foundAttributes.Len() != len(expectedAttributes) { return fmt.Errorf("number of found volume attributes does not match, expected %d, got %d", len(expectedAttributes), foundAttributes.Len()) </del> <ins> if len(volumeContexts) == 0 { return fmt.Errorf("NodePublishVolume was never called") </ins> } <del> return nil </del> <ins> return fmt.Errorf("NodePublishVolume was called %d times, but no call had expected attributes %s or calls have unwanted attributes key %+v", len(volumeContexts), format.Object(expectedAttributes, 1), unexpectedAttributeKeys.UnsortedList()) </ins> } // createFSGroupRequestPreHook creates a hook that records the fsGroup passed in

Discussion:
1 ci-kubernetes-e2e-gci-gce 1 ci-cos-containerd-e2e-cos-gce in the master blocking test grid 1 ci-kubernetes-e2e-gci-gce-network-proxy-grpc 1 ci-kubernetes-e2e-gci-gce-proto Kubernetes e2e suite.[It] [sig-storage] CSI Mock workload info CSI PodInfoOnMount Update should be passed when update from false to true 12/14 code thaw after 1.29.0 release was merged at the time and is related to PodInfoOnMount. /cc /sig storage
This issue is currently awaiting triage. If a SIG or subproject determines this is a relevant issue, they will accept it by applying the label and provide further guidance. The label can be by org members by writing in a comment. <detailsInstructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details
/assign
testCase: podInfoOnMount should be passed when update from false to true kubelet log: csi-mockplugin-0-mock log: the function in the test case is not working as expected. expect log at Line 2, but actual log is at Line 3.
is called twice for the same volume sometime even though the volume is already published successfully. Not only this issue, but also other issues like I wonder if it is a potential bug or a normal behavior. cc what do you think?
good catch. I think that any test that depends on exact index of NodePublish call will be flaky, sometimes Kubelet has to retry NodePublish. It would be better to check for NodePublish parameter changes. For example, test should check there were 1 or more NodePublish calls with no pod info and then 1 or more NodePublish calls with pod info afterwards.