go.mod: update github.com/vmware/govmomi to v0.48.0

Needs manual change of import paths.
This commit is contained in:
Achilleas Koutsou 2025-01-31 18:26:22 +01:00 committed by Sanne Raymaekers
parent 3a6bea380e
commit bec893e37c
170 changed files with 7474 additions and 1604 deletions

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

@ -0,0 +1,249 @@
/*
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"
"os"
"path/filepath"
"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: %[1]s <COMMAND> [COMMON OPTIONS] [PATH]...
govmomi is a Go library for interacting with VMware vSphere APIs (ESXi and/or
vCenter Server).
It is licensed under the Apache License, Version 2.0
%[1]s is the CLI for govmomi.
The available commands are listed below. A detailed description of each
command can be displayed with "govc <COMMAND> -h". The description of all
commands can be also found at https://github.com/vmware/govmomi/blob/main/govc/USAGE.md.
Examples:
show usage of a command: govc <COMMAND> -h
show toplevel structure: govc ls
show datacenter summary: govc datacenter.info
show all VMs: govc find -type m
upload a ISO file: govc datastore.upload -ds datastore1 ./config.iso vm-name/config.iso
Common options:
-h Show this message
-cert= Certificate [GOVC_CERTIFICATE]
-debug=false Store debug logs [GOVC_DEBUG]
-trace=false Write SOAP/REST traffic to stderr
-verbose=false Write request/response data to stderr
-dump=false Enable output dump
-json=false Enable JSON output
-xml=false Enable XML output
-k=false Skip verification of server certificate [GOVC_INSECURE]
-key= Private key [GOVC_PRIVATE_KEY]
-persist-session=true Persist session to disk [GOVC_PERSIST_SESSION]
-tls-ca-certs= TLS CA certificates file [GOVC_TLS_CA_CERTS]
-tls-known-hosts= TLS known hosts file [GOVC_TLS_KNOWN_HOSTS]
-u= ESX or vCenter URL [GOVC_URL]
-vim-namespace=urn:vim25 Vim namespace [GOVC_VIM_NAMESPACE]
-vim-version=6.0 Vim version [GOVC_VIM_VERSION]
-dc= Datacenter [GOVC_DATACENTER]
-host.dns= Find host by FQDN
-host.ip= Find host by IP address
-host.ipath= Find host by inventory path
-host.uuid= Find host by UUID
-vm.dns= Find VM by FQDN
-vm.ip= Find VM by IP address
-vm.ipath= Find VM by inventory path
-vm.path= Find VM by path to .vmx file
-vm.uuid= Find VM by UUID
Available commands:
`, filepath.Base(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) {
arg = strings.TrimLeft(arg, "-")
if arg == "h" || arg == "help" {
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(io.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
}

152
vendor/github.com/vmware/govmomi/cli/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/cli"
"github.com/vmware/govmomi/cli/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,349 @@
/*
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/cli"
"github.com/vmware/govmomi/cli/flags"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/units"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
)
const (
sectorSize = 512 // Sector size in bytes
startSector = 2048 // Start sector (typically fixed)
)
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
Size units.ByteSize
// 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")
f.Var(&cmd.Size, "size", "Size of new disk. Default is to use entire disk")
// 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 # use entire disk
govc datastore.create -type vmfs -name vmfsDatastore -disk=mpx.vmhba0:C0:T0:L0 -size 20G cluster1 # use 20G of disk
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.Size > 0 {
endSector := CalculateSectors(int64(cmd.Size))
// set values for Sectors
spec.Partition.Partition[0].StartSector = startSector
spec.Partition.Partition[0].EndSector = endSector
}
if cmd.Version != nil {
spec.Vmfs.MajorVersion = *cmd.Version
}
_, err = ds.CreateVmfsDatastore(ctx, spec)
if err != nil {
return err
}
}
return nil
}
// CalculateSectors calculates the start and end sectors based on the given size.
func CalculateSectors(sizeInBytes int64) (endSector int64) {
totalSectors := sizeInBytes / sectorSize
endSector = startSector + totalSectors - 1
return endSector
}
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,137 @@
// © Broadcom. All Rights Reserved.
// The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
// SPDX-License-Identifier: Apache-2.0
package datastore
import (
"context"
"errors"
"flag"
"fmt"
"io"
"os"
"path"
"github.com/vmware/govmomi/cli"
"github.com/vmware/govmomi/cli/flags"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/ovf"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vmdk"
)
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
govc datastore.download -json vm-name/vm-name.vmdk - | jq .ddb
ovf=$(govc library.info -l -L vmservice/photon-5.0/*.ovf)
govc datastore.download -json "$ovf" - | jq -r .diskSection.disk[].capacity`
}
func (cmd *download) Run(ctx context.Context, f *flag.FlagSet) error {
args := f.Args()
if len(args) != 2 {
return errors.New("invalid arguments")
}
src := args[0]
dst := args[1]
var dp object.DatastorePath
if dp.FromString(src) {
// e.g. `govc library.info -l -L ...`
cmd.DatastoreFlag.Name = dp.Datastore
src = dp.Path
}
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
if dst == "-" {
f, _, err := ds.Download(ctx, src, &p)
if err != nil {
return err
}
if cmd.DatastoreFlag.All() {
switch path.Ext(src) {
case ".vmdk":
data, err := vmdk.ParseDescriptor(f)
if err != nil {
return err
}
return cmd.DatastoreFlag.WriteResult(data)
case ".ovf":
data, err := ovf.Unmarshal(f)
if err != nil {
return err
}
return cmd.DatastoreFlag.WriteResult(data)
}
}
_, 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/cli/datastore/info.go generated vendored Normal file
View file

@ -0,0 +1,213 @@
/*
Copyright (c) 2015-2024 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/cli"
"github.com/vmware/govmomi/cli/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 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 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 `json:"datastores"`
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()
}

283
vendor/github.com/vmware/govmomi/cli/datastore/ls.go generated vendored Normal file
View file

@ -0,0 +1,283 @@
/*
Copyright (c) 2014-2024 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/cli"
"github.com/vmware/govmomi/cli/flags"
"github.com/vmware/govmomi/fault"
"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
human 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.human, "H", true, "Display human friendly name") // vSAN top-level dirs are ID by default
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 {
return fault.Is(err, &types.InvalidArgument{})
}
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 {
info := f.GetFileInfo()
if info.Path[0] == '.' && !o.cmd.all {
continue
}
if o.cmd.human {
if info.FriendlyName != "" {
info.Path = info.FriendlyName
}
}
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
}

115
vendor/github.com/vmware/govmomi/cli/datastore/mkdir.go generated vendored Normal file
View file

@ -0,0 +1,115 @@
/*
Copyright (c) 2014-2024 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/cli"
"github.com/vmware/govmomi/cli/flags"
"github.com/vmware/govmomi/fault"
"github.com/vmware/govmomi/object"
"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 fault.Is(err, &types.FileAlreadyExists{}) {
return nil
}
}
}
return err
}

77
vendor/github.com/vmware/govmomi/cli/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/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/cli"
"github.com/vmware/govmomi/cli/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/cli/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/cli"
"github.com/vmware/govmomi/cli/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/cli/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/cli"
"github.com/vmware/govmomi/cli/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/cli"
"github.com/vmware/govmomi/cli/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)
}

163
vendor/github.com/vmware/govmomi/cli/esx/command.go generated vendored Normal file
View file

@ -0,0 +1,163 @@
/*
Copyright (c) 2014-2024 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 esx
import (
"flag"
"fmt"
"strings"
"github.com/vmware/govmomi/internal"
)
type Command struct {
name []string
args []string
}
type CommandInfoItem struct {
Name string `xml:"name" json:"name"`
DisplayName string `xml:"displayName" json:"displayName"`
Help string `xml:"help" json:"help"`
}
type CommandInfoParam struct {
CommandInfoItem
Aliases []string `xml:"aliases" json:"aliases"`
Flag bool `xml:"flag" json:"flag"`
}
type CommandInfoHint struct {
Key string `xml:"key" json:"key"`
Value string `xml:"value" json:"value"`
}
type CommandInfoHints []CommandInfoHint
type CommandInfoMethod struct {
CommandInfoItem
Param []CommandInfoParam `xml:"param" json:"param"`
Hints CommandInfoHints `xml:"hints" json:"hints"`
}
type CommandInfo struct {
CommandInfoItem
Method []CommandInfoMethod `xml:"method" json:"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], "-")
}
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
}
// 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) {
fs := flag.NewFlagSet(strings.Join(c.name, " "), flag.ExitOnError)
vals := make([]stringList, len(params))
for i, p := range params {
v := &vals[i]
for _, a := range p.Aliases {
a = strings.TrimPrefix(a[1:], "-")
fs.Var(v, a, p.Help)
}
}
err := fs.Parse(c.args)
if err != nil {
return nil, err
}
args := []internal.ReflectManagedMethodExecuterSoapArgument{}
for i, p := range params {
if len(vals[i]) != 0 {
args = append(args, c.Argument(p.Name, vals[i]...))
}
}
return args, nil
}
func (c *Command) Argument(name string, args ...string) internal.ReflectManagedMethodExecuterSoapArgument {
var vars []string
for _, arg := range args {
vars = append(vars, fmt.Sprintf("<%s>%s</%s>", name, arg, name))
}
return internal.ReflectManagedMethodExecuterSoapArgument{
Name: name,
Val: strings.Join(vars, ""),
}
}
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
}

209
vendor/github.com/vmware/govmomi/cli/esx/executor.go generated vendored Normal file
View file

@ -0,0 +1,209 @@
/*
Copyright (c) 2014-2024 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 esx
import (
"context"
"fmt"
"github.com/vmware/govmomi/internal"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
"github.com/vmware/govmomi/vim25/xml"
)
type Fault struct {
Message string `json:"message"`
Detail string `json:"detail"`
}
func (f Fault) Error() string {
return f.Message
}
func (f Fault) MessageDetail() string {
if f.Detail != "" {
return fmt.Sprintf("%s %s", f.Message, f.Detail)
}
return f.Message
}
type Executor struct {
c *vim25.Client
host mo.Reference
mme *internal.ReflectManagedMethodExecuter
dtm *internal.InternalDynamicTypeManager
info map[string]*CommandInfo
Trace func(*internal.ExecuteSoapRequest, *internal.ExecuteSoapResponse)
}
func NewExecutor(ctx context.Context, c *vim25.Client, host mo.Reference) (*Executor, error) {
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) Client() *vim25.Client {
return e.c
}
func (e *Executor) DynamicTypeManager() types.ManagedObjectReference {
return e.dtm.ManagedObjectReference
}
func (e *Executor) CommandInfo(ctx context.Context, ns string) (*CommandInfo, error) {
info, ok := e.info[ns]
if ok {
return info, nil
}
req := internal.ExecuteSoapRequest{
Moid: "ha-dynamic-type-manager-local-cli-cliinfo",
Method: "vim.CLIInfo.FetchCLIInfo",
Argument: []internal.ReflectManagedMethodExecuterSoapArgument{
NewCommand(nil).Argument("typeName", "vim.EsxCLI."+ns),
},
}
info = new(CommandInfo)
if err := e.Execute(ctx, &req, info); err != nil {
return nil, err
}
e.info[ns] = info
return info, nil
}
func (e *Executor) CommandInfoMethod(ctx context.Context, c *Command) (*CommandInfoMethod, error) {
ns := c.Namespace()
info, err := e.CommandInfo(ctx, ns)
if err != nil {
return nil, err
}
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(ctx context.Context, args []string) (*internal.ExecuteSoapRequest, *CommandInfoMethod, error) {
c := NewCommand(args)
info, err := e.CommandInfoMethod(ctx, 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(ctx context.Context, req *internal.ExecuteSoapRequest, res interface{}) error {
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 e.Trace != nil {
e.Trace(req, x)
}
if x.Returnval != nil {
if x.Returnval.Fault != nil {
return &Fault{
x.Returnval.Fault.FaultMsg,
x.Returnval.Fault.FaultDetail,
}
}
if err := xml.Unmarshal([]byte(x.Returnval.Response), res); err != nil {
return err
}
}
return nil
}
func (e *Executor) Run(ctx context.Context, args []string) (*Response, error) {
req, info, err := e.NewRequest(ctx, args)
if err != nil {
return nil, err
}
res := &Response{
Info: info,
}
if err := e.Execute(ctx, req, res); err != nil {
return nil, err
}
return res, nil
}

View file

@ -0,0 +1,43 @@
/*
Copyright (c) 2015-2024 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 esx
import "context"
type FirewallInfo struct {
Loaded bool `json:"loaded"`
Enabled bool `json:"enabled"`
DefaultAction string `json:"defaultAction"`
}
// 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 (x *Executor) GetFirewallInfo(ctx context.Context) (*FirewallInfo, error) {
res, err := x.Run(ctx, []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
}

116
vendor/github.com/vmware/govmomi/cli/esx/guest_info.go generated vendored Normal file
View file

@ -0,0 +1,116 @@
/*
Copyright (c) 2014-2024 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 esx
import (
"context"
"strings"
"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(ctx context.Context, ref *types.ManagedObjectReference) (*hostInfo, error) {
// cache exectuor and uuid -> worldid map
if h, ok := g.hosts[ref.Value]; ok {
return h, nil
}
e, err := NewExecutor(ctx, g.c, ref)
if err != nil {
return nil, err
}
res, err := e.Run(ctx, []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(ctx context.Context, vm mo.Reference) (string, error) {
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(ctx, 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(ctx, []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
}

188
vendor/github.com/vmware/govmomi/cli/esx/response.go generated vendored Normal file
View file

@ -0,0 +1,188 @@
/*
Copyright (c) 2014-2024 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 esx
import (
"io"
"github.com/vmware/govmomi/vim25/xml"
)
type Values map[string][]string
type Response struct {
Info *CommandInfoMethod `json:"info"`
Values []Values `json:"values"`
String string `json:"string"`
Kind string `json:"-"`
}
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 (s Values) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
tokens := []xml.Token{start}
for key, val := range s {
field := xml.StartElement{Name: xml.Name{Local: key}}
for _, v := range val {
tokens = append(tokens, field, xml.CharData(v), field.End())
}
}
tokens = append(tokens, start.End())
for _, t := range tokens {
err := e.EncodeToken(t)
if err != nil {
return err
}
}
return nil
}
func (v Values) Value(name string) string {
if val, ok := v[name]; ok {
if len(val) != 0 {
return val[0]
}
}
return ""
}
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", "xsd:boolean", "xsd:long":
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)
}
}
}
}
func (r *Response) MarshalXML(e *xml.Encoder, _ xml.StartElement) error {
kind := "ArrayOfDataObject"
native := r.String != ""
if native {
kind = "xsd:" + r.Kind
}
start := xml.StartElement{
Name: xml.Name{
Space: "urn:vim25",
Local: "obj",
},
Attr: []xml.Attr{
{
Name: xml.Name{Local: "xmlns:xsd"},
Value: "http://www.w3.org/2001/XMLSchema",
},
{
Name: xml.Name{Local: "xmlns:xsi"},
Value: "http://www.w3.org/2001/XMLSchema-instance",
},
{
Name: xml.Name{Local: "xsi:type"},
Value: kind,
},
},
}
if err := e.EncodeToken(start); err != nil {
return err
}
var err error
if native {
err = e.EncodeToken(xml.CharData(r.String))
} else {
obj := xml.StartElement{
Name: xml.Name{Local: "DataObject"},
Attr: []xml.Attr{{
Name: xml.Name{Local: "xsi:type"},
Value: r.Kind,
}},
}
err = e.EncodeElement(r.Values, obj)
}
if err != nil {
return err
}
return e.EncodeToken(start.End())
}

499
vendor/github.com/vmware/govmomi/cli/flags/client.go generated vendored Normal file
View file

@ -0,0 +1,499 @@
/*
Copyright (c) 2014-2023 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/cns"
"github.com/vmware/govmomi/pbm"
"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"
)
const cDescr = "ESX or vCenter URL"
type ClientFlag struct {
common
*DebugFlag
username string
password string
cert string
key string
persist bool
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)
}
{
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", strings.TrimPrefix(BuildVersion, "v"))
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
}
}
sc.UseJSON(os.Getenv("GOVC_VI_JSON") != "")
return nil
}
func (flag *ClientFlag) SetRootCAs(c *soap.Client) error {
if flag.tlsCaCerts != "" {
return c.SetRootCAs(flag.tlsCaCerts)
}
return nil
}
func (flag *ClientFlag) RoundTripper(c *soap.Client) soap.RoundTripper {
// Retry twice when a temporary I/O error occurs.
// This means a maximum of 3 attempts.
rt := vim25.Retry(c, vim25.RetryTemporaryNetworkError, 3)
switch {
case flag.dump:
rt = &dump{roundTripper: rt}
case flag.verbose:
rt = &verbose{roundTripper: rt}
}
return rt
}
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
}
if flag.vimVersion == "" || flag.vimVersion == "-" {
err = c.UseServiceVersion()
if err != nil {
return nil, err
}
}
c.RoundTripper = flag.RoundTripper(c.Client)
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) PbmClient() (*pbm.Client, error) {
vc, err := flag.Client()
if err != nil {
return nil, err
}
c, err := pbm.NewClient(context.Background(), vc)
if err != nil {
return nil, err
}
c.RoundTripper = flag.RoundTripper(c.Client)
return c, nil
}
func (flag *ClientFlag) CnsClient() (*cns.Client, error) {
vc, err := flag.Client()
if err != nil {
return nil, err
}
c, err := cns.NewClient(context.Background(), vc)
if err != nil {
return nil, err
}
c.RoundTripper = flag.RoundTripper(c.Client)
return c, 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/cli/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/cli/flags/common.go generated vendored Normal file
View file

@ -0,0 +1,38 @@
/*
Copyright (c) 2015-2023 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,219 @@
/*
Copyright (c) 2014-2024 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 match %q: %s (unique inventory path required)", 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 {
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)
}
if len(elements) > 1 && !strings.Contains(arg, "/") {
return nil, fmt.Errorf("%q must be qualified with a path", arg)
}
for _, e := range elements {
refs = append(refs, e.Object.Reference())
}
}
return refs, nil
}

209
vendor/github.com/vmware/govmomi/cli/flags/datastore.go generated vendored Normal file
View file

@ -0,0 +1,209 @@
/*
Copyright (c) 2014-2024 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"
"os"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vapi/library"
"github.com/vmware/govmomi/vapi/library/finder"
"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 (flag *DatastoreFlag) IsSet() bool {
return flag.Name != ""
}
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)
}
func (f *DatastoreFlag) libraryPath(ctx context.Context, p string) (string, error) {
vc, err := f.Client()
if err != nil {
return "", err
}
rc, err := f.RestClient()
if err != nil {
return "", err
}
m := library.NewManager(rc)
r, err := finder.NewFinder(m).Find(ctx, p)
if err != nil {
return "", err
}
if len(r) != 1 {
return "", fmt.Errorf("%s: %d found", p, len(r))
}
return finder.NewPathFinder(m, vc).Path(ctx, r[0])
}
// FileBacking converts the given file path for use as VirtualDeviceFileBackingInfo.FileName.
func (f *DatastoreFlag) FileBacking(ctx context.Context, file string, stat bool) (string, error) {
u, err := url.Parse(file)
if err != nil {
return "", err
}
switch u.Scheme {
case "library":
return f.libraryPath(ctx, u.Path)
case "ds":
// datastore url, e.g. ds:///vmfs/volumes/$uuid/...
return file, nil
}
var p object.DatastorePath
if p.FromString(file) {
// datastore is specified
return file, nil
}
if stat {
// Verify ISO exists
if _, err := f.Stat(ctx, file); err != nil {
return "", err
}
}
return f.DatastorePath(file)
}

474
vendor/github.com/vmware/govmomi/cli/flags/debug.go generated vendored Normal file
View file

@ -0,0 +1,474 @@
/*
Copyright (c) 2014-2024 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 (
"bufio"
"context"
"flag"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"reflect"
"strings"
"sync"
"text/tabwriter"
"time"
"github.com/dougm/pretty"
"github.com/vmware/govmomi/vim25/debug"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
)
type cmdFormat struct {
path string
err error
args []string
}
func (c *cmdFormat) lookPath(file string, args ...string) {
c.args = args
c.path, c.err = exec.LookPath(file)
}
func (c *cmdFormat) cmd() (*exec.Cmd, error) {
if c.err != nil {
return nil, c.err
}
return exec.Command(c.path, c.args...), nil
}
type DebugFlag struct {
common
enable bool
trace bool
verbose bool
dump bool
xml cmdFormat
json cmdFormat
}
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) Verbose() bool {
return flag.verbose
}
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)
f.BoolVar(&flag.trace, "trace", false, "Write SOAP/REST traffic to stderr")
f.BoolVar(&flag.verbose, "verbose", false, "Write request/response data to stderr")
})
}
type cmdFormatCloser struct {
rc io.Closer
in io.Closer
cmd *exec.Cmd
wg *sync.WaitGroup
}
func (c *cmdFormatCloser) Close() error {
_ = c.rc.Close()
_ = c.in.Close()
c.wg.Wait()
return c.cmd.Wait()
}
func (flag *DebugFlag) newFormatReader(rc io.ReadCloser, w io.Writer, ext string) (io.ReadCloser, error) {
var err error
var cmd *exec.Cmd
switch ext {
case "json":
cmd, err = flag.json.cmd()
if err != nil {
return nil, err
}
case "xml":
cmd, err = flag.xml.cmd()
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unsupported type %s", ext)
}
cmd.Stderr = os.Stderr
stdin, err := cmd.StdinPipe()
if err != nil {
return nil, err
}
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}
err = cmd.Start()
if err != nil {
return nil, err
}
var wg sync.WaitGroup
wg.Add(1)
go func() {
_, _ = io.Copy(w, stdout)
wg.Done()
}()
return debug.ReadCloser{
Reader: io.TeeReader(rc, stdin),
Closer: &cmdFormatCloser{rc, stdin, cmd, &wg},
}, nil
}
func (flag *DebugFlag) debugTrace(rc io.ReadCloser, w io.Writer, ext string) io.ReadCloser {
fr, err := flag.newFormatReader(rc, w, ext)
if err != nil {
return debug.NewTeeReader(rc, w)
}
return fr
}
func (flag *DebugFlag) Process(ctx context.Context) error {
// Base path for storing debug logs.
r := os.Getenv("GOVC_DEBUG_PATH")
if flag.trace {
if flag.verbose {
flag.dump = true // output req/res as Go code
return nil
}
r = "-"
flag.enable = true
if os.Getenv("GOVC_DEBUG_FORMAT") != "false" {
debugXML := os.Getenv("GOVC_DEBUG_XML")
if debugXML == "" {
debugXML = "xmlstarlet"
}
flag.xml.lookPath(debugXML, "fo")
debugJSON := os.Getenv("GOVC_DEBUG_JSON")
if debugJSON == "" {
debugJSON = "jq"
}
flag.json.lookPath(debugJSON, ".")
soap.Trace = flag.debugTrace
}
}
if !flag.enable {
return nil
}
return flag.ProcessOnce(func() error {
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
})
}
type dump struct {
roundTripper soap.RoundTripper
}
func (d *dump) RoundTrip(ctx context.Context, req, res soap.HasFault) error {
vreq := reflect.ValueOf(req).Elem().FieldByName("Req").Elem()
pretty.Fprintf(os.Stderr, "%# v\n", vreq.Interface())
err := d.roundTripper.RoundTrip(ctx, req, res)
if err != nil {
if fault := res.Fault(); fault != nil {
pretty.Fprintf(os.Stderr, "%# v\n", fault)
}
return err
}
vres := reflect.ValueOf(res).Elem().FieldByName("Res").Elem()
pretty.Fprintf(os.Stderr, "%# v\n", vres.Interface())
return nil
}
type verbose struct {
roundTripper soap.RoundTripper
}
func (*verbose) mor(ref types.ManagedObjectReference) string {
if strings.HasPrefix(ref.Value, "session") {
ref.Value = "session[...]"
return ref.String()
}
return ref.Value
}
func (*verbose) str(val reflect.Value) string {
if !val.IsValid() {
return ""
}
switch val.Kind() {
case reflect.Ptr, reflect.Interface:
if val.IsNil() {
return "nil"
}
}
p := ""
switch pval := val.Interface().(type) {
case fmt.Stringer:
p = pval.String()
case string:
if len(pval) > 45 {
pval = pval[:42] + "..."
}
p = fmt.Sprintf("%s", pval)
case []string:
p = fmt.Sprintf("%v", pval)
case []types.ManagedObjectReference:
refs := make([]string, len(pval))
for i := range pval {
refs[i] = pval[i].Value
}
p = fmt.Sprintf("%v", refs)
default:
return ""
}
return p
}
func (v *verbose) value(val types.AnyType) string {
rval := reflect.ValueOf(val)
if rval.Kind() == reflect.Ptr && !rval.IsNil() {
rval = rval.Elem()
}
if rval.Kind() == reflect.Struct {
if strings.HasPrefix(rval.Type().Name(), "ArrayOf") {
rval = rval.Field(0)
val = rval.Interface()
}
}
s := v.str(rval)
if s != "" {
return s
}
return v.prettyPrint(val)
}
func (v *verbose) propertyValue(obj types.ManagedObjectReference, name string, pval types.AnyType) string {
val := v.value(pval)
if obj.Type != "Task" && !strings.HasPrefix(obj.Value, "session") {
if len(val) > 512 {
val = fmt.Sprintf("`govc collect -dump %s %s`", obj, name)
}
}
return fmt.Sprintf("%s\t%s:\t%s", v.mor(obj), name, val)
}
func (v *verbose) missingSet(o types.ManagedObjectReference, m []types.MissingProperty) []string {
var s []string
for _, p := range m {
s = append(s, fmt.Sprintf("%s\t%s:\t%s", v.mor(o), p.Path, v.prettyPrint(p.Fault.Fault)))
}
return s
}
func (v *verbose) updateSet(u *types.UpdateSet) []string {
var s []string
if u == nil {
return s
}
for _, f := range u.FilterSet {
for _, o := range f.ObjectSet {
for _, c := range o.ChangeSet {
s = append(s, v.propertyValue(o.Obj, c.Name, c.Val))
}
s = append(s, v.missingSet(o.Obj, o.MissingSet)...)
}
}
return s
}
func (v *verbose) objectContent(content []types.ObjectContent) []string {
var s []string
for _, o := range content {
for _, p := range o.PropSet {
s = append(s, v.propertyValue(o.Obj, p.Name, p.Val))
}
s = append(s, v.missingSet(o.Obj, o.MissingSet)...)
}
return s
}
func (v *verbose) prettyPrint(val interface{}) string {
p := pretty.Sprintf("%# v\n", val)
var res []string
scanner := bufio.NewScanner(strings.NewReader(p))
for scanner.Scan() {
line := scanner.Text()
if strings.Contains(line, "nil,") || strings.Contains(line, "(nil),") {
continue // nil pointer field
}
if strings.Contains(line, `"",`) {
continue // empty string field
}
if strings.Contains(line, `{},`) {
continue // empty embedded struct
}
if strings.Contains(line, "[context]") {
continue // noisy base64 encoded backtrace
}
res = append(res, line)
}
return strings.Join(res, "\n")
}
func (v *verbose) table(vals []string) {
tw := tabwriter.NewWriter(os.Stderr, 2, 0, 1, ' ', 0)
for _, val := range vals {
fmt.Fprintf(tw, "...%s\n", val)
}
tw.Flush()
}
func (v *verbose) RoundTrip(ctx context.Context, req, res soap.HasFault) error {
vreq := reflect.ValueOf(req).Elem().FieldByName("Req").Elem()
param := []string{""}
switch f := vreq.Field(0).Interface().(type) {
case types.ManagedObjectReference:
param[0] = v.mor(f)
default:
param[0] = fmt.Sprintf("%v", f)
}
for i := 1; i < vreq.NumField(); i++ {
val := vreq.Field(i)
if val.Kind() == reflect.Interface {
val = val.Elem()
}
p := v.str(val)
if p == "" {
switch val.Kind() {
case reflect.Ptr, reflect.Slice, reflect.Struct:
p = val.Type().String()
default:
p = fmt.Sprintf("%v", val.Interface())
}
}
param = append(param, p)
}
fmt.Fprintf(os.Stderr, "%s(%s)...\n", vreq.Type().Name(), strings.Join(param, ", "))
err := v.roundTripper.RoundTrip(ctx, req, res)
if err != nil {
if fault := res.Fault(); fault != nil {
fmt.Fprintln(os.Stderr, v.prettyPrint(fault))
} else {
fmt.Fprintf(os.Stderr, "...%s\n", err)
}
return err
}
vres := reflect.ValueOf(res).Elem().FieldByName("Res").Elem()
ret := vres.FieldByName("Returnval")
var s interface{} = "void"
if ret.IsValid() {
switch x := ret.Interface().(type) {
case types.ManagedObjectReference:
s = v.mor(x)
case *types.UpdateSet:
s = v.updateSet(x)
case []types.ObjectContent:
s = v.objectContent(x)
case fmt.Stringer:
s = x.String()
default:
s = v.value(x)
}
}
if vals, ok := s.([]string); ok {
v.table(vals)
} else {
fmt.Fprintf(os.Stderr, "...%s\n", s)
}
fmt.Fprintln(os.Stderr)
return err
}

31
vendor/github.com/vmware/govmomi/cli/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
}

94
vendor/github.com/vmware/govmomi/cli/flags/env.go generated vendored Normal file
View file

@ -0,0 +1,94 @@
/*
Copyright (c) 2023-2023 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"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/mo"
)
type EnvBrowser struct {
*ClusterFlag
*HostSystemFlag
*VirtualMachineFlag
}
func (cmd *EnvBrowser) Register(ctx context.Context, f *flag.FlagSet) {
cmd.ClusterFlag, ctx = NewClusterFlag(ctx)
cmd.ClusterFlag.Register(ctx, f)
cmd.HostSystemFlag, ctx = NewHostSystemFlag(ctx)
cmd.HostSystemFlag.Register(ctx, f)
cmd.VirtualMachineFlag, ctx = NewVirtualMachineFlag(ctx)
cmd.VirtualMachineFlag.Register(ctx, f)
}
func (cmd *EnvBrowser) Process(ctx context.Context) error {
if err := cmd.ClusterFlag.Process(ctx); err != nil {
return err
}
if err := cmd.HostSystemFlag.Process(ctx); err != nil {
return err
}
return cmd.VirtualMachineFlag.Process(ctx)
}
func (cmd *EnvBrowser) Browser(ctx context.Context) (*object.EnvironmentBrowser, error) {
c, err := cmd.VirtualMachineFlag.Client()
if err != nil {
return nil, err
}
vm, err := cmd.VirtualMachine()
if err != nil {
return nil, err
}
if vm != nil {
return vm.EnvironmentBrowser(ctx)
}
host, err := cmd.HostSystemIfSpecified()
if err != nil {
return nil, err
}
if host != nil {
var h mo.HostSystem
err = host.Properties(ctx, host.Reference(), []string{"parent"}, &h)
if err != nil {
return nil, err
}
return object.NewComputeResource(c, *h.Parent).EnvironmentBrowser(ctx)
}
finder, ferr := cmd.ClusterFlag.Finder()
if ferr != nil {
return nil, ferr
}
cr, ferr := finder.ComputeResourceOrDefault(ctx, cmd.ClusterFlag.Name)
if ferr != nil {
return nil, ferr
}
return cr.EnvironmentBrowser(ctx)
}

142
vendor/github.com/vmware/govmomi/cli/flags/folder.go generated vendored Normal file
View file

@ -0,0 +1,142 @@
/*
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) IsSet() bool {
return flag.name != ""
}
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,95 @@
/*
Copyright (c) 2015-2024 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/fault"
"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 {
var verify *types.SSLVerifyFault
if _, ok := fault.As(err, &verify); ok {
return fmt.Errorf("%s thumbprint=%s", err, verify.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() && flag.SearchFlag.t == SearchHosts {
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/cli/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/cli/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/cli/flags/library.go generated vendored Normal file
View file

@ -0,0 +1,93 @@
/*
Copyright (c) 2020-2022 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/cli/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
}

165
vendor/github.com/vmware/govmomi/cli/flags/network.go generated vendored Normal file
View file

@ -0,0 +1,165 @@
/*
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
proto string
}
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")
f.StringVar(&flag.proto, "net.protocol", "", fmt.Sprintf("Network device protocol. Applicable to vmxnet3vrdma. Default to '%s'", string(types.VirtualVmxnet3VrdmaOptionDeviceProtocolsRocev2)))
})
}
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 a, ok := device.(*types.VirtualVmxnet3Vrdma); ok {
if flag.proto != "" {
if flag.proto != string(types.VirtualVmxnet3VrdmaOptionDeviceProtocolsRocev2) &&
flag.proto != string(types.VirtualVmxnet3VrdmaOptionDeviceProtocolsRocev1) {
return nil, fmt.Errorf("invalid device protocol '%s'", flag.proto)
}
a.DeviceProtocol = flag.proto
}
} else if flag.proto != "" {
return nil, fmt.Errorf("device protocol is only supported for vmxnet3vrdma at the moment")
}
if flag.address == "-" {
card := device.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard()
card.AddressType = string(types.VirtualEthernetCardMacTypeGenerated)
card.MacAddress = ""
} else 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}
}

View file

@ -0,0 +1,50 @@
/*
Copyright (c) 2023-2023 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"
)
type optionalString struct {
val **string
}
func (s *optionalString) Set(input string) error {
*s.val = &input
return nil
}
func (s *optionalString) Get() interface{} {
if *s.val == nil {
return nil
}
return **s.val
}
func (s *optionalString) String() string {
if s.val == nil || *s.val == nil {
return "<nil>"
}
return **s.val
}
// NewOptionalString returns a flag.Value implementation where there is no default value.
// This avoids sending a default value over the wire as using flag.StringVar() would.
func NewOptionalString(v **string) flag.Value {
return &optionalString{v}
}

308
vendor/github.com/vmware/govmomi/cli/flags/output.go generated vendored Normal file
View file

@ -0,0 +1,308 @@
/*
Copyright (c) 2014-2024 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"
"strings"
"time"
"github.com/dougm/pretty"
"github.com/vmware/govmomi/cli"
"github.com/vmware/govmomi/task"
"github.com/vmware/govmomi/vim25/progress"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
"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
Spec bool
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")
if cli.ShowUnreleased() {
f.BoolVar(&flag.Spec, "spec", false, "Output spec without sending request")
}
// 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
}
w := flag.Out
if w == nil {
w = os.Stdout
}
n, err := w.Write(b)
if w == os.Stdout {
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
}
type outputAny struct {
Value any
}
func (*outputAny) Write(io.Writer) error {
return nil
}
func (a *outputAny) Dump() interface{} {
return a.Value
}
func (flag *OutputFlag) WriteAny(val any) error {
if !flag.All() {
flag.XML = true
}
return flag.WriteResult(&outputAny{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 {
reason := e.Error()
var messages []string
var faults []types.LocalizableMessage
switch err := e.error.(type) {
case task.Error:
faults = err.LocalizedMethodFault.Fault.GetMethodFault().FaultMessage
if err.Description != nil {
reason = fmt.Sprintf("%s (%s)", reason, err.Description.Message)
}
default:
if soap.IsSoapFault(err) {
detail := soap.ToSoapFault(err).Detail.Fault
if f, ok := detail.(types.BaseMethodFault); ok {
faults = f.GetMethodFault().FaultMessage
}
}
}
for _, m := range faults {
if m.Message != "" && !strings.HasPrefix(m.Message, "[context]") {
messages = append(messages, fmt.Sprintf("%s (%s)", m.Message, m.Key))
}
}
messages = append(messages, reason)
for _, message := range messages {
if _, err := fmt.Fprintf(w, "%s: %s\n", os.Args[0], message); err != nil {
return err
}
}
return nil
}
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)
}
// errCannotEncode causes cli.Run to output err.Error() as it would without an error format specified
var errCannotEncode = 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, errCannotEncode
}
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 errCannotEncode
}
func (flag *OutputFlag) ProgressLogger(prefix string) *progress.ProgressLogger {
return progress.NewProgressLogger(flag.Log, 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,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 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) IsSet() bool {
return flag.name != ""
}
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()
}

435
vendor/github.com/vmware/govmomi/cli/flags/search.go generated vendored Normal file
View file

@ -0,0 +1,435 @@
/*
Copyright (c) 2014-2024 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/fault"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25"
"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
}
func NewSearchFlag(ctx context.Context, t int) (*SearchFlag, context.Context) {
searchFlagKey := flagKey(fmt.Sprintf("search%d", t))
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 fault.Is(err, &types.InvalidArgument{}) {
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,94 @@
/*
Copyright (c) 2014-2022 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 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
}

View file

@ -0,0 +1,124 @@
/*
Copyright (c) 2024-2024 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"
"github.com/vmware/govmomi/vim25/types"
)
type StorageProfileFlag struct {
*ClientFlag
Name []string
option string
}
func NewStorageProfileFlag(ctx context.Context, option ...string) (*StorageProfileFlag, context.Context) {
v := &StorageProfileFlag{}
if len(option) == 1 {
v.option = option[0]
} else {
v.option = "profile"
}
v.ClientFlag, ctx = NewClientFlag(ctx)
return v, ctx
}
func (e *StorageProfileFlag) String() string {
return fmt.Sprint(e.Name)
}
func (e *StorageProfileFlag) Set(value string) error {
e.Name = append(e.Name, value)
return nil
}
func (flag *StorageProfileFlag) Register(ctx context.Context, f *flag.FlagSet) {
flag.ClientFlag.Register(ctx, f)
f.Var(flag, flag.option, "Storage profile name or ID")
}
func (flag *StorageProfileFlag) StorageProfileList(ctx context.Context) ([]string, error) {
if len(flag.Name) == 0 {
return nil, nil
}
c, err := flag.PbmClient()
if err != nil {
return nil, err
}
m, err := c.ProfileMap(ctx)
if err != nil {
return nil, err
}
list := make([]string, len(flag.Name))
for i, name := range flag.Name {
p, ok := m.Name[name]
if !ok {
return nil, fmt.Errorf("storage profile %q not found", name)
}
list[i] = p.GetPbmProfile().ProfileId.UniqueId
}
return list, nil
}
func (flag *StorageProfileFlag) StorageProfile(ctx context.Context) (string, error) {
switch len(flag.Name) {
case 0:
return "", nil
case 1:
default:
return "", errors.New("only 1 '-profile' can be specified")
}
list, err := flag.StorageProfileList(ctx)
if err != nil {
return "", err
}
return list[0], nil
}
func (flag *StorageProfileFlag) StorageProfileSpec(ctx context.Context) ([]types.BaseVirtualMachineProfileSpec, error) {
if len(flag.Name) == 0 {
return nil, nil
}
list, err := flag.StorageProfileList(ctx)
if err != nil {
return nil, err
}
spec := make([]types.BaseVirtualMachineProfileSpec, len(list))
for i, name := range list {
spec[i] = &types.VirtualMachineDefinedProfileSpec{
ProfileId: name,
}
}
return spec, nil
}

71
vendor/github.com/vmware/govmomi/cli/flags/version.go generated vendored Normal file
View file

@ -0,0 +1,71 @@
/*
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"
)
var (
BuildVersion = "v0.0.0" // govc-test requires an (arbitrary) version set
BuildCommit string
BuildDate string
)
type version []int
func ParseVersion(s string) (version, error) {
// remove any trailing "v" version identifier
s = strings.TrimPrefix(s, "v")
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
}

170
vendor/github.com/vmware/govmomi/cli/importx/options.go generated vendored Normal file
View file

@ -0,0 +1,170 @@
/*
Copyright (c) 2015-2024 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/cli/flags"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/ovf"
"github.com/vmware/govmomi/ovf/importer"
"github.com/vmware/govmomi/vim25/types"
)
type OptionsFlag struct {
Options importer.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
}

64
vendor/github.com/vmware/govmomi/cli/importx/ova.go generated vendored Normal file
View file

@ -0,0 +1,64 @@
/*
Copyright (c) 2014-2024 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/cli"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/ovf/importer"
"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 := &importer.TapeArchive{Path: fpath}
archive.Client = cmd.Importer.Client
cmd.Importer.Archive = archive
moref, err := cmd.Import(fpath)
if err != nil {
return err
}
vm := object.NewVirtualMachine(cmd.Importer.Client, *moref)
return cmd.Deploy(vm, cmd.OutputFlag)
}
func (cmd *ova) Import(fpath string) (*types.ManagedObjectReference, error) {
ovf := "*.ovf"
return cmd.Importer.Import(context.TODO(), ovf, cmd.Options)
}

186
vendor/github.com/vmware/govmomi/cli/importx/ovf.go generated vendored Normal file
View file

@ -0,0 +1,186 @@
/*
Copyright (c) 2014-2024 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"
"github.com/vmware/govmomi/cli"
"github.com/vmware/govmomi/cli/flags"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/ovf/importer"
)
type ovfx struct {
*flags.DatastoreFlag
*flags.HostSystemFlag
*flags.OutputFlag
*flags.ResourcePoolFlag
*flags.FolderFlag
*OptionsFlag
Importer importer.Importer
}
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.OptionsFlag, ctx = newOptionsFlag(ctx)
cmd.OptionsFlag.Register(ctx, f)
f.StringVar(&cmd.Importer.Name, "name", "", "Name to use for new entity")
f.BoolVar(&cmd.Importer.VerifyManifest, "m", false, "Verify checksum of uploaded files against manifest (.mf)")
f.BoolVar(&cmd.Importer.Hidden, "hidden", false, "Enable hidden properties")
}
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.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 := &importer.FileArchive{Path: fpath}
archive.Client = cmd.Importer.Client
cmd.Importer.Archive = archive
moref, err := cmd.Importer.Import(context.TODO(), fpath, cmd.Options)
if err != nil {
return err
}
vm := object.NewVirtualMachine(cmd.Importer.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.Importer.Log = cmd.OutputFlag.Log
cmd.Importer.Client, err = cmd.DatastoreFlag.Client()
if err != nil {
return "", err
}
cmd.Importer.Datacenter, err = cmd.DatastoreFlag.Datacenter()
if err != nil {
return "", err
}
cmd.Importer.Datastore, err = cmd.DatastoreFlag.Datastore()
if err != nil {
return "", err
}
cmd.Importer.ResourcePool, err = cmd.ResourcePoolIfSpecified()
if err != nil {
return "", err
}
host, err := cmd.HostSystemIfSpecified()
if err != nil {
return "", err
}
if cmd.Importer.ResourcePool == nil {
if host == nil {
cmd.Importer.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePool()
} else {
cmd.Importer.ResourcePool, err = host.ResourcePool(context.TODO())
}
if err != nil {
return "", err
}
}
cmd.Importer.Finder, err = cmd.DatastoreFlag.Finder()
if err != nil {
return "", err
}
cmd.Importer.Host, err = cmd.HostSystemIfSpecified()
if err != nil {
return "", err
}
// 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.Importer.ResourcePool.Reference().Type != "VirtualApp" {
cmd.Importer.Folder, err = cmd.FolderOrDefault("vm")
if err != nil {
return "", err
}
}
if cmd.Importer.Name == "" {
// Override name from options if specified
if cmd.Options.Name != nil {
cmd.Importer.Name = *cmd.Options.Name
}
} else {
cmd.Options.Name = &cmd.Importer.Name
}
return f.Arg(0), nil
}

114
vendor/github.com/vmware/govmomi/cli/importx/spec.go generated vendored Normal file
View file

@ -0,0 +1,114 @@
/*
Copyright (c) 2015-2024 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"
"github.com/vmware/govmomi/cli"
"github.com/vmware/govmomi/cli/flags"
"github.com/vmware/govmomi/ovf/importer"
)
type spec struct {
*flags.ClientFlag
*flags.OutputFlag
Archive importer.Archive
hidden bool
}
func init() {
cli.Register("import.spec", &spec{})
}
func (cmd *spec) 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)
f.BoolVar(&cmd.hidden, "hidden", false, "Enable hidden properties")
}
func (cmd *spec) Process(ctx context.Context) error {
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 = &importer.FileArchive{Path: fpath}
case "", ".ova":
cmd.Archive = &importer.TapeArchive{Path: fpath}
fpath = "*.ovf"
default:
return fmt.Errorf("invalid file extension %s", path.Ext(fpath))
}
if importer.IsRemotePath(f.Arg(0)) {
client, err := cmd.Client()
if err != nil {
return err
}
switch archive := cmd.Archive.(type) {
case *importer.FileArchive:
archive.Client = client
case *importer.TapeArchive:
archive.Client = client
}
}
}
env, err := importer.Spec(fpath, cmd.Archive, cmd.hidden, cmd.Verbose())
if err != nil {
return err
}
if !cmd.All() {
cmd.JSON = true
}
return cmd.WriteResult(&specResult{env})
}
type specResult struct {
*importer.Options
}
func (*specResult) Write(w io.Writer) error {
return nil
}

132
vendor/github.com/vmware/govmomi/cli/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/cli"
"github.com/vmware/govmomi/cli/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
}

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

@ -0,0 +1,47 @@
/*
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 ShowUnreleased() bool {
return !hideUnreleased
}
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
}

264
vendor/github.com/vmware/govmomi/cli/vm/change.go generated vendored Normal file
View file

@ -0,0 +1,264 @@
/*
Copyright (c) 2015-2024 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"
"os"
"reflect"
"strings"
"github.com/vmware/govmomi/cli"
"github.com/vmware/govmomi/cli/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 extraConfigFile []types.BaseOptionValue
func (e *extraConfigFile) String() string {
return fmt.Sprintf("%v", *e)
}
func (e *extraConfigFile) Set(v string) error {
r := strings.SplitN(v, "=", 2)
if len(r) < 2 {
return fmt.Errorf("failed to parse extraConfigFile: %s", v)
}
var fileContents = ""
if len(r[1]) > 0 {
contents, err := os.ReadFile(r[1])
if err != nil {
return fmt.Errorf("failed to parse extraConfigFile '%s': %w", v, err)
}
fileContents = string(contents)
}
*e = append(*e, &types.OptionValue{Key: r[0], Value: fileContents})
return nil
}
type change struct {
*flags.VirtualMachineFlag
*flags.ResourceAllocationFlag
types.VirtualMachineConfigSpec
extraConfig extraConfig
extraConfigFile extraConfigFile
Latency string
hwUpgradePolicy string
managedBy string
}
func init() {
cli.Register("vm.change", &change{})
}
var latencyLevels = types.LatencySensitivitySensitivityLevel("").Strings()
// 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, "|"))
}
var (
hwUpgradePolicies = types.ScheduledHardwareUpgradeInfoHardwareUpgradePolicy("").Strings()
ftEncryptionModes = types.VirtualMachineConfigSpecEncryptedFtModes("").Strings()
migrateEncryptionModes = types.VirtualMachineConfigSpecEncryptedVMotionModes("").Strings()
)
// setHwUpgradePolicy validates hwUpgradePolicy if set
func (cmd *change) setHwUpgradePolicy() error {
if cmd.hwUpgradePolicy == "" {
return nil
}
for _, l := range hwUpgradePolicies {
if l == cmd.hwUpgradePolicy {
cmd.ScheduledHardwareUpgradeInfo = &types.ScheduledHardwareUpgradeInfo{
UpgradePolicy: string(types.ScheduledHardwareUpgradeInfoHardwareUpgradePolicy(cmd.hwUpgradePolicy)),
}
return nil
}
}
return fmt.Errorf("Hardware upgrade policy must be one of: %s", strings.Join(hwUpgradePolicies, "|"))
}
// 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.StringVar(&cmd.managedBy, "managed-by", "", "Set or clear managed by VC Extension")
f.Var(&cmd.extraConfig, "e", "ExtraConfig. <key>=<value>")
f.Var(&cmd.extraConfigFile, "f", "ExtraConfig. <key>=<absolute path to file>")
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")
cmd.Flags = &types.VirtualMachineFlagInfo{}
f.Var(flags.NewOptionalBool(&cmd.Flags.VvtdEnabled), "iommu-enabled", "Enable IOMMU")
f.StringVar(&cmd.hwUpgradePolicy, "scheduled-hw-upgrade-policy", "", fmt.Sprintf("Schedule hardware upgrade policy (%s)", strings.Join(hwUpgradePolicies, "|")))
f.StringVar(&cmd.FtEncryptionMode, "ft-encryption-mode", "", fmt.Sprintf("Encrypted fault tolerance mode (%s)", strings.Join(ftEncryptionModes, "|")))
f.StringVar(&cmd.MigrateEncryption, "migrate-encryption", "", fmt.Sprintf("Encrypted vMotion mode (%s)", strings.Join(migrateEncryptionModes, "|")))
}
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 contents of a file and use them as ExtraConfig value
govc vm.change -vm $vm -f guestinfo.data="$(realpath .)/vmdata.config"
# 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
govc vm.change -vm $vm -scheduled-hw-upgrade-policy always`
}
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
}
cmd.VirtualMachineConfigSpec.ExtraConfig = append(cmd.extraConfig, cmd.extraConfigFile...)
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 reflect.DeepEqual(cmd.Flags, new(types.VirtualMachineFlagInfo)) {
cmd.Flags = nil // no flags set, avoid sending <flags/> in the request
}
if err = cmd.setLatency(); err != nil {
return err
}
if err = cmd.setHwUpgradePolicy(); err != nil {
return err
}
if cmd.managedBy != "" {
// From the VirtualMachineConfigSpec doc:
// To unset this field pass a ManagedByInfo object with an empty extensionKey
if cmd.managedBy == "-" {
cmd.managedBy = ""
}
cmd.ManagedBy = &types.ManagedByInfo{
Type: vm.Reference().Type,
ExtensionKey: cmd.managedBy,
}
}
task, err := vm.Reconfigure(ctx, cmd.VirtualMachineConfigSpec)
if err != nil {
return err
}
return task.Wait(ctx)
}

495
vendor/github.com/vmware/govmomi/cli/vm/clone.go generated vendored Normal file
View file

@ -0,0 +1,495 @@
/*
Copyright (c) 2016-2024 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/cli"
"github.com/vmware/govmomi/cli/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
}
} else {
if cmd.ResourcePool, err = cmd.Cluster.ResourcePool(ctx); 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.Spec {
return nil
}
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 := 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
}
if cmd.Spec {
return nil, cmd.WriteAny(cloneSpec)
}
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
}

186
vendor/github.com/vmware/govmomi/cli/vm/console.go generated vendored Normal file
View file

@ -0,0 +1,186 @@
/*
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/cli"
"github.com/vmware/govmomi/cli/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
wss 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.BoolVar(&cmd.wss, "wss", false, "Generate WebSocket 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 (cmd.capture != "" || cmd.wss) && 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)
}
if cmd.wss {
ticket, err := vm.AcquireTicket(ctx, string(types.VirtualMachineTicketTypeWebmks))
if err != nil {
return err
}
link := fmt.Sprintf("wss://%s:%d/ticket/%s", ticket.Host, ticket.Port, ticket.Ticket)
fmt.Fprintln(cmd.Out, link)
return nil
}
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(cmd.Out, link)
return nil
}

697
vendor/github.com/vmware/govmomi/cli/vm/create.go generated vendored Normal file
View file

@ -0,0 +1,697 @@
/*
Copyright (c) 2014-2024 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"
"strings"
"text/tabwriter"
"github.com/vmware/govmomi/cli"
"github.com/vmware/govmomi/cli/flags"
"github.com/vmware/govmomi/find"
"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 (
FirmwareTypes = types.GuestOsDescriptorFirmwareType("").Strings()
FirmwareUsage = fmt.Sprintf("Firmware type [%s]", strings.Join(FirmwareTypes, "|"))
)
type create struct {
*flags.ClientFlag
*flags.ClusterFlag
*flags.DatacenterFlag
*flags.DatastoreFlag
*flags.StoragePodFlag
*flags.ResourcePoolFlag
*flags.HostSystemFlag
*flags.NetworkFlag
*flags.FolderFlag
*flags.StorageProfileFlag
name string
memory int
cpus int
guestID string
link bool
on bool
force bool
controller string
eager bool
thick bool
annotation string
firmware string
version string
place bool
iso string
isoDatastoreFlag *flags.DatastoreFlag
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)
cmd.StorageProfileFlag, ctx = flags.NewStorageProfileFlag(ctx)
cmd.StorageProfileFlag.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.BoolVar(&cmd.eager, "disk.eager", false, "Eagerly scrub new disk")
f.BoolVar(&cmd.thick, "disk.thick", false, "Thick provision new disk")
f.StringVar(&cmd.annotation, "annotation", "", "VM description")
f.StringVar(&cmd.firmware, "firmware", FirmwareTypes[0], FirmwareUsage)
if cli.ShowUnreleased() {
f.BoolVar(&cmd.place, "place", false, "Place VM without creating")
}
esxiVersions := types.GetESXiVersions()
esxiVersionStrings := make([]string, len(esxiVersions))
for i := range esxiVersions {
esxiVersionStrings[i] = esxiVersions[i].String()
}
f.StringVar(&cmd.version, "version", "",
fmt.Sprintf("ESXi hardware version [%s]", strings.Join(esxiVersionStrings, "|")))
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
}
if err := cmd.StorageProfileFlag.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 -iso library:/boot/linux/ubuntu.iso vm-name # Content Library ISO
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 != "" {
iso, err := cmd.isoDatastoreFlag.FileBacking(ctx, cmd.iso, true)
if err != nil {
return err
}
cmd.iso = iso
}
// 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
}
if cmd.place || cmd.Spec {
return nil
}
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
}
type place struct {
Spec types.PlacementSpec `json:"spec"`
Recommendations []types.ClusterRecommendation `json:"recommendations"`
ctx context.Context
cmd *create
}
func (p *place) Dump() interface{} {
return p.Recommendations
}
func (p *place) action(w io.Writer, r types.ClusterRecommendation, a *types.PlacementAction) error {
spec := a.RelocateSpec
if spec == nil {
return nil
}
fields := []struct {
name string
moid *types.ManagedObjectReference
}{
{"Target", r.Target},
{" Folder", spec.Folder},
{" Datastore", spec.Datastore},
{" Pool", spec.Pool},
{" Host", spec.Host},
}
for _, f := range fields {
if f.moid == nil {
continue
}
path, err := find.InventoryPath(p.ctx, p.cmd.Client, *f.moid)
if err != nil {
return err
}
fmt.Fprintf(w, "%s:\t%s\n", f.name, path)
}
return nil
}
func (p *place) Write(w io.Writer) error {
tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0)
for _, r := range p.Recommendations {
for _, a := range r.Action {
p.action(tw, r, a.(*types.PlacementAction))
}
}
return tw.Flush()
}
func (cmd *create) createVM(ctx context.Context) (*object.Task, error) {
var devices object.VirtualDeviceList
var err error
if cmd.version != "" {
if v, _ := types.ParseESXiVersion(cmd.version); v.IsValid() {
cmd.version = v.HardwareVersion().String()
} else if v, _ := types.ParseHardwareVersion(cmd.version); v.IsValid() {
cmd.version = v.String()
} else {
return nil, fmt.Errorf("invalid version: %s", cmd.version)
}
}
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,
}
spec.VmProfile, err = cmd.StorageProfileSpec(ctx)
if err != nil {
return nil, err
}
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 cmd.place {
return nil, cmd.WriteResult(&place{pspec, recs, ctx, cmd})
}
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 && !cmd.Spec {
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()),
}
if cmd.Spec {
return nil, cmd.WriteAny(spec)
}
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 if cmd.controller == "sata" {
sata, err := devices.CreateSATAController()
if err != nil {
return nil, err
}
devices = append(devices, sata)
cmd.controller = devices.Name(sata)
} 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
}
backing := &types.VirtualDiskFlatVer2BackingInfo{
DiskMode: string(types.VirtualDiskModePersistent),
ThinProvisioned: types.NewBool(!cmd.thick),
}
if cmd.thick {
backing.EagerlyScrub = &cmd.eager
}
disk := &types.VirtualDisk{
VirtualDevice: types.VirtualDevice{
Key: devices.NewKey(),
Backing: backing,
},
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.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
}

321
vendor/github.com/vmware/govmomi/cli/vm/customize.go generated vendored Normal file
View file

@ -0,0 +1,321 @@
/*
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/cli"
"github.com/vmware/govmomi/cli/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
ip6 flags.StringList
gateway flags.StringList
netmask flags.StringList
dnsserver flags.StringList
dnssuffix flags.StringList
kind string
username string
org 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", "IPv4 address")
cmd.ip = nil
f.Var(&cmd.ip6, "ip6", "IPv6 addresses with optional netmask (defaults to /64), separated by comma")
cmd.ip6 = 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 list")
cmd.dnsserver = nil
f.Var(&cmd.dnssuffix, "dns-suffix", "DNS suffix list")
cmd.dnssuffix = nil
f.StringVar(&cmd.kind, "type", "Linux", "Customization type if spec NAME is not specified (Linux|Windows)")
f.StringVar(&cmd.username, "username", "", "Windows only : full name of the end user in firstname lastname format")
f.StringVar(&cmd.org, "org", "", "Windows only : name of the org that owns the VM")
}
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.
The '-dns-server' and '-dns-suffix' flags can be specified multiple times.
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
# Dual stack IPv4/IPv6, single NIC
govc vm.customize -vm VM -ip 10.0.0.1 -netmask 255.255.255.0 -ip6 '2001:db8::1/64' -name my-hostname NAME
# DHCPv6, single NIC
govc vm.customize -vm VM -ip6 dhcp6 NAME
# Static IPv6, three NICs, last one with two addresses
govc vm.customize -vm VM -ip6 2001:db8::1/64 -ip6 2001:db8::2/64 -ip6 2001:db8::3/64,2001:db8::4/64 NAME
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`
}
// Parse a string of multiple IPv6 addresses with optional netmask; separated by comma
func parseIPv6Argument(argv string) (ipconf []types.BaseCustomizationIpV6Generator, err error) {
for _, substring := range strings.Split(argv, ",") {
// remove leading and trailing white space
substring = strings.TrimSpace(substring)
// handle "dhcp6" and lists of static IPv6 addresses
switch substring {
case "dhcp6":
ipconf = append(
ipconf,
&types.CustomizationDhcpIpV6Generator{},
)
default:
// check if subnet mask was specified
switch strings.Count(substring, "/") {
// no mask, set default
case 0:
ipconf = append(ipconf, &types.CustomizationFixedIpV6{
IpAddress: substring,
SubnetMask: 64,
})
// a single forward slash was found: parse and use subnet mask
case 1:
parts := strings.Split(substring, "/")
mask, err := strconv.Atoi(parts[1])
if err != nil {
return nil, fmt.Errorf("unable to convert subnet mask to int: %w", err)
}
ipconf = append(ipconf, &types.CustomizationFixedIpV6{
IpAddress: parts[0],
SubnetMask: int32(mask),
})
// too many forward slashes; return error
default:
return nil, fmt.Errorf("unable to parse IPv6 address (too many subnet separators): %s", substring)
}
}
}
return ipconf, nil
}
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 isWindows {
sysprep.Identification.JoinDomain = cmd.domain
sysprep.UserData.FullName = cmd.username
sysprep.UserData.OrgName = cmd.org
} 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, ",")...)
}
}
}
spec.GlobalIPSettings.DnsSuffixList = cmd.dnssuffix
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], ",")
}
}
}
for i, ip6 := range cmd.ip6 {
ipconfig, err := parseIPv6Argument(ip6)
if err != nil {
return err
}
// use the same logic as the ip switch: the first occurrence of the ip6 switch is assigned to the first nic,
// the second to the second nic and so forth.
if spec.NicSettingMap == nil || len(spec.NicSettingMap) < i {
return fmt.Errorf("unable to find a network adapter for IPv6 settings %d (%s)", i, ip6)
}
nic := &spec.NicSettingMap[i]
if nic.Adapter.IpV6Spec == nil {
nic.Adapter.IpV6Spec = new(types.CustomizationIPSettingsIpV6AddressSpec)
}
nic.Adapter.IpV6Spec.Ip = append(nic.Adapter.IpV6Spec.Ip, ipconfig...)
}
task, err := vm.Customize(ctx, *spec)
if err != nil {
return err
}
return task.Wait(ctx)
}

110
vendor/github.com/vmware/govmomi/cli/vm/destroy.go generated vendored Normal file
View file

@ -0,0 +1,110 @@
/*
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/cli"
"github.com/vmware/govmomi/cli/flags"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/types"
)
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 {
var (
task *object.Task
state types.VirtualMachinePowerState
)
state, err = vm.PowerState(ctx)
if err != nil {
return err
}
if state == types.VirtualMachinePowerStatePoweredOn {
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
}
if err = task.Wait(ctx); err != nil {
return err
}
}
return nil
}

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

@ -0,0 +1,78 @@
/*
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("could not set guest login values: %v", err)
}
usage := fmt.Sprintf("Guest VM credentials (<user>:<password>) [%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 {
if flag.auth.Username == "" {
return fmt.Errorf("guest login username must not be empty")
}
return nil
}
func (flag *AuthFlag) Auth() types.BaseGuestAuthentication {
return &flag.auth
}

77
vendor/github.com/vmware/govmomi/cli/vm/guest/chmod.go generated vendored Normal file
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/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)
}

96
vendor/github.com/vmware/govmomi/cli/vm/guest/chown.go generated vendored Normal file
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/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/cli/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/cli"
"github.com/vmware/govmomi/cli/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/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(ctx)
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/cli/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/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
}

135
vendor/github.com/vmware/govmomi/cli/vm/guest/guest.go generated vendored Normal file
View file

@ -0,0 +1,135 @@
/*
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/cli/flags"
"github.com/vmware/govmomi/guest"
"github.com/vmware/govmomi/guest/toolbox"
"github.com/vmware/govmomi/object"
)
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(ctx context.Context) (*toolbox.Client, error) {
vm, err := flag.VirtualMachine()
if err != nil {
return nil, err
}
c, err := flag.Client()
if err != nil {
return nil, err
}
return toolbox.NewClient(ctx, c, vm, flag.Auth())
}
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/cli/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/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/cli/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/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
}

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

@ -0,0 +1,80 @@
/*
Copyright (c) 2014-2024 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/cli"
"github.com/vmware/govmomi/fault"
"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 fault.Is(err, &types.FileAlreadyExists{}) {
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/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
}

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

@ -0,0 +1,82 @@
/*
Copyright (c) 2017-2024 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/cli"
"github.com/vmware/govmomi/fault"
"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 fault.Is(err, &types.NotAFile{}) {
err = m.MoveDirectory(ctx, cmd.Auth(), src, dst)
}
}
return err
}

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

@ -0,0 +1,199 @@
/*
Copyright (c) 2014-2023 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/cli"
"github.com/vmware/govmomi/cli/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 `json:"processInfo"`
}
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/cli/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/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))
}

69
vendor/github.com/vmware/govmomi/cli/vm/guest/rmdir.go generated vendored Normal file
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/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)
}

106
vendor/github.com/vmware/govmomi/cli/vm/guest/run.go generated vendored Normal file
View file

@ -0,0 +1,106 @@
/*
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 (
"bytes"
"context"
"flag"
"os"
"os/exec"
"github.com/vmware/govmomi/cli"
)
type run struct {
*GuestFlag
data string
dir string
vars env
}
func init() {
cli.Register("guest.run", &run{})
}
func (cmd *run) Register(ctx context.Context, f *flag.FlagSet) {
cmd.GuestFlag, ctx = newGuestProcessFlag(ctx)
cmd.GuestFlag.Register(ctx, f)
f.StringVar(&cmd.data, "d", "", "Input data string. A value of '-' reads from OS stdin")
f.StringVar(&cmd.dir, "C", "", "The absolute path of the working directory for the program to start")
f.Var(&cmd.vars, "e", "Set environment variables")
}
func (cmd *run) Usage() string {
return "PATH [ARG]..."
}
func (cmd *run) Description() string {
return `Run program PATH in VM and display output.
The guest.run command starts a program in the VM with i/o redirected, waits for the process to exit and
propagates the exit code to the govc process exit code. Note that stdout and stderr are redirected by default,
stdin is only redirected when the '-d' flag is specified.
Note that vmware-tools requires program PATH to be absolute.
If PATH is not absolute and vm guest family is Windows,
guest.run changes the command to: 'c:\\Windows\\System32\\cmd.exe /c "PATH [ARG]..."'
Otherwise the command is changed to: '/bin/bash -c "PATH [ARG]..."'
Examples:
govc guest.run -vm $name ifconfig
govc guest.run -vm $name ifconfig eth0
cal | govc guest.run -vm $name -d - cat
govc guest.run -vm $name -d "hello $USER" cat
govc guest.run -vm $name curl -s :invalid: || echo $? # exit code 6
govc guest.run -vm $name -e FOO=bar -e BIZ=baz -C /tmp env
govc guest.run -vm $name -l root:mypassword ntpdate -u pool.ntp.org
govc guest.run -vm $name powershell C:\\network_refresh.ps1`
}
func (cmd *run) Run(ctx context.Context, f *flag.FlagSet) error {
if f.NArg() == 0 {
return flag.ErrHelp
}
name := f.Arg(0)
c, err := cmd.Toolbox(ctx)
if err != nil {
return err
}
ecmd := &exec.Cmd{
Path: name,
Args: f.Args()[1:],
Env: cmd.vars,
Dir: cmd.dir,
Stdout: os.Stdout,
Stderr: os.Stderr,
}
switch cmd.data {
case "":
case "-":
ecmd.Stdin = os.Stdin
default:
ecmd.Stdin = bytes.NewBuffer([]byte(cmd.data))
}
return c.Run(ctx, ecmd)
}

103
vendor/github.com/vmware/govmomi/cli/vm/guest/start.go generated vendored Normal file
View file

@ -0,0 +1,103 @@
/*
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"
"strings"
"github.com/vmware/govmomi/cli"
"github.com/vmware/govmomi/vim25/types"
)
type start struct {
*GuestFlag
dir string
vars env
}
type env []string
func (e *env) String() string {
return fmt.Sprint(*e)
}
func (e *env) Set(value string) error {
*e = append(*e, value)
return nil
}
func init() {
cli.Register("guest.start", &start{})
}
func (cmd *start) Register(ctx context.Context, f *flag.FlagSet) {
cmd.GuestFlag, ctx = newGuestProcessFlag(ctx)
cmd.GuestFlag.Register(ctx, f)
f.StringVar(&cmd.dir, "C", "", "The absolute path of the working directory for the program to start")
f.Var(&cmd.vars, "e", "Set environment variable (key=val)")
}
func (cmd *start) Process(ctx context.Context) error {
if err := cmd.GuestFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *start) Usage() string {
return "PATH [ARG]..."
}
func (cmd *start) Description() string {
return `Start program in VM.
The process can have its status queried with govc guest.ps.
When the process completes, its exit code and end time will be available for 5 minutes after completion.
Examples:
govc guest.start -vm $name /bin/mount /dev/hdb1 /data
pid=$(govc guest.start -vm $name /bin/long-running-thing)
govc guest.ps -vm $name -p $pid -X`
}
func (cmd *start) Run(ctx context.Context, f *flag.FlagSet) error {
m, err := cmd.ProcessManager()
if err != nil {
return err
}
spec := types.GuestProgramSpec{
ProgramPath: f.Arg(0),
Arguments: strings.Join(f.Args()[1:], " "),
WorkingDirectory: cmd.dir,
EnvVariables: cmd.vars,
}
pid, err := m.StartProgram(ctx, cmd.Auth(), &spec)
if err != nil {
return err
}
fmt.Printf("%d\n", pid)
return nil
}

116
vendor/github.com/vmware/govmomi/cli/vm/guest/tools.go generated vendored Normal file
View file

@ -0,0 +1,116 @@
/*
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/cli"
"github.com/vmware/govmomi/cli/flags"
"github.com/vmware/govmomi/object"
)
type tools struct {
*flags.ClientFlag
*flags.SearchFlag
mount bool
upgrade bool
options string
unmount bool
}
func init() {
cli.Register("vm.guest.tools", &tools{})
}
func (cmd *tools) 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)
f.BoolVar(&cmd.mount, "mount", false, "Mount tools CD installer in the guest")
f.BoolVar(&cmd.upgrade, "upgrade", false, "Upgrade tools in the guest")
f.StringVar(&cmd.options, "options", "", "Installer options")
f.BoolVar(&cmd.unmount, "unmount", false, "Unmount tools CD installer in the guest")
}
func (cmd *tools) 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 *tools) Usage() string {
return "VM..."
}
func (cmd *tools) Description() string {
return `Manage guest tools in VM.
Examples:
govc vm.guest.tools -mount VM
govc vm.guest.tools -unmount VM
govc vm.guest.tools -upgrade -options "opt1 opt2" VM`
}
func (cmd *tools) Upgrade(ctx context.Context, vm *object.VirtualMachine) error {
task, err := vm.UpgradeTools(ctx, cmd.options)
if err != nil {
return err
}
return task.Wait(ctx)
}
func (cmd *tools) Run(ctx context.Context, f *flag.FlagSet) error {
vms, err := cmd.VirtualMachines(f.Args())
if err != nil {
return err
}
for _, vm := range vms {
switch {
case cmd.mount:
err = vm.MountToolsInstaller(ctx)
if err != nil {
return err
}
case cmd.upgrade:
err = cmd.Upgrade(ctx, vm)
if err != nil {
return err
}
case cmd.unmount:
err = vm.UnmountToolsInstaller(ctx)
if err != nil {
return err
}
default:
return flag.ErrHelp
}
}
return nil
}

126
vendor/github.com/vmware/govmomi/cli/vm/guest/touch.go generated vendored Normal file
View file

@ -0,0 +1,126 @@
/*
Copyright (c) 2017-2024 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 (
"bytes"
"context"
"flag"
"time"
"github.com/vmware/govmomi/cli"
"github.com/vmware/govmomi/fault"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
)
type touch struct {
*GuestFlag
nocreate bool
atime bool
date string
}
func init() {
cli.Register("guest.touch", &touch{})
}
func (cmd *touch) Register(ctx context.Context, f *flag.FlagSet) {
cmd.GuestFlag, ctx = newGuestFlag(ctx)
cmd.GuestFlag.Register(ctx, f)
f.BoolVar(&cmd.atime, "a", false, "Change only the access time")
f.BoolVar(&cmd.nocreate, "c", false, "Do not create any files")
f.StringVar(&cmd.date, "d", "", "Use DATE instead of current time")
}
func (cmd *touch) Process(ctx context.Context) error {
if err := cmd.GuestFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *touch) Usage() string {
return "FILE"
}
func (cmd *touch) Description() string {
return `Change FILE times on VM.
Examples:
govc guest.touch -vm $name /var/log/foo.log
govc guest.touch -vm $name -d "$(date -d '1 day ago')" /var/log/foo.log`
}
func (cmd *touch) Run(ctx context.Context, f *flag.FlagSet) error {
if f.NArg() != 1 {
return flag.ErrHelp
}
m, err := cmd.FileManager()
if err != nil {
return err
}
name := f.Arg(0)
var attr types.GuestFileAttributes
now := time.Now()
if cmd.date != "" {
now, err = time.Parse(time.UnixDate, cmd.date)
if err != nil {
return err
}
}
if cmd.atime {
attr.AccessTime = &now
} else {
attr.ModificationTime = &now
}
err = m.ChangeFileAttributes(ctx, cmd.Auth(), name, &attr)
if err != nil && !cmd.nocreate {
if fault.Is(err, &types.FileNotFound{}) {
// create a new empty file
url, cerr := m.InitiateFileTransferToGuest(ctx, cmd.Auth(), name, &attr, 0, false)
if cerr != nil {
return cerr
}
u, cerr := cmd.ParseURL(url)
if cerr != nil {
return cerr
}
c, cerr := cmd.Client()
if cerr != nil {
return cerr
}
err = c.Client.Upload(ctx, new(bytes.Buffer), u, &soap.DefaultUpload)
if err == nil && cmd.date != "" {
err = m.ChangeFileAttributes(ctx, cmd.Auth(), name, &attr)
}
}
}
return err
}

109
vendor/github.com/vmware/govmomi/cli/vm/guest/upload.go generated vendored Normal file
View file

@ -0,0 +1,109 @@
/*
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"
"path/filepath"
"github.com/vmware/govmomi/cli"
"github.com/vmware/govmomi/vim25/soap"
)
type upload struct {
*GuestFlag
*FileAttrFlag
overwrite bool
}
func init() {
cli.Register("guest.upload", &upload{})
}
func (cmd *upload) Register(ctx context.Context, f *flag.FlagSet) {
cmd.GuestFlag, ctx = newGuestFlag(ctx)
cmd.GuestFlag.Register(ctx, f)
cmd.FileAttrFlag, ctx = newFileAttrFlag(ctx)
cmd.FileAttrFlag.Register(ctx, f)
f.BoolVar(&cmd.overwrite, "f", false, "If set, the guest destination file is clobbered")
}
func (cmd *upload) Usage() string {
return "SOURCE DEST"
}
func (cmd *upload) Description() string {
return `Copy SOURCE from the local system to DEST in the guest VM.
If SOURCE name is "-", read source from stdin.
Examples:
govc guest.upload -l user:pass -vm=my-vm ~/.ssh/id_rsa.pub /home/$USER/.ssh/authorized_keys
cowsay "have a great day" | govc guest.upload -l user:pass -vm=my-vm - /etc/motd
tar -cf- foo/ | govc guest.run -d - tar -C /tmp -xf- # upload a directory`
}
func (cmd *upload) Process(ctx context.Context) error {
if err := cmd.GuestFlag.Process(ctx); err != nil {
return err
}
if err := cmd.FileAttrFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *upload) Run(ctx context.Context, f *flag.FlagSet) error {
if f.NArg() != 2 {
return flag.ErrHelp
}
c, err := cmd.Toolbox(ctx)
if err != nil {
return err
}
src := f.Arg(0)
dst := f.Arg(1)
p := soap.DefaultUpload
var r io.Reader = os.Stdin
if src != "-" {
f, err := os.Open(filepath.Clean(src))
if err != nil {
return err
}
defer f.Close()
r = f
if cmd.OutputFlag.TTY {
logger := cmd.ProgressLogger("Uploading... ")
p.Progress = logger
defer logger.Wait()
}
}
return c.Upload(ctx, r, dst, p, cmd.Attr(), cmd.overwrite)
}

361
vendor/github.com/vmware/govmomi/cli/vm/info.go generated vendored Normal file
View file

@ -0,0 +1,361 @@
/*
Copyright (c) 2014-2023 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"
"os"
"strings"
"text/tabwriter"
"github.com/vmware/govmomi/cli"
"github.com/vmware/govmomi/cli/flags"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/units"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
type info struct {
*flags.ClientFlag
*flags.OutputFlag
*flags.SearchFlag
WaitForIP bool
General bool
ExtraConfig bool
Resources bool
ToolsConfigInfo bool
}
func init() {
cli.Register("vm.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.SearchFlag, ctx = flags.NewSearchFlag(ctx, flags.SearchVirtualMachines)
cmd.SearchFlag.Register(ctx, f)
f.BoolVar(&cmd.WaitForIP, "waitip", false, "Wait for VM to acquire IP address")
f.BoolVar(&cmd.General, "g", true, "Show general summary")
f.BoolVar(&cmd.ExtraConfig, "e", false, "Show ExtraConfig")
f.BoolVar(&cmd.Resources, "r", false, "Show resource summary")
f.BoolVar(&cmd.ToolsConfigInfo, "t", false, "Show ToolsConfigInfo")
}
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.SearchFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *info) Usage() string {
return `VM...`
}
func (cmd *info) Description() string {
return `Display info for VM.
The '-r' flag displays additional info for CPU, memory and storage usage,
along with the VM's Datastores, Networks and PortGroups.
Examples:
govc vm.info $vm
govc vm.info -r $vm | grep Network:
govc vm.info -json $vm
govc find . -type m -runtime.powerState poweredOn | xargs govc vm.info`
}
func (cmd *info) Run(ctx context.Context, f *flag.FlagSet) error {
c, err := cmd.Client()
if err != nil {
return err
}
vms, err := cmd.VirtualMachines(f.Args())
if err != nil {
if _, ok := err.(*find.NotFoundError); ok {
// Continue with empty VM slice
} else {
return err
}
}
refs := make([]types.ManagedObjectReference, 0, len(vms))
for _, vm := range vms {
refs = append(refs, vm.Reference())
}
var res infoResult
var props []string
if cmd.OutputFlag.All() {
props = nil // Load everything
} else {
props = []string{"summary"} // Load summary
if cmd.General {
props = append(props, "guest.ipAddress")
}
if cmd.ExtraConfig {
props = append(props, "config.extraConfig")
}
if cmd.Resources {
props = append(props, "datastore", "network")
}
if cmd.ToolsConfigInfo {
props = append(props, "config.tools")
}
}
pc := property.DefaultCollector(c)
if len(refs) != 0 {
err = pc.Retrieve(ctx, refs, props, &res.VirtualMachines)
if err != nil {
return err
}
}
if cmd.WaitForIP {
for i, vm := range res.VirtualMachines {
if vm.Guest == nil || vm.Guest.IpAddress == "" {
_, err = vms[i].WaitForIP(ctx)
if err != nil {
return err
}
// Reload virtual machine object
err = pc.RetrieveOne(ctx, vms[i].Reference(), props, &res.VirtualMachines[i])
if err != nil {
return err
}
}
}
}
if !cmd.OutputFlag.All() {
res.objects = vms
res.cmd = cmd
if err = res.collectReferences(pc, ctx); err != nil {
return err
}
}
return cmd.WriteResult(&res)
}
type infoResult struct {
VirtualMachines []mo.VirtualMachine `json:"virtualMachines"`
objects []*object.VirtualMachine
entities map[types.ManagedObjectReference]string
cmd *info
}
// collectReferences builds a unique set of MORs to the set of VirtualMachines,
// so we can collect properties in a single call for each reference type {host,datastore,network}.
func (r *infoResult) collectReferences(pc *property.Collector, ctx context.Context) error {
// MOR -> Name map
r.entities = make(map[types.ManagedObjectReference]string)
var host []mo.HostSystem
var network []mo.Network
var opaque []mo.OpaqueNetwork
var dvp []mo.DistributedVirtualPortgroup
var datastore []mo.Datastore
// Table to drive inflating refs to their mo.* counterparts (dest)
// and save() the Name to r.entities w/o using reflection here.
// Note that we cannot use a []mo.ManagedEntity here, since mo.Network has its own 'Name' field,
// the mo.Network.ManagedEntity.Name field will not be set.
vrefs := map[string]*struct {
dest interface{}
refs []types.ManagedObjectReference
save func()
}{
"HostSystem": {
&host, nil, func() {
for _, e := range host {
r.entities[e.Reference()] = e.Name
}
},
},
"Network": {
&network, nil, func() {
for _, e := range network {
r.entities[e.Reference()] = e.Name
}
},
},
"OpaqueNetwork": {
&opaque, nil, func() {
for _, e := range opaque {
r.entities[e.Reference()] = e.Name
}
},
},
"DistributedVirtualPortgroup": {
&dvp, nil, func() {
for _, e := range dvp {
r.entities[e.Reference()] = e.Name
}
},
},
"Datastore": {
&datastore, nil, func() {
for _, e := range datastore {
r.entities[e.Reference()] = e.Name
}
},
},
}
xrefs := make(map[types.ManagedObjectReference]bool)
// Add MOR to vrefs[kind].refs avoiding any duplicates.
addRef := func(refs ...types.ManagedObjectReference) {
for _, ref := range refs {
if _, exists := xrefs[ref]; exists {
return
}
xrefs[ref] = true
vref := vrefs[ref.Type]
vref.refs = append(vref.refs, ref)
}
}
for _, vm := range r.VirtualMachines {
if r.cmd.General {
if ref := vm.Summary.Runtime.Host; ref != nil {
addRef(*ref)
}
}
if r.cmd.Resources {
addRef(vm.Datastore...)
addRef(vm.Network...)
}
}
for _, vref := range vrefs {
if vref.refs == nil {
continue
}
err := pc.Retrieve(ctx, vref.refs, []string{"name"}, vref.dest)
if err != nil {
return err
}
vref.save()
}
return nil
}
func (r *infoResult) entityNames(refs []types.ManagedObjectReference) string {
var names []string
for _, ref := range refs {
names = append(names, r.entities[ref])
}
return strings.Join(names, ", ")
}
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.VirtualMachine, len(r.VirtualMachines))
for _, o := range r.VirtualMachines {
objects[o.Reference()] = o
}
tw := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0)
for _, o := range r.objects {
vm := objects[o.Reference()]
s := vm.Summary
fmt.Fprintf(tw, "Name:\t%s\n", s.Config.Name)
if r.cmd.General {
hostName := "<unavailable>"
if href := vm.Summary.Runtime.Host; href != nil {
if name, ok := r.entities[*href]; ok {
hostName = name
}
}
fmt.Fprintf(tw, " Path:\t%s\n", o.InventoryPath)
fmt.Fprintf(tw, " UUID:\t%s\n", s.Config.Uuid)
fmt.Fprintf(tw, " Guest name:\t%s\n", s.Config.GuestFullName)
fmt.Fprintf(tw, " Memory:\t%dMB\n", s.Config.MemorySizeMB)
fmt.Fprintf(tw, " CPU:\t%d vCPU(s)\n", s.Config.NumCpu)
fmt.Fprintf(tw, " Power state:\t%s\n", s.Runtime.PowerState)
fmt.Fprintf(tw, " Boot time:\t%s\n", s.Runtime.BootTime)
fmt.Fprintf(tw, " IP address:\t%s\n", s.Guest.IpAddress)
fmt.Fprintf(tw, " Host:\t%s\n", hostName)
}
if r.cmd.Resources {
if s.Storage == nil {
s.Storage = new(types.VirtualMachineStorageSummary)
}
fmt.Fprintf(tw, " CPU usage:\t%dMHz\n", s.QuickStats.OverallCpuUsage)
fmt.Fprintf(tw, " Host memory usage:\t%dMB\n", s.QuickStats.HostMemoryUsage)
fmt.Fprintf(tw, " Guest memory usage:\t%dMB\n", s.QuickStats.GuestMemoryUsage)
fmt.Fprintf(tw, " Storage uncommitted:\t%s\n", units.ByteSize(s.Storage.Uncommitted))
fmt.Fprintf(tw, " Storage committed:\t%s\n", units.ByteSize(s.Storage.Committed))
fmt.Fprintf(tw, " Storage unshared:\t%s\n", units.ByteSize(s.Storage.Unshared))
fmt.Fprintf(tw, " Storage:\t%s\n", r.entityNames(vm.Datastore))
fmt.Fprintf(tw, " Network:\t%s\n", r.entityNames(vm.Network))
}
if r.cmd.ExtraConfig {
fmt.Fprintf(tw, " ExtraConfig:\n")
for _, v := range vm.Config.ExtraConfig {
fmt.Fprintf(tw, " %s:\t%s\n", v.GetOptionValue().Key, v.GetOptionValue().Value)
}
}
if r.cmd.ToolsConfigInfo {
t := vm.Config.Tools
fmt.Fprintf(tw, " ToolsConfigInfo:\n")
fmt.Fprintf(tw, " ToolsVersion:\t%d\n", t.ToolsVersion)
fmt.Fprintf(tw, " AfterPowerOn:\t%s\n", flags.NewOptionalBool(&t.AfterPowerOn).String())
fmt.Fprintf(tw, " AfterResume:\t%s\n", flags.NewOptionalBool(&t.AfterResume).String())
fmt.Fprintf(tw, " BeforeGuestStandby:\t%s\n", flags.NewOptionalBool(&t.BeforeGuestStandby).String())
fmt.Fprintf(tw, " BeforeGuestShutdown:\t%s\n", flags.NewOptionalBool(&t.BeforeGuestShutdown).String())
fmt.Fprintf(tw, " BeforeGuestReboot:\t%s\n", flags.NewOptionalBool(&t.BeforeGuestReboot).String())
fmt.Fprintf(tw, " ToolsUpgradePolicy:\t%s\n", t.ToolsUpgradePolicy)
fmt.Fprintf(tw, " PendingCustomization:\t%s\n", t.PendingCustomization)
fmt.Fprintf(tw, " SyncTimeWithHost:\t%s\n", flags.NewOptionalBool(&t.SyncTimeWithHost).String())
}
}
return tw.Flush()
}

250
vendor/github.com/vmware/govmomi/cli/vm/instantclone.go generated vendored Normal file
View file

@ -0,0 +1,250 @@
/*
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/cli"
"github.com/vmware/govmomi/cli/flags"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/types"
)
type instantclone struct {
*flags.ClientFlag
*flags.DatacenterFlag
*flags.DatastoreFlag
*flags.ResourcePoolFlag
*flags.NetworkFlag
*flags.FolderFlag
*flags.VirtualMachineFlag
name string
extraConfig extraConfig
Client *vim25.Client
Datacenter *object.Datacenter
Datastore *object.Datastore
ResourcePool *object.ResourcePool
Folder *object.Folder
VirtualMachine *object.VirtualMachine
}
func init() {
cli.Register("vm.instantclone", &instantclone{})
}
func (cmd *instantclone) Register(ctx context.Context, f *flag.FlagSet) {
cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
cmd.ClientFlag.Register(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.ResourcePoolFlag, ctx = flags.NewResourcePoolFlag(ctx)
cmd.ResourcePoolFlag.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.Var(&cmd.extraConfig, "e", "ExtraConfig. <key>=<value>")
}
func (cmd *instantclone) Usage() string {
return "NAME"
}
func (cmd *instantclone) Description() string {
return `Instant Clone VM to NAME.
Examples:
govc vm.instantclone -vm source-vm new-vm
# Configure ExtraConfig variables on a guest VM:
govc vm.instantclone -vm source-vm -e guestinfo.ipaddress=192.168.0.1 -e guestinfo.netmask=255.255.255.0 new-vm
# Read the variable set above inside the guest:
vmware-rpctool "info-get guestinfo.ipaddress"
vmware-rpctool "info-get guestinfo.netmask"`
}
func (cmd *instantclone) Process(ctx context.Context) error {
if err := cmd.ClientFlag.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.ResourcePoolFlag.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 *instantclone) 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.Datacenter, err = cmd.DatacenterFlag.Datacenter()
if err != nil {
return err
}
cmd.Datastore, err = cmd.DatastoreFlag.Datastore()
if err != nil {
return err
}
cmd.Folder, err = cmd.FolderFlag.Folder()
if err != nil {
return err
}
cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePool()
if err != nil {
return err
}
cmd.VirtualMachine, err = cmd.VirtualMachineFlag.VirtualMachine()
if err != nil {
return err
}
if cmd.VirtualMachine == nil {
return flag.ErrHelp
}
_, err = cmd.instantcloneVM(ctx)
if err != nil {
return err
}
return nil
}
func (cmd *instantclone) instantcloneVM(ctx context.Context) (*object.VirtualMachine, error) {
relocateSpec := types.VirtualMachineRelocateSpec{}
if cmd.NetworkFlag.IsSet() {
devices, err := cmd.VirtualMachine.Device(ctx)
if err != nil {
return nil, err
}
// prepare virtual device config spec for network card
configSpecs := []types.BaseVirtualDeviceConfigSpec{}
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,
})
relocateSpec.DeviceChange = configSpecs
}
if cmd.FolderFlag.IsSet() {
folderref := cmd.Folder.Reference()
relocateSpec.Folder = &folderref
}
if cmd.ResourcePoolFlag.IsSet() {
poolref := cmd.ResourcePool.Reference()
relocateSpec.Pool = &poolref
}
if cmd.DatastoreFlag.IsSet() {
datastoreref := cmd.Datastore.Reference()
relocateSpec.Datastore = &datastoreref
}
instantcloneSpec := &types.VirtualMachineInstantCloneSpec{
Name: cmd.name,
Location: relocateSpec,
}
if len(cmd.extraConfig) > 0 {
instantcloneSpec.Config = cmd.extraConfig
}
task, err := cmd.VirtualMachine.InstantClone(ctx, *instantcloneSpec)
if err != nil {
return nil, err
}
logger := cmd.ProgressLogger(fmt.Sprintf("Instant 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
}

192
vendor/github.com/vmware/govmomi/cli/vm/ip.go generated vendored Normal file
View file

@ -0,0 +1,192 @@
/*
Copyright (c) 2014-2023 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"
"time"
"github.com/vmware/govmomi/cli"
"github.com/vmware/govmomi/cli/esx"
"github.com/vmware/govmomi/cli/flags"
"github.com/vmware/govmomi/object"
)
type ip struct {
*flags.OutputFlag
*flags.SearchFlag
esx bool
all bool
v4 bool
wait time.Duration
nic string
}
func init() {
cli.Register("vm.ip", &ip{})
}
func (cmd *ip) Register(ctx context.Context, f *flag.FlagSet) {
cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
cmd.OutputFlag.Register(ctx, f)
cmd.SearchFlag, ctx = flags.NewSearchFlag(ctx, flags.SearchVirtualMachines)
cmd.SearchFlag.Register(ctx, f)
f.BoolVar(&cmd.esx, "esxcli", false, "Use esxcli instead of guest tools")
f.BoolVar(&cmd.all, "a", false, "Wait for an IP address on all NICs")
f.StringVar(&cmd.nic, "n", "", "Wait for IP address on NIC, specified by device name or MAC")
f.BoolVar(&cmd.v4, "v4", false, "Only report IPv4 addresses")
f.DurationVar(&cmd.wait, "wait", time.Hour, "Wait time for the VM obtain an IP address")
}
func (cmd *ip) Usage() string {
return "VM..."
}
func (cmd *ip) Description() string {
return `List IPs for VM.
By default the vm.ip command depends on vmware-tools to report the 'guest.ipAddress' field and will
wait until it has done so. This value can also be obtained using:
govc vm.info -json $vm | jq -r .virtualMachines[].guest.ipAddress
When given the '-a' flag, only IP addresses for which there is a corresponding virtual nic are listed.
If there are multiple nics, the listed addresses will be comma delimited. The '-a' flag depends on
vmware-tools to report the 'guest.net' field and will wait until it has done so for all nics.
Note that this list includes IPv6 addresses if any, use '-v4' to filter them out. IP addresses reported
by tools for which there is no virtual nic are not included, for example that of the 'docker0' interface.
These values can also be obtained using:
govc vm.info -json $vm | jq -r .virtualMachines[].guest.net[].ipConfig.ipAddress[].ipAddress
When given the '-n' flag, filters '-a' behavior to the nic specified by MAC address or device name.
The 'esxcli' flag does not require vmware-tools to be installed, but does require the ESX host to
have the /Net/GuestIPHack setting enabled.
The 'wait' flag default to 1hr (original default was infinite). If a VM does not obtain an IP within
the wait time, the command will still exit with status 0.
Examples:
govc vm.ip $vm
govc vm.ip -wait 5m $vm
govc vm.ip -a -v4 $vm
govc vm.ip -n 00:0c:29:57:7b:c3 $vm
govc vm.ip -n ethernet-0 $vm
govc host.esxcli system settings advanced set -o /Net/GuestIPHack -i 1
govc vm.ip -esxcli $vm`
}
func (cmd *ip) Process(ctx context.Context) error {
if err := cmd.OutputFlag.Process(ctx); err != nil {
return err
}
if err := cmd.SearchFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *ip) Run(ctx context.Context, f *flag.FlagSet) error {
c, err := cmd.Client()
if err != nil {
return err
}
vms, err := cmd.VirtualMachines(f.Args())
if err != nil {
return err
}
var get func(*object.VirtualMachine, context.Context) (string, error)
if cmd.esx {
get = func(vm *object.VirtualMachine, deadline context.Context) (string, error) {
guest := esx.NewGuestInfo(c)
ticker := time.NewTicker(time.Millisecond * 500)
defer ticker.Stop()
for {
select {
case <-ticker.C:
ip, err := guest.IpAddress(ctx, vm)
if err != nil {
return "", err
}
if ip != "0.0.0.0" {
return ip, nil
}
case <-deadline.Done():
return "", nil
}
}
}
} else {
var hwaddr []string
if cmd.nic != "" {
hwaddr = strings.Split(cmd.nic, ",")
}
get = func(vm *object.VirtualMachine, deadline context.Context) (string, error) {
if cmd.all || hwaddr != nil {
macs, err := vm.WaitForNetIP(deadline, cmd.v4, hwaddr...)
if err != nil {
return "", err
}
var ips []string
for _, addrs := range macs {
ips = append(ips, addrs...)
}
return strings.Join(ips, ","), nil
}
return vm.WaitForIP(deadline, cmd.v4)
}
}
for _, vm := range vms {
deadline, cancel := context.WithDeadline(ctx, time.Now().Add(cmd.wait))
ip, err := get(vm, deadline)
if err != nil {
if deadline.Err() != context.DeadlineExceeded {
cancel()
return err
}
}
cancel()
if ip == "" {
continue
}
// TODO(PN): Display inventory path to VM
fmt.Fprintf(cmd, "%s\n", ip)
}
return nil
}

710
vendor/github.com/vmware/govmomi/cli/vm/keystrokes.go generated vendored Normal file
View file

@ -0,0 +1,710 @@
/*
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"
"sort"
"strconv"
"strings"
"github.com/vmware/govmomi/cli"
"github.com/vmware/govmomi/cli/flags"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/types"
)
type hidKey struct {
Code int32
ShiftPressed bool
}
// stolen from
// https://gist.github.com/MightyPork/6da26e382a7ad91b5496ee55fdc73db2#file-usb_hid_keys-h-L110
const (
KEY_MOD_LCTRL = 0x01
KEY_MOD_LSHIFT = 0x02
KEY_MOD_LALT = 0x04
KEY_MOD_LMETA = 0x08
KEY_MOD_RCTRL = 0x10
KEY_MOD_RSHIFT = 0x20
KEY_MOD_RALT = 0x40
KEY_MOD_RMETA = 0x80
KEY_NONE = 0x00
KEY_ERR_OVF = 0x01
KEY_A = 0x04
KEY_B = 0x05
KEY_C = 0x06
KEY_D = 0x07
KEY_E = 0x08
KEY_F = 0x09
KEY_G = 0x0a
KEY_H = 0x0b
KEY_I = 0x0c
KEY_J = 0x0d
KEY_K = 0x0e
KEY_L = 0x0f
KEY_M = 0x10
KEY_N = 0x11
KEY_O = 0x12
KEY_P = 0x13
KEY_Q = 0x14
KEY_R = 0x15
KEY_S = 0x16
KEY_T = 0x17
KEY_U = 0x18
KEY_V = 0x19
KEY_W = 0x1a
KEY_X = 0x1b
KEY_Y = 0x1c
KEY_Z = 0x1d
KEY_1 = 0x1e
KEY_2 = 0x1f
KEY_3 = 0x20
KEY_4 = 0x21
KEY_5 = 0x22
KEY_6 = 0x23
KEY_7 = 0x24
KEY_8 = 0x25
KEY_9 = 0x26
KEY_0 = 0x27
KEY_ENTER = 0x28
KEY_ESC = 0x29
KEY_BACKSPACE = 0x2a
KEY_TAB = 0x2b
KEY_SPACE = 0x2c
KEY_MINUS = 0x2d
KEY_EQUAL = 0x2e
KEY_LEFTBRACE = 0x2f
KEY_RIGHTBRACE = 0x30
KEY_BACKSLASH = 0x31
KEY_HASHTILDE = 0x32
KEY_SEMICOLON = 0x33
KEY_APOSTROPHE = 0x34
KEY_GRAVE = 0x35
KEY_COMMA = 0x36
KEY_DOT = 0x37
KEY_SLASH = 0x38
KEY_CAPSLOCK = 0x39
KEY_F1 = 0x3a
KEY_F2 = 0x3b
KEY_F3 = 0x3c
KEY_F4 = 0x3d
KEY_F5 = 0x3e
KEY_F6 = 0x3f
KEY_F7 = 0x40
KEY_F8 = 0x41
KEY_F9 = 0x42
KEY_F10 = 0x43
KEY_F11 = 0x44
KEY_F12 = 0x45
KEY_SYSRQ = 0x46
KEY_SCROLLLOCK = 0x47
KEY_PAUSE = 0x48
KEY_INSERT = 0x49
KEY_HOME = 0x4a
KEY_PAGEUP = 0x4b
KEY_DELETE = 0x4c
KEY_END = 0x4d
KEY_PAGEDOWN = 0x4e
KEY_RIGHT = 0x4f
KEY_LEFT = 0x50
KEY_DOWN = 0x51
KEY_UP = 0x52
KEY_NUMLOCK = 0x53
KEY_KPSLASH = 0x54
KEY_KPASTERISK = 0x55
KEY_KPMINUS = 0x56
KEY_KPPLUS = 0x57
KEY_KPENTER = 0x58
KEY_KP1 = 0x59
KEY_KP2 = 0x5a
KEY_KP3 = 0x5b
KEY_KP4 = 0x5c
KEY_KP5 = 0x5d
KEY_KP6 = 0x5e
KEY_KP7 = 0x5f
KEY_KP8 = 0x60
KEY_KP9 = 0x61
KEY_KP0 = 0x62
KEY_KPDOT = 0x63
KEY_102ND = 0x64
KEY_COMPOSE = 0x65
KEY_POWER = 0x66
KEY_KPEQUAL = 0x67
KEY_F13 = 0x68
KEY_F14 = 0x69
KEY_F15 = 0x6a
KEY_F16 = 0x6b
KEY_F17 = 0x6c
KEY_F18 = 0x6d
KEY_F19 = 0x6e
KEY_F20 = 0x6f
KEY_F21 = 0x70
KEY_F22 = 0x71
KEY_F23 = 0x72
KEY_F24 = 0x73
KEY_OPEN = 0x74
KEY_HELP = 0x75
KEY_PROPS = 0x76
KEY_FRONT = 0x77
KEY_STOP = 0x78
KEY_AGAIN = 0x79
KEY_UNDO = 0x7a
KEY_CUT = 0x7b
KEY_COPY = 0x7c
KEY_PASTE = 0x7d
KEY_FIND = 0x7e
KEY_MUTE = 0x7f
KEY_VOLUMEUP = 0x80
KEY_VOLUMEDOWN = 0x81
KEY_KPCOMMA = 0x85
KEY_RO = 0x87
KEY_KATAKANAHIRAGANA = 0x88
KEY_YEN = 0x89
KEY_HENKAN = 0x8a
KEY_MUHENKAN = 0x8b
KEY_KPJPCOMMA = 0x8c
KEY_HANGEUL = 0x90
KEY_HANJA = 0x91
KEY_KATAKANA = 0x92
KEY_HIRAGANA = 0x93
KEY_ZENKAKUHANKAKU = 0x94
KEY_KPLEFTPAREN = 0xb6
KEY_KPRIGHTPAREN = 0xb7
KEY_LEFTCTRL = 0xe0
KEY_LEFTSHIFT = 0xe1
KEY_LEFTALT = 0xe2
KEY_LEFTMETA = 0xe3
KEY_RIGHTCTRL = 0xe4
KEY_RIGHTSHIFT = 0xe5
KEY_RIGHTALT = 0xe6
KEY_RIGHTMETA = 0xe7
KEY_MEDIA_PLAYPAUSE = 0xe8
KEY_MEDIA_STOPCD = 0xe9
KEY_MEDIA_PREVIOUSSONG = 0xea
KEY_MEDIA_NEXTSONG = 0xeb
KEY_MEDIA_EJECTCD = 0xec
KEY_MEDIA_VOLUMEUP = 0xed
KEY_MEDIA_VOLUMEDOWN = 0xee
KEY_MEDIA_MUTE = 0xef
KEY_MEDIA_WWW = 0xf0
KEY_MEDIA_BACK = 0xf1
KEY_MEDIA_FORWARD = 0xf2
KEY_MEDIA_STOP = 0xf3
KEY_MEDIA_FIND = 0xf4
KEY_MEDIA_SCROLLUP = 0xf5
KEY_MEDIA_SCROLLDOWN = 0xf6
KEY_MEDIA_EDIT = 0xf7
KEY_MEDIA_SLEEP = 0xf8
KEY_MEDIA_COFFEE = 0xf9
KEY_MEDIA_REFRESH = 0xfa
KEY_MEDIA_CALC = 0xfb
)
var hidKeyMap = map[string]int32{
"KEY_MOD_LCTRL": KEY_MOD_LCTRL,
"KEY_MOD_LSHIFT": KEY_MOD_LSHIFT,
"KEY_MOD_LALT": KEY_MOD_LALT,
"KEY_MOD_LMETA": KEY_MOD_LMETA,
"KEY_MOD_RCTRL": KEY_MOD_RCTRL,
"KEY_MOD_RSHIFT": KEY_MOD_RSHIFT,
"KEY_MOD_RALT": KEY_MOD_RALT,
"KEY_MOD_RMETA": KEY_MOD_RMETA,
"KEY_NONE": KEY_NONE,
"KEY_ERR_OVF": KEY_ERR_OVF,
"KEY_A": KEY_A,
"KEY_B": KEY_B,
"KEY_C": KEY_C,
"KEY_D": KEY_D,
"KEY_E": KEY_E,
"KEY_F": KEY_F,
"KEY_G": KEY_G,
"KEY_H": KEY_H,
"KEY_I": KEY_I,
"KEY_J": KEY_J,
"KEY_K": KEY_K,
"KEY_L": KEY_L,
"KEY_M": KEY_M,
"KEY_N": KEY_N,
"KEY_O": KEY_O,
"KEY_P": KEY_P,
"KEY_Q": KEY_Q,
"KEY_R": KEY_R,
"KEY_S": KEY_S,
"KEY_T": KEY_T,
"KEY_U": KEY_U,
"KEY_V": KEY_V,
"KEY_W": KEY_W,
"KEY_X": KEY_X,
"KEY_Y": KEY_Y,
"KEY_Z": KEY_Z,
"KEY_1": KEY_1,
"KEY_2": KEY_2,
"KEY_3": KEY_3,
"KEY_4": KEY_4,
"KEY_5": KEY_5,
"KEY_6": KEY_6,
"KEY_7": KEY_7,
"KEY_8": KEY_8,
"KEY_9": KEY_9,
"KEY_0": KEY_0,
"KEY_ENTER": KEY_ENTER,
"KEY_ESC": KEY_ESC,
"KEY_BACKSPACE": KEY_BACKSPACE,
"KEY_TAB": KEY_TAB,
"KEY_SPACE": KEY_SPACE,
"KEY_MINUS": KEY_MINUS,
"KEY_EQUAL": KEY_EQUAL,
"KEY_LEFTBRACE": KEY_LEFTBRACE,
"KEY_RIGHTBRACE": KEY_RIGHTBRACE,
"KEY_BACKSLASH": KEY_BACKSLASH,
"KEY_HASHTILDE": KEY_HASHTILDE,
"KEY_SEMICOLON": KEY_SEMICOLON,
"KEY_APOSTROPHE": KEY_APOSTROPHE,
"KEY_GRAVE": KEY_GRAVE,
"KEY_COMMA": KEY_COMMA,
"KEY_DOT": KEY_DOT,
"KEY_SLASH": KEY_SLASH,
"KEY_CAPSLOCK": KEY_CAPSLOCK,
"KEY_F1": KEY_F1,
"KEY_F2": KEY_F2,
"KEY_F3": KEY_F3,
"KEY_F4": KEY_F4,
"KEY_F5": KEY_F5,
"KEY_F6": KEY_F6,
"KEY_F7": KEY_F7,
"KEY_F8": KEY_F8,
"KEY_F9": KEY_F9,
"KEY_F10": KEY_F10,
"KEY_F11": KEY_F11,
"KEY_F12": KEY_F12,
"KEY_SYSRQ": KEY_SYSRQ,
"KEY_SCROLLLOCK": KEY_SCROLLLOCK,
"KEY_PAUSE": KEY_PAUSE,
"KEY_INSERT": KEY_INSERT,
"KEY_HOME": KEY_HOME,
"KEY_PAGEUP": KEY_PAGEUP,
"KEY_DELETE": KEY_DELETE,
"KEY_END": KEY_END,
"KEY_PAGEDOWN": KEY_PAGEDOWN,
"KEY_RIGHT": KEY_RIGHT,
"KEY_LEFT": KEY_LEFT,
"KEY_DOWN": KEY_DOWN,
"KEY_UP": KEY_UP,
"KEY_NUMLOCK": KEY_NUMLOCK,
"KEY_KPSLASH": KEY_KPSLASH,
"KEY_KPASTERISK": KEY_KPASTERISK,
"KEY_KPMINUS": KEY_KPMINUS,
"KEY_KPPLUS": KEY_KPPLUS,
"KEY_KPENTER": KEY_KPENTER,
"KEY_KP1": KEY_KP1,
"KEY_KP2": KEY_KP2,
"KEY_KP3": KEY_KP3,
"KEY_KP4": KEY_KP4,
"KEY_KP5": KEY_KP5,
"KEY_KP6": KEY_KP6,
"KEY_KP7": KEY_KP7,
"KEY_KP8": KEY_KP8,
"KEY_KP9": KEY_KP9,
"KEY_KP0": KEY_KP0,
"KEY_KPDOT": KEY_KPDOT,
"KEY_102ND": KEY_102ND,
"KEY_COMPOSE": KEY_COMPOSE,
"KEY_POWER": KEY_POWER,
"KEY_KPEQUAL": KEY_KPEQUAL,
"KEY_F13": KEY_F13,
"KEY_F14": KEY_F14,
"KEY_F15": KEY_F15,
"KEY_F16": KEY_F16,
"KEY_F17": KEY_F17,
"KEY_F18": KEY_F18,
"KEY_F19": KEY_F19,
"KEY_F20": KEY_F20,
"KEY_F21": KEY_F21,
"KEY_F22": KEY_F22,
"KEY_F23": KEY_F23,
"KEY_F24": KEY_F24,
"KEY_OPEN": KEY_OPEN,
"KEY_HELP": KEY_HELP,
"KEY_PROPS": KEY_PROPS,
"KEY_FRONT": KEY_FRONT,
"KEY_STOP": KEY_STOP,
"KEY_AGAIN": KEY_AGAIN,
"KEY_UNDO": KEY_UNDO,
"KEY_CUT": KEY_CUT,
"KEY_COPY": KEY_COPY,
"KEY_PASTE": KEY_PASTE,
"KEY_FIND": KEY_FIND,
"KEY_MUTE": KEY_MUTE,
"KEY_VOLUMEUP": KEY_VOLUMEUP,
"KEY_VOLUMEDOWN": KEY_VOLUMEDOWN,
"KEY_KPCOMMA": KEY_KPCOMMA,
"KEY_RO": KEY_RO,
"KEY_KATAKANAHIRAGANA": KEY_KATAKANAHIRAGANA,
"KEY_YEN": KEY_YEN,
"KEY_HENKAN": KEY_HENKAN,
"KEY_MUHENKAN": KEY_MUHENKAN,
"KEY_KPJPCOMMA": KEY_KPJPCOMMA,
"KEY_HANGEUL": KEY_HANGEUL,
"KEY_HANJA": KEY_HANJA,
"KEY_KATAKANA": KEY_KATAKANA,
"KEY_HIRAGANA": KEY_HIRAGANA,
"KEY_ZENKAKUHANKAKU": KEY_ZENKAKUHANKAKU,
"KEY_KPLEFTPAREN": KEY_KPLEFTPAREN,
"KEY_KPRIGHTPAREN": KEY_KPRIGHTPAREN,
"KEY_LEFTCTRL": KEY_LEFTCTRL,
"KEY_LEFTSHIFT": KEY_LEFTSHIFT,
"KEY_LEFTALT": KEY_LEFTALT,
"KEY_LEFTMETA": KEY_LEFTMETA,
"KEY_RIGHTCTRL": KEY_RIGHTCTRL,
"KEY_RIGHTSHIFT": KEY_RIGHTSHIFT,
"KEY_RIGHTALT": KEY_RIGHTALT,
"KEY_RIGHTMETA": KEY_RIGHTMETA,
"KEY_MEDIA_PLAYPAUSE": KEY_MEDIA_PLAYPAUSE,
"KEY_MEDIA_STOPCD": KEY_MEDIA_STOPCD,
"KEY_MEDIA_PREVIOUSSONG": KEY_MEDIA_PREVIOUSSONG,
"KEY_MEDIA_NEXTSONG": KEY_MEDIA_NEXTSONG,
"KEY_MEDIA_EJECTCD": KEY_MEDIA_EJECTCD,
"KEY_MEDIA_VOLUMEUP": KEY_MEDIA_VOLUMEUP,
"KEY_MEDIA_VOLUMEDOWN": KEY_MEDIA_VOLUMEDOWN,
"KEY_MEDIA_MUTE": KEY_MEDIA_MUTE,
"KEY_MEDIA_WWW": KEY_MEDIA_WWW,
"KEY_MEDIA_BACK": KEY_MEDIA_BACK,
"KEY_MEDIA_FORWARD": KEY_MEDIA_FORWARD,
"KEY_MEDIA_STOP": KEY_MEDIA_STOP,
"KEY_MEDIA_FIND": KEY_MEDIA_FIND,
"KEY_MEDIA_SCROLLUP": KEY_MEDIA_SCROLLUP,
"KEY_MEDIA_SCROLLDOWN": KEY_MEDIA_SCROLLDOWN,
"KEY_MEDIA_EDIT": KEY_MEDIA_EDIT,
"KEY_MEDIA_SLEEP": KEY_MEDIA_SLEEP,
"KEY_MEDIA_COFFEE": KEY_MEDIA_COFFEE,
"KEY_MEDIA_REFRESH": KEY_MEDIA_REFRESH,
"KEY_MEDIA_CALC": KEY_MEDIA_CALC,
}
var hidCharacterMap = map[string]hidKey{
"a": {KEY_A, false},
"b": {KEY_B, false},
"c": {KEY_C, false},
"d": {KEY_D, false},
"e": {KEY_E, false},
"f": {KEY_F, false},
"g": {KEY_G, false},
"h": {KEY_H, false},
"i": {KEY_I, false},
"j": {KEY_J, false},
"k": {KEY_K, false},
"l": {KEY_L, false},
"m": {KEY_M, false},
"n": {KEY_N, false},
"o": {KEY_O, false},
"p": {KEY_P, false},
"q": {KEY_Q, false},
"r": {KEY_R, false},
"s": {KEY_S, false},
"t": {KEY_T, false},
"u": {KEY_U, false},
"v": {KEY_V, false},
"w": {KEY_W, false},
"x": {KEY_X, false},
"y": {KEY_Y, false},
"z": {KEY_Z, false},
"1": {KEY_1, false},
"2": {KEY_2, false},
"3": {KEY_3, false},
"4": {KEY_4, false},
"5": {KEY_5, false},
"6": {KEY_6, false},
"7": {KEY_7, false},
"8": {KEY_8, false},
"9": {KEY_9, false},
"0": {KEY_0, false},
"A": {KEY_A, true},
"B": {KEY_B, true},
"C": {KEY_C, true},
"D": {KEY_D, true},
"E": {KEY_E, true},
"F": {KEY_F, true},
"G": {KEY_G, true},
"H": {KEY_H, true},
"I": {KEY_I, true},
"J": {KEY_J, true},
"K": {KEY_K, true},
"L": {KEY_L, true},
"M": {KEY_M, true},
"N": {KEY_N, true},
"O": {KEY_O, true},
"P": {KEY_P, true},
"Q": {KEY_Q, true},
"R": {KEY_R, true},
"S": {KEY_S, true},
"T": {KEY_T, true},
"U": {KEY_U, true},
"V": {KEY_V, true},
"W": {KEY_W, true},
"X": {KEY_X, true},
"Y": {KEY_Y, true},
"Z": {KEY_Z, true},
"!": {KEY_1, true},
"@": {KEY_2, true},
"#": {KEY_3, true},
"$": {KEY_4, true},
"%": {KEY_5, true},
"^": {KEY_6, true},
"&": {KEY_7, true},
"*": {KEY_8, true},
"(": {KEY_9, true},
")": {KEY_0, true},
" ": {KEY_SPACE, false},
"-": {KEY_MINUS, false},
"_": {KEY_MINUS, true},
"=": {KEY_EQUAL, false},
"+": {KEY_EQUAL, true},
"[": {KEY_LEFTBRACE, false},
"{": {KEY_LEFTBRACE, true},
"]": {KEY_RIGHTBRACE, false},
"}": {KEY_RIGHTBRACE, true},
`\`: {KEY_BACKSLASH, false},
"|": {KEY_BACKSLASH, true},
";": {KEY_SEMICOLON, false},
":": {KEY_SEMICOLON, true},
"'": {KEY_APOSTROPHE, false},
`"`: {KEY_APOSTROPHE, true},
"`": {KEY_GRAVE, false},
"~": {KEY_GRAVE, true},
",": {KEY_COMMA, false},
"<": {KEY_COMMA, true},
".": {KEY_DOT, false},
">": {KEY_DOT, true},
"/": {KEY_SLASH, false},
"?": {KEY_SLASH, true},
}
type keystrokes struct {
*flags.VirtualMachineFlag
UsbHidCodeValue int32
UsbHidCodes string
UsbHidString string
LeftControl bool
LeftShift bool
LeftAlt bool
LeftGui bool
RightControl bool
RightShift bool
RightAlt bool
RightGui bool
}
func init() {
cli.Register("vm.keystrokes", &keystrokes{})
}
func (cmd *keystrokes) Register(ctx context.Context, f *flag.FlagSet) {
cmd.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx)
cmd.VirtualMachineFlag.Register(ctx, f)
f.StringVar(&cmd.UsbHidString, "s", "", "Raw String to Send")
f.StringVar(&cmd.UsbHidCodes, "c", "", "USB HID Codes (hex) or aliases, comma separated")
f.Var(flags.NewInt32(&cmd.UsbHidCodeValue), "r", "Raw USB HID Code Value (int32)")
f.BoolVar(&cmd.LeftControl, "lc", false, "Enable/Disable Left Control")
f.BoolVar(&cmd.LeftShift, "ls", false, "Enable/Disable Left Shift")
f.BoolVar(&cmd.LeftAlt, "la", false, "Enable/Disable Left Alt")
f.BoolVar(&cmd.LeftGui, "lg", false, "Enable/Disable Left Gui")
f.BoolVar(&cmd.RightControl, "rc", false, "Enable/Disable Right Control")
f.BoolVar(&cmd.RightShift, "rs", false, "Enable/Disable Right Shift")
f.BoolVar(&cmd.RightAlt, "ra", false, "Enable/Disable Right Alt")
f.BoolVar(&cmd.RightGui, "rg", false, "Enable/Disable Right Gui")
}
func (cmd *keystrokes) Usage() string {
return "VM"
}
func (cmd *keystrokes) Description() string {
description := `Send Keystrokes to VM.
Examples:
Default Scenario
govc vm.keystrokes -vm $vm -s "root" # writes 'root' to the console
govc vm.keystrokes -vm $vm -c 0x15 # writes an 'r' to the console
govc vm.keystrokes -vm $vm -r 1376263 # writes an 'r' to the console
govc vm.keystrokes -vm $vm -c 0x28 # presses ENTER on the console
govc vm.keystrokes -vm $vm -c 0x4c -la=true -lc=true # sends CTRL+ALT+DEL to console
govc vm.keystrokes -vm $vm -c 0x15,KEY_ENTER # writes an 'r' to the console and press ENTER
List of available aliases:
`
keys := make([]string, 0)
for key, _ := range hidKeyMap {
keys = append(keys, key)
}
sort.Strings(keys)
for i, key := range keys {
if i > 0 {
description += ", "
}
description += key
}
return description + "\n"
}
func (cmd *keystrokes) Process(ctx context.Context) error {
if err := cmd.VirtualMachineFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *keystrokes) Run(ctx context.Context, f *flag.FlagSet) error {
vm, err := cmd.VirtualMachine()
if err != nil {
return err
}
if vm == nil {
return flag.ErrHelp
}
err = cmd.processUserInput(ctx, vm)
if err != nil {
return err
}
return nil
}
func (cmd *keystrokes) processUserInput(ctx context.Context, vm *object.VirtualMachine) error {
if err := cmd.checkValidInputs(); err != nil {
return err
}
codes, err := cmd.processUsbCode()
if err != nil {
return err
}
var keyEventArray []types.UsbScanCodeSpecKeyEvent
for _, code := range codes {
leftShiftSetting := false
if code.ShiftPressed || cmd.LeftShift {
leftShiftSetting = true
}
modifiers := types.UsbScanCodeSpecModifierType{
LeftControl: &cmd.LeftControl,
LeftShift: &leftShiftSetting,
LeftAlt: &cmd.LeftAlt,
LeftGui: &cmd.LeftGui,
RightControl: &cmd.RightControl,
RightShift: &cmd.RightShift,
RightAlt: &cmd.RightAlt,
RightGui: &cmd.RightGui,
}
keyEvent := types.UsbScanCodeSpecKeyEvent{
UsbHidCode: code.Code,
Modifiers: &modifiers,
}
keyEventArray = append(keyEventArray, keyEvent)
}
spec := types.UsbScanCodeSpec{
KeyEvents: keyEventArray,
}
_, err = vm.PutUsbScanCodes(ctx, spec)
return err
}
func (cmd *keystrokes) processUsbCode() ([]hidKey, error) {
if cmd.rawCodeProvided() {
return []hidKey{{cmd.UsbHidCodeValue, false}}, nil
}
if cmd.hexCodeProvided() {
var retKeyArray []hidKey
for _, c := range strings.Split(cmd.UsbHidCodes, ",") {
var s int32
lookupvalue, ok := hidKeyMap[c]
if ok {
s = intToHidCode(lookupvalue)
} else {
var err error
s, err = hexStringToHidCode(c)
if err != nil {
return nil, err
}
}
retKeyArray = append(retKeyArray, hidKey{s, false})
}
return retKeyArray, nil
}
if cmd.stringProvided() {
var retKeyArray []hidKey
for _, c := range cmd.UsbHidString {
lookupValue, ok := hidCharacterMap[string(c)]
if !ok {
return nil, fmt.Errorf("invalid Character %s in String: %s", string(c), cmd.UsbHidString)
}
lookupValue.Code = intToHidCode(lookupValue.Code)
retKeyArray = append(retKeyArray, lookupValue)
}
return retKeyArray, nil
}
return nil, nil
}
func hexStringToHidCode(hex string) (int32, error) {
s, err := strconv.ParseInt(hex, 0, 32)
if err != nil {
return 0, err
}
return intToHidCode(int32(s)), nil
}
func intToHidCode(v int32) int32 {
var s int32 = v << 16
s |= 7
return s
}
func (cmd *keystrokes) checkValidInputs() error {
// poor man's boolean XOR -> A xor B xor C = A'BC' + AB'C' + A'B'C + ABC
if (!cmd.rawCodeProvided() && cmd.hexCodeProvided() && !cmd.stringProvided()) || // A'BC'
(cmd.rawCodeProvided() && !cmd.hexCodeProvided() && !cmd.stringProvided()) || // AB'C'
(!cmd.rawCodeProvided() && !cmd.hexCodeProvided() && cmd.stringProvided()) || // A'B'C
(cmd.rawCodeProvided() && cmd.hexCodeProvided() && cmd.stringProvided()) { // ABC
return nil
}
return fmt.Errorf("specify only 1 argument")
}
func (cmd keystrokes) rawCodeProvided() bool {
return cmd.UsbHidCodeValue != 0
}
func (cmd keystrokes) hexCodeProvided() bool {
return cmd.UsbHidCodes != ""
}
func (cmd keystrokes) stringProvided() bool {
return cmd.UsbHidString != ""
}

View file

@ -0,0 +1,72 @@
/*
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/cli"
"github.com/vmware/govmomi/cli/flags"
)
type markastemplate struct {
*flags.SearchFlag
}
func init() {
cli.Register("vm.markastemplate", &markastemplate{})
}
func (cmd *markastemplate) Register(ctx context.Context, f *flag.FlagSet) {
cmd.SearchFlag, ctx = flags.NewSearchFlag(ctx, flags.SearchVirtualMachines)
cmd.SearchFlag.Register(ctx, f)
}
func (cmd *markastemplate) Process(ctx context.Context) error {
if err := cmd.SearchFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *markastemplate) Usage() string {
return "VM..."
}
func (cmd *markastemplate) Description() string {
return `Mark VM as a virtual machine template.
Examples:
govc vm.markastemplate $name`
}
func (cmd *markastemplate) Run(ctx context.Context, f *flag.FlagSet) error {
vms, err := cmd.VirtualMachines(f.Args())
if err != nil {
return err
}
for _, vm := range vms {
err := vm.MarkAsTemplate(ctx)
if err != nil {
return err
}
}
return nil
}

106
vendor/github.com/vmware/govmomi/cli/vm/markasvm.go generated vendored Normal file
View file

@ -0,0 +1,106 @@
/*
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/cli"
"github.com/vmware/govmomi/cli/flags"
)
type markasvm struct {
*flags.SearchFlag
*flags.ResourcePoolFlag
*flags.HostSystemFlag
}
func init() {
cli.Register("vm.markasvm", &markasvm{})
}
func (cmd *markasvm) Register(ctx context.Context, f *flag.FlagSet) {
cmd.SearchFlag, ctx = flags.NewSearchFlag(ctx, flags.SearchVirtualMachines)
cmd.SearchFlag.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)
}
func (cmd *markasvm) Process(ctx context.Context) error {
if err := cmd.SearchFlag.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
}
return nil
}
func (cmd *markasvm) Usage() string {
return "VM..."
}
func (cmd *markasvm) Description() string {
return `Mark VM template as a virtual machine.
Examples:
govc vm.markasvm -host host1 $name
govc vm.markasvm -host host1 $name`
}
func (cmd *markasvm) Run(ctx context.Context, f *flag.FlagSet) error {
vms, err := cmd.VirtualMachines(f.Args())
if err != nil {
return err
}
pool, err := cmd.ResourcePoolIfSpecified()
if err != nil {
return err
}
host, err := cmd.HostSystemFlag.HostSystemIfSpecified()
if err != nil {
return err
}
if pool == nil {
if host == nil {
return flag.ErrHelp
}
pool, err = host.ResourcePool(ctx)
if err != nil {
return err
}
}
for _, vm := range vms {
err := vm.MarkAsVirtualMachine(ctx, *pool, host)
if err != nil {
return err
}
}
return nil
}

211
vendor/github.com/vmware/govmomi/cli/vm/migrate.go generated vendored Normal file
View file

@ -0,0 +1,211 @@
/*
Copyright (c) 2016-2024 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/cli"
"github.com/vmware/govmomi/cli/flags"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/types"
)
type migrate struct {
*flags.FolderFlag
*flags.ResourcePoolFlag
*flags.HostSystemFlag
*flags.DatastoreFlag
*flags.NetworkFlag
*flags.VirtualMachineFlag
priority types.VirtualMachineMovePriority
spec types.VirtualMachineRelocateSpec
}
func init() {
cli.Register("vm.migrate", &migrate{})
}
func (cmd *migrate) Register(ctx context.Context, f *flag.FlagSet) {
cmd.FolderFlag, ctx = flags.NewFolderFlag(ctx)
cmd.FolderFlag.Register(ctx, f)
cmd.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx)
cmd.VirtualMachineFlag.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.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
cmd.DatastoreFlag.Register(ctx, f)
cmd.NetworkFlag, ctx = flags.NewNetworkFlag(ctx)
cmd.NetworkFlag.Register(ctx, f)
f.StringVar((*string)(&cmd.priority), "priority", string(types.VirtualMachineMovePriorityDefaultPriority), "The task priority")
}
func (cmd *migrate) Process(ctx context.Context) error {
if err := cmd.FolderFlag.Process(ctx); err != nil {
return err
}
if err := cmd.VirtualMachineFlag.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.DatastoreFlag.Process(ctx); err != nil {
return err
}
if err := cmd.NetworkFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *migrate) Usage() string {
return "VM..."
}
func (cmd *migrate) Description() string {
return `Migrates VM to a specific resource pool, host or datastore.
Examples:
govc vm.migrate -host another-host vm-1 vm-2 vm-3
govc vm.migrate -pool another-pool vm-1 vm-2 vm-3
govc vm.migrate -ds another-ds vm-1 vm-2 vm-3`
}
func (cmd *migrate) relocate(ctx context.Context, vm *object.VirtualMachine) error {
spec := cmd.spec
if cmd.NetworkFlag.IsSet() {
dev, err := cmd.NetworkFlag.Device()
if err != nil {
return err
}
devices, err := vm.Device(ctx)
if err != nil {
return err
}
net := devices.SelectByType((*types.VirtualEthernetCard)(nil))
if len(net) != 1 {
return fmt.Errorf("-net specified, but %s has %d nics", vm.Name(), len(net))
}
cmd.NetworkFlag.Change(net[0], dev)
spec.DeviceChange = append(spec.DeviceChange, &types.VirtualDeviceConfigSpec{
Device: net[0],
Operation: types.VirtualDeviceConfigSpecOperationEdit,
})
}
if cmd.VirtualMachineFlag.Spec {
return cmd.VirtualMachineFlag.WriteAny(spec)
}
task, err := vm.Relocate(ctx, spec, cmd.priority)
if err != nil {
return err
}
logger := cmd.DatastoreFlag.ProgressLogger(fmt.Sprintf("migrating %s... ", vm.Reference()))
_, err = task.WaitForResult(ctx, logger)
if err != nil {
return err
}
logger.Wait()
return nil
}
func (cmd *migrate) Run(ctx context.Context, f *flag.FlagSet) error {
vms, err := cmd.VirtualMachineFlag.VirtualMachines(f.Args())
if err != nil {
return err
}
folder, err := cmd.FolderIfSpecified()
if err != nil {
return err
}
if folder != nil {
ref := folder.Reference()
cmd.spec.Folder = &ref
}
host, err := cmd.HostSystemFlag.HostSystemIfSpecified()
if err != nil {
return err
}
if host != nil {
ref := host.Reference()
cmd.spec.Host = &ref
}
pool, err := cmd.ResourcePoolFlag.ResourcePoolIfSpecified()
if err != nil {
return err
}
if pool == nil && host != nil {
pool, err = host.ResourcePool(ctx)
if err != nil {
return err
}
}
if pool != nil {
ref := pool.Reference()
cmd.spec.Pool = &ref
}
ds, err := cmd.DatastoreFlag.DatastoreIfSpecified()
if err != nil {
return err
}
if ds != nil {
ref := ds.Reference()
cmd.spec.Datastore = &ref
}
for _, vm := range vms {
err = cmd.relocate(ctx, vm)
if err != nil {
return err
}
}
return nil
}

216
vendor/github.com/vmware/govmomi/cli/vm/power.go generated vendored Normal file
View file

@ -0,0 +1,216 @@
/*
Copyright (c) 2014-2024 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/cli"
"github.com/vmware/govmomi/cli/flags"
"github.com/vmware/govmomi/fault"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/types"
)
type power struct {
*flags.ClientFlag
*flags.SearchFlag
On bool
Off bool
Reset bool
Reboot bool
Shutdown bool
Standby bool
Suspend bool
Force bool
Multi bool
Wait bool
}
func init() {
cli.Register("vm.power", &power{})
}
func (cmd *power) 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)
f.BoolVar(&cmd.On, "on", false, "Power on")
f.BoolVar(&cmd.Off, "off", false, "Power off")
f.BoolVar(&cmd.Reset, "reset", false, "Power reset")
f.BoolVar(&cmd.Suspend, "suspend", false, "Power suspend")
f.BoolVar(&cmd.Reboot, "r", false, "Reboot guest")
f.BoolVar(&cmd.Shutdown, "s", false, "Shutdown guest")
f.BoolVar(&cmd.Standby, "standby", false, "Standby guest")
f.BoolVar(&cmd.Force, "force", false, "Force (ignore state error and hard shutdown/reboot if tools unavailable)")
f.BoolVar(&cmd.Multi, "M", false, "Use Datacenter.PowerOnMultiVM method instead of VirtualMachine.PowerOnVM")
f.BoolVar(&cmd.Wait, "wait", true, "Wait for the operation to complete")
}
func (cmd *power) Usage() string {
return "NAME..."
}
func (cmd *power) Description() string {
return `Invoke VM power operations.
Examples:
govc vm.power -on VM1 VM2 VM3
govc vm.power -on -M VM1 VM2 VM3
govc vm.power -off -force VM1`
}
func (cmd *power) 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
}
opts := []bool{cmd.On, cmd.Off, cmd.Reset, cmd.Suspend, cmd.Reboot, cmd.Shutdown, cmd.Standby}
selected := false
for _, opt := range opts {
if opt {
if selected {
return flag.ErrHelp
}
selected = opt
}
}
if !selected {
return flag.ErrHelp
}
return nil
}
func isToolsUnavailable(err error) bool {
return fault.Is(err, &types.ToolsUnavailable{})
}
// this is annoying, but the likely use cases for Datacenter.PowerOnVM outside of this command would
// use []types.ManagedObjectReference via ContainerView or field such as ResourcePool.Vm rather than the Finder.
func vmReferences(vms []*object.VirtualMachine) []types.ManagedObjectReference {
refs := make([]types.ManagedObjectReference, len(vms))
for i, vm := range vms {
refs[i] = vm.Reference()
}
return refs
}
func (cmd *power) Run(ctx context.Context, f *flag.FlagSet) error {
vms, err := cmd.VirtualMachines(f.Args())
if err != nil {
return err
}
if cmd.On && cmd.Multi {
dc, derr := cmd.Datacenter()
if derr != nil {
return derr
}
task, derr := dc.PowerOnVM(ctx, vmReferences(vms))
if derr != nil {
return derr
}
msg := fmt.Sprintf("Powering on %d VMs...", len(vms))
if task == nil {
// running against ESX
fmt.Fprintf(cmd, "%s OK\n", msg)
return nil
}
if cmd.Wait {
logger := cmd.ProgressLogger(msg)
defer logger.Wait()
_, err = task.WaitForResult(ctx, logger)
return err
}
}
for _, vm := range vms {
var task *object.Task
switch {
case cmd.On:
fmt.Fprintf(cmd, "Powering on %s... ", vm.Reference())
task, err = vm.PowerOn(ctx)
case cmd.Off:
fmt.Fprintf(cmd, "Powering off %s... ", vm.Reference())
task, err = vm.PowerOff(ctx)
case cmd.Reset:
fmt.Fprintf(cmd, "Reset %s... ", vm.Reference())
task, err = vm.Reset(ctx)
case cmd.Suspend:
fmt.Fprintf(cmd, "Suspend %s... ", vm.Reference())
task, err = vm.Suspend(ctx)
case cmd.Reboot:
fmt.Fprintf(cmd, "Reboot guest %s... ", vm.Reference())
err = vm.RebootGuest(ctx)
if err != nil && cmd.Force && isToolsUnavailable(err) {
task, err = vm.Reset(ctx)
}
case cmd.Shutdown:
fmt.Fprintf(cmd, "Shutdown guest %s... ", vm.Reference())
err = vm.ShutdownGuest(ctx)
if err != nil && cmd.Force && isToolsUnavailable(err) {
task, err = vm.PowerOff(ctx)
}
case cmd.Standby:
fmt.Fprintf(cmd, "Standby guest %s... ", vm.Reference())
err = vm.StandbyGuest(ctx)
if err != nil && cmd.Force && isToolsUnavailable(err) {
task, err = vm.Suspend(ctx)
}
}
if err != nil {
return err
}
if cmd.Wait && task != nil {
err = task.Wait(ctx)
}
if err == nil {
fmt.Fprintf(cmd, "OK\n")
continue
}
if cmd.Force {
fmt.Fprintf(cmd, "Error: %s\n", err)
continue
}
return err
}
return nil
}

98
vendor/github.com/vmware/govmomi/cli/vm/question.go generated vendored Normal file
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 vm
import (
"context"
"errors"
"flag"
"fmt"
"github.com/vmware/govmomi/cli"
"github.com/vmware/govmomi/cli/flags"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
type question struct {
*flags.VirtualMachineFlag
answer string
}
func init() {
cli.Register("vm.question", &question{})
}
func (cmd *question) Register(ctx context.Context, f *flag.FlagSet) {
cmd.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx)
cmd.VirtualMachineFlag.Register(ctx, f)
f.StringVar(&cmd.answer, "answer", "", "Answer to question")
}
func (cmd *question) Process(ctx context.Context) error {
if err := cmd.VirtualMachineFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *question) Run(ctx context.Context, f *flag.FlagSet) error {
c, err := cmd.Client()
if err != nil {
return err
}
vm, err := cmd.VirtualMachine()
if err != nil {
return err
}
if vm == nil {
return errors.New("no VM specified")
}
var mvm mo.VirtualMachine
pc := property.DefaultCollector(c)
err = pc.RetrieveOne(ctx, vm.Reference(), []string{"runtime.question"}, &mvm)
if err != nil {
return err
}
q := mvm.Runtime.Question
if q == nil {
fmt.Printf("No pending question\n")
return nil
}
// Print question if no answer is specified
if cmd.answer == "" {
fmt.Printf("Question:\n%s\n\n", q.Text)
fmt.Printf("Possible answers:\n")
for _, e := range q.Choice.ChoiceInfo {
ed := e.(*types.ElementDescription)
fmt.Printf("%s) %s\n", ed.Key, ed.Description.Label)
}
return nil
}
// Answer question
return vm.Answer(ctx, q.Id, cmd.answer)
}

139
vendor/github.com/vmware/govmomi/cli/vm/register.go generated vendored Normal file
View file

@ -0,0 +1,139 @@
/*
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 vm
import (
"context"
"flag"
"github.com/vmware/govmomi/cli"
"github.com/vmware/govmomi/cli/flags"
)
type register struct {
*flags.DatastoreFlag
*flags.ResourcePoolFlag
*flags.HostSystemFlag
*flags.FolderFlag
name string
template bool
}
func init() {
cli.Register("vm.register", &register{})
}
func (cmd *register) 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.HostSystemFlag, ctx = flags.NewHostSystemFlag(ctx)
cmd.HostSystemFlag.Register(ctx, f)
cmd.FolderFlag, ctx = flags.NewFolderFlag(ctx)
cmd.FolderFlag.Register(ctx, f)
f.StringVar(&cmd.name, "name", "", "Name of the VM")
f.BoolVar(&cmd.template, "template", false, "Mark VM as template")
}
func (cmd *register) 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.HostSystemFlag.Process(ctx); err != nil {
return err
}
if err := cmd.FolderFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *register) Usage() string {
return "VMX"
}
func (cmd *register) Description() string {
return `Add an existing VM to the inventory.
VMX is a path to the vm config file, relative to DATASTORE.
Examples:
govc vm.register path/name.vmx
govc vm.register -template -host $host path/name.vmx`
}
func (cmd *register) Run(ctx context.Context, f *flag.FlagSet) error {
if len(f.Args()) != 1 {
return flag.ErrHelp
}
pool, err := cmd.ResourcePoolIfSpecified()
if err != nil {
return err
}
host, err := cmd.HostSystemFlag.HostSystemIfSpecified()
if err != nil {
return err
}
if cmd.template {
if pool != nil || host == nil {
return flag.ErrHelp
}
} else if pool == nil {
if host != nil {
pool, err = host.ResourcePool(ctx)
if err != nil {
return err
}
} else {
// neither -host nor -pool were specified, so use the default pool (ESX)
pool, err = cmd.ResourcePool()
if err != nil {
return err
}
}
}
folder, err := cmd.FolderFlag.Folder()
if err != nil {
return err
}
path, err := cmd.DatastorePath(f.Arg(0))
if err != nil {
return err
}
task, err := folder.RegisterVM(ctx, path, cmd.name, cmd.template, pool, host)
if err != nil {
return err
}
return task.Wait(ctx)
}

76
vendor/github.com/vmware/govmomi/cli/vm/unregister.go generated vendored Normal file
View file

@ -0,0 +1,76 @@
/*
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 vm
import (
"context"
"flag"
"github.com/vmware/govmomi/cli"
"github.com/vmware/govmomi/cli/flags"
)
type unregister struct {
*flags.ClientFlag
*flags.SearchFlag
}
func init() {
cli.Register("vm.unregister", &unregister{})
}
func (cmd *unregister) 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 *unregister) 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 *unregister) Usage() string {
return "VM..."
}
func (cmd *unregister) Description() string {
return `Remove VM from inventory without removing any of the VM files on disk.`
}
func (cmd *unregister) Run(ctx context.Context, f *flag.FlagSet) error {
vms, err := cmd.VirtualMachines(f.Args())
if err != nil {
return err
}
for _, vm := range vms {
err := vm.Unregister(ctx)
if err != nil {
return err
}
}
return nil
}

87
vendor/github.com/vmware/govmomi/cli/vm/upgrade.go generated vendored Normal file
View file

@ -0,0 +1,87 @@
/*
Copyright (c) 2017-2024 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/cli"
"github.com/vmware/govmomi/cli/flags"
"github.com/vmware/govmomi/fault"
"github.com/vmware/govmomi/vim25/types"
)
type upgrade struct {
*flags.VirtualMachineFlag
version int
}
func init() {
cli.Register("vm.upgrade", &upgrade{})
}
func (cmd *upgrade) Register(ctx context.Context, f *flag.FlagSet) {
cmd.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx)
cmd.VirtualMachineFlag.Register(ctx, f)
f.IntVar(&cmd.version, "version", 0, "Target vm hardware version, by default -- latest available")
}
func (cmd *upgrade) Process(ctx context.Context) error {
if err := cmd.VirtualMachineFlag.Process(ctx); err != nil {
return err
}
return nil
}
func (cmd *upgrade) Description() string {
return `Upgrade VMs to latest hardware version
Examples:
govc vm.upgrade -vm $vm_name
govc vm.upgrade -version=$version -vm $vm_name
govc vm.upgrade -version=$version -vm.uuid $vm_uuid`
}
func (cmd *upgrade) Run(ctx context.Context, f *flag.FlagSet) error {
vm, err := cmd.VirtualMachine()
if err != nil {
return err
}
var version = ""
if cmd.version != 0 {
version = fmt.Sprintf("vmx-%02d", cmd.version)
}
task, err := vm.UpgradeVM(ctx, version)
if err != nil {
return err
}
err = task.Wait(ctx)
if err != nil {
if fault.Is(err, &types.AlreadyUpgraded{}) {
fmt.Println(err.Error())
} else {
return err
}
}
return nil
}

504
vendor/github.com/vmware/govmomi/cli/vm/vnc.go generated vendored Normal file
View file

@ -0,0 +1,504 @@
/*
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"
"encoding/json"
"flag"
"fmt"
"io"
"reflect"
"regexp"
"strconv"
"strings"
"github.com/vmware/govmomi/cli"
"github.com/vmware/govmomi/cli/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 intRange struct {
low, high int
}
var intRangeRegexp = regexp.MustCompile("^([0-9]+)-([0-9]+)$")
func (i *intRange) Set(s string) error {
m := intRangeRegexp.FindStringSubmatch(s)
if m == nil {
return fmt.Errorf("invalid range: %s", s)
}
low, err := strconv.Atoi(m[1])
if err != nil {
return fmt.Errorf("couldn't convert to integer: %v", err)
}
high, err := strconv.Atoi(m[2])
if err != nil {
return fmt.Errorf("couldn't convert to integer: %v", err)
}
if low > high {
return fmt.Errorf("invalid range: low > high")
}
i.low = low
i.high = high
return nil
}
func (i *intRange) String() string {
return fmt.Sprintf("%d-%d", i.low, i.high)
}
type vnc struct {
*flags.SearchFlag
Enable bool
Disable bool
Port int
PortRange intRange
Password string
}
func init() {
cmd := &vnc{}
err := cmd.PortRange.Set("5900-5999")
if err != nil {
fmt.Printf("Error setting port range %v", err)
}
cli.Register("vm.vnc", cmd)
}
func (cmd *vnc) Register(ctx context.Context, f *flag.FlagSet) {
cmd.SearchFlag, ctx = flags.NewSearchFlag(ctx, flags.SearchVirtualMachines)
cmd.SearchFlag.Register(ctx, f)
f.BoolVar(&cmd.Enable, "enable", false, "Enable VNC")
f.BoolVar(&cmd.Disable, "disable", false, "Disable VNC")
f.IntVar(&cmd.Port, "port", -1, "VNC port (-1 for auto-select)")
f.Var(&cmd.PortRange, "port-range", "VNC port auto-select range")
f.StringVar(&cmd.Password, "password", "", "VNC password")
}
func (cmd *vnc) Process(ctx context.Context) error {
if err := cmd.SearchFlag.Process(ctx); err != nil {
return err
}
// Either may be true or none may be true.
if cmd.Enable && cmd.Disable {
return flag.ErrHelp
}
return nil
}
func (cmd *vnc) Usage() string {
return "VM..."
}
func (cmd *vnc) Description() string {
return `Enable or disable VNC for VM.
Port numbers are automatically chosen if not specified.
If neither -enable or -disable is specified, the current state is returned.
Examples:
govc vm.vnc -enable -password 1234 $vm | awk '{print $2}' | xargs open`
}
func (cmd *vnc) Run(ctx context.Context, f *flag.FlagSet) error {
vms, err := cmd.loadVMs(f.Args())
if err != nil {
return err
}
// Actuate settings in VMs
for _, vm := range vms {
switch {
case cmd.Enable:
err = vm.enable(cmd.Port, cmd.Password)
if err != nil {
return err
}
case cmd.Disable:
err = vm.disable()
if err != nil {
return err
}
}
}
// Reconfigure VMs to reflect updates
for _, vm := range vms {
err = vm.reconfigure()
if err != nil {
return err
}
}
return cmd.WriteResult(vncResult(vms))
}
func (cmd *vnc) loadVMs(args []string) ([]*vncVM, error) {
c, err := cmd.Client()
if err != nil {
return nil, err
}
vms, err := cmd.VirtualMachines(args)
if err != nil {
return nil, err
}
var vncVMs []*vncVM
for _, vm := range vms {
v, err := newVNCVM(c, vm)
if err != nil {
return nil, err
}
vncVMs = append(vncVMs, v)
}
// Assign vncHosts to vncVMs
hosts := make(map[string]*vncHost)
for _, vm := range vncVMs {
if h, ok := hosts[vm.hostReference().Value]; ok {
vm.host = h
continue
}
hs := object.NewHostSystem(c, vm.hostReference())
h, err := newVNCHost(c, hs, cmd.PortRange.low, cmd.PortRange.high)
if err != nil {
return nil, err
}
hosts[vm.hostReference().Value] = h
vm.host = h
}
return vncVMs, nil
}
type vncVM struct {
c *vim25.Client
vm *object.VirtualMachine
mvm mo.VirtualMachine
host *vncHost
curOptions vncOptions
newOptions vncOptions
}
func newVNCVM(c *vim25.Client, vm *object.VirtualMachine) (*vncVM, error) {
v := &vncVM{
c: c,
vm: vm,
}
virtualMachineProperties := []string{
"name",
"config.extraConfig",
"runtime.host",
}
pc := property.DefaultCollector(c)
ctx := context.TODO()
err := pc.RetrieveOne(ctx, vm.Reference(), virtualMachineProperties, &v.mvm)
if err != nil {
return nil, err
}
v.curOptions = vncOptionsFromExtraConfig(v.mvm.Config.ExtraConfig)
v.newOptions = vncOptionsFromExtraConfig(v.mvm.Config.ExtraConfig)
return v, nil
}
func (v *vncVM) hostReference() types.ManagedObjectReference {
return *v.mvm.Runtime.Host
}
func (v *vncVM) enable(port int, password string) error {
v.newOptions["enabled"] = "true"
v.newOptions["port"] = fmt.Sprintf("%d", port)
v.newOptions["password"] = password
// Find port if auto-select
if port == -1 {
// Reuse port if If VM already has a port, reuse it.
// Otherwise, find unused VNC port on host.
if p, ok := v.curOptions["port"]; ok && p != "" {
v.newOptions["port"] = p
} else {
port, err := v.host.popUnusedPort()
if err != nil {
return err
}
v.newOptions["port"] = fmt.Sprintf("%d", port)
}
}
return nil
}
func (v *vncVM) disable() error {
v.newOptions["enabled"] = "false"
v.newOptions["port"] = ""
v.newOptions["password"] = ""
return nil
}
func (v *vncVM) reconfigure() error {
if reflect.DeepEqual(v.curOptions, v.newOptions) {
// No changes to settings
return nil
}
spec := types.VirtualMachineConfigSpec{
ExtraConfig: v.newOptions.ToExtraConfig(),
}
ctx := context.TODO()
task, err := v.vm.Reconfigure(ctx, spec)
if err != nil {
return err
}
return task.Wait(ctx)
}
func (v *vncVM) uri() (string, error) {
ip, err := v.host.managementIP()
if err != nil {
return "", err
}
uri := fmt.Sprintf("vnc://:%s@%s:%s",
v.newOptions["password"],
ip,
v.newOptions["port"])
return uri, nil
}
func (v *vncVM) write(w io.Writer) error {
if strings.EqualFold(v.newOptions["enabled"], "true") {
uri, err := v.uri()
if err != nil {
return err
}
fmt.Printf("%s: %s\n", v.mvm.Name, uri)
} else {
fmt.Printf("%s: disabled\n", v.mvm.Name)
}
return nil
}
type vncHost struct {
c *vim25.Client
host *object.HostSystem
ports map[int]struct{}
ip string // This field is populated by `managementIP`
}
func newVNCHost(c *vim25.Client, host *object.HostSystem, low, high int) (*vncHost, error) {
ports := make(map[int]struct{})
for i := low; i <= high; i++ {
ports[i] = struct{}{}
}
used, err := loadUsedPorts(c, host.Reference())
if err != nil {
return nil, err
}
// Remove used ports from range
for _, u := range used {
delete(ports, u)
}
h := &vncHost{
c: c,
host: host,
ports: ports,
}
return h, nil
}
func loadUsedPorts(c *vim25.Client, host types.ManagedObjectReference) ([]int, error) {
ctx := context.TODO()
ospec := types.ObjectSpec{
Obj: host,
SelectSet: []types.BaseSelectionSpec{
&types.TraversalSpec{
Type: "HostSystem",
Path: "vm",
Skip: types.NewBool(false),
},
},
Skip: types.NewBool(false),
}
pspec := types.PropertySpec{
Type: "VirtualMachine",
PathSet: []string{"config.extraConfig"},
}
req := types.RetrieveProperties{
This: c.ServiceContent.PropertyCollector,
SpecSet: []types.PropertyFilterSpec{
{
ObjectSet: []types.ObjectSpec{ospec},
PropSet: []types.PropertySpec{pspec},
},
},
}
var vms []mo.VirtualMachine
err := mo.RetrievePropertiesForRequest(ctx, c, req, &vms)
if err != nil {
return nil, err
}
var ports []int
for _, vm := range vms {
if vm.Config == nil || vm.Config.ExtraConfig == nil {
continue
}
options := vncOptionsFromExtraConfig(vm.Config.ExtraConfig)
if ps, ok := options["port"]; ok && ps != "" {
pi, err := strconv.Atoi(ps)
if err == nil {
ports = append(ports, pi)
}
}
}
return ports, nil
}
func (h *vncHost) popUnusedPort() (int, error) {
if len(h.ports) == 0 {
return 0, fmt.Errorf("no unused ports in range")
}
// Return first port we get when iterating
var port int
for port = range h.ports {
break
}
delete(h.ports, port)
return port, nil
}
func (h *vncHost) managementIP() (string, error) {
ctx := context.TODO()
if h.ip != "" {
return h.ip, nil
}
ips, err := h.host.ManagementIPs(ctx)
if err != nil {
return "", err
}
if len(ips) > 0 {
h.ip = ips[0].String()
} else {
h.ip = "<unknown>"
}
return h.ip, nil
}
type vncResult []*vncVM
func (vms vncResult) MarshalJSON() ([]byte, error) {
out := make(map[string]string)
for _, vm := range vms {
uri, err := vm.uri()
if err != nil {
return nil, err
}
out[vm.mvm.Name] = uri
}
return json.Marshal(out)
}
func (vms vncResult) Write(w io.Writer) error {
for _, vm := range vms {
err := vm.write(w)
if err != nil {
return err
}
}
return nil
}
type vncOptions map[string]string
var vncPrefix = "RemoteDisplay.vnc."
func vncOptionsFromExtraConfig(ov []types.BaseOptionValue) vncOptions {
vo := make(vncOptions)
for _, b := range ov {
o := b.GetOptionValue()
if strings.HasPrefix(o.Key, vncPrefix) {
key := o.Key[len(vncPrefix):]
if key != "key" {
vo[key] = o.Value.(string)
}
}
}
return vo
}
func (vo vncOptions) ToExtraConfig() []types.BaseOptionValue {
ov := make([]types.BaseOptionValue, 0)
for k, v := range vo {
key := vncPrefix + k
value := v
o := types.OptionValue{
Key: key,
Value: &value, // Pass pointer to avoid omitempty
}
ov = append(ov, &o)
}
// Don't know how to deal with the key option, set it to be empty...
o := types.OptionValue{
Key: vncPrefix + "key",
Value: new(string), // Pass pointer to avoid omitempty
}
ov = append(ov, &o)
return ov
}