1515package main
1616
1717import (
18+ "fmt"
1819 "log"
1920 "os"
2021 "strings"
22+ "sync"
2123 "time"
2224
2325 . "github.com/onsi/ginkgo"
@@ -29,6 +31,12 @@ import (
2931 "github.com/projectcalico/libcalico-go/lib/ipip"
3032 "github.com/projectcalico/libcalico-go/lib/net"
3133 "github.com/projectcalico/libcalico-go/lib/testutils"
34+ "k8s.io/client-go/tools/clientcmd"
35+
36+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
37+ "k8s.io/client-go/kubernetes"
38+ "k8s.io/client-go/pkg/api/v1"
39+ clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
3240)
3341
3442var exitCode int
@@ -454,3 +462,82 @@ var _ = Describe("UT for Node IP assignment and conflict checking.", func() {
454462 Entry ("Test with \" IP6\" env var set to IP and BGP spec populated with different IP" , makeNode ("192.168.1.10/24" , "2001:db8:85a3:8d3:1319:8a2e:370:7348/32" ), []EnvItem {{"IP" , "192.168.1.10/24" }, {"IP6" , "2001:db8:85a3:8d3:1319:8a2e:370:7349/32" }}, true ),
455463 )
456464})
465+
466+ var _ = Describe ("FV tests against K8s API server." , func () {
467+ It ("should not throw an error when multiple Nodes configure the same global CRD value." , func () {
468+ // How many Nodes we want to "create".
469+ numNodes := 10
470+
471+ // Create a K8s client.
472+ configOverrides := & clientcmd.ConfigOverrides {
473+ ClusterInfo : clientcmdapi.Cluster {
474+ Server : "http://127.0.0.1:8080" ,
475+ InsecureSkipTLSVerify : true ,
476+ },
477+ }
478+
479+ kcfg , err := clientcmd .NewNonInteractiveDeferredLoadingClientConfig (& clientcmd.ClientConfigLoadingRules {}, configOverrides ).ClientConfig ()
480+ if err != nil {
481+ Fail (fmt .Sprintf ("Failed to create K8s config: %v" , err ))
482+ }
483+
484+ cs , err := kubernetes .NewForConfig (kcfg )
485+ if err != nil {
486+ Fail (fmt .Sprintf ("Could not create K8s client: %v" , err ))
487+ }
488+
489+ // Create Calico client with k8s backend.
490+ cfg := api .NewCalicoAPIConfig ()
491+ cfg .Spec = api.CalicoAPIConfigSpec {
492+ DatastoreType : api .Kubernetes ,
493+ KubeConfig : api.KubeConfig {
494+ K8sAPIEndpoint : "http://127.0.0.1:8080" ,
495+ K8sInsecureSkipTLSVerify : true ,
496+ },
497+ }
498+
499+ c := testutils .CreateClient (* cfg )
500+
501+ // Create some Nodes using K8s client, Calico client does not support Node creation for KDD.
502+ kNodes := []* v1.Node {}
503+ for i := 0 ; i < numNodes ; i ++ {
504+ n := & v1.Node {
505+ ObjectMeta : metav1.ObjectMeta {
506+ Name : fmt .Sprintf ("raceNode%02d" , i + 1 ),
507+ },
508+ }
509+ kNodes = append (kNodes , n )
510+ cs .Nodes ().Create (n )
511+ }
512+
513+ // Pull above Nodes using Calico client.
514+ nodes , err := c .Nodes ().List (api.NodeMetadata {})
515+ if err != nil {
516+ Fail (fmt .Sprintf ("Could not retrieve Nodes %v" , err ))
517+ }
518+
519+ // Run ensureDefaultConfig against each of the Nodes using goroutines to simulate multiple Nodes coming online.
520+ var wg sync.WaitGroup
521+ errors := []error {}
522+ for _ , node := range nodes .Items {
523+ wg .Add (1 )
524+ go func () {
525+ defer wg .Done ()
526+ err = ensureDefaultConfig (cfg , c , & node )
527+ if err != nil {
528+ errors = append (errors , err )
529+ }
530+ }()
531+ }
532+
533+ wg .Wait ()
534+
535+ // Verify all runs complete without error.
536+ Expect (len (errors )).To (Equal (0 ))
537+
538+ // Clean up our Nodes.
539+ for _ , node := range nodes .Items {
540+ cs .Nodes ().Delete (node .Metadata .Name , & metav1.DeleteOptions {})
541+ }
542+ })
543+ })
0 commit comments