github.com/vmware/govmomi@v0.51.0/cli/vm/console.go (about)

     1  // © Broadcom. All Rights Reserved.
     2  // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package vm
     6  
     7  import (
     8  	"context"
     9  	"flag"
    10  	"fmt"
    11  	"io"
    12  	"net/url"
    13  	"os"
    14  
    15  	"github.com/vmware/govmomi/cli"
    16  	"github.com/vmware/govmomi/cli/flags"
    17  	"github.com/vmware/govmomi/object"
    18  	"github.com/vmware/govmomi/session"
    19  	"github.com/vmware/govmomi/vim25/soap"
    20  	"github.com/vmware/govmomi/vim25/types"
    21  )
    22  
    23  type console struct {
    24  	*flags.VirtualMachineFlag
    25  
    26  	h5      bool
    27  	wss     bool
    28  	capture string
    29  }
    30  
    31  func init() {
    32  	cli.Register("vm.console", &console{})
    33  }
    34  
    35  func (cmd *console) Register(ctx context.Context, f *flag.FlagSet) {
    36  	cmd.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx)
    37  	cmd.VirtualMachineFlag.Register(ctx, f)
    38  
    39  	f.BoolVar(&cmd.h5, "h5", false, "Generate HTML5 UI console link")
    40  	f.BoolVar(&cmd.wss, "wss", false, "Generate WebSocket console link")
    41  	f.StringVar(&cmd.capture, "capture", "", "Capture console screen shot to file")
    42  }
    43  
    44  func (cmd *console) Process(ctx context.Context) error {
    45  	if err := cmd.VirtualMachineFlag.Process(ctx); err != nil {
    46  		return err
    47  	}
    48  	return nil
    49  }
    50  
    51  func (cmd *console) Usage() string {
    52  	return "VM"
    53  }
    54  
    55  func (cmd *console) Description() string {
    56  	return `Generate console URL or screen capture for VM.
    57  
    58  One of VMRC, VMware Player, VMware Fusion or VMware Workstation must be installed to
    59  open VMRC console URLs.
    60  
    61  Examples:
    62    govc vm.console my-vm
    63    govc vm.console -capture screen.png my-vm  # screen capture
    64    govc vm.console -capture - my-vm | display # screen capture to stdout
    65    open $(govc vm.console my-vm)              # MacOSX VMRC
    66    open $(govc vm.console -h5 my-vm)          # MacOSX H5
    67    xdg-open $(govc vm.console my-vm)          # Linux VMRC
    68    xdg-open $(govc vm.console -h5 my-vm)      # Linux H5`
    69  }
    70  
    71  func (cmd *console) Run(ctx context.Context, f *flag.FlagSet) error {
    72  	vms, err := cmd.VirtualMachines(f.Args())
    73  	if err != nil {
    74  		return err
    75  	}
    76  
    77  	if len(vms) != 1 {
    78  		return flag.ErrHelp
    79  	}
    80  
    81  	vm := vms[0]
    82  
    83  	state, err := vm.PowerState(ctx)
    84  	if err != nil {
    85  		return err
    86  	}
    87  
    88  	if (cmd.capture != "" || cmd.wss) && state != types.VirtualMachinePowerStatePoweredOn {
    89  		return fmt.Errorf("vm is not powered on (%s)", state)
    90  	}
    91  
    92  	c := vm.Client()
    93  
    94  	u := c.URL()
    95  
    96  	if cmd.capture != "" {
    97  		u.Path = "/screen"
    98  		query := url.Values{"id": []string{vm.Reference().Value}}
    99  		u.RawQuery = query.Encode()
   100  
   101  		param := soap.DefaultDownload
   102  
   103  		if cmd.capture == "-" {
   104  			w, _, derr := c.Download(ctx, u, &param)
   105  			if derr != nil {
   106  				return derr
   107  			}
   108  
   109  			_, err = io.Copy(os.Stdout, w)
   110  			if err != nil {
   111  				return err
   112  			}
   113  
   114  			return w.Close()
   115  		}
   116  
   117  		return c.DownloadFile(ctx, cmd.capture, u, &param)
   118  	}
   119  
   120  	if cmd.wss {
   121  		ticket, err := vm.AcquireTicket(ctx, string(types.VirtualMachineTicketTypeWebmks))
   122  		if err != nil {
   123  			return err
   124  		}
   125  
   126  		link := fmt.Sprintf("wss://%s:%d/ticket/%s", ticket.Host, ticket.Port, ticket.Ticket)
   127  		fmt.Fprintln(cmd.Out, link)
   128  		return nil
   129  	}
   130  
   131  	m := session.NewManager(c)
   132  	ticket, err := m.AcquireCloneTicket(ctx)
   133  	if err != nil {
   134  		return err
   135  	}
   136  
   137  	var link string
   138  
   139  	if cmd.h5 {
   140  		m := object.NewOptionManager(c, *c.ServiceContent.Setting)
   141  
   142  		opt, err := m.Query(ctx, "VirtualCenter.FQDN")
   143  		if err != nil {
   144  			return err
   145  		}
   146  
   147  		fqdn := opt[0].GetOptionValue().Value.(string)
   148  
   149  		var info object.HostCertificateInfo
   150  		err = info.FromURL(u, nil)
   151  		if err != nil {
   152  			return err
   153  		}
   154  
   155  		u.Path = "/ui/webconsole.html"
   156  
   157  		u.RawQuery = url.Values{
   158  			"vmId":          []string{vm.Reference().Value},
   159  			"vmName":        []string{vm.Name()},
   160  			"serverGuid":    []string{c.ServiceContent.About.InstanceUuid},
   161  			"host":          []string{fqdn},
   162  			"sessionTicket": []string{ticket},
   163  			"thumbprint":    []string{info.ThumbprintSHA1},
   164  		}.Encode()
   165  
   166  		link = u.String()
   167  	} else {
   168  		link = fmt.Sprintf("vmrc://clone:%s@%s/?moid=%s", ticket, u.Hostname(), vm.Reference().Value)
   169  	}
   170  
   171  	fmt.Fprintln(cmd.Out, link)
   172  
   173  	return nil
   174  }