github.com/coreos/mantle@v0.13.0/kola/cluster/cluster.go (about)

     1  // Copyright 2016 CoreOS, Inc.
     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 cluster
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"os"
    21  	"path/filepath"
    22  	"strings"
    23  
    24  	"github.com/coreos/mantle/harness"
    25  	"github.com/coreos/mantle/platform"
    26  )
    27  
    28  // TestCluster embedds a Cluster to provide platform independant helper
    29  // methods.
    30  type TestCluster struct {
    31  	*harness.H
    32  	platform.Cluster
    33  	NativeFuncs []string
    34  
    35  	// If set to true and a sub-test fails all future sub-tests will be skipped
    36  	FailFast   bool
    37  	hasFailure bool
    38  }
    39  
    40  // Run runs f as a subtest and reports whether f succeeded.
    41  func (t *TestCluster) Run(name string, f func(c TestCluster)) bool {
    42  	if t.FailFast && t.hasFailure {
    43  		return t.H.Run(name, func(h *harness.H) {
    44  			func(c TestCluster) {
    45  				c.Skip("A previous test has already failed")
    46  			}(TestCluster{H: h, Cluster: t.Cluster})
    47  		})
    48  	}
    49  	t.hasFailure = !t.H.Run(name, func(h *harness.H) {
    50  		f(TestCluster{H: h, Cluster: t.Cluster})
    51  	})
    52  	return !t.hasFailure
    53  
    54  }
    55  
    56  // RunNative runs a registered NativeFunc on a remote machine
    57  func (t *TestCluster) RunNative(funcName string, m platform.Machine) bool {
    58  	command := fmt.Sprintf("./kolet run %q %q", t.H.Name(), funcName)
    59  	return t.Run(funcName, func(c TestCluster) {
    60  		client, err := m.SSHClient()
    61  		if err != nil {
    62  			c.Fatalf("kolet SSH client: %v", err)
    63  		}
    64  		defer client.Close()
    65  
    66  		session, err := client.NewSession()
    67  		if err != nil {
    68  			c.Fatalf("kolet SSH session: %v", err)
    69  		}
    70  		defer session.Close()
    71  
    72  		b, err := session.CombinedOutput(command)
    73  		b = bytes.TrimSpace(b)
    74  		if len(b) > 0 {
    75  			t.Logf("kolet:\n%s", b)
    76  		}
    77  		if err != nil {
    78  			c.Errorf("kolet: %v", err)
    79  		}
    80  	})
    81  }
    82  
    83  // ListNativeFunctions returns a slice of function names that can be executed
    84  // directly on machines in the cluster.
    85  func (t *TestCluster) ListNativeFunctions() []string {
    86  	return t.NativeFuncs
    87  }
    88  
    89  // DropFile places file from localPath to ~/ on every machine in cluster
    90  func (t *TestCluster) DropFile(localPath string) error {
    91  	in, err := os.Open(localPath)
    92  	if err != nil {
    93  		return err
    94  	}
    95  	defer in.Close()
    96  
    97  	for _, m := range t.Machines() {
    98  		if _, err := in.Seek(0, 0); err != nil {
    99  			return err
   100  		}
   101  		if err := platform.InstallFile(in, m, filepath.Base(localPath)); err != nil {
   102  			return err
   103  		}
   104  	}
   105  	return nil
   106  }
   107  
   108  // SSH runs a ssh command on the given machine in the cluster. It differs from
   109  // Machine.SSH in that stderr is written to the test's output as a 'Log' line.
   110  // This ensures the output will be correctly accumulated under the correct
   111  // test.
   112  func (t *TestCluster) SSH(m platform.Machine, cmd string) ([]byte, error) {
   113  	stdout, stderr, err := m.SSH(cmd)
   114  
   115  	if len(stderr) > 0 {
   116  		for _, line := range strings.Split(string(stderr), "\n") {
   117  			t.Log(line)
   118  		}
   119  	}
   120  
   121  	return stdout, err
   122  }
   123  
   124  // MustSSH runs a ssh command on the given machine in the cluster, writes
   125  // its stderr to the test's output as a 'Log' line, fails the test if the
   126  // command is unsuccessful, and returns the command's stdout.
   127  func (t *TestCluster) MustSSH(m platform.Machine, cmd string) []byte {
   128  	out, err := t.SSH(m, cmd)
   129  	if err != nil {
   130  		t.Fatalf("%q failed: output %s, status %v", cmd, out, err)
   131  	}
   132  	return out
   133  }