| package cluster |
| |
| import ( |
| "fmt" |
| "net" |
| "os" |
| "path" |
| "sort" |
| |
| "github.com/kballard/go-shellquote" |
| |
| metroctl "source.monogon.dev/metropolis/cli/metroctl/core" |
| "source.monogon.dev/metropolis/cli/pkg/datafile" |
| ) |
| |
| const metroctlRunfile = "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 := datafile.ResolveRunfile(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 |
| } |
| |
| // 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, |
| } |
| } |
| |
| // 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 |
| } |