mirror of https://github.com/k3s-io/k3s
Merge pull request #28116 from jsafrane/integration-startup
Automatic merge from submit-queue Add integration test for volume controller startup. Tests #28002 with real etcd (unit tests have a fake one with different behavior). @kubernetes/sig-storagepull/6/head
commit
10121b4c4b
|
@ -75,8 +75,8 @@ func getObjectCount() int {
|
||||||
return objectCount
|
return objectCount
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSyncPeriod() time.Duration {
|
func getSyncPeriod(syncPeriod time.Duration) time.Duration {
|
||||||
period := defaultSyncPeriod
|
period := syncPeriod
|
||||||
if s := os.Getenv("KUBE_INTEGRATION_PV_SYNC_PERIOD"); s != "" {
|
if s := os.Getenv("KUBE_INTEGRATION_PV_SYNC_PERIOD"); s != "" {
|
||||||
var err error
|
var err error
|
||||||
period, err = time.ParseDuration(s)
|
period, err = time.ParseDuration(s)
|
||||||
|
@ -112,7 +112,7 @@ func TestPersistentVolumeRecycler(t *testing.T) {
|
||||||
ns := framework.CreateTestingNamespace("pv-recycler", s, t)
|
ns := framework.CreateTestingNamespace("pv-recycler", s, t)
|
||||||
defer framework.DeleteTestingNamespace(ns, s, t)
|
defer framework.DeleteTestingNamespace(ns, s, t)
|
||||||
|
|
||||||
testClient, ctrl, watchPV, watchPVC := createClients(ns, t, s)
|
testClient, ctrl, watchPV, watchPVC := createClients(ns, t, s, defaultSyncPeriod)
|
||||||
defer watchPV.Stop()
|
defer watchPV.Stop()
|
||||||
defer watchPVC.Stop()
|
defer watchPVC.Stop()
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ func TestPersistentVolumeDeleter(t *testing.T) {
|
||||||
ns := framework.CreateTestingNamespace("pv-deleter", s, t)
|
ns := framework.CreateTestingNamespace("pv-deleter", s, t)
|
||||||
defer framework.DeleteTestingNamespace(ns, s, t)
|
defer framework.DeleteTestingNamespace(ns, s, t)
|
||||||
|
|
||||||
testClient, ctrl, watchPV, watchPVC := createClients(ns, t, s)
|
testClient, ctrl, watchPV, watchPVC := createClients(ns, t, s, defaultSyncPeriod)
|
||||||
defer watchPV.Stop()
|
defer watchPV.Stop()
|
||||||
defer watchPVC.Stop()
|
defer watchPVC.Stop()
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@ func TestPersistentVolumeBindRace(t *testing.T) {
|
||||||
ns := framework.CreateTestingNamespace("pv-bind-race", s, t)
|
ns := framework.CreateTestingNamespace("pv-bind-race", s, t)
|
||||||
defer framework.DeleteTestingNamespace(ns, s, t)
|
defer framework.DeleteTestingNamespace(ns, s, t)
|
||||||
|
|
||||||
testClient, ctrl, watchPV, watchPVC := createClients(ns, t, s)
|
testClient, ctrl, watchPV, watchPVC := createClients(ns, t, s, defaultSyncPeriod)
|
||||||
defer watchPV.Stop()
|
defer watchPV.Stop()
|
||||||
defer watchPVC.Stop()
|
defer watchPVC.Stop()
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ func TestPersistentVolumeClaimLabelSelector(t *testing.T) {
|
||||||
ns := framework.CreateTestingNamespace("pvc-label-selector", s, t)
|
ns := framework.CreateTestingNamespace("pvc-label-selector", s, t)
|
||||||
defer framework.DeleteTestingNamespace(ns, s, t)
|
defer framework.DeleteTestingNamespace(ns, s, t)
|
||||||
|
|
||||||
testClient, controller, watchPV, watchPVC := createClients(ns, t, s)
|
testClient, controller, watchPV, watchPVC := createClients(ns, t, s, defaultSyncPeriod)
|
||||||
defer watchPV.Stop()
|
defer watchPV.Stop()
|
||||||
defer watchPVC.Stop()
|
defer watchPVC.Stop()
|
||||||
|
|
||||||
|
@ -372,7 +372,7 @@ func TestPersistentVolumeClaimLabelSelectorMatchExpressions(t *testing.T) {
|
||||||
ns := framework.CreateTestingNamespace("pvc-match-expresssions", s, t)
|
ns := framework.CreateTestingNamespace("pvc-match-expresssions", s, t)
|
||||||
defer framework.DeleteTestingNamespace(ns, s, t)
|
defer framework.DeleteTestingNamespace(ns, s, t)
|
||||||
|
|
||||||
testClient, controller, watchPV, watchPVC := createClients(ns, t, s)
|
testClient, controller, watchPV, watchPVC := createClients(ns, t, s, defaultSyncPeriod)
|
||||||
defer watchPV.Stop()
|
defer watchPV.Stop()
|
||||||
defer watchPVC.Stop()
|
defer watchPVC.Stop()
|
||||||
|
|
||||||
|
@ -470,7 +470,7 @@ func TestPersistentVolumeMultiPVs(t *testing.T) {
|
||||||
ns := framework.CreateTestingNamespace("multi-pvs", s, t)
|
ns := framework.CreateTestingNamespace("multi-pvs", s, t)
|
||||||
defer framework.DeleteTestingNamespace(ns, s, t)
|
defer framework.DeleteTestingNamespace(ns, s, t)
|
||||||
|
|
||||||
testClient, controller, watchPV, watchPVC := createClients(ns, t, s)
|
testClient, controller, watchPV, watchPVC := createClients(ns, t, s, defaultSyncPeriod)
|
||||||
defer watchPV.Stop()
|
defer watchPV.Stop()
|
||||||
defer watchPVC.Stop()
|
defer watchPVC.Stop()
|
||||||
|
|
||||||
|
@ -558,7 +558,7 @@ func TestPersistentVolumeMultiPVsPVCs(t *testing.T) {
|
||||||
ns := framework.CreateTestingNamespace("multi-pvs-pvcs", s, t)
|
ns := framework.CreateTestingNamespace("multi-pvs-pvcs", s, t)
|
||||||
defer framework.DeleteTestingNamespace(ns, s, t)
|
defer framework.DeleteTestingNamespace(ns, s, t)
|
||||||
|
|
||||||
testClient, binder, watchPV, watchPVC := createClients(ns, t, s)
|
testClient, binder, watchPV, watchPVC := createClients(ns, t, s, defaultSyncPeriod)
|
||||||
defer watchPV.Stop()
|
defer watchPV.Stop()
|
||||||
defer watchPVC.Stop()
|
defer watchPVC.Stop()
|
||||||
|
|
||||||
|
@ -708,6 +708,133 @@ func TestPersistentVolumeMultiPVsPVCs(t *testing.T) {
|
||||||
testSleep()
|
testSleep()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestPersistentVolumeControllerStartup tests startup of the controller.
|
||||||
|
// The controller should not unbind any volumes when it starts.
|
||||||
|
func TestPersistentVolumeControllerStartup(t *testing.T) {
|
||||||
|
_, s := framework.RunAMaster(nil)
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
ns := framework.CreateTestingNamespace("controller-startup", s, t)
|
||||||
|
defer framework.DeleteTestingNamespace(ns, s, t)
|
||||||
|
|
||||||
|
objCount := getObjectCount()
|
||||||
|
|
||||||
|
const shortSyncPeriod = 2 * time.Second
|
||||||
|
syncPeriod := getSyncPeriod(shortSyncPeriod)
|
||||||
|
|
||||||
|
testClient, binder, watchPV, watchPVC := createClients(ns, t, s, shortSyncPeriod)
|
||||||
|
defer watchPV.Stop()
|
||||||
|
defer watchPVC.Stop()
|
||||||
|
|
||||||
|
// Create *bound* volumes and PVCs
|
||||||
|
pvs := make([]*api.PersistentVolume, objCount)
|
||||||
|
pvcs := make([]*api.PersistentVolumeClaim, objCount)
|
||||||
|
for i := 0; i < objCount; i++ {
|
||||||
|
pvName := "pv-startup-" + strconv.Itoa(i)
|
||||||
|
pvcName := "pvc-startup-" + strconv.Itoa(i)
|
||||||
|
|
||||||
|
pvc := createPVC(pvcName, ns.Name, "1G", []api.PersistentVolumeAccessMode{api.ReadWriteOnce})
|
||||||
|
pvc.Annotations = map[string]string{"annBindCompleted": ""}
|
||||||
|
pvc.Spec.VolumeName = pvName
|
||||||
|
newPVC, err := testClient.PersistentVolumeClaims(ns.Name).Create(pvc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Cannot create claim %q: %v", pvc.Name, err)
|
||||||
|
}
|
||||||
|
// Save Bound status as a separate transaction
|
||||||
|
newPVC.Status.Phase = api.ClaimBound
|
||||||
|
newPVC, err = testClient.PersistentVolumeClaims(ns.Name).UpdateStatus(newPVC)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Cannot update claim status %q: %v", pvc.Name, err)
|
||||||
|
}
|
||||||
|
pvcs[i] = newPVC
|
||||||
|
// Drain watchPVC with all events generated by the PVC until it's bound
|
||||||
|
// We don't want to catch "PVC craated with Status.Phase == Pending"
|
||||||
|
// later in this test.
|
||||||
|
waitForAnyPersistentVolumeClaimPhase(watchPVC, api.ClaimBound)
|
||||||
|
|
||||||
|
pv := createPV(pvName, "/tmp/foo"+strconv.Itoa(i), "1G",
|
||||||
|
[]api.PersistentVolumeAccessMode{api.ReadWriteOnce}, api.PersistentVolumeReclaimRetain)
|
||||||
|
claimRef, err := api.GetReference(newPVC)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(3).Infof("unexpected error getting claim reference: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pv.Spec.ClaimRef = claimRef
|
||||||
|
newPV, err := testClient.PersistentVolumes().Create(pv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Cannot create volume %q: %v", pv.Name, err)
|
||||||
|
}
|
||||||
|
// Save Bound status as a separate transaction
|
||||||
|
newPV.Status.Phase = api.VolumeBound
|
||||||
|
newPV, err = testClient.PersistentVolumes().UpdateStatus(newPV)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Cannot update volume status %q: %v", pv.Name, err)
|
||||||
|
}
|
||||||
|
pvs[i] = newPV
|
||||||
|
// Drain watchPV with all events generated by the PV until it's bound
|
||||||
|
// We don't want to catch "PV craated with Status.Phase == Pending"
|
||||||
|
// later in this test.
|
||||||
|
waitForAnyPersistentVolumePhase(watchPV, api.VolumeBound)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the controller when all PVs and PVCs are already saved in etcd
|
||||||
|
binder.Run()
|
||||||
|
defer binder.Stop()
|
||||||
|
|
||||||
|
// wait for at least two sync periods for changes. No volume should be
|
||||||
|
// Released and no claim should be Lost during this time.
|
||||||
|
timer := time.NewTimer(2 * syncPeriod)
|
||||||
|
defer timer.Stop()
|
||||||
|
finished := false
|
||||||
|
for !finished {
|
||||||
|
select {
|
||||||
|
case volumeEvent := <-watchPV.ResultChan():
|
||||||
|
volume, ok := volumeEvent.Object.(*api.PersistentVolume)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if volume.Status.Phase != api.VolumeBound {
|
||||||
|
t.Errorf("volume %s unexpectedly changed state to %s", volume.Name, volume.Status.Phase)
|
||||||
|
}
|
||||||
|
|
||||||
|
case claimEvent := <-watchPVC.ResultChan():
|
||||||
|
claim, ok := claimEvent.Object.(*api.PersistentVolumeClaim)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if claim.Status.Phase != api.ClaimBound {
|
||||||
|
t.Errorf("claim %s unexpectedly changed state to %s", claim.Name, claim.Status.Phase)
|
||||||
|
}
|
||||||
|
|
||||||
|
case <-timer.C:
|
||||||
|
// Wait finished
|
||||||
|
glog.V(2).Infof("Wait finished")
|
||||||
|
finished = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that everything is bound to something
|
||||||
|
for i := 0; i < objCount; 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 {
|
||||||
|
t.Fatalf("PV %q is not bound", pv.Name)
|
||||||
|
}
|
||||||
|
glog.V(2).Infof("PV %q is bound to PVC %q", pv.Name, pv.Spec.ClaimRef.Name)
|
||||||
|
|
||||||
|
pvc, err := testClient.PersistentVolumeClaims(ns.Name).Get(pvcs[i].Name)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error getting pvc: %v", err)
|
||||||
|
}
|
||||||
|
if pvc.Spec.VolumeName == "" {
|
||||||
|
t.Fatalf("PVC %q is not bound", pvc.Name)
|
||||||
|
}
|
||||||
|
glog.V(2).Infof("PVC %q is bound to PV %q", pvc.Name, pvc.Spec.VolumeName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestPersistentVolumeProvisionMultiPVCs tests provisioning of many PVCs.
|
// TestPersistentVolumeProvisionMultiPVCs tests provisioning of many PVCs.
|
||||||
// This test is configurable by KUBE_INTEGRATION_PV_* variables.
|
// This test is configurable by KUBE_INTEGRATION_PV_* variables.
|
||||||
func TestPersistentVolumeProvisionMultiPVCs(t *testing.T) {
|
func TestPersistentVolumeProvisionMultiPVCs(t *testing.T) {
|
||||||
|
@ -717,7 +844,7 @@ func TestPersistentVolumeProvisionMultiPVCs(t *testing.T) {
|
||||||
ns := framework.CreateTestingNamespace("provision-multi-pvs", s, t)
|
ns := framework.CreateTestingNamespace("provision-multi-pvs", s, t)
|
||||||
defer framework.DeleteTestingNamespace(ns, s, t)
|
defer framework.DeleteTestingNamespace(ns, s, t)
|
||||||
|
|
||||||
testClient, binder, watchPV, watchPVC := createClients(ns, t, s)
|
testClient, binder, watchPV, watchPVC := createClients(ns, t, s, defaultSyncPeriod)
|
||||||
defer watchPV.Stop()
|
defer watchPV.Stop()
|
||||||
defer watchPVC.Stop()
|
defer watchPVC.Stop()
|
||||||
|
|
||||||
|
@ -801,7 +928,7 @@ func TestPersistentVolumeMultiPVsDiffAccessModes(t *testing.T) {
|
||||||
ns := framework.CreateTestingNamespace("multi-pvs-diff-access", s, t)
|
ns := framework.CreateTestingNamespace("multi-pvs-diff-access", s, t)
|
||||||
defer framework.DeleteTestingNamespace(ns, s, t)
|
defer framework.DeleteTestingNamespace(ns, s, t)
|
||||||
|
|
||||||
testClient, controller, watchPV, watchPVC := createClients(ns, t, s)
|
testClient, controller, watchPV, watchPVC := createClients(ns, t, s, defaultSyncPeriod)
|
||||||
defer watchPV.Stop()
|
defer watchPV.Stop()
|
||||||
defer watchPVC.Stop()
|
defer watchPVC.Stop()
|
||||||
|
|
||||||
|
@ -941,7 +1068,7 @@ func waitForAnyPersistentVolumeClaimPhase(w watch.Interface, phase api.Persisten
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createClients(ns *api.Namespace, t *testing.T, s *httptest.Server) (*clientset.Clientset, *persistentvolumecontroller.PersistentVolumeController, watch.Interface, watch.Interface) {
|
func createClients(ns *api.Namespace, t *testing.T, s *httptest.Server, syncPeriod time.Duration) (*clientset.Clientset, *persistentvolumecontroller.PersistentVolumeController, watch.Interface, watch.Interface) {
|
||||||
// Use higher QPS and Burst, there is a test for race conditions which
|
// Use higher QPS and Burst, there is a test for race conditions which
|
||||||
// creates many objects and default values were too low.
|
// creates many objects and default values were too low.
|
||||||
binderClient := clientset.NewForConfigOrDie(&restclient.Config{
|
binderClient := clientset.NewForConfigOrDie(&restclient.Config{
|
||||||
|
@ -973,7 +1100,7 @@ func createClients(ns *api.Namespace, t *testing.T, s *httptest.Server) (*client
|
||||||
plugins := []volume.VolumePlugin{plugin}
|
plugins := []volume.VolumePlugin{plugin}
|
||||||
cloud := &fake_cloud.FakeCloud{}
|
cloud := &fake_cloud.FakeCloud{}
|
||||||
|
|
||||||
syncPeriod := getSyncPeriod()
|
syncPeriod = getSyncPeriod(syncPeriod)
|
||||||
ctrl := persistentvolumecontroller.NewPersistentVolumeController(binderClient, syncPeriod, plugin, plugins, cloud, "", nil, nil, nil, true)
|
ctrl := persistentvolumecontroller.NewPersistentVolumeController(binderClient, syncPeriod, plugin, plugins, cloud, "", nil, nil, nil, true)
|
||||||
|
|
||||||
watchPV, err := testClient.PersistentVolumes().Watch(api.ListOptions{})
|
watchPV, err := testClient.PersistentVolumes().Watch(api.ListOptions{})
|
||||||
|
|
Loading…
Reference in New Issue