tests: upload & test in vCenter. Closes #338

This commit is contained in:
Alexander Todorov 2020-07-30 09:26:13 -04:00 committed by Tom Gundersen
parent 02346faff8
commit 9cce43d384
255 changed files with 127290 additions and 3 deletions

View file

@ -26,6 +26,7 @@ import (
"github.com/osbuild/osbuild-composer/cmd/osbuild-image-tests/azuretest"
"github.com/osbuild/osbuild-composer/cmd/osbuild-image-tests/constants"
"github.com/osbuild/osbuild-composer/cmd/osbuild-image-tests/openstacktest"
"github.com/osbuild/osbuild-composer/cmd/osbuild-image-tests/vmwaretest"
"github.com/osbuild/osbuild-composer/internal/common"
)
@ -331,6 +332,42 @@ func testBootUsingOpenStack(t *testing.T, imagePath string) {
require.NoError(t, err)
}
func testBootUsingVMware(t *testing.T, imagePath string) {
creds, err := vmwaretest.AuthOptionsFromEnv()
// if no credentials are given, fall back to qemu
if (creds == nil) {
log.Print("No vCenter credentials given, falling back to booting using qemu")
log.Printf("Error=%v", err)
testBootUsingQemu(t, imagePath)
return
}
require.NoError(t, err)
// create a random test id to name all the resources used in this test
imageName, err := generateRandomString("osbuild-image-tests-vmware-image-")
require.NoError(t, err)
// the following line should be done by osbuild-composer at some point
err = vmwaretest.ImportImage(creds, imagePath, imageName)
require.NoErrorf(t, err, "Upload to vCenter failed, resources could have been leaked")
// delete the image after the test is over
defer func() {
err = vmwaretest.DeleteImage(creds, imageName)
require.NoErrorf(t, err, "Cannot delete image from vCenter, resources could have been leaked")
}()
// boot the uploaded image and try to connect to it
err = vmwaretest.WithSSHKeyPair(func(privateKey, publicKey string) error {
return vmwaretest.WithBootedImage(creds, imagePath, imageName, publicKey, func(address string) error {
testSSH(t, address, privateKey, nil)
return nil
})
})
require.NoError(t, err)
}
// testBoot tests if the image is able to successfully boot
// Before the test it boots the image respecting the specified bootType.
// The test passes if the function is able to connect to the image via ssh
@ -356,6 +393,9 @@ func testBoot(t *testing.T, imagePath string, bootType string) {
case "openstack":
testBootUsingOpenStack(t, imagePath)
case "vmware":
testBootUsingVMware(t, imagePath)
default:
panic("unknown boot type!")
}

View file

@ -0,0 +1,211 @@
// +build integration
package vmwaretest
import (
"errors"
"os"
"os/exec"
"fmt"
"path/filepath"
// importing the packages registers these cli commands
"github.com/vmware/govmomi/govc/cli"
_ "github.com/vmware/govmomi/govc/datastore"
_ "github.com/vmware/govmomi/govc/importx"
_ "github.com/vmware/govmomi/govc/vm"
_ "github.com/vmware/govmomi/govc/vm/guest"
)
const WaitTimeout = 6000 // in seconds
type AuthOptions struct {
Host string
Username string
Password string
Datacenter string
Cluster string
Network string
Datastore string
Folder string
}
func AuthOptionsFromEnv() (*AuthOptions, error) {
host, hostExists := os.LookupEnv("GOVMOMI_URL")
username, userExists := os.LookupEnv("GOVMOMI_USERNAME")
password, pwdExists := os.LookupEnv("GOVMOMI_PASSWORD")
datacenter, dcExists := os.LookupEnv("GOVMOMI_DATACENTER")
cluster, clusterExists := os.LookupEnv("GOVMOMI_CLUSTER")
network, netExists := os.LookupEnv("GOVMOMI_NETWORK")
datastore, dsExists := os.LookupEnv("GOVMOMI_DATASTORE")
folder, folderExists := os.LookupEnv("GOVMOMI_FOLDER")
// If only one/two of them are not set, then fail
if !hostExists {
return nil, errors.New("GOVMOMI_URL not set")
}
if !userExists {
return nil, errors.New("GOVMOMI_USERNAME not set")
}
if !pwdExists {
return nil, errors.New("GOVMOMI_PASSWORD not set")
}
if !dcExists {
return nil, errors.New("GOVMOMI_DATACENTER not set")
}
if !clusterExists {
return nil, errors.New("GOVMOMI_CLUSTER not set")
}
if !netExists {
return nil, errors.New("GOVMOMI_NETWORK not set")
}
if !dsExists {
return nil, errors.New("GOVMOMI_DATASTORE not set")
}
if !folderExists {
return nil, errors.New("GOVMOMI_FOLDER not set")
}
return &AuthOptions{
Host: host,
Username: username,
Password: password,
Datacenter: datacenter,
Cluster: cluster,
Network: network,
Datastore: datastore,
Folder: folder,
}, nil
}
func ImportImage(creds *AuthOptions, imagePath, imageName string) error {
args := []string{
"import.vmdk",
fmt.Sprintf("-u=%s:%s@%s", creds.Username, creds.Password, creds.Host),
"-k=true",
fmt.Sprintf("-dc=%s", creds.Datacenter),
fmt.Sprintf("-ds=%s", creds.Datastore),
imagePath,
imageName,
}
retcode := cli.Run(args)
if retcode != 0 {
return errors.New("importing vmdk failed")
}
return nil
}
func DeleteImage(creds *AuthOptions, directoryName string) error {
retcode := cli.Run([]string{
"datastore.rm",
"-f=true",
fmt.Sprintf("-u=%s:%s@%s", creds.Username, creds.Password, creds.Host),
"-k=true",
fmt.Sprintf("-dc=%s", creds.Datacenter),
fmt.Sprintf("-ds=%s", creds.Datastore),
directoryName + "*", // because vm.create creates another directory with _1 prefix
})
if retcode != 0 {
return errors.New("deleting directory failed")
}
return nil
}
func WithBootedImage(creds *AuthOptions, imagePath, imageName, publicKey string, f func(address string) error) (retErr error) {
vmdkBaseName := filepath.Base(imagePath)
args := []string{
"vm.create",
fmt.Sprintf("-u=%s:%s@%s", creds.Username, creds.Password, creds.Host),
"-k=true",
fmt.Sprintf("-dc=%s", creds.Datacenter),
fmt.Sprintf("-ds=%s", creds.Datastore),
fmt.Sprintf("-folder=%s", creds.Folder),
fmt.Sprintf("-net=%s", creds.Network),
"-m=2048", "-g=rhel8_64Guest", "-on=true", "-firmware=bios",
fmt.Sprintf("-disk=%s/%s", imageName, vmdkBaseName),
"--disk.controller=ide",
imageName,
}
retcode := cli.Run(args)
if retcode != 0 {
return errors.New("Creating VM from vmdk failed")
}
defer func() {
args = []string{
"vm.destroy",
fmt.Sprintf("-u=%s:%s@%s", creds.Username, creds.Password, creds.Host),
"-k=true",
imageName,
}
retcode := cli.Run(args)
if retcode != 0 {
fmt.Printf("Deleting VM %s failed", imageName)
return
}
}()
// note: by default this will wait/block until an IP address is returned
// note: using exec() instead of running the command b/c .Run() returns an int
ipAddress, err := exec.Command(
"/usr/bin/govc",
"vm.ip",
fmt.Sprintf("-u=%s:%s@%s", creds.Username, creds.Password, creds.Host),
"-k=true",
imageName,
).Output()
if err != nil {
fmt.Println("Getting IP address for VM failed:", string(ipAddress))
return err
}
// Disabled b/c of https://github.com/vmware/govmomi/issues/2054
// upload public key on the VM
//args = []string{
// "guest.mkdir",
// fmt.Sprintf("-u=%s:%s@%s", creds.Username, creds.Password, creds.Host),
// "-k=true",
// fmt.Sprintf("-vm=%s", imageName),
// "-p", "/root/.ssh",
//}
//retcode = cli.Run(args)
//if retcode != 0 {
// return errors.New("mkdir /root/.ssh on VM failed")
//}
//args = []string{
// "guest.upload",
// fmt.Sprintf("-u=%s:%s@%s", creds.Username, creds.Password, creds.Host),
// "-k=true",
// fmt.Sprintf("-vm=%s", imageName),
// "-f=true",
// publicKey, // this is a file path
// "/root/.ssh/authorized_keys",
//}
//retcode = cli.Run(args)
//if retcode != 0 {
// return errors.New("Uploading public key to VM failed")
//}
return f(string(ipAddress))
}
// hard-coded SSH keys b/c we're having troubles uploading publicKey
// to the VM, see https://github.com/vmware/govmomi/issues/2054
func WithSSHKeyPair(f func(privateKey, publicKey string) error) error {
public := "/usr/share/tests/osbuild-composer/keyring/id_rsa.pub"
private := "/usr/share/tests/osbuild-composer/keyring/id_rsa"
return f(private, public)
}

1
go.mod
View file

@ -21,6 +21,7 @@ require (
github.com/kolo/xmlrpc v0.0.0-20190909154602-56d5ec7c422e
github.com/pkg/errors v0.9.1 // indirect
github.com/stretchr/testify v1.4.0
github.com/vmware/govmomi v0.23.0
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4
)

5
go.sum
View file

@ -44,6 +44,7 @@ github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-xdr v0.0.0-20161123171359-e6a2ba005892/go.mod h1:CTDl0pzVzE5DEzZhPfvhY/9sPFMQIxaJ9VAMs9AagrE=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4=
@ -52,6 +53,7 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/uuid v0.0.0-20170306145142-6a5e28554805/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gophercloud/gophercloud v0.11.0 h1:pYMP9UZBdQa3lsfIZ1tZor4EbtxiuB6BHhocenkiH/E=
@ -79,6 +81,9 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/vmware/govmomi v0.23.0 h1:DC97v1FdSr3cPfq3eBKD5C1O4JtYxo+NTcbGTKe2k48=
github.com/vmware/govmomi v0.23.0/go.mod h1:Y+Wq4lst78L85Ge/F8+ORXIWiKYqaro1vhAulACy9Lc=
github.com/vmware/vmw-guestinfo v0.0.0-20170707015358-25eff159a728/go.mod h1:x9oS4Wk2s2u4tS29nEaDLdzvuHdB19CvSGJjPgkZJNk=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g=

View file

@ -45,6 +45,7 @@ BuildRequires: golang(github.com/gobwas/glob)
BuildRequires: golang(github.com/google/go-cmp/cmp)
BuildRequires: golang(github.com/gophercloud/gophercloud)
BuildRequires: golang(github.com/stretchr/testify/assert)
BuildRequires: golang(github.com/vmware/govmomi)
%endif
Requires: %{name}-worker = %{version}-%{release}
@ -222,6 +223,7 @@ Requires: createrepo_c
Requires: genisoimage
Requires: qemu-kvm-core
Requires: systemd-container
Requires: /usr/bin/govc
%ifarch %{arm}
Requires: edk2-aarch64
%endif

View file

