github.com/vmware/govmomi@v0.51.0/cli/vm/guest/ps.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 guest
     6  
     7  import (
     8  	"context"
     9  	"flag"
    10  	"fmt"
    11  	"io"
    12  	"strconv"
    13  	"strings"
    14  	"text/tabwriter"
    15  	"time"
    16  
    17  	"github.com/vmware/govmomi/cli"
    18  	"github.com/vmware/govmomi/cli/flags"
    19  	"github.com/vmware/govmomi/vim25/types"
    20  )
    21  
    22  type ps struct {
    23  	*flags.OutputFlag
    24  	*GuestFlag
    25  
    26  	every bool
    27  	exit  bool
    28  	wait  bool
    29  
    30  	pids pidSelector
    31  	uids uidSelector
    32  }
    33  
    34  type pidSelector []int64
    35  
    36  func (s *pidSelector) String() string {
    37  	return fmt.Sprint(*s)
    38  }
    39  
    40  func (s *pidSelector) Set(value string) error {
    41  	v, err := strconv.ParseInt(value, 0, 64)
    42  	if err != nil {
    43  		return err
    44  	}
    45  	*s = append(*s, v)
    46  	return nil
    47  }
    48  
    49  type uidSelector map[string]bool
    50  
    51  func (s uidSelector) String() string {
    52  	return ""
    53  }
    54  
    55  func (s uidSelector) Set(value string) error {
    56  	s[value] = true
    57  	return nil
    58  }
    59  
    60  func init() {
    61  	cli.Register("guest.ps", &ps{})
    62  }
    63  
    64  func (cmd *ps) Register(ctx context.Context, f *flag.FlagSet) {
    65  	cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
    66  	cmd.OutputFlag.Register(ctx, f)
    67  
    68  	cmd.GuestFlag, ctx = newGuestProcessFlag(ctx)
    69  	cmd.GuestFlag.Register(ctx, f)
    70  
    71  	cmd.uids = make(map[string]bool)
    72  	f.BoolVar(&cmd.every, "e", false, "Select all processes")
    73  	f.BoolVar(&cmd.exit, "x", false, "Output exit time and code")
    74  	f.BoolVar(&cmd.wait, "X", false, "Wait for process to exit")
    75  	f.Var(&cmd.pids, "p", "Select by process ID")
    76  	f.Var(&cmd.uids, "U", "Select by process UID")
    77  }
    78  
    79  func (cmd *ps) Process(ctx context.Context) error {
    80  	if err := cmd.OutputFlag.Process(ctx); err != nil {
    81  		return err
    82  	}
    83  	if err := cmd.GuestFlag.Process(ctx); err != nil {
    84  		return err
    85  	}
    86  	return nil
    87  }
    88  
    89  func (cmd *ps) Description() string {
    90  	return `List processes in VM.
    91  
    92  By default, unless the '-e', '-p' or '-U' flag is specified, only processes owned
    93  by the '-l' flag user are displayed.
    94  
    95  The '-x' and '-X' flags only apply to processes started by vmware-tools,
    96  such as those started with the govc guest.start command.
    97  
    98  Examples:
    99    govc guest.ps -vm $name
   100    govc guest.ps -vm $name -e
   101    govc guest.ps -vm $name -p 12345
   102    govc guest.ps -vm $name -U root`
   103  }
   104  
   105  func running(procs []types.GuestProcessInfo) bool {
   106  	for _, p := range procs {
   107  		if p.EndTime == nil {
   108  			return true
   109  		}
   110  	}
   111  	return false
   112  }
   113  
   114  func (cmd *ps) list(ctx context.Context) ([]types.GuestProcessInfo, error) {
   115  	m, err := cmd.ProcessManager()
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	auth := cmd.Auth()
   121  
   122  	for {
   123  		procs, err := m.ListProcesses(ctx, auth, cmd.pids)
   124  		if err != nil {
   125  			return nil, err
   126  		}
   127  
   128  		if cmd.wait && running(procs) {
   129  			<-time.After(time.Second)
   130  			continue
   131  		}
   132  
   133  		return procs, nil
   134  	}
   135  }
   136  
   137  func (cmd *ps) Run(ctx context.Context, f *flag.FlagSet) error {
   138  	procs, err := cmd.list(ctx)
   139  	if err != nil {
   140  		return err
   141  	}
   142  
   143  	r := &psResult{cmd, procs}
   144  
   145  	return cmd.WriteResult(r)
   146  }
   147  
   148  type psResult struct {
   149  	cmd         *ps
   150  	ProcessInfo []types.GuestProcessInfo `json:"processInfo"`
   151  }
   152  
   153  func (r *psResult) Write(w io.Writer) error {
   154  	tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0)
   155  
   156  	fmt.Fprintf(tw, "%s\t%s\t%s", "UID", "PID", "STIME")
   157  	if r.cmd.exit {
   158  		fmt.Fprintf(tw, "\t%s\t%s", "XTIME", "XCODE")
   159  	}
   160  	fmt.Fprint(tw, "\tCMD\n")
   161  
   162  	if len(r.cmd.pids) != 0 {
   163  		r.cmd.every = true
   164  	}
   165  
   166  	if !r.cmd.every && len(r.cmd.uids) == 0 {
   167  		r.cmd.uids[r.cmd.auth.Username] = true
   168  	}
   169  
   170  	for _, p := range r.ProcessInfo {
   171  		if r.cmd.every || r.cmd.uids[p.Owner] {
   172  			fmt.Fprintf(tw, "%s\t%d\t%s", p.Owner, p.Pid, p.StartTime.Format("15:04"))
   173  			if r.cmd.exit {
   174  				etime := "-"
   175  				ecode := "-"
   176  				if p.EndTime != nil {
   177  					etime = p.EndTime.Format("15:04")
   178  					ecode = strconv.Itoa(int(p.ExitCode))
   179  				}
   180  				fmt.Fprintf(tw, "\t%s\t%s", etime, ecode)
   181  			}
   182  			fmt.Fprintf(tw, "\t%s\n", strings.TrimSpace(p.CmdLine))
   183  		}
   184  	}
   185  
   186  	return tw.Flush()
   187  }