-
Notifications
You must be signed in to change notification settings - Fork 303
/
minikube.go
128 lines (108 loc) · 3.53 KB
/
minikube.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
package k8s
import (
"bufio"
"bytes"
"context"
"fmt"
"os/exec"
"regexp"
"strings"
"github.com/pkg/errors"
)
// This isn't perfect (because it won't unquote the value right) but
// it's good enough for 99% of cases.
var envMatcher = regexp.MustCompile(`export (\w+)="([^"]+)"`)
var versionMatcher = regexp.MustCompile(`^minikube version: v([0-9.]+)$`)
// Error messages if Minikube is running OK but docker-env is unsupported.
var dockerEnvUnsupportedMsgs = []string{
"ENV_DRIVER_CONFLICT",
"ENV_MULTINODE_CONFLICT",
"ENV_DOCKER_UNAVAILABLE",
"The docker-env command is only compatible",
}
type MinikubeClient interface {
Version(ctx context.Context) (string, error)
DockerEnv(ctx context.Context) (map[string]string, bool, error)
NodeIP(ctx context.Context) (NodeIP, error)
}
type minikubeClient struct {
context KubeContext
}
func ProvideMinikubeClient(context KubeContext) MinikubeClient {
return minikubeClient{context: context}
}
func (mc minikubeClient) cmd(ctx context.Context, args ...string) *exec.Cmd {
args = append([]string{"-p", string(mc.context)}, args...)
return exec.CommandContext(ctx, "minikube", args...)
}
func (mc minikubeClient) Version(ctx context.Context) (string, error) {
cmd := mc.cmd(ctx, "version")
output, err := cmd.Output()
if err != nil {
exitErr, isExitErr := err.(*exec.ExitError)
if isExitErr {
return "", fmt.Errorf("Could not read minikube version.\n%s", string(exitErr.Stderr))
}
return "", errors.Wrap(err, "Could not read minikube version")
}
return minikubeVersionFromOutput(output)
}
func minikubeVersionFromOutput(output []byte) (string, error) {
scanner := bufio.NewScanner(bytes.NewBuffer(output))
for scanner.Scan() {
line := scanner.Text()
match := versionMatcher.FindStringSubmatch(line)
if len(match) > 0 {
return match[1], nil
}
}
return "", fmt.Errorf("version not found in output:\n%s", string(output))
}
// Returns:
// - A map of env variables for the minikube docker-env.
// - True if this minikube supports a docker-env, false otherwise
// - An error if minikube doesn't appear to be running.
func (mc minikubeClient) DockerEnv(ctx context.Context) (map[string]string, bool, error) {
cmd := mc.cmd(ctx, "docker-env", "--shell", "sh")
output, err := cmd.Output()
if err != nil {
exitErr, isExitErr := err.(*exec.ExitError)
if isExitErr {
stderr := string(exitErr.Stderr)
for _, msg := range dockerEnvUnsupportedMsgs {
if strings.Contains(stderr, msg) {
return nil, false, nil
}
}
return nil, false, fmt.Errorf("Could not read docker env from minikube.\n"+
"Did you forget to run `minikube start`?\n%s", stderr)
}
return nil, false, errors.Wrap(err, "Could not read docker env from minikube")
}
return dockerEnvFromOutput(output), true, nil
}
func dockerEnvFromOutput(output []byte) map[string]string {
result := make(map[string]string)
scanner := bufio.NewScanner(bytes.NewBuffer(output))
for scanner.Scan() {
line := scanner.Text()
match := envMatcher.FindStringSubmatch(line)
if len(match) > 0 {
result[match[1]] = match[2]
}
}
return result
}
func (mc minikubeClient) NodeIP(ctx context.Context) (NodeIP, error) {
cmd := mc.cmd(ctx, "ip")
out, err := cmd.Output()
if err != nil {
exitErr, isExitErr := err.(*exec.ExitError)
if isExitErr {
return "", errors.Wrapf(exitErr, "Could not read node IP from minikube.\n"+
"Did you forget to run `minikube start`?\n%s", string(exitErr.Stderr))
}
return "", errors.Wrapf(err, "Could not read node IP from minikube")
}
return NodeIP(strings.TrimSpace(string(out))), nil
}