main
1package main
2
3import (
4 "fmt"
5 "os"
6 "os/exec"
7 "strings"
8)
9
10const usage = `shpool-remote - Manage shpool sessions on remote hosts
11
12Usage:
13 shpool-remote <host> list List all sessions on host
14 shpool-remote <host> detach <session> Detach a session
15 shpool-remote <host> kill <session> Kill a session
16 shpool-remote <host> attach <session> Attach to a session
17
18Examples:
19 shpool-remote rhea.home list
20 shpool-remote rhea.home detach mywork
21 shpool-remote rhea.home kill old-session
22 shpool-remote rhea.home attach dev
23`
24
25func main() {
26 if len(os.Args) < 3 {
27 fmt.Fprint(os.Stderr, usage)
28 os.Exit(1)
29 }
30
31 host := os.Args[1]
32 command := os.Args[2]
33
34 switch command {
35 case "list":
36 if err := runList(host); err != nil {
37 fmt.Fprintf(os.Stderr, "Error: %v\n", err)
38 os.Exit(1)
39 }
40 case "detach":
41 if len(os.Args) < 4 {
42 fmt.Fprintln(os.Stderr, "Error: session name required for detach")
43 os.Exit(1)
44 }
45 if err := runDetach(host, os.Args[3]); err != nil {
46 fmt.Fprintf(os.Stderr, "Error: %v\n", err)
47 os.Exit(1)
48 }
49 case "kill":
50 if len(os.Args) < 4 {
51 fmt.Fprintln(os.Stderr, "Error: session name required for kill")
52 os.Exit(1)
53 }
54 if err := runKill(host, os.Args[3]); err != nil {
55 fmt.Fprintf(os.Stderr, "Error: %v\n", err)
56 os.Exit(1)
57 }
58 case "attach":
59 if len(os.Args) < 4 {
60 fmt.Fprintln(os.Stderr, "Error: session name required for attach")
61 os.Exit(1)
62 }
63 if err := runAttach(host, os.Args[3]); err != nil {
64 fmt.Fprintf(os.Stderr, "Error: %v\n", err)
65 os.Exit(1)
66 }
67 default:
68 fmt.Fprintf(os.Stderr, "Error: unknown command '%s'\n\n", command)
69 fmt.Fprint(os.Stderr, usage)
70 os.Exit(1)
71 }
72}
73
74func runList(host string) error {
75 cmd := exec.Command("ssh", host, "shpool", "list")
76 cmd.Stdout = os.Stdout
77 cmd.Stderr = os.Stderr
78 return cmd.Run()
79}
80
81func runDetach(host, session string) error {
82 cmd := exec.Command("ssh", host, "shpool", "detach", session)
83 cmd.Stdout = os.Stdout
84 cmd.Stderr = os.Stderr
85 if err := cmd.Run(); err != nil {
86 return err
87 }
88 fmt.Printf("Session '%s' detached on %s\n", session, host)
89 return nil
90}
91
92func runKill(host, session string) error {
93 cmd := exec.Command("ssh", host, "shpool", "kill", session)
94 cmd.Stdout = os.Stdout
95 cmd.Stderr = os.Stderr
96 if err := cmd.Run(); err != nil {
97 return err
98 }
99 fmt.Printf("Session '%s' killed on %s\n", session, host)
100 return nil
101}
102
103func runAttach(host, session string) error {
104 // For attach, we need an interactive SSH session
105 // Use ssh host/session pattern which uses the shpool-ssh-wrapper
106 fullSession := fmt.Sprintf("%s/%s", host, session)
107 cmd := exec.Command("ssh", fullSession)
108 cmd.Stdin = os.Stdin
109 cmd.Stdout = os.Stdout
110 cmd.Stderr = os.Stderr
111 return cmd.Run()
112}
113
114// runCommand executes a remote shpool command and returns the output
115func runCommand(host string, args ...string) (string, error) {
116 cmdArgs := append([]string{host, "shpool"}, args...)
117 cmd := exec.Command("ssh", cmdArgs...)
118 output, err := cmd.CombinedOutput()
119 return strings.TrimSpace(string(output)), err
120}