/
metroctl.go
82 lines (70 loc) · 2.5 KB
/
metroctl.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
package cluster
import (
"context"
"crypto/x509"
"fmt"
"net"
"os"
"path"
"sort"
"github.com/bazelbuild/rules_go/go/runfiles"
"github.com/kballard/go-shellquote"
metroctl "source.monogon.dev/metropolis/cli/metroctl/core"
)
const metroctlRunfile = "_main/metropolis/cli/metroctl/metroctl_/metroctl"
// MetroctlRunfilePath returns the absolute path to the metroctl binary available
// if the built target depends on //metropolis/cli/metroctl. Otherwise, an error
// is returned.
func MetroctlRunfilePath() (string, error) {
path, err := runfiles.Rlocation(metroctlRunfile)
if err != nil {
return "", fmt.Errorf("//metropolis/cli/metroctl not found in runfiles, did you include it as a data dependency? error: %w", err)
}
return path, nil
}
type acceptall struct{}
func (a *acceptall) Ask(ctx context.Context, _ *metroctl.ConnectOptions, _ *x509.Certificate) (bool, error) {
return true, nil
}
// ConnectOptions returns metroctl.ConnectOptions that describe connectivity to
// the launched cluster.
func (c *Cluster) ConnectOptions() *metroctl.ConnectOptions {
// Use all metropolis nodes as endpoints. That's fine, metroctl's resolver will
// figure out what to actually use.
var endpoints []string
for _, n := range c.Nodes {
endpoints = append(endpoints, n.ManagementAddress)
}
sort.Strings(endpoints)
return &metroctl.ConnectOptions{
ConfigPath: c.metroctlDir,
ProxyServer: net.JoinHostPort("127.0.0.1", fmt.Sprintf("%d", c.Ports[SOCKSPort])),
Endpoints: endpoints,
TOFU: &acceptall{},
}
}
// MetroctlFlags return stringified flags to pass to a metroctl binary to connect
// to the launched cluster.
func (c *Cluster) MetroctlFlags() string {
return shellquote.Join(c.ConnectOptions().ToFlags()...)
}
// MakeMetroctlWrapper builds and returns the path to a shell script which calls
// metroctl (from //metropolis/cli/metroctl, which must be included as a data
// dependency of the built target) with all the required flags to connect to the
// launched cluster.
func (c *Cluster) MakeMetroctlWrapper() (string, error) {
mpath, err := MetroctlRunfilePath()
if err != nil {
return "", err
}
wpath := path.Join(c.metroctlDir, "metroctl.sh")
// Don't create wrapper if it already exists.
if _, err := os.Stat(wpath); err == nil {
return wpath, nil
}
wrapper := fmt.Sprintf("#!/usr/bin/env bash\nexec %s %s \"$@\"", mpath, c.MetroctlFlags())
if err := os.WriteFile(wpath, []byte(wrapper), 0555); err != nil {
return "", fmt.Errorf("could not write wrapper: %w", err)
}
return wpath, nil
}