github.com/vmware/govmomi@v0.37.2/govc/disk/ls.go (about)

     1  /*
     2  Copyright (c) 2018-2023 VMware, Inc. All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package disk
    18  
    19  import (
    20  	"context"
    21  	"flag"
    22  	"fmt"
    23  	"io"
    24  	"strings"
    25  	"text/tabwriter"
    26  	"time"
    27  
    28  	"github.com/vmware/govmomi/govc/cli"
    29  	"github.com/vmware/govmomi/govc/flags"
    30  	"github.com/vmware/govmomi/units"
    31  	"github.com/vmware/govmomi/vim25/soap"
    32  	"github.com/vmware/govmomi/vim25/types"
    33  	"github.com/vmware/govmomi/vslm"
    34  )
    35  
    36  type ls struct {
    37  	*flags.DatastoreFlag
    38  	long     bool
    39  	path     bool
    40  	r        bool
    41  	category string
    42  	tag      string
    43  	tags     bool
    44  }
    45  
    46  func init() {
    47  	cli.Register("disk.ls", &ls{})
    48  }
    49  
    50  func (cmd *ls) Register(ctx context.Context, f *flag.FlagSet) {
    51  	cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
    52  	cmd.DatastoreFlag.Register(ctx, f)
    53  
    54  	f.BoolVar(&cmd.long, "l", false, "Long listing format")
    55  	f.BoolVar(&cmd.path, "L", false, "Print disk backing path instead of disk name")
    56  	f.BoolVar(&cmd.r, "R", false, "Reconcile the datastore inventory info")
    57  	f.StringVar(&cmd.category, "c", "", "Query tag category")
    58  	f.StringVar(&cmd.tag, "t", "", "Query tag name")
    59  	f.BoolVar(&cmd.tags, "T", false, "List attached tags")
    60  }
    61  
    62  func (cmd *ls) Usage() string {
    63  	return "[ID]..."
    64  }
    65  
    66  func (cmd *ls) Description() string {
    67  	return `List disk IDs on DS.
    68  
    69  Examples:
    70    govc disk.ls
    71    govc disk.ls -l -T
    72    govc disk.ls -l e9b06a8b-d047-4d3c-b15b-43ea9608b1a6
    73    govc disk.ls -c k8s-region -t us-west-2`
    74  }
    75  
    76  type VStorageObject struct {
    77  	types.VStorageObject
    78  	Tags []types.VslmTagEntry `json:"tags"`
    79  }
    80  
    81  func (o *VStorageObject) tags() string {
    82  	var tags []string
    83  	for _, tag := range o.Tags {
    84  		tags = append(tags, tag.ParentCategoryName+":"+tag.TagName)
    85  	}
    86  	return strings.Join(tags, ",")
    87  }
    88  
    89  type lsResult struct {
    90  	cmd     *ls
    91  	Objects []VStorageObject `json:"objects"`
    92  }
    93  
    94  func (r *lsResult) Write(w io.Writer) error {
    95  	tw := tabwriter.NewWriter(r.cmd.Out, 2, 0, 2, ' ', 0)
    96  
    97  	for _, o := range r.Objects {
    98  		name := o.Config.Name
    99  		if r.cmd.path {
   100  			if file, ok := o.Config.Backing.(*types.BaseConfigInfoDiskFileBackingInfo); ok {
   101  				name = file.FilePath
   102  			}
   103  		}
   104  		_, _ = fmt.Fprintf(tw, "%s\t%s", o.Config.Id.Id, name)
   105  		if r.cmd.long {
   106  			created := o.Config.CreateTime.Format(time.Stamp)
   107  			size := units.FileSize(o.Config.CapacityInMB * 1024 * 1024)
   108  			_, _ = fmt.Fprintf(tw, "\t%s\t%s", size, created)
   109  		}
   110  		if r.cmd.tags {
   111  			_, _ = fmt.Fprintf(tw, "\t%s", o.tags())
   112  		}
   113  		_, _ = fmt.Fprintln(tw)
   114  	}
   115  
   116  	return tw.Flush()
   117  }
   118  
   119  func (r *lsResult) Dump() interface{} {
   120  	return r.Objects
   121  }
   122  
   123  func (cmd *ls) Run(ctx context.Context, f *flag.FlagSet) error {
   124  	c, err := cmd.Client()
   125  	if err != nil {
   126  		return err
   127  	}
   128  
   129  	ds, err := cmd.Datastore()
   130  	if err != nil {
   131  		return err
   132  	}
   133  
   134  	m := vslm.NewObjectManager(c)
   135  	if cmd.r {
   136  		task, err := m.ReconcileDatastoreInventory(ctx, ds)
   137  		if err != nil {
   138  			return err
   139  		}
   140  		if err = task.Wait(ctx); err != nil {
   141  			return err
   142  		}
   143  	}
   144  	res := lsResult{cmd: cmd}
   145  
   146  	filterNotFound := false
   147  	ids := f.Args()
   148  	if len(ids) == 0 {
   149  		filterNotFound = true
   150  		var oids []types.ID
   151  		if cmd.category == "" {
   152  			oids, err = m.List(ctx, ds)
   153  		} else {
   154  			oids, err = m.ListAttachedObjects(ctx, cmd.category, cmd.tag)
   155  		}
   156  
   157  		if err != nil {
   158  			return err
   159  		}
   160  		for _, id := range oids {
   161  			ids = append(ids, id.Id)
   162  		}
   163  	}
   164  
   165  	for _, id := range ids {
   166  		o, err := m.Retrieve(ctx, ds, id)
   167  		if err != nil {
   168  			if filterNotFound && soap.IsSoapFault(err) {
   169  				fault := soap.ToSoapFault(err).Detail.Fault
   170  				if _, ok := fault.(types.NotFound); ok {
   171  					// The case when an FCD is deleted by something other than DeleteVStorageObject_Task, such as VM destroy
   172  					return fmt.Errorf("%s not found: use 'disk.ls -R' to reconcile datastore inventory", id)
   173  				}
   174  			}
   175  			return fmt.Errorf("retrieve %q: %s", id, err)
   176  		}
   177  
   178  		obj := VStorageObject{VStorageObject: *o}
   179  		if cmd.tags {
   180  			obj.Tags, err = m.ListAttachedTags(ctx, id)
   181  			if err != nil {
   182  				return err
   183  			}
   184  		}
   185  		res.Objects = append(res.Objects, obj)
   186  	}
   187  
   188  	return cmd.WriteResult(&res)
   189  }