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}