1
0
mirror of https://github.com/openshift/installer.git synced 2026-02-05 06:46:36 +01:00

vshpere: download ova into cache

This change caches a copy of the vmware ova specified in rhcos.json in
preperation to upload the OVA into a Template.

Add vsphere terraform import ova

- Using terraform-provider-vsphere as an example and source
  add a resource `vsphereprivate_import_ova`.
- Modify existing terraform to use the above resource
- Modify vsphere tfvars

Co-authored-by: Jeremiah Stuever <jstuever@redhat.com>
This commit is contained in:
Jeremiah Stuever
2020-01-14 14:24:55 -08:00
committed by Joseph Callen
parent 0a22450774
commit ff35ac0372
76 changed files with 9393 additions and 9 deletions

View File

@@ -5,6 +5,13 @@ provider "vsphere" {
allow_unverified_ssl = false
}
provider "vsphereprivate" {
user = var.vsphere_username
password = var.vsphere_password
vsphere_server = var.vsphere_url
allow_unverified_ssl = false
}
data "vsphere_datacenter" "datacenter" {
name = var.vsphere_datacenter
}
@@ -25,10 +32,20 @@ data "vsphere_network" "network" {
}
data "vsphere_virtual_machine" "template" {
name = var.vsphere_template
name = vsphereprivate_import_ova.import.name
datacenter_id = data.vsphere_datacenter.datacenter.id
}
resource "vsphereprivate_import_ova" "import" {
name = var.vsphere_template
filename = var.vsphere_ova_filepath
cluster = var.vsphere_cluster
datacenter = var.vsphere_datacenter
datastore = var.vsphere_datastore
network = var.vsphere_network
folder = vsphere_folder.folder.path
}
resource "vsphere_tag_category" "category" {
name = "openshift-${var.cluster_id}"
description = "Added by openshift-install do not remove"

View File

@@ -22,7 +22,7 @@ data "ignition_config" "ign" {
}
files = [
data.ignition_file.hostname[count.index].id
data.ignition_file.hostname[count.index].rendered
]
}

View File

@@ -32,6 +32,11 @@ variable "vsphere_datastore" {
description = "This is the name of the vSphere data store."
}
variable "vsphere_ova_filepath" {
type = string
description = "This is the filepath to the ova file that will be imported into vSphere."
}
variable "vsphere_template" {
type = string
description = "This is the name of the VM template to clone."
@@ -65,3 +70,4 @@ variable "vsphere_control_plane_num_cpus" {
variable "vsphere_control_plane_cores_per_socket" {
type = number
}

4
go.mod
View File

@@ -101,7 +101,7 @@ require (
github.com/terraform-providers/terraform-provider-vsphere v1.16.2
github.com/ulikunitz/xz v0.5.6
github.com/vincent-petithory/dataurl v0.0.0-20191104211930-d1553a71de50
github.com/vmware/govmomi v0.22.1
github.com/vmware/govmomi v0.22.2
go.uber.org/atomic v1.5.1 // indirect
go.uber.org/multierr v1.4.0 // indirect
go.uber.org/zap v1.13.0 // indirect
@@ -116,7 +116,7 @@ require (
gopkg.in/ini.v1 v1.51.0
gopkg.in/yaml.v2 v2.2.8
k8s.io/api v0.17.2
k8s.io/apimachinery v0.17.2
k8s.io/apimachinery v0.17.3
k8s.io/client-go v12.0.0+incompatible
k8s.io/klog v1.0.0
k8s.io/utils v0.0.0-20191217005138-9e5e9d854fcc

2
go.sum
View File

@@ -2179,6 +2179,8 @@ github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59b
github.com/vmware/govmomi v0.21.0/go.mod h1:zbnFoBQ9GIjs2RVETy8CNEpb+L+Lwkjs3XZUL0B3/m0=
github.com/vmware/govmomi v0.22.1 h1:ZIEYmBdAS2i+s7RctapqdHfbeGiUcL8LRN05uS4TfPc=
github.com/vmware/govmomi v0.22.1/go.mod h1:Y+Wq4lst78L85Ge/F8+ORXIWiKYqaro1vhAulACy9Lc=
github.com/vmware/govmomi v0.22.2 h1:hmLv4f+RMTTseqtJRijjOWzwELiaLMIoHv2D6H3bF4I=
github.com/vmware/govmomi v0.22.2/go.mod h1:Y+Wq4lst78L85Ge/F8+ORXIWiKYqaro1vhAulACy9Lc=
github.com/vmware/vmw-guestinfo v0.0.0-20170707015358-25eff159a728/go.mod h1:x9oS4Wk2s2u4tS29nEaDLdzvuHdB19CvSGJjPgkZJNk=
github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8=

View File

@@ -447,6 +447,7 @@ func (t *TerraformVariables) Generate(parents asset.Parents) error {
Username: installConfig.Config.VSphere.Username,
Password: installConfig.Config.VSphere.Password,
Cluster: installConfig.Config.VSphere.Cluster,
ImageURL: string(*rhcosImage),
},
)
if err != nil {

View File

@@ -325,8 +325,9 @@ func (m *Master) Generate(dependencies asset.Parents) error {
mpool.Set(ic.Platform.VSphere.DefaultMachinePlatform)
mpool.Set(pool.Platform.VSphere)
pool.Platform.VSphere = &mpool
templateName := clusterID.InfraID + "-rhcos"
machines, err = vsphere.Machines(clusterID.InfraID, ic, pool, string(*rhcosImage), "master", "master-user-data")
machines, err = vsphere.Machines(clusterID.InfraID, ic, pool, templateName, "master", "master-user-data")
if err != nil {
return errors.Wrap(err, "failed to create master machine objects")
}

View File

@@ -322,8 +322,9 @@ func (w *Worker) Generate(dependencies asset.Parents) error {
mpool.Set(ic.Platform.VSphere.DefaultMachinePlatform)
mpool.Set(pool.Platform.VSphere)
pool.Platform.VSphere = &mpool
templateName := clusterID.InfraID + "-rhcos"
sets, err := vsphere.MachineSets(clusterID.InfraID, ic, &pool, string(*rhcosImage), "worker", "worker-user-data")
sets, err := vsphere.MachineSets(clusterID.InfraID, ic, &pool, templateName, "worker", "worker-user-data")
if err != nil {
return errors.Wrap(err, "failed to create worker machine objects")
}

View File

@@ -101,8 +101,15 @@ func osImage(config *types.InstallConfig) (string, error) {
// because this contains the necessary ironic config drive
// ignition support, which isn't enabled in the UPI BM images
osimage, err = rhcos.OpenStack(ctx, arch)
case none.Name, vsphere.Name:
case vsphere.Name:
// Check for RHCOS image URL override
if config.Platform.VSphere.ClusterOSImage != "" {
osimage = config.Platform.VSphere.ClusterOSImage
break
}
osimage, err = rhcos.VMware(ctx, arch)
case none.Name:
default:
return "", errors.New("invalid Platform")
}

View File

@@ -41,6 +41,10 @@ type metadata struct {
SHA256 string `json:"sha256"`
UncompressedSHA256 string `json:"uncompressed-sha256"`
} `json:"openstack"`
VMware struct {
Path string `json:"path"`
SHA256 string `json:"sha256"`
} `json:"vmware"`
} `json:"images"`
OSTreeVersion string `json:"ostree-version"`
}

43
pkg/rhcos/vmware.go Normal file
View File

@@ -0,0 +1,43 @@
package rhcos
import (
"context"
"net/url"
"github.com/pkg/errors"
"github.com/openshift/installer/pkg/types"
)
// VMware fetches the URL of the Red Hat Enterprise Linux CoreOS release.
func VMware(ctx context.Context, arch types.Architecture) (string, error) {
meta, err := fetchRHCOSBuild(ctx, arch)
if err != nil {
return "", errors.Wrap(err, "failed to fetch RHCOS metadata")
}
base, err := url.Parse(meta.BaseURI)
if err != nil {
return "", err
}
image, err := url.Parse(meta.Images.VMware.Path)
if err != nil {
return "", err
}
baseURL := base.ResolveReference(image).String()
// Attach sha256 checksum to the URL. Always provide the
// uncompressed SHA256; the cache will take care of
// uncompressing before checksumming.
baseURL += "?sha256=" + meta.Images.VMware.SHA256
// Check that we have generated a valid URL
_, err = url.ParseRequestURI(baseURL)
if err != nil {
return "", err
}
return baseURL, nil
}

View File

@@ -0,0 +1,14 @@
package plugins
import (
"github.com/hashicorp/terraform-plugin-sdk/plugin"
"github.com/openshift/installer/pkg/terraform/exec/plugins/vsphereprivate"
)
func init() {
vspherePrivateProvider := func() {
plugin.Serve(&plugin.ServeOpts{
ProviderFunc: vsphereprivate.Provider})
}
KnownPlugins["terraform-provider-vsphereprivate"] = vspherePrivateProvider
}

View File

@@ -0,0 +1,67 @@
package vsphereprivate
import (
"fmt"
"log"
"net/url"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/terraform-providers/terraform-provider-vsphere/vsphere"
"github.com/vmware/govmomi"
)
// VSphereClient - The VIM/govmomi client.
type VSphereClient struct {
vimClient *govmomi.Client
}
// ConfigWrapper - wrapping the terraform-provider-vsphere Config struct
type ConfigWrapper struct {
config *vsphere.Config
}
// NewConfig function
func NewConfig(d *schema.ResourceData) (*ConfigWrapper, error) {
config, err := vsphere.NewConfig(d)
if err != nil {
return nil, err
}
return &ConfigWrapper{config}, nil
}
// vimURL returns a URL to pass to the VIM SOAP client.
func (cw *ConfigWrapper) vimURL() (*url.URL, error) {
u, err := url.Parse("https://" + cw.config.VSphereServer + "/sdk")
if err != nil {
return nil, fmt.Errorf("error parse url: %s", err)
}
u.User = url.UserPassword(cw.config.User, cw.config.Password)
return u, nil
}
// Client returns a new client for accessing VMWare vSphere.
func (cw *ConfigWrapper) Client() (*VSphereClient, error) {
client := new(VSphereClient)
u, err := cw.vimURL()
if err != nil {
return nil, fmt.Errorf("error generating SOAP endpoint url: %s", err)
}
err = cw.config.EnableDebug()
if err != nil {
return nil, fmt.Errorf("error setting up client debug: %s", err)
}
// Set up the VIM/govmomi client connection, or load a previous session
client.vimClient, err = cw.config.SavedVimSessionOrNew(u)
if err != nil {
return nil, err
}
log.Printf("[DEBUG] VMWare vSphere Client configured for URL: %s", cw.config.VSphereServer)
return client, nil
}

View File

@@ -0,0 +1,36 @@
package vsphereprivate
import (
"time"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
"github.com/terraform-providers/terraform-provider-vsphere/vsphere"
)
// defaultAPITimeout is a default timeout value that is passed to functions
// requiring contexts, and other various waiters.
const defaultAPITimeout = time.Minute * 5
// Provider returns a terraform.ResourceProvider.
func Provider() terraform.ResourceProvider {
vsphereProvider := vsphere.Provider()
vsphereProvider.(*schema.Provider).DataSourcesMap = map[string]*schema.Resource{}
vsphereProvider.(*schema.Provider).ResourcesMap = map[string]*schema.Resource{
"vsphereprivate_import_ova": resourceVSpherePrivateImportOva(),
}
vsphereProvider.(*schema.Provider).ConfigureFunc = providerConfigure
return vsphereProvider
}
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
c, err := NewConfig(d)
if err != nil {
return nil, err
}
return c.Client()
}

View File

@@ -0,0 +1,387 @@
package vsphereprivate
import (
"context"
"fmt"
"log"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/pkg/errors"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/nfc"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/ovf"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
"github.com/vmware/govmomi/govc/importx"
)
func resourceVSpherePrivateImportOva() *schema.Resource {
return &schema.Resource{
Create: resourceVSpherePrivateImportOvaCreate,
Read: resourceVSpherePrivateImportOvaRead,
Delete: resourceVSpherePrivateImportOvaDelete,
SchemaVersion: 1,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Description: "The name of the virtual machine that will be created.",
Required: true,
ForceNew: true,
ValidateFunc: validation.NoZeroValues,
},
"filename": {
Type: schema.TypeString,
Description: "The filename path to the ova file to be imported.",
Required: true,
ForceNew: true,
ValidateFunc: validation.NoZeroValues,
},
"datacenter": {
Type: schema.TypeString,
Description: "The name of the datacenter.",
Required: true,
ForceNew: true,
ValidateFunc: validation.NoZeroValues,
},
"cluster": {
Type: schema.TypeString,
Description: "The name of the cluster.",
Required: true,
ForceNew: true,
ValidateFunc: validation.NoZeroValues,
},
"network": {
Type: schema.TypeString,
Description: "The name of a network that the virtual machine will use.",
Required: true,
ForceNew: true,
ValidateFunc: validation.NoZeroValues,
},
"datastore": {
Type: schema.TypeString,
Description: "The name of the virtual machine's datastore.",
Required: true,
ForceNew: true,
ValidateFunc: validation.NoZeroValues,
},
"folder": {
Type: schema.TypeString,
Description: "The name of the folder to locate the virtual machine in.",
Required: true,
ForceNew: true,
ValidateFunc: validation.NoZeroValues,
},
},
}
}
// importOvaParams contains the vCenter objects required to import a OVA into vSphere.
type importOvaParams struct {
ResourcePool *object.ResourcePool
Datacenter *object.Datacenter
Datastore *object.Datastore
Network *object.Network
Host *object.HostSystem
Folder *object.Folder
}
func findImportOvaParams(client *vim25.Client, datacenter, cluster, datastore, network string) (*importOvaParams, error) {
var ccrMo mo.ClusterComputeResource
ctx, cancel := context.WithTimeout(context.TODO(), defaultAPITimeout)
defer cancel()
importOvaParams := &importOvaParams{}
finder := find.NewFinder(client)
// Find the object Datacenter by using its name provided by install-config
dcObj, err := finder.Datacenter(ctx, datacenter)
if err != nil {
return nil, err
}
importOvaParams.Datacenter = dcObj
// Find the top-level (and hidden to view) folders in the
// datacenter
folders, err := importOvaParams.Datacenter.Folders(ctx)
if err != nil {
return nil, err
}
// The only folder we are interested in is VmFolder
// Which can contain our template
importOvaParams.Folder = folders.VmFolder
clusterPath := fmt.Sprintf("/%s/host/%s", datacenter, cluster)
// Find the cluster object by the datacenter and cluster name to
// generate the path e.g. /datacenter/host/cluster
clusterComputeResource, err := finder.ClusterComputeResource(ctx, clusterPath)
if err != nil {
return nil, err
}
// Get the network properties that is defined in ClusterComputeResource
// We need to know if the network name provided exists in the cluster that was
// also provided.
err = clusterComputeResource.Properties(ctx, clusterComputeResource.Reference(), []string{"network"}, &ccrMo)
if err != nil {
return nil, err
}
// Find the network object using the provided network name
for _, networkMoRef := range ccrMo.Network {
networkObj := object.NewNetwork(client, networkMoRef)
networkObjectName, err := networkObj.ObjectName(ctx)
if err != nil {
return nil, err
}
if network == networkObjectName {
importOvaParams.Network = networkObj
break
}
}
// Find all the datastores that are configured under the cluster
datastores, err := clusterComputeResource.Datastores(ctx)
if err != nil {
return nil, err
}
// Find the specific datastore by the name provided
for _, datastoreObj := range datastores {
datastoreObjName, err := datastoreObj.ObjectName(ctx)
if err != nil {
return nil, err
}
if datastore == datastoreObjName {
importOvaParams.Datastore = datastoreObj
break
}
}
// Find all the HostSystem(s) under cluster
hosts, err := clusterComputeResource.Hosts(ctx)
if err != nil {
return nil, err
}
foundDatastore := false
foundNetwork := false
var hostSystemManagedObject mo.HostSystem
// Confirm that the network and datastore that was provided is
// available for use on the HostSystem we will import the
// OVA to.
for _, hostObj := range hosts {
hostObj.Properties(ctx, hostObj.Reference(), []string{"network", "datastore"}, &hostSystemManagedObject)
if err != nil {
return nil, err
}
for _, dsMoRef := range hostSystemManagedObject.Datastore {
if importOvaParams.Datastore.Reference().Value == dsMoRef.Value {
foundDatastore = true
break
}
}
for _, nMoRef := range hostSystemManagedObject.Network {
if importOvaParams.Network.Reference().Value == nMoRef.Value {
foundNetwork = true
break
}
}
if foundDatastore && foundNetwork {
importOvaParams.Host = hostObj
resourcePool, err := hostObj.ResourcePool(ctx)
if err != nil {
return nil, err
}
importOvaParams.ResourcePool = resourcePool
}
}
if !foundDatastore {
return nil, errors.Errorf("failed to find a host in the cluster that contains the provided datastore")
}
if !foundNetwork {
return nil, errors.Errorf("failed to find a host in the cluster that contains the provided network")
}
return importOvaParams, nil
}
// Used govc/importx/ovf.go as an example to implement
// resourceVspherePrivateImportOvaCreate and upload functions
// See: https://github.com/vmware/govmomi/blob/cc10a0758d5b4d4873388bcea417251d1ad03e42/govc/importx/ovf.go#L196-L324
func upload(ctx context.Context, archive *importx.ArchiveFlag, lease *nfc.Lease, item nfc.FileItem) error {
file := item.Path
f, size, err := archive.Open(file)
if err != nil {
return err
}
defer f.Close()
opts := soap.Upload{
ContentLength: size,
}
return lease.Upload(ctx, item, f, opts)
}
func resourceVSpherePrivateImportOvaCreate(d *schema.ResourceData, meta interface{}) error {
log.Printf("[DEBUG] %s: Beginning import ova create", d.Get("filename").(string))
ctx, cancel := context.WithTimeout(context.TODO(), defaultAPITimeout)
defer cancel()
client := meta.(*VSphereClient).vimClient.Client
archive := &importx.ArchiveFlag{Archive: &importx.TapeArchive{Path: d.Get("filename").(string)}}
importOvaParams, err := findImportOvaParams(client,
d.Get("datacenter").(string),
d.Get("cluster").(string),
d.Get("datastore").(string),
d.Get("network").(string))
if err != nil {
return errors.Errorf("failed to find provided vSphere objects: %s", err)
}
ovfDescriptor, err := archive.ReadOvf("*.ovf")
if err != nil {
return errors.Errorf("failed to read ovf: %s", err)
}
ovfEnvelope, err := archive.ReadEnvelope(ovfDescriptor)
if err != nil {
return errors.Errorf("failed to parse ovf: %s", err)
}
// The RHCOS OVA only has one network defined by default
// The OVF envelope defines this. We need a 1:1 mapping
// between networks with the OVF and the host
if len(ovfEnvelope.Network.Networks) != 1 {
return errors.Errorf("Expected the OVA to only have a single network adapter")
}
// Create mapping between OVF and the network object
// found by Name
networkMappings := []types.OvfNetworkMapping{{
Name: ovfEnvelope.Network.Networks[0].Name,
Network: importOvaParams.Network.Reference(),
}}
// This is a very minimal spec for importing
// an OVF.
cisp := types.OvfCreateImportSpecParams{
EntityName: d.Get("name").(string),
NetworkMapping: networkMappings,
}
m := ovf.NewManager(client)
spec, err := m.CreateImportSpec(ctx,
string(ovfDescriptor),
importOvaParams.ResourcePool.Reference(),
importOvaParams.Datastore.Reference(),
cisp)
if err != nil {
return errors.Errorf("failed to create import spec: %s", err)
}
if spec.Error != nil {
return errors.New(spec.Error[0].LocalizedMessage)
}
// The lease and upload cannot be used with a timeout
// since we do not know how long it will take to upload
// the ova to vSphere
ctx = context.TODO()
//Creates a new entity in this resource pool.
//See VMware vCenter API documentation: Managed Object - ResourcePool - ImportVApp
lease, err := importOvaParams.ResourcePool.ImportVApp(ctx,
spec.ImportSpec,
importOvaParams.Folder,
importOvaParams.Host)
if err != nil {
return errors.Errorf("failed to import vapp: %s", err)
}
info, err := lease.Wait(ctx, spec.FileItem)
if err != nil {
return errors.Errorf("failed to lease wait: %s", err)
}
u := lease.StartUpdater(ctx, info)
defer u.Done()
for _, i := range info.Items {
// upload the vmdk to which ever host that was first
// available with the required network and datastore.
err = upload(ctx, archive, lease, i)
if err != nil {
return errors.Errorf("failed to upload: %s", err)
}
}
err = lease.Complete(ctx)
if err != nil {
return errors.Errorf("failed to lease complete: %s", err)
}
d.SetId(info.Entity.Value)
log.Printf("[DEBUG] %s: ova import complete", d.Get("name").(string))
return resourceVSpherePrivateImportOvaRead(d, meta)
}
func resourceVSpherePrivateImportOvaRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*VSphereClient).vimClient.Client
moRef := types.ManagedObjectReference{
Value: d.Id(),
Type: "VirtualMachine",
}
vm := object.NewVirtualMachine(client, moRef)
if vm == nil {
return fmt.Errorf("error VirtualMachine not found, managed object id: %s", d.Id())
}
return nil
}
func resourceVSpherePrivateImportOvaDelete(d *schema.ResourceData, meta interface{}) error {
log.Printf("[DEBUG] %s: Beginning delete", d.Get("name").(string))
ctx, cancel := context.WithTimeout(context.TODO(), defaultAPITimeout)
defer cancel()
client := meta.(*VSphereClient).vimClient.Client
moRef := types.ManagedObjectReference{
Value: d.Id(),
Type: "VirtualMachine",
}
vm := object.NewVirtualMachine(client, moRef)
if vm == nil {
return errors.Errorf("VirtualMachine not found")
}
task, err := vm.Destroy(ctx)
if err != nil {
return errors.Errorf("failed to destroy virtual machine %s", err)
}
err = task.Wait(ctx)
if err != nil {
return errors.Errorf("failed to destroy virtual machine %s", err)
}
d.SetId("")
log.Printf("[DEBUG] %s: Delete complete", d.Get("name").(string))
return nil
}

