diff --git a/README.md b/README.md index b5b5e61..ed9aeae 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,12 @@ actuated-cli ssh \ --token ~/reader.txt \ ssh ls -| ACTOR | HOSTNAME | RX | TX | CONNECTED | -|-------|----------|----|----|-----------| +Hosts are ordered by the connected time. + +| NO | ACTOR | HOSTNAME | RX | TX | CONNECTED | +|-----|-----------|------------------------------------------|-------|-------|-----------| +| 1 | alexellis | 6aafd53144e2f00ef5cd2c16681eeab4712561a6 | 13679 | 10371 | 6m4s | +| 2 | alexellis | fv-az268-245 | 23124 | 13828 | 12m2s | ``` ## Connect to an SSH session @@ -59,12 +63,28 @@ actuated-cli ssh \ ssh connect ``` +Connected to the second session in the list: + +```bash +actuated-cli ssh \ + --token ~/reader.txt \ + ssh connect 2 +``` + Connect to a specific session by hostname: ```bash actuated-cli ssh \ --token ~/reader.txt \ - ssh connect --host runner1 + ssh connect runner1 +``` + +Connect to a specific session with a host prefix: + +```bash +actuated-cli ssh \ + --token ~/reader.txt \ + ssh connect 6aafd ``` ## Check the logs of VMs diff --git a/cmd/ssh_connect.go b/cmd/ssh_connect.go index 3b98018..dfc29b0 100644 --- a/cmd/ssh_connect.go +++ b/cmd/ssh_connect.go @@ -8,7 +8,9 @@ import ( "net/url" "os" "os/exec" + "sort" "strconv" + "strings" "github.com/google/go-github/v52/github" "github.com/spf13/cobra" @@ -23,13 +25,12 @@ func makeSshConnect() *cobra.Command { actuated-cli ssh connect # Connect to a specific session - actuated-cli ssh connect --host HOST + actuated-cli ssh connect HOST `, } cmd.RunE = runSshConnectE - cmd.Flags().String("host", "", "Host to connect to or leave blank to connect to the first") cmd.Flags().Bool("print", false, "Print the SSH command instead of running it") return cmd @@ -46,9 +47,16 @@ func runSshConnectE(cmd *cobra.Command, args []string) error { return err } - host, err := cmd.Flags().GetString("host") - if err != nil { - return err + host := "" + hostIndex := 0 + useIndex := false + + if len(args) > 0 { + host = args[0] + if i, err := strconv.Atoi(host); err == nil { + useIndex = true + hostIndex = i + } } ctx := context.Background() @@ -85,22 +93,42 @@ func runSshConnectE(cmd *cobra.Command, args []string) error { return err } - if len(sessions) == 0 { + onlyActor := []sshSession{} + for _, session := range sessions { + if session.Actor == login { + onlyActor = append(onlyActor, session) + } + } + + sort.Slice(onlyActor, func(i, j int) bool { + return onlyActor[i].ConnectedAt > onlyActor[j].ConnectedAt + }) + + if len(onlyActor) == 0 { return fmt.Errorf("no sessions found") } var found *sshSession - for _, session := range sessions { - if session.Actor != login { - continue - } - + for i, session := range onlyActor { if host == "" { found = &session break } else if session.Hostname == host { found = &session break + } else if useIndex && hostIndex == i+1 { + found = &session + break + } + } + + // Try a fuzzy match + if found == nil { + for _, session := range onlyActor { + if strings.HasPrefix(session.Hostname, host) { + found = &session + break + } } } @@ -111,7 +139,7 @@ func runSshConnectE(cmd *cobra.Command, args []string) error { us, _ := url.Parse(SshGw) if printOnly { - fmt.Printf("ssh -p %d runner@%s\n", found.Port, us.Host) + fmt.Printf("ssh -p %d ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null runner@%s\n", found.Port, us.Host) return nil } diff --git a/cmd/ssh_ls.go b/cmd/ssh_ls.go index 81c9fe6..22a448b 100644 --- a/cmd/ssh_ls.go +++ b/cmd/ssh_ls.go @@ -6,6 +6,7 @@ import ( "encoding/json" "net/http" "net/url" + "sort" "strconv" "time" @@ -68,7 +69,7 @@ func runSshListE(cmd *cobra.Command, args []string) error { buf := bytes.NewBuffer(nil) table := tablewriter.NewWriter(buf) - table.SetHeader([]string{"Actor", "Hostname", "RX", "TX", "Connected"}) + table.SetHeader([]string{"No.", "Actor", "Hostname", "RX", "TX", "Connected"}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) table.SetCenterSeparator("|") @@ -79,20 +80,30 @@ func runSshListE(cmd *cobra.Command, args []string) error { return err } + onlyActor := []sshSession{} for _, session := range sessions { - if login == session.Actor { - connectedAt, _ := time.Parse(time.RFC3339, session.ConnectedAt) - since := time.Since(connectedAt).Round(time.Second) - table.Append([]string{ - session.Actor, - session.Hostname, - strconv.Itoa(session.Rx), - strconv.Itoa(session.Tx), - since.String(), - }) + if session.Actor == login { + onlyActor = append(onlyActor, session) } } + sort.Slice(onlyActor, func(i, j int) bool { + return onlyActor[i].ConnectedAt > onlyActor[j].ConnectedAt + }) + + for i, session := range onlyActor { + connectedAt, _ := time.Parse(time.RFC3339, session.ConnectedAt) + since := time.Since(connectedAt).Round(time.Second) + table.Append([]string{ + strconv.Itoa(i + 1), + session.Actor, + session.Hostname, + strconv.Itoa(session.Rx), + strconv.Itoa(session.Tx), + since.String(), + }) + } + table.Render() cmd.Print(buf.String())