github.com/koderover/helm@v2.17.0+incompatible/pkg/releasetesting/environment.go (about)

     1  /*
     2  Copyright The Helm Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package releasetesting
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"io/ioutil"
    23  	"log"
    24  	"strings"
    25  	"sync"
    26  	"time"
    27  
    28  	v1 "k8s.io/api/core/v1"
    29  
    30  	"k8s.io/helm/pkg/proto/hapi/release"
    31  	"k8s.io/helm/pkg/proto/hapi/services"
    32  	"k8s.io/helm/pkg/tiller/environment"
    33  )
    34  
    35  // logEscaper is necessary for escaping control characters found in the log stream.
    36  var logEscaper = strings.NewReplacer("%", "%%")
    37  
    38  // Environment encapsulates information about where test suite executes and returns results
    39  type Environment struct {
    40  	Namespace   string
    41  	KubeClient  environment.KubeClient
    42  	Stream      services.ReleaseService_RunReleaseTestServer
    43  	Timeout     int64
    44  	Parallel    bool
    45  	Parallelism uint32
    46  	streamLock  sync.Mutex
    47  }
    48  
    49  func (env *Environment) createTestPod(test *test) error {
    50  	b := bytes.NewBufferString(test.manifest)
    51  	if err := env.KubeClient.Create(env.Namespace, b, env.Timeout, false); err != nil {
    52  		log.Printf(err.Error())
    53  		test.result.Info = err.Error()
    54  		test.result.Status = release.TestRun_FAILURE
    55  		return err
    56  	}
    57  
    58  	return nil
    59  }
    60  
    61  func (env *Environment) getTestPodStatus(test *test) (v1.PodPhase, error) {
    62  	b := bytes.NewBufferString(test.manifest)
    63  	status, err := env.KubeClient.WaitAndGetCompletedPodPhase(env.Namespace, b, time.Duration(env.Timeout)*time.Second)
    64  	if err != nil {
    65  		log.Printf("Error getting status for pod %s: %s", test.result.Name, err)
    66  		test.result.Info = err.Error()
    67  		test.result.Status = release.TestRun_UNKNOWN
    68  		return status, err
    69  	}
    70  
    71  	return status, err
    72  }
    73  
    74  func (env *Environment) streamResult(r *release.TestRun) error {
    75  	switch r.Status {
    76  	case release.TestRun_SUCCESS:
    77  		if err := env.streamSuccess(r.Name); err != nil {
    78  			return err
    79  		}
    80  	case release.TestRun_FAILURE:
    81  		if err := env.streamFailed(r.Name); err != nil {
    82  			return err
    83  		}
    84  
    85  	default:
    86  		if err := env.streamUnknown(r.Name, r.Info); err != nil {
    87  			return err
    88  		}
    89  	}
    90  	return nil
    91  }
    92  
    93  func (env *Environment) streamRunning(name string) error {
    94  	msg := "RUNNING: " + name
    95  	return env.streamMessage(msg, release.TestRun_RUNNING)
    96  }
    97  
    98  func (env *Environment) streamError(info string) error {
    99  	msg := "ERROR: " + info
   100  	return env.streamMessage(msg, release.TestRun_FAILURE)
   101  }
   102  
   103  func (env *Environment) streamFailed(name string) error {
   104  	msg := fmt.Sprintf("FAILED: %s, run `kubectl logs %s --namespace %s` for more info", name, name, env.Namespace)
   105  	return env.streamMessage(msg, release.TestRun_FAILURE)
   106  }
   107  
   108  func (env *Environment) streamSuccess(name string) error {
   109  	msg := fmt.Sprintf("PASSED: %s", name)
   110  	return env.streamMessage(msg, release.TestRun_SUCCESS)
   111  }
   112  
   113  func (env *Environment) streamUnknown(name, info string) error {
   114  	msg := fmt.Sprintf("UNKNOWN: %s: %s", name, info)
   115  	return env.streamMessage(msg, release.TestRun_UNKNOWN)
   116  }
   117  
   118  func (env *Environment) streamMessage(msg string, status release.TestRun_Status) error {
   119  	resp := &services.TestReleaseResponse{Msg: msg, Status: status}
   120  	env.streamLock.Lock()
   121  	defer env.streamLock.Unlock()
   122  	return env.Stream.Send(resp)
   123  }
   124  
   125  // DeleteTestPods deletes resources given in testManifests
   126  func (env *Environment) DeleteTestPods(testManifests []string) {
   127  	for _, testManifest := range testManifests {
   128  		err := env.KubeClient.Delete(env.Namespace, bytes.NewBufferString(testManifest))
   129  		if err != nil {
   130  			env.streamError(err.Error())
   131  		}
   132  	}
   133  }
   134  
   135  // GetLogs collects the logs from the pods created in testManifests
   136  func (env *Environment) GetLogs(testManifests []string) {
   137  	for _, testManifest := range testManifests {
   138  		infos, err := env.KubeClient.Build(env.Namespace, bytes.NewBufferString(testManifest))
   139  		if err != nil {
   140  			env.streamError(err.Error())
   141  			continue
   142  		}
   143  		if len(infos) == 0 {
   144  			env.streamError(fmt.Sprint("Pod manifest is invalid. Unable to obtain the logs"))
   145  			continue
   146  		}
   147  		podName := infos[0].Object.(*v1.Pod).Name
   148  		lr, err := env.KubeClient.GetPodLogs(podName, env.Namespace)
   149  		if err != nil {
   150  			env.streamError(err.Error())
   151  			continue
   152  		}
   153  		logs, err := ioutil.ReadAll(lr)
   154  		if err != nil {
   155  			env.streamError(err.Error())
   156  			continue
   157  		}
   158  		msg := fmt.Sprintf("\nPOD LOGS: %s\n%s", podName, logEscaper.Replace(string(logs)))
   159  		env.streamMessage(msg, release.TestRun_RUNNING)
   160  	}
   161  }