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  }