Change:
For statically created PVs, the persistent volume label admission controller adds the zone label to the PV object. If the admission controller is not enabled or has some bugs, then an e2e test would be helpful for catching these errors. /assign
There are no sig labels on this issue. Please by:<br(1) mentioning a sig: <br(2) specifying the label manually: <br<brNote: method (1) will trigger a notification to the team. You can find the team list and label list

Discussion:
// (+optional) Annotations defines the PVC's annotations type PersistentVolumeClaimConfig struct { <del> AccessModes []v1.PersistentVolumeAccessMode Annotations map[string]string Selector    *metav1.LabelSelector </del> <ins> AccessModes      []v1.PersistentVolumeAccessMode Annotations      map[string]string Selector         *metav1.LabelSelector StorageClassName *string </ins> } // Clean up a pv and pvc in a single pv/pvc test case.

v1.ResourceName(v1.ResourceStorage): resource.MustParse("1Gi"), }, }, <ins> StorageClassName: cfg.StorageClassName, </ins> }, } } <del> func CreatePDWithRetry() (string, error) { </del> <ins> func createPDWithRetry(zone string) (string, error) { </ins> var err error for start := time.Now(); time.Since(start) < PDRetryTimeout; time.Sleep(PDRetryPollTime) { <del> newDiskName, err := createPD() </del> <ins> newDiskName, err := createPD(zone) </ins> if err != nil { Logf("Couldn't create a new PD, sleeping 5 seconds: %v", err) continue

return "", err } <ins> func CreatePDWithRetry() (string, error) { return createPDWithRetry("") } func CreatePDWithRetryAndZone(zone string) (string, error) { return createPDWithRetry(zone) } </ins> func DeletePDWithRetry(diskName string) error { var err error for start := time.Now(); time.Since(start) < PDRetryTimeout; time.Sleep(PDRetryPollTime) {

return fmt.Errorf("unable to delete PD %q: %v", diskName, err) } <del> func createPD() (string, error) { </del> <ins> func createPD(zone string) (string, error) { if zone == "" { zone = TestContext.CloudConfig.Zone } </ins> if TestContext.Provider == "gce" || TestContext.Provider == "gke" { pdName := fmt.Sprintf("%s-%s", TestContext.Prefix, string(uuid.NewUUID()))

} tags := map[string]string{} <del> err = gceCloud.CreateDisk(pdName, gcecloud.DiskTypeSSD, TestContext.CloudConfig.Zone, 10 /* sizeGb */, tags) </del> <ins> err = gceCloud.CreateDisk(pdName, gcecloud.DiskTypeSSD, zone, 10 /* sizeGb */, tags) </ins> if err != nil { return "", err }

client := ec2.New(session.New()) request := &ec2.CreateVolumeInput{} <del> request.AvailabilityZone = aws.String(TestContext.CloudConfig.Zone) </del> <ins> request.AvailabilityZone = aws.String(zone) </ins> request.Size = aws.Int64(10) request.VolumeType = aws.String(awscloud.DefaultVolumeType) response, err := client.CreateVolume(request)

} return persistentvolumes, nil } <ins> func CreatePVSource(zone string) (*v1.PersistentVolumeSource, error) { diskName, err := CreatePDWithRetryAndZone(zone) if err != nil { return nil, err } if TestContext.Provider == "gce" || TestContext.Provider == "gke" { return &v1.PersistentVolumeSource{ GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ PDName:   diskName, FSType:   "ext3", ReadOnly: false, }, }, nil } else if TestContext.Provider == "aws" { return &v1.PersistentVolumeSource{ AWSElasticBlockStore: &v1.AWSElasticBlockStoreVolumeSource{ VolumeID: diskName, FSType:   "ext3", }, }, nil } else { return nil, fmt.Errorf("Provider not supported") } } func DeletePVSource(pvSource *v1.PersistentVolumeSource) error { if TestContext.Provider == "gce" || TestContext.Provider == "gke" { return DeletePDWithRetry(pvSource.GCEPersistentDisk.PDName) } else if TestContext.Provider == "aws" { return DeletePDWithRetry(pvSource.AWSElasticBlockStore.VolumeID) } else { return fmt.Errorf("Provider not supported") } } </ins>

It("should spread the pods of a replication controller across zones", func() { SpreadRCOrFail(f, int32((2*zoneCount)+1), image) }) <ins> It("should schedule pods in the same zones as statically provisioned PVs", func() { PodsUseStaticPVsOrFail(f, (2*zoneCount)+1, image) }) </ins> }) // Check that the pods comprising a service get spread evenly across available zones

Expect(err).NotTo(HaveOccurred()) Expect(checkZoneSpreading(f.ClientSet, pods, zoneNames)).To(Equal(true)) } <ins> type StaticPVTestConfig struct { pvSource *v1.PersistentVolumeSource pv       *v1.PersistentVolume pvc      *v1.PersistentVolumeClaim pod      *v1.Pod } // Check that the pods using statically created PVs get scheduled to the same zone that the PV is in. func PodsUseStaticPVsOrFail(f *framework.Framework, podCount int, image string) { // TODO: add GKE after enabling admission plugin in GKE // TODO: add AWS framework.SkipUnlessProviderIs("gce") var err error c := f.ClientSet ns := f.Namespace.Name zones, err := getZoneNames(c) Expect(err).NotTo(HaveOccurred()) By("Creating static PVs across zones") configs := make([]*StaticPVTestConfig, podCount) for i := range configs { configs[i] = &StaticPVTestConfig{} } defer func() { By("Cleaning up pods and PVs") for _, config := range configs { framework.DeletePodOrFail(c, ns, config.pod.Name) } for _, config := range configs { framework.WaitForPodNoLongerRunningInNamespace(c, config.pod.Name, ns) framework.PVPVCCleanup(c, ns, config.pv, config.pvc) err = framework.DeletePVSource(config.pvSource) Expect(err).NotTo(HaveOccurred()) } }() for i, config := range configs { zone := zones[i%len(zones)] config.pvSource, err = framework.CreatePVSource(zone) Expect(err).NotTo(HaveOccurred()) pvConfig := framework.PersistentVolumeConfig{ NamePrefix: "multizone-pv", PVSource:   *config.pvSource, Prebind:    nil, } className := "" pvcConfig := framework.PersistentVolumeClaimConfig{StorageClassName: &className} config.pv, config.pvc, err = framework.CreatePVPVC(c, pvConfig, pvcConfig, ns, true) Expect(err).NotTo(HaveOccurred()) } By("Waiting for all PVCs to be bound") for _, config := range configs { framework.WaitOnPVandPVC(c, ns, config.pv, config.pvc) } By("Creating pods for each static PV") for _, config := range configs { podConfig := framework.MakePod(ns, []*v1.PersistentVolumeClaim{config.pvc}, false, "") config.pod, err = c.Core().Pods(ns).Create(podConfig) Expect(err).NotTo(HaveOccurred()) } By("Waiting for all pods to be running") for _, config := range configs { err = framework.WaitForPodRunningInNamespace(c, config.pod) Expect(err).NotTo(HaveOccurred()) } } </ins>