diff --git a/roverctl/src/commands/prechecks/prechecks.go b/roverctl/src/commands/prechecks/prechecks.go index bd09abd..94e2e1e 100644 --- a/roverctl/src/commands/prechecks/prechecks.go +++ b/roverctl/src/commands/prechecks/prechecks.go @@ -2,8 +2,10 @@ package command_prechecks import ( "fmt" + "strings" "github.com/VU-ASE/rover/roverctl/src/configuration" + "github.com/VU-ASE/rover/roverctl/src/utils" view_incompatible "github.com/VU-ASE/rover/roverctl/src/views/incompatible" "github.com/spf13/cobra" @@ -28,6 +30,12 @@ func Perform(cmd *cobra.Command, args []string, roverIndex int, roverdHost strin // Pad number to two digits and use mDNS to resolve the rover's hostname host = fmt.Sprintf("rover%02d.local", roverIndex) // host = fmt.Sprintf("192.168.0.%d", roverIndex+100) + + if strings.HasSuffix(host, ".local") { + if ip, err := utils.ResolveHostWithPing(host); err == nil { + host = ip + } + } } // Create connection diff --git a/roverctl/src/utils/mdns.go b/roverctl/src/utils/mdns.go new file mode 100644 index 0000000..218e678 --- /dev/null +++ b/roverctl/src/utils/mdns.go @@ -0,0 +1,60 @@ +package utils + +import ( + "bytes" + "context" + "fmt" + "os/exec" + "regexp" + "time" + "runtime" +) + +// A regular expression to match IPv4 addresses in ping output +var theIPv4Regex = regexp.MustCompile(`\((\d+\.\d+\.\d+\.\d+)\)`) + +func ResolveHostWithPing(host string) (string, error) { + // We use a context with timeout to avoid hanging indefinitely on the ping command + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + + // We prepare the ping command based on what OS is currently running roverctl + args := pingArgs(host) + cmd := exec.CommandContext(ctx, "ping", args...) + + // Capture the output + var out bytes.Buffer + cmd.Stdout = &out + cmd.Stderr = &out + + // Run the ping command, but do not return an error yet + // Since ping might fail even if mDNS resolution worked + // We will check the output for an IP address, and if we cannot find one, we return an error + if err := cmd.Run(); err != nil { + _ = err + } + + // Search the output for an IPv4 address + matches := theIPv4Regex.FindStringSubmatch(out.String()) + if len(matches) >= 2 { + return matches[1], nil + } + + // If we reach here, we could not find an IP address in the ping output + return "", fmt.Errorf("could not resolve host %s via ping, output: %s", host, out.String()) +} + +func pingArgs(host string) []string { + // Different OSes have different arguments for ping + switch runtime.GOOS { + // MacOS + case "darwin": + return []string{"-c", "1", "-W", "1000", host} + // Linux + default: + return []string{"-c", "1", "-w", "1", host} + } +} + + +