github.com/vmware/govmomi@v0.43.0/govc/library/info.go (about)

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