This repository has been archived by the owner on May 7, 2021. It is now read-only.
/
cluster.go
133 lines (116 loc) · 3.57 KB
/
cluster.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright 2016 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cluster
import (
"bytes"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/coreos/mantle/harness"
"github.com/coreos/mantle/platform"
)
// TestCluster embedds a Cluster to provide platform independant helper
// methods.
type TestCluster struct {
*harness.H
platform.Cluster
NativeFuncs []string
// If set to true and a sub-test fails all future sub-tests will be skipped
FailFast bool
hasFailure bool
}
// Run runs f as a subtest and reports whether f succeeded.
func (t *TestCluster) Run(name string, f func(c TestCluster)) bool {
if t.FailFast && t.hasFailure {
return t.H.Run(name, func(h *harness.H) {
func(c TestCluster) {
c.Skip("A previous test has already failed")
}(TestCluster{H: h, Cluster: t.Cluster})
})
}
t.hasFailure = !t.H.Run(name, func(h *harness.H) {
f(TestCluster{H: h, Cluster: t.Cluster})
})
return !t.hasFailure
}
// RunNative runs a registered NativeFunc on a remote machine
func (t *TestCluster) RunNative(funcName string, m platform.Machine) bool {
command := fmt.Sprintf("./kolet run %q %q", t.H.Name(), funcName)
return t.Run(funcName, func(c TestCluster) {
client, err := m.SSHClient()
if err != nil {
c.Fatalf("kolet SSH client: %v", err)
}
defer client.Close()
session, err := client.NewSession()
if err != nil {
c.Fatalf("kolet SSH session: %v", err)
}
defer session.Close()
b, err := session.CombinedOutput(command)
b = bytes.TrimSpace(b)
if len(b) > 0 {
t.Logf("kolet:\n%s", b)
}
if err != nil {
c.Errorf("kolet: %v", err)
}
})
}
// ListNativeFunctions returns a slice of function names that can be executed
// directly on machines in the cluster.
func (t *TestCluster) ListNativeFunctions() []string {
return t.NativeFuncs
}
// DropFile places file from localPath to ~/ on every machine in cluster
func (t *TestCluster) DropFile(localPath string) error {
in, err := os.Open(localPath)
if err != nil {
return err
}
defer in.Close()
for _, m := range t.Machines() {
if _, err := in.Seek(0, 0); err != nil {
return err
}
if err := platform.InstallFile(in, m, filepath.Base(localPath)); err != nil {
return err
}
}
return nil
}
// SSH runs a ssh command on the given machine in the cluster. It differs from
// Machine.SSH in that stderr is written to the test's output as a 'Log' line.
// This ensures the output will be correctly accumulated under the correct
// test.
func (t *TestCluster) SSH(m platform.Machine, cmd string) ([]byte, error) {
stdout, stderr, err := m.SSH(cmd)
if len(stderr) > 0 {
for _, line := range strings.Split(string(stderr), "\n") {
t.Log(line)
}
}
return stdout, err
}
// MustSSH runs a ssh command on the given machine in the cluster, writes
// its stderr to the test's output as a 'Log' line, fails the test if the
// command is unsuccessful, and returns the command's stdout.
func (t *TestCluster) MustSSH(m platform.Machine, cmd string) []byte {
out, err := t.SSH(m, cmd)
if err != nil {
t.Fatalf("%q failed: output %s, status %v", cmd, out, err)
}
return out
}