mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Merge pull request #25216 from rootfs/pv-integration-test
Automatic merge from submit-queue Add PV test to persistent volume integration test This is a follow-up to #25120 @kubernetes/sig-storage
This commit is contained in:
commit
e484f142d6
@ -21,6 +21,8 @@ package integration
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -47,36 +49,15 @@ func TestPersistentVolumeRecycler(t *testing.T) {
|
||||
defer s.Close()
|
||||
|
||||
deleteAllEtcdKeys()
|
||||
// Use higher QPS and Burst, there is a test for race condition below, which
|
||||
// creates many claims and default values were too low.
|
||||
testClient := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}, QPS: 1000, Burst: 100000})
|
||||
host := volumetest.NewFakeVolumeHost("/tmp/fake", nil, nil)
|
||||
testClient, ctrl := createClients(s)
|
||||
|
||||
plugins := []volume.VolumePlugin{&volumetest.FakeVolumePlugin{"plugin-name", host, volume.VolumeConfig{}, volume.VolumeOptions{}, 0, 0, nil, nil, nil, nil}}
|
||||
cloud := &fake_cloud.FakeCloud{}
|
||||
|
||||
ctrl := persistentvolumecontroller.NewPersistentVolumeController(testClient, 10*time.Second, nil, plugins, cloud, "", nil, nil, nil)
|
||||
ctrl.Run()
|
||||
defer ctrl.Stop()
|
||||
|
||||
// This PV will be claimed, released, and recycled.
|
||||
pv := &api.PersistentVolume{
|
||||
ObjectMeta: api.ObjectMeta{Name: "fake-pv"},
|
||||
Spec: api.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: api.PersistentVolumeSource{HostPath: &api.HostPathVolumeSource{Path: "/tmp/foo"}},
|
||||
Capacity: api.ResourceList{api.ResourceName(api.ResourceStorage): resource.MustParse("10G")},
|
||||
AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
|
||||
PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimRecycle,
|
||||
},
|
||||
}
|
||||
pv := createPV("fake-pv", "/tmp/foo", "10G", []api.PersistentVolumeAccessMode{api.ReadWriteOnce}, api.PersistentVolumeReclaimRecycle)
|
||||
|
||||
pvc := &api.PersistentVolumeClaim{
|
||||
ObjectMeta: api.ObjectMeta{Name: "fake-pvc"},
|
||||
Spec: api.PersistentVolumeClaimSpec{
|
||||
Resources: api.ResourceRequirements{Requests: api.ResourceList{api.ResourceName(api.ResourceStorage): resource.MustParse("5G")}},
|
||||
AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
|
||||
},
|
||||
}
|
||||
pvc := createPVC("fake-pvc", "5G", []api.PersistentVolumeAccessMode{api.ReadWriteOnce})
|
||||
|
||||
w, _ := testClient.PersistentVolumes().Watch(api.ListOptions{})
|
||||
defer w.Stop()
|
||||
@ -84,7 +65,7 @@ func TestPersistentVolumeRecycler(t *testing.T) {
|
||||
_, _ = testClient.PersistentVolumes().Create(pv)
|
||||
_, _ = testClient.PersistentVolumeClaims(api.NamespaceDefault).Create(pvc)
|
||||
|
||||
// wait until the binder pairs the volume and claim
|
||||
// wait until the controller pairs the volume and claim
|
||||
waitForPersistentVolumePhase(w, api.VolumeBound)
|
||||
|
||||
// deleting a claim releases the volume, after which it can be recycled
|
||||
@ -171,6 +152,130 @@ func TestPersistentVolumeRecycler(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPersistentVolumeMultiPVs(t *testing.T) {
|
||||
_, s := framework.RunAMaster(t)
|
||||
defer s.Close()
|
||||
|
||||
deleteAllEtcdKeys()
|
||||
testClient, controller := createClients(s)
|
||||
controller.Run()
|
||||
defer controller.Stop()
|
||||
|
||||
maxPVs := 100
|
||||
pvs := make([]*api.PersistentVolume, maxPVs)
|
||||
for i := 0; i < maxPVs; i++ {
|
||||
// This PV will be claimed, released, and deleted
|
||||
pvs[i] = createPV("pv-"+strconv.Itoa(i), "/tmp/foo"+strconv.Itoa(i), strconv.Itoa(i)+"G",
|
||||
[]api.PersistentVolumeAccessMode{api.ReadWriteOnce}, api.PersistentVolumeReclaimDelete)
|
||||
}
|
||||
|
||||
pvc := createPVC("pvc-2", strconv.Itoa(maxPVs/2)+"G", []api.PersistentVolumeAccessMode{api.ReadWriteOnce})
|
||||
|
||||
w, _ := testClient.PersistentVolumes().Watch(api.ListOptions{})
|
||||
defer w.Stop()
|
||||
|
||||
for i := 0; i < maxPVs; i++ {
|
||||
_, _ = testClient.PersistentVolumes().Create(pvs[i])
|
||||
}
|
||||
|
||||
_, _ = testClient.PersistentVolumeClaims(api.NamespaceDefault).Create(pvc)
|
||||
|
||||
// wait until the controller pairs the volume and claim
|
||||
waitForPersistentVolumePhase(w, api.VolumeBound)
|
||||
|
||||
// only one PV is bound
|
||||
bound := 0
|
||||
for i := 0; i < maxPVs; i++ {
|
||||
pv, err := testClient.PersistentVolumes().Get(pvs[i].Name)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error getting pv: %v", err)
|
||||
}
|
||||
if pv.Spec.ClaimRef == nil {
|
||||
continue
|
||||
}
|
||||
// found a bounded PV
|
||||
p := pv.Spec.Capacity[api.ResourceStorage]
|
||||
pvCap := p.Value()
|
||||
expectedCap := resource.MustParse(strconv.Itoa(maxPVs/2) + "G")
|
||||
expectedCapVal := expectedCap.Value()
|
||||
if pv.Spec.ClaimRef.Name != pvc.Name || pvCap != expectedCapVal {
|
||||
t.Fatalf("Bind mismatch! Expected %s capacity %d but got %s capacity %d", pvc.Name, expectedCapVal, pv.Spec.ClaimRef.Name, pvCap)
|
||||
}
|
||||
t.Logf("claim bounded to %s capacity %v", pv.Name, pv.Spec.Capacity[api.ResourceStorage])
|
||||
bound += 1
|
||||
}
|
||||
|
||||
if bound != 1 {
|
||||
t.Fatalf("Only 1 PV should be bound but got %d", bound)
|
||||
}
|
||||
|
||||
// deleting a claim releases the volume
|
||||
if err := testClient.PersistentVolumeClaims(api.NamespaceDefault).Delete(pvc.Name, nil); err != nil {
|
||||
t.Errorf("error deleting claim %s", pvc.Name)
|
||||
}
|
||||
|
||||
waitForPersistentVolumePhase(w, api.VolumeReleased)
|
||||
|
||||
deleteAllEtcdKeys()
|
||||
}
|
||||
|
||||
func TestPersistentVolumeMultiPVsDiffAccessModes(t *testing.T) {
|
||||
_, s := framework.RunAMaster(t)
|
||||
defer s.Close()
|
||||
|
||||
deleteAllEtcdKeys()
|
||||
testClient, controller := createClients(s)
|
||||
controller.Run()
|
||||
defer controller.Stop()
|
||||
|
||||
// This PV will be claimed, released, and deleted
|
||||
pv_rwo := createPV("pv-rwo", "/tmp/foo", "10G",
|
||||
[]api.PersistentVolumeAccessMode{api.ReadWriteOnce}, api.PersistentVolumeReclaimDelete)
|
||||
pv_rwm := createPV("pv-rwm", "/tmp/bar", "10G",
|
||||
[]api.PersistentVolumeAccessMode{api.ReadWriteMany}, api.PersistentVolumeReclaimDelete)
|
||||
|
||||
pvc := createPVC("pvc-rwm", "5G", []api.PersistentVolumeAccessMode{api.ReadWriteMany})
|
||||
|
||||
w, _ := testClient.PersistentVolumes().Watch(api.ListOptions{})
|
||||
defer w.Stop()
|
||||
|
||||
_, _ = testClient.PersistentVolumes().Create(pv_rwm)
|
||||
_, _ = testClient.PersistentVolumes().Create(pv_rwo)
|
||||
|
||||
_, _ = testClient.PersistentVolumeClaims(api.NamespaceDefault).Create(pvc)
|
||||
|
||||
// wait until the controller pairs the volume and claim
|
||||
waitForPersistentVolumePhase(w, api.VolumeBound)
|
||||
|
||||
// only RWM PV is bound
|
||||
pv, err := testClient.PersistentVolumes().Get("pv-rwo")
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error getting pv: %v", err)
|
||||
}
|
||||
if pv.Spec.ClaimRef != nil {
|
||||
t.Fatalf("ReadWriteOnce PV shouldn't be bound")
|
||||
}
|
||||
pv, err = testClient.PersistentVolumes().Get("pv-rwm")
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error getting pv: %v", err)
|
||||
}
|
||||
if pv.Spec.ClaimRef == nil {
|
||||
t.Fatalf("ReadWriteMany PV should be bound")
|
||||
}
|
||||
if pv.Spec.ClaimRef.Name != pvc.Name {
|
||||
t.Fatalf("Bind mismatch! Expected %s but got %s", pvc.Name, pv.Spec.ClaimRef.Name)
|
||||
}
|
||||
|
||||
// deleting a claim releases the volume
|
||||
if err := testClient.PersistentVolumeClaims(api.NamespaceDefault).Delete(pvc.Name, nil); err != nil {
|
||||
t.Errorf("error deleting claim %s", pvc.Name)
|
||||
}
|
||||
|
||||
waitForPersistentVolumePhase(w, api.VolumeReleased)
|
||||
|
||||
deleteAllEtcdKeys()
|
||||
}
|
||||
|
||||
func waitForPersistentVolumePhase(w watch.Interface, phase api.PersistentVolumePhase) {
|
||||
for {
|
||||
event := <-w.ResultChan()
|
||||
@ -180,3 +285,36 @@ func waitForPersistentVolumePhase(w watch.Interface, phase api.PersistentVolumeP
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createClients(s *httptest.Server) (*clientset.Clientset, *persistentvolumecontroller.PersistentVolumeController) {
|
||||
// Use higher QPS and Burst, there is a test for race condition below, which
|
||||
// creates many claims and default values were too low.
|
||||
testClient := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}, QPS: 1000, Burst: 100000})
|
||||
host := volumetest.NewFakeVolumeHost("/tmp/fake", nil, nil)
|
||||
plugins := []volume.VolumePlugin{&volumetest.FakeVolumePlugin{"plugin-name", host, volume.VolumeConfig{}, volume.VolumeOptions{}, 0, 0, nil, nil, nil, nil}}
|
||||
cloud := &fake_cloud.FakeCloud{}
|
||||
ctrl := persistentvolumecontroller.NewPersistentVolumeController(testClient, 10*time.Second, nil, plugins, cloud, "", nil, nil, nil)
|
||||
return testClient, ctrl
|
||||
}
|
||||
|
||||
func createPV(name, path, cap string, mode []api.PersistentVolumeAccessMode, reclaim api.PersistentVolumeReclaimPolicy) *api.PersistentVolume {
|
||||
return &api.PersistentVolume{
|
||||
ObjectMeta: api.ObjectMeta{Name: name},
|
||||
Spec: api.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: api.PersistentVolumeSource{HostPath: &api.HostPathVolumeSource{Path: path}},
|
||||
Capacity: api.ResourceList{api.ResourceName(api.ResourceStorage): resource.MustParse(cap)},
|
||||
AccessModes: mode,
|
||||
PersistentVolumeReclaimPolicy: reclaim,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createPVC(name, cap string, mode []api.PersistentVolumeAccessMode) *api.PersistentVolumeClaim {
|
||||
return &api.PersistentVolumeClaim{
|
||||
ObjectMeta: api.ObjectMeta{Name: name},
|
||||
Spec: api.PersistentVolumeClaimSpec{
|
||||
Resources: api.ResourceRequirements{Requests: api.ResourceList{api.ResourceName(api.ResourceStorage): resource.MustParse(cap)}},
|
||||
AccessModes: mode,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user