3
3
package tests
4
4
5
5
import (
6
+ "errors"
6
7
"fmt"
7
8
"time"
8
9
9
10
"github.com/onsi/ginkgo/v2"
10
11
"github.com/openshift-kni/k8sreporter"
11
12
"go.universe.tf/e2etest/pkg/frr/container"
13
+ frrcontainer "go.universe.tf/e2etest/pkg/frr/container"
14
+
15
+ "go.universe.tf/e2etest/pkg/executor"
16
+ "go.universe.tf/e2etest/pkg/frr"
12
17
13
18
frrk8sv1beta1 "github.com/metallb/frr-k8s/api/v1beta1"
14
19
"github.com/metallb/frrk8stests/pkg/config"
@@ -28,10 +33,11 @@ import (
28
33
29
34
var _ = ginkgo .Describe ("Establish BGP session with EnableGracefulRestart" , func () {
30
35
var (
31
- cs clientset.Interface
32
- updater * config.Updater
33
- reporter * k8sreporter.KubernetesReporter
34
- nodes []corev1.Node
36
+ cs clientset.Interface
37
+ updater * config.Updater
38
+ reporter * k8sreporter.KubernetesReporter
39
+ nodes []corev1.Node
40
+ prefixesV4 = scaleUP (200 )
35
41
)
36
42
37
43
cleanup := func (u * config.Updater ) error {
@@ -63,17 +69,23 @@ var _ = ginkgo.Describe("Establish BGP session with EnableGracefulRestart", func
63
69
})
64
70
65
71
ginkgo .AfterEach (func () {
72
+
73
+ seed := ginkgo .GinkgoRandomSeed ()
74
+ testName := fmt .Sprintf ("%s-%d" , ginkgo .CurrentSpecReport ().LeafNodeText , seed )
66
75
if ginkgo .CurrentSpecReport ().Failed () {
67
- testName := ginkgo .CurrentSpecReport ().LeafNodeText
68
- dump .K8sInfo (testName , reporter )
69
- dump .BGPInfo (testName , infra .FRRContainers , cs )
76
+ testName += "-failed"
70
77
}
78
+ ginkgo .By (testName )
79
+ dump .K8sInfo (testName , reporter )
80
+ dump .BGPInfo (testName , infra .FRRContainers , cs )
71
81
})
72
82
73
83
ginkgo .Context ("When restarting the frrk8s deamon pods" , func () {
74
84
75
- ginkgo .DescribeTable ("external BGP peer maintains routes" , func (ipFam ipfamily.Family , prefix string ) {
85
+ ginkgo .DescribeTable ("external BGP peer maintains routes" , func (ipFam ipfamily.Family , prefix [] string ) {
76
86
frrs := config .ContainersForVRF (infra .FRRContainers , "" )
87
+ // cnt, err := config.ContainerByName(infra.FRRContainers, "ebgp-multi-hop")
88
+ // frrs := []*frrcontainer.FRR{cnt}
77
89
for _ , c := range frrs {
78
90
err := container .PairWithNodes (cs , c , ipFam )
79
91
Expect (err ).NotTo (HaveOccurred (), "set frr config in infra containers failed" )
@@ -88,48 +100,145 @@ var _ = ginkgo.Describe("Establish BGP session with EnableGracefulRestart", func
88
100
Namespace : k8s .FRRK8sNamespace ,
89
101
},
90
102
Spec : frrk8sv1beta1.FRRConfigurationSpec {
103
+ // NodeSelector: metav1.LabelSelector{
104
+ // MatchLabels: map[string]string{
105
+ // "kubernetes.io/hostname": nodes[0].GetLabels()["kubernetes.io/hostname"],
106
+ // },
107
+ // },
91
108
BGP : frrk8sv1beta1.BGPConfig {
92
109
Routers : []frrk8sv1beta1.Router {
93
110
{
94
111
ASN : infra .FRRK8sASN ,
95
112
Neighbors : config .NeighborsFromPeers (peersConfig .PeersV4 , peersConfig .PeersV6 ),
96
- Prefixes : [] string { prefix } ,
113
+ Prefixes : prefix ,
97
114
},
98
115
},
99
116
},
100
117
},
101
118
}
119
+ ginkgo .By ("Before GR test" )
102
120
103
121
err := updater .Update (peersConfig .Secrets , frrConfigCR )
104
122
Expect (err ).NotTo (HaveOccurred (), "apply the CR in k8s api failed" )
105
-
106
- check := func () error {
123
+ Eventually (func () error {
107
124
for _ , p := range peersConfig .Peers () {
108
- err := routes .CheckNeighborHasPrefix (p .FRR , p .FRR .RouterConfig .VRF , prefix , nodes )
125
+ ValidateFRRPeeredWithNodes (nodes , & p .FRR , ipFam )
126
+ neighbors , err := frr .NeighborsInfo (p .FRR )
127
+ Expect (err ).NotTo (HaveOccurred ())
128
+ for _ , n := range neighbors {
129
+ Expect (n .GRInfo .RemoteGrMode ).Should (Equal ("Restart" ))
130
+ }
131
+
132
+ err = routes .CheckNeighborHasPrefix (p .FRR , p .FRR .RouterConfig .VRF , prefix [0 ], nodes )
109
133
if err != nil {
110
- return fmt .Errorf ("Neigh %s does not have prefix %s : %w" , p .FRR .Name , prefix , err )
134
+ return fmt .Errorf ("Neigh %s does not have prefixes : %w" , p .FRR .Name , err )
111
135
}
112
136
}
113
137
return nil
114
- }
115
-
116
- Eventually (check , time .Minute , time .Second ).ShouldNot (HaveOccurred (),
117
- "route should exist before we restart frr-k8s" )
138
+ }, time .Minute , time .Second ).ShouldNot (HaveOccurred (), "route should exist before we restart frr-k8s" )
118
139
140
+ ginkgo .By ("Start GR test" )
119
141
c := make (chan struct {})
120
142
go func () { // go restart frr-k8s while Consistently check that route exists
121
143
defer ginkgo .GinkgoRecover ()
122
144
err := k8s .RestartFRRK8sPods (cs )
123
145
Expect (err ).NotTo (HaveOccurred (), "frr-k8s pods failed to restart" )
146
+ for _ , p := range peersConfig .Peers () {
147
+ ValidateFRRPeeredWithNodes (nodes , & p .FRR , ipFam )
148
+ }
149
+ ginkgo .By ("FRRK8s pod restarted and BGP established" )
124
150
close (c )
125
151
}()
126
152
153
+ check := func () error {
154
+ var returnError error
155
+
156
+ for _ , p := range peersConfig .Peers () {
157
+ err := checkRoutes (p .FRR , prefix )
158
+ if err != nil {
159
+ returnError = errors .Join (returnError , fmt .Errorf ("Neigh %s : %w" , p .FRR .Name , err ))
160
+ for i := 0 ; i < 20 ; i ++ {
161
+ if err := checkRoutes (p .FRR , prefix ); err != nil {
162
+ ginkgo .By (fmt .Sprintf ("%d Neigh %s does NOT have prefix %v" , i , p .FRR .Name , err ))
163
+ } else {
164
+ ginkgo .By (fmt .Sprintf ("%d Neigh %s does have prefix" , i , p .FRR .Name ))
165
+ }
166
+ time .Sleep (time .Second )
167
+ }
168
+ }
169
+ }
170
+ return returnError
171
+ }
172
+
127
173
// 2*time.Minute is important because that is the Graceful Restart timer.
128
- Consistently (check , 2 * time .Minute , time .Second ).ShouldNot (HaveOccurred ())
174
+ Consistently (check , 30 * time .Second , time .Second ).ShouldNot (HaveOccurred ())
129
175
Eventually (c , time .Minute , time .Second ).Should (BeClosed (), "restart FRRK8s pods are not yet ready" )
130
176
},
131
- ginkgo .Entry ("IPV4" , ipfamily .IPv4 , "192.168.2.0/24" ),
132
- ginkgo .Entry ("IPV6" , ipfamily .IPv6 , "fc00:f853:ccd:e799::/64" ),
177
+ ginkgo .Entry ("IPV4" , ipfamily .IPv4 , prefixesV4 ),
178
+ // ginkgo.Entry("IPV6", ipfamily.IPv6, []string{"2001:db8:5555::5/128"} ),
133
179
)
134
180
})
135
181
})
182
+
183
+ func checkRoutes (cnt frrcontainer.FRR , want []string ) error {
184
+ m := sliceToMap (want )
185
+ v4 , _ , err := frr .Routes (cnt )
186
+ if err != nil {
187
+ // ignore the docker exec errors
188
+ return nil
189
+ }
190
+ if len (m ) == 0 {
191
+ return fmt .Errorf ("nil map m" )
192
+ }
193
+ if len (v4 ) == 0 {
194
+ IPRoutes (cnt )
195
+ return fmt .Errorf ("nil map v4" )
196
+ }
197
+ for _ , r := range v4 {
198
+ // if r.Stale {
199
+ // fmt.Printf("S")
200
+ // }
201
+ delete (m , r .Destination .String ())
202
+ }
203
+ if len (m ) > 0 {
204
+ return fmt .Errorf ("%d routes %+v not found " , len (m ), getKeys (m ))
205
+ }
206
+ return nil
207
+ }
208
+
209
+ func scaleUP (size int ) []string {
210
+ if size > 255 {
211
+ panic ("255 is max" )
212
+ }
213
+
214
+ ret := []string {}
215
+ for i := 0 ; i < size ; i ++ {
216
+ ret = append (ret , fmt .Sprintf ("5.5.5.%d/32" , i ))
217
+ }
218
+
219
+ return ret
220
+ }
221
+
222
+ func sliceToMap (slice []string ) map [string ]bool {
223
+ m := make (map [string ]bool )
224
+ for _ , v := range slice {
225
+ m [v ] = true
226
+ }
227
+ return m
228
+ }
229
+ func getKeys (m map [string ]bool ) []string {
230
+ keys := make ([]string , 0 , len (m )) // Initialize slice with the capacity of the map length
231
+ for key := range m {
232
+ keys = append (keys , key )
233
+ }
234
+ return keys
235
+ }
236
+ func IPRoutes (exec executor.Executor ) error {
237
+ cmd := "show ip route bgp"
238
+ res , err := exec .Exec ("vtysh" , "-c" , cmd )
239
+ if err != nil {
240
+ return errors .Join (err , errors .New ("Failed to query routes" ))
241
+ }
242
+ fmt .Println ("res" , res )
243
+ return nil
244
+ }
0 commit comments