golang.org/x/build@v0.0.0-20240506185731-218518f32b70/kubernetes/gke/gke_test.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package gke_test 6 7 import ( 8 "context" 9 "flag" 10 "strings" 11 "testing" 12 13 "cloud.google.com/go/compute/metadata" 14 "golang.org/x/build/kubernetes" 15 "golang.org/x/build/kubernetes/gke" 16 "golang.org/x/oauth2" 17 "golang.org/x/oauth2/google" 18 compute "google.golang.org/api/compute/v1" 19 container "google.golang.org/api/container/v1" 20 ) 21 22 // Note: The TestNewClient, TestDialPod, TestDialService, and TestGetNodes 23 // tests require to be run on GCE and with Application Default Credentials 24 // that have at least the container.clusters.list permission, at least one 25 // GKE cluster, and possibly more. 26 // 27 // They're currently disabled on the Go builders; see golang.org/issue/28543. 28 var flagRunGKETests = flag.Bool("run-gke-tests", false, "run gke tests that require special permissions") 29 30 // Tests NewClient and also Dialer. 31 func TestNewClient(t *testing.T) { 32 ctx := context.Background() 33 foreachCluster(t, func(cl *container.Cluster, kc *kubernetes.Client) { 34 _, err := kc.GetPods(ctx) 35 if err != nil { 36 t.Fatal(err) 37 } 38 }) 39 } 40 41 func TestDialPod(t *testing.T) { 42 var passed bool 43 var candidates int 44 ctx := context.Background() 45 foreachCluster(t, func(cl *container.Cluster, kc *kubernetes.Client) { 46 if passed { 47 return 48 } 49 pods, err := kc.GetPods(ctx) 50 if err != nil { 51 t.Fatal(err) 52 } 53 54 for _, pod := range pods { 55 if pod.Status.Phase != "Running" { 56 continue 57 } 58 for _, container := range pod.Spec.Containers { 59 for _, port := range container.Ports { 60 if strings.ToLower(string(port.Protocol)) == "udp" || port.ContainerPort == 0 { 61 continue 62 } 63 candidates++ 64 c, err := kc.DialPod(ctx, pod.Name, port.ContainerPort) 65 if err != nil { 66 t.Logf("Dial %q/%q/%d: %v", cl.Name, pod.Name, port.ContainerPort, err) 67 continue 68 } 69 c.Close() 70 t.Logf("Dialed %q/%q/%d.", cl.Name, pod.Name, port.ContainerPort) 71 passed = true 72 return 73 } 74 } 75 } 76 }) 77 if candidates == 0 { 78 t.Skip("no pods to dial") 79 } 80 if !passed { 81 t.Errorf("dial failures") 82 } 83 } 84 85 func TestDialService(t *testing.T) { 86 var passed bool 87 var candidates int 88 ctx := context.Background() 89 foreachCluster(t, func(cl *container.Cluster, kc *kubernetes.Client) { 90 if passed { 91 return 92 } 93 svcs, err := kc.GetServices(ctx) 94 if err != nil { 95 t.Fatal(err) 96 } 97 for _, svc := range svcs { 98 eps, err := kc.GetServiceEndpoints(ctx, svc.Name, "") 99 if err != nil { 100 t.Fatal(err) 101 } 102 if len(eps) != 1 { 103 continue 104 } 105 candidates++ 106 conn, err := kc.DialServicePort(ctx, svc.Name, "") 107 if err != nil { 108 t.Logf("%s: DialServicePort(%q) error: %v", cl.Name, svc.Name, err) 109 continue 110 } 111 conn.Close() 112 passed = true 113 t.Logf("Dialed cluster %q service %q.", cl.Name, svc.Name) 114 return 115 } 116 117 }) 118 if candidates == 0 { 119 t.Skip("no services to dial") 120 } 121 if !passed { 122 t.Errorf("dial failures") 123 } 124 } 125 126 func foreachCluster(t *testing.T, fn func(*container.Cluster, *kubernetes.Client)) { 127 if testing.Short() { 128 t.Skip("skipping in short mode") 129 } 130 if !*flagRunGKETests { 131 t.Skip("-run-gke-tests not set") 132 } 133 ctx := context.Background() 134 ts, err := google.DefaultTokenSource(ctx, compute.CloudPlatformScope) 135 if err != nil { 136 t.Fatal(err) 137 } 138 httpClient := oauth2.NewClient(ctx, ts) 139 containerService, err := container.New(httpClient) 140 if err != nil { 141 t.Fatal(err) 142 } 143 proj, err := metadata.ProjectID() 144 if err != nil { 145 t.Fatal(err) 146 } 147 if _, err := ts.Token(); err != nil { 148 val, err := metadata.InstanceAttributeValue("service-accounts/default/token") 149 if val == "" { 150 t.Skip("skipping on GCE instance without a service account") 151 } 152 t.Skipf("default token source doesn't work; skipping test: %v", err) 153 } 154 155 clusters, err := containerService.Projects.Locations.Clusters.List("/project/" + proj + "/locations/-").Context(ctx).Do() 156 if err != nil { 157 t.Fatal(err) 158 } 159 160 if len(clusters.Clusters) == 0 { 161 t.Skip("no GKE clusters") 162 } 163 for _, cl := range clusters.Clusters { 164 kc, err := gke.NewClient(ctx, cl.Name, cl.Zone) 165 if err != nil { 166 t.Fatal(err) 167 } 168 fn(cl, kc) 169 kc.Close() 170 } 171 } 172 173 func TestGetNodes(t *testing.T) { 174 var passed bool 175 ctx := context.Background() 176 foreachCluster(t, func(cl *container.Cluster, kc *kubernetes.Client) { 177 if passed { 178 return 179 } 180 nodes, err := kc.GetNodes(ctx) 181 if err != nil { 182 t.Fatal(err) 183 } 184 t.Logf("%d nodes in cluster %s", len(nodes), cl.Name) 185 passed = true 186 }) 187 }