github.com/wmuizelaar/kpt@v0.0.0-20221018115725-bd564717b2ed/pkg/test/porch/cluster.go (about)

     1  // Copyright 2022 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  //      http://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 porch
    16  
    17  import (
    18  	"bytes"
    19  	"os/exec"
    20  	"strings"
    21  	"testing"
    22  	"time"
    23  )
    24  
    25  const (
    26  	TestGitServerImage = "test-git-server"
    27  )
    28  
    29  func GetGitServerImageName(t *testing.T) string {
    30  	cmd := exec.Command("kubectl", "get", "pods", "--selector=app=porch-server", "--namespace=porch-system",
    31  		"--output=jsonpath={.items[*].spec.containers[*].image}")
    32  
    33  	var stderr bytes.Buffer
    34  	var stdout bytes.Buffer
    35  
    36  	cmd.Stderr = &stderr
    37  	cmd.Stdout = &stdout
    38  
    39  	if err := cmd.Run(); err != nil {
    40  		t.Fatalf("Error when getting Porch image version: %v: %s", err, stderr.String())
    41  	}
    42  
    43  	out := stdout.String()
    44  	t.Logf("Porch image query output: %s", out)
    45  
    46  	lines := strings.Split(out, "\n")
    47  	if len(lines) == 0 {
    48  		t.Fatalf("kubectl get pods didn't return any images: %s", out)
    49  	}
    50  	image := strings.TrimSpace(lines[0])
    51  	if image == "" {
    52  		t.Fatalf("Cannot determine Porch server image: output was %q", out)
    53  	}
    54  	return InferGitServerImage(image)
    55  }
    56  
    57  func InferGitServerImage(porchImage string) string {
    58  	slash := strings.LastIndex(porchImage, "/")
    59  	repo := porchImage[:slash+1]
    60  	image := porchImage[slash+1:]
    61  	colon := strings.LastIndex(image, ":")
    62  	tag := image[colon+1:]
    63  
    64  	return repo + TestGitServerImage + ":" + tag
    65  }
    66  
    67  func KubectlApply(t *testing.T, config string) {
    68  	cmd := exec.Command("kubectl", "apply", "-f", "-")
    69  	cmd.Stdin = strings.NewReader(config)
    70  	out, err := cmd.CombinedOutput()
    71  	if err != nil {
    72  		t.Fatalf("kubectl apply failed: %v\ninput: %s\n\noutput:%s", err, config, string(out))
    73  	}
    74  	t.Logf("kubectl apply\n%s\noutput:\n%s", config, string(out))
    75  }
    76  
    77  func KubectlWaitForDeployment(t *testing.T, namespace, name string) {
    78  	args := []string{"rollout", "status", "deployment", "--namespace", namespace, name}
    79  	cmd := exec.Command("kubectl", args...)
    80  	out, err := cmd.CombinedOutput()
    81  	if err != nil {
    82  		t.Fatalf("kubectl %s failed: %v\noutput:\n%s", strings.Join(args, " "), err, string(out))
    83  	}
    84  	t.Logf("kubectl %s:\n%s", strings.Join(args, " "), string(out))
    85  }
    86  
    87  func KubectlWaitForService(t *testing.T, namespace, name string) {
    88  	args := []string{"get", "endpoints", "--namespace", namespace, name, "--output=jsonpath='{.subsets[*].addresses[*].ip}'"}
    89  
    90  	giveUp := time.Now().Add(1 * time.Minute)
    91  	for {
    92  		cmd := exec.Command("kubectl", args...)
    93  		var stdout, stderr bytes.Buffer
    94  		cmd.Stdout = &stdout
    95  		cmd.Stderr = &stderr
    96  
    97  		err := cmd.Run()
    98  		s := stdout.String()
    99  		if err == nil && len(s) > 0 { // Endpoint has an IP address assigned
   100  			t.Logf("Endpoints: %q", s)
   101  			break
   102  		}
   103  
   104  		if time.Now().After(giveUp) {
   105  			var msg string
   106  			if err != nil {
   107  				msg = err.Error()
   108  			}
   109  			t.Fatalf("Service endpoint %s/%s not ready on time. Giving up: %s", namespace, name, msg)
   110  		}
   111  
   112  		time.Sleep(5 * time.Second)
   113  	}
   114  }
   115  
   116  // Kubernetes DNS needs time to propagate the updated address
   117  // Wait until we can register the repository and list its contents.
   118  func KubectlWaitForGitDNS(t *testing.T, gitServerURL string) {
   119  	const name = "test-git-dns-resolve"
   120  
   121  	KubectlCreateNamespace(t, name)
   122  	defer KubectlDeleteNamespace(t, name)
   123  
   124  	// We expect repos to automatically be created (albeit empty)
   125  	repoURL := gitServerURL + "/" + name
   126  
   127  	cmd := exec.Command("kpt", "alpha", "repo", "register", "--namespace", name, "--name", name, repoURL)
   128  	t.Logf("running command %v", strings.Join(cmd.Args, " "))
   129  	out, err := cmd.CombinedOutput()
   130  	if err != nil {
   131  		t.Fatalf("Failed to register probe repository: %v\n%s", err, string(out))
   132  	}
   133  
   134  	// Based on experience, DNS seems to get updated inside the cluster within
   135  	// few seconds. We will wait about a minute.
   136  	// If this turns out to be an issue, we will sidestep DNS and use the Endpoints
   137  	// IP address directly.
   138  	giveUp := time.Now().Add(1 * time.Minute)
   139  	for {
   140  		cmd := exec.Command("kpt", "alpha", "rpkg", "get", "--namespace", name)
   141  		t.Logf("running command %v", strings.Join(cmd.Args, " "))
   142  		out, err := cmd.CombinedOutput()
   143  		t.Logf("output: %v", string(out))
   144  
   145  		if err == nil {
   146  			break
   147  		}
   148  
   149  		if time.Now().After(giveUp) {
   150  			t.Fatalf("Git service DNS resolution failed: %v", err)
   151  		}
   152  
   153  		time.Sleep(5 * time.Second)
   154  	}
   155  }
   156  
   157  func KubectlCreateNamespace(t *testing.T, name string) {
   158  	cmd := exec.Command("kubectl", "create", "namespace", name)
   159  	t.Logf("running command %v", strings.Join(cmd.Args, " "))
   160  	out, err := cmd.CombinedOutput()
   161  	if err != nil {
   162  		t.Fatalf("Failed to create namespace %q: %v\n%s", name, err, string(out))
   163  	}
   164  	t.Logf("output: %v", string(out))
   165  }
   166  
   167  func KubectlDeleteNamespace(t *testing.T, name string) {
   168  	cmd := exec.Command("kubectl", "delete", "namespace", name)
   169  	t.Logf("running command %v", strings.Join(cmd.Args, " "))
   170  	out, err := cmd.CombinedOutput()
   171  	if err != nil {
   172  		t.Logf("Failed to delete namespace %q: %v\n%s", name, err, string(out))
   173  	}
   174  	t.Logf("output: %v", string(out))
   175  }
   176  
   177  func RegisterRepository(t *testing.T, repoURL, namespace, name string) {
   178  	cmd := exec.Command("kpt", "alpha", "repo", "register", "--namespace", namespace, "--name", name, repoURL)
   179  	t.Logf("running command %v", strings.Join(cmd.Args, " "))
   180  	out, err := cmd.CombinedOutput()
   181  	if err != nil {
   182  		t.Fatalf("Failed to register repository %q: %v\n%s", repoURL, err, string(out))
   183  	}
   184  	t.Logf("output: %v", string(out))
   185  }