102 lines
2.2 KiB
Go
102 lines
2.2 KiB
Go
package vnc
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/cirruslabs/orchard/internal/command/ssh"
|
|
"github.com/cirruslabs/orchard/internal/proxy"
|
|
"github.com/cirruslabs/orchard/pkg/client"
|
|
"github.com/skratchdot/open-golang/open"
|
|
"github.com/spf13/cobra"
|
|
"net"
|
|
)
|
|
|
|
const vncPort = 5900
|
|
|
|
var username string
|
|
var password string
|
|
var wait uint16
|
|
|
|
func newVNCVMCommand() *cobra.Command {
|
|
command := &cobra.Command{
|
|
Use: "vm VM_NAME",
|
|
Short: "Open VNC session with the VM",
|
|
Args: cobra.ExactArgs(1),
|
|
RunE: runVNCVM,
|
|
}
|
|
|
|
command.PersistentFlags().StringVarP(&username, "username", "u", "",
|
|
"VNC username")
|
|
command.PersistentFlags().StringVarP(&password, "password", "p", "",
|
|
"VNC password")
|
|
command.PersistentFlags().Uint16VarP(&wait, "wait", "w", 60,
|
|
"Amount of seconds to wait for the VM to start running if it's not running already")
|
|
|
|
return command
|
|
}
|
|
|
|
func runVNCVM(cmd *cobra.Command, args []string) (err error) {
|
|
name := args[0]
|
|
|
|
client, err := client.New()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
if listenerErr := listener.Close(); listenerErr != nil && err == nil {
|
|
err = listenerErr
|
|
}
|
|
}()
|
|
|
|
fmt.Printf("forwarding %s -> %s:%d...\n", listener.Addr(), name, vncPort)
|
|
|
|
errCh := make(chan error, 1)
|
|
|
|
go func() {
|
|
for {
|
|
conn, err := listener.Accept()
|
|
if err != nil {
|
|
errCh <- err
|
|
|
|
return
|
|
}
|
|
|
|
go func() {
|
|
wsConn, err := client.VMs().PortForward(cmd.Context(), name, vncPort, wait)
|
|
if err != nil {
|
|
fmt.Printf("failed to forward port: %v\n", err)
|
|
|
|
return
|
|
}
|
|
defer wsConn.Close()
|
|
|
|
if err := proxy.Connections(wsConn, conn); err != nil {
|
|
fmt.Printf("failed to forward port: %v\n", err)
|
|
}
|
|
}()
|
|
}
|
|
}()
|
|
|
|
username, password = ssh.ChooseUsernameAndPassword(cmd.Context(), client, name, username, password)
|
|
|
|
openURL := fmt.Sprintf("vnc://%s:%s@%s", username, password, listener.Addr().String())
|
|
openURLSanitized := fmt.Sprintf("vnc://%s@%s", username, listener.Addr().String())
|
|
|
|
fmt.Printf("opening %s...\n", openURLSanitized)
|
|
|
|
if err := open.Start(openURL); err != nil {
|
|
fmt.Printf("failed to open: %v\n", err)
|
|
}
|
|
|
|
select {
|
|
case <-cmd.Context().Done():
|
|
return cmd.Context().Err()
|
|
case err := <-errCh:
|
|
return err
|
|
}
|
|
}
|