@ -1,6 +1,6 @@
{
"boot": {
"type": "qemu"
"type": "vmware"
},
"compose-request": {
"distro": "fedora-31",

View file

@ -1,6 +1,6 @@
{
"boot": {
"type": "qemu"
"type": "vmware"
},
"compose-request": {
"distro": "fedora-32",

View file

@ -1,6 +1,6 @@
{
"boot": {
"type": "qemu"
"type": "vmware"
},
"compose-request": {
"distro": "rhel-8",

4
vendor/github.com/kr/pretty/.gitignore generated vendored Normal file
View file

@ -0,0 +1,4 @@
[568].out
_go*
_test*
_obj

21
vendor/github.com/kr/pretty/License generated vendored Normal file
View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright 2012 Keith Rarick
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

9
vendor/github.com/kr/pretty/Readme generated vendored Normal file
View file

@ -0,0 +1,9 @@
package pretty
import "github.com/kr/pretty"
Package pretty provides pretty-printing for Go values.
Documentation
http://godoc.org/github.com/kr/pretty

265
vendor/github.com/kr/pretty/diff.go generated vendored Normal file
View file

@ -0,0 +1,265 @@
package pretty
import (
"fmt"
"io"
"reflect"
)
type sbuf []string
func (p *sbuf) Printf(format string, a ...interface{}) {
s := fmt.Sprintf(format, a...)
*p = append(*p, s)
}
// Diff returns a slice where each element describes
// a difference between a and b.
func Diff(a, b interface{}) (desc []string) {
Pdiff((*sbuf)(&desc), a, b)
return desc
}
// wprintfer calls Fprintf on w for each Printf call
// with a trailing newline.
type wprintfer struct{ w io.Writer }
func (p *wprintfer) Printf(format string, a ...interface{}) {
fmt.Fprintf(p.w, format+"\n", a...)
}
// Fdiff writes to w a description of the differences between a and b.
func Fdiff(w io.Writer, a, b interface{}) {
Pdiff(&wprintfer{w}, a, b)
}
type Printfer interface {
Printf(format string, a ...interface{})
}
// Pdiff prints to p a description of the differences between a and b.
// It calls Printf once for each difference, with no trailing newline.
// The standard library log.Logger is a Printfer.
func Pdiff(p Printfer, a, b interface{}) {
diffPrinter{w: p}.diff(reflect.ValueOf(a), reflect.ValueOf(b))
}
type Logfer interface {
Logf(format string, a ...interface{})
}
// logprintfer calls Fprintf on w for each Printf call
// with a trailing newline.
type logprintfer struct{ l Logfer }
func (p *logprintfer) Printf(format string, a ...interface{}) {
p.l.Logf(format, a...)
}
// Ldiff prints to l a description of the differences between a and b.
// It calls Logf once for each difference, with no trailing newline.
// The standard library testing.T and testing.B are Logfers.
func Ldiff(l Logfer, a, b interface{}) {
Pdiff(&logprintfer{l}, a, b)
}
type diffPrinter struct {
w Printfer
l string // label
}
func (w diffPrinter) printf(f string, a ...interface{}) {
var l string
if w.l != "" {
l = w.l + ": "
}
w.w.Printf(l+f, a...)
}
func (w diffPrinter) diff(av, bv reflect.Value) {
if !av.IsValid() && bv.IsValid() {
w.printf("nil != %# v", formatter{v: bv, quote: true})
return
}
if av.IsValid() && !bv.IsValid() {
w.printf("%# v != nil", formatter{v: av, quote: true})
return
}
if !av.IsValid() && !bv.IsValid() {
return
}
at := av.Type()
bt := bv.Type()
if at != bt {
w.printf("%v != %v", at, bt)
return
}
switch kind := at.Kind(); kind {
case reflect.Bool:
if a, b := av.Bool(), bv.Bool(); a != b {
w.printf("%v != %v", a, b)
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if a, b := av.Int(), bv.Int(); a != b {
w.printf("%d != %d", a, b)
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
if a, b := av.Uint(), bv.Uint(); a != b {
w.printf("%d != %d", a, b)
}
case reflect.Float32, reflect.Float64:
if a, b := av.Float(), bv.Float(); a != b {
w.printf("%v != %v", a, b)
}
case reflect.Complex64, reflect.Complex128:
if a, b := av.Complex(), bv.Complex(); a != b {
w.printf("%v != %v", a, b)
}
case reflect.Array:
n := av.Len()
for i := 0; i < n; i++ {
w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i))
}
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
if a, b := av.Pointer(), bv.Pointer(); a != b {
w.printf("%#x != %#x", a, b)
}
case reflect.Interface:
w.diff(av.Elem(), bv.Elem())
case reflect.Map:
ak, both, bk := keyDiff(av.MapKeys(), bv.MapKeys())
for _, k := range ak {
w := w.relabel(fmt.Sprintf("[%#v]", k))
w.printf("%q != (missing)", av.MapIndex(k))
}
for _, k := range both {
w := w.relabel(fmt.Sprintf("[%#v]", k))
w.diff(av.MapIndex(k), bv.MapIndex(k))
}
for _, k := range bk {
w := w.relabel(fmt.Sprintf("[%#v]", k))
w.printf("(missing) != %q", bv.MapIndex(k))
}
case reflect.Ptr:
switch {
case av.IsNil() && !bv.IsNil():
w.printf("nil != %# v", formatter{v: bv, quote: true})
case !av.IsNil() && bv.IsNil():
w.printf("%# v != nil", formatter{v: av, quote: true})
case !av.IsNil() && !bv.IsNil():
w.diff(av.Elem(), bv.Elem())
}
case reflect.Slice:
lenA := av.Len()
lenB := bv.Len()
if lenA != lenB {
w.printf("%s[%d] != %s[%d]", av.Type(), lenA, bv.Type(), lenB)
break
}
for i := 0; i < lenA; i++ {
w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i))
}
case reflect.String:
if a, b := av.String(), bv.String(); a != b {
w.printf("%q != %q", a, b)
}
case reflect.Struct:
for i := 0; i < av.NumField(); i++ {
w.relabel(at.Field(i).Name).diff(av.Field(i), bv.Field(i))
}
default:
panic("unknown reflect Kind: " + kind.String())
}
}
func (d diffPrinter) relabel(name string) (d1 diffPrinter) {
d1 = d
if d.l != "" && name[0] != '[' {
d1.l += "."
}
d1.l += name
return d1
}
// keyEqual compares a and b for equality.
// Both a and b must be valid map keys.
func keyEqual(av, bv reflect.Value) bool {
if !av.IsValid() && !bv.IsValid() {
return true
}
if !av.IsValid() || !bv.IsValid() || av.Type() != bv.Type() {
return false
}
switch kind := av.Kind(); kind {
case reflect.Bool:
a, b := av.Bool(), bv.Bool()
return a == b
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
a, b := av.Int(), bv.Int()
return a == b
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
a, b := av.Uint(), bv.Uint()
return a == b
case reflect.Float32, reflect.Float64:
a, b := av.Float(), bv.Float()
return a == b
case reflect.Complex64, reflect.Complex128:
a, b := av.Complex(), bv.Complex()
return a == b
case reflect.Array:
for i := 0; i < av.Len(); i++ {
if !keyEqual(av.Index(i), bv.Index(i)) {
return false
}
}
return true
case reflect.Chan, reflect.UnsafePointer, reflect.Ptr:
a, b := av.Pointer(), bv.Pointer()
return a == b
case reflect.Interface:
return keyEqual(av.Elem(), bv.Elem())
case reflect.String:
a, b := av.String(), bv.String()
return a == b
case reflect.Struct:
for i := 0; i < av.NumField(); i++ {
if !keyEqual(av.Field(i), bv.Field(i)) {
return false
}
}
return true
default:
panic("invalid map key type " + av.Type().String())
}
}
func keyDiff(a, b []reflect.Value) (ak, both, bk []reflect.Value) {
for _, av := range a {
inBoth := false
for _, bv := range b {
if keyEqual(av, bv) {
inBoth = true
both = append(both, av)
break
}
}
if !inBoth {
ak = append(ak, av)
}
}
for _, bv := range b {
inBoth := false
for _, av := range a {
if keyEqual(av, bv) {
inBoth = true
break
}
}
if !inBoth {
bk = append(bk, bv)
}
}
return
}

328
vendor/github.com/kr/pretty/formatter.go generated vendored Normal file
View file

@ -0,0 +1,328 @@
package pretty
import (
"fmt"
"io"
"reflect"
"strconv"
"text/tabwriter"
"github.com/kr/text"
)
type formatter struct {
v reflect.Value
force bool
quote bool
}
// Formatter makes a wrapper, f, that will format x as go source with line
// breaks and tabs. Object f responds to the "%v" formatting verb when both the
// "#" and " " (space) flags are set, for example:
//
// fmt.Sprintf("%# v", Formatter(x))
//
// If one of these two flags is not set, or any other verb is used, f will
// format x according to the usual rules of package fmt.
// In particular, if x satisfies fmt.Formatter, then x.Format will be called.
func Formatter(x interface{}) (f fmt.Formatter) {
return formatter{v: reflect.ValueOf(x), quote: true}
}
func (fo formatter) String() string {
return fmt.Sprint(fo.v.Interface()) // unwrap it
}
func (fo formatter) passThrough(f fmt.State, c rune) {
s := "%"
for i := 0; i < 128; i++ {
if f.Flag(i) {
s += string(i)
}
}
if w, ok := f.Width(); ok {
s += fmt.Sprintf("%d", w)
}
if p, ok := f.Precision(); ok {
s += fmt.Sprintf(".%d", p)
}
s += string(c)
fmt.Fprintf(f, s, fo.v.Interface())
}
func (fo formatter) Format(f fmt.State, c rune) {
if fo.force || c == 'v' && f.Flag('#') && f.Flag(' ') {
w := tabwriter.NewWriter(f, 4, 4, 1, ' ', 0)
p := &printer{tw: w, Writer: w, visited: make(map[visit]int)}
p.printValue(fo.v, true, fo.quote)
w.Flush()
return
}
fo.passThrough(f, c)
}
type printer struct {
io.Writer
tw *tabwriter.Writer
visited map[visit]int
depth int
}
func (p *printer) indent() *printer {
q := *p
q.tw = tabwriter.NewWriter(p.Writer, 4, 4, 1, ' ', 0)
q.Writer = text.NewIndentWriter(q.tw, []byte{'\t'})
return &q
}
func (p *printer) printInline(v reflect.Value, x interface{}, showType bool) {
if showType {
io.WriteString(p, v.Type().String())
fmt.Fprintf(p, "(%#v)", x)
} else {
fmt.Fprintf(p, "%#v", x)
}
}
// printValue must keep track of already-printed pointer values to avoid
// infinite recursion.
type visit struct {
v uintptr
typ reflect.Type
}
func (p *printer) printValue(v reflect.Value, showType, quote bool) {
if p.depth > 10 {
io.WriteString(p, "!%v(DEPTH EXCEEDED)")
return
}
switch v.Kind() {
case reflect.Bool:
p.printInline(v, v.Bool(), showType)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p.printInline(v, v.Int(), showType)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p.printInline(v, v.Uint(), showType)
case reflect.Float32, reflect.Float64:
p.printInline(v, v.Float(), showType)
case reflect.Complex64, reflect.Complex128:
fmt.Fprintf(p, "%#v", v.Complex())
case reflect.String:
p.fmtString(v.String(), quote)
case reflect.Map:
t := v.Type()
if showType {
io.WriteString(p, t.String())
}
writeByte(p, '{')
if nonzero(v) {
expand := !canInline(v.Type())
pp := p
if expand {
writeByte(p, '\n')
pp = p.indent()
}
keys := v.MapKeys()
for i := 0; i < v.Len(); i++ {
showTypeInStruct := true
k := keys[i]
mv := v.MapIndex(k)
pp.printValue(k, false, true)
writeByte(pp, ':')
if expand {
writeByte(pp, '\t')
}
showTypeInStruct = t.Elem().Kind() == reflect.Interface
pp.printValue(mv, showTypeInStruct, true)
if expand {
io.WriteString(pp, ",\n")
} else if i < v.Len()-1 {
io.WriteString(pp, ", ")
}
}
if expand {
pp.tw.Flush()
}
}
writeByte(p, '}')
case reflect.Struct:
t := v.Type()
if v.CanAddr() {
addr := v.UnsafeAddr()
vis := visit{addr, t}
if vd, ok := p.visited[vis]; ok && vd < p.depth {
p.fmtString(t.String()+"{(CYCLIC REFERENCE)}", false)
break // don't print v again
}
p.visited[vis] = p.depth
}
if showType {
io.WriteString(p, t.String())
}
writeByte(p, '{')
if nonzero(v) {
expand := !canInline(v.Type())
pp := p
if expand {
writeByte(p, '\n')
pp = p.indent()
}
for i := 0; i < v.NumField(); i++ {
showTypeInStruct := true
if f := t.Field(i); f.Name != "" {
io.WriteString(pp, f.Name)
writeByte(pp, ':')
if expand {
writeByte(pp, '\t')
}
showTypeInStruct = labelType(f.Type)
}
pp.printValue(getField(v, i), showTypeInStruct, true)
if expand {
io.WriteString(pp, ",\n")
} else if i < v.NumField()-1 {
io.WriteString(pp, ", ")
}
}
if expand {
pp.tw.Flush()
}
}
writeByte(p, '}')
case reflect.Interface:
switch e := v.Elem(); {
case e.Kind() == reflect.Invalid:
io.WriteString(p, "nil")
case e.IsValid():
pp := *p
pp.depth++
pp.printValue(e, showType, true)
default:
io.WriteString(p, v.Type().String())
io.WriteString(p, "(nil)")
}
case reflect.Array, reflect.Slice:
t := v.Type()
if showType {
io.WriteString(p, t.String())
}
if v.Kind() == reflect.Slice && v.IsNil() && showType {
io.WriteString(p, "(nil)")
break
}
if v.Kind() == reflect.Slice && v.IsNil() {
io.WriteString(p, "nil")
break
}
writeByte(p, '{')
expand := !canInline(v.Type())
pp := p
if expand {
writeByte(p, '\n')
pp = p.indent()
}
for i := 0; i < v.Len(); i++ {
showTypeInSlice := t.Elem().Kind() == reflect.Interface
pp.printValue(v.Index(i), showTypeInSlice, true)
if expand {
io.WriteString(pp, ",\n")
} else if i < v.Len()-1 {
io.WriteString(pp, ", ")
}
}
if expand {
pp.tw.Flush()
}
writeByte(p, '}')
case reflect.Ptr:
e := v.Elem()
if !e.IsValid() {
writeByte(p, '(')
io.WriteString(p, v.Type().String())
io.WriteString(p, ")(nil)")
} else {
pp := *p
pp.depth++
writeByte(pp, '&')
pp.printValue(e, true, true)
}
case reflect.Chan:
x := v.Pointer()
if showType {
writeByte(p, '(')
io.WriteString(p, v.Type().String())
fmt.Fprintf(p, ")(%#v)", x)
} else {
fmt.Fprintf(p, "%#v", x)
}
case reflect.Func:
io.WriteString(p, v.Type().String())
io.WriteString(p, " {...}")
case reflect.UnsafePointer:
p.printInline(v, v.Pointer(), showType)
case reflect.Invalid:
io.WriteString(p, "nil")
}
}
func canInline(t reflect.Type) bool {
switch t.Kind() {
case reflect.Map:
return !canExpand(t.Elem())
case reflect.Struct:
for i := 0; i < t.NumField(); i++ {
if canExpand(t.Field(i).Type) {
return false
}
}
return true
case reflect.Interface:
return false
case reflect.Array, reflect.Slice:
return !canExpand(t.Elem())
case reflect.Ptr:
return false
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
return false
}
return true
}
func canExpand(t reflect.Type) bool {
switch t.Kind() {
case reflect.Map, reflect.Struct,
reflect.Interface, reflect.Array, reflect.Slice,
reflect.Ptr:
return true
}
return false
}
func labelType(t reflect.Type) bool {
switch t.Kind() {
case reflect.Interface, reflect.Struct:
return true
}
return false
}
func (p *printer) fmtString(s string, quote bool) {
if quote {
s = strconv.Quote(s)
}
io.WriteString(p, s)
}
func writeByte(w io.Writer, b byte) {
w.Write([]byte{b})
}
func getField(v reflect.Value, i int) reflect.Value {
val := v.Field(i)
if val.Kind() == reflect.Interface && !val.IsNil() {
val = val.Elem()
}
return val
}

3
vendor/github.com/kr/pretty/go.mod generated vendored Normal file
View file

@ -0,0 +1,3 @@
module "github.com/kr/pretty"
require "github.com/kr/text" v0.1.0

108
vendor/github.com/kr/pretty/pretty.go generated vendored Normal file
View file

@ -0,0 +1,108 @@
// Package pretty provides pretty-printing for Go values. This is
// useful during debugging, to avoid wrapping long output lines in
// the terminal.
//
// It provides a function, Formatter, that can be used with any
// function that accepts a format string. It also provides
// convenience wrappers for functions in packages fmt and log.
package pretty
import (
"fmt"
"io"
"log"
"reflect"
)
// Errorf is a convenience wrapper for fmt.Errorf.
//
// Calling Errorf(f, x, y) is equivalent to
// fmt.Errorf(f, Formatter(x), Formatter(y)).
func Errorf(format string, a ...interface{}) error {
return fmt.Errorf(format, wrap(a, false)...)
}
// Fprintf is a convenience wrapper for fmt.Fprintf.
//
// Calling Fprintf(w, f, x, y) is equivalent to
// fmt.Fprintf(w, f, Formatter(x), Formatter(y)).
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, error error) {
return fmt.Fprintf(w, format, wrap(a, false)...)
}
// Log is a convenience wrapper for log.Printf.
//
// Calling Log(x, y) is equivalent to
// log.Print(Formatter(x), Formatter(y)), but each operand is
// formatted with "%# v".
func Log(a ...interface{}) {
log.Print(wrap(a, true)...)
}
// Logf is a convenience wrapper for log.Printf.
//
// Calling Logf(f, x, y) is equivalent to
// log.Printf(f, Formatter(x), Formatter(y)).
func Logf(format string, a ...interface{}) {
log.Printf(format, wrap(a, false)...)
}
// Logln is a convenience wrapper for log.Printf.
//
// Calling Logln(x, y) is equivalent to
// log.Println(Formatter(x), Formatter(y)), but each operand is
// formatted with "%# v".
func Logln(a ...interface{}) {
log.Println(wrap(a, true)...)
}
// Print pretty-prints its operands and writes to standard output.
//
// Calling Print(x, y) is equivalent to
// fmt.Print(Formatter(x), Formatter(y)), but each operand is
// formatted with "%# v".
func Print(a ...interface{}) (n int, errno error) {
return fmt.Print(wrap(a, true)...)
}
// Printf is a convenience wrapper for fmt.Printf.
//
// Calling Printf(f, x, y) is equivalent to
// fmt.Printf(f, Formatter(x), Formatter(y)).
func Printf(format string, a ...interface{}) (n int, errno error) {
return fmt.Printf(format, wrap(a, false)...)
}
// Println pretty-prints its operands and writes to standard output.
//
// Calling Print(x, y) is equivalent to
// fmt.Println(Formatter(x), Formatter(y)), but each operand is
// formatted with "%# v".
func Println(a ...interface{}) (n int, errno error) {
return fmt.Println(wrap(a, true)...)
}
// Sprint is a convenience wrapper for fmt.Sprintf.
//
// Calling Sprint(x, y) is equivalent to
// fmt.Sprint(Formatter(x), Formatter(y)), but each operand is
// formatted with "%# v".
func Sprint(a ...interface{}) string {
return fmt.Sprint(wrap(a, true)...)
}
// Sprintf is a convenience wrapper for fmt.Sprintf.
//
// Calling Sprintf(f, x, y) is equivalent to
// fmt.Sprintf(f, Formatter(x), Formatter(y)).
func Sprintf(format string, a ...interface{}) string {
return fmt.Sprintf(format, wrap(a, false)...)
}
func wrap(a []interface{}, force bool) []interface{} {
w := make([]interface{}, len(a))
for i, x := range a {
w[i] = formatter{v: reflect.ValueOf(x), force: force}
}
return w
}

41
vendor/github.com/kr/pretty/zero.go generated vendored Normal file
View file

@ -0,0 +1,41 @@
package pretty
import (
"reflect"
)
func nonzero(v reflect.Value) bool {
switch v.Kind() {
case reflect.Bool:
return v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() != 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() != 0
case reflect.Float32, reflect.Float64:
return v.Float() != 0
case reflect.Complex64, reflect.Complex128:
return v.Complex() != complex(0, 0)
case reflect.String:
return v.String() != ""
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
if nonzero(getField(v, i)) {
return true
}
}
return false
case reflect.Array:
for i := 0; i < v.Len(); i++ {
if nonzero(v.Index(i)) {
return true
}
}
return false
case reflect.Map, reflect.Interface, reflect.Slice, reflect.Ptr, reflect.Chan, reflect.Func:
return !v.IsNil()
case reflect.UnsafePointer:
return v.Pointer() != 0
}
return true
}

19
vendor/github.com/kr/text/License generated vendored Normal file
View file

@ -0,0 +1,19 @@
Copyright 2012 Keith Rarick
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

3
vendor/github.com/kr/text/Readme generated vendored Normal file
View file

@ -0,0 +1,3 @@
This is a Go package for manipulating paragraphs of text.
See http://go.pkgdoc.org/github.com/kr/text for full documentation.

3
vendor/github.com/kr/text/doc.go generated vendored Normal file
View file

@ -0,0 +1,3 @@
// Package text provides rudimentary functions for manipulating text in
// paragraphs.
package text

3
vendor/github.com/kr/text/go.mod generated vendored Normal file
View file

@ -0,0 +1,3 @@
module "github.com/kr/text"
require "github.com/kr/pty" v1.1.1

74
vendor/github.com/kr/text/indent.go generated vendored Normal file
View file

@ -0,0 +1,74 @@
package text
import (
"io"
)
// Indent inserts prefix at the beginning of each non-empty line of s. The
// end-of-line marker is NL.
func Indent(s, prefix string) string {
return string(IndentBytes([]byte(s), []byte(prefix)))
}
// IndentBytes inserts prefix at the beginning of each non-empty line of b.
// The end-of-line marker is NL.
func IndentBytes(b, prefix []byte) []byte {
var res []byte
bol := true
for _, c := range b {
if bol && c != '\n' {
res = append(res, prefix...)
}
res = append(res, c)
bol = c == '\n'
}
return res
}
// Writer indents each line of its input.
type indentWriter struct {
w io.Writer
bol bool
pre [][]byte
sel int
off int
}
// NewIndentWriter makes a new write filter that indents the input
// lines. Each line is prefixed in order with the corresponding
// element of pre. If there are more lines than elements, the last
// element of pre is repeated for each subsequent line.
func NewIndentWriter(w io.Writer, pre ...[]byte) io.Writer {
return &indentWriter{
w: w,
pre: pre,
bol: true,
}
}
// The only errors returned are from the underlying indentWriter.
func (w *indentWriter) Write(p []byte) (n int, err error) {
for _, c := range p {
if w.bol {
var i int
i, err = w.w.Write(w.pre[w.sel][w.off:])
w.off += i
if err != nil {
return n, err
}
}
_, err = w.w.Write([]byte{c})
if err != nil {
return n, err
}
n++
w.bol = c == '\n'
if w.bol {
w.off = 0
if w.sel < len(w.pre)-1 {
w.sel++
}
}
}
return n, nil
}

86
vendor/github.com/kr/text/wrap.go generated vendored Normal file
View file

@ -0,0 +1,86 @@
package text
import (
"bytes"
"math"
)
var (
nl = []byte{'\n'}
sp = []byte{' '}
)
const defaultPenalty = 1e5
// Wrap wraps s into a paragraph of lines of length lim, with minimal
// raggedness.
func Wrap(s string, lim int) string {
return string(WrapBytes([]byte(s), lim))
}
// WrapBytes wraps b into a paragraph of lines of length lim, with minimal
// raggedness.
func WrapBytes(b []byte, lim int) []byte {
words := bytes.Split(bytes.Replace(bytes.TrimSpace(b), nl, sp, -1), sp)
var lines [][]byte
for _, line := range WrapWords(words, 1, lim, defaultPenalty) {
lines = append(lines, bytes.Join(line, sp))
}
return bytes.Join(lines, nl)
}
// WrapWords is the low-level line-breaking algorithm, useful if you need more
// control over the details of the text wrapping process. For most uses, either
// Wrap or WrapBytes will be sufficient and more convenient.
//
// WrapWords splits a list of words into lines with minimal "raggedness",
// treating each byte as one unit, accounting for spc units between adjacent
// words on each line, and attempting to limit lines to lim units. Raggedness
// is the total error over all lines, where error is the square of the
// difference of the length of the line and lim. Too-long lines (which only
// happen when a single word is longer than lim units) have pen penalty units
// added to the error.
func WrapWords(words [][]byte, spc, lim, pen int) [][][]byte {
n := len(words)
length := make([][]int, n)
for i := 0; i < n; i++ {
length[i] = make([]int, n)
length[i][i] = len(words[i])
for j := i + 1; j < n; j++ {
length[i][j] = length[i][j-1] + spc + len(words[j])
}
}
nbrk := make([]int, n)
cost := make([]int, n)
for i := range cost {
cost[i] = math.MaxInt32
}
for i := n - 1; i >= 0; i-- {
if length[i][n-1] <= lim || i == n-1 {
cost[i] = 0
nbrk[i] = n
} else {
for j := i + 1; j < n; j++ {
d := lim - length[i][j-1]
c := d*d + cost[j]
if length[i][j-1] > lim {
c += pen // too-long lines get a worse penalty
}
if c < cost[i] {
cost[i] = c
nbrk[i] = j
}
}
}
}
var lines [][][]byte
i := 0
for i < n {
lines = append(lines, words[i:nbrk[i]])
i = nbrk[i]
}
return lines
}

168
vendor/github.com/vmware/govmomi/CONTRIBUTORS generated vendored Normal file
View file

@ -0,0 +1,168 @@
# People who can (and typically have) contributed to this repository.
#
# This script is generated by contributors.sh
#
Abhijeet Kasurde <akasurde@redhat.com>
abrarshivani <abrarshivani@users.noreply.github.com>
Adam Shannon <adamkshannon@gmail.com>
Al Biheiri <abiheiri@apple.com>
Alessandro Cortiana <alessandro.cortiana@gmail.com>
Alex Bozhenko <alexbozhenko@fb.com>
Alex Ellis (VMware) <alexellis2@gmail.com>
Alex <puzo2002@gmail.com>
Alvaro Miranda <kikitux@gmail.com>
Amanda H. L. de Andrade <amanda.andrade@serpro.gov.br>
Amit Bathla <abathla@.vmware.com>
amit bezalel <amit.bezalel@hpe.com>
Andrew <AndrewDi@users.noreply.github.com>
Andrew Chin <andrew@andrewtchin.com>
Andrew Kutz <akutz@vmware.com>
Andrey Klimentyev <andrey.klimentyev@flant.com>
Anfernee Yongkun Gui <agui@vmware.com>
angystardust <angystardust@users.noreply.github.com>
aniketGslab <aniket.shinde@gslab.com>
Ankit Vaidya <vaidyaa@vmware.com>
Anna Carrigan <anna.carrigan@hpe.com>
Arran Walker <arran.walker@zopa.com>
Artem Anisimov <aanisimov@inbox.ru>
Aryeh Weinreb <aryehweinreb@gmail.com>
Austin Parker <aparker@apprenda.com>
Balu Dontu <bdontu@vmware.com>
bastienbc <bastien.barbe.creuly@gmail.com>
Ben Corrie <bcorrie@vmware.com>
Benjamin Davini <davinib@vmware.com>
Benjamin Peterson <benjamin@python.org>
Bob Killen <killen.bob@gmail.com>
Brad Fitzpatrick <bradfitz@golang.org>
Bruce Downs <bruceadowns@gmail.com>
Cédric Blomart <cblomart@gmail.com>
Cheng Cheng <chengch@vmware.com>
Chethan Venkatesh <chethanv@vmware.com>
Chris Marchesi <chrism@vancluevertech.com>
Christian Höltje <docwhat@gerf.org>
Clint Greenwood <cgreenwood@vmware.com>
CuiHaozhi <cuihaozhi@chinacloud.com.cn>
Daniel Mueller <deso@posteo.net>
Dan Ilan <danilan@google.com>
Danny Lockard <danny.lockard@banno.com>
Dave Gress <gressd@vmware.com>
Dave Smith-Uchida <dsmithuchida@vmware.com>
Dave Tucker <dave@dtucker.co.uk>
Davide Agnello <dagnello@hp.com>
David Gress <gressd@vmware.com>
David Stark <dave@davidstark.name>
Davinder Kumar <davinderk@vmware.com>
demarey <christophe.demarey@inria.fr>
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Deric Crago <deric.crago@gmail.com>
Divyen Patel <divyenp@vmware.com>
Dnyanesh Gate <dnyanesh.gate@druva.com>
Doug MacEachern <dougm@vmware.com>
Eloy Coto <eloy.coto@gmail.com>
Eric Edens <ericedens@google.com>
Eric Graham <16710890+Pheric@users.noreply.github.com>
Eric Gray <egray@vmware.com>
Eric Yutao <eric.yutao@gmail.com>
Erik Hollensbe <github@hollensbe.org>
Ethan Kaley <ethan.kaley@emc.com>
Evan Chu <echu@vmware.com>
Fabio Rapposelli <fabio@vmware.com>
Faiyaz Ahmed <faiyaza@vmware.com>
Federico Pellegatta <12744504+federico-pellegatta@users.noreply.github.com>
forkbomber <forkbomber@users.noreply.github.com>
François Rigault <rigault.francois@gmail.com>
freebsdly <qinhuajun@outlook.com>
Gavin Gray <gavin@infinio.com>
Gavrie Philipson <gavrie.philipson@elastifile.com>
George Hicken <ghicken@vmware.com>
Gerrit Renker <Gerrit.Renker@ctl.io>
gthombare <gthombare@vmware.com>
Hasan Mahmood <mahmoodh@vmware.com>
Henrik Hodne <henrik@travis-ci.com>
hkumar <hkumar@vmware.com>
hui luo <luoh@vmware.com>
Isaac Rodman <isaac@eyz.us>
Ivan Mikushin <imikushin@vmware.com>
Ivan Porto Carrero <icarrero@vmware.com>
James King <james.king@emc.com>
Jason Kincl <jkincl@gmail.com>
Jeremy Canady <jcanady@jackhenry.com>
jeremy-clerc <jeremy@clerc.io>
Jiatong Wang <wjiatong@vmware.com>
jingyizPensando <jingyiz@pensando.io>
João Pereira <joaodrp@gmail.com>
Jonas Ausevicius <jonas.ausevicius@virtustream.com>
Jorge Sevilla <jorge.sevilla@rstor.io>
kayrus <kay.diam@gmail.com>
Kevin George <georgek@vmware.com>
leslie-qiwa <leslie.qiwa@gmail.com>
Lintong Jiang <lintongj@vmware.com>
Liping Xue <lipingx@vmware.com>
Louie Jiang <jiangl@vmware.com>
Luther Monson <luther.monson@gmail.com>
maplain <fangyuanl@vmware.com>
Marc Carmier <mcarmier@gmail.com>
Marcus Tan <marcus.tan@rubrik.com>
Maria Ntalla <maria.ntalla@gmail.com>
Marin Atanasov Nikolov <mnikolov@vmware.com>
Mario Trangoni <mjtrangoni@gmail.com>
Mark Peek <markpeek@vmware.com>
Matt Clay <matt@mystile.com>
Matthew Cosgrove <matthew.cosgrove@dell.com>
Matt Moore <mattmoor@vmware.com>
Matt Moriarity <matt@mattmoriarity.com>
Mevan Samaratunga <mevansam@gmail.com>
Michal Jankowski <mjankowski@vmware.com>
mingwei <mingwei@smartx.com>
Nicolas Lamirault <nicolas.lamirault@gmail.com>
Omar Kohl <omarkohl@gmail.com>
Parham Alvani <parham.alvani@gmail.com>
Pierre Gronlier <pierre.gronlier@corp.ovh.com>
Pieter Noordhuis <pnoordhuis@vmware.com>
prydin <prydin@vmware.com>
rHermes <teodor_spaeren@riseup.net>
Rowan Jacobs <rojacobs@pivotal.io>
rsikdar <rsikdar@berkeley.edu>
runner.mei <runner.mei@gmail.com>
Sandeep Pissay Srinivasa Rao <ssrinivas@vmware.com>
S.Çağlar Onur <conur@vmware.com>
Sergey Ignatov <sergey.ignatov@jetbrains.com>
serokles <timbo.alexander@gmail.com>
Shalini Bhaskara <sbhaskara@vmware.com>
Shawn Neal <sneal@sneal.net>
shylasrinivas <sshyla@vmware.com>
sky-joker <sky.jokerxx@gmail.com>
Sten Feldman <exile@chamber.ee>
Stepan Mazurov <smazurov@gmail.com>
Steve Purcell <steve@sanityinc.com>
SUMIT AGRAWAL <asumit@vmware.com>
Takaaki Furukawa <takaaki.frkw@gmail.com>
Tamas Eger <tamas.eger@bitrise.io>
tanishi <tanishi503@gmail.com>
Ted Zlatanov <tzz@lifelogs.com>
Thad Craft <tcraft@pivotal.io>
Thibaut Ackermann <thibaut.ackermann@alcatel-lucent.com>
Tim McNamara <tim.mcnamara@canonical.com>
Tjeu Kayim <15987676+TjeuKayim@users.noreply.github.com>
Toomas Pelberg <toomas.pelberg@playtech.com>
Trevor Dawe <trevor.dawe@gmail.com>
tshihad <tshihad9@gmail.com>
Uwe Bessle <Uwe.Bessle@iteratec.de>
Vadim Egorov <vegorov@vmware.com>
Vikram Krishnamurthy <vikramkrishnamu@vmware.com>
volanja <volaaanja@gmail.com>
Volodymyr Bobyr <pupsua@gmail.com>
Waldek Maleska <w.maleska@gmail.com>
William Lam <info.virtuallyghetto@gmail.com>
Witold Krecicki <wpk@culm.net>
xing-yang <xingyang105@gmail.com>
yangxi <yangxi@vmware.com>
Yang Yang <yangy@vmware.com>
Yann Hodique <yhodique@google.com>
ykakarap <yuva2811@gmail.com>
Yuya Kusakabe <yuya.kusakabe@gmail.com>
Zacharias Taubert <zacharias.taubert@gmail.com>
Zach Tucker <ztucker@vmware.com>
Zee Yang <zeey@vmware.com>
zyuxin <zyuxin@vmware.com>

202
vendor/github.com/vmware/govmomi/LICENSE.txt generated vendored Normal file
View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

37
vendor/github.com/vmware/govmomi/find/doc.go generated vendored Normal file
View file

@ -0,0 +1,37 @@
/*
Copyright (c) 2014-2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Package find implements inventory listing and searching.
The Finder is an alternative to the object.SearchIndex FindByInventoryPath() and FindChild() methods.
SearchIndex.FindByInventoryPath requires an absolute path, whereas the Finder also supports relative paths
and patterns via path.Match.
SearchIndex.FindChild requires a parent to find the child, whereas the Finder also supports an ancestor via
recursive object traversal.
The various Finder methods accept a "path" argument, which can absolute or relative to the Folder for the object type.
The Finder supports two modes, "list" and "find". The "list" mode behaves like the "ls" command, only searching within
the immediate path. The "find" mode behaves like the "find" command, with the search starting at the immediate path but
also recursing into sub Folders relative to the Datacenter. The default mode is "list" if the given path contains a "/",
otherwise "find" mode is used.
The exception is to use a "..." wildcard with a path to find all objects recursively underneath any root object.
For example: VirtualMachineList("/DC1/...")
See also: https://github.com/vmware/govmomi/blob/master/govc/README.md#usage
*/
package find

64
vendor/github.com/vmware/govmomi/find/error.go generated vendored Normal file
View file

@ -0,0 +1,64 @@
/*
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package find
import "fmt"
type NotFoundError struct {
kind string
path string
}
func (e *NotFoundError) Error() string {
return fmt.Sprintf("%s '%s' not found", e.kind, e.path)
}
type MultipleFoundError struct {
kind string
path string
}
func (e *MultipleFoundError) Error() string {
return fmt.Sprintf("path '%s' resolves to multiple %ss", e.path, e.kind)
}
type DefaultNotFoundError struct {
kind string
}
func (e *DefaultNotFoundError) Error() string {
return fmt.Sprintf("no default %s found", e.kind)
}
type DefaultMultipleFoundError struct {
kind string
}
func (e DefaultMultipleFoundError) Error() string {
return fmt.Sprintf("default %s resolves to multiple instances, please specify", e.kind)
}
func toDefaultError(err error) error {
switch e := err.(type) {
case *NotFoundError:
return &DefaultNotFoundError{e.kind}
case *MultipleFoundError:
return &DefaultMultipleFoundError{e.kind}
default:
return err
}
}

1058
vendor/github.com/vmware/govmomi/find/finder.go generated vendored Normal file

File diff suppressed because it is too large Load diff

253
vendor/github.com/vmware/govmomi/find/recurser.go generated vendored Normal file
View file

@ -0,0 +1,253 @@
/*
Copyright (c) 2014-2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package find
import (
"context"
"os"
"path"
"strings"
"github.com/vmware/govmomi/list"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/vim25/mo"
)
// spec is used to specify per-search configuration, independent of the Finder instance.
type spec struct {
// Relative returns the root object to resolve Relative paths (starts with ".")
Relative func(ctx context.Context) (object.Reference, error)
// ListMode can be used to optionally force "ls" behavior, rather than "find" behavior
ListMode *bool
// Contents configures the Recurser to list the Contents of traversable leaf nodes.
// This is typically set to true when used from the ls command, where listing
// a folder means listing its Contents. This is typically set to false for
// commands that take managed entities that are not folders as input.
Contents bool
// Parents specifies the types which can contain the child types being searched for.
// for example, when searching for a HostSystem, parent types can be
// "ComputeResource" or "ClusterComputeResource".
Parents []string
// Include specifies which types to be included in the results, used only in "find" mode.
Include []string
// Nested should be set to types that can be Nested, used only in "find" mode.
Nested []string
// ChildType avoids traversing into folders that can't contain the Include types, used only in "find" mode.
ChildType []string
}
func (s *spec) traversable(o mo.Reference) bool {
ref := o.Reference()
switch ref.Type {
case "Datacenter":
if len(s.Include) == 1 && s.Include[0] == "Datacenter" {
// No point in traversing deeper as Datacenters cannot be nested
return false
}
return true
case "Folder":
if f, ok := o.(mo.Folder); ok {
// TODO: Not making use of this yet, but here we can optimize when searching the entire
// inventory across Datacenters for specific types, for example: 'govc ls -t VirtualMachine /**'
// should not traverse into a Datacenter's host, network or datatore folders.
if !s.traversableChildType(f.ChildType) {
return false
}
}
return true
}
for _, kind := range s.Parents {
if kind == ref.Type {
return true
}
}
return false
}
func (s *spec) traversableChildType(ctypes []string) bool {
if len(s.ChildType) == 0 {
return true
}
for _, t := range ctypes {
for _, c := range s.ChildType {
if t == c {
return true
}
}
}
return false
}
func (s *spec) wanted(e list.Element) bool {
if len(s.Include) == 0 {
return true
}
w := e.Object.Reference().Type
for _, kind := range s.Include {
if w == kind {
return true
}
}
return false
}
// listMode is a global option to revert to the original Finder behavior,
// disabling the newer "find" mode.
var listMode = os.Getenv("GOVMOMI_FINDER_LIST_MODE") == "true"
func (s *spec) listMode(isPath bool) bool {
if listMode {
return true
}
if s.ListMode != nil {
return *s.ListMode
}
return isPath
}
type recurser struct {
Collector *property.Collector
// All configures the recurses to fetch complete objects for leaf nodes.
All bool
}
func (r recurser) List(ctx context.Context, s *spec, root list.Element, parts []string) ([]list.Element, error) {
if len(parts) == 0 {
// Include non-traversable leaf elements in result. For example, consider
// the pattern "./vm/my-vm-*", where the pattern should match the VMs and
// not try to traverse them.
//
// Include traversable leaf elements in result, if the contents
// field is set to false.
//
if !s.Contents || !s.traversable(root.Object.Reference()) {
return []list.Element{root}, nil
}
}
k := list.Lister{
Collector: r.Collector,
Reference: root.Object.Reference(),
Prefix: root.Path,
}
if r.All && len(parts) < 2 {
k.All = true
}
in, err := k.List(ctx)
if err != nil {
return nil, err
}
// This folder is a leaf as far as the glob goes.
if len(parts) == 0 {
return in, nil
}
all := parts
pattern := parts[0]
parts = parts[1:]
var out []list.Element
for _, e := range in {
matched, err := path.Match(pattern, path.Base(e.Path))
if err != nil {
return nil, err
}
if !matched {
matched = strings.HasSuffix(e.Path, "/"+path.Join(all...))
if matched {
// name contains a '/'
out = append(out, e)
}
continue
}
nres, err := r.List(ctx, s, e, parts)
if err != nil {
return nil, err
}
out = append(out, nres...)
}
return out, nil
}
func (r recurser) Find(ctx context.Context, s *spec, root list.Element, parts []string) ([]list.Element, error) {
var out []list.Element
if len(parts) > 0 {
pattern := parts[0]
matched, err := path.Match(pattern, path.Base(root.Path))
if err != nil {
return nil, err
}
if matched && s.wanted(root) {
out = append(out, root)
}
}
if !s.traversable(root.Object) {
return out, nil
}
k := list.Lister{
Collector: r.Collector,
Reference: root.Object.Reference(),
Prefix: root.Path,
}
in, err := k.List(ctx)
if err != nil {
return nil, err
}
for _, e := range in {
nres, err := r.Find(ctx, s, e, parts)
if err != nil {
return nil, err
}
out = append(out, nres...)
}
return out, nil
}

199
vendor/github.com/vmware/govmomi/govc/cli/command.go generated vendored Normal file
View file

@ -0,0 +1,199 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cli
import (
"context"
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"sort"
"strings"
"text/tabwriter"
"github.com/vmware/govmomi/vim25/types"
)
type HasFlags interface {
// Register may be called more than once and should be idempotent.
Register(ctx context.Context, f *flag.FlagSet)
// Process may be called more than once and should be idempotent.
Process(ctx context.Context) error
}
type Command interface {
HasFlags
Run(ctx context.Context, f *flag.FlagSet) error
}
func generalHelp(w io.Writer, filter string) {
var cmds, matches []string
for name := range commands {
cmds = append(cmds, name)
if filter != "" && strings.Contains(name, filter) {
matches = append(matches, name)
}
}
if len(matches) == 0 {
fmt.Fprintf(w, "Usage of %s:\n", os.Args[0])
} else {
fmt.Fprintf(w, "%s: command '%s' not found, did you mean:\n", os.Args[0], filter)
cmds = matches
}
sort.Strings(cmds)
for _, name := range cmds {
fmt.Fprintf(w, " %s\n", name)
}
}
func commandHelp(w io.Writer, name string, cmd Command, f *flag.FlagSet) {
type HasUsage interface {
Usage() string
}
fmt.Fprintf(w, "Usage: %s %s [OPTIONS]", os.Args[0], name)
if u, ok := cmd.(HasUsage); ok {
fmt.Fprintf(w, " %s", u.Usage())
}
fmt.Fprintf(w, "\n")
type HasDescription interface {
Description() string
}
if u, ok := cmd.(HasDescription); ok {
fmt.Fprintf(w, "\n%s\n", u.Description())
}
n := 0
f.VisitAll(func(_ *flag.Flag) {
n += 1
})
if n > 0 {
fmt.Fprintf(w, "\nOptions:\n")
tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0)
f.VisitAll(func(f *flag.Flag) {
fmt.Fprintf(tw, "\t-%s=%s\t%s\n", f.Name, f.DefValue, f.Usage)
})
tw.Flush()
}
}
func clientLogout(ctx context.Context, cmd Command) error {
type logout interface {
Logout(context.Context) error
}
if l, ok := cmd.(logout); ok {
return l.Logout(ctx)
}
return nil
}
func Run(args []string) int {
hw := os.Stderr
rc := 1
hwrc := func(arg string) {
if arg == "-h" {
hw = os.Stdout
rc = 0
}
}
var err error
if len(args) == 0 {
generalHelp(hw, "")
return rc
}
// Look up real command name in aliases table.
name, ok := aliases[args[0]]
if !ok {
name = args[0]
}
cmd, ok := commands[name]
if !ok {
hwrc(name)
generalHelp(hw, name)
return rc
}
fs := flag.NewFlagSet("", flag.ContinueOnError)
fs.SetOutput(ioutil.Discard)
ctx := context.Background()
if id := os.Getenv("GOVC_OPERATION_ID"); id != "" {
ctx = context.WithValue(ctx, types.ID{}, id)
}
cmd.Register(ctx, fs)
if err = fs.Parse(args[1:]); err != nil {
goto error
}
if err = cmd.Process(ctx); err != nil {
goto error
}
if err = cmd.Run(ctx, fs); err != nil {
goto error
}
if err = clientLogout(ctx, cmd); err != nil {
goto error
}
return 0
error:
if err == flag.ErrHelp {
if len(args) == 2 {
hwrc(args[1])
}
commandHelp(hw, args[0], cmd, fs)
} else {
if x, ok := err.(interface{ ExitCode() int }); ok {
// propagate exit code, e.g. from guest.run
rc = x.ExitCode()
} else {
w, ok := cmd.(interface{ WriteError(error) bool })
if ok {
ok = w.WriteError(err)
}
if !ok {
fmt.Fprintf(os.Stderr, "%s: %s\n", os.Args[0], err)
}
}
}
_ = clientLogout(ctx, cmd)
return rc
}

43
vendor/github.com/vmware/govmomi/govc/cli/register.go generated vendored Normal file
View file

@ -0,0 +1,43 @@
/*
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cli
import "os"
var commands = map[string]Command{}
var aliases = map[string]string{}
// hideUnreleased allows commands to be compiled into the govc binary without being registered by default.
// Unreleased commands are omitted from 'govc -h' help text and the generated govc/USAGE.md
// Setting the env var GOVC_SHOW_UNRELEASED=true enables any commands registered as unreleased.
var hideUnreleased = os.Getenv("GOVC_SHOW_UNRELEASED") != "true"
func Register(name string, c Command, unreleased ...bool) {
if len(unreleased) != 0 && unreleased[0] && hideUnreleased {
return
}
commands[name] = c
}
func Alias(name string, alias string) {
aliases[alias] = name
}
func Commands() map[string]Command {
return commands
}

152
vendor/github.com/vmware/govmomi/govc/datastore/cp.go generated vendored Normal file
View file

@ -0,0 +1,152 @@
/*
Copyright (c) 2014-2018 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package datastore
import (
"context"
"flag"
"fmt"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/object"
)
type cp struct {
target
}
func init() {
cli.Register("datastore.cp", &cp{})
}
type target struct {
*flags.DatastoreFlag // The source Datastore and the default target Datastore
dc *flags.DatacenterFlag // Optionally target a different Datacenter
ds *flags.DatastoreFlag // Optionally target a different Datastore
kind bool
force bool
}
func (cmd *target) FileManager() (*object.DatastoreFileManager, error) {
dc, err := cmd.Datacenter()
if err != nil {
return nil, err
}
ds, err := cmd.Datastore()
if err != nil {
return nil, err
}
m := ds.NewFileManager(dc, cmd.force)
dc, err = cmd.dc.Datacenter()
if err != nil {
return nil, err
}
m.DatacenterTarget = dc
return m, nil
}
func (cmd *target) Register(ctx context.Context, f *flag.FlagSet) {
cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
cmd.DatastoreFlag.Register(ctx, f)
cmd.dc = &flags.DatacenterFlag{
OutputFlag: cmd.OutputFlag,
ClientFlag: cmd.ClientFlag,
}
f.StringVar(&cmd.dc.Name, "dc-target", "", "Datacenter destination (defaults to -dc)")
cmd.ds = &flags.DatastoreFlag{
DatacenterFlag: cmd.dc,
}
f.StringVar(&cmd.ds.Name, "ds-target", "", "Datastore destination (defaults to -ds)")
f.BoolVar(&cmd.kind, "t", true, "Use file type to choose disk or file manager")
f.BoolVar(&cmd.force, "f", false, "If true, overwrite any identically named file at the destination")
}
func (cmd *target) Process(ctx context.Context) error {
if err := cmd.DatastoreFlag.Process(ctx); err != nil {
return err
}
if cmd.dc.Name == "" {
// Use source DC as target DC
cmd.dc = cmd.DatacenterFlag
cmd.ds.DatacenterFlag = cmd.dc
}
if cmd.ds.Name == "" {
// Use source DS as target DS
cmd.ds.Name = cmd.DatastoreFlag.Name
}
return nil
}
func (cmd *cp) Usage() string {
return "SRC DST"
}
func (cmd *cp) Description() string {
return `Copy SRC to DST on DATASTORE.
Examples:
govc datastore.cp foo/foo.vmx foo/foo.vmx.old
govc datastore.cp -f my.vmx foo/foo.vmx
govc datastore.cp disks/disk1.vmdk disks/disk2.vmdk
govc datastore.cp disks/disk1.vmdk -dc-target DC2 disks/disk2.vmdk
govc datastore.cp disks/disk1.vmdk -ds-target NFS-2 disks/disk2.vmdk`
}
func (cmd *cp) Run(ctx context.Context, f *flag.FlagSet) error {
args := f.Args()
if len(args) != 2 {
return flag.ErrHelp
}
m, err := cmd.FileManager()
if err != nil {
return err
}
src, err := cmd.DatastorePath(args[0])
if err != nil {
return err
}
dst, err := cmd.target.ds.DatastorePath(args[1])
if err != nil {
return err
}
cp := m.CopyFile
if cmd.kind {
cp = m.Copy
}
logger := cmd.ProgressLogger(fmt.Sprintf("Copying %s to %s...", src, dst))
defer logger.Wait()
return cp(m.WithProgress(ctx, logger), src, dst)
}

View file

@ -0,0 +1,326 @@
/*
Copyright (c) 2015-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package datastore
import (
"context"
"errors"
"flag"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
)
type create struct {
*flags.HostSystemFlag
// Generic options
Type typeFlag
Name string
Force bool
// Options for NAS
RemoteHost string
RemotePath string
AccessMode string
UserName string
Password string
// Options for VMFS
DiskCanonicalName string
Version *int32
// Options for local
Path string
}
func init() {
cli.Register("datastore.create", &create{})
}
var nasTypes = []string{
string(types.HostFileSystemVolumeFileSystemTypeNFS),
string(types.HostFileSystemVolumeFileSystemTypeNFS41),
string(types.HostFileSystemVolumeFileSystemTypeCIFS),
}
var vmfsTypes = []string{
string(types.HostFileSystemVolumeFileSystemTypeVMFS),
}
var localTypes = []string{
"local",
}
var allTypes = []string{}
func init() {
allTypes = append(allTypes, nasTypes...)
allTypes = append(allTypes, vmfsTypes...)
allTypes = append(allTypes, localTypes...)
}
type typeFlag string
func (t *typeFlag) Set(s string) error {
s = strings.ToLower(s)
for _, e := range allTypes {
if s == strings.ToLower(e) {
*t = typeFlag(e)
return nil
}
}
return fmt.Errorf("unknown type")
}
func (t *typeFlag) String() string {
return string(*t)
}
func (t *typeFlag) partOf(m []string) bool {
for _, e := range m {
if t.String() == e {
return true
}
}
return false
}
func (t *typeFlag) IsNasType() bool {
return t.partOf(nasTypes)
}
func (t *typeFlag) IsVmfsType() bool {
return t.partOf(vmfsTypes)
}
func (t *typeFlag) IsLocalType() bool {
return t.partOf(localTypes)
}
func (cmd *create) Register(ctx context.Context, f *flag.FlagSet) {
cmd.HostSystemFlag, ctx = flags.NewHostSystemFlag(ctx)
cmd.HostSystemFlag.Register(ctx, f)
modes := []string{
string(types.HostMountModeReadOnly),
string(types.HostMountModeReadWrite),
}
f.StringVar(&cmd.Name, "name", "", "Datastore name")
f.Var(&cmd.Type, "type", fmt.Sprintf("Datastore type (%s)", strings.Join(allTypes, "|")))
f.BoolVar(&cmd.Force, "force", false, "Ignore DuplicateName error if datastore is already mounted on a host")
// Options for NAS
f.StringVar(&cmd.RemoteHost, "remote-host", "", "Remote hostname of the NAS datastore")
f.StringVar(&cmd.RemotePath, "remote-path", "", "Remote path of the NFS mount point")
f.StringVar(&cmd.AccessMode, "mode", modes[0],
fmt.Sprintf("Access mode for the mount point (%s)", strings.Join(modes, "|")))
f.StringVar(&cmd.UserName, "username", "", "Username to use when connecting (CIFS only)")
f.StringVar(&cmd.Password, "password", "", "Password to use when connecting (CIFS only)")
// Options for VMFS
f.StringVar(&cmd.DiskCanonicalName, "disk", "", "Canonical name of disk (VMFS only)")
f.Var(flags.NewOptionalInt32(&cmd.Version), "version", "VMFS major version")
// Options for Local
f.StringVar(&cmd.Path, "path", "", "Local directory path for the datastore (local only)")
}
func (cmd *create) Process(ctx context.Context) error {
if err := cmd.HostSystemFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *create) Usage() string {
return "HOST..."
}
func (cmd *create) Description() string {
return `Create datastore on HOST.
Examples:
govc datastore.create -type nfs -name nfsDatastore -remote-host 10.143.2.232 -remote-path /share cluster1
govc datastore.create -type vmfs -name vmfsDatastore -disk=mpx.vmhba0:C0:T0:L0 cluster1
govc datastore.create -type local -name localDatastore -path /var/datastore host1`
}
func (cmd *create) Run(ctx context.Context, f *flag.FlagSet) error {
hosts, err := cmd.HostSystems(f.Args())
if err != nil {
return err
}
switch {
case cmd.Type.IsNasType():
return cmd.CreateNasDatastore(ctx, hosts)
case cmd.Type.IsVmfsType():
return cmd.CreateVmfsDatastore(ctx, hosts)
case cmd.Type.IsLocalType():
return cmd.CreateLocalDatastore(ctx, hosts)
default:
return fmt.Errorf("unhandled type %#v", cmd.Type)
}
}
func (cmd *create) GetHostNasVolumeSpec() types.HostNasVolumeSpec {
localPath := cmd.Path
if localPath == "" {
localPath = cmd.Name
}
s := types.HostNasVolumeSpec{
LocalPath: localPath,
Type: cmd.Type.String(),
RemoteHost: cmd.RemoteHost,
RemotePath: cmd.RemotePath,
AccessMode: cmd.AccessMode,
UserName: cmd.UserName,
Password: cmd.Password,
}
return s
}
func (cmd *create) CreateNasDatastore(ctx context.Context, hosts []*object.HostSystem) error {
object := types.ManagedObjectReference{
Type: "Datastore",
Value: fmt.Sprintf("%s:%s", cmd.RemoteHost, cmd.RemotePath),
}
spec := cmd.GetHostNasVolumeSpec()
for _, host := range hosts {
ds, err := host.ConfigManager().DatastoreSystem(ctx)
if err != nil {
return err
}
_, err = ds.CreateNasDatastore(ctx, spec)
if err != nil {
if soap.IsSoapFault(err) {
switch fault := soap.ToSoapFault(err).VimFault().(type) {
case types.PlatformConfigFault:
if len(fault.FaultMessage) != 0 {
return errors.New(fault.FaultMessage[0].Message)
}
case types.DuplicateName:
if cmd.Force && fault.Object == object {
fmt.Fprintf(os.Stderr, "%s: '%s' already mounted\n",
host.InventoryPath, cmd.Name)
continue
}
}
}
return fmt.Errorf("%s: %s", host.InventoryPath, err)
}
}
return nil
}
func (cmd *create) CreateVmfsDatastore(ctx context.Context, hosts []*object.HostSystem) error {
for _, host := range hosts {
ds, err := host.ConfigManager().DatastoreSystem(ctx)
if err != nil {
return err
}
// Find the specified disk
disks, err := ds.QueryAvailableDisksForVmfs(ctx)
if err != nil {
return err
}
var disk *types.HostScsiDisk
for _, e := range disks {
if e.CanonicalName == cmd.DiskCanonicalName {
disk = &e
break
}
}
if disk == nil {
return fmt.Errorf("no eligible disk found for name %#v", cmd.DiskCanonicalName)
}
// Query for creation options and pick the right one
options, err := ds.QueryVmfsDatastoreCreateOptions(ctx, disk.DevicePath)
if err != nil {
return err
}
var option *types.VmfsDatastoreOption
for _, e := range options {
if _, ok := e.Info.(*types.VmfsDatastoreAllExtentOption); ok {
option = &e
break
}
}
if option == nil {
return fmt.Errorf("cannot use entire disk for datastore for name %#v", cmd.DiskCanonicalName)
}
spec := *option.Spec.(*types.VmfsDatastoreCreateSpec)
spec.Vmfs.VolumeName = cmd.Name
if cmd.Version != nil {
spec.Vmfs.MajorVersion = *cmd.Version
}
_, err = ds.CreateVmfsDatastore(ctx, spec)
if err != nil {
return err
}
}
return nil
}
func (cmd *create) CreateLocalDatastore(ctx context.Context, hosts []*object.HostSystem) error {
for _, host := range hosts {
ds, err := host.ConfigManager().DatastoreSystem(ctx)
if err != nil {
return err
}
if cmd.Path == "" {
cmd.Path = cmd.Name
}
if cmd.Name == "" {
cmd.Name = filepath.Base(cmd.Path)
}
_, err = ds.CreateLocalDatastore(ctx, cmd.Name, cmd.Path)
if err != nil {
return err
}
}
return nil
}

View file

@ -0,0 +1,117 @@
/*
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package datastore
import (
"context"
"errors"
"flag"
"fmt"
"io"
"os"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/vim25/soap"
)
type download struct {
*flags.DatastoreFlag
*flags.HostSystemFlag
}
func init() {
cli.Register("datastore.download", &download{})
}
func (cmd *download) Register(ctx context.Context, f *flag.FlagSet) {
cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
cmd.DatastoreFlag.Register(ctx, f)
cmd.HostSystemFlag, ctx = flags.NewHostSystemFlag(ctx)
cmd.HostSystemFlag.Register(ctx, f)
}
func (cmd *download) Process(ctx context.Context) error {
if err := cmd.DatastoreFlag.Process(ctx); err != nil {
return err
}
if err := cmd.HostSystemFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *download) Usage() string {
return "SOURCE DEST"
}
func (cmd *download) Description() string {
return `Copy SOURCE from DS to DEST on the local system.
If DEST name is "-", source is written to stdout.
Examples:
govc datastore.download vm-name/vmware.log ./local.log
govc datastore.download vm-name/vmware.log - | grep -i error`
}
func (cmd *download) Run(ctx context.Context, f *flag.FlagSet) error {
args := f.Args()
if len(args) != 2 {
return errors.New("invalid arguments")
}
ds, err := cmd.Datastore()
if err != nil {
return err
}
h, err := cmd.HostSystemIfSpecified()
if err != nil {
return err
}
var via string
if h != nil {
via = fmt.Sprintf(" via %s", h.InventoryPath)
ctx = ds.HostContext(ctx, h)
}
p := soap.DefaultDownload
src := args[0]
dst := args[1]
if dst == "-" {
f, _, err := ds.Download(ctx, src, &p)
if err != nil {
return err
}
_, err = io.Copy(os.Stdout, f)
return err
}
if cmd.DatastoreFlag.OutputFlag.TTY {
logger := cmd.DatastoreFlag.ProgressLogger(fmt.Sprintf("Downloading%s... ", via))
p.Progress = logger
defer logger.Wait()
}
return ds.DownloadFile(ctx, src, dst, &p)
}

213
vendor/github.com/vmware/govmomi/govc/datastore/info.go generated vendored Normal file
View file

@ -0,0 +1,213 @@
/*
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package datastore
import (
"context"
"flag"
"fmt"
"io"
"os"
"text/tabwriter"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
type info struct {
*flags.ClientFlag
*flags.OutputFlag
*flags.DatacenterFlag
host bool
}
func init() {
cli.Register("datastore.info", &info{})
}
func (cmd *info) Register(ctx context.Context, f *flag.FlagSet) {
cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
cmd.ClientFlag.Register(ctx, f)
cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
cmd.OutputFlag.Register(ctx, f)
cmd.DatacenterFlag, ctx = flags.NewDatacenterFlag(ctx)
cmd.DatacenterFlag.Register(ctx, f)
f.BoolVar(&cmd.host, "H", false, "Display info for Datastores shared between hosts")
}
func (cmd *info) Process(ctx context.Context) error {
if err := cmd.ClientFlag.Process(ctx); err != nil {
return err
}
if err := cmd.OutputFlag.Process(ctx); err != nil {
return err
}
if err := cmd.DatacenterFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *info) Usage() string {
return "[PATH]..."
}
func (cmd *info) Description() string {
return `Display info for Datastores.
Examples:
govc datastore.info
govc datastore.info vsanDatastore
# info on Datastores shared between cluster hosts:
govc object.collect -s -d " " /dc1/host/k8s-cluster host | xargs govc datastore.info -H
# info on Datastores shared between VM hosts:
govc ls /dc1/vm/*k8s* | xargs -n1 -I% govc object.collect -s % summary.runtime.host | xargs govc datastore.info -H`
}
func intersect(common []types.ManagedObjectReference, refs []types.ManagedObjectReference) []types.ManagedObjectReference {
var shared []types.ManagedObjectReference
for i := range common {
for j := range refs {
if common[i] == refs[j] {
shared = append(shared, common[i])
break
}
}
}
return shared
}
func (cmd *info) Run(ctx context.Context, f *flag.FlagSet) error {
c, err := cmd.Client()
if err != nil {
return err
}
pc := property.DefaultCollector(c)
finder, err := cmd.Finder()
if err != nil {
return err
}
args := f.Args()
if len(args) == 0 {
args = []string{"*"}
}
var res infoResult
var props []string
if cmd.OutputFlag.All() {
props = nil // Load everything
} else {
props = []string{"info", "summary"} // Load summary
}
if cmd.host {
if f.NArg() == 0 {
return flag.ErrHelp
}
refs, err := cmd.ManagedObjects(ctx, args)
if err != nil {
return err
}
var hosts []mo.HostSystem
err = pc.Retrieve(ctx, refs, []string{"name", "datastore"}, &hosts)
if err != nil {
return err
}
refs = hosts[0].Datastore
for _, host := range hosts[1:] {
refs = intersect(refs, host.Datastore)
if len(refs) == 0 {
return fmt.Errorf("host %s (%s) has no shared datastores", host.Name, host.Reference())
}
}
for i := range refs {
ds, err := finder.ObjectReference(ctx, refs[i])
if err != nil {
return err
}
res.objects = append(res.objects, ds.(*object.Datastore))
}
} else {
for _, arg := range args {
objects, err := finder.DatastoreList(ctx, arg)
if err != nil {
return err
}
res.objects = append(res.objects, objects...)
}
}
if len(res.objects) != 0 {
refs := make([]types.ManagedObjectReference, 0, len(res.objects))
for _, o := range res.objects {
refs = append(refs, o.Reference())
}
err = pc.Retrieve(ctx, refs, props, &res.Datastores)
if err != nil {
return err
}
}
return cmd.WriteResult(&res)
}
type infoResult struct {
Datastores []mo.Datastore
objects []*object.Datastore
}
func (r *infoResult) Write(w io.Writer) error {
// Maintain order via r.objects as Property collector does not always return results in order.
objects := make(map[types.ManagedObjectReference]mo.Datastore, len(r.Datastores))
for _, o := range r.Datastores {
objects[o.Reference()] = o
}
tw := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0)
for _, o := range r.objects {
ds := objects[o.Reference()]
s := ds.Summary
fmt.Fprintf(tw, "Name:\t%s\n", s.Name)
fmt.Fprintf(tw, " Path:\t%s\n", o.InventoryPath)
fmt.Fprintf(tw, " Type:\t%s\n", s.Type)
fmt.Fprintf(tw, " URL:\t%s\n", s.Url)
fmt.Fprintf(tw, " Capacity:\t%.1f GB\n", float64(s.Capacity)/(1<<30))
fmt.Fprintf(tw, " Free:\t%.1f GB\n", float64(s.FreeSpace)/(1<<30))
switch info := ds.Info.(type) {
case *types.NasDatastoreInfo:
fmt.Fprintf(tw, " Remote:\t%s:%s\n", info.Nas.RemoteHost, info.Nas.RemotePath)
}
}
return tw.Flush()
}

280
vendor/github.com/vmware/govmomi/govc/datastore/ls.go generated vendored Normal file
View file

@ -0,0 +1,280 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package datastore
import (
"context"
"encoding/json"
"flag"
"fmt"
"io"
"path"
"strings"
"text/tabwriter"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/units"
"github.com/vmware/govmomi/vim25/types"
)
type ls struct {
*flags.DatastoreFlag
*flags.OutputFlag
long bool
slash bool
all bool
recurse bool
}
func init() {
cli.Register("datastore.ls", &ls{})
}
func (cmd *ls) Register(ctx context.Context, f *flag.FlagSet) {
cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
cmd.DatastoreFlag.Register(ctx, f)
cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
cmd.OutputFlag.Register(ctx, f)
f.BoolVar(&cmd.long, "l", false, "Long listing format")
f.BoolVar(&cmd.slash, "p", false, "Append / indicator to directories")
f.BoolVar(&cmd.all, "a", false, "Do not ignore entries starting with .")
f.BoolVar(&cmd.recurse, "R", false, "List subdirectories recursively")
}
func (cmd *ls) Process(ctx context.Context) error {
if err := cmd.DatastoreFlag.Process(ctx); err != nil {
return err
}
if err := cmd.OutputFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *ls) Usage() string {
return "[FILE]..."
}
func isInvalid(err error) bool {
if f, ok := err.(types.HasFault); ok {
switch f.Fault().(type) {
case *types.InvalidArgument:
return true
}
}
return false
}
func (cmd *ls) Run(ctx context.Context, f *flag.FlagSet) error {
args := cmd.Args(f.Args())
ds, err := cmd.Datastore()
if err != nil {
return err
}
b, err := ds.Browser(ctx)
if err != nil {
return err
}
if len(args) == 0 {
args = append(args, object.DatastorePath{})
}
result := &listOutput{
rs: make([]types.HostDatastoreBrowserSearchResults, 0),
cmd: cmd,
}
for _, p := range args {
arg := p.Path
spec := types.HostDatastoreBrowserSearchSpec{
MatchPattern: []string{"*"},
}
if cmd.long {
spec.Details = &types.FileQueryFlags{
FileType: true,
FileSize: true,
FileOwner: types.NewBool(true), // TODO: omitempty is generated, but seems to be required
Modification: true,
}
}
for i := 0; ; i++ {
r, err := cmd.ListPath(b, arg, spec)
if err != nil {
// Treat the argument as a match pattern if not found as directory
if i == 0 && types.IsFileNotFound(err) || isInvalid(err) {
spec.MatchPattern[0] = path.Base(arg)
arg = path.Dir(arg)
continue
}
return err
}
// Treat an empty result against match pattern as file not found
if i == 1 && len(r) == 1 && len(r[0].File) == 0 {
return fmt.Errorf("file %s/%s was not found", r[0].FolderPath, spec.MatchPattern[0])
}
for n := range r {
result.add(r[n])
}
break
}
}
return cmd.WriteResult(result)
}
func (cmd *ls) ListPath(b *object.HostDatastoreBrowser, path string, spec types.HostDatastoreBrowserSearchSpec) ([]types.HostDatastoreBrowserSearchResults, error) {
ctx := context.TODO()
path, err := cmd.DatastorePath(path)
if err != nil {
return nil, err
}
search := b.SearchDatastore
if cmd.recurse {
search = b.SearchDatastoreSubFolders
}
task, err := search(ctx, path, &spec)
if err != nil {
return nil, err
}
info, err := task.WaitForResult(ctx, nil)
if err != nil {
return nil, err
}
switch r := info.Result.(type) {
case types.HostDatastoreBrowserSearchResults:
return []types.HostDatastoreBrowserSearchResults{r}, nil
case types.ArrayOfHostDatastoreBrowserSearchResults:
return r.HostDatastoreBrowserSearchResults, nil
default:
panic(fmt.Sprintf("unknown result type: %T", r))
}
}
type listOutput struct {
rs []types.HostDatastoreBrowserSearchResults
cmd *ls
}
func (o *listOutput) add(r types.HostDatastoreBrowserSearchResults) {
if o.cmd.recurse && !o.cmd.all {
// filter out ".hidden" directories
path := strings.SplitN(r.FolderPath, " ", 2)
if len(path) == 2 {
path = strings.Split(path[1], "/")
if path[0] == "." {
path = path[1:]
}
for _, p := range path {
if p != "" && p[0] == '.' {
return
}
}
}
}
res := r
res.File = nil
for _, f := range r.File {
if f.GetFileInfo().Path[0] == '.' && !o.cmd.all {
continue
}
if o.cmd.slash {
if d, ok := f.(*types.FolderFileInfo); ok {
d.Path += "/"
}
}
res.File = append(res.File, f)
}
o.rs = append(o.rs, res)
}
// hasMultiplePaths returns whether or not the slice of search results contains
// results from more than one folder path.
func (o *listOutput) hasMultiplePaths() bool {
if len(o.rs) == 0 {
return false
}
p := o.rs[0].FolderPath
// Multiple paths if any entry is not equal to the first one.
for _, e := range o.rs {
if e.FolderPath != p {
return true
}
}
return false
}
func (o *listOutput) MarshalJSON() ([]byte, error) {
return json.Marshal(o.rs)
}
func (o *listOutput) Write(w io.Writer) error {
// Only include path header if we're dealing with more than one path.
includeHeader := false
if o.hasMultiplePaths() {
includeHeader = true
}
tw := tabwriter.NewWriter(w, 3, 0, 2, ' ', 0)
for i, r := range o.rs {
if includeHeader {
if i > 0 {
fmt.Fprintf(tw, "\n")
}
fmt.Fprintf(tw, "%s:\n", r.FolderPath)
}
for _, file := range r.File {
info := file.GetFileInfo()
if o.cmd.long {
fmt.Fprintf(tw, "%s\t%s\t%s\n", units.ByteSize(info.FileSize), info.Modification.Format("Mon Jan 2 15:04:05 2006"), info.Path)
} else {
fmt.Fprintf(tw, "%s\n", info.Path)
}
}
}
tw.Flush()
return nil
}

View file

@ -0,0 +1,118 @@
/*
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package datastore
import (
"context"
"errors"
"flag"
"fmt"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
)
type mkdir struct {
*flags.DatastoreFlag
createParents bool
isNamespace bool
}
func init() {
cli.Register("datastore.mkdir", &mkdir{})
}
func (cmd *mkdir) Register(ctx context.Context, f *flag.FlagSet) {
cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
cmd.DatastoreFlag.Register(ctx, f)
f.BoolVar(&cmd.createParents, "p", false, "Create intermediate directories as needed")
f.BoolVar(&cmd.isNamespace, "namespace", false, "Return uuid of namespace created on vsan datastore")
}
func (cmd *mkdir) Process(ctx context.Context) error {
if err := cmd.DatastoreFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *mkdir) Usage() string {
return "DIRECTORY"
}
func (cmd *mkdir) Run(ctx context.Context, f *flag.FlagSet) error {
args := f.Args()
if len(args) == 0 {
return errors.New("missing operand")
}
c, err := cmd.Client()
if err != nil {
return err
}
if cmd.isNamespace {
var uuid string
var ds *object.Datastore
if ds, err = cmd.Datastore(); err != nil {
return err
}
path := args[0]
nm := object.NewDatastoreNamespaceManager(c)
if uuid, err = nm.CreateDirectory(ctx, ds, path, ""); err != nil {
return err
}
fmt.Println(uuid)
} else {
var dc *object.Datacenter
var path string
dc, err = cmd.Datacenter()
if err != nil {
return err
}
path, err = cmd.DatastorePath(args[0])
if err != nil {
return err
}
m := object.NewFileManager(c)
err = m.MakeDirectory(ctx, path, dc, cmd.createParents)
// ignore EEXIST if -p flag is given
if err != nil && cmd.createParents {
if soap.IsSoapFault(err) {
soapFault := soap.ToSoapFault(err)
if _, ok := soapFault.VimFault().(types.FileAlreadyExists); ok {
return nil
}
}
}
}
return err
}

77
vendor/github.com/vmware/govmomi/govc/datastore/mv.go generated vendored Normal file
View file

@ -0,0 +1,77 @@
/*
Copyright (c) 2014-2018 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package datastore
import (
"context"
"flag"
"fmt"
"github.com/vmware/govmomi/govc/cli"
)
type mv struct {
target
}
func init() {
cli.Register("datastore.mv", &mv{})
}
func (cmd *mv) Usage() string {
return "SRC DST"
}
func (cmd *mv) Description() string {
return `Move SRC to DST on DATASTORE.
Examples:
govc datastore.mv foo/foo.vmx foo/foo.vmx.old
govc datastore.mv -f my.vmx foo/foo.vmx`
}
func (cmd *mv) Run(ctx context.Context, f *flag.FlagSet) error {
args := f.Args()
if len(args) != 2 {
return flag.ErrHelp
}
m, err := cmd.FileManager()
if err != nil {
return err
}
src, err := cmd.DatastorePath(args[0])
if err != nil {
return err
}
dst, err := cmd.target.ds.DatastorePath(args[1])
if err != nil {
return err
}
mv := m.MoveFile
if cmd.kind {
mv = m.Move
}
logger := cmd.ProgressLogger(fmt.Sprintf("Moving %s to %s...", src, dst))
defer logger.Wait()
return mv(m.WithProgress(ctx, logger), src, dst)
}

View file

@ -0,0 +1,90 @@
/*
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package datastore
import (
"context"
"flag"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
)
type remove struct {
*flags.HostSystemFlag
*flags.DatastoreFlag
}
func init() {
cli.Register("datastore.remove", &remove{})
}
func (cmd *remove) Register(ctx context.Context, f *flag.FlagSet) {
cmd.HostSystemFlag, ctx = flags.NewHostSystemFlag(ctx)
cmd.HostSystemFlag.Register(ctx, f)
cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
cmd.DatastoreFlag.Register(ctx, f)
}
func (cmd *remove) Process(ctx context.Context) error {
if err := cmd.HostSystemFlag.Process(ctx); err != nil {
return err
}
if err := cmd.DatastoreFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *remove) Usage() string {
return "HOST..."
}
func (cmd *remove) Description() string {
return `Remove datastore from HOST.
Examples:
govc datastore.remove -ds nfsDatastore cluster1
govc datastore.remove -ds nasDatastore host1 host2 host3`
}
func (cmd *remove) Run(ctx context.Context, f *flag.FlagSet) error {
ds, err := cmd.Datastore()
if err != nil {
return err
}
hosts, err := cmd.HostSystems(f.Args())
if err != nil {
return err
}
for _, host := range hosts {
hds, err := host.ConfigManager().DatastoreSystem(ctx)
if err != nil {
return err
}
err = hds.Remove(ctx, ds)
if err != nil {
return err
}
}
return nil
}

117
vendor/github.com/vmware/govmomi/govc/datastore/rm.go generated vendored Normal file
View file

@ -0,0 +1,117 @@
/*
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package datastore
import (
"context"
"flag"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/types"
)
type rm struct {
*flags.DatastoreFlag
kind bool
force bool
isNamespace bool
}
func init() {
cli.Register("datastore.rm", &rm{})
cli.Alias("datastore.rm", "datastore.delete")
}
func (cmd *rm) Register(ctx context.Context, f *flag.FlagSet) {
cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
cmd.DatastoreFlag.Register(ctx, f)
f.BoolVar(&cmd.kind, "t", true, "Use file type to choose disk or file manager")
f.BoolVar(&cmd.force, "f", false, "Force; ignore nonexistent files and arguments")
f.BoolVar(&cmd.isNamespace, "namespace", false, "Path is uuid of namespace on vsan datastore")
}
func (cmd *rm) Process(ctx context.Context) error {
if err := cmd.DatastoreFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *rm) Usage() string {
return "FILE"
}
func (cmd *rm) Description() string {
return `Remove FILE from DATASTORE.
Examples:
govc datastore.rm vm/vmware.log
govc datastore.rm vm
govc datastore.rm -f images/base.vmdk`
}
func (cmd *rm) Run(ctx context.Context, f *flag.FlagSet) error {
args := f.Args()
if len(args) == 0 {
return flag.ErrHelp
}
c, err := cmd.Client()
if err != nil {
return err
}
var dc *object.Datacenter
dc, err = cmd.Datacenter()
if err != nil {
return err
}
ds, err := cmd.Datastore()
if err != nil {
return err
}
if cmd.isNamespace {
path := args[0]
nm := object.NewDatastoreNamespaceManager(c)
err = nm.DeleteDirectory(ctx, dc, path)
} else {
fm := ds.NewFileManager(dc, cmd.force)
remove := fm.DeleteFile // File delete
if cmd.kind {
remove = fm.Delete // VirtualDisk or File delete
}
err = remove(ctx, args[0])
}
if err != nil {
if types.IsFileNotFound(err) && cmd.force {
// Ignore error
return nil
}
}
return err
}

137
vendor/github.com/vmware/govmomi/govc/datastore/tail.go generated vendored Normal file
View file

@ -0,0 +1,137 @@
/*
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package datastore
import (
"context"
"flag"
"io"
"os"
"time"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
)
type tail struct {
*flags.DatastoreFlag
*flags.HostSystemFlag
count int64
lines int
follow bool
}
func init() {
cli.Register("datastore.tail", &tail{})
}
func (cmd *tail) Register(ctx context.Context, f *flag.FlagSet) {
cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
cmd.DatastoreFlag.Register(ctx, f)
cmd.HostSystemFlag, ctx = flags.NewHostSystemFlag(ctx)
cmd.HostSystemFlag.Register(ctx, f)
f.Int64Var(&cmd.count, "c", -1, "Output the last NUM bytes")
f.IntVar(&cmd.lines, "n", 10, "Output the last NUM lines")
f.BoolVar(&cmd.follow, "f", false, "Output appended data as the file grows")
}
func (cmd *tail) Description() string {
return `Output the last part of datastore files.
Examples:
govc datastore.tail -n 100 vm-name/vmware.log
govc datastore.tail -n 0 -f vm-name/vmware.log`
}
func (cmd *tail) Process(ctx context.Context) error {
if err := cmd.DatastoreFlag.Process(ctx); err != nil {
return err
}
if err := cmd.HostSystemFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *tail) Usage() string {
return "PATH"
}
func (cmd *tail) Run(ctx context.Context, f *flag.FlagSet) error {
if f.NArg() != 1 {
return flag.ErrHelp
}
p := cmd.Args(f.Args())[0]
ds, err := cmd.Datastore()
if err != nil {
return err
}
h, err := cmd.HostSystemIfSpecified()
if err != nil {
return err
}
if h != nil {
ctx = ds.HostContext(ctx, h)
}
file, err := ds.Open(ctx, p.Path)
if err != nil {
return err
}
var reader io.ReadCloser = file
var offset int64
if cmd.count >= 0 {
info, serr := file.Stat()
if serr != nil {
return serr
}
if info.Size() > cmd.count {
offset = info.Size() - cmd.count
_, err = file.Seek(offset, io.SeekStart)
if err != nil {
return err
}
}
} else if cmd.lines >= 0 {
err = file.Tail(cmd.lines)
if err != nil {
return err
}
}
if cmd.follow {
reader = file.Follow(time.Second)
}
_, err = io.Copy(os.Stdout, reader)
_ = reader.Close()
return err
}

View file

@ -0,0 +1,98 @@
/*
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package datastore
import (
"context"
"errors"
"flag"
"os"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/vim25/soap"
)
type upload struct {
*flags.OutputFlag
*flags.DatastoreFlag
}
func init() {
cli.Register("datastore.upload", &upload{})
}
func (cmd *upload) Register(ctx context.Context, f *flag.FlagSet) {
cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
cmd.OutputFlag.Register(ctx, f)
cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
cmd.DatastoreFlag.Register(ctx, f)
}
func (cmd *upload) Process(ctx context.Context) error {
if err := cmd.OutputFlag.Process(ctx); err != nil {
return err
}
if err := cmd.DatastoreFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *upload) Usage() string {
return "SOURCE DEST"
}
func (cmd *upload) Description() string {
return `Copy SOURCE from the local system to DEST on DS.
If SOURCE name is "-", read source from stdin.
Examples:
govc datastore.upload -ds datastore1 ./config.iso vm-name/config.iso
genisoimage ... | govc datastore.upload -ds datastore1 - vm-name/config.iso`
}
func (cmd *upload) Run(ctx context.Context, f *flag.FlagSet) error {
args := f.Args()
if len(args) != 2 {
return errors.New("invalid arguments")
}
ds, err := cmd.Datastore()
if err != nil {
return err
}
p := soap.DefaultUpload
src := args[0]
dst := args[1]
if src == "-" {
return ds.Upload(ctx, os.Stdin, dst, &p)
}
if cmd.OutputFlag.TTY {
logger := cmd.ProgressLogger("Uploading... ")
p.Progress = logger
defer logger.Wait()
}
return ds.UploadFile(ctx, src, dst, &p)
}

508
vendor/github.com/vmware/govmomi/govc/flags/client.go generated vendored Normal file
View file

@ -0,0 +1,508 @@
/*
Copyright (c) 2014-2018 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"crypto/tls"
"errors"
"flag"
"fmt"
"net/url"
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
"time"
"github.com/vmware/govmomi/session"
"github.com/vmware/govmomi/session/cache"
"github.com/vmware/govmomi/session/keepalive"
"github.com/vmware/govmomi/vapi/rest"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/soap"
)
const (
envURL = "GOVC_URL"
envUsername = "GOVC_USERNAME"
envPassword = "GOVC_PASSWORD"
envCertificate = "GOVC_CERTIFICATE"
envPrivateKey = "GOVC_PRIVATE_KEY"
envInsecure = "GOVC_INSECURE"
envPersist = "GOVC_PERSIST_SESSION"
envMinAPIVersion = "GOVC_MIN_API_VERSION"
envVimNamespace = "GOVC_VIM_NAMESPACE"
envVimVersion = "GOVC_VIM_VERSION"
envTLSCaCerts = "GOVC_TLS_CA_CERTS"
envTLSKnownHosts = "GOVC_TLS_KNOWN_HOSTS"
defaultMinVimVersion = "5.5"
)
const cDescr = "ESX or vCenter URL"
type ClientFlag struct {
common
*DebugFlag
username string
password string
cert string
key string
persist bool
minAPIVersion string
vimNamespace string
vimVersion string
tlsCaCerts string
tlsKnownHosts string
client *vim25.Client
restClient *rest.Client
Session cache.Session
}
var (
home = os.Getenv("GOVMOMI_HOME")
clientFlagKey = flagKey("client")
)
func init() {
if home == "" {
home = filepath.Join(os.Getenv("HOME"), ".govmomi")
}
}
func NewClientFlag(ctx context.Context) (*ClientFlag, context.Context) {
if v := ctx.Value(clientFlagKey); v != nil {
return v.(*ClientFlag), ctx
}
v := &ClientFlag{}
v.DebugFlag, ctx = NewDebugFlag(ctx)
ctx = context.WithValue(ctx, clientFlagKey, v)
return v, ctx
}
func (flag *ClientFlag) String() string {
url := flag.Session.Endpoint()
if url == nil {
return ""
}
return url.String()
}
func (flag *ClientFlag) Set(s string) error {
var err error
flag.Session.URL, err = soap.ParseURL(s)
return err
}
func (flag *ClientFlag) Register(ctx context.Context, f *flag.FlagSet) {
flag.RegisterOnce(func() {
flag.DebugFlag.Register(ctx, f)
{
flag.Set(os.Getenv(envURL))
usage := fmt.Sprintf("%s [%s]", cDescr, envURL)
f.Var(flag, "u", usage)
}
{
flag.username = os.Getenv(envUsername)
flag.password = os.Getenv(envPassword)
}
{
value := os.Getenv(envCertificate)
usage := fmt.Sprintf("Certificate [%s]", envCertificate)
f.StringVar(&flag.cert, "cert", value, usage)
}
{
value := os.Getenv(envPrivateKey)
usage := fmt.Sprintf("Private key [%s]", envPrivateKey)
f.StringVar(&flag.key, "key", value, usage)
}
{
insecure := false
switch env := strings.ToLower(os.Getenv(envInsecure)); env {
case "1", "true":
insecure = true
}
usage := fmt.Sprintf("Skip verification of server certificate [%s]", envInsecure)
f.BoolVar(&flag.Session.Insecure, "k", insecure, usage)
}
{
persist := true
switch env := strings.ToLower(os.Getenv(envPersist)); env {
case "0", "false":
persist = false
}
usage := fmt.Sprintf("Persist session to disk [%s]", envPersist)
f.BoolVar(&flag.persist, "persist-session", persist, usage)
}
{
env := os.Getenv(envMinAPIVersion)
if env == "" {
env = defaultMinVimVersion
}
flag.minAPIVersion = env
}
{
value := os.Getenv(envVimNamespace)
if value == "" {
value = vim25.Namespace
}
usage := fmt.Sprintf("Vim namespace [%s]", envVimNamespace)
f.StringVar(&flag.vimNamespace, "vim-namespace", value, usage)
}
{
value := os.Getenv(envVimVersion)
if value == "" {
value = vim25.Version
}
usage := fmt.Sprintf("Vim version [%s]", envVimVersion)
f.StringVar(&flag.vimVersion, "vim-version", value, usage)
}
{
value := os.Getenv(envTLSCaCerts)
usage := fmt.Sprintf("TLS CA certificates file [%s]", envTLSCaCerts)
f.StringVar(&flag.tlsCaCerts, "tls-ca-certs", value, usage)
}
{
value := os.Getenv(envTLSKnownHosts)
usage := fmt.Sprintf("TLS known hosts file [%s]", envTLSKnownHosts)
f.StringVar(&flag.tlsKnownHosts, "tls-known-hosts", value, usage)
}
})
}
func (flag *ClientFlag) Process(ctx context.Context) error {
return flag.ProcessOnce(func() error {
err := flag.DebugFlag.Process(ctx)
if err != nil {
return err
}
if flag.Session.URL == nil {
return errors.New("specify an " + cDescr)
}
if !flag.persist {
flag.Session.Passthrough = true
}
flag.username, err = session.Secret(flag.username)
if err != nil {
return err
}
flag.password, err = session.Secret(flag.password)
if err != nil {
return err
}
// Override username if set
if flag.username != "" {
var password string
var ok bool
if flag.Session.URL.User != nil {
password, ok = flag.Session.URL.User.Password()
}
if ok {
flag.Session.URL.User = url.UserPassword(flag.username, password)
} else {
flag.Session.URL.User = url.User(flag.username)
}
}
// Override password if set
if flag.password != "" {
var username string
if flag.Session.URL.User != nil {
username = flag.Session.URL.User.Username()
}
flag.Session.URL.User = url.UserPassword(username, flag.password)
}
return nil
})
}
func (flag *ClientFlag) ConfigureTLS(sc *soap.Client) error {
if flag.cert != "" {
cert, err := tls.LoadX509KeyPair(flag.cert, flag.key)
if err != nil {
return fmt.Errorf("%s=%q %s=%q: %s", envCertificate, flag.cert, envPrivateKey, flag.key, err)
}
sc.SetCertificate(cert)
}
// Set namespace and version
sc.Namespace = "urn:" + flag.vimNamespace
sc.Version = flag.vimVersion
sc.UserAgent = fmt.Sprintf("govc/%s", Version)
if err := flag.SetRootCAs(sc); err != nil {
return err
}
if err := sc.LoadThumbprints(flag.tlsKnownHosts); err != nil {
return err
}
t := sc.DefaultTransport()
var err error
value := os.Getenv("GOVC_TLS_HANDSHAKE_TIMEOUT")
if value != "" {
t.TLSHandshakeTimeout, err = time.ParseDuration(value)
if err != nil {
return err
}
}
return nil
}
func (flag *ClientFlag) SetRootCAs(c *soap.Client) error {
if flag.tlsCaCerts != "" {
return c.SetRootCAs(flag.tlsCaCerts)
}
return nil
}
func isDevelopmentVersion(apiVersion string) bool {
// Skip version check for development builds which can be in the form of "r4A70F" or "6.5.x"
return strings.Count(apiVersion, ".") == 0 || strings.HasSuffix(apiVersion, ".x")
}
// apiVersionValid returns whether or not the API version supported by the
// server the client is connected to is not recent enough.
func apiVersionValid(c *vim25.Client, minVersionString string) error {
if minVersionString == "-" {
// Disable version check
return nil
}
apiVersion := c.ServiceContent.About.ApiVersion
if isDevelopmentVersion(apiVersion) {
return nil
}
realVersion, err := ParseVersion(apiVersion)
if err != nil {
return fmt.Errorf("error parsing API version %q: %s", apiVersion, err)
}
minVersion, err := ParseVersion(minVersionString)
if err != nil {
return fmt.Errorf("error parsing %s=%q: %s", envMinAPIVersion, minVersionString, err)
}
if !minVersion.Lte(realVersion) {
err = fmt.Errorf("require API version %q, connected to API version %q (set %s to override)",
minVersionString,
c.ServiceContent.About.ApiVersion,
envMinAPIVersion)
return err
}
return nil
}
func (flag *ClientFlag) Client() (*vim25.Client, error) {
if flag.client != nil {
return flag.client, nil
}
c := new(vim25.Client)
err := flag.Session.Login(context.Background(), c, flag.ConfigureTLS)
if err != nil {
return nil, err
}
// Check that the endpoint has the right API version
err = apiVersionValid(c, flag.minAPIVersion)
if err != nil {
return nil, err
}
if flag.vimVersion == "" {
err = c.UseServiceVersion()
if err != nil {
return nil, err
}
}
// Retry twice when a temporary I/O error occurs.
// This means a maximum of 3 attempts.
c.RoundTripper = vim25.Retry(c.Client, vim25.TemporaryNetworkError(3))
flag.client = c
return flag.client, nil
}
func (flag *ClientFlag) RestClient() (*rest.Client, error) {
if flag.restClient != nil {
return flag.restClient, nil
}
c := new(rest.Client)
err := flag.Session.Login(context.Background(), c, flag.ConfigureTLS)
if err != nil {
return nil, err
}
flag.restClient = c
return flag.restClient, nil
}
func (flag *ClientFlag) KeepAlive(client cache.Client) {
switch c := client.(type) {
case *vim25.Client:
keepalive.NewHandlerSOAP(c, 0, nil).Start()
case *rest.Client:
keepalive.NewHandlerREST(c, 0, nil).Start()
default:
panic(fmt.Sprintf("unsupported client type=%T", client))
}
}
func (flag *ClientFlag) Logout(ctx context.Context) error {
if flag.client != nil {
_ = flag.Session.Logout(ctx, flag.client)
}
if flag.restClient != nil {
_ = flag.Session.Logout(ctx, flag.restClient)
}
return nil
}
// Environ returns the govc environment variables for this connection
func (flag *ClientFlag) Environ(extra bool) []string {
var env []string
add := func(k, v string) {
env = append(env, fmt.Sprintf("%s=%s", k, v))
}
u := *flag.Session.URL
if u.User != nil {
add(envUsername, u.User.Username())
if p, ok := u.User.Password(); ok {
add(envPassword, p)
}
u.User = nil
}
if u.Path == vim25.Path {
u.Path = ""
}
u.Fragment = ""
u.RawQuery = ""
add(envURL, strings.TrimPrefix(u.String(), "https://"))
keys := []string{
envCertificate,
envPrivateKey,
envInsecure,
envPersist,
envMinAPIVersion,
envVimNamespace,
envVimVersion,
}
for _, k := range keys {
if v := os.Getenv(k); v != "" {
add(k, v)
}
}
if extra {
add("GOVC_URL_SCHEME", flag.Session.URL.Scheme)
v := strings.SplitN(u.Host, ":", 2)
add("GOVC_URL_HOST", v[0])
if len(v) == 2 {
add("GOVC_URL_PORT", v[1])
}
add("GOVC_URL_PATH", flag.Session.URL.Path)
if f := flag.Session.URL.Fragment; f != "" {
add("GOVC_URL_FRAGMENT", f)
}
if q := flag.Session.URL.RawQuery; q != "" {
add("GOVC_URL_QUERY", q)
}
}
return env
}
// WithCancel calls the given function, returning when complete or canceled via SIGINT.
func (flag *ClientFlag) WithCancel(ctx context.Context, f func(context.Context) error) error {
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT)
wctx, cancel := context.WithCancel(ctx)
defer cancel()
done := make(chan bool)
var werr error
go func() {
defer close(done)
werr = f(wctx)
}()
select {
case <-sig:
cancel()
<-done // Wait for f() to complete
case <-done:
}
return werr
}

204
vendor/github.com/vmware/govmomi/govc/flags/cluster.go generated vendored Normal file
View file

@ -0,0 +1,204 @@
/*
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"flag"
"fmt"
"os"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/view"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
type ClusterFlag struct {
common
*DatacenterFlag
Name string
cluster *object.ClusterComputeResource
pc *property.Collector
}
var clusterFlagKey = flagKey("cluster")
func NewClusterFlag(ctx context.Context) (*ClusterFlag, context.Context) {
if v := ctx.Value(clusterFlagKey); v != nil {
return v.(*ClusterFlag), ctx
}
v := &ClusterFlag{}
v.DatacenterFlag, ctx = NewDatacenterFlag(ctx)
ctx = context.WithValue(ctx, clusterFlagKey, v)
return v, ctx
}
func (f *ClusterFlag) Register(ctx context.Context, fs *flag.FlagSet) {
f.RegisterOnce(func() {
f.DatacenterFlag.Register(ctx, fs)
env := "GOVC_CLUSTER"
value := os.Getenv(env)
usage := fmt.Sprintf("Cluster [%s]", env)
fs.StringVar(&f.Name, "cluster", value, usage)
})
}
// RegisterPlacement registers the -cluster flag without using GOVC_CLUSTER env as the default value,
// usage is specific to VM placement.
func (f *ClusterFlag) RegisterPlacement(ctx context.Context, fs *flag.FlagSet) {
f.RegisterOnce(func() {
f.DatacenterFlag.Register(ctx, fs)
fs.StringVar(&f.Name, "cluster", "", "Use cluster for VM placement via DRS")
})
}
func (f *ClusterFlag) Process(ctx context.Context) error {
return f.ProcessOnce(func() error {
if err := f.DatacenterFlag.Process(ctx); err != nil {
return err
}
return nil
})
}
func (f *ClusterFlag) Cluster() (*object.ClusterComputeResource, error) {
if f.cluster != nil {
return f.cluster, nil
}
finder, err := f.Finder()
if err != nil {
return nil, err
}
if f.cluster, err = finder.ClusterComputeResourceOrDefault(context.TODO(), f.Name); err != nil {
return nil, err
}
f.pc = property.DefaultCollector(f.cluster.Client())
return f.cluster, nil
}
func (f *ClusterFlag) ClusterIfSpecified() (*object.ClusterComputeResource, error) {
if f.Name == "" {
return nil, nil
}
return f.Cluster()
}
func (f *ClusterFlag) Reconfigure(ctx context.Context, spec types.BaseComputeResourceConfigSpec) error {
cluster, err := f.Cluster()
if err != nil {
return err
}
task, err := cluster.Reconfigure(ctx, spec, true)
if err != nil {
return err
}
logger := f.ProgressLogger(fmt.Sprintf("Reconfigure %s...", cluster.InventoryPath))
defer logger.Wait()
_, err = task.WaitForResult(ctx, logger)
return err
}
func (f *ClusterFlag) objectMap(ctx context.Context, kind string, names []string) (map[string]types.ManagedObjectReference, error) {
cluster, err := f.Cluster()
if err != nil {
return nil, err
}
objects := make(map[string]types.ManagedObjectReference, len(names))
for _, name := range names {
objects[name] = types.ManagedObjectReference{}
}
m := view.NewManager(cluster.Client())
v, err := m.CreateContainerView(ctx, cluster.Reference(), []string{kind}, true)
if err != nil {
return nil, err
}
defer func() {
_ = v.Destroy(ctx)
}()
var entities []mo.ManagedEntity
err = v.Retrieve(ctx, []string{"ManagedEntity"}, []string{"name"}, &entities)
if err != nil {
return nil, err
}
for _, e := range entities {
if _, ok := objects[e.Name]; ok {
objects[e.Name] = e.Self
}
}
for name, ref := range objects {
if ref.Value == "" {
return nil, fmt.Errorf("%s %q not found", kind, name)
}
}
return objects, nil
}
func (f *ClusterFlag) ObjectList(ctx context.Context, kind string, names []string) ([]types.ManagedObjectReference, error) {
objs, err := f.objectMap(ctx, kind, names)
if err != nil {
return nil, err
}
var refs []types.ManagedObjectReference
for _, name := range names { // preserve order
refs = append(refs, objs[name])
}
return refs, nil
}
func (f *ClusterFlag) Names(ctx context.Context, refs []types.ManagedObjectReference) (map[types.ManagedObjectReference]string, error) {
names := make(map[types.ManagedObjectReference]string, len(refs))
if len(refs) != 0 {
var objs []mo.ManagedEntity
err := f.pc.Retrieve(ctx, refs, []string{"name"}, &objs)
if err != nil {
return nil, err
}
for _, obj := range objs {
names[obj.Self] = obj.Name
}
}
return names, nil
}

38
vendor/github.com/vmware/govmomi/govc/flags/common.go generated vendored Normal file
View file

@ -0,0 +1,38 @@
/*
Copyright (c) 2015-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import "sync"
// Key type for storing flag instances in a context.Context.
type flagKey string
// Type to help flags out with only registering/processing once.
type common struct {
register sync.Once
process sync.Once
}
func (c *common) RegisterOnce(fn func()) {
c.register.Do(fn)
}
func (c *common) ProcessOnce(fn func() error) (err error) {
c.process.Do(func() {
err = fn()
})
return err
}

View file

@ -0,0 +1,221 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"flag"
"fmt"
"os"
"strings"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/vim25/types"
)
type DatacenterFlag struct {
common
*ClientFlag
*OutputFlag
Name string
dc *object.Datacenter
finder *find.Finder
err error
}
var datacenterFlagKey = flagKey("datacenter")
func NewDatacenterFlag(ctx context.Context) (*DatacenterFlag, context.Context) {
if v := ctx.Value(datacenterFlagKey); v != nil {
return v.(*DatacenterFlag), ctx
}
v := &DatacenterFlag{}
v.ClientFlag, ctx = NewClientFlag(ctx)
v.OutputFlag, ctx = NewOutputFlag(ctx)
ctx = context.WithValue(ctx, datacenterFlagKey, v)
return v, ctx
}
func (flag *DatacenterFlag) Register(ctx context.Context, f *flag.FlagSet) {
flag.RegisterOnce(func() {
flag.ClientFlag.Register(ctx, f)
flag.OutputFlag.Register(ctx, f)
env := "GOVC_DATACENTER"
value := os.Getenv(env)
usage := fmt.Sprintf("Datacenter [%s]", env)
f.StringVar(&flag.Name, "dc", value, usage)
})
}
func (flag *DatacenterFlag) Process(ctx context.Context) error {
return flag.ProcessOnce(func() error {
if err := flag.ClientFlag.Process(ctx); err != nil {
return err
}
if err := flag.OutputFlag.Process(ctx); err != nil {
return err
}
return nil
})
}
func (flag *DatacenterFlag) Finder(all ...bool) (*find.Finder, error) {
if flag.finder != nil {
return flag.finder, nil
}
c, err := flag.Client()
if err != nil {
return nil, err
}
allFlag := false
if len(all) == 1 {
allFlag = all[0]
}
finder := find.NewFinder(c, allFlag)
// Datacenter is not required (ls command for example).
// Set for relative func if dc flag is given or
// if there is a single (default) Datacenter
ctx := context.TODO()
if flag.Name == "" {
flag.dc, flag.err = finder.DefaultDatacenter(ctx)
} else {
if flag.dc, err = finder.Datacenter(ctx, flag.Name); err != nil {
return nil, err
}
}
finder.SetDatacenter(flag.dc)
flag.finder = finder
return flag.finder, nil
}
func (flag *DatacenterFlag) Datacenter() (*object.Datacenter, error) {
if flag.dc != nil {
return flag.dc, nil
}
_, err := flag.Finder()
if err != nil {
return nil, err
}
if flag.err != nil {
// Should only happen if no dc is specified and len(dcs) > 1
return nil, flag.err
}
return flag.dc, err
}
func (flag *DatacenterFlag) DatacenterIfSpecified() (*object.Datacenter, error) {
if flag.Name == "" {
return nil, nil
}
return flag.Datacenter()
}
func (flag *DatacenterFlag) ManagedObject(ctx context.Context, arg string) (types.ManagedObjectReference, error) {
var ref types.ManagedObjectReference
finder, err := flag.Finder()
if err != nil {
return ref, err
}
if ref.FromString(arg) {
if strings.HasPrefix(ref.Type, "com.vmware.content.") {
return ref, nil // special case for content library
}
pc := property.DefaultCollector(flag.client)
var content []types.ObjectContent
err = pc.RetrieveOne(ctx, ref, []string{"name"}, &content)
if err == nil {
return ref, nil
}
}
l, err := finder.ManagedObjectList(ctx, arg)
if err != nil {
return ref, err
}
switch len(l) {
case 0:
return ref, fmt.Errorf("%s not found", arg)
case 1:
return l[0].Object.Reference(), nil
default:
var objs []types.ManagedObjectReference
for _, o := range l {
objs = append(objs, o.Object.Reference())
}
return ref, fmt.Errorf("%d objects at path %q: %s", len(l), arg, objs)
}
}
func (flag *DatacenterFlag) ManagedObjects(ctx context.Context, args []string) ([]types.ManagedObjectReference, error) {
var refs []types.ManagedObjectReference
c, err := flag.Client()
if err != nil {
return nil, err
}
if len(args) == 0 {
refs = append(refs, c.ServiceContent.RootFolder)
return refs, nil
}
finder, err := flag.Finder()
if err != nil {
return nil, err
}
for _, arg := range args {
var ref types.ManagedObjectReference
if ref.FromString(arg) {
// e.g. output from object.collect
refs = append(refs, ref)
continue
}
elements, err := finder.ManagedObjectList(ctx, arg)
if err != nil {
return nil, err
}
if len(elements) == 0 {
return nil, fmt.Errorf("object '%s' not found", arg)
}
for _, e := range elements {
refs = append(refs, e.Object.Reference())
}
}
return refs, nil
}

View file

@ -0,0 +1,146 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"flag"
"fmt"
"os"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/types"
)
type DatastoreFlag struct {
common
*DatacenterFlag
Name string
ds *object.Datastore
}
var datastoreFlagKey = flagKey("datastore")
// NewCustomDatastoreFlag creates and returns a new DatastoreFlag without
// trying to retrieve an existing one from the specified context.
func NewCustomDatastoreFlag(ctx context.Context) (*DatastoreFlag, context.Context) {
v := &DatastoreFlag{}
v.DatacenterFlag, ctx = NewDatacenterFlag(ctx)
return v, ctx
}
func NewDatastoreFlag(ctx context.Context) (*DatastoreFlag, context.Context) {
if v := ctx.Value(datastoreFlagKey); v != nil {
return v.(*DatastoreFlag), ctx
}
v, ctx := NewCustomDatastoreFlag(ctx)
ctx = context.WithValue(ctx, datastoreFlagKey, v)
return v, ctx
}
func (f *DatastoreFlag) Register(ctx context.Context, fs *flag.FlagSet) {
f.RegisterOnce(func() {
f.DatacenterFlag.Register(ctx, fs)
env := "GOVC_DATASTORE"
value := os.Getenv(env)
usage := fmt.Sprintf("Datastore [%s]", env)
fs.StringVar(&f.Name, "ds", value, usage)
})
}
func (f *DatastoreFlag) Process(ctx context.Context) error {
return f.ProcessOnce(func() error {
if err := f.DatacenterFlag.Process(ctx); err != nil {
return err
}
return nil
})
}
func (f *DatastoreFlag) Args(args []string) []object.DatastorePath {
var files []object.DatastorePath
for _, arg := range args {
var p object.DatastorePath
if p.FromString(arg) {
f.Name = p.Datastore
} else {
p.Datastore = f.Name
p.Path = arg
}
files = append(files, p)
}
return files
}
func (f *DatastoreFlag) Datastore() (*object.Datastore, error) {
if f.ds != nil {
return f.ds, nil
}
var p object.DatastorePath
if p.FromString(f.Name) {
// Example use case:
// -ds "$(govc object.collect -s vm/foo config.files.logDirectory)"
f.Name = p.Datastore
}
finder, err := f.Finder()
if err != nil {
return nil, err
}
if f.ds, err = finder.DatastoreOrDefault(context.TODO(), f.Name); err != nil {
return nil, err
}
return f.ds, nil
}
func (flag *DatastoreFlag) DatastoreIfSpecified() (*object.Datastore, error) {
if flag.Name == "" {
return nil, nil
}
return flag.Datastore()
}
func (f *DatastoreFlag) DatastorePath(name string) (string, error) {
ds, err := f.Datastore()
if err != nil {
return "", err
}
return ds.Path(name), nil
}
func (f *DatastoreFlag) Stat(ctx context.Context, file string) (types.BaseFileInfo, error) {
ds, err := f.Datastore()
if err != nil {
return nil, err
}
return ds.Stat(ctx, file)
}

103
vendor/github.com/vmware/govmomi/govc/flags/debug.go generated vendored Normal file
View file

@ -0,0 +1,103 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"flag"
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/vmware/govmomi/vim25/debug"
)
type DebugFlag struct {
common
enable bool
}
var debugFlagKey = flagKey("debug")
func NewDebugFlag(ctx context.Context) (*DebugFlag, context.Context) {
if v := ctx.Value(debugFlagKey); v != nil {
return v.(*DebugFlag), ctx
}
v := &DebugFlag{}
ctx = context.WithValue(ctx, debugFlagKey, v)
return v, ctx
}
func (flag *DebugFlag) Register(ctx context.Context, f *flag.FlagSet) {
flag.RegisterOnce(func() {
env := "GOVC_DEBUG"
enable := false
switch env := strings.ToLower(os.Getenv(env)); env {
case "1", "true":
enable = true
}
usage := fmt.Sprintf("Store debug logs [%s]", env)
f.BoolVar(&flag.enable, "debug", enable, usage)
})
}
func (flag *DebugFlag) Process(ctx context.Context) error {
if !flag.enable {
return nil
}
return flag.ProcessOnce(func() error {
// Base path for storing debug logs.
r := os.Getenv("GOVC_DEBUG_PATH")
switch r {
case "-":
debug.SetProvider(&debug.LogProvider{})
return nil
case "":
r = home
}
r = filepath.Join(r, "debug")
// Path for this particular run.
run := os.Getenv("GOVC_DEBUG_PATH_RUN")
if run == "" {
now := time.Now().Format("2006-01-02T15-04-05.999999999")
r = filepath.Join(r, now)
} else {
// reuse the same path
r = filepath.Join(r, run)
_ = os.RemoveAll(r)
}
err := os.MkdirAll(r, 0700)
if err != nil {
return err
}
p := debug.FileProvider{
Path: r,
}
debug.SetProvider(&p)
return nil
})
}

31
vendor/github.com/vmware/govmomi/govc/flags/empty.go generated vendored Normal file
View file

@ -0,0 +1,31 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"flag"
)
type EmptyFlag struct{}
func (flag *EmptyFlag) Register(ctx context.Context, f *flag.FlagSet) {
}
func (flag *EmptyFlag) Process(ctx context.Context) error {
return nil
}

138
vendor/github.com/vmware/govmomi/govc/flags/folder.go generated vendored Normal file
View file

@ -0,0 +1,138 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"flag"
"fmt"
"os"
"github.com/vmware/govmomi/object"
)
type FolderFlag struct {
common
*DatacenterFlag
name string
folder *object.Folder
}
var folderFlagKey = flagKey("folder")
func NewFolderFlag(ctx context.Context) (*FolderFlag, context.Context) {
if v := ctx.Value(folderFlagKey); v != nil {
return v.(*FolderFlag), ctx
}
v := &FolderFlag{}
v.DatacenterFlag, ctx = NewDatacenterFlag(ctx)
ctx = context.WithValue(ctx, folderFlagKey, v)
return v, ctx
}
func (flag *FolderFlag) Register(ctx context.Context, f *flag.FlagSet) {
flag.RegisterOnce(func() {
flag.DatacenterFlag.Register(ctx, f)
env := "GOVC_FOLDER"
value := os.Getenv(env)
usage := fmt.Sprintf("Inventory folder [%s]", env)
f.StringVar(&flag.name, "folder", value, usage)
})
}
func (flag *FolderFlag) Process(ctx context.Context) error {
return flag.ProcessOnce(func() error {
if err := flag.DatacenterFlag.Process(ctx); err != nil {
return err
}
return nil
})
}
func (flag *FolderFlag) Folder() (*object.Folder, error) {
if flag.folder != nil {
return flag.folder, nil
}
finder, err := flag.Finder()
if err != nil {
return nil, err
}
if flag.folder, err = finder.FolderOrDefault(context.TODO(), flag.name); err != nil {
return nil, err
}
return flag.folder, nil
}
func (flag *FolderFlag) FolderIfSpecified() (*object.Folder, error) {
if flag.name == "" {
return nil, nil
}
return flag.Folder()
}
func (flag *FolderFlag) FolderOrDefault(kind string) (*object.Folder, error) {
if flag.folder != nil {
return flag.folder, nil
}
if flag.name != "" {
return flag.Folder()
}
// RootFolder, no dc required
if kind == "/" {
client, err := flag.Client()
if err != nil {
return nil, err
}
flag.folder = object.NewRootFolder(client)
return flag.folder, nil
}
dc, err := flag.Datacenter()
if err != nil {
return nil, err
}
folders, err := dc.Folders(context.TODO())
if err != nil {
return nil, err
}
switch kind {
case "vm":
flag.folder = folders.VmFolder
case "host":
flag.folder = folders.HostFolder
case "datastore":
flag.folder = folders.DatastoreFolder
case "network":
flag.folder = folders.NetworkFolder
default:
panic(kind)
}
return flag.folder, nil
}

View file

@ -0,0 +1,100 @@
/*
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"flag"
"fmt"
"net/url"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/types"
)
type HostConnectFlag struct {
common
types.HostConnectSpec
noverify bool
}
var hostConnectFlagKey = flagKey("hostConnect")
func NewHostConnectFlag(ctx context.Context) (*HostConnectFlag, context.Context) {
if v := ctx.Value(hostConnectFlagKey); v != nil {
return v.(*HostConnectFlag), ctx
}
v := &HostConnectFlag{}
ctx = context.WithValue(ctx, hostConnectFlagKey, v)
return v, ctx
}
func (flag *HostConnectFlag) Register(ctx context.Context, f *flag.FlagSet) {
flag.RegisterOnce(func() {
f.StringVar(&flag.HostName, "hostname", "", "Hostname or IP address of the host")
f.StringVar(&flag.UserName, "username", "", "Username of administration account on the host")
f.StringVar(&flag.Password, "password", "", "Password of administration account on the host")
f.StringVar(&flag.SslThumbprint, "thumbprint", "", "SHA-1 thumbprint of the host's SSL certificate")
f.BoolVar(&flag.Force, "force", false, "Force when host is managed by another VC")
f.BoolVar(&flag.noverify, "noverify", false, "Accept host thumbprint without verification")
})
}
func (flag *HostConnectFlag) Process(ctx context.Context) error {
return nil
}
// Spec attempts to fill in SslThumbprint if empty.
// First checks GOVC_TLS_KNOWN_HOSTS, if not found and noverify=true then
// use object.HostCertificateInfo to get the thumbprint.
func (flag *HostConnectFlag) Spec(c *vim25.Client) types.HostConnectSpec {
spec := flag.HostConnectSpec
if spec.SslThumbprint == "" {
spec.SslThumbprint = c.Thumbprint(spec.HostName)
if spec.SslThumbprint == "" && flag.noverify {
var info object.HostCertificateInfo
t := c.DefaultTransport()
_ = info.FromURL(&url.URL{Host: spec.HostName}, t.TLSClientConfig)
spec.SslThumbprint = info.ThumbprintSHA1
}
}
return spec
}
// Fault checks if error is SSLVerifyFault, including the thumbprint if so
func (flag *HostConnectFlag) Fault(err error) error {
if err == nil {
return nil
}
if f, ok := err.(types.HasFault); ok {
switch fault := f.Fault().(type) {
case *types.SSLVerifyFault:
return fmt.Errorf("%s thumbprint=%s", err, fault.Thumbprint)
}
}
return err
}

View file

@ -0,0 +1,141 @@
/*
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"flag"
"fmt"
"os"
"github.com/vmware/govmomi/object"
)
type HostSystemFlag struct {
common
*ClientFlag
*DatacenterFlag
*SearchFlag
name string
host *object.HostSystem
pool *object.ResourcePool
}
var hostSystemFlagKey = flagKey("hostSystem")
func NewHostSystemFlag(ctx context.Context) (*HostSystemFlag, context.Context) {
if v := ctx.Value(hostSystemFlagKey); v != nil {
return v.(*HostSystemFlag), ctx
}
v := &HostSystemFlag{}
v.ClientFlag, ctx = NewClientFlag(ctx)
v.DatacenterFlag, ctx = NewDatacenterFlag(ctx)
v.SearchFlag, ctx = NewSearchFlag(ctx, SearchHosts)
ctx = context.WithValue(ctx, hostSystemFlagKey, v)
return v, ctx
}
func (flag *HostSystemFlag) Register(ctx context.Context, f *flag.FlagSet) {
flag.RegisterOnce(func() {
flag.ClientFlag.Register(ctx, f)
flag.DatacenterFlag.Register(ctx, f)
flag.SearchFlag.Register(ctx, f)
env := "GOVC_HOST"
value := os.Getenv(env)
usage := fmt.Sprintf("Host system [%s]", env)
f.StringVar(&flag.name, "host", value, usage)
})
}
func (flag *HostSystemFlag) Process(ctx context.Context) error {
return flag.ProcessOnce(func() error {
if err := flag.ClientFlag.Process(ctx); err != nil {
return err
}
if err := flag.DatacenterFlag.Process(ctx); err != nil {
return err
}
if err := flag.SearchFlag.Process(ctx); err != nil {
return err
}
return nil
})
}
func (flag *HostSystemFlag) HostSystemIfSpecified() (*object.HostSystem, error) {
if flag.host != nil {
return flag.host, nil
}
// Use search flags if specified.
if flag.SearchFlag.IsSet() {
host, err := flag.SearchFlag.HostSystem()
if err != nil {
return nil, err
}
flag.host = host
return flag.host, nil
}
// Never look for a default host system.
// A host system parameter is optional for vm creation. It uses a mandatory
// resource pool parameter to determine where the vm should be placed.
if flag.name == "" {
return nil, nil
}
finder, err := flag.Finder()
if err != nil {
return nil, err
}
flag.host, err = finder.HostSystem(context.TODO(), flag.name)
return flag.host, err
}
func (flag *HostSystemFlag) HostSystem() (*object.HostSystem, error) {
host, err := flag.HostSystemIfSpecified()
if err != nil {
return nil, err
}
if host != nil {
return host, nil
}
finder, err := flag.Finder()
if err != nil {
return nil, err
}
flag.host, err = finder.DefaultHostSystem(context.TODO())
return flag.host, err
}
func (flag *HostSystemFlag) HostNetworkSystem() (*object.HostNetworkSystem, error) {
host, err := flag.HostSystem()
if err != nil {
return nil, err
}
return host.ConfigManager().NetworkSystem(context.TODO())
}

72
vendor/github.com/vmware/govmomi/govc/flags/int32.go generated vendored Normal file
View file

@ -0,0 +1,72 @@
/*
Copyright (c) 2016-2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"flag"
"fmt"
"strconv"
)
// This flag type is internal to stdlib:
// https://github.com/golang/go/blob/master/src/cmd/internal/obj/flag.go
type int32Value int32
func (i *int32Value) Set(s string) error {
v, err := strconv.ParseInt(s, 0, 32)
*i = int32Value(v)
return err
}
func (i *int32Value) Get() interface{} {
return int32(*i)
}
func (i *int32Value) String() string {
return fmt.Sprintf("%v", *i)
}
// NewInt32 behaves as flag.IntVar, but using an int32 type.
func NewInt32(v *int32) flag.Value {
return (*int32Value)(v)
}
type int32ptrValue struct {
val **int32
}
func (i *int32ptrValue) Set(s string) error {
v, err := strconv.ParseInt(s, 0, 32)
*i.val = new(int32)
**i.val = int32(v)
return err
}
func (i *int32ptrValue) Get() interface{} {
if i.val == nil || *i.val == nil {
return nil
}
return *i.val
}
func (i *int32ptrValue) String() string {
return fmt.Sprintf("%v", i.Get())
}
func NewOptionalInt32(v **int32) flag.Value {
return &int32ptrValue{val: v}
}

72
vendor/github.com/vmware/govmomi/govc/flags/int64.go generated vendored Normal file
View file

@ -0,0 +1,72 @@
/*
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"flag"
"fmt"
"strconv"
)
// This flag type is internal to stdlib:
// https://github.com/golang/go/blob/master/src/cmd/internal/obj/flag.go
type int64Value int64
func (i *int64Value) Set(s string) error {
v, err := strconv.ParseInt(s, 0, 64)
*i = int64Value(v)
return err
}
func (i *int64Value) Get() interface{} {
return int64(*i)
}
func (i *int64Value) String() string {
return fmt.Sprintf("%v", *i)
}
// NewInt64 behaves as flag.IntVar, but using an int64 type.
func NewInt64(v *int64) flag.Value {
return (*int64Value)(v)
}
type int64ptrValue struct {
val **int64
}
func (i *int64ptrValue) Set(s string) error {
v, err := strconv.ParseInt(s, 0, 64)
*i.val = new(int64)
**i.val = int64(v)
return err
}
func (i *int64ptrValue) Get() interface{} {
if i.val == nil || *i.val == nil {
return nil
}
return **i.val
}
func (i *int64ptrValue) String() string {
return fmt.Sprintf("%v", i.Get())
}
func NewOptionalInt64(v **int64) flag.Value {
return &int64ptrValue{val: v}
}

93
vendor/github.com/vmware/govmomi/govc/flags/library.go generated vendored Normal file
View file

@ -0,0 +1,93 @@
/*
Copyright (c) 2020 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"fmt"
"github.com/vmware/govmomi/vapi/library"
"github.com/vmware/govmomi/vapi/library/finder"
"github.com/vmware/govmomi/vapi/rest"
)
// errContentLibraryMatch is an error returned when a query returns more than one result.
type errContentLibraryMatch struct {
// Type is the type of object being queried.
Type string
// Key is the key used to perform the query.
Key string
// Val is the value used to perform the query.
Val string
// Count is the number of objects returned.
Count int
}
// Error returns the error string.
func (e errContentLibraryMatch) Error() string {
kind := e.Type
if kind == "" {
kind = "library|item"
}
hint := ""
if e.Count > 1 {
hint = fmt.Sprintf(" (use %q ID instead of NAME)", kind)
}
return fmt.Sprintf("%q=%q matches %d items%s", e.Key, e.Val, e.Count, hint)
}
func ContentLibraryResult(ctx context.Context, c *rest.Client, kind string, path string) (finder.FindResult, error) {
res, err := finder.NewFinder(library.NewManager(c)).Find(ctx, path)
if err != nil {
return nil, err
}
if len(res) != 1 {
return nil, errContentLibraryMatch{Type: kind, Key: "path", Val: path, Count: len(res)}
}
return res[0], nil
}
// ContentLibrary attempts to find a content library with the given path,
// asserting 1 match of type library.Library.
func ContentLibrary(ctx context.Context, c *rest.Client, path string) (*library.Library, error) {
r, err := ContentLibraryResult(ctx, c, "library", path)
if err != nil {
return nil, err
}
lib, ok := r.GetResult().(library.Library)
if !ok {
return nil, fmt.Errorf("%q is a %T", path, r)
}
return &lib, nil
}
// ContentLibraryItem attempts to find a content library with the given path,
// asserting 1 match of type library.Item.
func ContentLibraryItem(ctx context.Context, c *rest.Client, path string) (*library.Item, error) {
r, err := ContentLibraryResult(ctx, c, "item", path)
if err != nil {
return nil, err
}
item, ok := r.GetResult().(library.Item)
if !ok {
return nil, fmt.Errorf("%q is a %T", path, r)
}
return &item, nil
}

30
vendor/github.com/vmware/govmomi/govc/flags/list.go generated vendored Normal file
View file

@ -0,0 +1,30 @@
/*
Copyright (c) 2019 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import "fmt"
type StringList []string
func (l *StringList) String() string {
return fmt.Sprint(*l)
}
func (l *StringList) Set(value string) error {
*l = append(*l, value)
return nil
}

147
vendor/github.com/vmware/govmomi/govc/flags/network.go generated vendored Normal file
View file

@ -0,0 +1,147 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"flag"
"fmt"
"os"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/types"
)
type NetworkFlag struct {
common
*DatacenterFlag
name string
net object.NetworkReference
adapter string
address string
isset bool
}
var networkFlagKey = flagKey("network")
func NewNetworkFlag(ctx context.Context) (*NetworkFlag, context.Context) {
if v := ctx.Value(networkFlagKey); v != nil {
return v.(*NetworkFlag), ctx
}
v := &NetworkFlag{}
v.DatacenterFlag, ctx = NewDatacenterFlag(ctx)
ctx = context.WithValue(ctx, networkFlagKey, v)
return v, ctx
}
func (flag *NetworkFlag) Register(ctx context.Context, f *flag.FlagSet) {
flag.RegisterOnce(func() {
flag.DatacenterFlag.Register(ctx, f)
env := "GOVC_NETWORK"
value := os.Getenv(env)
flag.name = value
usage := fmt.Sprintf("Network [%s]", env)
f.Var(flag, "net", usage)
f.StringVar(&flag.adapter, "net.adapter", "e1000", "Network adapter type")
f.StringVar(&flag.address, "net.address", "", "Network hardware address")
})
}
func (flag *NetworkFlag) Process(ctx context.Context) error {
return flag.ProcessOnce(func() error {
if err := flag.DatacenterFlag.Process(ctx); err != nil {
return err
}
return nil
})
}
func (flag *NetworkFlag) String() string {
return flag.name
}
func (flag *NetworkFlag) Set(name string) error {
flag.name = name
flag.isset = true
return nil
}
func (flag *NetworkFlag) IsSet() bool {
return flag.isset
}
func (flag *NetworkFlag) Network() (object.NetworkReference, error) {
if flag.net != nil {
return flag.net, nil
}
finder, err := flag.Finder()
if err != nil {
return nil, err
}
if flag.net, err = finder.NetworkOrDefault(context.TODO(), flag.name); err != nil {
return nil, err
}
return flag.net, nil
}
func (flag *NetworkFlag) Device() (types.BaseVirtualDevice, error) {
net, err := flag.Network()
if err != nil {
return nil, err
}
backing, err := net.EthernetCardBackingInfo(context.TODO())
if err != nil {
return nil, err
}
device, err := object.EthernetCardTypes().CreateEthernetCard(flag.adapter, backing)
if err != nil {
return nil, err
}
if flag.address != "" {
card := device.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard()
card.AddressType = string(types.VirtualEthernetCardMacTypeManual)
card.MacAddress = flag.address
}
return device, nil
}
// Change applies update backing and hardware address changes to the given network device.
func (flag *NetworkFlag) Change(device types.BaseVirtualDevice, update types.BaseVirtualDevice) {
current := device.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard()
changed := update.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard()
current.Backing = changed.Backing
if changed.MacAddress != "" {
current.MacAddress = changed.MacAddress
}
if changed.AddressType != "" {
current.AddressType = changed.AddressType
}
}

View file

@ -0,0 +1,55 @@
/*
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"flag"
"fmt"
"strconv"
)
type optionalBool struct {
val **bool
}
func (b *optionalBool) Set(s string) error {
v, err := strconv.ParseBool(s)
*b.val = &v
return err
}
func (b *optionalBool) Get() interface{} {
if *b.val == nil {
return nil
}
return **b.val
}
func (b *optionalBool) String() string {
if b.val == nil || *b.val == nil {
return "<nil>"
}
return fmt.Sprintf("%v", **b.val)
}
func (b *optionalBool) IsBoolFlag() bool { return true }
// NewOptionalBool returns a flag.Value implementation where there is no default value.
// This avoids sending a default value over the wire as using flag.BoolVar() would.
func NewOptionalBool(v **bool) flag.Value {
return &optionalBool{v}
}

343
vendor/github.com/vmware/govmomi/govc/flags/output.go generated vendored Normal file
View file

@ -0,0 +1,343 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"encoding/json"
"errors"
"flag"
"fmt"
"io"
"os"
"reflect"
"sync"
"time"
"github.com/kr/pretty"
"github.com/vmware/govmomi/task"
"github.com/vmware/govmomi/vim25/progress"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/xml"
)
type OutputWriter interface {
Write(io.Writer) error
}
type OutputFlag struct {
common
JSON bool
XML bool
TTY bool
Dump bool
Out io.Writer
formatError bool
formatIndent bool
}
var outputFlagKey = flagKey("output")
func NewOutputFlag(ctx context.Context) (*OutputFlag, context.Context) {
if v := ctx.Value(outputFlagKey); v != nil {
return v.(*OutputFlag), ctx
}
v := &OutputFlag{Out: os.Stdout}
ctx = context.WithValue(ctx, outputFlagKey, v)
return v, ctx
}
func (flag *OutputFlag) Register(ctx context.Context, f *flag.FlagSet) {
flag.RegisterOnce(func() {
f.BoolVar(&flag.JSON, "json", false, "Enable JSON output")
f.BoolVar(&flag.XML, "xml", false, "Enable XML output")
f.BoolVar(&flag.Dump, "dump", false, "Enable Go output")
// Avoid adding more flags for now..
flag.formatIndent = os.Getenv("GOVC_INDENT") != "false" // Default to indented output
flag.formatError = os.Getenv("GOVC_FORMAT_ERROR") != "false" // Default to formatted errors
})
}
func (flag *OutputFlag) Process(ctx context.Context) error {
return flag.ProcessOnce(func() error {
if !flag.All() {
// Assume we have a tty if not outputting JSON
flag.TTY = true
}
return nil
})
}
// Log outputs the specified string, prefixed with the current time.
// A newline is not automatically added. If the specified string
// starts with a '\r', the current line is cleared first.
func (flag *OutputFlag) Log(s string) (int, error) {
if len(s) > 0 && s[0] == '\r' {
flag.Write([]byte{'\r', 033, '[', 'K'})
s = s[1:]
}
return flag.WriteString(time.Now().Format("[02-01-06 15:04:05] ") + s)
}
func (flag *OutputFlag) Write(b []byte) (int, error) {
if !flag.TTY {
return 0, nil
}
n, err := os.Stdout.Write(b)
os.Stdout.Sync()
return n, err
}
func (flag *OutputFlag) WriteString(s string) (int, error) {
return flag.Write([]byte(s))
}
func (flag *OutputFlag) All() bool {
return flag.JSON || flag.XML || flag.Dump
}
func dumpValue(val interface{}) interface{} {
type dumper interface {
Dump() interface{}
}
if d, ok := val.(dumper); ok {
return d.Dump()
}
rval := reflect.ValueOf(val)
if rval.Type().Kind() != reflect.Ptr {
return val
}
rval = rval.Elem()
if rval.Type().Kind() == reflect.Struct {
f := rval.Field(0)
if f.Type().Kind() == reflect.Slice {
// common case for the various 'type infoResult'
if f.Len() == 1 {
return f.Index(0).Interface()
}
return f.Interface()
}
if rval.NumField() == 1 && rval.Type().Field(0).Anonymous {
// common case where govc type wraps govmomi type to implement OutputWriter
return f.Interface()
}
}
return val
}
func (flag *OutputFlag) WriteResult(result OutputWriter) error {
var err error
switch {
case flag.Dump:
format := "%#v\n"
if flag.formatIndent {
format = "%# v\n"
}
_, err = pretty.Fprintf(flag.Out, format, dumpValue(result))
case flag.JSON:
e := json.NewEncoder(flag.Out)
if flag.formatIndent {
e.SetIndent("", " ")
}
err = e.Encode(result)
case flag.XML:
e := xml.NewEncoder(flag.Out)
if flag.formatIndent {
e.Indent("", " ")
}
err = e.Encode(dumpValue(result))
if err == nil {
fmt.Fprintln(flag.Out)
}
default:
err = result.Write(flag.Out)
}
return err
}
func (flag *OutputFlag) WriteError(err error) bool {
if flag.formatError {
flag.Out = os.Stderr
return flag.WriteResult(&errorOutput{err}) == nil
}
return false
}
type errorOutput struct {
error
}
func (e errorOutput) Write(w io.Writer) error {
_, ferr := fmt.Fprintf(w, "%s: %s\n", os.Args[0], e.error)
return ferr
}
func (e errorOutput) Dump() interface{} {
if f, ok := e.error.(task.Error); ok {
return f.LocalizedMethodFault
}
if soap.IsSoapFault(e.error) {
return soap.ToSoapFault(e.error)
}
if soap.IsVimFault(e.error) {
return soap.ToVimFault(e.error)
}
return e
}
func (e errorOutput) canEncode() bool {
switch e.error.(type) {
case task.Error:
return true
}
return soap.IsSoapFault(e.error) || soap.IsVimFault(e.error)
}
// cannotEncode causes cli.Run to output err.Error() as it would without an error format specified
var cannotEncode = errors.New("cannot encode error")
func (e errorOutput) MarshalJSON() ([]byte, error) {
_, ok := e.error.(json.Marshaler)
if ok || e.canEncode() {
return json.Marshal(e.error)
}
return nil, cannotEncode
}
func (e errorOutput) MarshalXML(encoder *xml.Encoder, start xml.StartElement) error {
_, ok := e.error.(xml.Marshaler)
if ok || e.canEncode() {
return encoder.Encode(e.error)
}
return cannotEncode
}
type progressLogger struct {
flag *OutputFlag
prefix string
wg sync.WaitGroup
sink chan chan progress.Report
done chan struct{}
}
func newProgressLogger(flag *OutputFlag, prefix string) *progressLogger {
p := &progressLogger{
flag: flag,
prefix: prefix,
sink: make(chan chan progress.Report),
done: make(chan struct{}),
}
p.wg.Add(1)
go p.loopA()
return p
}
// loopA runs before Sink() has been called.
func (p *progressLogger) loopA() {
var err error
defer p.wg.Done()
tick := time.NewTicker(100 * time.Millisecond)
defer tick.Stop()
called := false
for stop := false; !stop; {
select {
case ch := <-p.sink:
err = p.loopB(tick, ch)
stop = true
called = true
case <-p.done:
stop = true
case <-tick.C:
line := fmt.Sprintf("\r%s", p.prefix)
p.flag.Log(line)
}
}
if err != nil && err != io.EOF {
p.flag.Log(fmt.Sprintf("\r%sError: %s\n", p.prefix, err))
} else if called {
p.flag.Log(fmt.Sprintf("\r%sOK\n", p.prefix))
}
}
// loopA runs after Sink() has been called.
func (p *progressLogger) loopB(tick *time.Ticker, ch <-chan progress.Report) error {
var r progress.Report
var ok bool
var err error
for ok = true; ok; {
select {
case r, ok = <-ch:
if !ok {
break
}
err = r.Error()
case <-tick.C:
line := fmt.Sprintf("\r%s", p.prefix)
if r != nil {
line += fmt.Sprintf("(%.0f%%", r.Percentage())
detail := r.Detail()
if detail != "" {
line += fmt.Sprintf(", %s", detail)
}
line += ")"
}
p.flag.Log(line)
}
}
return err
}
func (p *progressLogger) Sink() chan<- progress.Report {
ch := make(chan progress.Report)
p.sink <- ch
return ch
}
func (p *progressLogger) Wait() {
close(p.done)
p.wg.Wait()
}
func (flag *OutputFlag) ProgressLogger(prefix string) *progressLogger {
return newProgressLogger(flag, prefix)
}

View file

@ -0,0 +1,85 @@
/*
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"flag"
"strconv"
"strings"
"github.com/vmware/govmomi/vim25/types"
)
type sharesInfo types.SharesInfo
func (s *sharesInfo) String() string {
return string(s.Level)
}
func (s *sharesInfo) Set(val string) error {
switch val {
case string(types.SharesLevelNormal), string(types.SharesLevelLow), string(types.SharesLevelHigh):
s.Level = types.SharesLevel(val)
default:
n, err := strconv.Atoi(val)
if err != nil {
return err
}
s.Level = types.SharesLevelCustom
s.Shares = int32(n)
}
return nil
}
type ResourceAllocationFlag struct {
cpu, mem *types.ResourceAllocationInfo
ExpandableReservation bool
}
func NewResourceAllocationFlag(cpu, mem *types.ResourceAllocationInfo) *ResourceAllocationFlag {
return &ResourceAllocationFlag{cpu, mem, true}
}
func (r *ResourceAllocationFlag) Register(ctx context.Context, f *flag.FlagSet) {
opts := []struct {
name string
units string
*types.ResourceAllocationInfo
}{
{"CPU", "MHz", r.cpu},
{"Memory", "MB", r.mem},
}
for _, opt := range opts {
prefix := strings.ToLower(opt.name)[:3]
shares := (*sharesInfo)(opt.Shares)
f.Var(NewOptionalInt64(&opt.Limit), prefix+".limit", opt.name+" limit in "+opt.units)
f.Var(NewOptionalInt64(&opt.Reservation), prefix+".reservation", opt.name+" reservation in "+opt.units)
if r.ExpandableReservation {
f.Var(NewOptionalBool(&opt.ExpandableReservation), prefix+".expandable", opt.name+" expandable reservation")
}
f.Var(shares, prefix+".shares", opt.name+" shares level or number")
}
}
func (s *ResourceAllocationFlag) Process(ctx context.Context) error {
return nil
}

View file

@ -0,0 +1,102 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"flag"
"fmt"
"os"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/object"
)
type ResourcePoolFlag struct {
common
*DatacenterFlag
name string
pool *object.ResourcePool
}
var resourcePoolFlagKey = flagKey("resourcePool")
func NewResourcePoolFlag(ctx context.Context) (*ResourcePoolFlag, context.Context) {
if v := ctx.Value(resourcePoolFlagKey); v != nil {
return v.(*ResourcePoolFlag), ctx
}
v := &ResourcePoolFlag{}
v.DatacenterFlag, ctx = NewDatacenterFlag(ctx)
ctx = context.WithValue(ctx, resourcePoolFlagKey, v)
return v, ctx
}
func (flag *ResourcePoolFlag) Register(ctx context.Context, f *flag.FlagSet) {
flag.RegisterOnce(func() {
flag.DatacenterFlag.Register(ctx, f)
env := "GOVC_RESOURCE_POOL"
value := os.Getenv(env)
usage := fmt.Sprintf("Resource pool [%s]", env)
f.StringVar(&flag.name, "pool", value, usage)
})
}
func (flag *ResourcePoolFlag) Process(ctx context.Context) error {
return flag.ProcessOnce(func() error {
if err := flag.DatacenterFlag.Process(ctx); err != nil {
return err
}
return nil
})
}
func (flag *ResourcePoolFlag) ResourcePool() (*object.ResourcePool, error) {
if flag.pool != nil {
return flag.pool, nil
}
finder, err := flag.Finder()
if err != nil {
return nil, err
}
flag.pool, err = finder.ResourcePoolOrDefault(context.TODO(), flag.name)
if err != nil {
if _, ok := err.(*find.NotFoundError); ok {
vapp, verr := finder.VirtualApp(context.TODO(), flag.name)
if verr != nil {
return nil, err
}
flag.pool = vapp.ResourcePool
} else {
return nil, err
}
}
return flag.pool, nil
}
func (flag *ResourcePoolFlag) ResourcePoolIfSpecified() (*object.ResourcePool, error) {
if flag.name == "" {
return nil, nil
}
return flag.ResourcePool()
}

438
vendor/github.com/vmware/govmomi/govc/flags/search.go generated vendored Normal file
View file

@ -0,0 +1,438 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"errors"
"flag"
"fmt"
"strings"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
)
const (
SearchVirtualMachines = iota + 1
SearchHosts
SearchVirtualApps
)
type SearchFlag struct {
common
*ClientFlag
*DatacenterFlag
t int
entity string
byDatastorePath string
byDNSName string
byInventoryPath string
byIP string
byUUID string
isset bool
}
var searchFlagKey = flagKey("search")
func NewSearchFlag(ctx context.Context, t int) (*SearchFlag, context.Context) {
if v := ctx.Value(searchFlagKey); v != nil {
return v.(*SearchFlag), ctx
}
v := &SearchFlag{
t: t,
}
v.ClientFlag, ctx = NewClientFlag(ctx)
v.DatacenterFlag, ctx = NewDatacenterFlag(ctx)
switch t {
case SearchVirtualMachines:
v.entity = "VM"
case SearchHosts:
v.entity = "host"
case SearchVirtualApps:
v.entity = "vapp"
default:
panic("invalid search type")
}
ctx = context.WithValue(ctx, searchFlagKey, v)
return v, ctx
}
func (flag *SearchFlag) Register(ctx context.Context, fs *flag.FlagSet) {
flag.RegisterOnce(func() {
flag.ClientFlag.Register(ctx, fs)
flag.DatacenterFlag.Register(ctx, fs)
register := func(v *string, f string, d string) {
f = fmt.Sprintf("%s.%s", strings.ToLower(flag.entity), f)
d = fmt.Sprintf(d, flag.entity)
fs.StringVar(v, f, "", d)
}
switch flag.t {
case SearchVirtualMachines:
register(&flag.byDatastorePath, "path", "Find %s by path to .vmx file")
}
switch flag.t {
case SearchVirtualMachines, SearchHosts:
register(&flag.byDNSName, "dns", "Find %s by FQDN")
register(&flag.byIP, "ip", "Find %s by IP address")
register(&flag.byUUID, "uuid", "Find %s by UUID")
}
register(&flag.byInventoryPath, "ipath", "Find %s by inventory path")
})
}
func (flag *SearchFlag) Process(ctx context.Context) error {
return flag.ProcessOnce(func() error {
if err := flag.ClientFlag.Process(ctx); err != nil {
return err
}
if err := flag.DatacenterFlag.Process(ctx); err != nil {
return err
}
flags := []string{
flag.byDatastorePath,
flag.byDNSName,
flag.byInventoryPath,
flag.byIP,
flag.byUUID,
}
flag.isset = false
for _, f := range flags {
if f != "" {
if flag.isset {
return errors.New("cannot use more than one search flag")
}
flag.isset = true
}
}
return nil
})
}
func (flag *SearchFlag) IsSet() bool {
return flag.isset
}
func (flag *SearchFlag) searchIndex(c *vim25.Client) *object.SearchIndex {
return object.NewSearchIndex(c)
}
func (flag *SearchFlag) searchByDatastorePath(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) {
ctx := context.TODO()
switch flag.t {
case SearchVirtualMachines:
return flag.searchIndex(c).FindByDatastorePath(ctx, dc, flag.byDatastorePath)
default:
panic("unsupported type")
}
}
func (flag *SearchFlag) searchByDNSName(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) {
ctx := context.TODO()
switch flag.t {
case SearchVirtualMachines:
return flag.searchIndex(c).FindByDnsName(ctx, dc, flag.byDNSName, true)
case SearchHosts:
return flag.searchIndex(c).FindByDnsName(ctx, dc, flag.byDNSName, false)
default:
panic("unsupported type")
}
}
func (flag *SearchFlag) searchByInventoryPath(c *vim25.Client) (object.Reference, error) {
ctx := context.TODO()
return flag.searchIndex(c).FindByInventoryPath(ctx, flag.byInventoryPath)
}
func (flag *SearchFlag) searchByIP(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) {
ctx := context.TODO()
switch flag.t {
case SearchVirtualMachines:
return flag.searchIndex(c).FindByIp(ctx, dc, flag.byIP, true)
case SearchHosts:
return flag.searchIndex(c).FindByIp(ctx, dc, flag.byIP, false)
default:
panic("unsupported type")
}
}
func (flag *SearchFlag) searchByUUID(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) {
ctx := context.TODO()
isVM := false
switch flag.t {
case SearchVirtualMachines:
isVM = true
case SearchHosts:
default:
panic("unsupported type")
}
var ref object.Reference
var err error
for _, iu := range []*bool{nil, types.NewBool(true)} {
ref, err = flag.searchIndex(c).FindByUuid(ctx, dc, flag.byUUID, isVM, iu)
if err != nil {
if soap.IsSoapFault(err) {
fault := soap.ToSoapFault(err).VimFault()
if _, ok := fault.(types.InvalidArgument); ok {
continue
}
}
return nil, err
}
if ref != nil {
break
}
}
return ref, nil
}
func (flag *SearchFlag) search() (object.Reference, error) {
ctx := context.TODO()
var ref object.Reference
var err error
var dc *object.Datacenter
c, err := flag.Client()
if err != nil {
return nil, err
}
isPath := flag.byInventoryPath != ""
if !isPath {
// All other SearchIndex methods require a Datacenter param
dc, err = flag.Datacenter()
if err != nil {
return nil, err
}
}
switch {
case isPath:
ref, err = flag.searchByInventoryPath(c)
case flag.byDatastorePath != "":
ref, err = flag.searchByDatastorePath(c, dc)
case flag.byDNSName != "":
ref, err = flag.searchByDNSName(c, dc)
case flag.byIP != "":
ref, err = flag.searchByIP(c, dc)
case flag.byUUID != "":
ref, err = flag.searchByUUID(c, dc)
default:
err = errors.New("no search flag specified")
}
if err != nil {
return nil, err
}
if ref == nil {
return nil, fmt.Errorf("no such %s", flag.entity)
}
// set the InventoryPath field
finder, err := flag.Finder()
if err != nil {
return nil, err
}
ref, err = finder.ObjectReference(ctx, ref.Reference())
if err != nil {
return nil, err
}
return ref, nil
}
func (flag *SearchFlag) VirtualMachine() (*object.VirtualMachine, error) {
ref, err := flag.search()
if err != nil {
return nil, err
}
vm, ok := ref.(*object.VirtualMachine)
if !ok {
return nil, fmt.Errorf("expected VirtualMachine entity, got %s", ref.Reference().Type)
}
return vm, nil
}
func (flag *SearchFlag) VirtualMachines(args []string) ([]*object.VirtualMachine, error) {
ctx := context.TODO()
var out []*object.VirtualMachine
if flag.IsSet() {
vm, err := flag.VirtualMachine()
if err != nil {
return nil, err
}
out = append(out, vm)
return out, nil
}
// List virtual machines
if len(args) == 0 {
return nil, errors.New("no argument")
}
finder, err := flag.Finder()
if err != nil {
return nil, err
}
var nfe error
// List virtual machines for every argument
for _, arg := range args {
vms, err := finder.VirtualMachineList(ctx, arg)
if err != nil {
if _, ok := err.(*find.NotFoundError); ok {
// Let caller decide how to handle NotFoundError
nfe = err
continue
}
return nil, err
}
out = append(out, vms...)
}
return out, nfe
}
func (flag *SearchFlag) VirtualApp() (*object.VirtualApp, error) {
ref, err := flag.search()
if err != nil {
return nil, err
}
app, ok := ref.(*object.VirtualApp)
if !ok {
return nil, fmt.Errorf("expected VirtualApp entity, got %s", ref.Reference().Type)
}
return app, nil
}
func (flag *SearchFlag) VirtualApps(args []string) ([]*object.VirtualApp, error) {
ctx := context.TODO()
var out []*object.VirtualApp
if flag.IsSet() {
app, err := flag.VirtualApp()
if err != nil {
return nil, err
}
out = append(out, app)
return out, nil
}
// List virtual apps
if len(args) == 0 {
return nil, errors.New("no argument")
}
finder, err := flag.Finder()
if err != nil {
return nil, err
}
// List virtual apps for every argument
for _, arg := range args {
apps, err := finder.VirtualAppList(ctx, arg)
if err != nil {
return nil, err
}
out = append(out, apps...)
}
return out, nil
}
func (flag *SearchFlag) HostSystem() (*object.HostSystem, error) {
ref, err := flag.search()
if err != nil {
return nil, err
}
host, ok := ref.(*object.HostSystem)
if !ok {
return nil, fmt.Errorf("expected HostSystem entity, got %s", ref.Reference().Type)
}
return host, nil
}
func (flag *SearchFlag) HostSystems(args []string) ([]*object.HostSystem, error) {
ctx := context.TODO()
var out []*object.HostSystem
if flag.IsSet() {
host, err := flag.HostSystem()
if err != nil {
return nil, err
}
out = append(out, host)
return out, nil
}
// List host system
if len(args) == 0 {
return nil, errors.New("no argument")
}
finder, err := flag.Finder()
if err != nil {
return nil, err
}
// List host systems for every argument
for _, arg := range args {
vms, err := finder.HostSystemList(ctx, arg)
if err != nil {
return nil, err
}
out = append(out, vms...)
}
return out, nil
}

View file

@ -0,0 +1,78 @@
package flags
import (
"context"
"flag"
"fmt"
"os"
"github.com/vmware/govmomi/object"
)
type StoragePodFlag struct {
common
*DatacenterFlag
Name string
sp *object.StoragePod
}
var storagePodFlagKey = flagKey("storagePod")
func NewStoragePodFlag(ctx context.Context) (*StoragePodFlag, context.Context) {
if v := ctx.Value(storagePodFlagKey); v != nil {
return v.(*StoragePodFlag), ctx
}
v := &StoragePodFlag{}
v.DatacenterFlag, ctx = NewDatacenterFlag(ctx)
ctx = context.WithValue(ctx, storagePodFlagKey, v)
return v, ctx
}
func (f *StoragePodFlag) Register(ctx context.Context, fs *flag.FlagSet) {
f.RegisterOnce(func() {
f.DatacenterFlag.Register(ctx, fs)
env := "GOVC_DATASTORE_CLUSTER"
value := os.Getenv(env)
usage := fmt.Sprintf("Datastore cluster [%s]", env)
fs.StringVar(&f.Name, "datastore-cluster", value, usage)
})
}
func (f *StoragePodFlag) Process(ctx context.Context) error {
return f.DatacenterFlag.Process(ctx)
}
func (f *StoragePodFlag) Isset() bool {
return f.Name != ""
}
func (f *StoragePodFlag) StoragePod() (*object.StoragePod, error) {
ctx := context.TODO()
if f.sp != nil {
return f.sp, nil
}
finder, err := f.Finder()
if err != nil {
return nil, err
}
if f.Isset() {
f.sp, err = finder.DatastoreCluster(ctx, f.Name)
if err != nil {
return nil, err
}
} else {
f.sp, err = finder.DefaultDatastoreCluster(ctx)
if err != nil {
return nil, err
}
}
return f.sp, nil
}

66
vendor/github.com/vmware/govmomi/govc/flags/version.go generated vendored Normal file
View file

@ -0,0 +1,66 @@
/*
Copyright (c) 2014-2020 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"strconv"
"strings"
)
const Version = "0.23.0"
var GitVersion string
type version []int
func ParseVersion(s string) (version, error) {
v := make(version, 0)
ds := strings.Split(s, "-")
ps := strings.Split(ds[0], ".")
for _, p := range ps {
i, err := strconv.Atoi(p)
if err != nil {
return nil, err
}
v = append(v, i)
}
return v, nil
}
func (v version) Lte(u version) bool {
lv := len(v)
lu := len(u)
for i := 0; i < lv; i++ {
// Everything up to here has been equal and v has more elements than u.
if i >= lu {
return false
}
// Move to next digit if equal.
if v[i] == u[i] {
continue
}
return v[i] < u[i]
}
// Equal.
return true
}

View file

@ -0,0 +1,106 @@
/*
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"flag"
"fmt"
"os"
"github.com/vmware/govmomi/object"
)
type VirtualAppFlag struct {
common
*DatacenterFlag
*SearchFlag
name string
app *object.VirtualApp
}
var virtualAppFlagKey = flagKey("virtualApp")
func NewVirtualAppFlag(ctx context.Context) (*VirtualAppFlag, context.Context) {
if v := ctx.Value(virtualAppFlagKey); v != nil {
return v.(*VirtualAppFlag), ctx
}
v := &VirtualAppFlag{}
v.DatacenterFlag, ctx = NewDatacenterFlag(ctx)
v.SearchFlag, ctx = NewSearchFlag(ctx, SearchVirtualApps)
ctx = context.WithValue(ctx, virtualAppFlagKey, v)
return v, ctx
}
func (flag *VirtualAppFlag) Register(ctx context.Context, f *flag.FlagSet) {
flag.RegisterOnce(func() {
flag.DatacenterFlag.Register(ctx, f)
flag.SearchFlag.Register(ctx, f)
env := "GOVC_VAPP"
value := os.Getenv(env)
usage := fmt.Sprintf("Virtual App [%s]", env)
f.StringVar(&flag.name, "vapp", value, usage)
})
}
func (flag *VirtualAppFlag) Process(ctx context.Context) error {
return flag.ProcessOnce(func() error {
if err := flag.DatacenterFlag.Process(ctx); err != nil {
return err
}
if err := flag.SearchFlag.Process(ctx); err != nil {
return err
}
return nil
})
}
func (flag *VirtualAppFlag) VirtualApp() (*object.VirtualApp, error) {
ctx := context.TODO()
if flag.app != nil {
return flag.app, nil
}
// Use search flags if specified.
if flag.SearchFlag.IsSet() {
app, err := flag.SearchFlag.VirtualApp()
if err != nil {
return nil, err
}
flag.app = app
return flag.app, nil
}
// Never look for a default virtual app.
if flag.name == "" {
return nil, nil
}
finder, err := flag.Finder()
if err != nil {
return nil, err
}
flag.app, err = finder.VirtualApp(ctx, flag.name)
return flag.app, err
}

View file

@ -0,0 +1,112 @@
/*
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"flag"
"fmt"
"os"
"github.com/vmware/govmomi/object"
)
type VirtualMachineFlag struct {
common
*ClientFlag
*DatacenterFlag
*SearchFlag
name string
vm *object.VirtualMachine
}
var virtualMachineFlagKey = flagKey("virtualMachine")
func NewVirtualMachineFlag(ctx context.Context) (*VirtualMachineFlag, context.Context) {
if v := ctx.Value(virtualMachineFlagKey); v != nil {
return v.(*VirtualMachineFlag), ctx
}
v := &VirtualMachineFlag{}
v.ClientFlag, ctx = NewClientFlag(ctx)
v.DatacenterFlag, ctx = NewDatacenterFlag(ctx)
v.SearchFlag, ctx = NewSearchFlag(ctx, SearchVirtualMachines)
ctx = context.WithValue(ctx, virtualMachineFlagKey, v)
return v, ctx
}
func (flag *VirtualMachineFlag) Register(ctx context.Context, f *flag.FlagSet) {
flag.RegisterOnce(func() {
flag.ClientFlag.Register(ctx, f)
flag.DatacenterFlag.Register(ctx, f)
flag.SearchFlag.Register(ctx, f)
env := "GOVC_VM"
value := os.Getenv(env)
usage := fmt.Sprintf("Virtual machine [%s]", env)
f.StringVar(&flag.name, "vm", value, usage)
})
}
func (flag *VirtualMachineFlag) Process(ctx context.Context) error {
return flag.ProcessOnce(func() error {
if err := flag.ClientFlag.Process(ctx); err != nil {
return err
}
if err := flag.DatacenterFlag.Process(ctx); err != nil {
return err
}
if err := flag.SearchFlag.Process(ctx); err != nil {
return err
}
return nil
})
}
func (flag *VirtualMachineFlag) VirtualMachine() (*object.VirtualMachine, error) {
ctx := context.TODO()
if flag.vm != nil {
return flag.vm, nil
}
// Use search flags if specified.
if flag.SearchFlag.IsSet() {
vm, err := flag.SearchFlag.VirtualMachine()
if err != nil {
return nil, err
}
flag.vm = vm
return flag.vm, nil
}
// Never look for a default virtual machine.
if flag.name == "" {
return nil, nil
}
finder, err := flag.Finder()
if err != nil {
return nil, err
}
flag.vm, err = finder.VirtualMachine(ctx, flag.name)
return flag.vm, err
}

View file

@ -0,0 +1,149 @@
/*
Copyright (c) 2014 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package esxcli
import (
"flag"
"fmt"
"strings"
"github.com/vmware/govmomi/internal"
)
type Command struct {
name []string
args []string
}
type CommandInfoItem struct {
Name string `xml:"name"`
DisplayName string `xml:"displayName"`
Help string `xml:"help"`
}
type CommandInfoParam struct {
CommandInfoItem
Aliases []string `xml:"aliases"`
Flag bool `xml:"flag"`
}
type CommandInfoHint struct {
Key string `xml:"key"`
Value string `xml:"value"`
}
type CommandInfoHints []CommandInfoHint
type CommandInfoMethod struct {
CommandInfoItem
Param []CommandInfoParam `xml:"param"`
Hints CommandInfoHints `xml:"hints"`
}
type CommandInfo struct {
CommandInfoItem
Method []*CommandInfoMethod `xml:"method"`
}
func NewCommand(args []string) *Command {
c := &Command{}
for i, arg := range args {
if strings.HasPrefix(arg, "-") {
c.args = args[i:]
break
} else {
c.name = append(c.name, arg)
}
}
return c
}
func (c *Command) Namespace() string {
return strings.Join(c.name[:len(c.name)-1], ".")
}
func (c *Command) Name() string {
return c.name[len(c.name)-1]
}
func (c *Command) Method() string {
return "vim.EsxCLI." + strings.Join(c.name, ".")
}
func (c *Command) Moid() string {
return "ha-cli-handler-" + strings.Join(c.name[:len(c.name)-1], "-")
}
// Parse generates a flag.FlagSet based on the given []CommandInfoParam and
// returns arguments for use with methods.ExecuteSoap
func (c *Command) Parse(params []CommandInfoParam) ([]internal.ReflectManagedMethodExecuterSoapArgument, error) {
flags := flag.NewFlagSet(strings.Join(c.name, " "), flag.ExitOnError)
vals := make([]string, len(params))
for i, p := range params {
v := &vals[i]
for _, a := range p.Aliases {
a = strings.TrimPrefix(a[1:], "-")
flags.StringVar(v, a, "", p.Help)
}
}
err := flags.Parse(c.args)
if err != nil {
return nil, err
}
args := []internal.ReflectManagedMethodExecuterSoapArgument{}
for i, p := range params {
if vals[i] == "" {
continue
}
args = append(args, c.Argument(p.Name, vals[i]))
}
return args, nil
}
func (c *Command) Argument(name string, val string) internal.ReflectManagedMethodExecuterSoapArgument {
return internal.ReflectManagedMethodExecuterSoapArgument{
Name: name,
Val: fmt.Sprintf("<%s>%s</%s>", name, val, name),
}
}
func (h CommandInfoHints) Formatter() string {
for _, hint := range h {
if hint.Key == "formatter" {
return hint.Value
}
}
return "simple"
}
func (h CommandInfoHints) Fields() []string {
for _, hint := range h {
if strings.HasPrefix(hint.Key, "fields:") {
return strings.Split(hint.Value, ",")
}
}
return nil
}

View file

@ -0,0 +1,182 @@
/*
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package esxcli
import (
"context"
"flag"
"fmt"
"io"
"sort"
"strings"
"text/tabwriter"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
)
type esxcli struct {
*flags.HostSystemFlag
hints bool
}
func init() {
cli.Register("host.esxcli", &esxcli{})
}
func (cmd *esxcli) Usage() string {
return "COMMAND [ARG]..."
}
func (cmd *esxcli) Register(ctx context.Context, f *flag.FlagSet) {
cmd.HostSystemFlag, ctx = flags.NewHostSystemFlag(ctx)
cmd.HostSystemFlag.Register(ctx, f)
f.BoolVar(&cmd.hints, "hints", true, "Use command info hints when formatting output")
}
func (cmd *esxcli) Description() string {
return `Invoke esxcli command on HOST.
Output is rendered in table form when possible, unless disabled with '-hints=false'.
Examples:
govc host.esxcli network ip connection list
govc host.esxcli system settings advanced set -o /Net/GuestIPHack -i 1
govc host.esxcli network firewall ruleset set -r remoteSerialPort -e true
govc host.esxcli network firewall set -e false
govc host.esxcli hardware platform get`
}
func (cmd *esxcli) Process(ctx context.Context) error {
if err := cmd.HostSystemFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *esxcli) Run(ctx context.Context, f *flag.FlagSet) error {
c, err := cmd.Client()
if err != nil {
return err
}
host, err := cmd.HostSystem()
if err != nil {
return err
}
e, err := NewExecutor(c, host)
if err != nil {
return err
}
res, err := e.Run(f.Args())
if err != nil {
return err
}
if len(res.Values) == 0 {
if res.String != "" {
fmt.Print(res.String)
if !strings.HasSuffix(res.String, "\n") {
fmt.Println()
}
}
return nil
}
return cmd.WriteResult(&result{res, cmd})
}
type result struct {
*Response
cmd *esxcli
}
func (r *result) Write(w io.Writer) error {
var formatType string
if r.cmd.hints {
formatType = r.Info.Hints.Formatter()
}
switch formatType {
case "table":
r.cmd.formatTable(w, r.Response)
default:
r.cmd.formatSimple(w, r.Response)
}
return nil
}
func (cmd *esxcli) formatSimple(w io.Writer, res *Response) {
var keys []string
for key := range res.Values[0] {
keys = append(keys, key)
}
sort.Strings(keys)
tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0)
for i, rv := range res.Values {
if i > 0 {
fmt.Fprintln(tw)
_ = tw.Flush()
}
for _, key := range keys {
fmt.Fprintf(tw, "%s:\t%s\n", key, strings.Join(rv[key], ", "))
}
}
_ = tw.Flush()
}
func (cmd *esxcli) formatTable(w io.Writer, res *Response) {
fields := res.Info.Hints.Fields()
if len(fields) == 0 {
cmd.formatSimple(w, res)
return
}
tw := tabwriter.NewWriter(w, len(fields), 0, 2, ' ', 0)
var hr []string
for _, name := range fields {
hr = append(hr, strings.Repeat("-", len(name)))
}
fmt.Fprintln(tw, strings.Join(fields, "\t"))
fmt.Fprintln(tw, strings.Join(hr, "\t"))
for _, vals := range res.Values {
var row []string
for _, name := range fields {
key := strings.Replace(name, " ", "", -1)
if val, ok := vals[key]; ok {
row = append(row, strings.Join(val, ", "))
} else {
row = append(row, "")
}
}
fmt.Fprintln(tw, strings.Join(row, "\t"))
}
_ = tw.Flush()
}

View file

@ -0,0 +1,167 @@
/*
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package esxcli
import (
"context"
"errors"
"fmt"
"github.com/vmware/govmomi/internal"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/xml"
)
type Executor struct {
c *vim25.Client
host *object.HostSystem
mme *internal.ReflectManagedMethodExecuter
dtm *internal.InternalDynamicTypeManager
info map[string]*CommandInfo
}
func NewExecutor(c *vim25.Client, host *object.HostSystem) (*Executor, error) {
ctx := context.TODO()
e := &Executor{
c: c,
host: host,
info: make(map[string]*CommandInfo),
}
{
req := internal.RetrieveManagedMethodExecuterRequest{
This: host.Reference(),
}
res, err := internal.RetrieveManagedMethodExecuter(ctx, c, &req)
if err != nil {
return nil, err
}
e.mme = res.Returnval
}
{
req := internal.RetrieveDynamicTypeManagerRequest{
This: host.Reference(),
}
res, err := internal.RetrieveDynamicTypeManager(ctx, c, &req)
if err != nil {
return nil, err
}
e.dtm = res.Returnval
}
return e, nil
}
func (e *Executor) CommandInfo(c *Command) (*CommandInfoMethod, error) {
ns := c.Namespace()
var info *CommandInfo
var ok bool
if info, ok = e.info[ns]; !ok {
req := internal.ExecuteSoapRequest{
Moid: "ha-dynamic-type-manager-local-cli-cliinfo",
Method: "vim.CLIInfo.FetchCLIInfo",
Argument: []internal.ReflectManagedMethodExecuterSoapArgument{
c.Argument("typeName", "vim.EsxCLI."+ns),
},
}
info = new(CommandInfo)
if err := e.Execute(&req, info); err != nil {
return nil, err
}
e.info[ns] = info
}
name := c.Name()
for _, method := range info.Method {
if method.Name == name {
return method, nil
}
}
return nil, fmt.Errorf("method '%s' not found in name space '%s'", name, c.Namespace())
}
func (e *Executor) NewRequest(args []string) (*internal.ExecuteSoapRequest, *CommandInfoMethod, error) {
c := NewCommand(args)
info, err := e.CommandInfo(c)
if err != nil {
return nil, nil, err
}
sargs, err := c.Parse(info.Param)
if err != nil {
return nil, nil, err
}
sreq := internal.ExecuteSoapRequest{
Moid: c.Moid(),
Method: c.Method(),
Argument: sargs,
}
return &sreq, info, nil
}
func (e *Executor) Execute(req *internal.ExecuteSoapRequest, res interface{}) error {
ctx := context.TODO()
req.This = e.mme.ManagedObjectReference
req.Version = "urn:vim25/5.0"
x, err := internal.ExecuteSoap(ctx, e.c, req)
if err != nil {
return err
}
if x.Returnval != nil {
if x.Returnval.Fault != nil {
return errors.New(x.Returnval.Fault.FaultMsg)
}
if err := xml.Unmarshal([]byte(x.Returnval.Response), res); err != nil {
return err
}
}
return nil
}
func (e *Executor) Run(args []string) (*Response, error) {
req, info, err := e.NewRequest(args)
if err != nil {
return nil, err
}
res := &Response{
Info: info,
}
if err := e.Execute(req, res); err != nil {
return nil, err
}
return res, nil
}

View file

@ -0,0 +1,48 @@
/*
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package esxcli
import "github.com/vmware/govmomi/object"
type FirewallInfo struct {
Loaded bool
Enabled bool
DefaultAction string
}
// GetFirewallInfo via 'esxcli network firewall get'
// The HostFirewallSystem type does not expose this data.
// This helper can be useful in particular to determine if the firewall is enabled or disabled.
func GetFirewallInfo(s *object.HostSystem) (*FirewallInfo, error) {
x, err := NewExecutor(s.Client(), s)
if err != nil {
return nil, err
}
res, err := x.Run([]string{"network", "firewall", "get"})
if err != nil {
return nil, err
}
info := &FirewallInfo{
Loaded: res.Values[0]["Loaded"][0] == "true",
Enabled: res.Values[0]["Enabled"][0] == "true",
DefaultAction: res.Values[0]["DefaultAction"][0],
}
return info, nil
}

View file

@ -0,0 +1,120 @@
/*
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package esxcli
import (
"context"
"strings"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
type hostInfo struct {
*Executor
wids map[string]string
}
type GuestInfo struct {
c *vim25.Client
hosts map[string]*hostInfo
}
func NewGuestInfo(c *vim25.Client) *GuestInfo {
return &GuestInfo{
c: c,
hosts: make(map[string]*hostInfo),
}
}
func (g *GuestInfo) hostInfo(ref *types.ManagedObjectReference) (*hostInfo, error) {
// cache exectuor and uuid -> worldid map
if h, ok := g.hosts[ref.Value]; ok {
return h, nil
}
host := object.NewHostSystem(g.c, *ref)
e, err := NewExecutor(g.c, host)
if err != nil {
return nil, err
}
res, err := e.Run([]string{"vm", "process", "list"})
if err != nil {
return nil, err
}
ids := make(map[string]string, len(res.Values))
for _, process := range res.Values {
// Normalize uuid, esxcli and mo.VirtualMachine have different formats
uuid := strings.Replace(process["UUID"][0], " ", "", -1)
uuid = strings.Replace(uuid, "-", "", -1)
ids[uuid] = process["WorldID"][0]
}
h := &hostInfo{e, ids}
g.hosts[ref.Value] = h
return h, nil
}
// IpAddress attempts to find the guest IP address using esxcli.
// ESX hosts must be configured with the /Net/GuestIPHack enabled.
// For example:
// $ govc host.esxcli -- system settings advanced set -o /Net/GuestIPHack -i 1
func (g *GuestInfo) IpAddress(vm *object.VirtualMachine) (string, error) {
ctx := context.TODO()
const any = "0.0.0.0"
var mvm mo.VirtualMachine
pc := property.DefaultCollector(g.c)
err := pc.RetrieveOne(ctx, vm.Reference(), []string{"runtime.host", "config.uuid"}, &mvm)
if err != nil {
return "", err
}
h, err := g.hostInfo(mvm.Runtime.Host)
if err != nil {
return "", err
}
// Normalize uuid, esxcli and mo.VirtualMachine have different formats
uuid := strings.Replace(mvm.Config.Uuid, "-", "", -1)
if wid, ok := h.wids[uuid]; ok {
res, err := h.Run([]string{"network", "vm", "port", "list", "--world-id", wid})
if err != nil {
return "", err
}
for _, val := range res.Values {
if ip, ok := val["IPAddress"]; ok {
if ip[0] != any {
return ip[0], nil
}
}
}
}
return any, nil
}

View file

@ -0,0 +1,102 @@
/*
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package esxcli
import (
"io"
"github.com/vmware/govmomi/vim25/xml"
)
type Values map[string][]string
type Response struct {
Info *CommandInfoMethod
Values []Values
String string
}
func (v Values) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
for {
t, err := d.Token()
if err != nil {
if err == io.EOF {
return nil
}
return err
}
if s, ok := t.(xml.StartElement); ok {
t, err = d.Token()
if err != nil {
return err
}
key := s.Name.Local
var val string
if c, ok := t.(xml.CharData); ok {
val = string(c)
}
v[key] = append(v[key], val)
}
}
}
func (r *Response) Type(start xml.StartElement) string {
for _, a := range start.Attr {
if a.Name.Local == "type" {
return a.Value
}
}
return ""
}
func (r *Response) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
stype := r.Type(start)
if stype != "ArrayOfDataObject" {
switch stype {
case "xsd:string":
return d.DecodeElement(&r.String, &start)
}
v := Values{}
if err := d.DecodeElement(&v, &start); err != nil {
return err
}
r.Values = append(r.Values, v)
return nil
}
for {
t, err := d.Token()
if err != nil {
if err == io.EOF {
return nil
}
return err
}
if s, ok := t.(xml.StartElement); ok {
if s.Name.Local == "DataObject" {
v := Values{}
if err := d.DecodeElement(&v, &s); err != nil {
return err
}
r.Values = append(r.Values, v)
}
}
}
}

View file

@ -0,0 +1,187 @@
/*
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package importx
import (
"archive/tar"
"bytes"
"context"
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
"net/url"
"os"
"path"
"path/filepath"
"strings"
"github.com/vmware/govmomi/ovf"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/soap"
)
// ArchiveFlag doesn't register any flags;
// only encapsulates some common archive related functionality.
type ArchiveFlag struct {
Archive
}
func newArchiveFlag(ctx context.Context) (*ArchiveFlag, context.Context) {
return &ArchiveFlag{}, ctx
}
func (f *ArchiveFlag) Register(ctx context.Context, fs *flag.FlagSet) {
}
func (f *ArchiveFlag) Process(ctx context.Context) error {
return nil
}
func (f *ArchiveFlag) ReadOvf(fpath string) ([]byte, error) {
r, _, err := f.Open(fpath)
if err != nil {
return nil, err
}
defer r.Close()
return ioutil.ReadAll(r)
}
func (f *ArchiveFlag) ReadEnvelope(data []byte) (*ovf.Envelope, error) {
e, err := ovf.Unmarshal(bytes.NewReader(data))
if err != nil {
return nil, fmt.Errorf("failed to parse ovf: %s", err)
}
return e, nil
}
type Archive interface {
Open(string) (io.ReadCloser, int64, error)
}
type TapeArchive struct {
Path string
Opener
}
type TapeArchiveEntry struct {
io.Reader
f io.Closer
Name string
}
func (t *TapeArchiveEntry) Close() error {
return t.f.Close()
}
func (t *TapeArchive) Open(name string) (io.ReadCloser, int64, error) {
f, _, err := t.OpenFile(t.Path)
if err != nil {
return nil, 0, err
}
r := tar.NewReader(f)
for {
h, err := r.Next()
if err == io.EOF {
break
}
if err != nil {
return nil, 0, err
}
matched, err := path.Match(name, path.Base(h.Name))
if err != nil {
return nil, 0, err
}
if matched {
return &TapeArchiveEntry{r, f, h.Name}, h.Size, nil
}
}
_ = f.Close()
return nil, 0, os.ErrNotExist
}
type FileArchive struct {
Path string
Opener
}
func (t *FileArchive) Open(name string) (io.ReadCloser, int64, error) {
fpath := name
if name != t.Path {
index := strings.LastIndex(t.Path, "/")
if index != -1 {
fpath = t.Path[:index] + "/" + name
}
}
return t.OpenFile(fpath)
}
type Opener struct {
*vim25.Client
}
func isRemotePath(path string) bool {
if strings.HasPrefix(path, "http://") || strings.HasPrefix(path, "https://") {
return true
}
return false
}
func (o Opener) OpenLocal(path string) (io.ReadCloser, int64, error) {
f, err := os.Open(filepath.Clean(path))
if err != nil {
return nil, 0, err
}
s, err := f.Stat()
if err != nil {
return nil, 0, err
}
return f, s.Size(), nil
}
func (o Opener) OpenFile(path string) (io.ReadCloser, int64, error) {
if isRemotePath(path) {
return o.OpenRemote(path)
}
return o.OpenLocal(path)
}
func (o Opener) OpenRemote(link string) (io.ReadCloser, int64, error) {
if o.Client == nil {
return nil, 0, errors.New("remote path not supported")
}
u, err := url.Parse(link)
if err != nil {
return nil, 0, err
}
return o.Download(context.Background(), u, &soap.DefaultDownload)
}

View file

@ -0,0 +1,59 @@
/*
Copyright (c) 2014 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package importx
import (
"fmt"
"path"
)
type importable struct {
localPath string
remotePath string
}
func (i importable) Ext() string {
return path.Ext(i.localPath)
}
func (i importable) Base() string {
return path.Base(i.localPath)
}
func (i importable) BaseClean() string {
b := i.Base()
e := i.Ext()
return b[:len(b)-len(e)]
}
func (i importable) RemoteSrcVMDK() string {
file := fmt.Sprintf("%s-src.vmdk", i.BaseClean())
return i.toRemotePath(file)
}
func (i importable) RemoteDstVMDK() string {
file := fmt.Sprintf("%s.vmdk", i.BaseClean())
return i.toRemotePath(file)
}
func (i importable) toRemotePath(p string) string {
if i.remotePath == "" {
return p
}
return path.Join(i.remotePath, p)
}

View file

@ -0,0 +1,205 @@
/*
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package importx
import (
"context"
"encoding/json"
"flag"
"fmt"
"os"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/ovf"
"github.com/vmware/govmomi/vim25/types"
)
type Property struct {
types.KeyValue
Spec *ovf.Property `json:",omitempty"`
}
type Network struct {
Name string
Network string
}
type Options struct {
AllDeploymentOptions []string `json:",omitempty"`
Deployment string `json:",omitempty"`
AllDiskProvisioningOptions []string `json:",omitempty"`
DiskProvisioning string
AllIPAllocationPolicyOptions []string `json:",omitempty"`
IPAllocationPolicy string
AllIPProtocolOptions []string `json:",omitempty"`
IPProtocol string
PropertyMapping []Property `json:",omitempty"`
NetworkMapping []Network `json:",omitempty"`
Annotation string `json:",omitempty"`
MarkAsTemplate bool
PowerOn bool
InjectOvfEnv bool
WaitForIP bool
Name *string
}
type OptionsFlag struct {
Options Options
path string
}
func newOptionsFlag(ctx context.Context) (*OptionsFlag, context.Context) {
return &OptionsFlag{}, ctx
}
func (flag *OptionsFlag) Register(ctx context.Context, f *flag.FlagSet) {
f.StringVar(&flag.path, "options", "", "Options spec file path for VM deployment")
}
func (flag *OptionsFlag) Process(ctx context.Context) error {
if len(flag.path) == 0 {
return nil
}
var err error
in := os.Stdin
if flag.path != "-" {
in, err = os.Open(flag.path)
if err != nil {
return err
}
defer in.Close()
}
return json.NewDecoder(in).Decode(&flag.Options)
}
func (flag *OptionsFlag) powerOn(vm *object.VirtualMachine, out *flags.OutputFlag) error {
if !flag.Options.PowerOn || flag.Options.MarkAsTemplate {
return nil
}
out.Log("Powering on VM...\n")
task, err := vm.PowerOn(context.Background())
if err != nil {
return err
}
return task.Wait(context.Background())
}
func (flag *OptionsFlag) markAsTemplate(vm *object.VirtualMachine, out *flags.OutputFlag) error {
if !flag.Options.MarkAsTemplate {
return nil
}
out.Log("Marking VM as template...\n")
return vm.MarkAsTemplate(context.Background())
}
func (flag *OptionsFlag) injectOvfEnv(vm *object.VirtualMachine, out *flags.OutputFlag) error {
if !flag.Options.InjectOvfEnv {
return nil
}
out.Log("Injecting OVF environment...\n")
var opts []types.BaseOptionValue
a := vm.Client().ServiceContent.About
// build up Environment in order to marshal to xml
var props []ovf.EnvProperty
for _, p := range flag.Options.PropertyMapping {
props = append(props, ovf.EnvProperty{
Key: p.Key,
Value: p.Value,
})
}
env := ovf.Env{
EsxID: vm.Reference().Value,
Platform: &ovf.PlatformSection{
Kind: a.Name,
Version: a.Version,
Vendor: a.Vendor,
Locale: "US",
},
Property: &ovf.PropertySection{
Properties: props,
},
}
opts = append(opts, &types.OptionValue{
Key: "guestinfo.ovfEnv",
Value: env.MarshalManual(),
})
task, err := vm.Reconfigure(context.Background(), types.VirtualMachineConfigSpec{
ExtraConfig: opts,
})
if err != nil {
return err
}
return task.Wait(context.Background())
}
func (flag *OptionsFlag) waitForIP(vm *object.VirtualMachine, out *flags.OutputFlag) error {
if !flag.Options.PowerOn || !flag.Options.WaitForIP || flag.Options.MarkAsTemplate {
return nil
}
out.Log("Waiting for IP address...\n")
ip, err := vm.WaitForIP(context.Background())
if err != nil {
return err
}
out.Log(fmt.Sprintf("Received IP address: %s\n", ip))
return nil
}
func (flag *OptionsFlag) Deploy(vm *object.VirtualMachine, out *flags.OutputFlag) error {
deploy := []func(*object.VirtualMachine, *flags.OutputFlag) error{
flag.injectOvfEnv,
flag.markAsTemplate,
flag.powerOn,
flag.waitForIP,
}
for _, step := range deploy {
if err := step(vm, out); err != nil {
return err
}
}
return nil
}

63
vendor/github.com/vmware/govmomi/govc/importx/ova.go generated vendored Normal file
View file

@ -0,0 +1,63 @@
/*
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package importx
import (
"context"
"flag"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/types"
)
type ova struct {
*ovfx
}
func init() {
cli.Register("import.ova", &ova{&ovfx{}})
}
func (cmd *ova) Usage() string {
return "PATH_TO_OVA"
}
func (cmd *ova) Run(ctx context.Context, f *flag.FlagSet) error {
fpath, err := cmd.Prepare(f)
if err != nil {
return err
}
archive := &TapeArchive{Path: fpath}
archive.Client = cmd.Client
cmd.Archive = archive
moref, err := cmd.Import(fpath)
if err != nil {
return err
}
vm := object.NewVirtualMachine(cmd.Client, *moref)
return cmd.Deploy(vm, cmd.OutputFlag)
}
func (cmd *ova) Import(fpath string) (*types.ManagedObjectReference, error) {
ovf := "*.ovf"
return cmd.ovfx.Import(ovf)
}

343
vendor/github.com/vmware/govmomi/govc/importx/ovf.go generated vendored Normal file
View file

@ -0,0 +1,343 @@
/*
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package importx
import (
"context"
"errors"
"flag"
"fmt"
"path"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/nfc"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/ovf"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
)
type ovfx struct {
*flags.DatastoreFlag
*flags.HostSystemFlag
*flags.OutputFlag
*flags.ResourcePoolFlag
*flags.FolderFlag
*ArchiveFlag
*OptionsFlag
Name string
Client *vim25.Client
Datacenter *object.Datacenter
Datastore *object.Datastore
ResourcePool *object.ResourcePool
}
func init() {
cli.Register("import.ovf", &ovfx{})
}
func (cmd *ovfx) Register(ctx context.Context, f *flag.FlagSet) {
cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
cmd.DatastoreFlag.Register(ctx, f)
cmd.HostSystemFlag, ctx = flags.NewHostSystemFlag(ctx)
cmd.HostSystemFlag.Register(ctx, f)
cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
cmd.OutputFlag.Register(ctx, f)
cmd.ResourcePoolFlag, ctx = flags.NewResourcePoolFlag(ctx)
cmd.ResourcePoolFlag.Register(ctx, f)
cmd.FolderFlag, ctx = flags.NewFolderFlag(ctx)
cmd.FolderFlag.Register(ctx, f)
cmd.ArchiveFlag, ctx = newArchiveFlag(ctx)
cmd.ArchiveFlag.Register(ctx, f)
cmd.OptionsFlag, ctx = newOptionsFlag(ctx)
cmd.OptionsFlag.Register(ctx, f)
f.StringVar(&cmd.Name, "name", "", "Name to use for new entity")
}
func (cmd *ovfx) Process(ctx context.Context) error {
if err := cmd.DatastoreFlag.Process(ctx); err != nil {
return err
}
if err := cmd.HostSystemFlag.Process(ctx); err != nil {
return err
}
if err := cmd.OutputFlag.Process(ctx); err != nil {
return err
}
if err := cmd.ResourcePoolFlag.Process(ctx); err != nil {
return err
}
if err := cmd.ArchiveFlag.Process(ctx); err != nil {
return err
}
if err := cmd.OptionsFlag.Process(ctx); err != nil {
return err
}
if err := cmd.FolderFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *ovfx) Usage() string {
return "PATH_TO_OVF"
}
func (cmd *ovfx) Run(ctx context.Context, f *flag.FlagSet) error {
fpath, err := cmd.Prepare(f)
if err != nil {
return err
}
archive := &FileArchive{Path: fpath}
archive.Client = cmd.Client
cmd.Archive = archive
moref, err := cmd.Import(fpath)
if err != nil {
return err
}
vm := object.NewVirtualMachine(cmd.Client, *moref)
return cmd.Deploy(vm, cmd.OutputFlag)
}
func (cmd *ovfx) Prepare(f *flag.FlagSet) (string, error) {
var err error
args := f.Args()
if len(args) != 1 {
return "", errors.New("no file specified")
}
cmd.Client, err = cmd.DatastoreFlag.Client()
if err != nil {
return "", err
}
cmd.Datacenter, err = cmd.DatastoreFlag.Datacenter()
if err != nil {
return "", err
}
cmd.Datastore, err = cmd.DatastoreFlag.Datastore()
if err != nil {
return "", err
}
cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePoolIfSpecified()
if err != nil {
return "", err
}
return f.Arg(0), nil
}
func (cmd *ovfx) Map(op []Property) (p []types.KeyValue) {
for _, v := range op {
p = append(p, v.KeyValue)
}
return
}
func (cmd *ovfx) NetworkMap(e *ovf.Envelope) ([]types.OvfNetworkMapping, error) {
ctx := context.TODO()
finder, err := cmd.DatastoreFlag.Finder()
if err != nil {
return nil, err
}
var nmap []types.OvfNetworkMapping
for _, m := range cmd.Options.NetworkMapping {
if m.Network == "" {
continue // Not set, let vSphere choose the default network
}
var ref types.ManagedObjectReference
net, err := finder.Network(ctx, m.Network)
if err != nil {
switch err.(type) {
case *find.NotFoundError:
if !ref.FromString(m.Network) {
return nil, err
} // else this is a raw MO ref
default:
return nil, err
}
} else {
ref = net.Reference()
}
nmap = append(nmap, types.OvfNetworkMapping{
Name: m.Name,
Network: ref,
})
}
return nmap, err
}
func (cmd *ovfx) Import(fpath string) (*types.ManagedObjectReference, error) {
ctx := context.TODO()
o, err := cmd.ReadOvf(fpath)
if err != nil {
return nil, err
}
e, err := cmd.ReadEnvelope(o)
if err != nil {
return nil, fmt.Errorf("failed to parse ovf: %s", err)
}
name := "Govc Virtual Appliance"
if e.VirtualSystem != nil {
name = e.VirtualSystem.ID
if e.VirtualSystem.Name != nil {
name = *e.VirtualSystem.Name
}
}
// Override name from options if specified
if cmd.Options.Name != nil {
name = *cmd.Options.Name
}
// Override name from arguments if specified
if cmd.Name != "" {
name = cmd.Name
}
nmap, err := cmd.NetworkMap(e)
if err != nil {
return nil, err
}
cisp := types.OvfCreateImportSpecParams{
DiskProvisioning: cmd.Options.DiskProvisioning,
EntityName: name,
IpAllocationPolicy: cmd.Options.IPAllocationPolicy,
IpProtocol: cmd.Options.IPProtocol,
OvfManagerCommonParams: types.OvfManagerCommonParams{
DeploymentOption: cmd.Options.Deployment,
Locale: "US"},
PropertyMapping: cmd.Map(cmd.Options.PropertyMapping),
NetworkMapping: nmap,
}
host, err := cmd.HostSystemIfSpecified()
if err != nil {
return nil, err
}
if cmd.ResourcePool == nil {
if host == nil {
cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePool()
} else {
cmd.ResourcePool, err = host.ResourcePool(ctx)
}
if err != nil {
return nil, err
}
}
m := ovf.NewManager(cmd.Client)
spec, err := m.CreateImportSpec(ctx, string(o), cmd.ResourcePool, cmd.Datastore, cisp)
if err != nil {
return nil, err
}
if spec.Error != nil {
return nil, errors.New(spec.Error[0].LocalizedMessage)
}
if spec.Warning != nil {
for _, w := range spec.Warning {
_, _ = cmd.Log(fmt.Sprintf("Warning: %s\n", w.LocalizedMessage))
}
}
if cmd.Options.Annotation != "" {
switch s := spec.ImportSpec.(type) {
case *types.VirtualMachineImportSpec:
s.ConfigSpec.Annotation = cmd.Options.Annotation
case *types.VirtualAppImportSpec:
s.VAppConfigSpec.Annotation = cmd.Options.Annotation
}
}
var folder *object.Folder
// The folder argument must not be set on a VM in a vApp, otherwise causes
// InvalidArgument fault: A specified parameter was not correct: pool
if cmd.ResourcePool.Reference().Type != "VirtualApp" {
folder, err = cmd.FolderOrDefault("vm")
if err != nil {
return nil, err
}
}
lease, err := cmd.ResourcePool.ImportVApp(ctx, spec.ImportSpec, folder, host)
if err != nil {
return nil, err
}
info, err := lease.Wait(ctx, spec.FileItem)
if err != nil {
return nil, err
}
u := lease.StartUpdater(ctx, info)
defer u.Done()
for _, i := range info.Items {
err = cmd.Upload(ctx, lease, i)
if err != nil {
return nil, err
}
}
return &info.Entity, lease.Complete(ctx)
}
func (cmd *ovfx) Upload(ctx context.Context, lease *nfc.Lease, item nfc.FileItem) error {
file := item.Path
f, size, err := cmd.Open(file)
if err != nil {
return err
}
defer f.Close()
logger := cmd.ProgressLogger(fmt.Sprintf("Uploading %s... ", path.Base(file)))
defer logger.Wait()
opts := soap.Upload{
ContentLength: size,
Progress: logger,
}
return lease.Upload(ctx, item, f, opts)
}

256
vendor/github.com/vmware/govmomi/govc/importx/spec.go generated vendored Normal file
View file

@ -0,0 +1,256 @@
/*
Copyright (c) 2015-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package importx
import (
"context"
"flag"
"fmt"
"io"
"path"
"strings"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/ovf"
"github.com/vmware/govmomi/vim25/types"
)
var (
allDiskProvisioningOptions = []string{
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeFlat),
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeMonolithicSparse),
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeMonolithicFlat),
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeTwoGbMaxExtentSparse),
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeTwoGbMaxExtentFlat),
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeThin),
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeThick),
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeSeSparse),
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeEagerZeroedThick),
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeSparse),
}
allIPAllocationPolicyOptions = []string{
string(types.VAppIPAssignmentInfoIpAllocationPolicyDhcpPolicy),
string(types.VAppIPAssignmentInfoIpAllocationPolicyTransientPolicy),
string(types.VAppIPAssignmentInfoIpAllocationPolicyFixedPolicy),
string(types.VAppIPAssignmentInfoIpAllocationPolicyFixedAllocatedPolicy),
}
allIPProtocolOptions = []string{
string(types.VAppIPAssignmentInfoProtocolsIPv4),
string(types.VAppIPAssignmentInfoProtocolsIPv6),
}
)
type spec struct {
*ArchiveFlag
*flags.ClientFlag
*flags.OutputFlag
verbose bool
}
func init() {
cli.Register("import.spec", &spec{})
}
func (cmd *spec) Register(ctx context.Context, f *flag.FlagSet) {
cmd.ArchiveFlag, ctx = newArchiveFlag(ctx)
cmd.ArchiveFlag.Register(ctx, f)
cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
cmd.ClientFlag.Register(ctx, f)
cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
cmd.OutputFlag.Register(ctx, f)
f.BoolVar(&cmd.verbose, "verbose", false, "Verbose spec output")
}
func (cmd *spec) Process(ctx context.Context) error {
if err := cmd.ArchiveFlag.Process(ctx); err != nil {
return err
}
if err := cmd.ClientFlag.Process(ctx); err != nil {
return err
}
return cmd.OutputFlag.Process(ctx)
}
func (cmd *spec) Usage() string {
return "PATH_TO_OVF_OR_OVA"
}
func (cmd *spec) Run(ctx context.Context, f *flag.FlagSet) error {
fpath := ""
args := f.Args()
if len(args) == 1 {
fpath = f.Arg(0)
}
if len(fpath) > 0 {
switch path.Ext(fpath) {
case ".ovf":
cmd.Archive = &FileArchive{Path: fpath}
case "", ".ova":
cmd.Archive = &TapeArchive{Path: fpath}
fpath = "*.ovf"
default:
return fmt.Errorf("invalid file extension %s", path.Ext(fpath))
}
if isRemotePath(fpath) {
client, err := cmd.Client()
if err != nil {
return err
}
switch archive := cmd.Archive.(type) {
case *FileArchive:
archive.Client = client
case *TapeArchive:
archive.Client = client
}
}
}
env, err := cmd.Spec(fpath)
if err != nil {
return err
}
if !cmd.All() {
cmd.JSON = true
}
return cmd.WriteResult(&specResult{env})
}
type specResult struct {
*Options
}
func (*specResult) Write(w io.Writer) error {
return nil
}
func (cmd *spec) Map(e *ovf.Envelope) (res []Property) {
if e == nil || e.VirtualSystem == nil {
return nil
}
for _, p := range e.VirtualSystem.Product {
for i, v := range p.Property {
if v.UserConfigurable == nil || !*v.UserConfigurable {
continue
}
d := ""
if v.Default != nil {
d = *v.Default
}
// vSphere only accept True/False as boolean values for some reason
if v.Type == "boolean" {
d = strings.Title(d)
}
// From OVF spec, section 9.5.1:
// key-value-env = [class-value "."] key-value-prod ["." instance-value]
k := v.Key
if p.Class != nil {
k = fmt.Sprintf("%s.%s", *p.Class, k)
}
if p.Instance != nil {
k = fmt.Sprintf("%s.%s", k, *p.Instance)
}
np := Property{KeyValue: types.KeyValue{Key: k, Value: d}}
if cmd.verbose {
np.Spec = &p.Property[i]
}
res = append(res, np)
}
}
return
}
func (cmd *spec) Spec(fpath string) (*Options, error) {
e := &ovf.Envelope{}
if fpath != "" {
d, err := cmd.ReadOvf(fpath)
if err != nil {
return nil, err
}
if e, err = cmd.ReadEnvelope(d); err != nil {
return nil, err
}
}
var deploymentOptions []string
if e.DeploymentOption != nil && e.DeploymentOption.Configuration != nil {
// add default first
for _, c := range e.DeploymentOption.Configuration {
if c.Default != nil && *c.Default {
deploymentOptions = append(deploymentOptions, c.ID)
}
}
for _, c := range e.DeploymentOption.Configuration {
if c.Default == nil || !*c.Default {
deploymentOptions = append(deploymentOptions, c.ID)
}
}
}
o := Options{
DiskProvisioning: allDiskProvisioningOptions[0],
IPAllocationPolicy: allIPAllocationPolicyOptions[0],
IPProtocol: allIPProtocolOptions[0],
MarkAsTemplate: false,
PowerOn: false,
WaitForIP: false,
InjectOvfEnv: false,
PropertyMapping: cmd.Map(e),
}
if deploymentOptions != nil {
o.Deployment = deploymentOptions[0]
}
if e.VirtualSystem != nil && e.VirtualSystem.Annotation != nil {
for _, a := range e.VirtualSystem.Annotation {
o.Annotation += a.Annotation
}
}
if e.Network != nil {
for _, net := range e.Network.Networks {
o.NetworkMapping = append(o.NetworkMapping, Network{net.Name, ""})
}
}
if cmd.verbose {
if deploymentOptions != nil {
o.AllDeploymentOptions = deploymentOptions
}
o.AllDiskProvisioningOptions = allDiskProvisioningOptions
o.AllIPAllocationPolicyOptions = allIPAllocationPolicyOptions
o.AllIPProtocolOptions = allIPProtocolOptions
}
return &o, nil
}

132
vendor/github.com/vmware/govmomi/govc/importx/vmdk.go generated vendored Normal file
View file

@ -0,0 +1,132 @@
/*
Copyright (c) 2014-2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package importx
import (
"context"
"errors"
"flag"
"fmt"
"path"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/vmdk"
)
type disk struct {
*flags.DatastoreFlag
*flags.ResourcePoolFlag
*flags.FolderFlag
*flags.OutputFlag
force bool
}
func init() {
cli.Register("import.vmdk", &disk{})
}
func (cmd *disk) Register(ctx context.Context, f *flag.FlagSet) {
cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
cmd.DatastoreFlag.Register(ctx, f)
cmd.ResourcePoolFlag, ctx = flags.NewResourcePoolFlag(ctx)
cmd.ResourcePoolFlag.Register(ctx, f)
cmd.FolderFlag, ctx = flags.NewFolderFlag(ctx)
cmd.FolderFlag.Register(ctx, f)
cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
cmd.OutputFlag.Register(ctx, f)
f.BoolVar(&cmd.force, "force", false, "Overwrite existing disk")
}
func (cmd *disk) Process(ctx context.Context) error {
if err := cmd.DatastoreFlag.Process(ctx); err != nil {
return err
}
if err := cmd.ResourcePoolFlag.Process(ctx); err != nil {
return err
}
if err := cmd.FolderFlag.Process(ctx); err != nil {
return err
}
if err := cmd.OutputFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *disk) Usage() string {
return "PATH_TO_VMDK [REMOTE_DIRECTORY]"
}
func (cmd *disk) Run(ctx context.Context, f *flag.FlagSet) error {
args := f.Args()
if len(args) < 1 {
return errors.New("no file to import")
}
src := f.Arg(0)
c, err := cmd.DatastoreFlag.Client()
if err != nil {
return err
}
dc, err := cmd.DatastoreFlag.Datacenter()
if err != nil {
return err
}
ds, err := cmd.DatastoreFlag.Datastore()
if err != nil {
return err
}
pool, err := cmd.ResourcePoolFlag.ResourcePool()
if err != nil {
return err
}
folder, err := cmd.FolderOrDefault("vm")
if err != nil {
return err
}
logger := cmd.ProgressLogger(fmt.Sprintf("Uploading %s... ", path.Base(src)))
defer logger.Wait()
p := vmdk.ImportParams{
Path: f.Arg(1),
Logger: logger,
Type: "", // TODO: flag
Force: cmd.force,
Datacenter: dc,
Pool: pool,
Folder: folder,
}
err = vmdk.Import(ctx, c, src, ds, p)
if err != nil && err == vmdk.ErrInvalidFormat {
return fmt.Errorf(`%s
The vmdk can be converted using one of:
vmware-vdiskmanager -t 5 -r '%s' new.vmdk
qemu-img convert -O vmdk -o subformat=streamOptimized '%s' new.vmdk`, err, src, src)
}
return err
}

187
vendor/github.com/vmware/govmomi/govc/vm/change.go generated vendored Normal file
View file

@ -0,0 +1,187 @@
/*
Copyright (c) 2015-2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package vm
import (
"context"
"flag"
"fmt"
"reflect"
"strings"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/vim25/types"
)
type extraConfig []types.BaseOptionValue
func (e *extraConfig) String() string {
return fmt.Sprintf("%v", *e)
}
func (e *extraConfig) Set(v string) error {
r := strings.SplitN(v, "=", 2)
if len(r) < 2 {
return fmt.Errorf("failed to parse extraConfig: %s", v)
}
*e = append(*e, &types.OptionValue{Key: r[0], Value: r[1]})
return nil
}
type change struct {
*flags.VirtualMachineFlag
*flags.ResourceAllocationFlag
types.VirtualMachineConfigSpec
extraConfig extraConfig
Latency string
}
func init() {
cli.Register("vm.change", &change{})
}
var latencyLevels = []string{
string(types.LatencySensitivitySensitivityLevelLow),
string(types.LatencySensitivitySensitivityLevelNormal),
string(types.LatencySensitivitySensitivityLevelHigh),
}
// setLatency validates latency level if set
func (cmd *change) setLatency() error {
if cmd.Latency == "" {
return nil
}
for _, l := range latencyLevels {
if l == cmd.Latency {
cmd.LatencySensitivity = &types.LatencySensitivity{
Level: types.LatencySensitivitySensitivityLevel(cmd.Latency),
}
return nil
}
}
return fmt.Errorf("latency must be one of: %s", strings.Join(latencyLevels, "|"))
}
// setAllocation sets *info=nil if none of the fields have been set.
// We need non-nil fields for use with flag.FlagSet, but we want the
// VirtualMachineConfigSpec fields to be nil if none of the related flags were given.
func setAllocation(info **types.ResourceAllocationInfo) {
r := *info
if r.Shares.Level == "" {
r.Shares = nil
} else {
return
}
if r.Limit != nil {
return
}
if r.Reservation != nil {
return
}
*info = nil
}
func (cmd *change) Register(ctx context.Context, f *flag.FlagSet) {
cmd.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx)
cmd.VirtualMachineFlag.Register(ctx, f)
cmd.CpuAllocation = &types.ResourceAllocationInfo{Shares: new(types.SharesInfo)}
cmd.MemoryAllocation = &types.ResourceAllocationInfo{Shares: new(types.SharesInfo)}
cmd.ResourceAllocationFlag = flags.NewResourceAllocationFlag(cmd.CpuAllocation, cmd.MemoryAllocation)
cmd.ResourceAllocationFlag.ExpandableReservation = false
cmd.ResourceAllocationFlag.Register(ctx, f)
f.Int64Var(&cmd.MemoryMB, "m", 0, "Size in MB of memory")
f.Var(flags.NewInt32(&cmd.NumCPUs), "c", "Number of CPUs")
f.StringVar(&cmd.GuestId, "g", "", "Guest OS")
f.StringVar(&cmd.Name, "name", "", "Display name")
f.StringVar(&cmd.Latency, "latency", "", fmt.Sprintf("Latency sensitivity (%s)", strings.Join(latencyLevels, "|")))
f.StringVar(&cmd.Annotation, "annotation", "", "VM description")
f.StringVar(&cmd.Uuid, "uuid", "", "BIOS UUID")
f.Var(&cmd.extraConfig, "e", "ExtraConfig. <key>=<value>")
f.Var(flags.NewOptionalBool(&cmd.NestedHVEnabled), "nested-hv-enabled", "Enable nested hardware-assisted virtualization")
cmd.Tools = &types.ToolsConfigInfo{}
f.Var(flags.NewOptionalBool(&cmd.Tools.SyncTimeWithHost), "sync-time-with-host", "Enable SyncTimeWithHost")
f.Var(flags.NewOptionalBool(&cmd.VPMCEnabled), "vpmc-enabled", "Enable CPU performance counters")
f.Var(flags.NewOptionalBool(&cmd.MemoryHotAddEnabled), "memory-hot-add-enabled", "Enable memory hot add")
f.Var(flags.NewOptionalBool(&cmd.MemoryReservationLockedToMax), "memory-pin", "Reserve all guest memory")
f.Var(flags.NewOptionalBool(&cmd.CpuHotAddEnabled), "cpu-hot-add-enabled", "Enable CPU hot add")
}
func (cmd *change) Description() string {
return `Change VM configuration.
To add ExtraConfig variables that can read within the guest, use the 'guestinfo.' prefix.
Examples:
govc vm.change -vm $vm -mem.reservation 2048
govc vm.change -vm $vm -e smc.present=TRUE -e ich7m.present=TRUE
# Enable both cpu and memory hotplug on a guest:
govc vm.change -vm $vm -cpu-hot-add-enabled -memory-hot-add-enabled
govc vm.change -vm $vm -e guestinfo.vmname $vm
# Read the variable set above inside the guest:
vmware-rpctool "info-get guestinfo.vmname"
govc vm.change -vm $vm -latency high
govc vm.change -vm $vm -latency normal
govc vm.change -vm $vm -uuid 4139c345-7186-4924-a842-36b69a24159b`
}
func (cmd *change) Process(ctx context.Context) error {
if err := cmd.VirtualMachineFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *change) Run(ctx context.Context, f *flag.FlagSet) error {
vm, err := cmd.VirtualMachine()
if err != nil {
return err
}
if vm == nil {
return flag.ErrHelp
}
if len(cmd.extraConfig) > 0 {
cmd.VirtualMachineConfigSpec.ExtraConfig = cmd.extraConfig
}
setAllocation(&cmd.CpuAllocation)
setAllocation(&cmd.MemoryAllocation)
if reflect.DeepEqual(cmd.Tools, new(types.ToolsConfigInfo)) {
cmd.Tools = nil // no flags set, avoid sending <tools/> in the request
}
if err = cmd.setLatency(); err != nil {
return err
}
task, err := vm.Reconfigure(ctx, cmd.VirtualMachineConfigSpec)
if err != nil {
return err
}
return task.Wait(ctx)
}

484
vendor/github.com/vmware/govmomi/govc/vm/clone.go generated vendored Normal file
View file

@ -0,0 +1,484 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package vm
import (
"context"
"flag"
"fmt"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
type clone struct {
*flags.ClientFlag
*flags.ClusterFlag
*flags.DatacenterFlag
*flags.DatastoreFlag
*flags.StoragePodFlag
*flags.ResourcePoolFlag
*flags.HostSystemFlag
*flags.NetworkFlag
*flags.FolderFlag
*flags.VirtualMachineFlag
name string
memory int
cpus int
on bool
force bool
template bool
customization string
waitForIP bool
annotation string
snapshot string
link bool
Client *vim25.Client
Cluster *object.ClusterComputeResource
Datacenter *object.Datacenter
Datastore *object.Datastore
StoragePod *object.StoragePod
ResourcePool *object.ResourcePool
HostSystem *object.HostSystem
Folder *object.Folder
VirtualMachine *object.VirtualMachine
}
func init() {
cli.Register("vm.clone", &clone{})
}
func (cmd *clone) Register(ctx context.Context, f *flag.FlagSet) {
cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
cmd.ClientFlag.Register(ctx, f)
cmd.ClusterFlag, ctx = flags.NewClusterFlag(ctx)
cmd.ClusterFlag.RegisterPlacement(ctx, f)
cmd.DatacenterFlag, ctx = flags.NewDatacenterFlag(ctx)
cmd.DatacenterFlag.Register(ctx, f)
cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
cmd.DatastoreFlag.Register(ctx, f)
cmd.StoragePodFlag, ctx = flags.NewStoragePodFlag(ctx)
cmd.StoragePodFlag.Register(ctx, f)
cmd.ResourcePoolFlag, ctx = flags.NewResourcePoolFlag(ctx)
cmd.ResourcePoolFlag.Register(ctx, f)
cmd.HostSystemFlag, ctx = flags.NewHostSystemFlag(ctx)
cmd.HostSystemFlag.Register(ctx, f)
cmd.NetworkFlag, ctx = flags.NewNetworkFlag(ctx)
cmd.NetworkFlag.Register(ctx, f)
cmd.FolderFlag, ctx = flags.NewFolderFlag(ctx)
cmd.FolderFlag.Register(ctx, f)
cmd.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx)
cmd.VirtualMachineFlag.Register(ctx, f)
f.IntVar(&cmd.memory, "m", 0, "Size in MB of memory")
f.IntVar(&cmd.cpus, "c", 0, "Number of CPUs")
f.BoolVar(&cmd.on, "on", true, "Power on VM")
f.BoolVar(&cmd.force, "force", false, "Create VM if vmx already exists")
f.BoolVar(&cmd.template, "template", false, "Create a Template")
f.StringVar(&cmd.customization, "customization", "", "Customization Specification Name")
f.BoolVar(&cmd.waitForIP, "waitip", false, "Wait for VM to acquire IP address")
f.StringVar(&cmd.annotation, "annotation", "", "VM description")
f.StringVar(&cmd.snapshot, "snapshot", "", "Snapshot name to clone from")
f.BoolVar(&cmd.link, "link", false, "Creates a linked clone from snapshot or source VM")
}
func (cmd *clone) Usage() string {
return "NAME"
}
func (cmd *clone) Description() string {
return `Clone VM or template to NAME.
Examples:
govc vm.clone -vm template-vm new-vm
govc vm.clone -vm template-vm -link new-vm
govc vm.clone -vm template-vm -snapshot s-name new-vm
govc vm.clone -vm template-vm -link -snapshot s-name new-vm
govc vm.clone -vm template-vm -cluster cluster1 new-vm # use compute cluster placement
govc vm.clone -vm template-vm -datastore-cluster dscluster new-vm # use datastore cluster placement
govc vm.clone -vm template-vm -snapshot $(govc snapshot.tree -vm template-vm -C) new-vm
govc vm.clone -vm template-vm -template new-template # clone a VM template
govc vm.clone -vm=/ClusterName/vm/FolderName/VM_templateName -on=true -host=myesxi01 -ds=datastore01 myVM_name`
}
func (cmd *clone) Process(ctx context.Context) error {
if err := cmd.ClientFlag.Process(ctx); err != nil {
return err
}
if err := cmd.ClusterFlag.Process(ctx); err != nil {
return err
}
if err := cmd.DatacenterFlag.Process(ctx); err != nil {
return err
}
if err := cmd.DatastoreFlag.Process(ctx); err != nil {
return err
}
if err := cmd.StoragePodFlag.Process(ctx); err != nil {
return err
}
if err := cmd.ResourcePoolFlag.Process(ctx); err != nil {
return err
}
if err := cmd.HostSystemFlag.Process(ctx); err != nil {
return err
}
if err := cmd.NetworkFlag.Process(ctx); err != nil {
return err
}
if err := cmd.FolderFlag.Process(ctx); err != nil {
return err
}
if err := cmd.VirtualMachineFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *clone) Run(ctx context.Context, f *flag.FlagSet) error {
var err error
if len(f.Args()) != 1 {
return flag.ErrHelp
}
cmd.name = f.Arg(0)
if cmd.name == "" {
return flag.ErrHelp
}
cmd.Client, err = cmd.ClientFlag.Client()
if err != nil {
return err
}
cmd.Cluster, err = cmd.ClusterFlag.ClusterIfSpecified()
if err != nil {
return err
}
cmd.Datacenter, err = cmd.DatacenterFlag.Datacenter()
if err != nil {
return err
}
if cmd.StoragePodFlag.Isset() {
cmd.StoragePod, err = cmd.StoragePodFlag.StoragePod()
if err != nil {
return err
}
} else if cmd.Cluster == nil {
cmd.Datastore, err = cmd.DatastoreFlag.Datastore()
if err != nil {
return err
}
}
cmd.HostSystem, err = cmd.HostSystemFlag.HostSystemIfSpecified()
if err != nil {
return err
}
if cmd.HostSystem != nil {
if cmd.ResourcePool, err = cmd.HostSystem.ResourcePool(ctx); err != nil {
return err
}
} else {
if cmd.Cluster == nil {
// -host is optional
if cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePool(); err != nil {
return err
}
}
}
if cmd.Folder, err = cmd.FolderFlag.Folder(); err != nil {
return err
}
if cmd.VirtualMachine, err = cmd.VirtualMachineFlag.VirtualMachine(); err != nil {
return err
}
if cmd.VirtualMachine == nil {
return flag.ErrHelp
}
vm, err := cmd.cloneVM(ctx)
if err != nil {
return err
}
if cmd.cpus > 0 || cmd.memory > 0 || cmd.annotation != "" {
vmConfigSpec := types.VirtualMachineConfigSpec{}
if cmd.cpus > 0 {
vmConfigSpec.NumCPUs = int32(cmd.cpus)
}
if cmd.memory > 0 {
vmConfigSpec.MemoryMB = int64(cmd.memory)
}
vmConfigSpec.Annotation = cmd.annotation
task, err := vm.Reconfigure(ctx, vmConfigSpec)
if err != nil {
return err
}
_, err = task.WaitForResult(ctx, nil)
if err != nil {
return err
}
}
if cmd.template {
return nil
}
if cmd.on {
task, err := vm.PowerOn(ctx)
if err != nil {
return err
}
_, err = task.WaitForResult(ctx, nil)
if err != nil {
return err
}
if cmd.waitForIP {
_, err = vm.WaitForIP(ctx)
if err != nil {
return err
}
}
}
return nil
}
func (cmd *clone) cloneVM(ctx context.Context) (*object.VirtualMachine, error) {
devices, err := cmd.VirtualMachine.Device(ctx)
if err != nil {
return nil, err
}
// prepare virtual device config spec for network card
configSpecs := []types.BaseVirtualDeviceConfigSpec{}
if cmd.NetworkFlag.IsSet() {
op := types.VirtualDeviceConfigSpecOperationAdd
card, derr := cmd.NetworkFlag.Device()
if derr != nil {
return nil, derr
}
// search for the first network card of the source
for _, device := range devices {
if _, ok := device.(types.BaseVirtualEthernetCard); ok {
op = types.VirtualDeviceConfigSpecOperationEdit
// set new backing info
cmd.NetworkFlag.Change(device, card)
card = device
break
}
}
configSpecs = append(configSpecs, &types.VirtualDeviceConfigSpec{
Operation: op,
Device: card,
})
}
folderref := cmd.Folder.Reference()
var poolref *types.ManagedObjectReference
if cmd.ResourcePool != nil {
poolref = types.NewReference(cmd.ResourcePool.Reference())
}
relocateSpec := types.VirtualMachineRelocateSpec{
DeviceChange: configSpecs,
Folder: &folderref,
Pool: poolref,
}
if cmd.HostSystem != nil {
hostref := cmd.HostSystem.Reference()
relocateSpec.Host = &hostref
}
cloneSpec := &types.VirtualMachineCloneSpec{
PowerOn: false,
Template: cmd.template,
}
if cmd.snapshot == "" {
if cmd.link {
relocateSpec.DiskMoveType = string(types.VirtualMachineRelocateDiskMoveOptionsMoveAllDiskBackingsAndAllowSharing)
}
} else {
if cmd.link {
relocateSpec.DiskMoveType = string(types.VirtualMachineRelocateDiskMoveOptionsCreateNewChildDiskBacking)
}
ref, ferr := cmd.VirtualMachine.FindSnapshot(ctx, cmd.snapshot)
if ferr != nil {
return nil, ferr
}
cloneSpec.Snapshot = ref
}
cloneSpec.Location = relocateSpec
vmref := cmd.VirtualMachine.Reference()
// clone to storage pod
datastoreref := types.ManagedObjectReference{}
if cmd.StoragePod != nil && cmd.Datastore == nil {
storagePod := cmd.StoragePod.Reference()
// Build pod selection spec from config spec
podSelectionSpec := types.StorageDrsPodSelectionSpec{
StoragePod: &storagePod,
}
// Build the placement spec
storagePlacementSpec := types.StoragePlacementSpec{
Folder: &folderref,
Vm: &vmref,
CloneName: cmd.name,
CloneSpec: cloneSpec,
PodSelectionSpec: podSelectionSpec,
Type: string(types.StoragePlacementSpecPlacementTypeClone),
}
// Get the storage placement result
storageResourceManager := object.NewStorageResourceManager(cmd.Client)
result, err := storageResourceManager.RecommendDatastores(ctx, storagePlacementSpec)
if err != nil {
return nil, err
}
// Get the recommendations
recommendations := result.Recommendations
if len(recommendations) == 0 {
return nil, fmt.Errorf("no datastore-cluster recommendations")
}
// Get the first recommendation
datastoreref = recommendations[0].Action[0].(*types.StoragePlacementAction).Destination
} else if cmd.StoragePod == nil && cmd.Datastore != nil {
datastoreref = cmd.Datastore.Reference()
} else if cmd.Cluster != nil {
spec := types.PlacementSpec{
PlacementType: string(types.PlacementSpecPlacementTypeClone),
CloneName: cmd.name,
CloneSpec: cloneSpec,
RelocateSpec: &cloneSpec.Location,
Vm: &vmref,
}
result, err := cmd.Cluster.PlaceVm(ctx, spec)
if err != nil {
return nil, err
}
recs := result.Recommendations
if len(recs) == 0 {
return nil, fmt.Errorf("no cluster recommendations")
}
rspec := *recs[0].Action[0].(*types.PlacementAction).RelocateSpec
cloneSpec.Location.Host = rspec.Host
cloneSpec.Location.Datastore = rspec.Datastore
datastoreref = *rspec.Datastore
} else {
return nil, fmt.Errorf("please provide either a cluster, datastore or datastore-cluster")
}
// Set the destination datastore
cloneSpec.Location.Datastore = &datastoreref
// Check if vmx already exists
if !cmd.force {
vmxPath := fmt.Sprintf("%s/%s.vmx", cmd.name, cmd.name)
var mds mo.Datastore
err = property.DefaultCollector(cmd.Client).RetrieveOne(ctx, datastoreref, []string{"name"}, &mds)
if err != nil {
return nil, err
}
datastore := object.NewDatastore(cmd.Client, datastoreref)
datastore.InventoryPath = mds.Name
_, err := datastore.Stat(ctx, vmxPath)
if err == nil {
dsPath := cmd.Datastore.Path(vmxPath)
return nil, fmt.Errorf("file %s already exists", dsPath)
}
}
// check if customization specification requested
if len(cmd.customization) > 0 {
// get the customization spec manager
customizationSpecManager := object.NewCustomizationSpecManager(cmd.Client)
// check if customization specification exists
exists, err := customizationSpecManager.DoesCustomizationSpecExist(ctx, cmd.customization)
if err != nil {
return nil, err
}
if !exists {
return nil, fmt.Errorf("customization specification %s does not exists", cmd.customization)
}
// get the customization specification
customSpecItem, err := customizationSpecManager.GetCustomizationSpec(ctx, cmd.customization)
if err != nil {
return nil, err
}
customSpec := customSpecItem.Spec
// set the customization
cloneSpec.Customization = &customSpec
}
task, err := cmd.VirtualMachine.Clone(ctx, cmd.Folder, cmd.name, *cloneSpec)
if err != nil {
return nil, err
}
logger := cmd.ProgressLogger(fmt.Sprintf("Cloning %s to %s...", cmd.VirtualMachine.InventoryPath, cmd.name))
defer logger.Wait()
info, err := task.WaitForResult(ctx, logger)
if err != nil {
return nil, err
}
return object.NewVirtualMachine(cmd.Client, info.Result.(types.ManagedObjectReference)), nil
}

173
vendor/github.com/vmware/govmomi/govc/vm/console.go generated vendored Normal file
View file

@ -0,0 +1,173 @@
/*
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package vm
import (
"context"
"flag"
"fmt"
"io"
"net/url"
"os"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/session"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
)
type console struct {
*flags.VirtualMachineFlag
h5 bool
capture string
}
func init() {
cli.Register("vm.console", &console{})
}
func (cmd *console) Register(ctx context.Context, f *flag.FlagSet) {
cmd.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx)
cmd.VirtualMachineFlag.Register(ctx, f)
f.BoolVar(&cmd.h5, "h5", false, "Generate HTML5 UI console link")
f.StringVar(&cmd.capture, "capture", "", "Capture console screen shot to file")
}
func (cmd *console) Process(ctx context.Context) error {
if err := cmd.VirtualMachineFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *console) Usage() string {
return "VM"
}
func (cmd *console) Description() string {
return `Generate console URL or screen capture for VM.
One of VMRC, VMware Player, VMware Fusion or VMware Workstation must be installed to
open VMRC console URLs.
Examples:
govc vm.console my-vm
govc vm.console -capture screen.png my-vm # screen capture
govc vm.console -capture - my-vm | display # screen capture to stdout
open $(govc vm.console my-vm) # MacOSX VMRC
open $(govc vm.console -h5 my-vm) # MacOSX H5
xdg-open $(govc vm.console my-vm) # Linux VMRC
xdg-open $(govc vm.console -h5 my-vm) # Linux H5`
}
func (cmd *console) Run(ctx context.Context, f *flag.FlagSet) error {
vms, err := cmd.VirtualMachines(f.Args())
if err != nil {
return err
}
if len(vms) != 1 {
return flag.ErrHelp
}
vm := vms[0]
state, err := vm.PowerState(ctx)
if err != nil {
return err
}
if state != types.VirtualMachinePowerStatePoweredOn {
return fmt.Errorf("vm is not powered on (%s)", state)
}
c := vm.Client()
u := c.URL()
if cmd.capture != "" {
u.Path = "/screen"
query := url.Values{"id": []string{vm.Reference().Value}}
u.RawQuery = query.Encode()
param := soap.DefaultDownload
if cmd.capture == "-" {
w, _, derr := c.Download(ctx, u, &param)
if derr != nil {
return derr
}
_, err = io.Copy(os.Stdout, w)
if err != nil {
return err
}
return w.Close()
}
return c.DownloadFile(ctx, cmd.capture, u, &param)
}
m := session.NewManager(c)
ticket, err := m.AcquireCloneTicket(ctx)
if err != nil {
return err
}
var link string
if cmd.h5 {
m := object.NewOptionManager(c, *c.ServiceContent.Setting)
opt, err := m.Query(ctx, "VirtualCenter.FQDN")
if err != nil {
return err
}
fqdn := opt[0].GetOptionValue().Value.(string)
var info object.HostCertificateInfo
err = info.FromURL(u, nil)
if err != nil {
return err
}
u.Path = "/ui/webconsole.html"
u.RawQuery = url.Values{
"vmId": []string{vm.Reference().Value},
"vmName": []string{vm.Name()},
"serverGuid": []string{c.ServiceContent.About.InstanceUuid},
"host": []string{fqdn},
"sessionTicket": []string{ticket},
"thumbprint": []string{info.ThumbprintSHA1},
}.Encode()
link = u.String()
} else {
link = fmt.Sprintf("vmrc://clone:%s@%s/?moid=%s", ticket, u.Hostname(), vm.Reference().Value)
}
fmt.Fprintln(os.Stdout, link)
return nil
}

611
vendor/github.com/vmware/govmomi/govc/vm/create.go generated vendored Normal file
View file

@ -0,0 +1,611 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package vm
import (
"context"
"flag"
"fmt"
"strings"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/units"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
var hardwareVersions = []struct {
esx, vmx string
}{
{"5.0", "vmx-8"},
{"5.5", "vmx-10"},
{"6.0", "vmx-11"},
{"6.5", "vmx-13"},
{"6.7", "vmx-14"},
{"7.0", "vmx-17"},
}
type create struct {
*flags.ClientFlag
*flags.ClusterFlag
*flags.DatacenterFlag
*flags.DatastoreFlag
*flags.StoragePodFlag
*flags.ResourcePoolFlag
*flags.HostSystemFlag
*flags.NetworkFlag
*flags.FolderFlag
name string
memory int
cpus int
guestID string
link bool
on bool
force bool
controller string
annotation string
firmware string
version string
iso string
isoDatastoreFlag *flags.DatastoreFlag
isoDatastore *object.Datastore
disk string
diskDatastoreFlag *flags.DatastoreFlag
diskDatastore *object.Datastore
// Only set if the disk argument is a byte size, which means the disk
// doesn't exist yet and should be created
diskByteSize int64
Client *vim25.Client
Cluster *object.ClusterComputeResource
Datacenter *object.Datacenter
Datastore *object.Datastore
StoragePod *object.StoragePod
ResourcePool *object.ResourcePool
HostSystem *object.HostSystem
Folder *object.Folder
}
func init() {
cli.Register("vm.create", &create{})
}
func (cmd *create) Register(ctx context.Context, f *flag.FlagSet) {
cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
cmd.ClientFlag.Register(ctx, f)
cmd.ClusterFlag, ctx = flags.NewClusterFlag(ctx)
cmd.ClusterFlag.RegisterPlacement(ctx, f)
cmd.DatacenterFlag, ctx = flags.NewDatacenterFlag(ctx)
cmd.DatacenterFlag.Register(ctx, f)
cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
cmd.DatastoreFlag.Register(ctx, f)
cmd.StoragePodFlag, ctx = flags.NewStoragePodFlag(ctx)
cmd.StoragePodFlag.Register(ctx, f)
cmd.ResourcePoolFlag, ctx = flags.NewResourcePoolFlag(ctx)
cmd.ResourcePoolFlag.Register(ctx, f)
cmd.HostSystemFlag, ctx = flags.NewHostSystemFlag(ctx)
cmd.HostSystemFlag.Register(ctx, f)
cmd.NetworkFlag, ctx = flags.NewNetworkFlag(ctx)
cmd.NetworkFlag.Register(ctx, f)
cmd.FolderFlag, ctx = flags.NewFolderFlag(ctx)
cmd.FolderFlag.Register(ctx, f)
f.IntVar(&cmd.memory, "m", 1024, "Size in MB of memory")
f.IntVar(&cmd.cpus, "c", 1, "Number of CPUs")
f.StringVar(&cmd.guestID, "g", "otherGuest", "Guest OS ID")
f.BoolVar(&cmd.link, "link", true, "Link specified disk")
f.BoolVar(&cmd.on, "on", true, "Power on VM")
f.BoolVar(&cmd.force, "force", false, "Create VM if vmx already exists")
f.StringVar(&cmd.controller, "disk.controller", "scsi", "Disk controller type")
f.StringVar(&cmd.annotation, "annotation", "", "VM description")
firmwareTypes := []string{
string(types.GuestOsDescriptorFirmwareTypeBios),
string(types.GuestOsDescriptorFirmwareTypeEfi),
}
f.StringVar(&cmd.firmware, "firmware", firmwareTypes[0],
fmt.Sprintf("Firmware type [%s]", strings.Join(firmwareTypes, "|")))
var versions []string
for i := range hardwareVersions {
versions = append(versions, hardwareVersions[i].esx)
}
f.StringVar(&cmd.version, "version", "",
fmt.Sprintf("ESXi hardware version [%s]", strings.Join(versions, "|")))
f.StringVar(&cmd.iso, "iso", "", "ISO path")
cmd.isoDatastoreFlag, ctx = flags.NewCustomDatastoreFlag(ctx)
f.StringVar(&cmd.isoDatastoreFlag.Name, "iso-datastore", "", "Datastore for ISO file")
f.StringVar(&cmd.disk, "disk", "", "Disk path (to use existing) OR size (to create new, e.g. 20GB)")
cmd.diskDatastoreFlag, _ = flags.NewCustomDatastoreFlag(ctx)
f.StringVar(&cmd.diskDatastoreFlag.Name, "disk-datastore", "", "Datastore for disk file")
}
func (cmd *create) Process(ctx context.Context) error {
if err := cmd.ClientFlag.Process(ctx); err != nil {
return err
}
if err := cmd.ClusterFlag.Process(ctx); err != nil {
return err
}
if err := cmd.DatacenterFlag.Process(ctx); err != nil {
return err
}
if err := cmd.DatastoreFlag.Process(ctx); err != nil {
return err
}
if err := cmd.StoragePodFlag.Process(ctx); err != nil {
return err
}
if err := cmd.ResourcePoolFlag.Process(ctx); err != nil {
return err
}
if err := cmd.HostSystemFlag.Process(ctx); err != nil {
return err
}
if err := cmd.NetworkFlag.Process(ctx); err != nil {
return err
}
if err := cmd.FolderFlag.Process(ctx); err != nil {
return err
}
// Default iso/disk datastores to the VM's datastore
if cmd.isoDatastoreFlag.Name == "" {
cmd.isoDatastoreFlag = cmd.DatastoreFlag
}
if cmd.diskDatastoreFlag.Name == "" {
cmd.diskDatastoreFlag = cmd.DatastoreFlag
}
return nil
}
func (cmd *create) Usage() string {
return "NAME"
}
func (cmd *create) Description() string {
return `Create VM.
For a list of possible '-g' IDs, use 'govc vm.option.info' or see:
https://code.vmware.com/apis/358/vsphere/doc/vim.vm.GuestOsDescriptor.GuestOsIdentifier.html
Examples:
govc vm.create -on=false vm-name
govc vm.create -cluster cluster1 vm-name # use compute cluster placement
govc vm.create -datastore-cluster dscluster vm-name # use datastore cluster placement
govc vm.create -m 2048 -c 2 -g freebsd64Guest -net.adapter vmxnet3 -disk.controller pvscsi vm-name`
}
func (cmd *create) Run(ctx context.Context, f *flag.FlagSet) error {
var err error
if len(f.Args()) != 1 {
return flag.ErrHelp
}
cmd.name = f.Arg(0)
if cmd.name == "" {
return flag.ErrHelp
}
cmd.Client, err = cmd.ClientFlag.Client()
if err != nil {
return err
}
cmd.Cluster, err = cmd.ClusterFlag.ClusterIfSpecified()
if err != nil {
return err
}
cmd.Datacenter, err = cmd.DatacenterFlag.Datacenter()
if err != nil {
return err
}
if cmd.StoragePodFlag.Isset() {
cmd.StoragePod, err = cmd.StoragePodFlag.StoragePod()
if err != nil {
return err
}
} else if cmd.Cluster == nil {
cmd.Datastore, err = cmd.DatastoreFlag.Datastore()
if err != nil {
return err
}
}
cmd.HostSystem, err = cmd.HostSystemFlag.HostSystemIfSpecified()
if err != nil {
return err
}
if cmd.HostSystem != nil {
if cmd.ResourcePool, err = cmd.HostSystem.ResourcePool(ctx); err != nil {
return err
}
} else {
if cmd.Cluster == nil {
// -host is optional
if cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePool(); err != nil {
return err
}
} else {
if cmd.ResourcePool, err = cmd.Cluster.ResourcePool(ctx); err != nil {
return err
}
}
}
if cmd.Folder, err = cmd.FolderFlag.Folder(); err != nil {
return err
}
// Verify ISO exists
if cmd.iso != "" {
_, err = cmd.isoDatastoreFlag.Stat(ctx, cmd.iso)
if err != nil {
return err
}
cmd.isoDatastore, err = cmd.isoDatastoreFlag.Datastore()
if err != nil {
return err
}
}
// Verify disk exists
if cmd.disk != "" {
var b units.ByteSize
// If disk can be parsed as byte units, don't stat
err = b.Set(cmd.disk)
if err == nil {
cmd.diskByteSize = int64(b)
} else {
_, err = cmd.diskDatastoreFlag.Stat(ctx, cmd.disk)
if err != nil {
return err
}
cmd.diskDatastore, err = cmd.diskDatastoreFlag.Datastore()
if err != nil {
return err
}
}
}
task, err := cmd.createVM(ctx)
if err != nil {
return err
}
info, err := task.WaitForResult(ctx, nil)
if err != nil {
return err
}
vm := object.NewVirtualMachine(cmd.Client, info.Result.(types.ManagedObjectReference))
if cmd.on {
task, err := vm.PowerOn(ctx)
if err != nil {
return err
}
_, err = task.WaitForResult(ctx, nil)
if err != nil {
return err
}
}
return nil
}
func (cmd *create) createVM(ctx context.Context) (*object.Task, error) {
var devices object.VirtualDeviceList
var err error
if cmd.version != "" {
for i := range hardwareVersions {
if hardwareVersions[i].esx == cmd.version {
cmd.version = hardwareVersions[i].vmx
break
}
}
}
spec := &types.VirtualMachineConfigSpec{
Name: cmd.name,
GuestId: cmd.guestID,
NumCPUs: int32(cmd.cpus),
MemoryMB: int64(cmd.memory),
Annotation: cmd.annotation,
Firmware: cmd.firmware,
Version: cmd.version,
}
devices, err = cmd.addStorage(nil)
if err != nil {
return nil, err
}
devices, err = cmd.addNetwork(devices)
if err != nil {
return nil, err
}
deviceChange, err := devices.ConfigSpec(types.VirtualDeviceConfigSpecOperationAdd)
if err != nil {
return nil, err
}
spec.DeviceChange = deviceChange
var datastore *object.Datastore
// If storage pod is specified, collect placement recommendations
if cmd.StoragePod != nil {
datastore, err = cmd.recommendDatastore(ctx, spec)
if err != nil {
return nil, err
}
} else if cmd.Datastore != nil {
datastore = cmd.Datastore
} else if cmd.Cluster != nil {
pspec := types.PlacementSpec{
PlacementType: string(types.PlacementSpecPlacementTypeCreate),
ConfigSpec: spec,
}
result, err := cmd.Cluster.PlaceVm(ctx, pspec)
if err != nil {
return nil, err
}
recs := result.Recommendations
if len(recs) == 0 {
return nil, fmt.Errorf("no cluster recommendations")
}
rspec := *recs[0].Action[0].(*types.PlacementAction).RelocateSpec
if rspec.Datastore != nil {
datastore = object.NewDatastore(cmd.Client, *rspec.Datastore)
datastore.InventoryPath, _ = datastore.ObjectName(ctx)
cmd.Datastore = datastore
}
if rspec.Host != nil {
cmd.HostSystem = object.NewHostSystem(cmd.Client, *rspec.Host)
}
if rspec.Pool != nil {
cmd.ResourcePool = object.NewResourcePool(cmd.Client, *rspec.Pool)
}
} else {
return nil, fmt.Errorf("please provide either a cluster, datastore or datastore-cluster")
}
if !cmd.force {
vmxPath := fmt.Sprintf("%s/%s.vmx", cmd.name, cmd.name)
_, err := datastore.Stat(ctx, vmxPath)
if err == nil {
dsPath := cmd.Datastore.Path(vmxPath)
return nil, fmt.Errorf("file %s already exists", dsPath)
}
}
folder := cmd.Folder
spec.Files = &types.VirtualMachineFileInfo{
VmPathName: fmt.Sprintf("[%s]", datastore.Name()),
}
return folder.CreateVM(ctx, *spec, cmd.ResourcePool, cmd.HostSystem)
}
func (cmd *create) addStorage(devices object.VirtualDeviceList) (object.VirtualDeviceList, error) {
if cmd.controller != "ide" {
if cmd.controller == "nvme" {
nvme, err := devices.CreateNVMEController()
if err != nil {
return nil, err
}
devices = append(devices, nvme)
cmd.controller = devices.Name(nvme)
} else {
scsi, err := devices.CreateSCSIController(cmd.controller)
if err != nil {
return nil, err
}
devices = append(devices, scsi)
cmd.controller = devices.Name(scsi)
}
}
// If controller is specified to be IDE or if an ISO is specified, add IDE controller.
if cmd.controller == "ide" || cmd.iso != "" {
ide, err := devices.CreateIDEController()
if err != nil {
return nil, err
}
devices = append(devices, ide)
}
if cmd.diskByteSize != 0 {
controller, err := devices.FindDiskController(cmd.controller)
if err != nil {
return nil, err
}
disk := &types.VirtualDisk{
VirtualDevice: types.VirtualDevice{
Key: devices.NewKey(),
Backing: &types.VirtualDiskFlatVer2BackingInfo{
DiskMode: string(types.VirtualDiskModePersistent),
ThinProvisioned: types.NewBool(true),
},
},
CapacityInKB: cmd.diskByteSize / 1024,
}
devices.AssignController(disk, controller)
devices = append(devices, disk)
} else if cmd.disk != "" {
controller, err := devices.FindDiskController(cmd.controller)
if err != nil {
return nil, err
}
ds := cmd.diskDatastore.Reference()
path := cmd.diskDatastore.Path(cmd.disk)
disk := devices.CreateDisk(controller, ds, path)
if cmd.link {
disk = devices.ChildDisk(disk)
}
devices = append(devices, disk)
}
if cmd.iso != "" {
ide, err := devices.FindIDEController("")
if err != nil {
return nil, err
}
cdrom, err := devices.CreateCdrom(ide)
if err != nil {
return nil, err
}
cdrom = devices.InsertIso(cdrom, cmd.isoDatastore.Path(cmd.iso))
devices = append(devices, cdrom)
}
return devices, nil
}
func (cmd *create) addNetwork(devices object.VirtualDeviceList) (object.VirtualDeviceList, error) {
netdev, err := cmd.NetworkFlag.Device()
if err != nil {
return nil, err
}
devices = append(devices, netdev)
return devices, nil
}
func (cmd *create) recommendDatastore(ctx context.Context, spec *types.VirtualMachineConfigSpec) (*object.Datastore, error) {
sp := cmd.StoragePod.Reference()
// Build pod selection spec from config spec
podSelectionSpec := types.StorageDrsPodSelectionSpec{
StoragePod: &sp,
}
// Keep list of disks that need to be placed
var disks []*types.VirtualDisk
// Collect disks eligible for placement
for _, deviceConfigSpec := range spec.DeviceChange {
s := deviceConfigSpec.GetVirtualDeviceConfigSpec()
if s.Operation != types.VirtualDeviceConfigSpecOperationAdd {
continue
}
if s.FileOperation != types.VirtualDeviceConfigSpecFileOperationCreate {
continue
}
d, ok := s.Device.(*types.VirtualDisk)
if !ok {
continue
}
podConfigForPlacement := types.VmPodConfigForPlacement{
StoragePod: sp,
Disk: []types.PodDiskLocator{
{
DiskId: d.Key,
DiskBackingInfo: d.Backing,
},
},
}
podSelectionSpec.InitialVmConfig = append(podSelectionSpec.InitialVmConfig, podConfigForPlacement)
disks = append(disks, d)
}
sps := types.StoragePlacementSpec{
Type: string(types.StoragePlacementSpecPlacementTypeCreate),
ResourcePool: types.NewReference(cmd.ResourcePool.Reference()),
PodSelectionSpec: podSelectionSpec,
ConfigSpec: spec,
}
srm := object.NewStorageResourceManager(cmd.Client)
result, err := srm.RecommendDatastores(ctx, sps)
if err != nil {
return nil, err
}
// Use result to pin disks to recommended datastores
recs := result.Recommendations
if len(recs) == 0 {
return nil, fmt.Errorf("no datastore-cluster recommendations")
}
ds := recs[0].Action[0].(*types.StoragePlacementAction).Destination
var mds mo.Datastore
err = property.DefaultCollector(cmd.Client).RetrieveOne(ctx, ds, []string{"name"}, &mds)
if err != nil {
return nil, err
}
datastore := object.NewDatastore(cmd.Client, ds)
datastore.InventoryPath = mds.Name
// Apply recommendation to eligible disks
for _, disk := range disks {
backing := disk.Backing.(*types.VirtualDiskFlatVer2BackingInfo)
backing.Datastore = &ds
}
return datastore, nil
}

243
vendor/github.com/vmware/govmomi/govc/vm/customize.go generated vendored Normal file
View file

@ -0,0 +1,243 @@
/*
Copyright (c) 2019 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package vm
import (
"context"
"flag"
"fmt"
"strconv"
"strings"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/types"
)
type customize struct {
*flags.VirtualMachineFlag
alc int
prefix types.CustomizationPrefixName
tz string
domain string
host types.CustomizationFixedName
mac flags.StringList
ip flags.StringList
gateway flags.StringList
netmask flags.StringList
dnsserver flags.StringList
kind string
}
func init() {
cli.Register("vm.customize", &customize{})
}
func (cmd *customize) Register(ctx context.Context, f *flag.FlagSet) {
cmd.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx)
cmd.VirtualMachineFlag.Register(ctx, f)
f.IntVar(&cmd.alc, "auto-login", 0, "Number of times the VM should automatically login as an administrator")
f.StringVar(&cmd.prefix.Base, "prefix", "", "Host name generator prefix")
f.StringVar(&cmd.tz, "tz", "", "Time zone")
f.StringVar(&cmd.domain, "domain", "", "Domain name")
f.StringVar(&cmd.host.Name, "name", "", "Host name")
f.Var(&cmd.mac, "mac", "MAC address")
cmd.mac = nil
f.Var(&cmd.ip, "ip", "IP address")
cmd.ip = nil
f.Var(&cmd.gateway, "gateway", "Gateway")
cmd.gateway = nil
f.Var(&cmd.netmask, "netmask", "Netmask")
cmd.netmask = nil
f.Var(&cmd.dnsserver, "dns-server", "DNS server")
cmd.dnsserver = nil
f.StringVar(&cmd.kind, "type", "Linux", "Customization type if spec NAME is not specified (Linux|Windows)")
}
func (cmd *customize) Usage() string {
return "[NAME]"
}
func (cmd *customize) Description() string {
return `Customize VM.
Optionally specify a customization spec NAME.
The '-ip', '-netmask' and '-gateway' flags are for static IP configuration.
If the VM has multiple NICs, an '-ip' and '-netmask' must be specified for each.
Windows -tz value requires the Index (hex): https://support.microsoft.com/en-us/help/973627/microsoft-time-zone-index-values
Examples:
govc vm.customize -vm VM NAME
govc vm.customize -vm VM -name my-hostname -ip dhcp
govc vm.customize -vm VM -gateway GATEWAY -ip NEWIP -netmask NETMASK -dns-server DNS1,DNS2 NAME
# Multiple -ip without -mac are applied by vCenter in the order in which the NICs appear on the bus
govc vm.customize -vm VM -ip 10.0.0.178 -netmask 255.255.255.0 -ip 10.0.0.162 -netmask 255.255.255.0
# Multiple -ip with -mac are applied by vCenter to the NIC with the given MAC address
govc vm.customize -vm VM -mac 00:50:56:be:dd:f8 -ip 10.0.0.178 -netmask 255.255.255.0 -mac 00:50:56:be:60:cf -ip 10.0.0.162 -netmask 255.255.255.0
govc vm.customize -vm VM -auto-login 3 NAME
govc vm.customize -vm VM -prefix demo NAME
govc vm.customize -vm VM -tz America/New_York NAME`
}
func (cmd *customize) Run(ctx context.Context, f *flag.FlagSet) error {
vm, err := cmd.VirtualMachineFlag.VirtualMachine()
if err != nil {
return err
}
if vm == nil {
return flag.ErrHelp
}
var spec *types.CustomizationSpec
name := f.Arg(0)
if name == "" {
spec = &types.CustomizationSpec{
NicSettingMap: make([]types.CustomizationAdapterMapping, len(cmd.ip)),
}
switch cmd.kind {
case "Linux":
spec.Identity = &types.CustomizationLinuxPrep{
HostName: new(types.CustomizationVirtualMachineName),
}
case "Windows":
spec.Identity = &types.CustomizationSysprep{
UserData: types.CustomizationUserData{
ComputerName: new(types.CustomizationVirtualMachineName),
},
}
default:
return flag.ErrHelp
}
} else {
m := object.NewCustomizationSpecManager(vm.Client())
exists, err := m.DoesCustomizationSpecExist(ctx, name)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("specification %q does not exist", name)
}
item, err := m.GetCustomizationSpec(ctx, name)
if err != nil {
return err
}
spec = &item.Spec
}
if len(cmd.ip) > len(spec.NicSettingMap) {
return fmt.Errorf("%d -ip specified, spec %q has %d", len(cmd.ip), name, len(spec.NicSettingMap))
}
sysprep, isWindows := spec.Identity.(*types.CustomizationSysprep)
linprep, _ := spec.Identity.(*types.CustomizationLinuxPrep)
if cmd.domain != "" {
if isWindows {
sysprep.Identification.JoinDomain = cmd.domain
} else {
linprep.Domain = cmd.domain
}
}
if len(cmd.dnsserver) != 0 {
if !isWindows {
for _, s := range cmd.dnsserver {
spec.GlobalIPSettings.DnsServerList =
append(spec.GlobalIPSettings.DnsServerList, strings.Split(s, ",")...)
}
}
}
if cmd.prefix.Base != "" {
if isWindows {
sysprep.UserData.ComputerName = &cmd.prefix
} else {
linprep.HostName = &cmd.prefix
}
}
if cmd.host.Name != "" {
if isWindows {
sysprep.UserData.ComputerName = &cmd.host
} else {
linprep.HostName = &cmd.host
}
}
if cmd.alc != 0 {
if !isWindows {
return fmt.Errorf("option '-auto-login' is Windows only")
}
sysprep.GuiUnattended.AutoLogon = true
sysprep.GuiUnattended.AutoLogonCount = int32(cmd.alc)
}
if cmd.tz != "" {
if isWindows {
tz, err := strconv.ParseInt(cmd.tz, 16, 32)
if err != nil {
return fmt.Errorf("converting -tz=%q: %s", cmd.tz, err)
}
sysprep.GuiUnattended.TimeZone = int32(tz)
} else {
linprep.TimeZone = cmd.tz
}
}
for i, ip := range cmd.ip {
nic := &spec.NicSettingMap[i]
switch ip {
case "dhcp":
nic.Adapter.Ip = new(types.CustomizationDhcpIpGenerator)
default:
nic.Adapter.Ip = &types.CustomizationFixedIp{IpAddress: ip}
}
if i < len(cmd.netmask) {
nic.Adapter.SubnetMask = cmd.netmask[i]
}
if i < len(cmd.mac) {
nic.MacAddress = cmd.mac[i]
}
if i < len(cmd.gateway) {
nic.Adapter.Gateway = strings.Split(cmd.gateway[i], ",")
}
if isWindows {
if i < len(cmd.dnsserver) {
nic.Adapter.DnsServerList = strings.Split(cmd.dnsserver[i], ",")
}
}
}
task, err := vm.Customize(ctx, *spec)
if err != nil {
return err
}
return task.Wait(ctx)
}

97
vendor/github.com/vmware/govmomi/govc/vm/destroy.go generated vendored Normal file
View file

@ -0,0 +1,97 @@
/*
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package vm
import (
"context"
"flag"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
)
type destroy struct {
*flags.ClientFlag
*flags.SearchFlag
}
func init() {
cli.Register("vm.destroy", &destroy{})
}
func (cmd *destroy) Register(ctx context.Context, f *flag.FlagSet) {
cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
cmd.ClientFlag.Register(ctx, f)
cmd.SearchFlag, ctx = flags.NewSearchFlag(ctx, flags.SearchVirtualMachines)
cmd.SearchFlag.Register(ctx, f)
}
func (cmd *destroy) Process(ctx context.Context) error {
if err := cmd.ClientFlag.Process(ctx); err != nil {
return err
}
if err := cmd.SearchFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *destroy) Usage() string {
return "VM..."
}
func (cmd *destroy) Description() string {
return `Power off and delete VM.
When a VM is destroyed, any attached virtual disks are also deleted.
Use the 'device.remove -vm VM -keep disk-*' command to detach and
keep disks if needed, prior to calling vm.destroy.
Examples:
govc vm.destroy my-vm`
}
func (cmd *destroy) Run(ctx context.Context, f *flag.FlagSet) error {
vms, err := cmd.VirtualMachines(f.Args())
if err != nil {
return err
}
for _, vm := range vms {
task, err := vm.PowerOff(ctx)
if err != nil {
return err
}
// Ignore error since the VM may already been in powered off state.
// vm.Destroy will fail if the VM is still powered on.
_ = task.Wait(ctx)
task, err = vm.Destroy(ctx)
if err != nil {
return err
}
err = task.Wait(ctx)
if err != nil {
return err
}
}
return nil
}

74
vendor/github.com/vmware/govmomi/govc/vm/guest/auth.go generated vendored Normal file
View file

@ -0,0 +1,74 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package guest
import (
"context"
"flag"
"fmt"
"os"
"strings"
"github.com/vmware/govmomi/vim25/types"
)
type AuthFlag struct {
auth types.NamePasswordAuthentication
proc bool
}
func newAuthFlag(ctx context.Context) (*AuthFlag, context.Context) {
return &AuthFlag{}, ctx
}
func (flag *AuthFlag) String() string {
return fmt.Sprintf("%s:%s", flag.auth.Username, strings.Repeat("x", len(flag.auth.Password)))
}
func (flag *AuthFlag) Set(s string) error {
c := strings.SplitN(s, ":", 2)
if len(c) > 0 {
flag.auth.Username = c[0]
if len(c) > 1 {
flag.auth.Password = c[1]
}
}
return nil
}
func (flag *AuthFlag) Register(ctx context.Context, f *flag.FlagSet) {
env := "GOVC_GUEST_LOGIN"
value := os.Getenv(env)
err := flag.Set(value)
if err != nil {
fmt.Printf("couldn't set guest login values: %v", err)
}
usage := fmt.Sprintf("Guest VM credentials [%s]", env)
f.Var(flag, "l", usage)
if flag.proc {
f.BoolVar(&flag.auth.GuestAuthentication.InteractiveSession, "i", false, "Interactive session")
}
}
func (flag *AuthFlag) Process(ctx context.Context) error {
return nil
}
func (flag *AuthFlag) Auth() types.BaseGuestAuthentication {
return &flag.auth
}

View file

@ -0,0 +1,77 @@
/*
Copyright (c) 2014-2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package guest
import (
"context"
"flag"
"strconv"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/vim25/types"
)
type chmod struct {
*GuestFlag
}
func init() {
cli.Register("guest.chmod", &chmod{})
}
func (cmd *chmod) Register(ctx context.Context, f *flag.FlagSet) {
cmd.GuestFlag, ctx = newGuestFlag(ctx)
cmd.GuestFlag.Register(ctx, f)
}
func (cmd *chmod) Process(ctx context.Context) error {
if err := cmd.GuestFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *chmod) Usage() string {
return "MODE FILE"
}
func (cmd *chmod) Description() string {
return `Change FILE MODE on VM.
Examples:
govc guest.chmod -vm $name 0644 /var/log/foo.log`
}
func (cmd *chmod) Run(ctx context.Context, f *flag.FlagSet) error {
if f.NArg() != 2 {
return flag.ErrHelp
}
m, err := cmd.FileManager()
if err != nil {
return err
}
var attr types.GuestPosixFileAttributes
attr.Permissions, err = strconv.ParseInt(f.Arg(0), 0, 64)
if err != nil {
return err
}
return m.ChangeFileAttributes(ctx, cmd.Auth(), f.Arg(1), &attr)
}

View file

@ -0,0 +1,96 @@
/*
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package guest
import (
"context"
"flag"
"strconv"
"strings"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/vim25/types"
)
type chown struct {
*GuestFlag
}
func init() {
cli.Register("guest.chown", &chown{})
}
func (cmd *chown) Register(ctx context.Context, f *flag.FlagSet) {
cmd.GuestFlag, ctx = newGuestFlag(ctx)
cmd.GuestFlag.Register(ctx, f)
}
func (cmd *chown) Process(ctx context.Context) error {
if err := cmd.GuestFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *chown) Usage() string {
return "UID[:GID] FILE"
}
func (cmd *chown) Description() string {
return `Change FILE UID and GID on VM.
Examples:
govc guest.chown -vm $name UID[:GID] /var/log/foo.log`
}
func (cmd *chown) Run(ctx context.Context, f *flag.FlagSet) error {
if f.NArg() != 2 {
return flag.ErrHelp
}
m, err := cmd.FileManager()
if err != nil {
return err
}
var attr types.GuestPosixFileAttributes
ids := strings.SplitN(f.Arg(0), ":", 2)
if len(ids) == 0 {
return flag.ErrHelp
}
id, err := strconv.Atoi(ids[0])
if err != nil {
return err
}
attr.OwnerId = new(int32)
*attr.OwnerId = int32(id)
if len(ids) == 2 {
id, err = strconv.Atoi(ids[1])
if err != nil {
return err
}
attr.GroupId = new(int32)
*attr.GroupId = int32(id)
}
return m.ChangeFileAttributes(ctx, cmd.Auth(), f.Arg(1), &attr)
}

80
vendor/github.com/vmware/govmomi/govc/vm/guest/df.go generated vendored Normal file
View file

@ -0,0 +1,80 @@
/*
Copyright (c) 2019 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package guest
import (
"context"
"flag"
"fmt"
"io"
"text/tabwriter"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/units"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
type df struct {
*flags.VirtualMachineFlag
}
func init() {
cli.Register("guest.df", &df{})
}
func (cmd *df) Register(ctx context.Context, f *flag.FlagSet) {
cmd.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx)
cmd.VirtualMachineFlag.Register(ctx, f)
}
func (cmd *df) Description() string {
return `Report file system disk space usage.
Examples:
govc guest.df -vm $name`
}
type dfResult []types.GuestDiskInfo
func (r dfResult) Write(w io.Writer) error {
tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0)
_, _ = fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%s\n", "Filesystem", "Size", "Used", "Avail", "Use%")
for _, disk := range r {
used := disk.Capacity - disk.FreeSpace
use := 100.0 * float32(used) / float32(disk.Capacity)
_, _ = fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%.0f%%\n", disk.DiskPath,
units.ByteSize(disk.Capacity), units.ByteSize(used), units.ByteSize(disk.FreeSpace), use)
}
return tw.Flush()
}
func (cmd *df) Run(ctx context.Context, f *flag.FlagSet) error {
obj, err := cmd.VirtualMachine()
if err != nil {
return err
}
var vm mo.VirtualMachine
err = obj.Properties(ctx, obj.Reference(), []string{"guest.disk"}, &vm)
if err != nil {
return err
}
return cmd.WriteResult(dfResult(vm.Guest.Disk))
}

View file

@ -0,0 +1,106 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package guest
import (
"context"
"flag"
"io"
"os"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/vim25/progress"
)
type download struct {
*GuestFlag
overwrite bool
}
func init() {
cli.Register("guest.download", &download{})
}
func (cmd *download) Register(ctx context.Context, f *flag.FlagSet) {
cmd.GuestFlag, ctx = newGuestFlag(ctx)
cmd.GuestFlag.Register(ctx, f)
f.BoolVar(&cmd.overwrite, "f", false, "If set, the local destination file is clobbered")
}
func (cmd *download) Usage() string {
return "SOURCE DEST"
}
func (cmd *download) Description() string {
return `Copy SOURCE from the guest VM to DEST on the local system.
If DEST name is "-", source is written to stdout.
Examples:
govc guest.download -l user:pass -vm=my-vm /var/log/my.log ./local.log
govc guest.download -l user:pass -vm=my-vm /etc/motd -
tar -cf- foo/ | govc guest.run -d - tar -C /tmp -xf-
govc guest.run tar -C /tmp -cf- foo/ | tar -C /tmp -xf- # download directory`
}
func (cmd *download) Process(ctx context.Context) error {
if err := cmd.GuestFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *download) Run(ctx context.Context, f *flag.FlagSet) error {
if f.NArg() != 2 {
return flag.ErrHelp
}
src := f.Arg(0)
dst := f.Arg(1)
_, err := os.Stat(dst)
if err == nil && !cmd.overwrite {
return os.ErrExist
}
c, err := cmd.Toolbox()
if err != nil {
return err
}
s, n, err := c.Download(ctx, src)
if err != nil {
return err
}
if dst == "-" {
_, err = io.Copy(os.Stdout, s)
return err
}
var p progress.Sinker
if cmd.OutputFlag.TTY {
logger := cmd.ProgressLogger("Downloading... ")
p = logger
defer logger.Wait()
}
return c.ProcessManager.Client().WriteFile(ctx, dst, s, n, p, nil)
}

View file

@ -0,0 +1,47 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package guest
import (
"context"
"flag"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/vim25/types"
)
type FileAttrFlag struct {
types.GuestPosixFileAttributes
}
func newFileAttrFlag(ctx context.Context) (*FileAttrFlag, context.Context) {
return &FileAttrFlag{}, ctx
}
func (flag *FileAttrFlag) Register(ctx context.Context, f *flag.FlagSet) {
f.Var(flags.NewOptionalInt32(&flag.OwnerId), "uid", "User ID")
f.Var(flags.NewOptionalInt32(&flag.GroupId), "gid", "Group ID")
f.Int64Var(&flag.Permissions, "perm", 0, "File permissions")
}
func (flag *FileAttrFlag) Process(ctx context.Context) error {
return nil
}
func (flag *FileAttrFlag) Attr() types.BaseGuestFileAttributes {
return &flag.GuestPosixFileAttributes
}

View file

@ -0,0 +1,75 @@
/*
Copyright (c) 2014-2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package guest
import (
"context"
"flag"
"fmt"
"github.com/vmware/govmomi/govc/cli"
)
type getenv struct {
*GuestFlag
}
func init() {
cli.Register("guest.getenv", &getenv{})
}
func (cmd *getenv) Register(ctx context.Context, f *flag.FlagSet) {
cmd.GuestFlag, ctx = newGuestProcessFlag(ctx)
cmd.GuestFlag.Register(ctx, f)
}
func (cmd *getenv) Process(ctx context.Context) error {
if err := cmd.GuestFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *getenv) Usage() string {
return "[NAME]..."
}
func (cmd *getenv) Description() string {
return `Read NAME environment variables from VM.
Examples:
govc guest.getenv -vm $name
govc guest.getenv -vm $name HOME`
}
func (cmd *getenv) Run(ctx context.Context, f *flag.FlagSet) error {
m, err := cmd.ProcessManager()
if err != nil {
return err
}
vars, err := m.ReadEnvironmentVariable(ctx, cmd.Auth(), f.Args())
if err != nil {
return err
}
for _, v := range vars {
fmt.Printf("%s\n", v)
}
return nil
}

157
vendor/github.com/vmware/govmomi/govc/vm/guest/guest.go generated vendored Normal file
View file

@ -0,0 +1,157 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package guest
import (
"context"
"errors"
"flag"
"net/url"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/guest"
"github.com/vmware/govmomi/guest/toolbox"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
type GuestFlag struct {
*flags.ClientFlag
*flags.VirtualMachineFlag
*AuthFlag
}
func newGuestFlag(ctx context.Context) (*GuestFlag, context.Context) {
f := &GuestFlag{}
f.ClientFlag, ctx = flags.NewClientFlag(ctx)
f.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx)
f.AuthFlag, ctx = newAuthFlag(ctx)
return f, ctx
}
func newGuestProcessFlag(ctx context.Context) (*GuestFlag, context.Context) {
f, gctx := newGuestFlag(ctx)
f.proc = true
return f, gctx
}
func (flag *GuestFlag) Register(ctx context.Context, f *flag.FlagSet) {
flag.ClientFlag.Register(ctx, f)
flag.VirtualMachineFlag.Register(ctx, f)
flag.AuthFlag.Register(ctx, f)
}
func (flag *GuestFlag) Process(ctx context.Context) error {
if err := flag.ClientFlag.Process(ctx); err != nil {
return err
}
if err := flag.VirtualMachineFlag.Process(ctx); err != nil {
return err
}
if err := flag.AuthFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (flag *GuestFlag) Toolbox() (*toolbox.Client, error) {
pm, err := flag.ProcessManager()
if err != nil {
return nil, err
}
fm, err := flag.FileManager()
if err != nil {
return nil, err
}
vm, err := flag.VirtualMachine()
if err != nil {
return nil, err
}
family := ""
var props mo.VirtualMachine
err = vm.Properties(context.Background(), vm.Reference(), []string{"guest.guestFamily"}, &props)
if err != nil {
return nil, err
}
if props.Guest != nil {
family = props.Guest.GuestFamily
}
return &toolbox.Client{
ProcessManager: pm,
FileManager: fm,
Authentication: flag.Auth(),
GuestFamily: types.VirtualMachineGuestOsFamily(family),
}, nil
}
func (flag *GuestFlag) FileManager() (*guest.FileManager, error) {
ctx := context.TODO()
c, err := flag.Client()
if err != nil {
return nil, err
}
vm, err := flag.VirtualMachine()
if err != nil {
return nil, err
}
o := guest.NewOperationsManager(c, vm.Reference())
return o.FileManager(ctx)
}
func (flag *GuestFlag) ProcessManager() (*guest.ProcessManager, error) {
ctx := context.TODO()
c, err := flag.Client()
if err != nil {
return nil, err
}
vm, err := flag.VirtualMachine()
if err != nil {
return nil, err
}
o := guest.NewOperationsManager(c, vm.Reference())
return o.ProcessManager(ctx)
}
func (flag *GuestFlag) ParseURL(urlStr string) (*url.URL, error) {
c, err := flag.Client()
if err != nil {
return nil, err
}
return c.Client.ParseURL(urlStr)
}
func (flag *GuestFlag) VirtualMachine() (*object.VirtualMachine, error) {
vm, err := flag.VirtualMachineFlag.VirtualMachine()
if err != nil {
return nil, err
}
if vm == nil {
return nil, errors.New("no vm specified")
}
return vm, nil
}

70
vendor/github.com/vmware/govmomi/govc/vm/guest/kill.go generated vendored Normal file
View file

@ -0,0 +1,70 @@
/*
Copyright (c) 2014-2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package guest
import (
"context"
"flag"
"github.com/vmware/govmomi/govc/cli"
)
type kill struct {
*GuestFlag
pids pidSelector
}
func init() {
cli.Register("guest.kill", &kill{})
}
func (cmd *kill) Register(ctx context.Context, f *flag.FlagSet) {
cmd.GuestFlag, ctx = newGuestProcessFlag(ctx)
cmd.GuestFlag.Register(ctx, f)
f.Var(&cmd.pids, "p", "Process ID")
}
func (cmd *kill) Process(ctx context.Context) error {
if err := cmd.GuestFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *kill) Description() string {
return `Kill process ID on VM.
Examples:
govc guest.kill -vm $name -p 12345`
}
func (cmd *kill) Run(ctx context.Context, f *flag.FlagSet) error {
m, err := cmd.ProcessManager()
if err != nil {
return err
}
for _, pid := range cmd.pids {
if err := m.TerminateProcess(ctx, cmd.Auth(), pid); err != nil {
return err
}
}
return nil
}

128
vendor/github.com/vmware/govmomi/govc/vm/guest/ls.go generated vendored Normal file
View file

@ -0,0 +1,128 @@
/*
Copyright (c) 2014-2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package guest
import (
"context"
"flag"
"fmt"
"os"
"text/tabwriter"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/units"
"github.com/vmware/govmomi/vim25/types"
)
type ls struct {
*GuestFlag
simple bool
}
func init() {
cli.Register("guest.ls", &ls{})
}
func (cmd *ls) Register(ctx context.Context, f *flag.FlagSet) {
cmd.GuestFlag, ctx = newGuestFlag(ctx)
cmd.GuestFlag.Register(ctx, f)
f.BoolVar(&cmd.simple, "s", false, "Simple path only listing") // sadly we used '-l' for guest login
}
func (cmd *ls) Process(ctx context.Context) error {
if err := cmd.GuestFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *ls) Usage() string {
return "PATH"
}
func (cmd *ls) Description() string {
return `List PATH files in VM.
Examples:
govc guest.ls -vm $name /tmp`
}
func (cmd *ls) Run(ctx context.Context, f *flag.FlagSet) error {
m, err := cmd.FileManager()
if err != nil {
return err
}
var offset int32
tw := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0)
for {
info, err := m.ListFiles(ctx, cmd.Auth(), f.Arg(0), offset, 0, f.Arg(1))
if err != nil {
return err
}
for _, f := range info.Files {
if cmd.simple {
fmt.Fprintln(tw, f.Path)
continue
}
var kind byte
switch types.GuestFileType(f.Type) {
case types.GuestFileTypeDirectory:
kind = 'd'
if f.Size == 0 {
f.Size = 4092
}
case types.GuestFileTypeSymlink:
kind = 'l'
case types.GuestFileTypeFile:
kind = '-'
}
switch x := f.Attributes.(type) {
case *types.GuestPosixFileAttributes:
perm := os.FileMode(x.Permissions).Perm().String()[1:]
fmt.Fprintf(tw, "%c%s\t%d\t%d\t", kind, perm, *x.OwnerId, *x.GroupId)
}
attr := f.Attributes.GetGuestFileAttributes()
fmt.Fprintf(tw, "%s\t%s\t%s", units.FileSize(f.Size), attr.ModificationTime.Format("Jan 2 15:04 2006"), f.Path)
if attr.SymlinkTarget != "" {
fmt.Fprintf(tw, " -> %s", attr.SymlinkTarget)
}
fmt.Fprintln(tw)
}
err = tw.Flush()
if err != nil {
return err
}
if info.Remaining == 0 {
break
}
offset += int32(len(info.Files))
}
return nil
}

View file

@ -0,0 +1,83 @@
/*
Copyright (c) 2014-2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package guest
import (
"context"
"flag"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
)
type mkdir struct {
*GuestFlag
createParents bool
}
func init() {
cli.Register("guest.mkdir", &mkdir{})
}
func (cmd *mkdir) Register(ctx context.Context, f *flag.FlagSet) {
cmd.GuestFlag, ctx = newGuestFlag(ctx)
cmd.GuestFlag.Register(ctx, f)
f.BoolVar(&cmd.createParents, "p", false, "Create intermediate directories as needed")
}
func (cmd *mkdir) Process(ctx context.Context) error {
if err := cmd.GuestFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *mkdir) Usage() string {
return "PATH"
}
func (cmd *mkdir) Description() string {
return `Create directory PATH in VM.
Examples:
govc guest.mkdir -vm $name /tmp/logs
govc guest.mkdir -vm $name -p /tmp/logs/foo/bar`
}
func (cmd *mkdir) Run(ctx context.Context, f *flag.FlagSet) error {
m, err := cmd.FileManager()
if err != nil {
return err
}
err = m.MakeDirectory(ctx, cmd.Auth(), f.Arg(0), cmd.createParents)
// ignore EEXIST if -p flag is given
if err != nil && cmd.createParents {
if soap.IsSoapFault(err) {
soapFault := soap.ToSoapFault(err)
if _, ok := soapFault.VimFault().(types.FileAlreadyExists); ok {
return nil
}
}
}
return err
}

View file

@ -0,0 +1,86 @@
/*
Copyright (c) 2014-2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package guest
import (
"context"
"flag"
"fmt"
"github.com/vmware/govmomi/govc/cli"
)
type mktemp struct {
*GuestFlag
dir bool
path string
prefix string
suffix string
}
func init() {
cli.Register("guest.mktemp", &mktemp{})
}
func (cmd *mktemp) Register(ctx context.Context, f *flag.FlagSet) {
cmd.GuestFlag, ctx = newGuestFlag(ctx)
cmd.GuestFlag.Register(ctx, f)
f.BoolVar(&cmd.dir, "d", false, "Make a directory instead of a file")
f.StringVar(&cmd.path, "p", "", "If specified, create relative to this directory")
f.StringVar(&cmd.prefix, "t", "", "Prefix")
f.StringVar(&cmd.suffix, "s", "", "Suffix")
}
func (cmd *mktemp) Process(ctx context.Context) error {
if err := cmd.GuestFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *mktemp) Description() string {
return `Create a temporary file or directory in VM.
Examples:
govc guest.mktemp -vm $name
govc guest.mktemp -vm $name -d
govc guest.mktemp -vm $name -t myprefix
govc guest.mktemp -vm $name -p /var/tmp/$USER`
}
func (cmd *mktemp) Run(ctx context.Context, f *flag.FlagSet) error {
m, err := cmd.FileManager()
if err != nil {
return err
}
mk := m.CreateTemporaryFile
if cmd.dir {
mk = m.CreateTemporaryDirectory
}
name, err := mk(ctx, cmd.Auth(), cmd.prefix, cmd.suffix, cmd.path)
if err != nil {
return err
}
fmt.Println(name)
return nil
}

85
vendor/github.com/vmware/govmomi/govc/vm/guest/mv.go generated vendored Normal file
View file

@ -0,0 +1,85 @@
/*
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package guest
import (
"context"
"flag"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
)
type mv struct {
*GuestFlag
noclobber bool
}
func init() {
cli.Register("guest.mv", &mv{})
}
func (cmd *mv) Register(ctx context.Context, f *flag.FlagSet) {
cmd.GuestFlag, ctx = newGuestFlag(ctx)
cmd.GuestFlag.Register(ctx, f)
f.BoolVar(&cmd.noclobber, "n", false, "Do not overwrite an existing file")
}
func (cmd *mv) Process(ctx context.Context) error {
if err := cmd.GuestFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *mv) Usage() string {
return "SOURCE DEST"
}
func (cmd *mv) Description() string {
return `Move (rename) files in VM.
Examples:
govc guest.mv -vm $name /tmp/foo.sh /tmp/bar.sh
govc guest.mv -vm $name -n /tmp/baz.sh /tmp/bar.sh`
}
func (cmd *mv) Run(ctx context.Context, f *flag.FlagSet) error {
m, err := cmd.FileManager()
if err != nil {
return err
}
src := f.Arg(0)
dst := f.Arg(1)
err = m.MoveFile(ctx, cmd.Auth(), src, dst, !cmd.noclobber)
if err != nil {
if soap.IsSoapFault(err) {
soapFault := soap.ToSoapFault(err)
if _, ok := soapFault.VimFault().(types.NotAFile); ok {
err = m.MoveDirectory(ctx, cmd.Auth(), src, dst)
}
}
}
return err
}

199
vendor/github.com/vmware/govmomi/govc/vm/guest/ps.go generated vendored Normal file
View file

@ -0,0 +1,199 @@
/*
Copyright (c) 2014-2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package guest
import (
"context"
"flag"
"fmt"
"io"
"strconv"
"strings"
"text/tabwriter"
"time"
"github.com/vmware/govmomi/govc/cli"
"github.com/vmware/govmomi/govc/flags"
"github.com/vmware/govmomi/vim25/types"
)
type ps struct {
*flags.OutputFlag
*GuestFlag
every bool
exit bool
wait bool
pids pidSelector
uids uidSelector
}
type pidSelector []int64
func (s *pidSelector) String() string {
return fmt.Sprint(*s)
}
func (s *pidSelector) Set(value string) error {
v, err := strconv.ParseInt(value, 0, 64)
if err != nil {
return err
}
*s = append(*s, v)
return nil
}
type uidSelector map[string]bool
func (s uidSelector) String() string {
return ""
}
func (s uidSelector) Set(value string) error {
s[value] = true
return nil
}
func init() {
cli.Register("guest.ps", &ps{})
}
func (cmd *ps) Register(ctx context.Context, f *flag.FlagSet) {
cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
cmd.OutputFlag.Register(ctx, f)
cmd.GuestFlag, ctx = newGuestProcessFlag(ctx)
cmd.GuestFlag.Register(ctx, f)
cmd.uids = make(map[string]bool)
f.BoolVar(&cmd.every, "e", false, "Select all processes")
f.BoolVar(&cmd.exit, "x", false, "Output exit time and code")
f.BoolVar(&cmd.wait, "X", false, "Wait for process to exit")
f.Var(&cmd.pids, "p", "Select by process ID")
f.Var(&cmd.uids, "U", "Select by process UID")
}
func (cmd *ps) Process(ctx context.Context) error {
if err := cmd.OutputFlag.Process(ctx); err != nil {
return err
}
if err := cmd.GuestFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *ps) Description() string {
return `List processes in VM.
By default, unless the '-e', '-p' or '-U' flag is specified, only processes owned
by the '-l' flag user are displayed.
The '-x' and '-X' flags only apply to processes started by vmware-tools,
such as those started with the govc guest.start command.
Examples:
govc guest.ps -vm $name
govc guest.ps -vm $name -e
govc guest.ps -vm $name -p 12345
govc guest.ps -vm $name -U root`
}
func running(procs []types.GuestProcessInfo) bool {
for _, p := range procs {
if p.EndTime == nil {
return true
}
}
return false
}
func (cmd *ps) list(ctx context.Context) ([]types.GuestProcessInfo, error) {
m, err := cmd.ProcessManager()
if err != nil {
return nil, err
}
auth := cmd.Auth()
for {
procs, err := m.ListProcesses(ctx, auth, cmd.pids)
if err != nil {
return nil, err
}
if cmd.wait && running(procs) {
<-time.After(time.Second)
continue
}
return procs, nil
}
}
func (cmd *ps) Run(ctx context.Context, f *flag.FlagSet) error {
procs, err := cmd.list(ctx)
if err != nil {
return err
}
r := &psResult{cmd, procs}
return cmd.WriteResult(r)
}
type psResult struct {
cmd *ps
ProcessInfo []types.GuestProcessInfo
}
func (r *psResult) Write(w io.Writer) error {
tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0)
fmt.Fprintf(tw, "%s\t%s\t%s", "UID", "PID", "STIME")
if r.cmd.exit {
fmt.Fprintf(tw, "\t%s\t%s", "XTIME", "XCODE")
}
fmt.Fprint(tw, "\tCMD\n")
if len(r.cmd.pids) != 0 {
r.cmd.every = true
}
if !r.cmd.every && len(r.cmd.uids) == 0 {
r.cmd.uids[r.cmd.auth.Username] = true
}
for _, p := range r.ProcessInfo {
if r.cmd.every || r.cmd.uids[p.Owner] {
fmt.Fprintf(tw, "%s\t%d\t%s", p.Owner, p.Pid, p.StartTime.Format("15:04"))
if r.cmd.exit {
etime := "-"
ecode := "-"
if p.EndTime != nil {
etime = p.EndTime.Format("15:04")
ecode = strconv.Itoa(int(p.ExitCode))
}
fmt.Fprintf(tw, "\t%s\t%s", etime, ecode)
}
fmt.Fprintf(tw, "\t%s\n", strings.TrimSpace(p.CmdLine))
}
}
return tw.Flush()
}

64
vendor/github.com/vmware/govmomi/govc/vm/guest/rm.go generated vendored Normal file
View file

@ -0,0 +1,64 @@
/*
Copyright (c) 2014-2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package guest
import (
"context"
"flag"
"github.com/vmware/govmomi/govc/cli"
)
type rm struct {
*GuestFlag
}
func init() {
cli.Register("guest.rm", &rm{})
}
func (cmd *rm) Register(ctx context.Context, f *flag.FlagSet) {
cmd.GuestFlag, ctx = newGuestFlag(ctx)
cmd.GuestFlag.Register(ctx, f)
}
func (cmd *rm) Process(ctx context.Context) error {
if err := cmd.GuestFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *rm) Usage() string {
return "PATH"
}
func (cmd *rm) Description() string {
return `Remove file PATH in VM.
Examples:
govc guest.rm -vm $name /tmp/foo.log`
}
func (cmd *rm) Run(ctx context.Context, f *flag.FlagSet) error {
m, err := cmd.FileManager()
if err != nil {
return err
}
return m.DeleteFile(ctx, cmd.Auth(), f.Arg(0))
}

View file

@ -0,0 +1,69 @@
/*
Copyright (c) 2014-2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package guest
import (
"context"
"flag"
"github.com/vmware/govmomi/govc/cli"
)
type rmdir struct {
*GuestFlag
recursive bool
}
func init() {
cli.Register("guest.rmdir", &rmdir{})
}
func (cmd *rmdir) Register(ctx context.Context, f *flag.FlagSet) {
cmd.GuestFlag, ctx = newGuestFlag(ctx)
cmd.GuestFlag.Register(ctx, f)
f.BoolVar(&cmd.recursive, "r", false, "Recursive removal")
}
func (cmd *rmdir) Process(ctx context.Context) error {
if err := cmd.GuestFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *rmdir) Usage() string {
return "PATH"
}
func (cmd *rmdir) Description() string {
return `Remove directory PATH in VM.
Examples:
govc guest.rmdir -vm $name /tmp/empty-dir
govc guest.rmdir -vm $name -r /tmp/non-empty-dir`
}
func (cmd *rmdir) Run(ctx context.Context, f *flag.FlagSet) error {
m, err := cmd.FileManager()
if err != nil {
return err
}
return m.DeleteDirectory(ctx, cmd.Auth(), f.Arg(0), cmd.recursive)
}

Some files were not shown because too many files have changed in this diff Show more