Skip to content

Commit 8e012b6

Browse files
authored
Merge pull request #117 from arangodb/resilient-pv-destroyed-test
Added test that removes PV, PVC & Pod or dbserver. [ci VERBOSE=1] [ci LONG=1] [ci TESTOPTIONS="-test.run ^TestResiliencePVDBServer$"]
2 parents e71f9e9 + c3b99e6 commit 8e012b6

File tree

2 files changed

+111
-3
lines changed

2 files changed

+111
-3
lines changed

manifests/templates/test/rbac.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ rules:
99
- apiGroups: [""]
1010
resources: ["nodes"]
1111
verbs: ["list"]
12+
- apiGroups: [""]
13+
resources: ["pods", "services", "persistentvolumes", "persistentvolumeclaims", "secrets"]
14+
verbs: ["*"]
1215
- apiGroups: ["apps"]
1316
resources: ["daemonsets"]
1417
verbs: ["*"]

tests/resilience_test.go

Lines changed: 108 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"testing"
77
"time"
88

9+
"github.com/stretchr/testify/require"
10+
911
"github.com/dchest/uniuri"
1012
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1113

@@ -26,7 +28,7 @@ func TestResiliencePod(t *testing.T) {
2628
//fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))
2729

2830
// Prepare deployment config
29-
depl := newDeployment("test-pod-resilience" + uniuri.NewLen(4))
31+
depl := newDeployment("test-pod-resilience-" + uniuri.NewLen(4))
3032
depl.Spec.Mode = api.NewMode(api.DeploymentModeCluster)
3133
depl.Spec.SetDefaults(depl.GetName()) // this must be last
3234

@@ -106,7 +108,7 @@ func TestResiliencePVC(t *testing.T) {
106108
ns := getNamespace(t)
107109

108110
// Prepare deployment config
109-
depl := newDeployment("test-pvc-resilience" + uniuri.NewLen(4))
111+
depl := newDeployment("test-pvc-resilience-" + uniuri.NewLen(4))
110112
depl.Spec.Mode = api.NewMode(api.DeploymentModeCluster)
111113
depl.Spec.SetDefaults(depl.GetName()) // this must be last
112114

@@ -181,6 +183,109 @@ func TestResiliencePVC(t *testing.T) {
181183
removeDeployment(c, depl.GetName(), ns)
182184
}
183185

186+
// TestResiliencePVDBServer
187+
// Tests handling of entire PVs of dbservers being removed.
188+
func TestResiliencePVDBServer(t *testing.T) {
189+
longOrSkip(t)
190+
c := client.MustNewInCluster()
191+
kubecli := mustNewKubeClient(t)
192+
ns := getNamespace(t)
193+
194+
// Prepare deployment config
195+
depl := newDeployment("test-pv-prmr-resi-" + uniuri.NewLen(4))
196+
depl.Spec.Mode = api.NewMode(api.DeploymentModeCluster)
197+
depl.Spec.SetDefaults(depl.GetName()) // this must be last
198+
199+
// Create deployment
200+
apiObject, err := c.DatabaseV1alpha().ArangoDeployments(ns).Create(depl)
201+
if err != nil {
202+
t.Fatalf("Create deployment failed: %v", err)
203+
}
204+
205+
// Wait for deployment to be ready
206+
if _, err = waitUntilDeployment(c, depl.GetName(), ns, deploymentIsReady()); err != nil {
207+
t.Fatalf("Deployment not running in time: %v", err)
208+
}
209+
210+
// Create a database client
211+
ctx := context.Background()
212+
client := mustNewArangodDatabaseClient(ctx, kubecli, apiObject, t)
213+
214+
// Wait for cluster to be completely ready
215+
if err := waitUntilClusterHealth(client, func(h driver.ClusterHealth) error {
216+
return clusterHealthEqualsSpec(h, apiObject.Spec)
217+
}); err != nil {
218+
t.Fatalf("Cluster not running in expected health in time: %v", err)
219+
}
220+
221+
// Fetch latest status so we know all member details
222+
apiObject, err = c.DatabaseV1alpha().ArangoDeployments(ns).Get(depl.GetName(), metav1.GetOptions{})
223+
if err != nil {
224+
t.Fatalf("Failed to get deployment: %v", err)
225+
}
226+
227+
// Delete one pv, pvc & pod after the other
228+
apiObject.ForeachServerGroup(func(group api.ServerGroup, spec api.ServerGroupSpec, status *api.MemberStatusList) error {
229+
if group != api.ServerGroupDBServers {
230+
// Agents cannot be replaced with a new ID
231+
// Coordinators, Sync masters/workers have no persistent storage
232+
return nil
233+
}
234+
for i, m := range *status {
235+
// Only test first 2
236+
if i >= 2 {
237+
continue
238+
}
239+
// Get current pvc so we can compare UID later
240+
originalPVC, err := kubecli.CoreV1().PersistentVolumeClaims(ns).Get(m.PersistentVolumeClaimName, metav1.GetOptions{})
241+
if err != nil {
242+
t.Fatalf("Failed to get pvc %s: %v", m.PersistentVolumeClaimName, err)
243+
}
244+
// Get current pv
245+
pvName := originalPVC.Spec.VolumeName
246+
require.NotEmpty(t, pvName, "VolumeName of %s must be non-empty", originalPVC.GetName())
247+
// Delete PV
248+
if err := kubecli.CoreV1().PersistentVolumes().Delete(pvName, &metav1.DeleteOptions{}); err != nil {
249+
t.Fatalf("Failed to delete pv %s: %v", pvName, err)
250+
}
251+
// Delete PVC
252+
if err := kubecli.CoreV1().PersistentVolumeClaims(ns).Delete(m.PersistentVolumeClaimName, &metav1.DeleteOptions{}); err != nil {
253+
t.Fatalf("Failed to delete pvc %s: %v", m.PersistentVolumeClaimName, err)
254+
}
255+
// Delete Pod
256+
if err := kubecli.CoreV1().Pods(ns).Delete(m.PodName, &metav1.DeleteOptions{}); err != nil {
257+
t.Fatalf("Failed to delete pod %s: %v", m.PodName, err)
258+
}
259+
// Wait for cluster to be healthy again with the same number of
260+
// dbservers, but the current dbserver being replaced.
261+
expectedDBServerCount := apiObject.Spec.DBServers.GetCount()
262+
unexpectedID := m.ID
263+
pred := func(depl *api.ArangoDeployment) error {
264+
if len(depl.Status.Members.DBServers) != expectedDBServerCount {
265+
return maskAny(fmt.Errorf("Expected %d dbservers, got %d", expectedDBServerCount, len(depl.Status.Members.DBServers)))
266+
}
267+
if depl.Status.Members.ContainsID(unexpectedID) {
268+
return maskAny(fmt.Errorf("Member %s should be gone", unexpectedID))
269+
}
270+
return nil
271+
}
272+
if _, err := waitUntilDeployment(c, apiObject.GetName(), ns, pred, time.Minute*5); err != nil {
273+
t.Fatalf("Deployment not ready in time: %v", err)
274+
}
275+
// Wait for cluster to be completely ready
276+
if err := waitUntilClusterHealth(client, func(h driver.ClusterHealth) error {
277+
return clusterHealthEqualsSpec(h, apiObject.Spec)
278+
}); err != nil {
279+
t.Fatalf("Cluster not running in expected health in time: %v", err)
280+
}
281+
}
282+
return nil
283+
}, &apiObject.Status)
284+
285+
// Cleanup
286+
removeDeployment(c, depl.GetName(), ns)
287+
}
288+
184289
// TestResilienceService
185290
// Tests handling of individual service deletions
186291
func TestResilienceService(t *testing.T) {
@@ -190,7 +295,7 @@ func TestResilienceService(t *testing.T) {
190295
ns := getNamespace(t)
191296

192297
// Prepare deployment config
193-
depl := newDeployment("test-service-resilience" + uniuri.NewLen(4))
298+
depl := newDeployment("test-service-resilience-" + uniuri.NewLen(4))
194299
depl.Spec.Mode = api.NewMode(api.DeploymentModeCluster)
195300
depl.Spec.SetDefaults(depl.GetName()) // this must be last
196301

0 commit comments

Comments
 (0)