github.com/costinm/krun/gcp@v0.0.0-20220124172154-1a9be088ad1e/gcp_test.go (about) 1 // Copyright 2021 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package gcp 16 17 import ( 18 "context" 19 "log" 20 "os" 21 "testing" 22 "time" 23 24 "github.com/costinm/krun/k8s/k8s" 25 "github.com/costinm/krun/pkg/mesh" 26 "k8s.io/apimachinery/pkg/api/errors" 27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 "k8s.io/client-go/kubernetes" 29 ) 30 31 // Requires GOOGLE_APPLICATION_CREDENTIALS or metadata server and PROJECT_ID 32 func TestK8S(t *testing.T) { 33 os.Mkdir("../../out", 0775) 34 os.Chdir("../../out") 35 36 // For the entire test 37 ctx, cf := context.WithTimeout(context.Background(), 100*time.Second) 38 defer cf() 39 40 kr := mesh.New() 41 configFromEnvAndMD(ctx, kr) 42 // ADC or runner having permissions are required 43 projectID := kr.ProjectId 44 if projectID == "" { 45 // Attempt to use the kubeconfig 46 kr1 := mesh.New() 47 kr1.LoadConfig(ctx) 48 if kr1.ProjectId == "" { 49 t.Skip("Missing PROJECT_ID") 50 return 51 } 52 kr.ProjectId = kr1.ProjectId 53 } 54 55 t.Run("all-any", func(t *testing.T) { 56 cl, err := AllClusters(ctx, kr, "", "", "") 57 if err != nil { 58 t.Fatal(err) 59 } 60 if len(cl) == 0 { 61 t.Fatal("No ASM clusters") 62 } 63 }) 64 t.Run("all-mesh-id", func(t *testing.T) { 65 cl, err := AllClusters(ctx, kr, "", "mesh_id", "") 66 if err != nil { 67 t.Fatal(err) 68 } 69 if len(cl) == 0 { 70 t.Fatal("No ASM clusters") 71 } 72 }) 73 74 projectID := os.Getenv("PROJECT_ID") 75 if projectID == "" { 76 t.Skip("Missing PROJECT_ID") 77 return 78 } 79 80 kr := &k8s.K8S{Mesh: m} 81 82 cl, err := AllClusters(ctx, kr, "", "mesh_id", "") 83 if err != nil { 84 t.Fatal(err) 85 } 86 if len(cl) == 0 { 87 t.Fatal("No ASM clusters") 88 } 89 if kr.Mesh.ProjectId != projectID { 90 t.Error("Project ID initialization", kr.Mesh.ProjectId, projectID) 91 } 92 testCluster := cl[0] 93 94 // Run the tests on the first found cluster, unless the test is run with env variables to select a specific 95 // location and cluster name. 96 97 98 // WIP: using the hub, for multi-project 99 t.Run("hub", func(t *testing.T) { 100 kchub, err := AllHub(ctx, kr) 101 if err != nil { 102 t.Fatal(err) 103 } 104 for _, kh := range kchub { 105 t.Log("Hub:", kh.ClusterName, kh.ClusterLocation) 106 } 107 if len(kchub) == 0 { 108 t.Skip("No hub clusters registered") 109 } 110 111 c0 := kchub[0] 112 rc, err := restConfig(c0.KubeConfig) 113 if err != nil { 114 t.Fatal(err) 115 } 116 client, err := kubernetes.NewForConfig(rc) 117 if err != nil { 118 t.Fatal(err) 119 } 120 err = checkClient(client) 121 if err != nil { 122 if se, ok := err.(*errors.StatusError); ok { 123 if se.Status().Reason == "Forbidden" { 124 t.Skip("GKE Connect not authorized") 125 } 126 } 127 // Hub requires special setup - just log for now 128 t.Log(err) 129 } 130 131 }) 132 133 t.Run("gke", func(t *testing.T) { 134 // This is the main function for the package - given a KRun object, initialize the K8S Client based 135 // on settings and GKE API result. 136 kr1 := mesh.New() 137 kr1.ProjectId = kr.ProjectId 138 kr1.ClusterName = testCluster.ClusterName 139 kr1.ClusterLocation = testCluster.ClusterLocation 140 141 err = InitGCP(context.Background(), kr1) 142 if err != nil { 143 t.Fatal(err) 144 } 145 if kr1.Client == nil { 146 t.Fatal("No client") 147 } 148 149 err = checkClient(kr1.Client) 150 if err != nil { 151 t.Fatal(err) 152 } 153 }) 154 155 t.Run("configCluster", func(t *testing.T) { 156 kr1 := mesh.New() 157 kr1.MeshAddr, _ = url.Parse("gke://" + kr.ProjectId) 158 159 err = InitGCP(context.Background(), kr1) 160 if err != nil { 161 t.Fatal(err) 162 } 163 if kr1.Client == nil { 164 t.Fatal("No client") 165 } 166 167 err = checkClient(kr1.Client) 168 if err != nil { 169 t.Fatal(err) 170 } 171 }) 172 173 174 t.Run("configClusterExplicit", func(t *testing.T) { 175 kr1 := mesh.New() 176 kr1.MeshAddr, _ = url.Parse(fmt.Sprintf("https://container.googleapis.com/v1/projects/%s/locations/%s/clusters/%s", kr.ProjectId, kr.ClusterLocation, kr.ClusterName)) 177 178 err = InitGCP(context.Background(), kr1) 179 if err != nil { 180 t.Fatal(err) 181 } 182 if kr1.Client == nil { 183 t.Fatal("No client") 184 } 185 186 err = checkClient(kr1.Client) 187 if err != nil { 188 t.Fatal(err) 189 } 190 }) 191 192 } 193 194 func checkClient(kc *kubernetes.Clientset) error { 195 v, err := kc.ServerVersion() // /version on the server 196 if err != nil { 197 return err 198 } 199 log.Println("Cluster version", v) 200 201 _, err = kc.CoreV1().ConfigMaps("istio-system").List(context.Background(), metav1.ListOptions{}) 202 if err != nil { 203 return err 204 } 205 206 return nil 207 }