github.com/vmware/govmomi@v0.37.2/govc/library/export.go (about)

     1  /*
     2  Copyright (c) 2019 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  	"flag"
    22  	"fmt"
    23  	"io"
    24  	"net/url"
    25  	"os"
    26  	"path/filepath"
    27  	"time"
    28  
    29  	"github.com/vmware/govmomi/govc/cli"
    30  	"github.com/vmware/govmomi/govc/flags"
    31  	"github.com/vmware/govmomi/vapi/library"
    32  	"github.com/vmware/govmomi/vim25/soap"
    33  )
    34  
    35  type export struct {
    36  	*flags.ClientFlag
    37  	*flags.OutputFlag
    38  	library.Item
    39  }
    40  
    41  func init() {
    42  	cli.Register("library.export", &export{})
    43  }
    44  
    45  func (cmd *export) Register(ctx context.Context, f *flag.FlagSet) {
    46  	cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
    47  	cmd.ClientFlag.Register(ctx, f)
    48  
    49  	cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
    50  	cmd.OutputFlag.Register(ctx, f)
    51  }
    52  
    53  func (cmd *export) Usage() string {
    54  	return "PATH [DEST]"
    55  }
    56  
    57  func (cmd *export) Description() string {
    58  	return `Export library items.
    59  
    60  If the given PATH is a library item, all files will be downloaded.
    61  
    62  If the given PATH is a library item file, only that file will be downloaded.
    63  
    64  By default, files are saved using the library item's file names to the current directory.
    65  If DEST is given for a library item, files are saved there instead of the current directory.
    66  If DEST is given for a library item file, the file will be saved with that name.
    67  If DEST is '-', the file contents are written to stdout instead of saving to a file.
    68  
    69  Examples:
    70    govc library.export library_name/item_name
    71    govc library.export library_name/item_name/file_name
    72    govc library.export library_name/item_name/*.ovf -`
    73  }
    74  
    75  func (cmd *export) Process(ctx context.Context) error {
    76  	if err := cmd.ClientFlag.Process(ctx); err != nil {
    77  		return err
    78  	}
    79  	return cmd.OutputFlag.Process(ctx)
    80  }
    81  
    82  func (cmd *export) Run(ctx context.Context, f *flag.FlagSet) error {
    83  	c, err := cmd.RestClient()
    84  	if err != nil {
    85  		return err
    86  	}
    87  	cmd.KeepAlive(c)
    88  
    89  	var names []string
    90  	m := library.NewManager(c)
    91  	res, err := flags.ContentLibraryResult(ctx, c, "", f.Arg(0))
    92  	if err != nil {
    93  		return err
    94  	}
    95  
    96  	switch t := res.GetResult().(type) {
    97  	case library.Item:
    98  		cmd.Item = t
    99  	case library.File:
   100  		names = []string{t.Name}
   101  		cmd.Item = res.GetParent().GetResult().(library.Item)
   102  	default:
   103  		return fmt.Errorf("%q is a %T", f.Arg(0), t)
   104  	}
   105  
   106  	dst := f.Arg(1)
   107  	one := len(names) == 1
   108  	var log io.Writer = os.Stdout
   109  	isStdout := one && dst == "-"
   110  	if isStdout {
   111  		log = io.Discard
   112  	}
   113  
   114  	session, err := m.CreateLibraryItemDownloadSession(ctx, library.Session{
   115  		LibraryItemID: cmd.ID,
   116  	})
   117  	if err != nil {
   118  		return err
   119  	}
   120  
   121  	if len(names) == 0 {
   122  		files, err := m.ListLibraryItemDownloadSessionFile(ctx, session)
   123  		if err != nil {
   124  			return err
   125  		}
   126  
   127  		for _, file := range files {
   128  			names = append(names, file.Name)
   129  		}
   130  	}
   131  
   132  	for _, name := range names {
   133  		_, err = m.PrepareLibraryItemDownloadSessionFile(ctx, session, name)
   134  		if err != nil {
   135  			return err
   136  		}
   137  	}
   138  
   139  	download := func(src *url.URL, name string) error {
   140  		p := soap.DefaultDownload
   141  
   142  		if isStdout {
   143  			s, _, err := c.Download(ctx, src, &p)
   144  			if err != nil {
   145  				return err
   146  			}
   147  			_, err = io.Copy(os.Stdout, s)
   148  			_ = s.Close()
   149  			return err
   150  		}
   151  
   152  		if cmd.OutputFlag.TTY {
   153  			logger := cmd.ProgressLogger(fmt.Sprintf("Downloading %s... ", src.String()))
   154  			defer logger.Wait()
   155  			p.Progress = logger
   156  		}
   157  
   158  		if one && dst != "" {
   159  			name = dst
   160  		} else {
   161  			name = filepath.Join(dst, name)
   162  		}
   163  		return c.DownloadFile(ctx, name, src, &p)
   164  	}
   165  
   166  	for _, name := range names {
   167  		var info *library.DownloadFile
   168  		_, _ = fmt.Fprintf(log, "Checking %s... ", name)
   169  		for {
   170  			info, err = m.GetLibraryItemDownloadSessionFile(ctx, session, name)
   171  			if err != nil {
   172  				return err
   173  			}
   174  			if info.Status == "PREPARED" {
   175  				_, _ = fmt.Fprintln(log, info.Status)
   176  				break // with this status we have a DownloadEndpoint.URI
   177  			}
   178  			time.Sleep(time.Second)
   179  		}
   180  
   181  		src, err := url.Parse(info.DownloadEndpoint.URI)
   182  		if err != nil {
   183  			return err
   184  		}
   185  		err = download(src, name)
   186  		if err != nil {
   187  			return err
   188  		}
   189  	}
   190  
   191  	return nil
   192  }