Skip to content

Commit 1655d53

Browse files
committed
Add a new "chaosduck" e2e test tool for leaderelection.
This adds a new main package under knative.dev/pkg/leaderelection/chaosduck, which loads the leader election configuration, and periodically enumerates the leases in the system namespace and kills a leader pod for each sharded reconciler under a component.
1 parent a6fde80 commit 1655d53

File tree

1 file changed

+131
-0
lines changed

1 file changed

+131
-0
lines changed

leaderelection/chaosduck/main.go

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
Copyright 2020 The Knative Authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// The chaosduck binary is an e2e testing tool for leader election, which loads
18+
// the leader election configuration within the system namespace and
19+
// periodically kills one of the leader pods for each HA component.
20+
package main
21+
22+
import (
23+
"context"
24+
"log"
25+
"strings"
26+
"time"
27+
28+
"golang.org/x/sync/errgroup"
29+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30+
"k8s.io/apimachinery/pkg/util/sets"
31+
kubeclient "knative.dev/pkg/client/injection/kube/client"
32+
"knative.dev/pkg/controller"
33+
"knative.dev/pkg/injection"
34+
"knative.dev/pkg/injection/sharedmain"
35+
"knative.dev/pkg/signals"
36+
"knative.dev/pkg/system"
37+
)
38+
39+
// quack will periodically kill a leader shard of a component reconciler's leader set.
40+
func quack(ctx context.Context, component string) error {
41+
log.Printf("Quacking at %q", component)
42+
43+
kc := kubeclient.Get(ctx)
44+
for {
45+
select {
46+
case <-time.After(30 * time.Second):
47+
leases, err := kc.CoordinationV1().Leases(system.Namespace()).List(metav1.ListOptions{})
48+
if err != nil {
49+
return err
50+
}
51+
52+
shards := make(map[string]sets.String, 1)
53+
for _, lease := range leases.Items {
54+
if lease.Spec.HolderIdentity == nil {
55+
log.Printf("Found lease %q held by nobody!", lease.Name)
56+
continue
57+
}
58+
pod := strings.Split(*lease.Spec.HolderIdentity, "_")[0]
59+
60+
var reconciler string
61+
if lease.Name == component {
62+
// for back-compat
63+
reconciler = "all"
64+
} else if parts := strings.Split(lease.Name, "."); len(parts) < 3 || parts[0] != component {
65+
continue
66+
} else {
67+
// Shave off the prefix and the sharding
68+
reconciler = strings.Join(parts[1:len(parts)-1], ".")
69+
}
70+
71+
set := shards[reconciler]
72+
if set == nil {
73+
set = sets.NewString()
74+
}
75+
set.Insert(pod)
76+
shards[reconciler] = set
77+
}
78+
79+
killem := sets.NewString()
80+
81+
for _, v := range shards {
82+
if v.HasAny(killem.UnsortedList()...) {
83+
// This is covered by killem
84+
continue
85+
}
86+
87+
tribute, _ := v.PopAny()
88+
killem.Insert(tribute)
89+
}
90+
91+
for _, name := range killem.List() {
92+
err := kc.CoreV1().Pods(system.Namespace()).Delete(name, &metav1.DeleteOptions{})
93+
if err != nil {
94+
return err
95+
}
96+
}
97+
98+
case <-ctx.Done():
99+
return nil
100+
}
101+
}
102+
}
103+
104+
func main() {
105+
ctx := signals.NewContext()
106+
107+
ctx, informers := injection.Default.SetupInformers(ctx, sharedmain.ParseAndGetConfigOrDie())
108+
if err := controller.StartInformers(ctx.Done(), informers...); err != nil {
109+
log.Fatalf("Failed to start informers %v", err)
110+
}
111+
112+
lec, err := sharedmain.GetLeaderElectionConfig(ctx)
113+
if err != nil {
114+
log.Fatalf("Unable to load leader election configuration: %v", err)
115+
}
116+
if lec.ResourceLock != "leases" {
117+
log.Fatalf("chaosduck only supports leases, but got %q", lec.ResourceLock)
118+
}
119+
120+
eg, ctx := errgroup.WithContext(ctx)
121+
for _, x := range lec.EnabledComponents.List() {
122+
x := x
123+
eg.Go(func() error {
124+
return quack(ctx, x)
125+
})
126+
}
127+
128+
if err := eg.Wait(); err != nil {
129+
log.Fatalf("Ended with err: %v", err)
130+
}
131+
}

0 commit comments

Comments
 (0)