View File

@@ -4,6 +4,9 @@ import (
"encoding/json"
vsphereapis "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/v1alpha1"
"github.com/pkg/errors"
"github.com/openshift/installer/pkg/tfvars/internal/cache"
)
type config struct {
@@ -20,6 +23,7 @@ type config struct {
Folder string `json:"vsphere_folder"`
Network string `json:"vsphere_network"`
Template string `json:"vsphere_template"`
OvaFilePath string `json:"vsphere_ova_filepath"`
}
// TFVarsSources contains the parameters to be converted into Terraform variables
@@ -28,12 +32,18 @@ type TFVarsSources struct {
Username string
Password string
Cluster string
ImageURL string
}
//TFVars generate vSphere-specific Terraform variables
func TFVars(sources TFVarsSources) ([]byte, error) {
controlPlaneConfig := sources.ControlPlaneConfigs[0]
cachedImage, err := cache.DownloadImageFile(sources.ImageURL)
if err != nil {
return nil, errors.Wrap(err, "failed to use cached vsphere image")
}
cfg := &config{
VSphereURL: controlPlaneConfig.Workspace.Server,
VSphereUsername: sources.Username,
@@ -48,6 +58,7 @@ func TFVars(sources TFVarsSources) ([]byte, error) {
Folder: controlPlaneConfig.Workspace.Folder,
Network: controlPlaneConfig.Network.Devices[0].NetworkName,
Template: controlPlaneConfig.Template,
OvaFilePath: cachedImage,
}
return json.MarshalIndent(cfg, "", " ")

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@@ -0,0 +1,711 @@
/*
Copyright (c) 2014-2018 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"crypto/sha1"
"crypto/tls"
"encoding/json"
"errors"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
"time"
"github.com/vmware/govmomi/session"
"github.com/vmware/govmomi/sts"
"github.com/vmware/govmomi/vapi/rest"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
)
const (
envURL = "GOVC_URL"
envUsername = "GOVC_USERNAME"
envPassword = "GOVC_PASSWORD"
envCertificate = "GOVC_CERTIFICATE"
envPrivateKey = "GOVC_PRIVATE_KEY"
envInsecure = "GOVC_INSECURE"
envPersist = "GOVC_PERSIST_SESSION"
envMinAPIVersion = "GOVC_MIN_API_VERSION"
envVimNamespace = "GOVC_VIM_NAMESPACE"
envVimVersion = "GOVC_VIM_VERSION"
envTLSCaCerts = "GOVC_TLS_CA_CERTS"
envTLSKnownHosts = "GOVC_TLS_KNOWN_HOSTS"
defaultMinVimVersion = "5.5"
)
const cDescr = "ESX or vCenter URL"
type ClientFlag struct {
common
*DebugFlag
url *url.URL
username string
password string
cert string
key string
insecure bool
persist bool
minAPIVersion string
vimNamespace string
vimVersion string
tlsCaCerts string
tlsKnownHosts string
client *vim25.Client
Login func(context.Context, *vim25.Client) error
}
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.Login = v.login
v.DebugFlag, ctx = NewDebugFlag(ctx)
ctx = context.WithValue(ctx, clientFlagKey, v)
return v, ctx
}
func (flag *ClientFlag) URLWithoutPassword() *url.URL {
if flag.url == nil {
return nil
}
withoutCredentials := *flag.url
withoutCredentials.User = url.User(flag.url.User.Username())
return &withoutCredentials
}
func (flag *ClientFlag) Userinfo() *url.Userinfo {
return flag.url.User
}
func (flag *ClientFlag) IsSecure() bool {
return !flag.insecure
}
func (flag *ClientFlag) String() string {
url := flag.URLWithoutPassword()
if url == nil {
return ""
}
return url.String()
}
func (flag *ClientFlag) Set(s string) error {
var err error
flag.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.insecure, "k", insecure, usage)
}
{
persist := true
switch env := strings.ToLower(os.Getenv(envPersist)); env {
case "0", "false":
persist = false
}
usage := fmt.Sprintf("Persist session to disk [%s]", envPersist)
f.BoolVar(&flag.persist, "persist-session", persist, usage)
}
{
env := os.Getenv(envMinAPIVersion)
if env == "" {
env = defaultMinVimVersion
}
flag.minAPIVersion = env
}
{
value := os.Getenv(envVimNamespace)
if value == "" {
value = vim25.Namespace
}
usage := fmt.Sprintf("Vim namespace [%s]", envVimNamespace)
f.StringVar(&flag.vimNamespace, "vim-namespace", value, usage)
}
{
value := os.Getenv(envVimVersion)
if value == "" {
value = vim25.Version
}
usage := fmt.Sprintf("Vim version [%s]", envVimVersion)
f.StringVar(&flag.vimVersion, "vim-version", value, usage)
}
{
value := os.Getenv(envTLSCaCerts)
usage := fmt.Sprintf("TLS CA certificates file [%s]", envTLSCaCerts)
f.StringVar(&flag.tlsCaCerts, "tls-ca-certs", value, usage)
}
{
value := os.Getenv(envTLSKnownHosts)
usage := fmt.Sprintf("TLS known hosts file [%s]", envTLSKnownHosts)
f.StringVar(&flag.tlsKnownHosts, "tls-known-hosts", value, usage)
}
})
}
func (flag *ClientFlag) Process(ctx context.Context) error {
return flag.ProcessOnce(func() error {
err := flag.DebugFlag.Process(ctx)
if err != nil {
return err
}
if flag.url == nil {
return errors.New("specify an " + cDescr)
}
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.url.User != nil {
password, ok = flag.url.User.Password()
}
if ok {
flag.url.User = url.UserPassword(flag.username, password)
} else {
flag.url.User = url.User(flag.username)
}
}
// Override password if set
if flag.password != "" {
var username string
if flag.url.User != nil {
username = flag.url.User.Username()
}
flag.url.User = url.UserPassword(username, flag.password)
}
return nil
})
}
// configure TLS and retry settings before making any connections
func (flag *ClientFlag) configure(sc *soap.Client) (soap.RoundTripper, error) {
if flag.cert != "" {
cert, err := tls.LoadX509KeyPair(flag.cert, flag.key)
if err != nil {
return nil, fmt.Errorf("%s=%q %s=%q: %s", envCertificate, flag.cert, envPrivateKey, flag.key, err)
}
sc.SetCertificate(cert)
}
// Set namespace and version
sc.Namespace = "urn:" + flag.vimNamespace
sc.Version = flag.vimVersion
sc.UserAgent = fmt.Sprintf("govc/%s", Version)
if err := flag.SetRootCAs(sc); err != nil {
return nil, err
}
if err := sc.LoadThumbprints(flag.tlsKnownHosts); err != nil {
return nil, err
}
if t, ok := sc.Transport.(*http.Transport); ok {
var err error
value := os.Getenv("GOVC_TLS_HANDSHAKE_TIMEOUT")
if value != "" {
t.TLSHandshakeTimeout, err = time.ParseDuration(value)
if err != nil {
return nil, err
}
}
}
// Retry twice when a temporary I/O error occurs.
// This means a maximum of 3 attempts.
return vim25.Retry(sc, vim25.TemporaryNetworkError(3)), nil
}
func (flag *ClientFlag) sessionFile() string {
url := flag.URLWithoutPassword()
// Key session file off of full URI and insecure setting.
// Hash key to get a predictable, canonical format.
key := fmt.Sprintf("%s#insecure=%t", url.String(), flag.insecure)
name := fmt.Sprintf("%040x", sha1.Sum([]byte(key)))
return filepath.Join(home, "sessions", name)
}
func (flag *ClientFlag) saveClient(c *vim25.Client) error {
if !flag.persist {
return nil
}
p := flag.sessionFile()
err := os.MkdirAll(filepath.Dir(p), 0700)
if err != nil {
return err
}
f, err := os.OpenFile(p, os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
return err
}
defer f.Close()
err = json.NewEncoder(f).Encode(c)
if err != nil {
return err
}
return nil
}
func (flag *ClientFlag) restoreClient(c *vim25.Client) (bool, error) {
if !flag.persist {
return false, nil
}
f, err := os.Open(flag.sessionFile())
if err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
defer f.Close()
dec := json.NewDecoder(f)
err = dec.Decode(c)
if err != nil {
return false, err
}
return true, nil
}
func (flag *ClientFlag) loadClient() (*vim25.Client, error) {
c := new(vim25.Client)
ok, err := flag.restoreClient(c)
if err != nil {
return nil, err
}
if !ok || !c.Valid() {
return nil, nil
}
c.RoundTripper, err = flag.configure(c.Client)
if err != nil {
return nil, err
}
m := session.NewManager(c)
u, err := m.UserSession(context.TODO())
if err != nil {
if soap.IsSoapFault(err) {
fault := soap.ToSoapFault(err).VimFault()
// If the PropertyCollector is not found, the saved session for this URL is not valid
if _, ok := fault.(types.ManagedObjectNotFound); ok {
return nil, nil
}
}
return nil, err
}
// If the session is nil, the client is not authenticated
if u == nil {
return nil, nil
}
return c, nil
}
func (flag *ClientFlag) SetRootCAs(c *soap.Client) error {
if flag.tlsCaCerts != "" {
return c.SetRootCAs(flag.tlsCaCerts)
}
return nil
}
func (flag *ClientFlag) login(ctx context.Context, c *vim25.Client) error {
m := session.NewManager(c)
u := flag.url.User
name := u.Username()
if name == "" && !c.IsVC() {
// If no username is provided, try to acquire a local ticket.
// When invoked remotely, ESX returns an InvalidRequestFault.
// So, rather than return an error here, fallthrough to Login() with the original User to
// to avoid what would be a confusing error message.
luser, lerr := flag.localTicket(ctx, m)
if lerr == nil {
// We are running directly on an ESX or Workstation host and can use the ticket with Login()
u = luser
name = u.Username()
}
}
if name == "" {
// Skip auto-login if we don't have a username
flag.persist = true // Not persisting, but this avoids the call to Logout()
return nil // Avoid SaveSession for non-authenticated session
}
return m.Login(ctx, u)
}
func (flag *ClientFlag) newClient() (*vim25.Client, error) {
ctx := context.TODO()
sc := soap.NewClient(flag.url, flag.insecure)
rt, err := flag.configure(sc)
if err != nil {
return nil, err
}
c, err := vim25.NewClient(ctx, rt)
if err != nil {
return nil, err
}
// Set client, since we didn't pass it in the constructor
c.Client = sc
if flag.vimVersion == "" {
if err = c.UseServiceVersion(); err != nil {
return nil, err
}
flag.vimVersion = c.Version
}
if err := flag.Login(ctx, c); err != nil {
return nil, err
}
return c, flag.saveClient(c)
}
func (flag *ClientFlag) localTicket(ctx context.Context, m *session.Manager) (*url.Userinfo, error) {
ticket, err := m.AcquireLocalTicket(ctx, os.Getenv("USER"))
if err != nil {
return nil, err
}
password, err := ioutil.ReadFile(ticket.PasswordFilePath)
if err != nil {
return nil, err
}
return url.UserPassword(ticket.UserName, string(password)), nil
}
func isDevelopmentVersion(apiVersion string) bool {
// Skip version check for development builds which can be in the form of "r4A70F" or "6.5.x"
return strings.Count(apiVersion, ".") == 0 || strings.HasSuffix(apiVersion, ".x")
}
// apiVersionValid returns whether or not the API version supported by the
// server the client is connected to is not recent enough.
func apiVersionValid(c *vim25.Client, minVersionString string) error {
if minVersionString == "-" {
// Disable version check
return nil
}
apiVersion := c.ServiceContent.About.ApiVersion
if isDevelopmentVersion(apiVersion) {
return nil
}
realVersion, err := ParseVersion(apiVersion)
if err != nil {
return fmt.Errorf("error parsing API version %q: %s", apiVersion, err)
}
minVersion, err := ParseVersion(minVersionString)
if err != nil {
return fmt.Errorf("error parsing %s=%q: %s", envMinAPIVersion, minVersionString, err)
}
if !minVersion.Lte(realVersion) {
err = fmt.Errorf("require API version %q, connected to API version %q (set %s to override)",
minVersionString,
c.ServiceContent.About.ApiVersion,
envMinAPIVersion)
return err
}
return nil
}
func (flag *ClientFlag) Client() (*vim25.Client, error) {
if flag.client != nil {
return flag.client, nil
}
c, err := flag.loadClient()
if err != nil {
return nil, err
}
// loadClient returns nil if it was unable to load a session from disk
if c == nil {
c, err = flag.newClient()
if err != nil {
return nil, err
}
}
// Check that the endpoint has the right API version
err = apiVersionValid(c, flag.minAPIVersion)
if err != nil {
return nil, err
}
flag.client = c
return flag.client, nil
}
func (flag *ClientFlag) Logout(ctx context.Context) error {
if flag.persist || flag.client == nil {
return nil
}
m := session.NewManager(flag.client)
return m.Logout(ctx)
}
func (flag *ClientFlag) WithRestClient(ctx context.Context, f func(*rest.Client) error) error {
vc, err := flag.Client()
if err != nil {
return err
}
c := rest.NewClient(vc)
if err != nil {
return err
}
// TODO: rest.Client session cookie should be persisted as the soap.Client session cookie is.
if vc.Certificate() == nil {
if err = c.Login(ctx, flag.Userinfo()); err != nil {
return err
}
} else {
// TODO: session.login should support rest.Client SSO login to avoid this env var (depends on the TODO above)
token := os.Getenv("GOVC_LOGIN_TOKEN")
if token == "" {
return errors.New("GOVC_LOGIN_TOKEN must be set for rest.Client SSO login")
}
signer := &sts.Signer{
Certificate: c.Certificate(),
Token: token,
}
if err = c.LoginByToken(c.WithSigner(ctx, signer)); err != nil {
return err
}
}
defer func() {
if err := c.Logout(ctx); err != nil {
log.Printf("user logout error: %v", err)
}
}()
return f(c)
}
// 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.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.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.url.Path)
if f := flag.url.Fragment; f != "" {
add("GOVC_URL_FRAGMENT", f)
}
if q := flag.url.RawQuery; q != "" {
add("GOVC_URL_QUERY", q)
}
}
return env
}
// WithCancel calls the given function, returning when complete or canceled via SIGINT.
func (flag *ClientFlag) WithCancel(ctx context.Context, f func(context.Context) error) error {
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT)
wctx, cancel := context.WithCancel(ctx)
defer cancel()
done := make(chan bool)
var werr error
go func() {
defer close(done)
werr = f(wctx)
}()
select {
case <-sig:
cancel()
<-done // Wait for f() to complete
case <-done:
}
return werr
}

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

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

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

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

View File

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

View File

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

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

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

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

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

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

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

View File

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

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

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

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

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

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

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

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

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

View File

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

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

@@ -0,0 +1,251 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flags
import (
"context"
"encoding/json"
"flag"
"fmt"
"io"
"os"
"reflect"
"sync"
"time"
"github.com/kr/pretty"
"github.com/vmware/govmomi/vim25/progress"
)
type OutputWriter interface {
Write(io.Writer) error
}
type OutputFlag struct {
common
JSON bool
TTY bool
Dump bool
Out io.Writer
}
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.Dump, "dump", false, "Enable Go output")
})
}
func (flag *OutputFlag) Process(ctx context.Context) error {
return flag.ProcessOnce(func() error {
if !flag.JSON {
// Assume we have a tty if not outputting JSON
flag.TTY = true
}
return nil
})
}
// Log outputs the specified string, prefixed with the current time.
// A newline is not automatically added. If the specified string
// starts with a '\r', the current line is cleared first.
func (flag *OutputFlag) Log(s string) (int, error) {
if len(s) > 0 && s[0] == '\r' {
flag.Write([]byte{'\r', 033, '[', 'K'})
s = s[1:]
}
return flag.WriteString(time.Now().Format("[02-01-06 15:04:05] ") + s)
}
func (flag *OutputFlag) Write(b []byte) (int, error) {
if !flag.TTY {
return 0, nil
}
n, err := os.Stdout.Write(b)
os.Stdout.Sync()
return n, err
}
func (flag *OutputFlag) WriteString(s string) (int, error) {
return flag.Write([]byte(s))
}
func (flag *OutputFlag) All() bool {
return flag.JSON || flag.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()
}
}
return val
}
func (flag *OutputFlag) WriteResult(result OutputWriter) error {
var err error
if flag.JSON {
err = json.NewEncoder(flag.Out).Encode(result)
} else if flag.Dump {
pretty.Fprintf(flag.Out, "%# v\n", dumpValue(result))
} else {
err = result.Write(flag.Out)
}
return err
}
type progressLogger struct {
flag *OutputFlag
prefix string
wg sync.WaitGroup
sink chan chan progress.Report
done chan struct{}
}
func newProgressLogger(flag *OutputFlag, prefix string) *progressLogger {
p := &progressLogger{
flag: flag,
prefix: prefix,
sink: make(chan chan progress.Report),
done: make(chan struct{}),
}
p.wg.Add(1)
go p.loopA()
return p
}
// loopA runs before Sink() has been called.
func (p *progressLogger) loopA() {
var err error
defer p.wg.Done()
tick := time.NewTicker(100 * time.Millisecond)
defer tick.Stop()
called := false
for stop := false; !stop; {
select {
case ch := <-p.sink:
err = p.loopB(tick, ch)
stop = true
called = true
case <-p.done:
stop = true
case <-tick.C:
line := fmt.Sprintf("\r%s", p.prefix)
p.flag.Log(line)
}
}
if err != nil && err != io.EOF {
p.flag.Log(fmt.Sprintf("\r%sError: %s\n", p.prefix, err))
} else if called {
p.flag.Log(fmt.Sprintf("\r%sOK\n", p.prefix))
}
}
// loopA runs after Sink() has been called.
func (p *progressLogger) loopB(tick *time.Ticker, ch <-chan progress.Report) error {
var r progress.Report
var ok bool
var err error
for ok = true; ok; {
select {
case r, ok = <-ch:
if !ok {
break
}
err = r.Error()
case <-tick.C:
line := fmt.Sprintf("\r%s", p.prefix)
if r != nil {
line += fmt.Sprintf("(%.0f%%", r.Percentage())
detail := r.Detail()
if detail != "" {
line += fmt.Sprintf(", %s", detail)
}
line += ")"
}
p.flag.Log(line)
}
}
return err
}
func (p *progressLogger) Sink() chan<- progress.Report {
ch := make(chan progress.Report)
p.sink <- ch
return ch
}
func (p *progressLogger) Wait() {
close(p.done)
p.wg.Wait()
}
func (flag *OutputFlag) ProgressLogger(prefix string) *progressLogger {
return newProgressLogger(flag, prefix)
}

View File

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

View File

@@ -0,0 +1,92 @@
/*
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 ResourcePoolFlag struct {
common
*DatacenterFlag
name string
pool *object.ResourcePool
}
var resourcePoolFlagKey = flagKey("resourcePool")
func NewResourcePoolFlag(ctx context.Context) (*ResourcePoolFlag, context.Context) {
if v := ctx.Value(resourcePoolFlagKey); v != nil {
return v.(*ResourcePoolFlag), ctx
}
v := &ResourcePoolFlag{}
v.DatacenterFlag, ctx = NewDatacenterFlag(ctx)
ctx = context.WithValue(ctx, resourcePoolFlagKey, v)
return v, ctx
}
func (flag *ResourcePoolFlag) Register(ctx context.Context, f *flag.FlagSet) {
flag.RegisterOnce(func() {
flag.DatacenterFlag.Register(ctx, f)
env := "GOVC_RESOURCE_POOL"
value := os.Getenv(env)
usage := fmt.Sprintf("Resource pool [%s]", env)
f.StringVar(&flag.name, "pool", value, usage)
})
}
func (flag *ResourcePoolFlag) Process(ctx context.Context) error {
return flag.ProcessOnce(func() error {
if err := flag.DatacenterFlag.Process(ctx); err != nil {
return err
}
return nil
})
}
func (flag *ResourcePoolFlag) ResourcePool() (*object.ResourcePool, error) {
if flag.pool != nil {
return flag.pool, nil
}
finder, err := flag.Finder()
if err != nil {
return nil, err
}
if flag.pool, err = finder.ResourcePoolOrDefault(context.TODO(), flag.name); err != nil {
return nil, err
}
return flag.pool, nil
}
func (flag *ResourcePoolFlag) ResourcePoolIfSpecified() (*object.ResourcePool, error) {
if flag.name == "" {
return nil, nil
}
return flag.ResourcePool()
}

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

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

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

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

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

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

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

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

150
vendor/github.com/vmware/govmomi/lookup/client.go generated vendored Normal file
View File

@@ -0,0 +1,150 @@
/*
Copyright (c) 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 lookup
import (
"context"
"crypto/x509"
"encoding/base64"
"log"
"net/url"
"github.com/vmware/govmomi/lookup/methods"
"github.com/vmware/govmomi/lookup/types"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/soap"
vim "github.com/vmware/govmomi/vim25/types"
)
const (
Namespace = "lookup"
Version = "2.0"
Path = "/lookupservice" + vim25.Path
)
var (
ServiceInstance = vim.ManagedObjectReference{
Type: "LookupServiceInstance",
Value: "ServiceInstance",
}
)
// Client is a soap.Client targeting the SSO Lookup Service API endpoint.
type Client struct {
*soap.Client
ServiceContent types.LookupServiceContent
}
// NewClient returns a client targeting the SSO Lookup Service API endpoint.
func NewClient(ctx context.Context, c *vim25.Client) (*Client, error) {
// PSC may be external, attempt to derive from sts.uri
path := &url.URL{Path: Path}
if c.ServiceContent.Setting != nil {
m := object.NewOptionManager(c, *c.ServiceContent.Setting)
opts, err := m.Query(ctx, "config.vpxd.sso.sts.uri")
if err == nil && len(opts) == 1 {
u, err := url.Parse(opts[0].GetOptionValue().Value.(string))
if err == nil {
path.Scheme = u.Scheme
path.Host = u.Host
}
}
}
sc := c.Client.NewServiceClient(path.String(), Namespace)
sc.Version = Version
req := types.RetrieveServiceContent{
This: ServiceInstance,
}
res, err := methods.RetrieveServiceContent(ctx, sc, &req)
if err != nil {
return nil, err
}
return &Client{sc, res.Returnval}, nil
}
func (c *Client) List(ctx context.Context, filter *types.LookupServiceRegistrationFilter) ([]types.LookupServiceRegistrationInfo, error) {
req := types.List{
This: *c.ServiceContent.ServiceRegistration,
FilterCriteria: filter,
}
res, err := methods.List(ctx, c, &req)
if err != nil {
return nil, err
}
return res.Returnval, nil
}
func (c *Client) SiteID(ctx context.Context) (string, error) {
req := types.GetSiteId{
This: *c.ServiceContent.ServiceRegistration,
}
res, err := methods.GetSiteId(ctx, c, &req)
if err != nil {
return "", err
}
return res.Returnval, nil
}
// EndpointURL uses the Lookup Service to find the endpoint URL and thumbprint for the given filter.
// If the endpoint is found, its TLS certificate is also added to the vim25.Client's trusted host thumbprints.
// If the Lookup Service is not available, the given path is returned as the default.
func EndpointURL(ctx context.Context, c *vim25.Client, path string, filter *types.LookupServiceRegistrationFilter) string {
if lu, err := NewClient(ctx, c); err == nil {
info, _ := lu.List(ctx, filter)
if len(info) != 0 && len(info[0].ServiceEndpoints) != 0 {
endpoint := &info[0].ServiceEndpoints[0]
path = endpoint.Url
if u, err := url.Parse(path); err == nil {
if c.Thumbprint(u.Host) == "" {
c.SetThumbprint(u.Host, endpointThumbprint(endpoint))
}
}
}
}
return path
}
// endpointThumbprint converts the base64 encoded endpoint certificate to a SHA1 thumbprint.
func endpointThumbprint(endpoint *types.LookupServiceRegistrationEndpoint) string {
if len(endpoint.SslTrust) == 0 {
return ""
}
enc := endpoint.SslTrust[0]
b, err := base64.StdEncoding.DecodeString(enc)
if err != nil {
log.Printf("base64.Decode(%q): %s", enc, err)
return ""
}
cert, err := x509.ParseCertificate(b)
if err != nil {
log.Printf("x509.ParseCertificate(%q): %s", enc, err)
return ""
}
return soap.ThumbprintSHA1(cert)
}

View File

@@ -0,0 +1,224 @@
/*
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 methods
import (
"context"
"github.com/vmware/govmomi/lookup/types"
"github.com/vmware/govmomi/vim25/soap"
)
type CreateBody struct {
Req *types.Create `xml:"urn:lookup Create,omitempty"`
Res *types.CreateResponse `xml:"urn:lookup CreateResponse,omitempty"`
Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
}
func (b *CreateBody) Fault() *soap.Fault { return b.Fault_ }
func Create(ctx context.Context, r soap.RoundTripper, req *types.Create) (*types.CreateResponse, error) {
var reqBody, resBody CreateBody
reqBody.Req = req
if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
return nil, err
}
return resBody.Res, nil
}
type DeleteBody struct {
Req *types.Delete `xml:"urn:lookup Delete,omitempty"`
Res *types.DeleteResponse `xml:"urn:lookup DeleteResponse,omitempty"`
Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
}
func (b *DeleteBody) Fault() *soap.Fault { return b.Fault_ }
func Delete(ctx context.Context, r soap.RoundTripper, req *types.Delete) (*types.DeleteResponse, error) {
var reqBody, resBody DeleteBody
reqBody.Req = req
if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
return nil, err
}
return resBody.Res, nil
}
type GetBody struct {
Req *types.Get `xml:"urn:lookup Get,omitempty"`
Res *types.GetResponse `xml:"urn:lookup GetResponse,omitempty"`
Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
}
func (b *GetBody) Fault() *soap.Fault { return b.Fault_ }
func Get(ctx context.Context, r soap.RoundTripper, req *types.Get) (*types.GetResponse, error) {
var reqBody, resBody GetBody
reqBody.Req = req
if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
return nil, err
}
return resBody.Res, nil
}
type GetLocaleBody struct {
Req *types.GetLocale `xml:"urn:lookup GetLocale,omitempty"`
Res *types.GetLocaleResponse `xml:"urn:lookup GetLocaleResponse,omitempty"`
Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
}
func (b *GetLocaleBody) Fault() *soap.Fault { return b.Fault_ }
func GetLocale(ctx context.Context, r soap.RoundTripper, req *types.GetLocale) (*types.GetLocaleResponse, error) {
var reqBody, resBody GetLocaleBody
reqBody.Req = req
if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
return nil, err
}
return resBody.Res, nil
}
type GetSiteIdBody struct {
Req *types.GetSiteId `xml:"urn:lookup GetSiteId,omitempty"`
Res *types.GetSiteIdResponse `xml:"urn:lookup GetSiteIdResponse,omitempty"`
Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
}
func (b *GetSiteIdBody) Fault() *soap.Fault { return b.Fault_ }
func GetSiteId(ctx context.Context, r soap.RoundTripper, req *types.GetSiteId) (*types.GetSiteIdResponse, error) {
var reqBody, resBody GetSiteIdBody
reqBody.Req = req
if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
return nil, err
}
return resBody.Res, nil
}
type ListBody struct {
Req *types.List `xml:"urn:lookup List,omitempty"`
Res *types.ListResponse `xml:"urn:lookup ListResponse,omitempty"`
Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
}
func (b *ListBody) Fault() *soap.Fault { return b.Fault_ }
func List(ctx context.Context, r soap.RoundTripper, req *types.List) (*types.ListResponse, error) {
var reqBody, resBody ListBody
reqBody.Req = req
if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
return nil, err
}
return resBody.Res, nil
}
type RetrieveHaBackupConfigurationBody struct {
Req *types.RetrieveHaBackupConfiguration `xml:"urn:lookup RetrieveHaBackupConfiguration,omitempty"`
Res *types.RetrieveHaBackupConfigurationResponse `xml:"urn:lookup RetrieveHaBackupConfigurationResponse,omitempty"`
Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
}
func (b *RetrieveHaBackupConfigurationBody) Fault() *soap.Fault { return b.Fault_ }
func RetrieveHaBackupConfiguration(ctx context.Context, r soap.RoundTripper, req *types.RetrieveHaBackupConfiguration) (*types.RetrieveHaBackupConfigurationResponse, error) {
var reqBody, resBody RetrieveHaBackupConfigurationBody
reqBody.Req = req
if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
return nil, err
}
return resBody.Res, nil
}
type RetrieveServiceContentBody struct {
Req *types.RetrieveServiceContent `xml:"urn:lookup RetrieveServiceContent,omitempty"`
Res *types.RetrieveServiceContentResponse `xml:"urn:lookup RetrieveServiceContentResponse,omitempty"`
Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
}
func (b *RetrieveServiceContentBody) Fault() *soap.Fault { return b.Fault_ }
func RetrieveServiceContent(ctx context.Context, r soap.RoundTripper, req *types.RetrieveServiceContent) (*types.RetrieveServiceContentResponse, error) {
var reqBody, resBody RetrieveServiceContentBody
reqBody.Req = req
if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
return nil, err
}
return resBody.Res, nil
}
type SetBody struct {
Req *types.Set `xml:"urn:lookup Set,omitempty"`
Res *types.SetResponse `xml:"urn:lookup SetResponse,omitempty"`
Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
}
func (b *SetBody) Fault() *soap.Fault { return b.Fault_ }
func Set(ctx context.Context, r soap.RoundTripper, req *types.Set) (*types.SetResponse, error) {
var reqBody, resBody SetBody
reqBody.Req = req
if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
return nil, err
}
return resBody.Res, nil
}
type SetLocaleBody struct {
Req *types.SetLocale `xml:"urn:lookup SetLocale,omitempty"`
Res *types.SetLocaleResponse `xml:"urn:lookup SetLocaleResponse,omitempty"`
Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
}
func (b *SetLocaleBody) Fault() *soap.Fault { return b.Fault_ }
func SetLocale(ctx context.Context, r soap.RoundTripper, req *types.SetLocale) (*types.SetLocaleResponse, error) {
var reqBody, resBody SetLocaleBody
reqBody.Req = req
if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
return nil, err
}
return resBody.Res, nil
}

412
vendor/github.com/vmware/govmomi/lookup/types/types.go generated vendored Normal file
View File

@@ -0,0 +1,412 @@
/*
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 types
import (
"reflect"
"github.com/vmware/govmomi/vim25/types"
vim "github.com/vmware/govmomi/vim25/types"
)
type Create CreateRequestType
func init() {
types.Add("lookup:Create", reflect.TypeOf((*Create)(nil)).Elem())
}
type CreateRequestType struct {
This vim.ManagedObjectReference `xml:"_this"`
ServiceId string `xml:"serviceId"`
CreateSpec LookupServiceRegistrationCreateSpec `xml:"createSpec"`
}
func init() {
types.Add("lookup:CreateRequestType", reflect.TypeOf((*CreateRequestType)(nil)).Elem())
}
type CreateResponse struct {
}
type Delete DeleteRequestType
func init() {
types.Add("lookup:Delete", reflect.TypeOf((*Delete)(nil)).Elem())
}
type DeleteRequestType struct {
This vim.ManagedObjectReference `xml:"_this"`
ServiceId string `xml:"serviceId"`
}
func init() {
types.Add("lookup:DeleteRequestType", reflect.TypeOf((*DeleteRequestType)(nil)).Elem())
}
type DeleteResponse struct {
}
type Get GetRequestType
func init() {
types.Add("lookup:Get", reflect.TypeOf((*Get)(nil)).Elem())
}
type GetLocale GetLocaleRequestType
func init() {
types.Add("lookup:GetLocale", reflect.TypeOf((*GetLocale)(nil)).Elem())
}
type GetLocaleRequestType struct {
This vim.ManagedObjectReference `xml:"_this"`
}
func init() {
types.Add("lookup:GetLocaleRequestType", reflect.TypeOf((*GetLocaleRequestType)(nil)).Elem())
}
type GetLocaleResponse struct {
Returnval string `xml:"returnval"`
}
type GetRequestType struct {
This vim.ManagedObjectReference `xml:"_this"`
ServiceId string `xml:"serviceId"`
}
func init() {
types.Add("lookup:GetRequestType", reflect.TypeOf((*GetRequestType)(nil)).Elem())
}
type GetResponse struct {
Returnval LookupServiceRegistrationInfo `xml:"returnval"`
}
type GetSiteId GetSiteIdRequestType
func init() {
types.Add("lookup:GetSiteId", reflect.TypeOf((*GetSiteId)(nil)).Elem())
}
type GetSiteIdRequestType struct {
This vim.ManagedObjectReference `xml:"_this"`
}
func init() {
types.Add("lookup:GetSiteIdRequestType", reflect.TypeOf((*GetSiteIdRequestType)(nil)).Elem())
}
type GetSiteIdResponse struct {
Returnval string `xml:"returnval"`
}
type List ListRequestType
func init() {
types.Add("lookup:List", reflect.TypeOf((*List)(nil)).Elem())
}
type ListRequestType struct {
This vim.ManagedObjectReference `xml:"_this"`
FilterCriteria *LookupServiceRegistrationFilter `xml:"filterCriteria,omitempty"`
}
func init() {
types.Add("lookup:ListRequestType", reflect.TypeOf((*ListRequestType)(nil)).Elem())
}
type ListResponse struct {
Returnval []LookupServiceRegistrationInfo `xml:"returnval,omitempty"`
}
type LookupFaultEntryExistsFault struct {
LookupFaultServiceFault
Name string `xml:"name"`
}
func init() {
types.Add("lookup:LookupFaultEntryExistsFault", reflect.TypeOf((*LookupFaultEntryExistsFault)(nil)).Elem())
}
type LookupFaultEntryExistsFaultFault LookupFaultEntryExistsFault
func init() {
types.Add("lookup:LookupFaultEntryExistsFaultFault", reflect.TypeOf((*LookupFaultEntryExistsFaultFault)(nil)).Elem())
}
type LookupFaultEntryNotFoundFault struct {
LookupFaultServiceFault
Name string `xml:"name"`
}
func init() {
types.Add("lookup:LookupFaultEntryNotFoundFault", reflect.TypeOf((*LookupFaultEntryNotFoundFault)(nil)).Elem())
}
type LookupFaultEntryNotFoundFaultFault LookupFaultEntryNotFoundFault
func init() {
types.Add("lookup:LookupFaultEntryNotFoundFaultFault", reflect.TypeOf((*LookupFaultEntryNotFoundFaultFault)(nil)).Elem())
}
type LookupFaultServiceFault struct {
vim.MethodFault
ErrorMessage string `xml:"errorMessage,omitempty"`
}
func init() {
types.Add("lookup:LookupFaultServiceFault", reflect.TypeOf((*LookupFaultServiceFault)(nil)).Elem())
}
type LookupFaultUnsupportedSiteFault struct {
LookupFaultServiceFault
OperatingSite string `xml:"operatingSite"`
RequestedSite string `xml:"requestedSite"`
}
func init() {
types.Add("lookup:LookupFaultUnsupportedSiteFault", reflect.TypeOf((*LookupFaultUnsupportedSiteFault)(nil)).Elem())
}
type LookupFaultUnsupportedSiteFaultFault LookupFaultUnsupportedSiteFault
func init() {
types.Add("lookup:LookupFaultUnsupportedSiteFaultFault", reflect.TypeOf((*LookupFaultUnsupportedSiteFaultFault)(nil)).Elem())
}
type LookupHaBackupNodeConfiguration struct {
vim.DynamicData
DbType string `xml:"dbType"`
DbJdbcUrl string `xml:"dbJdbcUrl"`
DbUser string `xml:"dbUser"`
DbPass string `xml:"dbPass"`
}
func init() {
types.Add("lookup:LookupHaBackupNodeConfiguration", reflect.TypeOf((*LookupHaBackupNodeConfiguration)(nil)).Elem())
}
type LookupServiceContent struct {
vim.DynamicData
LookupService vim.ManagedObjectReference `xml:"lookupService"`
ServiceRegistration *vim.ManagedObjectReference `xml:"serviceRegistration,omitempty"`
DeploymentInformationService vim.ManagedObjectReference `xml:"deploymentInformationService"`
L10n vim.ManagedObjectReference `xml:"l10n"`
}
func init() {
types.Add("lookup:LookupServiceContent", reflect.TypeOf((*LookupServiceContent)(nil)).Elem())
}
type LookupServiceRegistrationAttribute struct {
vim.DynamicData
Key string `xml:"key"`
Value string `xml:"value"`
}
func init() {
types.Add("lookup:LookupServiceRegistrationAttribute", reflect.TypeOf((*LookupServiceRegistrationAttribute)(nil)).Elem())
}
type LookupServiceRegistrationCommonServiceInfo struct {
LookupServiceRegistrationMutableServiceInfo
OwnerId string `xml:"ownerId"`
ServiceType LookupServiceRegistrationServiceType `xml:"serviceType"`
NodeId string `xml:"nodeId,omitempty"`
}
func init() {
types.Add("lookup:LookupServiceRegistrationCommonServiceInfo", reflect.TypeOf((*LookupServiceRegistrationCommonServiceInfo)(nil)).Elem())
}
type LookupServiceRegistrationCreateSpec struct {
LookupServiceRegistrationCommonServiceInfo
}
func init() {
types.Add("lookup:LookupServiceRegistrationCreateSpec", reflect.TypeOf((*LookupServiceRegistrationCreateSpec)(nil)).Elem())
}
type LookupServiceRegistrationEndpoint struct {
vim.DynamicData
Url string `xml:"url"`
EndpointType LookupServiceRegistrationEndpointType `xml:"endpointType"`
SslTrust []string `xml:"sslTrust,omitempty"`
EndpointAttributes []LookupServiceRegistrationAttribute `xml:"endpointAttributes,omitempty"`
}
func init() {
types.Add("lookup:LookupServiceRegistrationEndpoint", reflect.TypeOf((*LookupServiceRegistrationEndpoint)(nil)).Elem())
}
type LookupServiceRegistrationEndpointType struct {
vim.DynamicData
Protocol string `xml:"protocol,omitempty"`
Type string `xml:"type,omitempty"`
}
func init() {
types.Add("lookup:LookupServiceRegistrationEndpointType", reflect.TypeOf((*LookupServiceRegistrationEndpointType)(nil)).Elem())
}
type LookupServiceRegistrationFilter struct {
vim.DynamicData
SiteId string `xml:"siteId,omitempty"`
NodeId string `xml:"nodeId,omitempty"`
ServiceType *LookupServiceRegistrationServiceType `xml:"serviceType,omitempty"`
EndpointType *LookupServiceRegistrationEndpointType `xml:"endpointType,omitempty"`
}
func init() {
types.Add("lookup:LookupServiceRegistrationFilter", reflect.TypeOf((*LookupServiceRegistrationFilter)(nil)).Elem())
}
type LookupServiceRegistrationInfo struct {
LookupServiceRegistrationCommonServiceInfo
ServiceId string `xml:"serviceId"`
SiteId string `xml:"siteId"`
}
func init() {
types.Add("lookup:LookupServiceRegistrationInfo", reflect.TypeOf((*LookupServiceRegistrationInfo)(nil)).Elem())
}
type LookupServiceRegistrationMutableServiceInfo struct {
vim.DynamicData
ServiceVersion string `xml:"serviceVersion"`
VendorNameResourceKey string `xml:"vendorNameResourceKey,omitempty"`
VendorNameDefault string `xml:"vendorNameDefault,omitempty"`
VendorProductInfoResourceKey string `xml:"vendorProductInfoResourceKey,omitempty"`
VendorProductInfoDefault string `xml:"vendorProductInfoDefault,omitempty"`
ServiceEndpoints []LookupServiceRegistrationEndpoint `xml:"serviceEndpoints,omitempty"`
ServiceAttributes []LookupServiceRegistrationAttribute `xml:"serviceAttributes,omitempty"`
ServiceNameResourceKey string `xml:"serviceNameResourceKey,omitempty"`
ServiceNameDefault string `xml:"serviceNameDefault,omitempty"`
ServiceDescriptionResourceKey string `xml:"serviceDescriptionResourceKey,omitempty"`
ServiceDescriptionDefault string `xml:"serviceDescriptionDefault,omitempty"`
}
func init() {
types.Add("lookup:LookupServiceRegistrationMutableServiceInfo", reflect.TypeOf((*LookupServiceRegistrationMutableServiceInfo)(nil)).Elem())
}
type LookupServiceRegistrationServiceType struct {
vim.DynamicData
Product string `xml:"product"`
Type string `xml:"type"`
}
func init() {
types.Add("lookup:LookupServiceRegistrationServiceType", reflect.TypeOf((*LookupServiceRegistrationServiceType)(nil)).Elem())
}
type LookupServiceRegistrationSetSpec struct {
LookupServiceRegistrationMutableServiceInfo
}
func init() {
types.Add("lookup:LookupServiceRegistrationSetSpec", reflect.TypeOf((*LookupServiceRegistrationSetSpec)(nil)).Elem())
}
type RetrieveHaBackupConfiguration RetrieveHaBackupConfigurationRequestType
func init() {
types.Add("lookup:RetrieveHaBackupConfiguration", reflect.TypeOf((*RetrieveHaBackupConfiguration)(nil)).Elem())
}
type RetrieveHaBackupConfigurationRequestType struct {
This vim.ManagedObjectReference `xml:"_this"`
}
func init() {
types.Add("lookup:RetrieveHaBackupConfigurationRequestType", reflect.TypeOf((*RetrieveHaBackupConfigurationRequestType)(nil)).Elem())
}
type RetrieveHaBackupConfigurationResponse struct {
Returnval LookupHaBackupNodeConfiguration `xml:"returnval"`
}
type RetrieveServiceContent RetrieveServiceContentRequestType
func init() {
types.Add("lookup:RetrieveServiceContent", reflect.TypeOf((*RetrieveServiceContent)(nil)).Elem())
}
type RetrieveServiceContentRequestType struct {
This vim.ManagedObjectReference `xml:"_this"`
}
func init() {
types.Add("lookup:RetrieveServiceContentRequestType", reflect.TypeOf((*RetrieveServiceContentRequestType)(nil)).Elem())
}
type RetrieveServiceContentResponse struct {
Returnval LookupServiceContent `xml:"returnval"`
}
type Set SetRequestType
func init() {
types.Add("lookup:Set", reflect.TypeOf((*Set)(nil)).Elem())
}
type SetLocale SetLocaleRequestType
func init() {
types.Add("lookup:SetLocale", reflect.TypeOf((*SetLocale)(nil)).Elem())
}
type SetLocaleRequestType struct {
This vim.ManagedObjectReference `xml:"_this"`
Locale string `xml:"locale"`
}
func init() {
types.Add("lookup:SetLocaleRequestType", reflect.TypeOf((*SetLocaleRequestType)(nil)).Elem())
}
type SetLocaleResponse struct {
Returnval string `xml:"returnval"`
}
type SetRequestType struct {
This vim.ManagedObjectReference `xml:"_this"`
ServiceId string `xml:"serviceId"`
ServiceSpec LookupServiceRegistrationSetSpec `xml:"serviceSpec"`
}
func init() {
types.Add("lookup:SetRequestType", reflect.TypeOf((*SetRequestType)(nil)).Elem())
}
type SetResponse struct {
}

128
vendor/github.com/vmware/govmomi/ovf/cim.go generated vendored Normal file
View File

@@ -0,0 +1,128 @@
/*
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 ovf
import (
"github.com/vmware/govmomi/vim25/types"
)
/*
Source: http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.24.0/CIM_VirtualSystemSettingData.xsd
*/
type CIMVirtualSystemSettingData struct {
ElementName string `xml:"ElementName"`
InstanceID string `xml:"InstanceID"`
AutomaticRecoveryAction *uint8 `xml:"AutomaticRecoveryAction"`
AutomaticShutdownAction *uint8 `xml:"AutomaticShutdownAction"`
AutomaticStartupAction *uint8 `xml:"AutomaticStartupAction"`
AutomaticStartupActionDelay *string `xml:"AutomaticStartupActionDelay>Interval"`
AutomaticStartupActionSequenceNumber *uint16 `xml:"AutomaticStartupActionSequenceNumber"`
Caption *string `xml:"Caption"`
ConfigurationDataRoot *string `xml:"ConfigurationDataRoot"`
ConfigurationFile *string `xml:"ConfigurationFile"`
ConfigurationID *string `xml:"ConfigurationID"`
CreationTime *string `xml:"CreationTime"`
Description *string `xml:"Description"`
LogDataRoot *string `xml:"LogDataRoot"`
Notes []string `xml:"Notes"`
RecoveryFile *string `xml:"RecoveryFile"`
SnapshotDataRoot *string `xml:"SnapshotDataRoot"`
SuspendDataRoot *string `xml:"SuspendDataRoot"`
SwapFileDataRoot *string `xml:"SwapFileDataRoot"`
VirtualSystemIdentifier *string `xml:"VirtualSystemIdentifier"`
VirtualSystemType *string `xml:"VirtualSystemType"`
}
/*
Source: http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.24.0/CIM_ResourceAllocationSettingData.xsd
*/
type CIMResourceAllocationSettingData struct {
ElementName string `xml:"ElementName"`
InstanceID string `xml:"InstanceID"`
ResourceType *uint16 `xml:"ResourceType"`
OtherResourceType *string `xml:"OtherResourceType"`
ResourceSubType *string `xml:"ResourceSubType"`
AddressOnParent *string `xml:"AddressOnParent"`
Address *string `xml:"Address"`
AllocationUnits *string `xml:"AllocationUnits"`
AutomaticAllocation *bool `xml:"AutomaticAllocation"`
AutomaticDeallocation *bool `xml:"AutomaticDeallocation"`
Caption *string `xml:"Caption"`
Connection []string `xml:"Connection"`
ConsumerVisibility *uint16 `xml:"ConsumerVisibility"`
Description *string `xml:"Description"`
HostResource []string `xml:"HostResource"`
Limit *uint64 `xml:"Limit"`
MappingBehavior *uint `xml:"MappingBehavior"`
Parent *string `xml:"Parent"`
PoolID *string `xml:"PoolID"`
Reservation *uint64 `xml:"Reservation"`
VirtualQuantity *uint `xml:"VirtualQuantity"`
VirtualQuantityUnits *string `xml:"VirtualQuantityUnits"`
Weight *uint `xml:"Weight"`
}
/*
Source: http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.24.0/CIM_StorageAllocationSettingData.xsd
*/
type CIMStorageAllocationSettingData struct {
ElementName string `xml:"ElementName"`
InstanceID string `xml:"InstanceID"`
ResourceType *uint16 `xml:"ResourceType"`
OtherResourceType *string `xml:"OtherResourceType"`
ResourceSubType *string `xml:"ResourceSubType"`
Access *uint16 `xml:"Access"`
Address *string `xml:"Address"`
AddressOnParent *string `xml:"AddressOnParent"`
AllocationUnits *string `xml:"AllocationUnits"`
AutomaticAllocation *bool `xml:"AutomaticAllocation"`
AutomaticDeallocation *bool `xml:"AutomaticDeallocation"`
Caption *string `xml:"Caption"`
ChangeableType *uint16 `xml:"ChangeableType"`
ComponentSetting []types.AnyType `xml:"ComponentSetting"`
ConfigurationName *string `xml:"ConfigurationName"`
Connection []string `xml:"Connection"`
ConsumerVisibility *uint16 `xml:"ConsumerVisibility"`
Description *string `xml:"Description"`
Generation *uint64 `xml:"Generation"`
HostExtentName *string `xml:"HostExtentName"`
HostExtentNameFormat *uint16 `xml:"HostExtentNameFormat"`
HostExtentNameNamespace *uint16 `xml:"HostExtentNameNamespace"`
HostExtentStartingAddress *uint64 `xml:"HostExtentStartingAddress"`
HostResource []string `xml:"HostResource"`
HostResourceBlockSize *uint64 `xml:"HostResourceBlockSize"`
Limit *uint64 `xml:"Limit"`
MappingBehavior *uint `xml:"MappingBehavior"`
OtherHostExtentNameFormat *string `xml:"OtherHostExtentNameFormat"`
OtherHostExtentNameNamespace *string `xml:"OtherHostExtentNameNamespace"`
Parent *string `xml:"Parent"`
PoolID *string `xml:"PoolID"`
Reservation *uint64 `xml:"Reservation"`
SoID *string `xml:"SoID"`
SoOrgID *string `xml:"SoOrgID"`
VirtualQuantity *uint `xml:"VirtualQuantity"`
VirtualQuantityUnits *string `xml:"VirtualQuantityUnits"`
VirtualResourceBlockSize *uint64 `xml:"VirtualResourceBlockSize"`
Weight *uint `xml:"Weight"`
}

25
vendor/github.com/vmware/govmomi/ovf/doc.go generated vendored Normal file
View File

@@ -0,0 +1,25 @@
/*
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 ovf provides functionality to unmarshal and inspect the structure
of an OVF file. It is not a complete implementation of the specification and
is intended to be used to import virtual infrastructure into vSphere.
For a complete specification of the OVF standard, refer to:
https://www.dmtf.org/sites/default/files/standards/documents/DSP0243_2.1.0.pdf
*/
package ovf

99
vendor/github.com/vmware/govmomi/ovf/env.go generated vendored Normal file
View File

@@ -0,0 +1,99 @@
/*
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 ovf
import (
"bytes"
"fmt"
"github.com/vmware/govmomi/vim25/xml"
)
const (
ovfEnvHeader = `<Environment
xmlns="http://schemas.dmtf.org/ovf/environment/1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oe="http://schemas.dmtf.org/ovf/environment/1"
xmlns:ve="http://www.vmware.com/schema/ovfenv"
oe:id=""
ve:esxId="%s">`
ovfEnvPlatformSection = `<PlatformSection>
<Kind>%s</Kind>
<Version>%s</Version>
<Vendor>%s</Vendor>
<Locale>%s</Locale>
</PlatformSection>`
ovfEnvPropertyHeader = `<PropertySection>`
ovfEnvPropertyEntry = `<Property oe:key="%s" oe:value="%s"/>`
ovfEnvPropertyFooter = `</PropertySection>`
ovfEnvFooter = `</Environment>`
)
type Env struct {
XMLName xml.Name `xml:"http://schemas.dmtf.org/ovf/environment/1 Environment"`
ID string `xml:"id,attr"`
EsxID string `xml:"http://www.vmware.com/schema/ovfenv esxId,attr"`
Platform *PlatformSection `xml:"PlatformSection"`
Property *PropertySection `xml:"PropertySection"`
}
type PlatformSection struct {
Kind string `xml:"Kind"`
Version string `xml:"Version"`
Vendor string `xml:"Vendor"`
Locale string `xml:"Locale"`
}
type PropertySection struct {
Properties []EnvProperty `xml:"Property"`
}
type EnvProperty struct {
Key string `xml:"key,attr"`
Value string `xml:"value,attr"`
}
// Marshal marshals Env to xml by using xml.Marshal.
func (e Env) Marshal() (string, error) {
x, err := xml.Marshal(e)
if err != nil {
return "", err
}
return fmt.Sprintf("%s%s", xml.Header, x), nil
}
// MarshalManual manually marshals Env to xml suitable for a vApp guest.
// It exists to overcome the lack of expressiveness in Go's XML namespaces.
func (e Env) MarshalManual() string {
var buffer bytes.Buffer
buffer.WriteString(xml.Header)
buffer.WriteString(fmt.Sprintf(ovfEnvHeader, e.EsxID))
buffer.WriteString(fmt.Sprintf(ovfEnvPlatformSection, e.Platform.Kind, e.Platform.Version, e.Platform.Vendor, e.Platform.Locale))
buffer.WriteString(fmt.Sprint(ovfEnvPropertyHeader))
for _, p := range e.Property.Properties {
buffer.WriteString(fmt.Sprintf(ovfEnvPropertyEntry, p.Key, p.Value))
}
buffer.WriteString(fmt.Sprint(ovfEnvPropertyFooter))
buffer.WriteString(fmt.Sprint(ovfEnvFooter))
return buffer.String()
}

200
vendor/github.com/vmware/govmomi/ovf/envelope.go generated vendored Normal file
View File

@@ -0,0 +1,200 @@
/*
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 ovf
type Envelope struct {
References []File `xml:"References>File"`
// Package level meta-data
Annotation *AnnotationSection `xml:"AnnotationSection"`
Product *ProductSection `xml:"ProductSection"`
Network *NetworkSection `xml:"NetworkSection"`
Disk *DiskSection `xml:"DiskSection"`
OperatingSystem *OperatingSystemSection `xml:"OperatingSystemSection"`
Eula *EulaSection `xml:"EulaSection"`
VirtualHardware *VirtualHardwareSection `xml:"VirtualHardwareSection"`
ResourceAllocation *ResourceAllocationSection `xml:"ResourceAllocationSection"`
DeploymentOption *DeploymentOptionSection `xml:"DeploymentOptionSection"`
// Content: A VirtualSystem or a VirtualSystemCollection
VirtualSystem *VirtualSystem `xml:"VirtualSystem"`
}
type VirtualSystem struct {
Content
Annotation []AnnotationSection `xml:"AnnotationSection"`
Product []ProductSection `xml:"ProductSection"`
OperatingSystem []OperatingSystemSection `xml:"OperatingSystemSection"`
Eula []EulaSection `xml:"EulaSection"`
VirtualHardware []VirtualHardwareSection `xml:"VirtualHardwareSection"`
}
type File struct {
ID string `xml:"id,attr"`
Href string `xml:"href,attr"`
Size uint `xml:"size,attr"`
Compression *string `xml:"compression,attr"`
ChunkSize *int `xml:"chunkSize,attr"`
}
type Content struct {
ID string `xml:"id,attr"`
Info string `xml:"Info"`
Name *string `xml:"Name"`
}
type Section struct {
Required *bool `xml:"required,attr"`
Info string `xml:"Info"`
}
type AnnotationSection struct {
Section
Annotation string `xml:"Annotation"`
}
type ProductSection struct {
Section
Class *string `xml:"class,attr"`
Instance *string `xml:"instance,attr"`
Product string `xml:"Product"`
Vendor string `xml:"Vendor"`
Version string `xml:"Version"`
FullVersion string `xml:"FullVersion"`
ProductURL string `xml:"ProductUrl"`
VendorURL string `xml:"VendorUrl"`
AppURL string `xml:"AppUrl"`
Property []Property `xml:"Property"`
}
type Property struct {
Key string `xml:"key,attr"`
Type string `xml:"type,attr"`
Qualifiers *string `xml:"qualifiers,attr"`
UserConfigurable *bool `xml:"userConfigurable,attr"`
Default *string `xml:"value,attr"`
Password *bool `xml:"password,attr"`
Label *string `xml:"Label"`
Description *string `xml:"Description"`
Values []PropertyConfigurationValue `xml:"Value"`
}
type PropertyConfigurationValue struct {
Value string `xml:"value,attr"`
Configuration *string `xml:"configuration,attr"`
}
type NetworkSection struct {
Section
Networks []Network `xml:"Network"`
}
type Network struct {
Name string `xml:"name,attr"`
Description string `xml:"Description"`
}
type DiskSection struct {
Section
Disks []VirtualDiskDesc `xml:"Disk"`
}
type VirtualDiskDesc struct {
DiskID string `xml:"diskId,attr"`
FileRef *string `xml:"fileRef,attr"`
Capacity string `xml:"capacity,attr"`
CapacityAllocationUnits *string `xml:"capacityAllocationUnits,attr"`
Format *string `xml:"format,attr"`
PopulatedSize *int `xml:"populatedSize,attr"`
ParentRef *string `xml:"parentRef,attr"`
}
type OperatingSystemSection struct {
Section
ID int16 `xml:"id,attr"`
Version *string `xml:"version,attr"`
OSType *string `xml:"osType,attr"`
Description *string `xml:"Description"`
}
type EulaSection struct {
Section
License string `xml:"License"`
}
type VirtualHardwareSection struct {
Section
ID *string `xml:"id,attr"`
Transport *string `xml:"transport,attr"`
System *VirtualSystemSettingData `xml:"System"`
Item []ResourceAllocationSettingData `xml:"Item"`
StorageItem []StorageAllocationSettingData `xml:"StorageItem"`
}
type VirtualSystemSettingData struct {
CIMVirtualSystemSettingData
}
type ResourceAllocationSettingData struct {
CIMResourceAllocationSettingData
Required *bool `xml:"required,attr"`
Configuration *string `xml:"configuration,attr"`
Bound *string `xml:"bound,attr"`
}
type StorageAllocationSettingData struct {
CIMStorageAllocationSettingData
Required *bool `xml:"required,attr"`
Configuration *string `xml:"configuration,attr"`
Bound *string `xml:"bound,attr"`
}
type ResourceAllocationSection struct {
Section
Item []ResourceAllocationSettingData `xml:"Item"`
}
type DeploymentOptionSection struct {
Section
Configuration []DeploymentOptionConfiguration `xml:"Configuration"`
}
type DeploymentOptionConfiguration struct {
ID string `xml:"id,attr"`
Default *bool `xml:"default,attr"`
Label string `xml:"Label"`
Description string `xml:"Description"`
}

103
vendor/github.com/vmware/govmomi/ovf/manager.go generated vendored Normal file
View File

@@ -0,0 +1,103 @@
/*
Copyright (c) 2015-2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ovf
import (
"context"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/methods"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
type Manager struct {
types.ManagedObjectReference
c *vim25.Client
}
func NewManager(c *vim25.Client) *Manager {
return &Manager{*c.ServiceContent.OvfManager, c}
}
// CreateDescriptor wraps methods.CreateDescriptor
func (m *Manager) CreateDescriptor(ctx context.Context, obj mo.Reference, cdp types.OvfCreateDescriptorParams) (*types.OvfCreateDescriptorResult, error) {
req := types.CreateDescriptor{
This: m.Reference(),
Obj: obj.Reference(),
Cdp: cdp,
}
res, err := methods.CreateDescriptor(ctx, m.c, &req)
if err != nil {
return nil, err
}
return &res.Returnval, nil
}
// CreateImportSpec wraps methods.CreateImportSpec
func (m *Manager) CreateImportSpec(ctx context.Context, ovfDescriptor string, resourcePool mo.Reference, datastore mo.Reference, cisp types.OvfCreateImportSpecParams) (*types.OvfCreateImportSpecResult, error) {
req := types.CreateImportSpec{
This: m.Reference(),
OvfDescriptor: ovfDescriptor,
ResourcePool: resourcePool.Reference(),
Datastore: datastore.Reference(),
Cisp: cisp,
}
res, err := methods.CreateImportSpec(ctx, m.c, &req)
if err != nil {
return nil, err
}
return &res.Returnval, nil
}
// ParseDescriptor wraps methods.ParseDescriptor
func (m *Manager) ParseDescriptor(ctx context.Context, ovfDescriptor string, pdp types.OvfParseDescriptorParams) (*types.OvfParseDescriptorResult, error) {
req := types.ParseDescriptor{
This: m.Reference(),
OvfDescriptor: ovfDescriptor,
Pdp: pdp,
}
res, err := methods.ParseDescriptor(ctx, m.c, &req)
if err != nil {
return nil, err
}
return &res.Returnval, nil
}
// ValidateHost wraps methods.ValidateHost
func (m *Manager) ValidateHost(ctx context.Context, ovfDescriptor string, host mo.Reference, vhp types.OvfValidateHostParams) (*types.OvfValidateHostResult, error) {
req := types.ValidateHost{
This: m.Reference(),
OvfDescriptor: ovfDescriptor,
Host: host.Reference(),
Vhp: vhp,
}
res, err := methods.ValidateHost(ctx, m.c, &req)
if err != nil {
return nil, err
}
return &res.Returnval, nil
}

35
vendor/github.com/vmware/govmomi/ovf/ovf.go generated vendored Normal file
View File

@@ -0,0 +1,35 @@
/*
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 ovf
import (
"io"
"github.com/vmware/govmomi/vim25/xml"
)
func Unmarshal(r io.Reader) (*Envelope, error) {
var e Envelope
dec := xml.NewDecoder(r)
err := dec.Decode(&e)
if err != nil {
return nil, err
}
return &e, nil
}

209
vendor/github.com/vmware/govmomi/sts/client.go generated vendored Normal file
View File

@@ -0,0 +1,209 @@
/*
Copyright (c) 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 sts
import (
"context"
"crypto/tls"
"errors"
"net/url"
"time"
"github.com/vmware/govmomi/lookup"
"github.com/vmware/govmomi/lookup/types"
"github.com/vmware/govmomi/sts/internal"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/soap"
)
const (
Namespace = "oasis:names:tc:SAML:2.0:assertion"
Path = "/sts/STSService"
)
// Client is a soap.Client targeting the STS (Secure Token Service) API endpoint.
type Client struct {
*soap.Client
}
// NewClient returns a client targeting the STS API endpoint.
// The Client.URL will be set to that of the Lookup Service's endpoint registration,
// as the SSO endpoint can be external to vCenter. If the Lookup Service is not available,
// URL defaults to Path on the vim25.Client.URL.Host.
func NewClient(ctx context.Context, c *vim25.Client) (*Client, error) {
filter := &types.LookupServiceRegistrationFilter{
ServiceType: &types.LookupServiceRegistrationServiceType{
Product: "com.vmware.cis",
Type: "cs.identity",
},
EndpointType: &types.LookupServiceRegistrationEndpointType{
Protocol: "wsTrust",
Type: "com.vmware.cis.cs.identity.sso",
},
}
url := lookup.EndpointURL(ctx, c, Path, filter)
sc := c.Client.NewServiceClient(url, Namespace)
return &Client{sc}, nil
}
// TokenRequest parameters for issuing a SAML token.
// At least one of Userinfo or Certificate must be specified.
type TokenRequest struct {
Userinfo *url.Userinfo // Userinfo when set issues a Bearer token
Certificate *tls.Certificate // Certificate when set issues a HoK token
Lifetime time.Duration // Lifetime is the token's lifetime, defaults to 10m
Renewable bool // Renewable allows the issued token to be renewed
Delegatable bool // Delegatable allows the issued token to be delegated (e.g. for use with ActAs)
ActAs bool // ActAs allows to request an ActAs token based on the passed Token.
Token string // Token for Renew request or Issue request ActAs identity or to be exchanged.
KeyType string // KeyType for requested token (if not set will be decucted from Userinfo and Certificate options)
KeyID string // KeyID used for signing the requests
}
func (c *Client) newRequest(req TokenRequest, kind string, s *Signer) (internal.RequestSecurityToken, error) {
if req.Lifetime == 0 {
req.Lifetime = 5 * time.Minute
}
created := time.Now().UTC()
rst := internal.RequestSecurityToken{
TokenType: c.Namespace,
RequestType: "http://docs.oasis-open.org/ws-sx/ws-trust/200512/" + kind,
SignatureAlgorithm: internal.SHA256,
Lifetime: &internal.Lifetime{
Created: created.Format(internal.Time),
Expires: created.Add(req.Lifetime).Format(internal.Time),
},
Renewing: &internal.Renewing{
Allow: req.Renewable,
// /wst:RequestSecurityToken/wst:Renewing/@OK
// "It NOT RECOMMENDED to use this as it can leave you open to certain types of security attacks.
// Issuers MAY restrict the period after expiration during which time the token can be renewed.
// This window is governed by the issuer's policy."
OK: false,
},
Delegatable: req.Delegatable,
KeyType: req.KeyType,
}
if req.KeyType == "" {
// Deduce KeyType based on Certificate nad Userinfo.
if req.Certificate == nil {
if req.Userinfo == nil {
return rst, errors.New("one of TokenRequest Certificate or Userinfo is required")
}
rst.KeyType = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer"
} else {
rst.KeyType = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/PublicKey"
// For HOK KeyID is required.
if req.KeyID == "" {
req.KeyID = newID()
}
}
}
if req.KeyID != "" {
rst.UseKey = &internal.UseKey{Sig: req.KeyID}
s.keyID = rst.UseKey.Sig
}
return rst, nil
}
func (s *Signer) setLifetime(lifetime *internal.Lifetime) error {
var err error
if lifetime != nil {
s.Lifetime.Created, err = time.Parse(internal.Time, lifetime.Created)
if err == nil {
s.Lifetime.Expires, err = time.Parse(internal.Time, lifetime.Expires)
}
}
return err
}
// Issue is used to request a security token.
// The returned Signer can be used to sign SOAP requests, such as the SessionManager LoginByToken method and the RequestSecurityToken method itself.
// One of TokenRequest Certificate or Userinfo is required, with Certificate taking precedence.
// When Certificate is set, a Holder-of-Key token will be requested. Otherwise, a Bearer token is requested with the Userinfo credentials.
// See: http://docs.oasis-open.org/ws-sx/ws-trust/v1.4/errata01/os/ws-trust-1.4-errata01-os-complete.html#_Toc325658937
func (c *Client) Issue(ctx context.Context, req TokenRequest) (*Signer, error) {
s := &Signer{
Certificate: req.Certificate,
keyID: req.KeyID,
Token: req.Token,
user: req.Userinfo,
}
rst, err := c.newRequest(req, "Issue", s)
if err != nil {
return nil, err
}
if req.ActAs {
rst.ActAs = &internal.Target{
Token: req.Token,
}
}
header := soap.Header{
Security: s,
Action: rst.Action(),
}
res, err := internal.Issue(c.WithHeader(ctx, header), c, &rst)
if err != nil {
return nil, err
}
s.Token = res.RequestSecurityTokenResponse.RequestedSecurityToken.Assertion
return s, s.setLifetime(res.RequestSecurityTokenResponse.Lifetime)
}
// Renew is used to request a security token renewal.
func (c *Client) Renew(ctx context.Context, req TokenRequest) (*Signer, error) {
s := &Signer{
Certificate: req.Certificate,
}
rst, err := c.newRequest(req, "Renew", s)
if err != nil {
return nil, err
}
if req.Token == "" {
return nil, errors.New("TokenRequest Token is required")
}
rst.RenewTarget = &internal.Target{Token: req.Token}
header := soap.Header{
Security: s,
Action: rst.Action(),
}
res, err := internal.Renew(c.WithHeader(ctx, header), c, &rst)
if err != nil {
return nil, err
}
s.Token = res.RequestedSecurityToken.Assertion
return s, s.setLifetime(res.Lifetime)
}

694
vendor/github.com/vmware/govmomi/sts/internal/types.go generated vendored Normal file
View File

@@ -0,0 +1,694 @@
/*
Copyright (c) 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 internal
// The sts/internal package provides the types for invoking the sts.Issue method.
// The sts.Issue and SessionManager LoginByToken methods require an XML signature.
// Unlike the JRE and .NET runtimes, the Go stdlib does not support XML signing.
// We should considering contributing to the goxmldsig package and gosaml2 to meet
// the needs of sts.Issue rather than maintaining this package long term.
// The tricky part of xmldig is the XML canonicalization (C14N), which is responsible
// for most of the make-your-eyes bleed XML formatting in this package.
// C14N is also why some structures use xml.Name without a field tag and methods modify the xml.Name directly,
// though also working around Go's handling of XML namespace prefixes.
// Most of the types in this package were originally generated from the wsdl and hacked up gen/ scripts,
// but have since been modified by hand.
import (
"bytes"
"context"
"crypto/sha256"
"encoding/base64"
"fmt"
"log"
"path"
"reflect"
"strings"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
"github.com/vmware/govmomi/vim25/xml"
)
const (
XSI = "http://www.w3.org/2001/XMLSchema-instance"
WSU = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
DSIG = "http://www.w3.org/2000/09/xmldsig#"
SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
Time = "2006-01-02T15:04:05.000Z"
)
// Security is used as soap.Envelope.Header.Security when signing requests.
type Security struct {
XMLName xml.Name `xml:"wsse:Security"`
WSSE string `xml:"xmlns:wsse,attr"`
WSU string `xml:"xmlns:wsu,attr"`
Timestamp Timestamp
BinarySecurityToken *BinarySecurityToken `xml:",omitempty"`
UsernameToken *UsernameToken `xml:",omitempty"`
Assertion string `xml:",innerxml"`
Signature *Signature `xml:",omitempty"`
}
type Timestamp struct {
XMLName xml.Name `xml:"wsu:Timestamp"`
NS string `xml:"xmlns:wsu,attr"`
ID string `xml:"wsu:Id,attr"`
Created string `xml:"wsu:Created"`
Expires string `xml:"wsu:Expires"`
}
func (t *Timestamp) C14N() string {
return Marshal(t)
}
type BinarySecurityToken struct {
XMLName xml.Name `xml:"wsse:BinarySecurityToken"`
EncodingType string `xml:"EncodingType,attr"`
ValueType string `xml:"ValueType,attr"`
ID string `xml:"wsu:Id,attr"`
Value string `xml:",chardata"`
}
type UsernameToken struct {
XMLName xml.Name `xml:"wsse:UsernameToken"`
Username string `xml:"wsse:Username"`
Password string `xml:"wsse:Password"`
}
type Signature struct {
XMLName xml.Name
NS string `xml:"xmlns:ds,attr"`
ID string `xml:"Id,attr"`
SignedInfo SignedInfo
SignatureValue Value
KeyInfo KeyInfo
}
func (s *Signature) C14N() string {
return fmt.Sprintf(`<ds:Signature xmlns:ds="%s">%s%s%s</ds:Signature>`,
DSIG, s.SignedInfo.C14N(), s.SignatureValue.C14N(), s.KeyInfo.C14N())
}
type SignedInfo struct {
XMLName xml.Name
NS string `xml:"xmlns:ds,attr,omitempty"`
CanonicalizationMethod Method
SignatureMethod Method
Reference []Reference
}
func (s SignedInfo) C14N() string {
ns := "" // empty in ActAs c14n form for example
if s.NS != "" {
ns = fmt.Sprintf(` xmlns:ds="%s"`, s.NS)
}
c14n := []string{fmt.Sprintf("<ds:SignedInfo%s>", ns)}
c14n = append(c14n, s.CanonicalizationMethod.C14N(), s.SignatureMethod.C14N())
for i := range s.Reference {
c14n = append(c14n, s.Reference[i].C14N())
}
c14n = append(c14n, "</ds:SignedInfo>")
return strings.Join(c14n, "")
}
type Method struct {
XMLName xml.Name
Algorithm string `xml:",attr"`
}
func (m *Method) C14N() string {
return mkns("ds", m, &m.XMLName)
}
type Value struct {
XMLName xml.Name
Value string `xml:",innerxml"`
}
func (v *Value) C14N() string {
return mkns("ds", v, &v.XMLName)
}
type Reference struct {
XMLName xml.Name
URI string `xml:",attr"`
Transforms Transforms
DigestMethod Method
DigestValue Value
}
func (r Reference) C14N() string {
for i := range r.Transforms.Transform {
t := &r.Transforms.Transform[i]
t.XMLName.Local = "ds:Transform"
t.XMLName.Space = ""
if t.InclusiveNamespaces != nil {
name := &t.InclusiveNamespaces.XMLName
if !strings.HasPrefix(name.Local, "ec:") {
name.Local = "ec:" + name.Local
name.Space = ""
}
t.InclusiveNamespaces.NS = t.Algorithm
}
}
c14n := []string{
fmt.Sprintf(`<ds:Reference URI="%s">`, r.URI),
r.Transforms.C14N(),
r.DigestMethod.C14N(),
r.DigestValue.C14N(),
"</ds:Reference>",
}
return strings.Join(c14n, "")
}
func NewReference(id string, val string) Reference {
sum := sha256.Sum256([]byte(val))
return Reference{
XMLName: xml.Name{Local: "ds:Reference"},
URI: "#" + id,
Transforms: Transforms{
XMLName: xml.Name{Local: "ds:Transforms"},
Transform: []Transform{
Transform{
XMLName: xml.Name{Local: "ds:Transform"},
Algorithm: "http://www.w3.org/2001/10/xml-exc-c14n#",
},
},
},
DigestMethod: Method{
XMLName: xml.Name{Local: "ds:DigestMethod"},
Algorithm: "http://www.w3.org/2001/04/xmlenc#sha256",
},
DigestValue: Value{
XMLName: xml.Name{Local: "ds:DigestValue"},
Value: base64.StdEncoding.EncodeToString(sum[:]),
},
}
}
type Transforms struct {
XMLName xml.Name
Transform []Transform
}
func (t *Transforms) C14N() string {
return mkns("ds", t, &t.XMLName)
}
type Transform struct {
XMLName xml.Name
Algorithm string `xml:",attr"`
InclusiveNamespaces *InclusiveNamespaces `xml:",omitempty"`
}
type InclusiveNamespaces struct {
XMLName xml.Name
NS string `xml:"xmlns:ec,attr,omitempty"`
PrefixList string `xml:",attr"`
}
type X509Data struct {
XMLName xml.Name
X509Certificate string `xml:",innerxml"`
}
type KeyInfo struct {
XMLName xml.Name
NS string `xml:"xmlns:ds,attr,omitempty"`
SecurityTokenReference *SecurityTokenReference `xml:",omitempty"`
X509Data *X509Data `xml:",omitempty"`
}
func (o *KeyInfo) C14N() string {
names := []*xml.Name{
&o.XMLName,
}
if o.SecurityTokenReference != nil {
names = append(names, &o.SecurityTokenReference.XMLName)
}
if o.X509Data != nil {
names = append(names, &o.X509Data.XMLName)
}
return mkns("ds", o, names...)
}
type SecurityTokenReference struct {
XMLName xml.Name `xml:"wsse:SecurityTokenReference"`
WSSE11 string `xml:"xmlns:wsse11,attr,omitempty"`
TokenType string `xml:"wsse11:TokenType,attr,omitempty"`
Reference *SecurityReference `xml:",omitempty"`
KeyIdentifier *KeyIdentifier `xml:",omitempty"`
}
type SecurityReference struct {
XMLName xml.Name `xml:"wsse:Reference"`
URI string `xml:",attr"`
ValueType string `xml:",attr"`
}
type KeyIdentifier struct {
XMLName xml.Name `xml:"wsse:KeyIdentifier"`
ID string `xml:",innerxml"`
ValueType string `xml:",attr"`
}
type Issuer struct {
XMLName xml.Name
Format string `xml:",attr"`
Value string `xml:",innerxml"`
}
func (i *Issuer) C14N() string {
return mkns("saml2", i, &i.XMLName)
}
type Assertion struct {
XMLName xml.Name
ID string `xml:",attr"`
IssueInstant string `xml:",attr"`
Version string `xml:",attr"`
Issuer Issuer
Signature Signature
Subject Subject
Conditions Conditions
AuthnStatement AuthnStatement
AttributeStatement AttributeStatement
}
func (a *Assertion) C14N() string {
start := `<saml2:Assertion xmlns:saml2="%s" ID="%s" IssueInstant="%s" Version="%s">`
c14n := []string{
fmt.Sprintf(start, a.XMLName.Space, a.ID, a.IssueInstant, a.Version),
a.Issuer.C14N(),
a.Signature.C14N(),
a.Subject.C14N(),
a.Conditions.C14N(),
a.AuthnStatement.C14N(),
a.AttributeStatement.C14N(),
`</saml2:Assertion>`,
}
return strings.Join(c14n, "")
}
type NameID struct {
XMLName xml.Name
Format string `xml:",attr"`
ID string `xml:",innerxml"`
}
type Subject struct {
XMLName xml.Name
NameID NameID
SubjectConfirmation SubjectConfirmation
}
func (s *Subject) C14N() string {
data := &s.SubjectConfirmation.SubjectConfirmationData
names := []*xml.Name{
&s.XMLName,
&s.NameID.XMLName,
&s.SubjectConfirmation.XMLName,
&data.XMLName,
}
if s.SubjectConfirmation.NameID != nil {
names = append(names, &s.SubjectConfirmation.NameID.XMLName)
}
if data.KeyInfo != nil {
data.NS = XSI
data.Type = "saml2:KeyInfoConfirmationDataType"
data.KeyInfo.XMLName = xml.Name{Local: "ds:KeyInfo"}
data.KeyInfo.X509Data.XMLName = xml.Name{Local: "ds:X509Data"}
data.KeyInfo.NS = DSIG
}
return mkns("saml2", s, names...)
}
type SubjectConfirmationData struct {
XMLName xml.Name
NS string `xml:"xmlns:xsi,attr,omitempty"`
Type string `xml:"xsi:type,attr,omitempty"`
NotOnOrAfter string `xml:",attr,omitempty"`
KeyInfo *KeyInfo
}
type SubjectConfirmation struct {
XMLName xml.Name
Method string `xml:",attr"`
NameID *NameID
SubjectConfirmationData SubjectConfirmationData
}
type Condition struct {
Type string `xml:"xsi:type,attr,omitempty"`
}
func (c *Condition) GetCondition() *Condition {
return c
}
type BaseCondition interface {
GetCondition() *Condition
}
func init() {
types.Add("BaseCondition", reflect.TypeOf((*Condition)(nil)).Elem())
types.Add("del:DelegationRestrictionType", reflect.TypeOf((*DelegateRestriction)(nil)).Elem())
types.Add("rsa:RenewRestrictionType", reflect.TypeOf((*RenewRestriction)(nil)).Elem())
}
type Conditions struct {
XMLName xml.Name
NotBefore string `xml:",attr"`
NotOnOrAfter string `xml:",attr"`
ProxyRestriction *ProxyRestriction `xml:",omitempty"`
Condition []BaseCondition `xml:",omitempty"`
}
func (c *Conditions) C14N() string {
names := []*xml.Name{
&c.XMLName,
}
if c.ProxyRestriction != nil {
names = append(names, &c.ProxyRestriction.XMLName)
}
for i := range c.Condition {
switch r := c.Condition[i].(type) {
case *DelegateRestriction:
names = append(names, &r.XMLName, &r.Delegate.NameID.XMLName)
r.NS = XSI
r.Type = "del:DelegationRestrictionType"
r.Delegate.NS = r.Delegate.XMLName.Space
r.Delegate.XMLName = xml.Name{Local: "del:Delegate"}
case *RenewRestriction:
names = append(names, &r.XMLName)
r.NS = XSI
r.Type = "rsa:RenewRestrictionType"
}
}
return mkns("saml2", c, names...)
}
type ProxyRestriction struct {
XMLName xml.Name
Count int32 `xml:",attr"`
}
type RenewRestriction struct {
XMLName xml.Name
NS string `xml:"xmlns:xsi,attr,omitempty"`
Count int32 `xml:",attr"`
Condition
}
type Delegate struct {
XMLName xml.Name
NS string `xml:"xmlns:del,attr,omitempty"`
DelegationInstant string `xml:",attr"`
NameID NameID
}
type DelegateRestriction struct {
XMLName xml.Name
NS string `xml:"xmlns:xsi,attr,omitempty"`
Condition
Delegate Delegate
}
type AuthnStatement struct {
XMLName xml.Name
AuthnInstant string `xml:",attr"`
AuthnContext struct {
XMLName xml.Name
AuthnContextClassRef struct {
XMLName xml.Name
Value string `xml:",innerxml"`
}
}
}
func (a *AuthnStatement) C14N() string {
return mkns("saml2", a, &a.XMLName, &a.AuthnContext.XMLName, &a.AuthnContext.AuthnContextClassRef.XMLName)
}
type AttributeStatement struct {
XMLName xml.Name
Attribute []Attribute
}
func (a *AttributeStatement) C14N() string {
c14n := []string{"<saml2:AttributeStatement>"}
for i := range a.Attribute {
c14n = append(c14n, a.Attribute[i].C14N())
}
c14n = append(c14n, "</saml2:AttributeStatement>")
return strings.Join(c14n, "")
}
type AttributeValue struct {
XMLName xml.Name
Type string `xml:"type,attr"`
Value string `xml:",innerxml"`
}
func (a *AttributeValue) C14N() string {
return fmt.Sprintf(`<saml2:AttributeValue xmlns:xsi="%s" xsi:type="%s">%s</saml2:AttributeValue>`, XSI, a.Type, a.Value)
}
type Attribute struct {
XMLName xml.Name
FriendlyName string `xml:",attr"`
Name string `xml:",attr"`
NameFormat string `xml:",attr"`
AttributeValue []AttributeValue
}
func (a *Attribute) C14N() string {
c14n := []string{
fmt.Sprintf(`<saml2:Attribute FriendlyName="%s" Name="%s" NameFormat="%s">`, a.FriendlyName, a.Name, a.NameFormat),
}
for i := range a.AttributeValue {
c14n = append(c14n, a.AttributeValue[i].C14N())
}
c14n = append(c14n, `</saml2:Attribute>`)
return strings.Join(c14n, "")
}
type Lifetime struct {
Created string `xml:"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd Created"`
Expires string `xml:"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd Expires"`
}
func (t *Lifetime) C14N() string {
return fmt.Sprintf(`<Lifetime><wsu:Created>%s</wsu:Created><wsu:Expires>%s</wsu:Expires></Lifetime>`, t.Created, t.Expires)
}
type Renewing struct {
Allow bool `xml:",attr"`
OK bool `xml:",attr"`
}
type UseKey struct {
Sig string `xml:",attr"`
}
type Target struct {
Token string `xml:",innerxml"`
}
type RequestSecurityToken struct {
TokenType string `xml:",omitempty"`
RequestType string `xml:",omitempty"`
Lifetime *Lifetime `xml:",omitempty"`
Renewing *Renewing `xml:",omitempty"`
Delegatable bool `xml:",omitempty"`
KeyType string `xml:",omitempty"`
SignatureAlgorithm string `xml:",omitempty"`
UseKey *UseKey `xml:",omitempty"`
ActAs *Target `xml:",omitempty"`
ValidateTarget *Target `xml:",omitempty"`
RenewTarget *Target `xml:",omitempty"`
}
func Unmarshal(data []byte, v interface{}) error {
dec := xml.NewDecoder(bytes.NewReader(data))
dec.TypeFunc = types.TypeFunc()
return dec.Decode(v)
}
// toString returns an XML encoded RequestSecurityToken.
// When c14n is true, returns the canonicalized ActAs.Assertion which is required to sign the Issue request.
// When c14n is false, returns the original content of the ActAs.Assertion.
// The original content must be used within the request Body, as it has its own signature.
func (r *RequestSecurityToken) toString(c14n bool) string {
actas := ""
if r.ActAs != nil {
token := r.ActAs.Token
if c14n {
var a Assertion
err := Unmarshal([]byte(r.ActAs.Token), &a)
if err != nil {
log.Printf("decode ActAs: %s", err)
}
token = a.C14N()
}
actas = fmt.Sprintf(`<wst:ActAs xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200802">%s</wst:ActAs>`, token)
}
body := []string{
fmt.Sprintf(`<RequestSecurityToken xmlns="http://docs.oasis-open.org/ws-sx/ws-trust/200512">`),
fmt.Sprintf(`<TokenType>%s</TokenType>`, r.TokenType),
fmt.Sprintf(`<RequestType>%s</RequestType>`, r.RequestType),
r.Lifetime.C14N(),
}
if r.RenewTarget == nil {
body = append(body,
fmt.Sprintf(`<Renewing Allow="%t" OK="%t"></Renewing>`, r.Renewing.Allow, r.Renewing.OK),
fmt.Sprintf(`<Delegatable>%t</Delegatable>`, r.Delegatable),
actas,
fmt.Sprintf(`<KeyType>%s</KeyType>`, r.KeyType),
fmt.Sprintf(`<SignatureAlgorithm>%s</SignatureAlgorithm>`, r.SignatureAlgorithm),
fmt.Sprintf(`<UseKey Sig="%s"></UseKey>`, r.UseKey.Sig))
} else {
token := r.RenewTarget.Token
if c14n {
var a Assertion
err := Unmarshal([]byte(r.RenewTarget.Token), &a)
if err != nil {
log.Printf("decode Renew: %s", err)
}
token = a.C14N()
}
body = append(body,
fmt.Sprintf(`<UseKey Sig="%s"></UseKey>`, r.UseKey.Sig),
fmt.Sprintf(`<RenewTarget>%s</RenewTarget>`, token))
}
return strings.Join(append(body, `</RequestSecurityToken>`), "")
}
func (r *RequestSecurityToken) C14N() string {
return r.toString(true)
}
func (r *RequestSecurityToken) String() string {
return r.toString(false)
}
type RequestSecurityTokenResponseCollection struct {
RequestSecurityTokenResponse RequestSecurityTokenResponse
}
type RequestSecurityTokenResponse struct {
RequestedSecurityToken RequestedSecurityToken
Lifetime *Lifetime `xml:"http://docs.oasis-open.org/ws-sx/ws-trust/200512 Lifetime"`
}
type RequestedSecurityToken struct {
Assertion string `xml:",innerxml"`
}
type RequestSecurityTokenBody struct {
Req *RequestSecurityToken `xml:"http://docs.oasis-open.org/ws-sx/ws-trust/200512 RequestSecurityToken,omitempty"`
Res *RequestSecurityTokenResponseCollection `xml:"http://docs.oasis-open.org/ws-sx/ws-trust/200512 RequestSecurityTokenResponseCollection,omitempty"`
Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
}
func (b *RequestSecurityTokenBody) Fault() *soap.Fault { return b.Fault_ }
func (b *RequestSecurityTokenBody) RequestSecurityToken() *RequestSecurityToken { return b.Req }
func (r *RequestSecurityToken) Action() string {
kind := path.Base(r.RequestType)
return "http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/" + kind
}
func Issue(ctx context.Context, r soap.RoundTripper, req *RequestSecurityToken) (*RequestSecurityTokenResponseCollection, error) {
var reqBody, resBody RequestSecurityTokenBody
reqBody.Req = req
if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
return nil, err
}
return resBody.Res, nil
}
type RenewSecurityTokenBody struct {
Req *RequestSecurityToken `xml:"http://docs.oasis-open.org/ws-sx/ws-trust/200512 RequestSecurityToken,omitempty"`
Res *RequestSecurityTokenResponse `xml:"http://docs.oasis-open.org/ws-sx/ws-trust/200512 RequestSecurityTokenResponse,omitempty"`
Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
}
func (b *RenewSecurityTokenBody) Fault() *soap.Fault { return b.Fault_ }
func (b *RenewSecurityTokenBody) RequestSecurityToken() *RequestSecurityToken { return b.Req }
func Renew(ctx context.Context, r soap.RoundTripper, req *RequestSecurityToken) (*RequestSecurityTokenResponse, error) {
var reqBody, resBody RenewSecurityTokenBody
reqBody.Req = req
if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
return nil, err
}
return resBody.Res, nil
}
// Marshal panics if xml.Marshal returns an error
func Marshal(val interface{}) string {
b, err := xml.Marshal(val)
if err != nil {
panic(err)
}
return string(b)
}
// mkns prepends the given namespace to xml.Name.Local and returns obj encoded as xml.
// Note that the namespace is required when encoding, but the namespace prefix must not be
// present when decoding as Go's decoding does not handle namespace prefix.
func mkns(ns string, obj interface{}, name ...*xml.Name) string {
ns += ":"
for i := range name {
name[i].Space = ""
if !strings.HasPrefix(name[i].Local, ns) {
name[i].Local = ns + name[i].Local
}
}
return Marshal(obj)
}

330
vendor/github.com/vmware/govmomi/sts/signer.go generated vendored Normal file
View File

@@ -0,0 +1,330 @@
/*
Copyright (c) 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 sts
import (
"bytes"
"compress/gzip"
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/tls"
"encoding/base64"
"errors"
"fmt"
"io"
"io/ioutil"
mrand "math/rand"
"net/http"
"net/url"
"strings"
"time"
"github.com/google/uuid"
"github.com/vmware/govmomi/sts/internal"
"github.com/vmware/govmomi/vim25/methods"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/xml"
)
// Signer implements the soap.Signer interface.
type Signer struct {
Token string // Token is a SAML token
Certificate *tls.Certificate // Certificate is used to sign requests
Lifetime struct {
Created time.Time
Expires time.Time
}
user *url.Userinfo // user contains the credentials for bearer token request
keyID string // keyID is the Signature UseKey ID, which is referenced in both the soap body and header
}
// signedEnvelope is similar to soap.Envelope, but with namespace and Body as innerxml
type signedEnvelope struct {
XMLName xml.Name `xml:"soap:Envelope"`
NS string `xml:"xmlns:soap,attr"`
Header soap.Header `xml:"soap:Header"`
Body string `xml:",innerxml"`
}
// newID returns a unique Reference ID, with a leading underscore as required by STS.
func newID() string {
return "_" + uuid.New().String()
}
func (s *Signer) setTokenReference(info *internal.KeyInfo) error {
var token struct {
ID string `xml:",attr"` // parse saml2:Assertion ID attribute
InnerXML string `xml:",innerxml"` // no need to parse the entire token
}
if err := xml.Unmarshal([]byte(s.Token), &token); err != nil {
return err
}
info.SecurityTokenReference = &internal.SecurityTokenReference{
WSSE11: "http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd",
TokenType: "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0",
KeyIdentifier: &internal.KeyIdentifier{
ID: token.ID,
ValueType: "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID",
},
}
return nil
}
// Sign is a soap.Signer implementation which can be used to sign RequestSecurityToken and LoginByTokenBody requests.
func (s *Signer) Sign(env soap.Envelope) ([]byte, error) {
var key *rsa.PrivateKey
hasKey := false
if s.Certificate != nil {
key, hasKey = s.Certificate.PrivateKey.(*rsa.PrivateKey)
if !hasKey {
return nil, errors.New("sts: rsa.PrivateKey is required")
}
}
created := time.Now().UTC()
header := &internal.Security{
WSU: internal.WSU,
WSSE: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
Timestamp: internal.Timestamp{
NS: internal.WSU,
ID: newID(),
Created: created.Format(internal.Time),
Expires: created.Add(time.Minute).Format(internal.Time), // If STS receives this request after this, it is assumed to have expired.
},
}
env.Header.Security = header
info := internal.KeyInfo{XMLName: xml.Name{Local: "ds:KeyInfo"}}
var c14n, body string
type requestToken interface {
RequestSecurityToken() *internal.RequestSecurityToken
}
switch x := env.Body.(type) {
case requestToken:
if hasKey {
// We need c14n for all requests, as its digest is included in the signature and must match on the server side.
// We need the body in original form when using an ActAs or RenewTarget token, where the token and its signature are embedded in the body.
req := x.RequestSecurityToken()
c14n = req.C14N()
body = req.String()
id := newID()
info.SecurityTokenReference = &internal.SecurityTokenReference{
Reference: &internal.SecurityReference{
URI: "#" + id,
ValueType: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3",
},
}
header.BinarySecurityToken = &internal.BinarySecurityToken{
EncodingType: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary",
ValueType: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3",
ID: id,
Value: base64.StdEncoding.EncodeToString(s.Certificate.Certificate[0]),
}
}
// When requesting HoK token for interactive user, request will have both priv. key and username/password.
if s.user.Username() != "" {
header.UsernameToken = &internal.UsernameToken{
Username: s.user.Username(),
}
header.UsernameToken.Password, _ = s.user.Password()
}
case *methods.LoginByTokenBody:
header.Assertion = s.Token
if hasKey {
if err := s.setTokenReference(&info); err != nil {
return nil, err
}
c14n = internal.Marshal(x.Req)
}
default:
// We can end up here via ssoadmin.SessionManager.Login().
// No other known cases where a signed request is needed.
header.Assertion = s.Token
if hasKey {
if err := s.setTokenReference(&info); err != nil {
return nil, err
}
type Req interface {
C14N() string
}
c14n = env.Body.(Req).C14N()
}
}
if !hasKey {
return xml.Marshal(env) // Bearer token without key to sign
}
id := newID()
tmpl := `<soap:Body xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsu="%s" wsu:Id="%s">%s</soap:Body>`
c14n = fmt.Sprintf(tmpl, internal.WSU, id, c14n)
if body == "" {
body = c14n
} else {
body = fmt.Sprintf(tmpl, internal.WSU, id, body)
}
header.Signature = &internal.Signature{
XMLName: xml.Name{Local: "ds:Signature"},
NS: internal.DSIG,
ID: s.keyID,
KeyInfo: info,
SignedInfo: internal.SignedInfo{
XMLName: xml.Name{Local: "ds:SignedInfo"},
NS: internal.DSIG,
CanonicalizationMethod: internal.Method{
XMLName: xml.Name{Local: "ds:CanonicalizationMethod"},
Algorithm: "http://www.w3.org/2001/10/xml-exc-c14n#",
},
SignatureMethod: internal.Method{
XMLName: xml.Name{Local: "ds:SignatureMethod"},
Algorithm: internal.SHA256,
},
Reference: []internal.Reference{
internal.NewReference(header.Timestamp.ID, header.Timestamp.C14N()),
internal.NewReference(id, c14n),
},
},
}
sum := sha256.Sum256([]byte(header.Signature.SignedInfo.C14N()))
sig, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, sum[:])
if err != nil {
return nil, err
}
header.Signature.SignatureValue = internal.Value{
XMLName: xml.Name{Local: "ds:SignatureValue"},
Value: base64.StdEncoding.EncodeToString(sig),
}
return xml.Marshal(signedEnvelope{
NS: "http://schemas.xmlsoap.org/soap/envelope/",
Header: *env.Header,
Body: body,
})
}
// SignRequest is a rest.Signer implementation which can be used to sign rest.Client.LoginByTokenBody requests.
func (s *Signer) SignRequest(req *http.Request) error {
type param struct {
key, val string
}
var params []string
add := func(p param) {
params = append(params, fmt.Sprintf(`%s="%s"`, p.key, p.val))
}
var buf bytes.Buffer
gz := gzip.NewWriter(&buf)
if _, err := io.WriteString(gz, s.Token); err != nil {
return fmt.Errorf("zip token: %s", err)
}
if err := gz.Close(); err != nil {
return fmt.Errorf("zip token: %s", err)
}
add(param{
key: "token",
val: base64.StdEncoding.EncodeToString(buf.Bytes()),
})
if s.Certificate != nil {
nonce := fmt.Sprintf("%d:%d", time.Now().UnixNano()/1e6, mrand.Int())
var body []byte
if req.GetBody != nil {
r, rerr := req.GetBody()
if rerr != nil {
return fmt.Errorf("sts: getting http.Request body: %s", rerr)
}
defer r.Close()
body, rerr = ioutil.ReadAll(r)
if rerr != nil {
return fmt.Errorf("sts: reading http.Request body: %s", rerr)
}
}
bhash := sha256.New().Sum(body)
port := req.URL.Port()
if port == "" {
port = "80" // Default port for the "Host" header on the server side
}
var buf bytes.Buffer
msg := []string{
nonce,
req.Method,
req.URL.Path,
strings.ToLower(req.URL.Hostname()),
port,
}
for i := range msg {
buf.WriteString(msg[i])
buf.WriteByte('\n')
}
buf.Write(bhash)
buf.WriteByte('\n')
sum := sha256.Sum256(buf.Bytes())
key, ok := s.Certificate.PrivateKey.(*rsa.PrivateKey)
if !ok {
return errors.New("sts: rsa.PrivateKey is required to sign http.Request")
}
sig, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, sum[:])
if err != nil {
return err
}
add(param{
key: "signature_alg",
val: "RSA-SHA256",
})
add(param{
key: "signature",
val: base64.StdEncoding.EncodeToString(sig),
})
add(param{
key: "nonce",
val: nonce,
})
add(param{
key: "bodyhash",
val: base64.StdEncoding.EncodeToString(bhash),
})
}
req.Header.Set("Authorization", fmt.Sprintf("SIGN %s", strings.Join(params, ", ")))
return nil
}
func (s *Signer) NewRequest() TokenRequest {
return TokenRequest{
Token: s.Token,
Certificate: s.Certificate,
Userinfo: s.user,
KeyID: s.keyID,
}
}

342
vendor/github.com/vmware/govmomi/vmdk/import.go generated vendored Normal file
View File

@@ -0,0 +1,342 @@
/*
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.
nSee the License for the specific language governing permissions and
limitations under the License.
*/
package vmdk
import (
"bytes"
"context"
"encoding/binary"
"errors"
"fmt"
"io"
"os"
"path"
"path/filepath"
"strings"
"text/template"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/ovf"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/progress"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
)
var (
ErrInvalidFormat = errors.New("vmdk: invalid format (must be streamOptimized)")
)
// info is used to inspect a vmdk and generate an ovf template
type info struct {
Header struct {
MagicNumber uint32
Version uint32
Flags uint32
Capacity uint64
}
Capacity uint64
Size int64
Name string
ImportName string
}
// stat looks at the vmdk header to make sure the format is streamOptimized and
// extracts the disk capacity required to properly generate the ovf descriptor.
func stat(name string) (*info, error) {
f, err := os.Open(filepath.Clean(name))
if err != nil {
return nil, err
}
var di info
var buf bytes.Buffer
_, err = io.CopyN(&buf, f, int64(binary.Size(di.Header)))
if err != nil {
return nil, err
}
fi, err := f.Stat()
if err != nil {
return nil, err
}
err = f.Close()
if err != nil {
return nil, err
}
err = binary.Read(&buf, binary.LittleEndian, &di.Header)
if err != nil {
return nil, err
}
if di.Header.MagicNumber != 0x564d444b { // SPARSE_MAGICNUMBER
return nil, ErrInvalidFormat
}
if di.Header.Flags&(1<<16) == 0 { // SPARSEFLAG_COMPRESSED
// Needs to be converted, for example:
// vmware-vdiskmanager -r src.vmdk -t 5 dst.vmdk
// qemu-img convert -O vmdk -o subformat=streamOptimized src.vmdk dst.vmdk
return nil, ErrInvalidFormat
}
di.Capacity = di.Header.Capacity * 512 // VMDK_SECTOR_SIZE
di.Size = fi.Size()
di.Name = filepath.Base(name)
di.ImportName = strings.TrimSuffix(di.Name, ".vmdk")
return &di, nil
}
// ovfenv is the minimal descriptor template required to import a vmdk
var ovfenv = `<?xml version="1.0" encoding="UTF-8"?>
<Envelope xmlns="http://schemas.dmtf.org/ovf/envelope/1"
xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"
xmlns:cim="http://schemas.dmtf.org/wbem/wscim/1/common"
xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
xmlns:vmw="http://www.vmware.com/schema/ovf"
xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<References>
<File ovf:href="{{ .Name }}" ovf:id="file1" ovf:size="{{ .Size }}"/>
</References>
<DiskSection>
<Info>Virtual disk information</Info>
<Disk ovf:capacity="{{ .Capacity }}" ovf:capacityAllocationUnits="byte" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" ovf:populatedSize="0"/>
</DiskSection>
<VirtualSystem ovf:id="{{ .ImportName }}">
<Info>A virtual machine</Info>
<Name>{{ .ImportName }}</Name>
<OperatingSystemSection ovf:id="100" vmw:osType="other26xLinux64Guest">
<Info>The kind of installed guest operating system</Info>
</OperatingSystemSection>
<VirtualHardwareSection>
<Info>Virtual hardware requirements</Info>
<System>
<vssd:ElementName>Virtual Hardware Family</vssd:ElementName>
<vssd:InstanceID>0</vssd:InstanceID>
<vssd:VirtualSystemIdentifier>{{ .ImportName }}</vssd:VirtualSystemIdentifier>
<vssd:VirtualSystemType>vmx-07</vssd:VirtualSystemType>
</System>
<Item>
<rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>
<rasd:Description>Number of Virtual CPUs</rasd:Description>
<rasd:ElementName>1 virtual CPU(s)</rasd:ElementName>
<rasd:InstanceID>1</rasd:InstanceID>
<rasd:ResourceType>3</rasd:ResourceType>
<rasd:VirtualQuantity>1</rasd:VirtualQuantity>
</Item>
<Item>
<rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>
<rasd:Description>Memory Size</rasd:Description>
<rasd:ElementName>1024MB of memory</rasd:ElementName>
<rasd:InstanceID>2</rasd:InstanceID>
<rasd:ResourceType>4</rasd:ResourceType>
<rasd:VirtualQuantity>1024</rasd:VirtualQuantity>
</Item>
<Item>
<rasd:Address>0</rasd:Address>
<rasd:Description>SCSI Controller</rasd:Description>
<rasd:ElementName>SCSI Controller 0</rasd:ElementName>
<rasd:InstanceID>3</rasd:InstanceID>
<rasd:ResourceSubType>VirtualSCSI</rasd:ResourceSubType>
<rasd:ResourceType>6</rasd:ResourceType>
</Item>
<Item>
<rasd:AddressOnParent>0</rasd:AddressOnParent>
<rasd:ElementName>Hard Disk 1</rasd:ElementName>
<rasd:HostResource>ovf:/disk/vmdisk1</rasd:HostResource>
<rasd:InstanceID>9</rasd:InstanceID>
<rasd:Parent>3</rasd:Parent>
<rasd:ResourceType>17</rasd:ResourceType>
<vmw:Config ovf:required="false" vmw:key="backing.writeThrough" vmw:value="false"/>
</Item>
</VirtualHardwareSection>
</VirtualSystem>
</Envelope>`
// ovf returns an expanded descriptor template
func (di *info) ovf() (string, error) {
var buf bytes.Buffer
tmpl, err := template.New("ovf").Parse(ovfenv)
if err != nil {
return "", err
}
err = tmpl.Execute(&buf, di)
if err != nil {
return "", err
}
return buf.String(), nil
}
// ImportParams contains the set of optional params to the Import function.
// Note that "optional" may depend on environment, such as ESX or vCenter.
type ImportParams struct {
Path string
Logger progress.Sinker
Type types.VirtualDiskType
Force bool
Datacenter *object.Datacenter
Pool *object.ResourcePool
Folder *object.Folder
Host *object.HostSystem
}
// Import uploads a local vmdk file specified by name to the given datastore.
func Import(ctx context.Context, c *vim25.Client, name string, datastore *object.Datastore, p ImportParams) error {
m := ovf.NewManager(c)
fm := datastore.NewFileManager(p.Datacenter, p.Force)
disk, err := stat(name)
if err != nil {
return err
}
var rename string
p.Path = strings.TrimSuffix(p.Path, "/")
if p.Path != "" {
disk.ImportName = p.Path
rename = path.Join(disk.ImportName, disk.Name)
}
// "target" is the path that will be created by ImportVApp()
// ImportVApp uses the same name for the VM and the disk.
target := fmt.Sprintf("%s/%s.vmdk", disk.ImportName, disk.ImportName)
if _, err = datastore.Stat(ctx, target); err == nil {
if p.Force {
// If we don't delete, the nfc upload adds a file name suffix
if err = fm.Delete(ctx, target); err != nil {
return err
}
} else {
return fmt.Errorf("%s: %s", os.ErrExist, datastore.Path(target))
}
}
// If we need to rename at the end, check if the file exists early unless Force.
if !p.Force && rename != "" {
if _, err = datastore.Stat(ctx, rename); err == nil {
return fmt.Errorf("%s: %s", os.ErrExist, datastore.Path(rename))
}
}
// Expand the ovf template
descriptor, err := disk.ovf()
if err != nil {
return err
}
pool := p.Pool // TODO: use datastore to derive a default
folder := p.Folder // TODO: use datacenter to derive a default
kind := p.Type
if kind == "" {
kind = types.VirtualDiskTypeThin
}
params := types.OvfCreateImportSpecParams{
DiskProvisioning: string(kind),
EntityName: disk.ImportName,
}
spec, err := m.CreateImportSpec(ctx, descriptor, pool, datastore, params)
if err != nil {
return err
}
if spec.Error != nil {
return errors.New(spec.Error[0].LocalizedMessage)
}
lease, err := pool.ImportVApp(ctx, spec.ImportSpec, folder, p.Host)
if err != nil {
return err
}
info, err := lease.Wait(ctx, spec.FileItem)
if err != nil {
return err
}
f, err := os.Open(filepath.Clean(name))
if err != nil {
return err
}
opts := soap.Upload{
ContentLength: disk.Size,
Progress: p.Logger,
}
u := lease.StartUpdater(ctx, info)
defer u.Done()
item := info.Items[0] // we only have 1 disk to upload
err = lease.Upload(ctx, item, f, opts)
if err != nil {
return err
}
err = f.Close()
if err != nil {
return err
}
if err = lease.Complete(ctx); err != nil {
return err
}
// ImportVApp created a VM, here we detach the vmdk, then delete the VM.
vm := object.NewVirtualMachine(c, info.Entity)
device, err := vm.Device(ctx)
if err != nil {
return err
}
device = device.SelectByType((*types.VirtualDisk)(nil))
err = vm.RemoveDevice(ctx, true, device...)
if err != nil {
return err
}
task, err := vm.Destroy(ctx)
if err != nil {
return err
}
if err = task.Wait(ctx); err != nil {
return err
}
if rename == "" {
return nil
}
return fm.Move(ctx, target, rename)
}

18
vendor/modules.txt vendored
View File

@@ -919,6 +919,10 @@ github.com/keybase/go-crypto/rsa
github.com/konsorten/go-windows-terminal-sequences
# github.com/kr/fs v0.1.0
github.com/kr/fs
# github.com/kr/pretty v0.1.0
github.com/kr/pretty
# github.com/kr/text v0.1.0
github.com/kr/text
# github.com/lib/pq v1.2.0
github.com/lib/pq
github.com/lib/pq/oid
@@ -1284,19 +1288,28 @@ github.com/vincent-petithory/dataurl
# github.com/vmihailenco/msgpack v4.0.4+incompatible
github.com/vmihailenco/msgpack
github.com/vmihailenco/msgpack/codes
# github.com/vmware/govmomi v0.22.1
# github.com/vmware/govmomi v0.22.2
github.com/vmware/govmomi
github.com/vmware/govmomi/event
github.com/vmware/govmomi/find
github.com/vmware/govmomi/govc/cli
github.com/vmware/govmomi/govc/flags
github.com/vmware/govmomi/govc/importx
github.com/vmware/govmomi/license
github.com/vmware/govmomi/list
github.com/vmware/govmomi/lookup
github.com/vmware/govmomi/lookup/methods
github.com/vmware/govmomi/lookup/types
github.com/vmware/govmomi/nfc
github.com/vmware/govmomi/object
github.com/vmware/govmomi/ovf
github.com/vmware/govmomi/pbm
github.com/vmware/govmomi/pbm/methods
github.com/vmware/govmomi/pbm/types
github.com/vmware/govmomi/property
github.com/vmware/govmomi/session
github.com/vmware/govmomi/sts
github.com/vmware/govmomi/sts/internal
github.com/vmware/govmomi/task
github.com/vmware/govmomi/vapi/internal
github.com/vmware/govmomi/vapi/rest
@@ -1310,6 +1323,7 @@ github.com/vmware/govmomi/vim25/progress
github.com/vmware/govmomi/vim25/soap
github.com/vmware/govmomi/vim25/types
github.com/vmware/govmomi/vim25/xml
github.com/vmware/govmomi/vmdk
# github.com/xanzy/ssh-agent v0.2.1
github.com/xanzy/ssh-agent
# github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca
@@ -1653,7 +1667,7 @@ k8s.io/api/settings/v1alpha1
k8s.io/api/storage/v1
k8s.io/api/storage/v1alpha1
k8s.io/api/storage/v1beta1
# k8s.io/apimachinery v0.17.2 => k8s.io/apimachinery v0.17.1
# k8s.io/apimachinery v0.17.3 => k8s.io/apimachinery v0.17.1
k8s.io/apimachinery/pkg/api/equality
k8s.io/apimachinery/pkg/api/errors
k8s.io/apimachinery/pkg/api/meta