github.com/vmware/govmomi@v0.51.0/cli/library/info.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 library
     6  
     7  import (
     8  	"context"
     9  	"encoding/json"
    10  	"flag"
    11  	"fmt"
    12  	"io"
    13  	"text/tabwriter"
    14  	"time"
    15  
    16  	"github.com/vmware/govmomi/cli"
    17  	"github.com/vmware/govmomi/cli/flags"
    18  	"github.com/vmware/govmomi/object"
    19  	"github.com/vmware/govmomi/units"
    20  	"github.com/vmware/govmomi/vapi/library"
    21  	"github.com/vmware/govmomi/vapi/library/finder"
    22  )
    23  
    24  type info struct {
    25  	*flags.ClientFlag
    26  	*flags.OutputFlag
    27  	*flags.DatacenterFlag
    28  
    29  	long bool
    30  	link bool
    31  	url  bool
    32  	stor bool
    33  	Stor bool
    34  
    35  	pathFinder *finder.PathFinder
    36  }
    37  
    38  func init() {
    39  	cli.Register("library.info", &info{})
    40  }
    41  
    42  func (cmd *info) Register(ctx context.Context, f *flag.FlagSet) {
    43  	cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
    44  	cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
    45  	cmd.ClientFlag.Register(ctx, f)
    46  	cmd.OutputFlag.Register(ctx, f)
    47  	cmd.DatacenterFlag, ctx = flags.NewDatacenterFlag(ctx)
    48  	cmd.DatacenterFlag.Register(ctx, f)
    49  
    50  	f.BoolVar(&cmd.long, "l", false, "Long listing format")
    51  	f.BoolVar(&cmd.link, "L", false, "List Datastore path only")
    52  	f.BoolVar(&cmd.url, "U", false, "List pub/sub URL(s) only")
    53  	f.BoolVar(&cmd.stor, "s", false, "Include file specific storage details")
    54  	if cli.ShowUnreleased() {
    55  		f.BoolVar(&cmd.Stor, "S", false, "Include file specific storage details (resolved)")
    56  	}
    57  }
    58  
    59  func (cmd *info) Process(ctx context.Context) error {
    60  	if err := cmd.ClientFlag.Process(ctx); err != nil {
    61  		return err
    62  	}
    63  	return nil
    64  }
    65  
    66  func (cmd *info) Description() string {
    67  	return `Display library information.
    68  
    69  Note: the '-s' flag only applies to files, not items or the library itself.
    70  
    71  Examples:
    72    govc library.info
    73    govc library.info /lib1
    74    govc library.info -l /lib1 | grep Size:
    75    govc library.info /lib1/item1
    76    govc library.info /lib1/item1/
    77    govc library.info */
    78    govc library.info -L /lib1/item1/file1 # file path relative to Datastore
    79    govc library.info -L -l /lib1/item1/file1 # file path including Datastore
    80    govc library.info -json | jq .
    81    govc library.info -json /lib1/item1 | jq .`
    82  }
    83  
    84  type infoResultsWriter struct {
    85  	Result []finder.FindResult `json:"result"`
    86  	m      *library.Manager
    87  	cmd    *info
    88  	ctx    context.Context
    89  }
    90  
    91  func (r infoResultsWriter) MarshalJSON() ([]byte, error) {
    92  	return json.Marshal(r.Result)
    93  }
    94  
    95  func (r infoResultsWriter) Dump() any {
    96  	res := make([]any, len(r.Result))
    97  	for i := range r.Result {
    98  		res[i] = r.Result[0].GetResult()
    99  	}
   100  	return res
   101  }
   102  
   103  func (r infoResultsWriter) Write(w io.Writer) error {
   104  	if r.cmd.link {
   105  		for _, j := range r.Result {
   106  			p, err := r.cmd.pathFinder.Path(context.Background(), j)
   107  			if err != nil {
   108  				return err
   109  			}
   110  			if !r.cmd.long {
   111  				var path object.DatastorePath
   112  				path.FromString(p)
   113  				p = path.Path
   114  			}
   115  			fmt.Fprintln(w, p)
   116  		}
   117  		return nil
   118  	}
   119  
   120  	tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0)
   121  	defer tw.Flush()
   122  	for _, j := range r.Result {
   123  		switch t := j.GetResult().(type) {
   124  		case library.Library:
   125  			if err := r.writeLibrary(tw, t, j); err != nil {
   126  				return err
   127  			}
   128  		case library.Item:
   129  			if err := r.writeItem(tw, t, j); err != nil {
   130  				return err
   131  			}
   132  		case library.File:
   133  			if err := r.writeFile(tw, t, j); err != nil {
   134  				return err
   135  			}
   136  		}
   137  		tw.Flush()
   138  	}
   139  	return nil
   140  }
   141  
   142  func (r infoResultsWriter) writeLibrary(
   143  	w io.Writer, v library.Library, res finder.FindResult) error {
   144  
   145  	published := v.Publication != nil && *v.Publication.Published
   146  
   147  	if r.cmd.url {
   148  		switch {
   149  		case v.Subscription != nil:
   150  			_, _ = fmt.Fprintf(w, "%s\n", v.Subscription.SubscriptionURL)
   151  		case published:
   152  			_, _ = fmt.Fprintf(w, "%s\n", v.Publication.PublishURL)
   153  		}
   154  
   155  		return nil
   156  	}
   157  
   158  	fmt.Fprintf(w, "Name:\t%s\n", v.Name)
   159  	fmt.Fprintf(w, "  ID:\t%s\n", v.ID)
   160  	fmt.Fprintf(w, "  Path:\t%s\n", res.GetPath())
   161  	if v.Description != nil {
   162  		fmt.Fprintf(w, "  Description:\t%s\n", *v.Description)
   163  	}
   164  	fmt.Fprintf(w, "  Version:\t%s\n", v.Version)
   165  	fmt.Fprintf(w, "  Created:\t%s\n", v.CreationTime.Format(time.ANSIC))
   166  	fmt.Fprintf(w, "  Security Policy ID\t%s\n", v.SecurityPolicyID)
   167  	fmt.Fprintf(w, "  StorageBackings:\t\n")
   168  	for _, d := range v.Storage {
   169  		fmt.Fprintf(w, "    DatastoreID:\t%s\n", d.DatastoreID)
   170  		fmt.Fprintf(w, "    Type:\t%s\n", d.Type)
   171  	}
   172  	if r.cmd.long {
   173  		p, err := r.cmd.pathFinder.Path(r.ctx, res)
   174  		if err != nil {
   175  			return err
   176  		}
   177  		fmt.Fprintf(w, "  Datastore Path:\t%s\n", p)
   178  		items, err := r.m.GetLibraryItems(r.ctx, v.ID)
   179  		if err != nil {
   180  			return err
   181  		}
   182  		var size int64
   183  		for i := range items {
   184  			size += items[i].Size
   185  		}
   186  		fmt.Fprintf(w, "  Size:\t%s\n", units.ByteSize(size))
   187  		fmt.Fprintf(w, "  Items:\t%d\n", len(items))
   188  	}
   189  	if v.Subscription != nil {
   190  		dl := "All"
   191  		if v.Subscription.OnDemand != nil && *v.Subscription.OnDemand {
   192  			dl = "On Demand"
   193  		}
   194  
   195  		fmt.Fprintf(w, "  Subscription:\t\n")
   196  		fmt.Fprintf(w, "    AutoSync:\t%t\n", *v.Subscription.AutomaticSyncEnabled)
   197  		fmt.Fprintf(w, "    URL:\t%s\n", v.Subscription.SubscriptionURL)
   198  		fmt.Fprintf(w, "    Auth:\t%s\n", v.Subscription.AuthenticationMethod)
   199  		fmt.Fprintf(w, "    Download:\t%s\n", dl)
   200  	}
   201  	if published {
   202  		fmt.Fprintf(w, "  Publication:\t\n")
   203  		fmt.Fprintf(w, "    URL:\t%s\n", v.Publication.PublishURL)
   204  		fmt.Fprintf(w, "    Auth:\t%s\n", v.Publication.AuthenticationMethod)
   205  	}
   206  	return nil
   207  }
   208  
   209  func (r infoResultsWriter) writeItem(
   210  	w io.Writer, v library.Item, res finder.FindResult) error {
   211  
   212  	fmt.Fprintf(w, "Name:\t%s\n", v.Name)
   213  	fmt.Fprintf(w, "  ID:\t%s\n", v.ID)
   214  	fmt.Fprintf(w, "  Path:\t%s\n", res.GetPath())
   215  	if v.Description != nil {
   216  		fmt.Fprintf(w, "  Description:\t%s\n", *v.Description)
   217  	}
   218  	fmt.Fprintf(w, "  Type:\t%s\n", v.Type)
   219  	fmt.Fprintf(w, "  Size:\t%s\n", units.ByteSize(v.Size))
   220  	fmt.Fprintf(w, "  Cached:\t%t\n", v.Cached)
   221  	fmt.Fprintf(w, "  Created:\t%s\n", v.CreationTime.Format(time.ANSIC))
   222  	fmt.Fprintf(w, "  Modified:\t%s\n", v.LastModifiedTime.Format(time.ANSIC))
   223  	fmt.Fprintf(w, "  Version:\t%s\n", v.Version)
   224  	if v.SecurityCompliance != nil {
   225  		fmt.Fprintf(w, "  Security Compliance:\t%t\n", *v.SecurityCompliance)
   226  	}
   227  	if v.CertificateVerification != nil {
   228  		fmt.Fprintf(w, "  Certificate Status:\t%s\n", v.CertificateVerification.Status)
   229  	}
   230  	if r.cmd.long {
   231  		p, err := r.cmd.pathFinder.Path(r.ctx, res)
   232  		if err != nil {
   233  			return err
   234  		}
   235  		fmt.Fprintf(w, "  Datastore Path:\t%s\n", p)
   236  	}
   237  
   238  	return nil
   239  }
   240  
   241  func (r infoResultsWriter) writeFile(
   242  	w io.Writer, v library.File, res finder.FindResult) error {
   243  
   244  	size := "-"
   245  	if v.Size != nil {
   246  		size = units.ByteSize(*v.Size).String()
   247  	}
   248  	fmt.Fprintf(w, "Name:\t%s\n", v.Name)
   249  	fmt.Fprintf(w, "  Path:\t%s\n", res.GetPath())
   250  	fmt.Fprintf(w, "  Size:\t%s\n", size)
   251  	fmt.Fprintf(w, "  Version:\t%s\n", v.Version)
   252  
   253  	if r.cmd.long {
   254  		p, err := r.cmd.pathFinder.Path(r.ctx, res)
   255  		if err != nil {
   256  			return err
   257  		}
   258  		fmt.Fprintf(w, "  Datastore Path:\t%s\n", p)
   259  	}
   260  	if r.cmd.stor || r.cmd.Stor {
   261  		label := "Storage URI"
   262  		s, err := r.m.GetLibraryItemStorage(r.ctx, res.GetParent().GetID(), v.Name)
   263  		if err != nil {
   264  			return err
   265  		}
   266  		if r.cmd.Stor {
   267  			label = "Resolved URI"
   268  			err = r.cmd.pathFinder.ResolveLibraryItemStorage(r.ctx, nil, nil, s)
   269  			if err != nil {
   270  				return err
   271  			}
   272  		}
   273  		for i := range s {
   274  			for _, uri := range s[i].StorageURIs {
   275  				fmt.Fprintf(w, "  %s:\t%s\n", label, uri)
   276  			}
   277  		}
   278  	}
   279  
   280  	return nil
   281  }
   282  
   283  func (cmd *info) Run(ctx context.Context, f *flag.FlagSet) error {
   284  	c, err := cmd.RestClient()
   285  	if err != nil {
   286  		return err
   287  	}
   288  	vc, err := cmd.Client()
   289  	if err != nil {
   290  		return err
   291  	}
   292  
   293  	m := library.NewManager(c)
   294  	cmd.pathFinder = finder.NewPathFinder(m, vc)
   295  	finder := finder.NewFinder(m)
   296  	findResults, err := finder.Find(ctx, f.Args()...)
   297  	if err != nil {
   298  		return err
   299  	}
   300  
   301  	return cmd.WriteResult(&infoResultsWriter{findResults, m, cmd, ctx})
   302  }