- Updated vmware/govmomi godep (Needs for vsan support)

- Fix unmount for vsanDatastore
- Add support for vsan datastore
pull/6/head
Abrar Shivani 2016-07-18 23:20:30 -07:00
parent 2301ab7e0e
commit 87e7535e94
31 changed files with 658 additions and 200 deletions

60
Godeps/Godeps.json generated
View File

@ -2015,78 +2015,78 @@
},
{
"ImportPath": "github.com/vmware/govmomi",
"Comment": "v0.6.2",
"Rev": "9051bd6b44125d9472e0c148b5965692ab283d4a"
"Comment": "v0.8.0-9-gb5ee639",
"Rev": "b5ee639d7aa4b8dbb48ab4f75dddc19f71b5c514"
},
{
"ImportPath": "github.com/vmware/govmomi/find",
"Comment": "v0.6.2",
"Rev": "9051bd6b44125d9472e0c148b5965692ab283d4a"
"Comment": "v0.8.0-9-gb5ee639",
"Rev": "b5ee639d7aa4b8dbb48ab4f75dddc19f71b5c514"
},
{
"ImportPath": "github.com/vmware/govmomi/list",
"Comment": "v0.6.2",
"Rev": "9051bd6b44125d9472e0c148b5965692ab283d4a"
"Comment": "v0.8.0-9-gb5ee639",
"Rev": "b5ee639d7aa4b8dbb48ab4f75dddc19f71b5c514"
},
{
"ImportPath": "github.com/vmware/govmomi/object",
"Comment": "v0.6.2",
"Rev": "9051bd6b44125d9472e0c148b5965692ab283d4a"
"Comment": "v0.8.0-9-gb5ee639",
"Rev": "b5ee639d7aa4b8dbb48ab4f75dddc19f71b5c514"
},
{
"ImportPath": "github.com/vmware/govmomi/property",
"Comment": "v0.6.2",
"Rev": "9051bd6b44125d9472e0c148b5965692ab283d4a"
"Comment": "v0.8.0-9-gb5ee639",
"Rev": "b5ee639d7aa4b8dbb48ab4f75dddc19f71b5c514"
},
{
"ImportPath": "github.com/vmware/govmomi/session",
"Comment": "v0.6.2",
"Rev": "9051bd6b44125d9472e0c148b5965692ab283d4a"
"Comment": "v0.8.0-9-gb5ee639",
"Rev": "b5ee639d7aa4b8dbb48ab4f75dddc19f71b5c514"
},
{
"ImportPath": "github.com/vmware/govmomi/task",
"Comment": "v0.6.2",
"Rev": "9051bd6b44125d9472e0c148b5965692ab283d4a"
"Comment": "v0.8.0-9-gb5ee639",
"Rev": "b5ee639d7aa4b8dbb48ab4f75dddc19f71b5c514"
},
{
"ImportPath": "github.com/vmware/govmomi/vim25",
"Comment": "v0.6.2",
"Rev": "9051bd6b44125d9472e0c148b5965692ab283d4a"
"Comment": "v0.8.0-9-gb5ee639",
"Rev": "b5ee639d7aa4b8dbb48ab4f75dddc19f71b5c514"
},
{
"ImportPath": "github.com/vmware/govmomi/vim25/debug",
"Comment": "v0.6.2",
"Rev": "9051bd6b44125d9472e0c148b5965692ab283d4a"
"Comment": "v0.8.0-9-gb5ee639",
"Rev": "b5ee639d7aa4b8dbb48ab4f75dddc19f71b5c514"
},
{
"ImportPath": "github.com/vmware/govmomi/vim25/methods",
"Comment": "v0.6.2",
"Rev": "9051bd6b44125d9472e0c148b5965692ab283d4a"
"Comment": "v0.8.0-9-gb5ee639",
"Rev": "b5ee639d7aa4b8dbb48ab4f75dddc19f71b5c514"
},
{
"ImportPath": "github.com/vmware/govmomi/vim25/mo",
"Comment": "v0.6.2",
"Rev": "9051bd6b44125d9472e0c148b5965692ab283d4a"
"Comment": "v0.8.0-9-gb5ee639",
"Rev": "b5ee639d7aa4b8dbb48ab4f75dddc19f71b5c514"
},
{
"ImportPath": "github.com/vmware/govmomi/vim25/progress",
"Comment": "v0.6.2",
"Rev": "9051bd6b44125d9472e0c148b5965692ab283d4a"
"Comment": "v0.8.0-9-gb5ee639",
"Rev": "b5ee639d7aa4b8dbb48ab4f75dddc19f71b5c514"
},
{
"ImportPath": "github.com/vmware/govmomi/vim25/soap",
"Comment": "v0.6.2",
"Rev": "9051bd6b44125d9472e0c148b5965692ab283d4a"
"Comment": "v0.8.0-9-gb5ee639",
"Rev": "b5ee639d7aa4b8dbb48ab4f75dddc19f71b5c514"
},
{
"ImportPath": "github.com/vmware/govmomi/vim25/types",
"Comment": "v0.6.2",
"Rev": "9051bd6b44125d9472e0c148b5965692ab283d4a"
"Comment": "v0.8.0-9-gb5ee639",
"Rev": "b5ee639d7aa4b8dbb48ab4f75dddc19f71b5c514"
},
{
"ImportPath": "github.com/vmware/govmomi/vim25/xml",
"Comment": "v0.6.2",
"Rev": "9051bd6b44125d9472e0c148b5965692ab283d4a"
"Comment": "v0.8.0-9-gb5ee639",
"Rev": "b5ee639d7aa4b8dbb48ab4f75dddc19f71b5c514"
},
{
"ImportPath": "github.com/xiang90/probing",

View File

@ -23,6 +23,7 @@ import (
"net"
"net/url"
"path"
"path/filepath"
"strings"
"github.com/vmware/govmomi"
@ -74,24 +75,35 @@ type VSphere struct {
type VSphereConfig struct {
Global struct {
User string `gcfg:"user"`
Password string `gcfg:"password"`
VCenterIP string `gcfg:"server"`
VCenterPort string `gcfg:"port"`
InsecureFlag bool `gcfg:"insecure-flag"`
Datacenter string `gcfg:"datacenter"`
Datastore string `gcfg:"datastore"`
WorkingDir string `gcfg:"working-dir"`
// vCenter username.
User string `gcfg:"user"`
// vCenter password in clear text.
Password string `gcfg:"password"`
// vCenter IP.
VCenterIP string `gcfg:"server"`
// vCenter port.
VCenterPort string `gcfg:"port"`
// True if vCenter uses self-signed cert.
InsecureFlag bool `gcfg:"insecure-flag"`
// Datacenter in which VMs are located.
Datacenter string `gcfg:"datacenter"`
// Datastore in which vmdks are stored.
Datastore string `gcfg:"datastore"`
// WorkingDir is path where VMs can be found.
WorkingDir string `gcfg:"working-dir"`
}
Network struct {
// PublicNetwork is name of the network the VMs are joined to.
PublicNetwork string `gcfg:"public-network"`
}
Disk struct {
// SCSIControllerType defines SCSI controller to be used.
SCSIControllerType string `dcfg:"scsicontrollertype"`
}
}
// Parses vSphere cloud config file and stores it into VSphereConfig.
func readConfig(config io.Reader) (VSphereConfig, error) {
if config == nil {
err := fmt.Errorf("no vSphere cloud provider config file given")
@ -113,6 +125,9 @@ func init() {
})
}
// Returns the name of the VM on which this code is running.
// This is done by searching for the name of virtual machine by current IP.
// Prerequisite: this code assumes VMWare vmtools or open-vm-tools to be installed in the VM.
func readInstanceID(cfg *VSphereConfig) (string, error) {
addrs, err := net.InterfaceAddrs()
if err != nil {
@ -153,6 +168,7 @@ func readInstanceID(cfg *VSphereConfig) (string, error) {
return "", fmt.Errorf("unable to parse cidr from ip")
}
// Finds a virtual machine or host by IP address.
svm, err = s.FindByIp(ctx, dc, ip.String(), true)
if err == nil && svm != nil {
break
@ -192,6 +208,7 @@ func newVSphere(cfg VSphereConfig) (*VSphere, error) {
return &vs, nil
}
// Returns if the given controller type is supported by the plugin
func checkControllerSupported(ctrlType string) bool {
for _, c := range supportedSCSIControllerType {
if ctrlType == c {
@ -201,8 +218,9 @@ func checkControllerSupported(ctrlType string) bool {
return false
}
// Returns a client which communicates with vCenter.
// This client can used to perform further vCenter operations.
func vsphereLogin(cfg *VSphereConfig, ctx context.Context) (*govmomi.Client, error) {
// Parse URL from string
u, err := url.Parse(fmt.Sprintf("https://%s:%s/sdk", cfg.Global.VCenterIP, cfg.Global.VCenterPort))
if err != nil {
@ -220,6 +238,7 @@ func vsphereLogin(cfg *VSphereConfig, ctx context.Context) (*govmomi.Client, err
return c, nil
}
// Returns vSphere object `virtual machine` by its name.
func getVirtualMachineByName(cfg *VSphereConfig, ctx context.Context, c *govmomi.Client, name string) (*object.VirtualMachine, error) {
// Create a new finder
f := find.NewFinder(c.Client, true)
@ -254,6 +273,7 @@ func getVirtualMachineManagedObjectReference(ctx context.Context, c *govmomi.Cli
return nil
}
// Returns names of running VMs inside VM folder.
func getInstances(cfg *VSphereConfig, ctx context.Context, c *govmomi.Client, filter string) ([]string, error) {
f := find.NewFinder(c.Client, true)
dc, err := f.Datacenter(ctx, cfg.Global.Datacenter)
@ -305,7 +325,7 @@ func (vs *VSphere) Instances() (cloudprovider.Instances, bool) {
return &Instances{vs.cfg, vs.localInstanceID}, true
}
// List is an implementation of Instances.List.
// List returns names of VMs (inside vm folder) by applying filter and which are currently running.
func (i *Instances) List(filter string) ([]string, error) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@ -492,40 +512,40 @@ func (vs *VSphere) ScrubDNS(nameservers, searches []string) (nsOut, srchOut []st
return nameservers, searches
}
func getVirtualMachineDevices(cfg *VSphereConfig, ctx context.Context, c *govmomi.Client, name string) (*object.VirtualMachine, object.VirtualDeviceList, *object.Datastore, error) {
// Returns vSphere objects virtual machine, virtual device list, datastore and datacenter.
func getVirtualMachineDevices(cfg *VSphereConfig, ctx context.Context, c *govmomi.Client, name string) (*object.VirtualMachine, object.VirtualDeviceList, *object.Datastore, *object.Datacenter, error) {
// Create a new finder
f := find.NewFinder(c.Client, true)
// Fetch and set data center
dc, err := f.Datacenter(ctx, cfg.Global.Datacenter)
if err != nil {
return nil, nil, nil, err
return nil, nil, nil, nil, err
}
f.SetDatacenter(dc)
// Find datastores
ds, err := f.Datastore(ctx, cfg.Global.Datastore)
if err != nil {
return nil, nil, nil, err
return nil, nil, nil, nil, err
}
vmRegex := cfg.Global.WorkingDir + name
vm, err := f.VirtualMachine(ctx, vmRegex)
if err != nil {
return nil, nil, nil, err
return nil, nil, nil, nil, err
}
// Get devices from VM
vmDevices, err := vm.Device(ctx)
if err != nil {
return nil, nil, nil, err
return nil, nil, nil, nil, err
}
return vm, vmDevices, ds, nil
return vm, vmDevices, ds, dc, nil
}
//cleaning up the controller
// Removes SCSI controller which is latest attached to VM.
func cleanUpController(newSCSIController types.BaseVirtualDevice, vmDevices object.VirtualDeviceList, vm *object.VirtualMachine, ctx context.Context) error {
ctls := vmDevices.SelectByType(newSCSIController)
if len(ctls) < 1 {
@ -561,7 +581,7 @@ func (vs *VSphere) AttachDisk(vmDiskPath string, nodeName string) (diskID string
}
// Get VM device list
vm, vmDevices, ds, err := getVirtualMachineDevices(vs.cfg, ctx, c, vSphereInstance)
vm, vmDevices, ds, _, err := getVirtualMachineDevices(vs.cfg, ctx, c, vSphereInstance)
if err != nil {
return "", "", err
}
@ -606,7 +626,7 @@ func (vs *VSphere) AttachDisk(vmDiskPath string, nodeName string) (diskID string
// verify scsi controller in virtual machine
vmDevices, err = vm.Device(ctx)
if err != nil {
//cannot cleanup if there is no device list
// cannot cleanup if there is no device list
return "", "", err
}
@ -747,33 +767,77 @@ func getAvailableSCSIController(scsiControllers []*types.VirtualController) *typ
return nil
}
// Returns formatted UUID for a virtual disk device.
func getVirtualDiskUUID(newDevice types.BaseVirtualDevice) (string, error) {
vd := newDevice.GetVirtualDevice()
if b, ok := vd.Backing.(*types.VirtualDiskFlatVer2BackingInfo); ok {
uuidWithNoHypens := strings.Replace(b.Uuid, "-", "", -1)
return strings.ToLower(uuidWithNoHypens), nil
uuid := formatVirtualDiskUUID(b.Uuid)
return uuid, nil
}
return "", ErrNoDiskUUIDFound
}
func getVirtualDiskID(volPath string, vmDevices object.VirtualDeviceList) (string, error) {
func formatVirtualDiskUUID(uuid string) string {
uuidwithNoSpace := strings.Replace(uuid, " ", "", -1)
uuidWithNoHypens := strings.Replace(uuidwithNoSpace, "-", "", -1)
return strings.ToLower(uuidWithNoHypens)
}
// Gets virtual disk UUID by datastore (namespace) path
//
// volPath can be namespace path (e.g. "[vsanDatastore] volumes/test.vmdk") or
// uuid path (e.g. "[vsanDatastore] 59427457-6c5a-a917-7997-0200103eedbc/test.vmdk").
// `volumes` in this case would be a symlink to
// `59427457-6c5a-a917-7997-0200103eedbc`.
//
// We want users to use namespace path. It is good for attaching the disk,
// but for detaching the API requires uuid path. Hence, to detach the right
// device we have to convert the namespace path to uuid path.
func getVirtualDiskUUIDByPath(volPath string, dc *object.Datacenter, client *govmomi.Client) (string, error) {
if len(volPath) > 0 && filepath.Ext(volPath) != ".vmdk" {
volPath += ".vmdk"
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// VirtualDiskManager provides a way to manage and manipulate virtual disks on vmware datastores.
vdm := object.NewVirtualDiskManager(client.Client)
// Returns uuid of vmdk virtual disk
diskUUID, err := vdm.QueryVirtualDiskUuid(ctx, volPath, dc)
if err != nil {
return "", ErrNoDiskUUIDFound
}
diskUUID = formatVirtualDiskUUID(diskUUID)
return diskUUID, nil
}
// Returns a device id which is internal vSphere API identifier for the attached virtual disk.
func getVirtualDiskID(volPath string, vmDevices object.VirtualDeviceList, dc *object.Datacenter, client *govmomi.Client) (string, error) {
volumeUUID, err := getVirtualDiskUUIDByPath(volPath, dc, client)
if err != nil {
glog.Warningf("disk uuid not found for %v ", volPath)
return "", err
}
// filter vm devices to retrieve disk ID for the given vmdk file
for _, device := range vmDevices {
if vmDevices.TypeName(device) == "VirtualDisk" {
d := device.GetVirtualDevice()
if b, ok := d.Backing.(types.BaseVirtualDeviceFileBackingInfo); ok {
fileName := b.GetVirtualDeviceFileBackingInfo().FileName
if fileName == volPath {
return vmDevices.Name(device), nil
}
diskUUID, _ := getVirtualDiskUUID(device)
if diskUUID == volumeUUID {
return vmDevices.Name(device), nil
}
}
}
return "", ErrNoDiskIDFound
}
// Detaches given virtual disk volume from the compute running kubelet.
// DetachDisk detaches given virtual disk volume from the compute running kubelet.
func (vs *VSphere) DetachDisk(volPath string, nodeName string) error {
// Create context
ctx, cancel := context.WithCancel(context.Background())
@ -794,23 +858,24 @@ func (vs *VSphere) DetachDisk(volPath string, nodeName string) error {
vSphereInstance = nodeName
}
vm, vmDevices, _, err := getVirtualMachineDevices(vs.cfg, ctx, c, vSphereInstance)
vm, vmDevices, _, dc, err := getVirtualMachineDevices(vs.cfg, ctx, c, vSphereInstance)
if err != nil {
return err
}
diskID, err := getVirtualDiskID(volPath, vmDevices)
diskID, err := getVirtualDiskID(volPath, vmDevices, dc, c)
if err != nil {
glog.Warningf("disk ID not found for %v ", volPath)
return err
}
// Remove disk from VM
// Gets virtual disk device
device := vmDevices.Find(diskID)
if device == nil {
return fmt.Errorf("device '%s' not found", diskID)
}
// Detach disk from VM
err = vm.RemoveDevice(ctx, true, device)
if err != nil {
return err
@ -819,7 +884,7 @@ func (vs *VSphere) DetachDisk(volPath string, nodeName string) error {
return nil
}
// Create a volume of given size (in KiB).
// CreateVolume creates a volume of given size (in KiB).
func (vs *VSphere) CreateVolume(name string, size int, tags *map[string]string) (volumePath string, err error) {
// Create context
ctx, cancel := context.WithCancel(context.Background())
@ -865,7 +930,7 @@ func (vs *VSphere) CreateVolume(name string, size int, tags *map[string]string)
return vmDiskPath, nil
}
// Deletes a volume given volume name.
// DeleteVolume deletes a volume given volume name.
func (vs *VSphere) DeleteVolume(vmDiskPath string) error {
// Create context
ctx, cancel := context.WithCancel(context.Background())

View File

@ -292,11 +292,13 @@ func (v *vsphereVolumeUnmounter) TearDownAt(dir string) error {
return fmt.Errorf("directory %s is not mounted", dir)
}
mountPath := refs[0]
// Assumption: No file or folder is named starting with '[' in datastore
volumePath := mountPath[strings.LastIndex(mountPath, "["):]
// space between datastore and vmdk name in volumePath is encoded as '\040' when returned by GetMountRefs().
// volumePath eg: "[local] xxx.vmdk" provided to attach/mount
// replacing \040 with space to match the actual volumePath
mountPath := strings.Replace(path.Base(refs[0]), "\\040", " ", -1)
v.volPath = mountPath
v.volPath = strings.Replace(volumePath, "\\040", " ", -1)
glog.V(4).Infof("Found volume %s mounted to %s", v.volPath, dir)
// Reload list of references, there might be SetUpAt finished in the meantime

View File

@ -1,5 +1,35 @@
# changelog
### 0.8.0 (2016-06-30)
* Add session.Manager.AcquireLocalTicket
* Include StoragePod in Finder.FolderList
* Add Finder methods for finding by ManagedObjectReference: Element, ObjectReference
* Add mo.ManagedObjectReference methods: Reference, String, FromString
* Add support using SessionManagerGenericServiceTicket.HostName for Datastore HTTP access
### 0.7.1 (2016-06-03)
* Fix object.ObjectName method
### 0.7.0 (2016-06-02)
* Move InventoryPath field to object.Common
* Add HostDatastoreSystem.CreateLocalDatastore method
* Add DatastoreNamespaceManager methods: CreateDirectory, DeleteDirectory
* Add HostServiceSystem
* Add HostStorageSystem methods: MarkAsSdd, MarkAsNonSdd, MarkAsLocal, MarkAsNonLocal
* Add HostStorageSystem.RescanAllHba method
### 0.6.2 (2016-05-11)
* Get complete file details in Datastore.Stat

View File

@ -9,10 +9,8 @@ Change _$USER_ below to your github username if they are not the same.
``` shell
export GOPATH=$HOME/govmomi
mkdir -p $GOPATH/src/github.com/vmware
cd $GOPATH/src/github.com/vmware
git clone git@github.com:vmware/govmomi.git
cd govmomi
go get github.com/vmware/govmomi
cd $GOPATH/src/github.com/vmware/govmomi
git config push.default nothing # anything to avoid pushing to vmware/govmomi by default
git remote rename origin vmware
git remote add $USER git@github.com:$USER/govmomi.git
@ -26,6 +24,7 @@ This is a rough outline of what a contributor's workflow looks like:
- Create a topic branch from where you want to base your work.
- Make commits of logical units.
- Make sure your commit messages are in the proper format (see below).
- Update CHANGELOG.md and/or govc/CHANGELOG.md when appropriate.
- Push your changes to a topic branch in your fork of the repository.
- Submit a pull request to vmware/govmomi.

View File

@ -10,10 +10,12 @@ Arran Walker <arran.walker@zopa.com>
Austin Parker <aparker@apprenda.com>
Bob Killen <killen.bob@gmail.com>
Bruce Downs <bdowns@vmware.com>
Clint Greenwood <cgreenwood@vmware.com> <clint.greenwood@gmail.com>
Cédric Blomart <cblomart@gmail.com>
Christian Höltje <docwhat@gerf.org>
Clint Greenwood <cgreenwood@vmware.com> <clint.greenwood@gmail.com>
Danny Lockard <danny.lockard@banno.com>
Dave Tucker <dave@dtucker.co.uk>
David Stark <dave@davidstark.name>
Doug MacEachern <dougm@vmware.com>
Eloy Coto <eloy.coto@gmail.com>
Eric Yutao <eric.yutao@gmail.com>
@ -31,8 +33,8 @@ Pieter Noordhuis <pnoordhuis@vmware.com> <pcnoordhuis@gmail.com>
runner.mei <runner.mei@gmail.com>
S.Çağlar Onur <conur@vmware.com>
Sergey Ignatov <sergey.ignatov@jetbrains.com>
Takaaki Furukawa <takaaki.frkw@gmail.com> <takaaki.furukawa@mail.rakuten.com>
Steve Purcell <steve@sanityinc.com>
Takaaki Furukawa <takaaki.frkw@gmail.com> <takaaki.furukawa@mail.rakuten.com>
Yang Yang <yangy@vmware.com>
Yuya Kusakabe <yuya.kusakabe@gmail.com>
Zach Tucker <ztucker@vmware.com>

View File

@ -4,21 +4,17 @@ all: check test
check: goimports govet
vendor:
go get golang.org/x/tools/cmd/goimports
go get github.com/davecgh/go-spew/spew
go get golang.org/x/net/context
goimports: vendor
goimports:
@echo checking go imports...
@go get golang.org/x/tools/cmd/goimports
@! goimports -d . 2>&1 | egrep -v '^$$'
govet:
@echo checking go vet...
@go tool vet -structtags=false -methods=false .
test: vendor
test:
go test -v $(TEST_OPTS) ./...
install: vendor
install:
go install github.com/vmware/govmomi/govc

View File

@ -25,6 +25,7 @@ import (
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
"golang.org/x/net/context"
)
@ -192,6 +193,48 @@ func (f *Finder) managedObjectList(ctx context.Context, path string, tl bool) ([
return f.find(ctx, fn, tl, path)
}
// Element returns an Element for the given ManagedObjectReference
// This method is only useful for looking up the InventoryPath of a ManagedObjectReference.
func (f *Finder) Element(ctx context.Context, ref types.ManagedObjectReference) (*list.Element, error) {
rl := func(_ context.Context) (object.Reference, error) {
return ref, nil
}
e, err := f.find(ctx, rl, false, ".")
if err != nil {
return nil, err
}
if len(e) == 0 {
return nil, &NotFoundError{ref.Type, ref.Value}
}
if len(e) > 1 {
panic("ManagedObjectReference must be unique")
}
return &e[0], nil
}
// ObjectReference converts the given ManagedObjectReference to a type from the object package via object.NewReference
// with the object.Common.InventoryPath field set.
func (f *Finder) ObjectReference(ctx context.Context, ref types.ManagedObjectReference) (object.Reference, error) {
e, err := f.Element(ctx, ref)
if err != nil {
return nil, err
}
r := object.NewReference(f.client, ref)
type common interface {
SetInventoryPath(string)
}
r.(common).SetInventoryPath(e.Path)
return r, nil
}
func (f *Finder) ManagedObjectList(ctx context.Context, path string) ([]list.Element, error) {
return f.managedObjectList(ctx, path, false)
}
@ -210,7 +253,9 @@ func (f *Finder) DatacenterList(ctx context.Context, path string) ([]*object.Dat
for _, e := range es {
ref := e.Object.Reference()
if ref.Type == "Datacenter" {
dcs = append(dcs, object.NewDatacenter(f.client, ref))
dc := object.NewDatacenter(f.client, ref)
dc.InventoryPath = e.Path
dcs = append(dcs, dc)
}
}
@ -772,7 +817,7 @@ func (f *Finder) FolderList(ctx context.Context, path string) ([]*object.Folder,
for _, e := range es {
switch o := e.Object.(type) {
case mo.Folder:
case mo.Folder, mo.StoragePod:
folder := object.NewFolder(f.client, o.Reference())
folder.InventoryPath = e.Path
folders = append(folders, folder)

View File

@ -25,8 +25,6 @@ import (
type ClusterComputeResource struct {
ComputeResource
InventoryPath string
}
func NewClusterComputeResource(c *vim25.Client, ref types.ManagedObjectReference) *ClusterComputeResource {

View File

@ -19,10 +19,12 @@ package object
import (
"errors"
"fmt"
"path"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/methods"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
"golang.org/x/net/context"
)
@ -33,12 +35,20 @@ var (
// Common contains the fields and functions common to all objects.
type Common struct {
InventoryPath string
c *vim25.Client
r types.ManagedObjectReference
}
func (c Common) String() string {
return fmt.Sprintf("%v", c.Reference())
ref := fmt.Sprintf("%v", c.Reference())
if c.InventoryPath == "" {
return ref
}
return fmt.Sprintf("%s @ %s", ref, c.InventoryPath)
}
func NewCommon(c *vim25.Client, r types.ManagedObjectReference) Common {
@ -53,6 +63,36 @@ func (c Common) Client() *vim25.Client {
return c.c
}
// Name returns the base name of the InventoryPath field
func (c Common) Name() string {
if c.InventoryPath == "" {
return ""
}
return path.Base(c.InventoryPath)
}
func (c *Common) SetInventoryPath(p string) {
c.InventoryPath = p
}
// ObjectName returns the base name of the InventoryPath field if set,
// otherwise fetches the mo.ManagedEntity.Name field via the property collector.
func (c Common) ObjectName(ctx context.Context) (string, error) {
var o mo.ManagedEntity
name := c.Name()
if name != "" {
return name, nil
}
err := c.Properties(ctx, c.Reference(), []string{"name"}, &o)
if err != nil {
return "", err
}
return o.Name, nil
}
func (c Common) Properties(ctx context.Context, r types.ManagedObjectReference, ps []string, dst interface{}) error {
return property.DefaultCollector(c.c).RetrieveOne(ctx, r, ps, dst)
}

View File

@ -29,8 +29,6 @@ import (
type ComputeResource struct {
Common
InventoryPath string
}
func NewComputeResource(c *vim25.Client, ref types.ManagedObjectReference) *ComputeResource {

View File

@ -20,6 +20,7 @@ import (
"fmt"
"io"
"math/rand"
"os"
"path"
"strings"
@ -57,8 +58,6 @@ func (e DatastoreNoSuchFileError) Error() string {
type Datastore struct {
Common
InventoryPath string
}
func NewDatastore(c *vim25.Client, ref types.ManagedObjectReference) *Datastore {
@ -67,10 +66,6 @@ func NewDatastore(c *vim25.Client, ref types.ManagedObjectReference) *Datastore
}
}
func (d Datastore) Name() string {
return path.Base(d.InventoryPath)
}
func (d Datastore) Path(path string) string {
name := d.Name()
if name == "" {
@ -116,6 +111,42 @@ func (d Datastore) Browser(ctx context.Context) (*HostDatastoreBrowser, error) {
return NewHostDatastoreBrowser(d.c, do.Browser), nil
}
func (d Datastore) useServiceTicketHostName(name string) bool {
// No need if talking directly to ESX.
if !d.c.IsVC() {
return false
}
// If version happens to be < 5.1
if name == "" {
return false
}
// If the HostSystem is using DHCP on a network without dynamic DNS,
// HostSystem.Config.Network.DnsConfig.HostName is set to "localhost" by default.
// This resolves to "localhost.localdomain" by default via /etc/hosts on ESX.
// In that case, we will stick with the HostSystem.Name which is the IP address that
// was used to connect the host to VC.
if name == "localhost.localdomain" {
return false
}
// Still possible to have HostName that don't resolve via DNS,
// so we default to false.
key := "GOVMOMI_USE_SERVICE_TICKET_HOSTNAME"
val := d.c.URL().Query().Get(key)
if val == "" {
val = os.Getenv(key)
}
if val == "1" || val == "true" {
return true
}
return false
}
// ServiceTicket obtains a ticket via AcquireGenericServiceTicket and returns it an http.Cookie with the url.URL
// that can be used along with the ticket cookie to access the given path.
func (d Datastore) ServiceTicket(ctx context.Context, path string, method string) (*url.URL, *http.Cookie, error) {
@ -142,7 +173,7 @@ func (d Datastore) ServiceTicket(ctx context.Context, path string, method string
// Pick a random attached host
host := hosts[rand.Intn(len(hosts))]
name, err := host.Name(ctx)
name, err := host.ObjectName(ctx)
if err != nil {
return nil, nil, err
}
@ -167,6 +198,10 @@ func (d Datastore) ServiceTicket(ctx context.Context, path string, method string
Value: ticket.Id,
}
if d.useServiceTicketHostName(ticket.HostName) {
u.Host = ticket.HostName
}
return u, cookie, nil
}

View File

@ -17,8 +17,6 @@ limitations under the License.
package object
import (
"path"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
@ -27,8 +25,6 @@ import (
type DistributedVirtualPortgroup struct {
Common
InventoryPath string
}
func NewDistributedVirtualPortgroup(c *vim25.Client, ref types.ManagedObjectReference) *DistributedVirtualPortgroup {
@ -36,9 +32,6 @@ func NewDistributedVirtualPortgroup(c *vim25.Client, ref types.ManagedObjectRefe
Common: NewCommon(c, ref),
}
}
func (p DistributedVirtualPortgroup) Name() string {
return path.Base(p.InventoryPath)
}
// EthernetCardBackingInfo returns the VirtualDeviceBackingInfo for this DistributedVirtualPortgroup
func (p DistributedVirtualPortgroup) EthernetCardBackingInfo(ctx context.Context) (types.BaseVirtualDeviceBackingInfo, error) {

View File

@ -25,8 +25,6 @@ import (
type DistributedVirtualSwitch struct {
Common
InventoryPath string
}
func NewDistributedVirtualSwitch(c *vim25.Client, ref types.ManagedObjectReference) *DistributedVirtualSwitch {

View File

@ -26,8 +26,6 @@ import (
type Folder struct {
Common
InventoryPath string
}
func NewFolder(c *vim25.Client, ref types.ManagedObjectReference) *Folder {
@ -113,6 +111,20 @@ func (f Folder) CreateFolder(ctx context.Context, name string) (*Folder, error)
return NewFolder(f.c, res.Returnval), err
}
func (f Folder) CreateStoragePod(ctx context.Context, name string) (*StoragePod, error) {
req := types.CreateStoragePod{
This: f.Reference(),
Name: name,
}
res, err := methods.CreateStoragePod(ctx, f.c, &req)
if err != nil {
return nil, err
}
return NewStoragePod(f.c, res.Returnval), err
}
func (f Folder) AddStandaloneHost(ctx context.Context, spec types.HostConnectSpec, addConnected bool, license *string, compResSpec *types.BaseComputeResourceConfigSpec) (*Task, error) {
req := types.AddStandaloneHost_Task{
This: f.Reference(),

View File

@ -120,3 +120,14 @@ func (m HostConfigManager) OptionManager(ctx context.Context) (*OptionManager, e
return NewOptionManager(m.c, *h.ConfigManager.AdvancedOption), nil
}
func (m HostConfigManager) ServiceSystem(ctx context.Context) (*HostServiceSystem, error) {
var h mo.HostSystem
err := m.Properties(ctx, m.Reference(), []string{"configManager.serviceSystem"}, &h)
if err != nil {
return nil, err
}
return NewHostServiceSystem(m.c, *h.ConfigManager.ServiceSystem), nil
}

View File

@ -33,6 +33,21 @@ func NewHostDatastoreSystem(c *vim25.Client, ref types.ManagedObjectReference) *
}
}
func (s HostDatastoreSystem) CreateLocalDatastore(ctx context.Context, name string, path string) (*Datastore, error) {
req := types.CreateLocalDatastore{
This: s.Reference(),
Name: name,
Path: path,
}
res, err := methods.CreateLocalDatastore(ctx, s.Client(), &req)
if err != nil {
return nil, err
}
return NewDatastore(s.Client(), res.Returnval), nil
}
func (s HostDatastoreSystem) CreateNasDatastore(ctx context.Context, spec types.HostNasVolumeSpec) (*Datastore, error) {
req := types.CreateNasDatastore{
This: s.Reference(),

View File

@ -0,0 +1,87 @@
/*
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package object
import (
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/methods"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
"golang.org/x/net/context"
)
type HostServiceSystem struct {
Common
}
func NewHostServiceSystem(c *vim25.Client, ref types.ManagedObjectReference) *HostServiceSystem {
return &HostServiceSystem{
Common: NewCommon(c, ref),
}
}
func (s HostServiceSystem) Service(ctx context.Context) ([]types.HostService, error) {
var ss mo.HostServiceSystem
err := s.Properties(ctx, s.Reference(), []string{"serviceInfo.service"}, &ss)
if err != nil {
return nil, err
}
return ss.ServiceInfo.Service, nil
}
func (s HostServiceSystem) Start(ctx context.Context, id string) error {
req := types.StartService{
This: s.Reference(),
Id: id,
}
_, err := methods.StartService(ctx, s.Client(), &req)
return err
}
func (s HostServiceSystem) Stop(ctx context.Context, id string) error {
req := types.StopService{
This: s.Reference(),
Id: id,
}
_, err := methods.StopService(ctx, s.Client(), &req)
return err
}
func (s HostServiceSystem) Restart(ctx context.Context, id string) error {
req := types.RestartService{
This: s.Reference(),
Id: id,
}
_, err := methods.RestartService(ctx, s.Client(), &req)
return err
}
func (s HostServiceSystem) UpdatePolicy(ctx context.Context, id string, policy string) error {
req := types.UpdateServicePolicy{
This: s.Reference(),
Id: id,
Policy: policy,
}
_, err := methods.UpdateServicePolicy(ctx, s.Client(), &req)
return err
}

View File

@ -78,3 +78,68 @@ func (s HostStorageSystem) UpdateDiskPartitionInfo(ctx context.Context, devicePa
_, err := methods.UpdateDiskPartitions(ctx, s.c, &req)
return err
}
func (s HostStorageSystem) RescanAllHba(ctx context.Context) error {
req := types.RescanAllHba{
This: s.Reference(),
}
_, err := methods.RescanAllHba(ctx, s.c, &req)
return err
}
func (s HostStorageSystem) MarkAsSsd(ctx context.Context, uuid string) (*Task, error) {
req := types.MarkAsSsd_Task{
This: s.Reference(),
ScsiDiskUuid: uuid,
}
res, err := methods.MarkAsSsd_Task(ctx, s.c, &req)
if err != nil {
return nil, err
}
return NewTask(s.c, res.Returnval), nil
}
func (s HostStorageSystem) MarkAsNonSsd(ctx context.Context, uuid string) (*Task, error) {
req := types.MarkAsNonSsd_Task{
This: s.Reference(),
ScsiDiskUuid: uuid,
}
res, err := methods.MarkAsNonSsd_Task(ctx, s.c, &req)
if err != nil {
return nil, err
}
return NewTask(s.c, res.Returnval), nil
}
func (s HostStorageSystem) MarkAsLocal(ctx context.Context, uuid string) (*Task, error) {
req := types.MarkAsLocal_Task{
This: s.Reference(),
ScsiDiskUuid: uuid,
}
res, err := methods.MarkAsLocal_Task(ctx, s.c, &req)
if err != nil {
return nil, err
}
return NewTask(s.c, res.Returnval), nil
}
func (s HostStorageSystem) MarkAsNonLocal(ctx context.Context, uuid string) (*Task, error) {
req := types.MarkAsNonLocal_Task{
This: s.Reference(),
ScsiDiskUuid: uuid,
}
res, err := methods.MarkAsNonLocal_Task(ctx, s.c, &req)
if err != nil {
return nil, err
}
return NewTask(s.c, res.Returnval), nil
}

View File

@ -29,15 +29,6 @@ import (
type HostSystem struct {
Common
InventoryPath string
}
func (h HostSystem) String() string {
if h.InventoryPath == "" {
return h.Common.String()
}
return fmt.Sprintf("%v @ %v", h.Common, h.InventoryPath)
}
func NewHostSystem(c *vim25.Client, ref types.ManagedObjectReference) *HostSystem {
@ -46,17 +37,6 @@ func NewHostSystem(c *vim25.Client, ref types.ManagedObjectReference) *HostSyste
}
}
func (h HostSystem) Name(ctx context.Context) (string, error) {
var mh mo.HostSystem
err := h.Properties(ctx, h.Reference(), []string{"name"}, &mh)
if err != nil {
return "", err
}
return mh.Name, nil
}
func (h HostSystem) ConfigManager() *HostConfigManager {
return NewHostConfigManager(h.c, h.Reference())
}

View File

@ -0,0 +1,75 @@
/*
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 object
import (
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/methods"
"github.com/vmware/govmomi/vim25/types"
"golang.org/x/net/context"
)
type DatastoreNamespaceManager struct {
Common
}
func NewDatastoreNamespaceManager(c *vim25.Client) *DatastoreNamespaceManager {
n := DatastoreNamespaceManager{
Common: NewCommon(c, *c.ServiceContent.DatastoreNamespaceManager),
}
return &n
}
// CreateDirectory creates a top-level directory on the given vsan datastore, using
// the given user display name hint and opaque storage policy.
func (nm DatastoreNamespaceManager) CreateDirectory(ctx context.Context, ds *Datastore, displayName string, policy string) (string, error) {
req := &types.CreateDirectory{
This: nm.Reference(),
Datastore: ds.Reference(),
DisplayName: displayName,
Policy: policy,
}
resp, err := methods.CreateDirectory(ctx, nm.c, req)
if err != nil {
return "", err
}
return resp.Returnval, nil
}
// DeleteDirectory deletes the given top-level directory from a vsan datastore.
func (nm DatastoreNamespaceManager) DeleteDirectory(ctx context.Context, dc *Datacenter, datastorePath string) error {
req := &types.DeleteDirectory{
This: nm.Reference(),
DatastorePath: datastorePath,
}
if dc != nil {
ref := dc.Reference()
req.Datacenter = &ref
}
if _, err := methods.DeleteDirectory(ctx, nm.c, req); err != nil {
return err
}
return nil
}

View File

@ -17,8 +17,6 @@ limitations under the License.
package object
import (
"path"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/types"
"golang.org/x/net/context"
@ -26,8 +24,6 @@ import (
type Network struct {
Common
InventoryPath string
}
func NewNetwork(c *vim25.Client, ref types.ManagedObjectReference) *Network {
@ -36,10 +32,6 @@ func NewNetwork(c *vim25.Client, ref types.ManagedObjectReference) *Network {
}
}
func (n Network) Name() string {
return path.Base(n.InventoryPath)
}
// EthernetCardBackingInfo returns the VirtualDeviceBackingInfo for this Network
func (n Network) EthernetCardBackingInfo(_ context.Context) (types.BaseVirtualDeviceBackingInfo, error) {
name := n.Name()

View File

@ -17,26 +17,14 @@ limitations under the License.
package object
import (
"fmt"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/methods"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
"golang.org/x/net/context"
)
type ResourcePool struct {
Common
InventoryPath string
}
func (p ResourcePool) String() string {
if p.InventoryPath == "" {
return p.Common.String()
}
return fmt.Sprintf("%v @ %v", p.Common, p.InventoryPath)
}
func NewResourcePool(c *vim25.Client, ref types.ManagedObjectReference) *ResourcePool {
@ -45,17 +33,6 @@ func NewResourcePool(c *vim25.Client, ref types.ManagedObjectReference) *Resourc
}
}
func (p ResourcePool) Name(ctx context.Context) (string, error) {
var o mo.ResourcePool
err := p.Properties(ctx, p.Reference(), []string{"name"}, &o)
if err != nil {
return "", err
}
return o.Name, nil
}
func (p ResourcePool) ImportVApp(ctx context.Context, spec types.BaseImportSpec, folder *Folder, host *HostSystem) (*HttpNfcLease, error) {
req := types.ImportVApp{
This: p.Reference(),

View File

@ -17,13 +17,10 @@ limitations under the License.
package object
import (
"fmt"
"golang.org/x/net/context"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/methods"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
@ -37,24 +34,6 @@ func NewVirtualApp(c *vim25.Client, ref types.ManagedObjectReference) *VirtualAp
}
}
func (p VirtualApp) String() string {
if p.InventoryPath == "" {
return p.Common.String()
}
return fmt.Sprintf("%v @ %v", p.Common, p.InventoryPath)
}
func (p VirtualApp) Name(ctx context.Context) (string, error) {
var o mo.VirtualApp
err := p.Properties(ctx, p.Reference(), []string{"name"}, &o)
if err != nil {
return "", err
}
return o.Name, nil
}
func (p VirtualApp) CreateChildVM_Task(ctx context.Context, config types.VirtualMachineConfigSpec, host *HostSystem) (*Task, error) {
req := types.CreateChildVM_Task{
This: p.Reference(),

View File

@ -143,3 +143,27 @@ func (m VirtualDiskManager) DeleteVirtualDisk(ctx context.Context, name string,
return NewTask(m.c, res.Returnval), nil
}
// Queries virtual disk uuid
func (m VirtualDiskManager) QueryVirtualDiskUuid(ctx context.Context, name string, dc *Datacenter) (string, error) {
req := types.QueryVirtualDiskUuid{
This: m.Reference(),
Name: name,
}
if dc != nil {
ref := dc.Reference()
req.Datacenter = &ref
}
res, err := methods.QueryVirtualDiskUuid(ctx, m.c, &req)
if err != nil {
return "", err
}
if res == nil {
return "", nil
}
return res.Returnval, nil
}

View File

@ -18,7 +18,6 @@ package object
import (
"errors"
"fmt"
"net"
"github.com/vmware/govmomi/property"
@ -35,15 +34,6 @@ const (
type VirtualMachine struct {
Common
InventoryPath string
}
func (v VirtualMachine) String() string {
if v.InventoryPath == "" {
return v.Common.String()
}
return fmt.Sprintf("%v @ %v", v.Common, v.InventoryPath)
}
func NewVirtualMachine(c *vim25.Client, ref types.ManagedObjectReference) *VirtualMachine {
@ -52,17 +42,6 @@ func NewVirtualMachine(c *vim25.Client, ref types.ManagedObjectReference) *Virtu
}
}
func (v VirtualMachine) Name(ctx context.Context) (string, error) {
var o mo.VirtualMachine
err := v.Properties(ctx, v.Reference(), []string{"name"}, &o)
if err != nil {
return "", err
}
return o.Name, nil
}
func (v VirtualMachine) PowerState(ctx context.Context) (types.VirtualMachinePowerState, error) {
var o mo.VirtualMachine

View File

@ -161,3 +161,17 @@ func (sm *Manager) AcquireGenericServiceTicket(ctx context.Context, spec types.B
return &res.Returnval, nil
}
func (sm *Manager) AcquireLocalTicket(ctx context.Context, userName string) (*types.SessionManagerLocalTicket, error) {
req := types.AcquireLocalTicket{
This: sm.Reference(),
UserName: userName,
}
res, err := methods.AcquireLocalTicket(ctx, sm.client, &req)
if err != nil {
return nil, err
}
return &res.Returnval, nil
}

View File

@ -17,6 +17,8 @@ limitations under the License.
package mo
import (
"fmt"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
"golang.org/x/net/context"
@ -76,6 +78,24 @@ func Ancestors(ctx context.Context, rt soap.RoundTripper, pc, obj types.ManagedO
// Find entity we're looking for given the last entity in the current tree.
for _, iface := range ifaces {
me := iface.(IsManagedEntity).GetManagedEntity()
if me.Name == "" {
// The types below have their own 'Name' field, so ManagedEntity.Name (me.Name) is empty.
// We only hit this case when the 'obj' param is one of these types.
// In most cases, 'obj' is a Folder so Name isn't collected in this call.
switch x := iface.(type) {
case Network:
me.Name = x.Name
case DistributedVirtualSwitch:
me.Name = x.Name
case DistributedVirtualPortgroup:
me.Name = x.Name
default:
// ManagedEntity always has a Name, if we hit this point we missed a case above.
panic(fmt.Sprintf("%#v Name is empty", me.Reference()))
}
}
if me.Parent == nil {
out = append(out, me)
break

View File

@ -36,6 +36,10 @@ func (m DistributedVirtualSwitch) GetManagedEntity() ManagedEntity {
return m.ManagedEntity
}
func (m DistributedVirtualPortgroup) GetManagedEntity() ManagedEntity {
return m.ManagedEntity
}
func (m Folder) GetManagedEntity() ManagedEntity {
return m.ManagedEntity
}

View File

@ -36,7 +36,7 @@ type Fault struct {
Code string `xml:"faultcode"`
String string `xml:"faultstring"`
Detail struct {
Fault types.AnyType `xml:",any"`
Fault types.AnyType `xml:",any,typeattr"`
} `xml:"detail"`
}

View File

@ -16,6 +16,8 @@ limitations under the License.
package types
import "strings"
func NewBool(v bool) *bool {
return &v
}
@ -23,3 +25,24 @@ func NewBool(v bool) *bool {
func NewReference(r ManagedObjectReference) *ManagedObjectReference {
return &r
}
func (r ManagedObjectReference) Reference() ManagedObjectReference {
return r
}
func (r ManagedObjectReference) String() string {
return strings.Join([]string{r.Type, r.Value}, ":")
}
func (r *ManagedObjectReference) FromString(o string) bool {
s := strings.SplitN(o, ":", 2)
if len(s) < 2 {
return false
}
r.Type = s[0]
r.Value = s[1]
return true
}