diff --git a/vendor/github.com/vmware/govmomi/find/doc.go b/vendor/github.com/vmware/govmomi/find/doc.go new file mode 100644 index 000000000..0c8acee01 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/find/doc.go @@ -0,0 +1,37 @@ +/* +Copyright (c) 2014-2017 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package find implements inventory listing and searching. + +The Finder is an alternative to the object.SearchIndex FindByInventoryPath() and FindChild() methods. +SearchIndex.FindByInventoryPath requires an absolute path, whereas the Finder also supports relative paths +and patterns via path.Match. +SearchIndex.FindChild requires a parent to find the child, whereas the Finder also supports an ancestor via +recursive object traversal. + +The various Finder methods accept a "path" argument, which can absolute or relative to the Folder for the object type. +The Finder supports two modes, "list" and "find". The "list" mode behaves like the "ls" command, only searching within +the immediate path. The "find" mode behaves like the "find" command, with the search starting at the immediate path but +also recursing into sub Folders relative to the Datacenter. The default mode is "list" if the given path contains a "/", +otherwise "find" mode is used. + +The exception is to use a "..." wildcard with a path to find all objects recursively underneath any root object. +For example: VirtualMachineList("/DC1/...") + +See also: https://github.com/vmware/govmomi/blob/master/govc/README.md#usage +*/ +package find diff --git a/vendor/github.com/vmware/govmomi/find/finder.go b/vendor/github.com/vmware/govmomi/find/finder.go index 3e9c3acb3..04d0e891a 100644 --- a/vendor/github.com/vmware/govmomi/find/finder.go +++ b/vendor/github.com/vmware/govmomi/find/finder.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved. +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. @@ -17,29 +17,32 @@ limitations under the License. package find import ( + "context" "errors" "path" + "strings" "github.com/vmware/govmomi/list" "github.com/vmware/govmomi/object" "github.com/vmware/govmomi/property" "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/mo" - "golang.org/x/net/context" + "github.com/vmware/govmomi/vim25/types" ) type Finder struct { - client *vim25.Client - recurser list.Recurser - + client *vim25.Client + r recurser dc *object.Datacenter + si *object.SearchIndex folders *object.DatacenterFolders } func NewFinder(client *vim25.Client, all bool) *Finder { f := &Finder{ client: client, - recurser: list.Recurser{ + si: object.NewSearchIndex(client), + r: recurser{ Collector: property.DefaultCollector(client), All: all, }, @@ -54,9 +57,41 @@ func (f *Finder) SetDatacenter(dc *object.Datacenter) *Finder { return f } -type findRelativeFunc func(ctx context.Context) (object.Reference, error) +// findRoot makes it possible to use "find" mode with a different root path. +// Example: ResourcePoolList("/dc1/host/cluster1/...") +func (f *Finder) findRoot(ctx context.Context, root *list.Element, parts []string) bool { + if len(parts) == 0 { + return false + } + + ix := len(parts) - 1 + + if parts[ix] != "..." { + return false + } + + if ix == 0 { + return true // We already have the Object for root.Path + } + + // Lookup the Object for the new root.Path + rootPath := path.Join(root.Path, path.Join(parts[:ix]...)) + + ref, err := f.si.FindByInventoryPath(ctx, rootPath) + if err != nil || ref == nil { + // If we get an error or fail to match, fall through to find() with the original root and path + return false + } + + root.Path = rootPath + root.Object = ref + + return true +} + +func (f *Finder) find(ctx context.Context, arg string, s *spec) ([]list.Element, error) { + isPath := strings.Contains(arg, "/") -func (f *Finder) find(ctx context.Context, fn findRelativeFunc, tl bool, arg string) ([]list.Element, error) { root := list.Element{ Path: "/", Object: object.NewRootFolder(f.client), @@ -69,7 +104,7 @@ func (f *Finder) find(ctx context.Context, fn findRelativeFunc, tl bool, arg str case "..": // Not supported; many edge case, little value return nil, errors.New("cannot traverse up a tree") case ".": // Relative to whatever - pivot, err := fn(ctx) + pivot, err := s.Relative(ctx) if err != nil { return nil, err } @@ -92,13 +127,17 @@ func (f *Finder) find(ctx context.Context, fn findRelativeFunc, tl bool, arg str } } - f.recurser.TraverseLeafs = tl - es, err := f.recurser.Recurse(ctx, root, parts) - if err != nil { - return nil, err + if s.listMode(isPath) { + if f.findRoot(ctx, &root, parts) { + parts = []string{"*"} + } else { + return f.r.List(ctx, s, root, parts) + } } - return es, nil + s.Parents = append(s.Parents, s.Nested...) + + return f.r.Find(ctx, s, root, parts) } func (f *Finder) datacenter() (*object.Datacenter, error) { @@ -109,6 +148,35 @@ func (f *Finder) datacenter() (*object.Datacenter, error) { return f.dc, nil } +// datacenterPath returns the absolute path to the Datacenter containing the given ref +func (f *Finder) datacenterPath(ctx context.Context, ref types.ManagedObjectReference) (string, error) { + mes, err := mo.Ancestors(ctx, f.client, f.client.ServiceContent.PropertyCollector, ref) + if err != nil { + return "", err + } + + // Chop leaves under the Datacenter + for i := len(mes) - 1; i > 0; i-- { + if mes[i].Self.Type == "Datacenter" { + break + } + mes = mes[:i] + } + + var p string + + for _, me := range mes { + // Skip root entity in building inventory path. + if me.Parent == nil { + continue + } + + p = p + "/" + me.Name + } + + return p, nil +} + func (f *Finder) dcFolders(ctx context.Context) (*object.DatacenterFolders, error) { if f.folders != nil { return f.folders, nil @@ -178,7 +246,7 @@ func (f *Finder) rootFolder(_ context.Context) (object.Reference, error) { return object.NewRootFolder(f.client), nil } -func (f *Finder) managedObjectList(ctx context.Context, path string, tl bool) ([]list.Element, error) { +func (f *Finder) managedObjectList(ctx context.Context, path string, tl bool, include []string) ([]list.Element, error) { fn := f.rootFolder if f.dc != nil { @@ -189,19 +257,87 @@ func (f *Finder) managedObjectList(ctx context.Context, path string, tl bool) ([ path = "." } - return f.find(ctx, fn, tl, path) + s := &spec{ + Relative: fn, + Parents: []string{"ComputeResource", "ClusterComputeResource", "HostSystem", "VirtualApp", "StoragePod"}, + Include: include, + } + + if tl { + s.Contents = true + s.ListMode = types.NewBool(true) + } + + return f.find(ctx, path, s) +} + +// 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 + } + + s := &spec{ + Relative: rl, + } + + e, err := f.find(ctx, "./", s) + 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) + + if f.dc != nil { + if ds, ok := r.(*object.Datastore); ok { + ds.DatacenterPath = f.dc.InventoryPath + } + } + + return r, nil } -func (f *Finder) ManagedObjectList(ctx context.Context, path string) ([]list.Element, error) { - return f.managedObjectList(ctx, path, false) +func (f *Finder) ManagedObjectList(ctx context.Context, path string, include ...string) ([]list.Element, error) { + return f.managedObjectList(ctx, path, false, include) } -func (f *Finder) ManagedObjectListChildren(ctx context.Context, path string) ([]list.Element, error) { - return f.managedObjectList(ctx, path, true) +func (f *Finder) ManagedObjectListChildren(ctx context.Context, path string, include ...string) ([]list.Element, error) { + return f.managedObjectList(ctx, path, true, include) } func (f *Finder) DatacenterList(ctx context.Context, path string) ([]*object.Datacenter, error) { - es, err := f.find(ctx, f.rootFolder, false, path) + s := &spec{ + Relative: f.rootFolder, + Include: []string{"Datacenter"}, + } + + es, err := f.find(ctx, path, s) if err != nil { return nil, err } @@ -210,7 +346,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) } } @@ -256,7 +394,12 @@ func (f *Finder) DatacenterOrDefault(ctx context.Context, path string) (*object. } func (f *Finder) DatastoreList(ctx context.Context, path string) ([]*object.Datastore, error) { - es, err := f.find(ctx, f.datastoreFolder, false, path) + s := &spec{ + Relative: f.datastoreFolder, + Parents: []string{"StoragePod"}, + } + + es, err := f.find(ctx, path, s) if err != nil { return nil, err } @@ -268,6 +411,16 @@ func (f *Finder) DatastoreList(ctx context.Context, path string) ([]*object.Data ds := object.NewDatastore(f.client, ref) ds.InventoryPath = e.Path + if f.dc == nil { + // In this case SetDatacenter was not called and path is absolute + ds.DatacenterPath, err = f.datacenterPath(ctx, ref) + if err != nil { + return nil, err + } + } else { + ds.DatacenterPath = f.dc.InventoryPath + } + dss = append(dss, ds) } } @@ -314,7 +467,11 @@ func (f *Finder) DatastoreOrDefault(ctx context.Context, path string) (*object.D } func (f *Finder) DatastoreClusterList(ctx context.Context, path string) ([]*object.StoragePod, error) { - es, err := f.find(ctx, f.datastoreFolder, false, path) + s := &spec{ + Relative: f.datastoreFolder, + } + + es, err := f.find(ctx, path, s) if err != nil { return nil, err } @@ -371,7 +528,11 @@ func (f *Finder) DatastoreClusterOrDefault(ctx context.Context, path string) (*o } func (f *Finder) ComputeResourceList(ctx context.Context, path string) ([]*object.ComputeResource, error) { - es, err := f.find(ctx, f.hostFolder, false, path) + s := &spec{ + Relative: f.hostFolder, + } + + es, err := f.find(ctx, path, s) if err != nil { return nil, err } @@ -433,7 +594,11 @@ func (f *Finder) ComputeResourceOrDefault(ctx context.Context, path string) (*ob } func (f *Finder) ClusterComputeResourceList(ctx context.Context, path string) ([]*object.ClusterComputeResource, error) { - es, err := f.find(ctx, f.hostFolder, false, path) + s := &spec{ + Relative: f.hostFolder, + } + + es, err := f.find(ctx, path, s) if err != nil { return nil, err } @@ -474,7 +639,13 @@ func (f *Finder) ClusterComputeResource(ctx context.Context, path string) (*obje } func (f *Finder) HostSystemList(ctx context.Context, path string) ([]*object.HostSystem, error) { - es, err := f.find(ctx, f.hostFolder, false, path) + s := &spec{ + Relative: f.hostFolder, + Parents: []string{"ComputeResource", "ClusterComputeResource"}, + Include: []string{"HostSystem"}, + } + + es, err := f.find(ctx, path, s) if err != nil { return nil, err } @@ -545,7 +716,11 @@ func (f *Finder) HostSystemOrDefault(ctx context.Context, path string) (*object. } func (f *Finder) NetworkList(ctx context.Context, path string) ([]object.NetworkReference, error) { - es, err := f.find(ctx, f.networkFolder, false, path) + s := &spec{ + Relative: f.networkFolder, + } + + es, err := f.find(ctx, path, s) if err != nil { return nil, err } @@ -558,6 +733,10 @@ func (f *Finder) NetworkList(ctx context.Context, path string) ([]object.Network r := object.NewNetwork(f.client, ref) r.InventoryPath = e.Path ns = append(ns, r) + case "OpaqueNetwork": + r := object.NewOpaqueNetwork(f.client, ref) + r.InventoryPath = e.Path + ns = append(ns, r) case "DistributedVirtualPortgroup": r := object.NewDistributedVirtualPortgroup(f.client, ref) r.InventoryPath = e.Path @@ -611,7 +790,14 @@ func (f *Finder) NetworkOrDefault(ctx context.Context, path string) (object.Netw } func (f *Finder) ResourcePoolList(ctx context.Context, path string) ([]*object.ResourcePool, error) { - es, err := f.find(ctx, f.hostFolder, true, path) + s := &spec{ + Relative: f.hostFolder, + Parents: []string{"ComputeResource", "ClusterComputeResource", "VirtualApp"}, + Nested: []string{"ResourcePool"}, + Contents: true, + } + + es, err := f.find(ctx, path, s) if err != nil { return nil, err } @@ -669,6 +855,29 @@ func (f *Finder) ResourcePoolOrDefault(ctx context.Context, path string) (*objec return f.DefaultResourcePool(ctx) } +// ResourcePoolListAll combines ResourcePoolList and VirtualAppList +// VirtualAppList is only called if ResourcePoolList does not find any pools with the given path. +func (f *Finder) ResourcePoolListAll(ctx context.Context, path string) ([]*object.ResourcePool, error) { + pools, err := f.ResourcePoolList(ctx, path) + if err != nil { + if _, ok := err.(*NotFoundError); !ok { + return nil, err + } + + vapps, _ := f.VirtualAppList(ctx, path) + + if len(vapps) == 0 { + return nil, err + } + + for _, vapp := range vapps { + pools = append(pools, vapp.ResourcePool) + } + } + + return pools, nil +} + func (f *Finder) DefaultFolder(ctx context.Context) (*object.Folder, error) { ref, err := f.vmFolder(ctx) if err != nil { @@ -691,7 +900,12 @@ func (f *Finder) FolderOrDefault(ctx context.Context, path string) (*object.Fold } func (f *Finder) VirtualMachineList(ctx context.Context, path string) ([]*object.VirtualMachine, error) { - es, err := f.find(ctx, f.vmFolder, false, path) + s := &spec{ + Relative: f.vmFolder, + Parents: []string{"VirtualApp"}, + } + + es, err := f.find(ctx, path, s) if err != nil { return nil, err } @@ -727,7 +941,11 @@ func (f *Finder) VirtualMachine(ctx context.Context, path string) (*object.Virtu } func (f *Finder) VirtualAppList(ctx context.Context, path string) ([]*object.VirtualApp, error) { - es, err := f.find(ctx, f.vmFolder, false, path) + s := &spec{ + Relative: f.vmFolder, + } + + es, err := f.find(ctx, path, s) if err != nil { return nil, err } @@ -772,7 +990,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) diff --git a/vendor/github.com/vmware/govmomi/find/recurser.go b/vendor/github.com/vmware/govmomi/find/recurser.go new file mode 100644 index 000000000..b62e93a6f --- /dev/null +++ b/vendor/github.com/vmware/govmomi/find/recurser.go @@ -0,0 +1,245 @@ +/* +Copyright (c) 2014-2017 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package find + +import ( + "context" + "os" + "path" + + "github.com/vmware/govmomi/list" + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/vim25/mo" +) + +// spec is used to specify per-search configuration, independent of the Finder instance. +type spec struct { + // Relative returns the root object to resolve Relative paths (starts with ".") + Relative func(ctx context.Context) (object.Reference, error) + + // ListMode can be used to optionally force "ls" behavior, rather than "find" behavior + ListMode *bool + + // Contents configures the Recurser to list the Contents of traversable leaf nodes. + // This is typically set to true when used from the ls command, where listing + // a folder means listing its Contents. This is typically set to false for + // commands that take managed entities that are not folders as input. + Contents bool + + // Parents specifies the types which can contain the child types being searched for. + // for example, when searching for a HostSystem, parent types can be + // "ComputeResource" or "ClusterComputeResource". + Parents []string + + // Include specifies which types to be included in the results, used only in "find" mode. + Include []string + + // Nested should be set to types that can be Nested, used only in "find" mode. + Nested []string + + // ChildType avoids traversing into folders that can't contain the Include types, used only in "find" mode. + ChildType []string +} + +func (s *spec) traversable(o mo.Reference) bool { + ref := o.Reference() + + switch ref.Type { + case "Datacenter": + if len(s.Include) == 1 && s.Include[0] == "Datacenter" { + // No point in traversing deeper as Datacenters cannot be nested + return false + } + return true + case "Folder": + if f, ok := o.(mo.Folder); ok { + // TODO: Not making use of this yet, but here we can optimize when searching the entire + // inventory across Datacenters for specific types, for example: 'govc ls -t VirtualMachine /**' + // should not traverse into a Datacenter's host, network or datatore folders. + if !s.traversableChildType(f.ChildType) { + return false + } + } + + return true + } + + for _, kind := range s.Parents { + if kind == ref.Type { + return true + } + } + + return false +} + +func (s *spec) traversableChildType(ctypes []string) bool { + if len(s.ChildType) == 0 { + return true + } + + for _, t := range ctypes { + for _, c := range s.ChildType { + if t == c { + return true + } + } + } + + return false +} + +func (s *spec) wanted(e list.Element) bool { + if len(s.Include) == 0 { + return true + } + + w := e.Object.Reference().Type + + for _, kind := range s.Include { + if w == kind { + return true + } + } + + return false +} + +// listMode is a global option to revert to the original Finder behavior, +// disabling the newer "find" mode. +var listMode = os.Getenv("GOVMOMI_FINDER_LIST_MODE") == "true" + +func (s *spec) listMode(isPath bool) bool { + if listMode { + return true + } + + if s.ListMode != nil { + return *s.ListMode + } + + return isPath +} + +type recurser struct { + Collector *property.Collector + + // All configures the recurses to fetch complete objects for leaf nodes. + All bool +} + +func (r recurser) List(ctx context.Context, s *spec, root list.Element, parts []string) ([]list.Element, error) { + if len(parts) == 0 { + // Include non-traversable leaf elements in result. For example, consider + // the pattern "./vm/my-vm-*", where the pattern should match the VMs and + // not try to traverse them. + // + // Include traversable leaf elements in result, if the contents + // field is set to false. + // + if !s.Contents || !s.traversable(root.Object.Reference()) { + return []list.Element{root}, nil + } + } + + k := list.Lister{ + Collector: r.Collector, + Reference: root.Object.Reference(), + Prefix: root.Path, + } + + if r.All && len(parts) < 2 { + k.All = true + } + + in, err := k.List(ctx) + if err != nil { + return nil, err + } + + // This folder is a leaf as far as the glob goes. + if len(parts) == 0 { + return in, nil + } + + pattern := parts[0] + parts = parts[1:] + + var out []list.Element + for _, e := range in { + matched, err := path.Match(pattern, path.Base(e.Path)) + if err != nil { + return nil, err + } + + if !matched { + continue + } + + nres, err := r.List(ctx, s, e, parts) + if err != nil { + return nil, err + } + + out = append(out, nres...) + } + + return out, nil +} + +func (r recurser) Find(ctx context.Context, s *spec, root list.Element, parts []string) ([]list.Element, error) { + var out []list.Element + + if len(parts) > 0 { + pattern := parts[0] + matched, err := path.Match(pattern, path.Base(root.Path)) + if err != nil { + return nil, err + } + + if matched && s.wanted(root) { + out = append(out, root) + } + } + + if !s.traversable(root.Object) { + return out, nil + } + + k := list.Lister{ + Collector: r.Collector, + Reference: root.Object.Reference(), + Prefix: root.Path, + } + + in, err := k.List(ctx) + if err != nil { + return nil, err + } + + for _, e := range in { + nres, err := r.Find(ctx, s, e, parts) + if err != nil { + return nil, err + } + + out = append(out, nres...) + } + + return out, nil +} diff --git a/vendor/github.com/vmware/govmomi/list/lister.go b/vendor/github.com/vmware/govmomi/list/lister.go index 355208f53..2ee32e6bc 100644 --- a/vendor/github.com/vmware/govmomi/list/lister.go +++ b/vendor/github.com/vmware/govmomi/list/lister.go @@ -17,6 +17,7 @@ limitations under the License. package list import ( + "context" "fmt" "path" "reflect" @@ -25,7 +26,6 @@ import ( "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/soap" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type Element struct { @@ -33,6 +33,10 @@ type Element struct { Object mo.Reference } +func (e Element) String() string { + return fmt.Sprintf("%s @ %s", e.Object.Reference(), e.Path) +} + func ToElement(r mo.Reference, prefix string) Element { var name string @@ -79,6 +83,8 @@ func ToElement(r mo.Reference, prefix string) Element { // Network entity folders on an ESXi host can contain only Network objects. case mo.Network: name = m.Name + case mo.OpaqueNetwork: + name = m.Name case mo.DistributedVirtualSwitch: name = m.Name case mo.DistributedVirtualPortgroup: @@ -110,23 +116,6 @@ type Lister struct { All bool } -func traversable(ref types.ManagedObjectReference) bool { - switch ref.Type { - case "Folder": - case "Datacenter": - case "ComputeResource", "ClusterComputeResource": - // Treat ComputeResource and ClusterComputeResource as one and the same. - // It doesn't matter from the perspective of the lister. - case "HostSystem": - case "VirtualApp": - case "StoragePod": - default: - return false - } - - return true -} - func (l Lister) retrieveProperties(ctx context.Context, req types.RetrieveProperties, dst *[]interface{}) error { res, err := l.Collector.RetrieveProperties(ctx, req) if err != nil { @@ -223,6 +212,8 @@ func (l Lister) ListFolder(ctx context.Context) ([]Element, error) { // Additional basic properties. switch t { + case "Folder": + pspec.PathSet = append(pspec.PathSet, "childType") case "ComputeResource", "ClusterComputeResource": // The ComputeResource and ClusterComputeResource are dereferenced in // the ResourcePoolFlag. Make sure they always have their resourcePool @@ -284,7 +275,7 @@ func (l Lister) ListDatacenter(ctx context.Context) ([]Element, error) { if l.All { pspec.All = types.NewBool(true) } else { - pspec.PathSet = []string{"name"} + pspec.PathSet = []string{"name", "childType"} } req := types.RetrieveProperties{ diff --git a/vendor/github.com/vmware/govmomi/list/recurser.go b/vendor/github.com/vmware/govmomi/list/recurser.go deleted file mode 100644 index 4b78415b3..000000000 --- a/vendor/github.com/vmware/govmomi/list/recurser.go +++ /dev/null @@ -1,97 +0,0 @@ -/* -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 list - -import ( - "path" - "path/filepath" - - "github.com/vmware/govmomi/property" - "golang.org/x/net/context" -) - -type Recurser struct { - Collector *property.Collector - - // All configures the recurses to fetch complete objects for leaf nodes. - All bool - - // TraverseLeafs configures the Recurser to traverse traversable leaf nodes. - // This is typically set to true when used from the ls command, where listing - // a folder means listing its contents. This is typically set to false for - // commands that take managed entities that are not folders as input. - TraverseLeafs bool -} - -func (r Recurser) Recurse(ctx context.Context, root Element, parts []string) ([]Element, error) { - if len(parts) == 0 { - // Include non-traversable leaf elements in result. For example, consider - // the pattern "./vm/my-vm-*", where the pattern should match the VMs and - // not try to traverse them. - // - // Include traversable leaf elements in result, if the TraverseLeafs - // field is set to false. - // - if !traversable(root.Object.Reference()) || !r.TraverseLeafs { - return []Element{root}, nil - } - } - - k := Lister{ - Collector: r.Collector, - Reference: root.Object.Reference(), - Prefix: root.Path, - } - - if r.All && len(parts) < 2 { - k.All = true - } - - in, err := k.List(ctx) - if err != nil { - return nil, err - } - - // This folder is a leaf as far as the glob goes. - if len(parts) == 0 { - return in, nil - } - - pattern := parts[0] - parts = parts[1:] - - var out []Element - for _, e := range in { - matched, err := filepath.Match(pattern, path.Base(e.Path)) - if err != nil { - return nil, err - } - - if !matched { - continue - } - - nres, err := r.Recurse(ctx, e, parts) - if err != nil { - return nil, err - } - - out = append(out, nres...) - } - - return out, nil -} diff --git a/vendor/github.com/vmware/govmomi/object/authorization_manager.go b/vendor/github.com/vmware/govmomi/object/authorization_manager.go index 868db4f71..b703258fe 100644 --- a/vendor/github.com/vmware/govmomi/object/authorization_manager.go +++ b/vendor/github.com/vmware/govmomi/object/authorization_manager.go @@ -17,11 +17,12 @@ limitations under the License. package object 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" - "golang.org/x/net/context" ) type AuthorizationManager struct { @@ -106,3 +107,68 @@ func (m AuthorizationManager) SetEntityPermissions(ctx context.Context, entity t _, err := methods.SetEntityPermissions(ctx, m.Client(), &req) return err } + +func (m AuthorizationManager) RetrieveRolePermissions(ctx context.Context, id int32) ([]types.Permission, error) { + req := types.RetrieveRolePermissions{ + This: m.Reference(), + RoleId: id, + } + + res, err := methods.RetrieveRolePermissions(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (m AuthorizationManager) RetrieveAllPermissions(ctx context.Context) ([]types.Permission, error) { + req := types.RetrieveAllPermissions{ + This: m.Reference(), + } + + res, err := methods.RetrieveAllPermissions(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (m AuthorizationManager) AddRole(ctx context.Context, name string, ids []string) (int32, error) { + req := types.AddAuthorizationRole{ + This: m.Reference(), + Name: name, + PrivIds: ids, + } + + res, err := methods.AddAuthorizationRole(ctx, m.Client(), &req) + if err != nil { + return -1, err + } + + return res.Returnval, nil +} + +func (m AuthorizationManager) RemoveRole(ctx context.Context, id int32, failIfUsed bool) error { + req := types.RemoveAuthorizationRole{ + This: m.Reference(), + RoleId: id, + FailIfUsed: failIfUsed, + } + + _, err := methods.RemoveAuthorizationRole(ctx, m.Client(), &req) + return err +} + +func (m AuthorizationManager) UpdateRole(ctx context.Context, id int32, name string, ids []string) error { + req := types.UpdateAuthorizationRole{ + This: m.Reference(), + RoleId: id, + NewName: name, + PrivIds: ids, + } + + _, err := methods.UpdateAuthorizationRole(ctx, m.Client(), &req) + return err +} diff --git a/vendor/github.com/vmware/govmomi/object/authorization_manager_internal.go b/vendor/github.com/vmware/govmomi/object/authorization_manager_internal.go new file mode 100644 index 000000000..4fa520f5a --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/authorization_manager_internal.go @@ -0,0 +1,86 @@ +/* +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 object + +import ( + "context" + + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +type DisabledMethodRequest struct { + Method string `xml:"method"` + Reason string `xml:"reasonId"` +} + +type disableMethodsRequest struct { + This types.ManagedObjectReference `xml:"_this"` + Entity []types.ManagedObjectReference `xml:"entity"` + Method []DisabledMethodRequest `xml:"method"` + Source string `xml:"sourceId"` + Scope bool `xml:"sessionScope,omitempty"` +} + +type disableMethodsBody struct { + Req *disableMethodsRequest `xml:"urn:internalvim25 DisableMethods,omitempty"` + Res interface{} `xml:"urn:vim25 DisableMethodsResponse,omitempty"` + Err *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *disableMethodsBody) Fault() *soap.Fault { return b.Err } + +func (m AuthorizationManager) DisableMethods(ctx context.Context, entity []types.ManagedObjectReference, method []DisabledMethodRequest, source string) error { + var reqBody, resBody disableMethodsBody + + reqBody.Req = &disableMethodsRequest{ + This: m.Reference(), + Entity: entity, + Method: method, + Source: source, + } + + return m.Client().RoundTrip(ctx, &reqBody, &resBody) +} + +type enableMethodsRequest struct { + This types.ManagedObjectReference `xml:"_this"` + Entity []types.ManagedObjectReference `xml:"entity"` + Method []string `xml:"method"` + Source string `xml:"sourceId"` +} + +type enableMethodsBody struct { + Req *enableMethodsRequest `xml:"urn:internalvim25 EnableMethods,omitempty"` + Res interface{} `xml:"urn:vim25 EnableMethodsResponse,omitempty"` + Err *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *enableMethodsBody) Fault() *soap.Fault { return b.Err } + +func (m AuthorizationManager) EnableMethods(ctx context.Context, entity []types.ManagedObjectReference, method []string, source string) error { + var reqBody, resBody enableMethodsBody + + reqBody.Req = &enableMethodsRequest{ + This: m.Reference(), + Entity: entity, + Method: method, + Source: source, + } + + return m.Client().RoundTrip(ctx, &reqBody, &resBody) +} diff --git a/vendor/github.com/vmware/govmomi/object/cluster_compute_resource.go b/vendor/github.com/vmware/govmomi/object/cluster_compute_resource.go index 3cd52f705..225f41b6d 100644 --- a/vendor/github.com/vmware/govmomi/object/cluster_compute_resource.go +++ b/vendor/github.com/vmware/govmomi/object/cluster_compute_resource.go @@ -17,16 +17,15 @@ limitations under the License. package object import ( + "context" + "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type ClusterComputeResource struct { ComputeResource - - InventoryPath string } func NewClusterComputeResource(c *vim25.Client, ref types.ManagedObjectReference) *ClusterComputeResource { diff --git a/vendor/github.com/vmware/govmomi/object/common.go b/vendor/github.com/vmware/govmomi/object/common.go index 97972849f..52feeed65 100644 --- a/vendor/github.com/vmware/govmomi/object/common.go +++ b/vendor/github.com/vmware/govmomi/object/common.go @@ -17,28 +17,38 @@ limitations under the License. package object import ( + "context" "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" ) var ( - ErrNotSupported = errors.New("not supported (vCenter only)") + ErrNotSupported = errors.New("product/version specific feature not supported by target") ) // 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) } diff --git a/vendor/github.com/vmware/govmomi/object/compute_resource.go b/vendor/github.com/vmware/govmomi/object/compute_resource.go index 328c2e07c..ac1c73019 100644 --- a/vendor/github.com/vmware/govmomi/object/compute_resource.go +++ b/vendor/github.com/vmware/govmomi/object/compute_resource.go @@ -17,6 +17,7 @@ limitations under the License. package object import ( + "context" "path" "github.com/vmware/govmomi/property" @@ -24,13 +25,10 @@ import ( "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type ComputeResource struct { Common - - InventoryPath string } func NewComputeResource(c *vim25.Client, ref types.ManagedObjectReference) *ComputeResource { diff --git a/vendor/github.com/vmware/govmomi/object/custom_fields_manager.go b/vendor/github.com/vmware/govmomi/object/custom_fields_manager.go index ce9abf087..60b78df2b 100644 --- a/vendor/github.com/vmware/govmomi/object/custom_fields_manager.go +++ b/vendor/github.com/vmware/govmomi/object/custom_fields_manager.go @@ -17,6 +17,7 @@ limitations under the License. package object import ( + "context" "errors" "strconv" @@ -24,7 +25,6 @@ import ( "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) var ( diff --git a/vendor/github.com/vmware/govmomi/object/customization_spec_manager.go b/vendor/github.com/vmware/govmomi/object/customization_spec_manager.go index aebe73e84..cb8b965dc 100644 --- a/vendor/github.com/vmware/govmomi/object/customization_spec_manager.go +++ b/vendor/github.com/vmware/govmomi/object/customization_spec_manager.go @@ -17,10 +17,11 @@ limitations under the License. package object import ( + "context" + "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type CustomizationSpecManager struct { diff --git a/vendor/github.com/vmware/govmomi/object/datacenter.go b/vendor/github.com/vmware/govmomi/object/datacenter.go index fa522fb05..adddc5ffa 100644 --- a/vendor/github.com/vmware/govmomi/object/datacenter.go +++ b/vendor/github.com/vmware/govmomi/object/datacenter.go @@ -17,13 +17,13 @@ limitations under the License. package object import ( + "context" "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 DatacenterFolders struct { diff --git a/vendor/github.com/vmware/govmomi/object/datastore.go b/vendor/github.com/vmware/govmomi/object/datastore.go index 123dde8a8..fc696cdf2 100644 --- a/vendor/github.com/vmware/govmomi/object/datastore.go +++ b/vendor/github.com/vmware/govmomi/object/datastore.go @@ -20,9 +20,11 @@ import ( "fmt" "io" "math/rand" + "os" "path" "strings" + "context" "net/http" "net/url" @@ -32,7 +34,6 @@ import ( "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/soap" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) // DatastoreNoSuchDirectoryError is returned when a directory could not be found. @@ -58,7 +59,7 @@ func (e DatastoreNoSuchFileError) Error() string { type Datastore struct { Common - InventoryPath string + DatacenterPath string } func NewDatastore(c *vim25.Client, ref types.ManagedObjectReference) *Datastore { @@ -67,31 +68,15 @@ 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 == "" { - panic("expected non-empty name") - } - - return fmt.Sprintf("[%s] %s", name, path) + return (&DatastorePath{ + Datastore: d.Name(), + Path: path, + }).String() } -// URL for datastore access over HTTP -func (d Datastore) URL(ctx context.Context, dc *Datacenter, path string) (*url.URL, error) { - var mdc mo.Datacenter - if err := dc.Properties(ctx, dc.Reference(), []string{"name"}, &mdc); err != nil { - return nil, err - } - - var mds mo.Datastore - if err := d.Properties(ctx, d.Reference(), []string{"name"}, &mds); err != nil { - return nil, err - } - +// NewURL constructs a url.URL with the given file path for datastore access over HTTP. +func (d Datastore) NewURL(path string) *url.URL { u := d.c.URL() return &url.URL{ @@ -99,10 +84,15 @@ func (d Datastore) URL(ctx context.Context, dc *Datacenter, path string) (*url.U Host: u.Host, Path: fmt.Sprintf("/folder/%s", path), RawQuery: url.Values{ - "dcPath": []string{mdc.Name}, - "dsName": []string{mds.Name}, + "dcPath": []string{d.DatacenterPath}, + "dsName": []string{d.Name()}, }.Encode(), - }, nil + } +} + +// URL is deprecated, use NewURL instead. +func (d Datastore) URL(ctx context.Context, dc *Datacenter, path string) (*url.URL, error) { + return d.NewURL(path), nil } func (d Datastore) Browser(ctx context.Context) (*HostDatastoreBrowser, error) { @@ -116,39 +106,119 @@ func (d Datastore) Browser(ctx context.Context) (*HostDatastoreBrowser, error) { return NewHostDatastoreBrowser(d.c, do.Browser), nil } +func (d Datastore) useServiceTicket() bool { + // If connected to workstation, service ticketing not supported + // If connected to ESX, service ticketing not needed + if !d.c.IsVC() { + return false + } + + key := "GOVMOMI_USE_SERVICE_TICKET" + + val := d.c.URL().Query().Get(key) + if val == "" { + val = os.Getenv(key) + } + + if val == "1" || val == "true" { + return true + } + + return false +} + +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 +} + +type datastoreServiceTicketHostKey struct{} + +// HostContext returns a Context where the given host will be used for datastore HTTP access +// via the ServiceTicket method. +func (d Datastore) HostContext(ctx context.Context, host *HostSystem) context.Context { + return context.WithValue(ctx, datastoreServiceTicketHostKey{}, host) +} + // 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. +// that can be used along with the ticket cookie to access the given path. An host is chosen at random unless the +// the given Context was created with a specific host via the HostContext method. func (d Datastore) ServiceTicket(ctx context.Context, path string, method string) (*url.URL, *http.Cookie, error) { - // We are uploading to an ESX host - u := &url.URL{ - Scheme: d.c.URL().Scheme, - Host: d.c.URL().Host, - Path: fmt.Sprintf("/folder/%s", path), - RawQuery: url.Values{ - "dsName": []string{d.Name()}, - }.Encode(), - } + u := d.NewURL(path) + + host, ok := ctx.Value(datastoreServiceTicketHostKey{}).(*HostSystem) + + if !ok { + if !d.useServiceTicket() { + return u, nil, nil + } - // If connected to VC, the ticket request must be for an ESX host. - if d.c.IsVC() { hosts, err := d.AttachedHosts(ctx) if err != nil { return nil, nil, err } if len(hosts) == 0 { - return nil, nil, fmt.Errorf("no hosts attached to datastore %#v", d.Reference()) + // Fallback to letting vCenter choose a host + return u, nil, nil } // Pick a random attached host - host := hosts[rand.Intn(len(hosts))] - name, err := host.Name(ctx) + host = hosts[rand.Intn(len(hosts))] + } + + ips, err := host.ManagementIPs(ctx) + if err != nil { + return nil, nil, err + } + + if len(ips) > 0 { + // prefer a ManagementIP + u.Host = ips[0].String() + } else { + // fallback to inventory name + u.Host, err = host.ObjectName(ctx) if err != nil { return nil, nil, err } - u.Host = name } + // VC datacenter path will not be valid against ESX + q := u.Query() + delete(q, "dcPath") + u.RawQuery = q.Encode() + spec := types.SessionManagerHttpServiceRequestSpec{ Url: u.String(), // See SessionManagerHttpServiceRequestSpecMethod enum @@ -167,6 +237,12 @@ func (d Datastore) ServiceTicket(ctx context.Context, path string, method string Value: ticket.Id, } + if d.useServiceTicketHostName(ticket.HostName) { + u.Host = ticket.HostName + } + + d.Client().SetThumbprint(u.Host, ticket.SslThumbprint) + return u, cookie, nil } @@ -278,7 +354,7 @@ func (d Datastore) AttachedHosts(ctx context.Context) ([]*HostSystem, error) { return hosts, nil } -// AttachedHosts returns hosts that have this Datastore attached, accessible and writable and are members of the given cluster. +// AttachedClusterHosts returns hosts that have this Datastore attached, accessible and writable and are members of the given cluster. func (d Datastore) AttachedClusterHosts(ctx context.Context, cluster *ComputeResource) ([]*HostSystem, error) { var hosts []*HostSystem @@ -323,12 +399,12 @@ func (d Datastore) Stat(ctx context.Context, file string) (types.BaseFileInfo, e } dsPath := d.Path(path.Dir(file)) - task, err := b.SearchDatastore(context.TODO(), dsPath, &spec) + task, err := b.SearchDatastore(ctx, dsPath, &spec) if err != nil { return nil, err } - info, err := task.WaitForResult(context.TODO(), nil) + info, err := task.WaitForResult(ctx, nil) if err != nil { if info == nil || info.Error != nil { _, ok := info.Error.Fault.(*types.FileNotFound) diff --git a/vendor/github.com/vmware/govmomi/object/datastore_file.go b/vendor/github.com/vmware/govmomi/object/datastore_file.go new file mode 100644 index 000000000..d4813a756 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/datastore_file.go @@ -0,0 +1,408 @@ +/* +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 object + +import ( + "bytes" + "context" + "errors" + "fmt" + "io" + "net/http" + "os" + "path" + "time" + + "github.com/vmware/govmomi/vim25/soap" +) + +// DatastoreFile implements io.Reader, io.Seeker and io.Closer interfaces for datastore file access. +type DatastoreFile struct { + d Datastore + ctx context.Context + name string + + buf io.Reader + body io.ReadCloser + length int64 + offset struct { + read, seek int64 + } +} + +// Open opens the named file relative to the Datastore. +func (d Datastore) Open(ctx context.Context, name string) (*DatastoreFile, error) { + return &DatastoreFile{ + d: d, + name: name, + length: -1, + ctx: ctx, + }, nil +} + +// Read reads up to len(b) bytes from the DatastoreFile. +func (f *DatastoreFile) Read(b []byte) (int, error) { + if f.offset.read != f.offset.seek { + // A Seek() call changed the offset, we need to issue a new GET + _ = f.Close() + + f.offset.read = f.offset.seek + } else if f.buf != nil { + // f.buf + f behaves like an io.MultiReader + n, err := f.buf.Read(b) + if err == io.EOF { + f.buf = nil // buffer has been drained + } + if n > 0 { + return n, nil + } + } + + body, err := f.get() + if err != nil { + return 0, err + } + + n, err := body.Read(b) + + f.offset.read += int64(n) + f.offset.seek += int64(n) + + return n, err +} + +// Close closes the DatastoreFile. +func (f *DatastoreFile) Close() error { + var err error + + if f.body != nil { + err = f.body.Close() + f.body = nil + } + + f.buf = nil + + return err +} + +// Seek sets the offset for the next Read on the DatastoreFile. +func (f *DatastoreFile) Seek(offset int64, whence int) (int64, error) { + switch whence { + case io.SeekStart: + case io.SeekCurrent: + offset += f.offset.seek + case io.SeekEnd: + if f.length < 0 { + _, err := f.Stat() + if err != nil { + return 0, err + } + } + offset += f.length + default: + return 0, errors.New("Seek: invalid whence") + } + + // allow negative SeekStart for initial Range request + if offset < 0 { + return 0, errors.New("Seek: invalid offset") + } + + f.offset.seek = offset + + return offset, nil +} + +type fileStat struct { + file *DatastoreFile + header http.Header +} + +func (s *fileStat) Name() string { + return path.Base(s.file.name) +} + +func (s *fileStat) Size() int64 { + return s.file.length +} + +func (s *fileStat) Mode() os.FileMode { + return 0 +} + +func (s *fileStat) ModTime() time.Time { + return time.Now() // no Last-Modified +} + +func (s *fileStat) IsDir() bool { + return false +} + +func (s *fileStat) Sys() interface{} { + return s.header +} + +func statusError(res *http.Response) error { + if res.StatusCode == http.StatusNotFound { + return os.ErrNotExist + } + return errors.New(res.Status) +} + +// Stat returns the os.FileInfo interface describing file. +func (f *DatastoreFile) Stat() (os.FileInfo, error) { + // TODO: consider using Datastore.Stat() instead + u, p, err := f.d.downloadTicket(f.ctx, f.name, &soap.Download{Method: "HEAD"}) + if err != nil { + return nil, err + } + + res, err := f.d.Client().DownloadRequest(u, p) + if err != nil { + return nil, err + } + + if res.StatusCode != http.StatusOK { + return nil, statusError(res) + } + + f.length = res.ContentLength + + return &fileStat{f, res.Header}, nil +} + +func (f *DatastoreFile) get() (io.Reader, error) { + if f.body != nil { + return f.body, nil + } + + u, p, err := f.d.downloadTicket(f.ctx, f.name, nil) + if err != nil { + return nil, err + } + + if f.offset.read != 0 { + p.Headers = map[string]string{ + "Range": fmt.Sprintf("bytes=%d-", f.offset.read), + } + } + + res, err := f.d.Client().DownloadRequest(u, p) + if err != nil { + return nil, err + } + + switch res.StatusCode { + case http.StatusOK: + f.length = res.ContentLength + case http.StatusPartialContent: + var start, end int + cr := res.Header.Get("Content-Range") + _, err = fmt.Sscanf(cr, "bytes %d-%d/%d", &start, &end, &f.length) + if err != nil { + f.length = -1 + } + case http.StatusRequestedRangeNotSatisfiable: + // ok: Read() will return io.EOF + default: + return nil, statusError(res) + } + + if f.length < 0 { + _ = res.Body.Close() + return nil, errors.New("unable to determine file size") + } + + f.body = res.Body + + return f.body, nil +} + +func lastIndexLines(s []byte, line *int, include func(l int, m string) bool) (int64, bool) { + i := len(s) - 1 + done := false + + for i > 0 { + o := bytes.LastIndexByte(s[:i], '\n') + if o < 0 { + break + } + + msg := string(s[o+1 : i+1]) + if !include(*line, msg) { + done = true + break + } else { + i = o + *line++ + } + } + + return int64(i), done +} + +// Tail seeks to the position of the last N lines of the file. +func (f *DatastoreFile) Tail(n int) error { + return f.TailFunc(n, func(line int, _ string) bool { return n > line }) +} + +// TailFunc will seek backwards in the datastore file until it hits a line that does +// not satisfy the supplied `include` function. +func (f *DatastoreFile) TailFunc(lines int, include func(line int, message string) bool) error { + // Read the file in reverse using bsize chunks + const bsize = int64(1024 * 16) + + fsize, err := f.Seek(0, io.SeekEnd) + if err != nil { + return err + } + + if lines == 0 { + return nil + } + + chunk := int64(-1) + + buf := bytes.NewBuffer(make([]byte, 0, bsize)) + line := 0 + + for { + var eof bool + var pos int64 + + nread := bsize + + offset := chunk * bsize + remain := fsize + offset + + if remain < 0 { + if pos, err = f.Seek(0, io.SeekStart); err != nil { + return err + } + + nread = bsize + remain + eof = true + } else { + if pos, err = f.Seek(offset, io.SeekEnd); err != nil { + return err + } + } + + if _, err = io.CopyN(buf, f, nread); err != nil { + if err != io.EOF { + return err + } + } + + b := buf.Bytes() + idx, done := lastIndexLines(b, &line, include) + + if done { + if chunk == -1 { + // We found all N lines in the last chunk of the file. + // The seek offset is also now at the current end of file. + // Save this buffer to avoid another GET request when Read() is called. + buf.Next(int(idx + 1)) + f.buf = buf + return nil + } + + if _, err = f.Seek(pos+idx+1, io.SeekStart); err != nil { + return err + } + + break + } + + if eof { + if remain < 0 { + // We found < N lines in the entire file, so seek to the start. + _, _ = f.Seek(0, io.SeekStart) + } + break + } + + chunk-- + buf.Reset() + } + + return nil +} + +type followDatastoreFile struct { + r *DatastoreFile + c chan struct{} + i time.Duration +} + +// Read reads up to len(b) bytes from the DatastoreFile being followed. +// This method will block until data is read, an error other than io.EOF is returned or Close() is called. +func (f *followDatastoreFile) Read(p []byte) (int, error) { + offset := f.r.offset.seek + stop := false + + for { + n, err := f.r.Read(p) + if err != nil && err == io.EOF { + _ = f.r.Close() // GET request body has been drained. + if stop { + return n, err + } + err = nil + } + + if n > 0 { + return n, err + } + + select { + case <-f.c: + // Wake up and stop polling once the body has been drained + stop = true + case <-time.After(f.i): + } + + info, serr := f.r.Stat() + if serr != nil { + // Return EOF rather than 404 if the file goes away + if serr == os.ErrNotExist { + _ = f.r.Close() + return 0, io.EOF + } + return 0, serr + } + + if info.Size() < offset { + // assume file has be truncated + offset, err = f.r.Seek(0, io.SeekStart) + if err != nil { + return 0, err + } + } + } +} + +// Close will stop Follow polling and close the underlying DatastoreFile. +func (f *followDatastoreFile) Close() error { + close(f.c) + return nil +} + +// Follow returns an io.ReadCloser to stream the file contents as data is appended. +func (f *DatastoreFile) Follow(interval time.Duration) io.ReadCloser { + return &followDatastoreFile{f, make(chan struct{}), interval} +} diff --git a/vendor/github.com/vmware/govmomi/object/datastore_file_manager.go b/vendor/github.com/vmware/govmomi/object/datastore_file_manager.go new file mode 100644 index 000000000..7164fbbed --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/datastore_file_manager.go @@ -0,0 +1,145 @@ +/* +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 object + +import ( + "bufio" + "bytes" + "context" + "fmt" + "io" + "log" + "path" + "strings" + + "github.com/vmware/govmomi/vim25/soap" +) + +// DatastoreFileManager combines FileManager and VirtualDiskManager to manage files on a Datastore +type DatastoreFileManager struct { + Datacenter *Datacenter + Datastore *Datastore + FileManager *FileManager + VirtualDiskManager *VirtualDiskManager + + Force bool +} + +// NewFileManager creates a new instance of DatastoreFileManager +func (d Datastore) NewFileManager(dc *Datacenter, force bool) *DatastoreFileManager { + c := d.Client() + + m := &DatastoreFileManager{ + Datacenter: dc, + Datastore: &d, + FileManager: NewFileManager(c), + VirtualDiskManager: NewVirtualDiskManager(c), + Force: force, + } + + return m +} + +// Delete dispatches to the appropriate Delete method based on file name extension +func (m *DatastoreFileManager) Delete(ctx context.Context, name string) error { + switch path.Ext(name) { + case ".vmdk": + return m.DeleteVirtualDisk(ctx, name) + default: + return m.DeleteFile(ctx, name) + } +} + +// DeleteFile calls FileManager.DeleteDatastoreFile +func (m *DatastoreFileManager) DeleteFile(ctx context.Context, name string) error { + p := m.Path(name) + + task, err := m.FileManager.DeleteDatastoreFile(ctx, p.String(), m.Datacenter) + if err != nil { + return err + } + + return task.Wait(ctx) +} + +// DeleteVirtualDisk calls VirtualDiskManager.DeleteVirtualDisk +// Regardless of the Datastore type, DeleteVirtualDisk will fail if 'ddb.deletable=false', +// so if Force=true this method attempts to set 'ddb.deletable=true' before starting the delete task. +func (m *DatastoreFileManager) DeleteVirtualDisk(ctx context.Context, name string) error { + p := m.Path(name) + + var merr error + + if m.Force { + merr = m.markDiskAsDeletable(ctx, p) + } + + task, err := m.VirtualDiskManager.DeleteVirtualDisk(ctx, p.String(), m.Datacenter) + if err != nil { + log.Printf("markDiskAsDeletable(%s): %s", p, merr) + return err + } + + return task.Wait(ctx) +} + +// Path converts path name to a DatastorePath +func (m *DatastoreFileManager) Path(name string) *DatastorePath { + var p DatastorePath + + if !p.FromString(name) { + p.Path = name + p.Datastore = m.Datastore.Name() + } + + return &p +} + +func (m *DatastoreFileManager) markDiskAsDeletable(ctx context.Context, path *DatastorePath) error { + r, _, err := m.Datastore.Download(ctx, path.Path, &soap.DefaultDownload) + if err != nil { + return err + } + + defer r.Close() + + hasFlag := false + buf := new(bytes.Buffer) + + s := bufio.NewScanner(&io.LimitedReader{R: r, N: 2048}) // should be only a few hundred bytes, limit to be sure + + for s.Scan() { + line := s.Text() + if strings.HasPrefix(line, "ddb.deletable") { + hasFlag = true + continue + } + + fmt.Fprintln(buf, line) + } + + if err := s.Err(); err != nil { + return err // any error other than EOF + } + + if !hasFlag { + return nil // already deletable, so leave as-is + } + + // rewrite the .vmdk with ddb.deletable flag removed (the default is true) + return m.Datastore.Upload(ctx, buf, path.Path, &soap.DefaultUpload) +} diff --git a/vendor/github.com/vmware/govmomi/object/datastore_path.go b/vendor/github.com/vmware/govmomi/object/datastore_path.go new file mode 100644 index 000000000..ea152103d --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/datastore_path.go @@ -0,0 +1,65 @@ +/* +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 ( + "fmt" + "strings" +) + +// DatastorePath contains the components of a datastore path. +type DatastorePath struct { + Datastore string + Path string +} + +// FromString parses a datastore path. +// Returns true if the path could be parsed, false otherwise. +func (p *DatastorePath) FromString(s string) bool { + if len(s) == 0 { + return false + } + + s = strings.TrimSpace(s) + + if !strings.HasPrefix(s, "[") { + return false + } + + s = s[1:] + + ix := strings.Index(s, "]") + if ix < 0 { + return false + } + + p.Datastore = s[:ix] + p.Path = strings.TrimSpace(s[ix+1:]) + + return true +} + +// String formats a datastore path. +func (p *DatastorePath) String() string { + s := fmt.Sprintf("[%s]", p.Datastore) + + if p.Path == "" { + return s + } + + return strings.Join([]string{s, p.Path}, " ") +} diff --git a/vendor/github.com/vmware/govmomi/object/diagnostic_log.go b/vendor/github.com/vmware/govmomi/object/diagnostic_log.go new file mode 100644 index 000000000..466d0ee91 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/diagnostic_log.go @@ -0,0 +1,76 @@ +/* +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 ( + "context" + "fmt" + "io" + "math" +) + +// DiagnosticLog wraps DiagnosticManager.BrowseLog +type DiagnosticLog struct { + m DiagnosticManager + + Key string + Host *HostSystem + + Start int32 +} + +// Seek to log position starting at the last nlines of the log +func (l *DiagnosticLog) Seek(ctx context.Context, nlines int32) error { + h, err := l.m.BrowseLog(ctx, l.Host, l.Key, math.MaxInt32, 0) + if err != nil { + return err + } + + l.Start = h.LineEnd - nlines + + return nil +} + +// Copy log starting from l.Start to the given io.Writer +// Returns on error or when end of log is reached. +func (l *DiagnosticLog) Copy(ctx context.Context, w io.Writer) (int, error) { + const max = 500 // VC max == 500, ESX max == 1000 + written := 0 + + for { + h, err := l.m.BrowseLog(ctx, l.Host, l.Key, l.Start, max) + if err != nil { + return 0, err + } + + for _, line := range h.LineText { + n, err := fmt.Fprintln(w, line) + written += n + if err != nil { + return written, err + } + } + + l.Start += int32(len(h.LineText)) + + if l.Start >= h.LineEnd { + break + } + } + + return written, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/diagnostic_manager.go b/vendor/github.com/vmware/govmomi/object/diagnostic_manager.go index 2a4cf1b8f..5baf1ad90 100644 --- a/vendor/github.com/vmware/govmomi/object/diagnostic_manager.go +++ b/vendor/github.com/vmware/govmomi/object/diagnostic_manager.go @@ -17,10 +17,11 @@ limitations under the License. package object import ( + "context" + "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type DiagnosticManager struct { @@ -35,6 +36,14 @@ func NewDiagnosticManager(c *vim25.Client) *DiagnosticManager { return &m } +func (m DiagnosticManager) Log(ctx context.Context, host *HostSystem, key string) *DiagnosticLog { + return &DiagnosticLog{ + m: m, + Key: key, + Host: host, + } +} + func (m DiagnosticManager) BrowseLog(ctx context.Context, host *HostSystem, key string, start, lines int32) (*types.DiagnosticManagerLogHeader, error) { req := types.BrowseDiagnosticLog{ This: m.Reference(), diff --git a/vendor/github.com/vmware/govmomi/object/distributed_virtual_portgroup.go b/vendor/github.com/vmware/govmomi/object/distributed_virtual_portgroup.go index 0dbd4b589..864bb783f 100644 --- a/vendor/github.com/vmware/govmomi/object/distributed_virtual_portgroup.go +++ b/vendor/github.com/vmware/govmomi/object/distributed_virtual_portgroup.go @@ -17,18 +17,16 @@ limitations under the License. package object import ( - "path" + "context" "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 DistributedVirtualPortgroup struct { Common - - InventoryPath string } func NewDistributedVirtualPortgroup(c *vim25.Client, ref types.ManagedObjectReference) *DistributedVirtualPortgroup { @@ -36,9 +34,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) { @@ -62,3 +57,17 @@ func (p DistributedVirtualPortgroup) EthernetCardBackingInfo(ctx context.Context return backing, nil } + +func (p DistributedVirtualPortgroup) Reconfigure(ctx context.Context, spec types.DVPortgroupConfigSpec) (*Task, error) { + req := types.ReconfigureDVPortgroup_Task{ + This: p.Reference(), + Spec: spec, + } + + res, err := methods.ReconfigureDVPortgroup_Task(ctx, p.Client(), &req) + if err != nil { + return nil, err + } + + return NewTask(p.Client(), res.Returnval), nil +} diff --git a/vendor/github.com/vmware/govmomi/object/distributed_virtual_switch.go b/vendor/github.com/vmware/govmomi/object/distributed_virtual_switch.go index f2fb0abee..29ee52d95 100644 --- a/vendor/github.com/vmware/govmomi/object/distributed_virtual_switch.go +++ b/vendor/github.com/vmware/govmomi/object/distributed_virtual_switch.go @@ -17,16 +17,15 @@ limitations under the License. package object import ( + "context" + "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type DistributedVirtualSwitch struct { Common - - InventoryPath string } func NewDistributedVirtualSwitch(c *vim25.Client, ref types.ManagedObjectReference) *DistributedVirtualSwitch { diff --git a/vendor/github.com/vmware/govmomi/object/extension_manager.go b/vendor/github.com/vmware/govmomi/object/extension_manager.go index b7ce77c5c..94ade017c 100644 --- a/vendor/github.com/vmware/govmomi/object/extension_manager.go +++ b/vendor/github.com/vmware/govmomi/object/extension_manager.go @@ -17,11 +17,12 @@ limitations under the License. package object 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" - "golang.org/x/net/context" ) type ExtensionManager struct { diff --git a/vendor/github.com/vmware/govmomi/object/file_manager.go b/vendor/github.com/vmware/govmomi/object/file_manager.go index 716472826..ba947be20 100644 --- a/vendor/github.com/vmware/govmomi/object/file_manager.go +++ b/vendor/github.com/vmware/govmomi/object/file_manager.go @@ -17,10 +17,11 @@ limitations under the License. package object import ( + "context" + "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type FileManager struct { diff --git a/vendor/github.com/vmware/govmomi/object/folder.go b/vendor/github.com/vmware/govmomi/object/folder.go index 97c793470..7a69949f9 100644 --- a/vendor/github.com/vmware/govmomi/object/folder.go +++ b/vendor/github.com/vmware/govmomi/object/folder.go @@ -17,17 +17,16 @@ limitations under the License. package object 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" - "golang.org/x/net/context" ) type Folder struct { Common - - InventoryPath string } func NewFolder(c *vim25.Client, ref types.ManagedObjectReference) *Folder { @@ -113,6 +112,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(), diff --git a/vendor/github.com/vmware/govmomi/object/history_collector.go b/vendor/github.com/vmware/govmomi/object/history_collector.go index 9d9ef4c91..afdcab78b 100644 --- a/vendor/github.com/vmware/govmomi/object/history_collector.go +++ b/vendor/github.com/vmware/govmomi/object/history_collector.go @@ -17,10 +17,11 @@ limitations under the License. package object import ( + "context" + "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type HistoryCollector struct { diff --git a/vendor/github.com/vmware/govmomi/object/host_account_manager.go b/vendor/github.com/vmware/govmomi/object/host_account_manager.go index 9505f508c..640aff860 100644 --- a/vendor/github.com/vmware/govmomi/object/host_account_manager.go +++ b/vendor/github.com/vmware/govmomi/object/host_account_manager.go @@ -17,10 +17,11 @@ limitations under the License. package object import ( + "context" + "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type HostAccountManager struct { diff --git a/vendor/github.com/vmware/govmomi/object/host_certificate_info.go b/vendor/github.com/vmware/govmomi/object/host_certificate_info.go new file mode 100644 index 000000000..52c26a9dd --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_certificate_info.go @@ -0,0 +1,250 @@ +/* +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 ( + "crypto/sha256" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" + "fmt" + "io" + "net/url" + "strings" + "text/tabwriter" + + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +// HostCertificateInfo provides helpers for types.HostCertificateManagerCertificateInfo +type HostCertificateInfo struct { + types.HostCertificateManagerCertificateInfo + + ThumbprintSHA1 string + ThumbprintSHA256 string + + Err error + Certificate *x509.Certificate `json:"-"` + + subjectName *pkix.Name + issuerName *pkix.Name +} + +// FromCertificate converts x509.Certificate to HostCertificateInfo +func (info *HostCertificateInfo) FromCertificate(cert *x509.Certificate) *HostCertificateInfo { + info.Certificate = cert + info.subjectName = &cert.Subject + info.issuerName = &cert.Issuer + + info.Issuer = info.fromName(info.issuerName) + info.NotBefore = &cert.NotBefore + info.NotAfter = &cert.NotAfter + info.Subject = info.fromName(info.subjectName) + + info.ThumbprintSHA1 = soap.ThumbprintSHA1(cert) + + // SHA-256 for info purposes only, API fields all use SHA-1 + sum := sha256.Sum256(cert.Raw) + hex := make([]string, len(sum)) + for i, b := range sum { + hex[i] = fmt.Sprintf("%02X", b) + } + info.ThumbprintSHA256 = strings.Join(hex, ":") + + if info.Status == "" { + info.Status = string(types.HostCertificateManagerCertificateInfoCertificateStatusUnknown) + } + + return info +} + +// FromURL connects to the given URL.Host via tls.Dial with the given tls.Config and populates the HostCertificateInfo +// via tls.ConnectionState. If the certificate was verified with the given tls.Config, the Err field will be nil. +// Otherwise, Err will be set to the x509.UnknownAuthorityError or x509.HostnameError. +// If tls.Dial returns an error of any other type, that error is returned. +func (info *HostCertificateInfo) FromURL(u *url.URL, config *tls.Config) error { + addr := u.Host + if !(strings.LastIndex(addr, ":") > strings.LastIndex(addr, "]")) { + addr += ":443" + } + + conn, err := tls.Dial("tcp", addr, config) + if err != nil { + switch err.(type) { + case x509.UnknownAuthorityError: + case x509.HostnameError: + default: + return err + } + + info.Err = err + + conn, err = tls.Dial("tcp", addr, &tls.Config{InsecureSkipVerify: true}) + if err != nil { + return err + } + } else { + info.Status = string(types.HostCertificateManagerCertificateInfoCertificateStatusGood) + } + + state := conn.ConnectionState() + _ = conn.Close() + info.FromCertificate(state.PeerCertificates[0]) + + return nil +} + +var emailAddressOID = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1} + +func (info *HostCertificateInfo) fromName(name *pkix.Name) string { + var attrs []string + + oids := map[string]string{ + emailAddressOID.String(): "emailAddress", + } + + for _, attr := range name.Names { + if key, ok := oids[attr.Type.String()]; ok { + attrs = append(attrs, fmt.Sprintf("%s=%s", key, attr.Value)) + } + } + + attrs = append(attrs, fmt.Sprintf("CN=%s", name.CommonName)) + + add := func(key string, vals []string) { + for _, val := range vals { + attrs = append(attrs, fmt.Sprintf("%s=%s", key, val)) + } + } + + elts := []struct { + key string + val []string + }{ + {"OU", name.OrganizationalUnit}, + {"O", name.Organization}, + {"L", name.Locality}, + {"ST", name.Province}, + {"C", name.Country}, + } + + for _, elt := range elts { + add(elt.key, elt.val) + } + + return strings.Join(attrs, ",") +} + +func (info *HostCertificateInfo) toName(s string) *pkix.Name { + var name pkix.Name + + for _, pair := range strings.Split(s, ",") { + attr := strings.SplitN(pair, "=", 2) + if len(attr) != 2 { + continue + } + + v := attr[1] + + switch strings.ToLower(attr[0]) { + case "cn": + name.CommonName = v + case "ou": + name.OrganizationalUnit = append(name.OrganizationalUnit, v) + case "o": + name.Organization = append(name.Organization, v) + case "l": + name.Locality = append(name.Locality, v) + case "st": + name.Province = append(name.Province, v) + case "c": + name.Country = append(name.Country, v) + case "emailaddress": + name.Names = append(name.Names, pkix.AttributeTypeAndValue{Type: emailAddressOID, Value: v}) + } + } + + return &name +} + +// SubjectName parses Subject into a pkix.Name +func (info *HostCertificateInfo) SubjectName() *pkix.Name { + if info.subjectName != nil { + return info.subjectName + } + + return info.toName(info.Subject) +} + +// IssuerName parses Issuer into a pkix.Name +func (info *HostCertificateInfo) IssuerName() *pkix.Name { + if info.issuerName != nil { + return info.issuerName + } + + return info.toName(info.Issuer) +} + +// Write outputs info similar to the Chrome Certificate Viewer. +func (info *HostCertificateInfo) Write(w io.Writer) error { + tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0) + + s := func(val string) string { + if val != "" { + return val + } + return "" + } + + ss := func(val []string) string { + return s(strings.Join(val, ",")) + } + + name := func(n *pkix.Name) { + fmt.Fprintf(tw, " Common Name (CN):\t%s\n", s(n.CommonName)) + fmt.Fprintf(tw, " Organization (O):\t%s\n", ss(n.Organization)) + fmt.Fprintf(tw, " Organizational Unit (OU):\t%s\n", ss(n.OrganizationalUnit)) + } + + status := info.Status + if info.Err != nil { + status = fmt.Sprintf("ERROR %s", info.Err) + } + fmt.Fprintf(tw, "Certificate Status:\t%s\n", status) + + fmt.Fprintln(tw, "Issued To:\t") + name(info.SubjectName()) + + fmt.Fprintln(tw, "Issued By:\t") + name(info.IssuerName()) + + fmt.Fprintln(tw, "Validity Period:\t") + fmt.Fprintf(tw, " Issued On:\t%s\n", info.NotBefore) + fmt.Fprintf(tw, " Expires On:\t%s\n", info.NotAfter) + + if info.ThumbprintSHA1 != "" { + fmt.Fprintln(tw, "Thumbprints:\t") + if info.ThumbprintSHA256 != "" { + fmt.Fprintf(tw, " SHA-256 Thumbprint:\t%s\n", info.ThumbprintSHA256) + } + fmt.Fprintf(tw, " SHA-1 Thumbprint:\t%s\n", info.ThumbprintSHA1) + } + + return tw.Flush() +} diff --git a/vendor/github.com/vmware/govmomi/object/host_certificate_manager.go b/vendor/github.com/vmware/govmomi/object/host_certificate_manager.go new file mode 100644 index 000000000..2875a9fc1 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_certificate_manager.go @@ -0,0 +1,162 @@ +/* +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 ( + "context" + + "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" +) + +// HostCertificateManager provides helper methods around the HostSystem.ConfigManager.CertificateManager +type HostCertificateManager struct { + Common + Host *HostSystem +} + +// NewHostCertificateManager creates a new HostCertificateManager helper +func NewHostCertificateManager(c *vim25.Client, ref types.ManagedObjectReference, host types.ManagedObjectReference) *HostCertificateManager { + return &HostCertificateManager{ + Common: NewCommon(c, ref), + Host: NewHostSystem(c, host), + } +} + +// CertificateInfo wraps the host CertificateManager certificateInfo property with the HostCertificateInfo helper. +// The ThumbprintSHA1 field is set to HostSystem.Summary.Config.SslThumbprint if the host system is managed by a vCenter. +func (m HostCertificateManager) CertificateInfo(ctx context.Context) (*HostCertificateInfo, error) { + var hs mo.HostSystem + var cm mo.HostCertificateManager + + pc := property.DefaultCollector(m.Client()) + + err := pc.RetrieveOne(ctx, m.Reference(), []string{"certificateInfo"}, &cm) + if err != nil { + return nil, err + } + + _ = pc.RetrieveOne(ctx, m.Host.Reference(), []string{"summary.config.sslThumbprint"}, &hs) + + return &HostCertificateInfo{ + HostCertificateManagerCertificateInfo: cm.CertificateInfo, + ThumbprintSHA1: hs.Summary.Config.SslThumbprint, + }, nil +} + +// GenerateCertificateSigningRequest requests the host system to generate a certificate-signing request (CSR) for itself. +// The CSR is then typically provided to a Certificate Authority to sign and issue the SSL certificate for the host system. +// Use InstallServerCertificate to import this certificate. +func (m HostCertificateManager) GenerateCertificateSigningRequest(ctx context.Context, useIPAddressAsCommonName bool) (string, error) { + req := types.GenerateCertificateSigningRequest{ + This: m.Reference(), + UseIpAddressAsCommonName: useIPAddressAsCommonName, + } + + res, err := methods.GenerateCertificateSigningRequest(ctx, m.Client(), &req) + if err != nil { + return "", err + } + + return res.Returnval, nil +} + +// GenerateCertificateSigningRequestByDn requests the host system to generate a certificate-signing request (CSR) for itself. +// Alternative version similar to GenerateCertificateSigningRequest but takes a Distinguished Name (DN) as a parameter. +func (m HostCertificateManager) GenerateCertificateSigningRequestByDn(ctx context.Context, distinguishedName string) (string, error) { + req := types.GenerateCertificateSigningRequestByDn{ + This: m.Reference(), + DistinguishedName: distinguishedName, + } + + res, err := methods.GenerateCertificateSigningRequestByDn(ctx, m.Client(), &req) + if err != nil { + return "", err + } + + return res.Returnval, nil +} + +// InstallServerCertificate imports the given SSL certificate to the host system. +func (m HostCertificateManager) InstallServerCertificate(ctx context.Context, cert string) error { + req := types.InstallServerCertificate{ + This: m.Reference(), + Cert: cert, + } + + _, err := methods.InstallServerCertificate(ctx, m.Client(), &req) + if err != nil { + return err + } + + // NotifyAffectedService is internal, not exposing as we don't have a use case other than with InstallServerCertificate + // Without this call, hostd needs to be restarted to use the updated certificate + // Note: using Refresh as it has the same struct/signature, we just need to use different xml name tags + body := struct { + Req *types.Refresh `xml:"urn:vim25 NotifyAffectedServices,omitempty"` + Res *types.RefreshResponse `xml:"urn:vim25 NotifyAffectedServicesResponse,omitempty"` + methods.RefreshBody + }{ + Req: &types.Refresh{This: m.Reference()}, + } + + return m.Client().RoundTrip(ctx, &body, &body) +} + +// ListCACertificateRevocationLists returns the SSL CRLs of Certificate Authorities that are trusted by the host system. +func (m HostCertificateManager) ListCACertificateRevocationLists(ctx context.Context) ([]string, error) { + req := types.ListCACertificateRevocationLists{ + This: m.Reference(), + } + + res, err := methods.ListCACertificateRevocationLists(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +// ListCACertificates returns the SSL certificates of Certificate Authorities that are trusted by the host system. +func (m HostCertificateManager) ListCACertificates(ctx context.Context) ([]string, error) { + req := types.ListCACertificates{ + This: m.Reference(), + } + + res, err := methods.ListCACertificates(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +// ReplaceCACertificatesAndCRLs replaces the trusted CA certificates and CRL used by the host system. +// These determine whether the server can verify the identity of an external entity. +func (m HostCertificateManager) ReplaceCACertificatesAndCRLs(ctx context.Context, caCert []string, caCrl []string) error { + req := types.ReplaceCACertificatesAndCRLs{ + This: m.Reference(), + CaCert: caCert, + CaCrl: caCrl, + } + + _, err := methods.ReplaceCACertificatesAndCRLs(ctx, m.Client(), &req) + return err +} diff --git a/vendor/github.com/vmware/govmomi/object/host_config_manager.go b/vendor/github.com/vmware/govmomi/object/host_config_manager.go index 12327ee0f..123227ecc 100644 --- a/vendor/github.com/vmware/govmomi/object/host_config_manager.go +++ b/vendor/github.com/vmware/govmomi/object/host_config_manager.go @@ -17,10 +17,11 @@ limitations under the License. package object import ( + "context" + "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type HostConfigManager struct { @@ -96,9 +97,30 @@ func (m HostConfigManager) VsanSystem(ctx context.Context) (*HostVsanSystem, err return nil, err } + // Added in 5.5 + if h.ConfigManager.VsanSystem == nil { + return nil, ErrNotSupported + } + return NewHostVsanSystem(m.c, *h.ConfigManager.VsanSystem), nil } +func (m HostConfigManager) VsanInternalSystem(ctx context.Context) (*HostVsanInternalSystem, error) { + var h mo.HostSystem + + err := m.Properties(ctx, m.Reference(), []string{"configManager.vsanInternalSystem"}, &h) + if err != nil { + return nil, err + } + + // Added in 5.5 + if h.ConfigManager.VsanInternalSystem == nil { + return nil, ErrNotSupported + } + + return NewHostVsanInternalSystem(m.c, *h.ConfigManager.VsanInternalSystem), nil +} + func (m HostConfigManager) AccountManager(ctx context.Context) (*HostAccountManager, error) { var h mo.HostSystem @@ -107,7 +129,21 @@ func (m HostConfigManager) AccountManager(ctx context.Context) (*HostAccountMana return nil, err } - return NewHostAccountManager(m.c, *h.ConfigManager.AccountManager), nil + ref := h.ConfigManager.AccountManager // Added in 6.0 + if ref == nil { + // Versions < 5.5 can use the ServiceContent ref, + // but we can only use it when connected directly to ESX. + c := m.Client() + if !c.IsVC() { + ref = c.ServiceContent.AccountManager + } + + if ref == nil { + return nil, ErrNotSupported + } + } + + return NewHostAccountManager(m.c, *ref), nil } func (m HostConfigManager) OptionManager(ctx context.Context) (*OptionManager, error) { @@ -120,3 +156,41 @@ 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 +} + +func (m HostConfigManager) CertificateManager(ctx context.Context) (*HostCertificateManager, error) { + var h mo.HostSystem + + err := m.Properties(ctx, m.Reference(), []string{"configManager.certificateManager"}, &h) + if err != nil { + return nil, err + } + + // Added in 6.0 + if h.ConfigManager.CertificateManager == nil { + return nil, ErrNotSupported + } + + return NewHostCertificateManager(m.c, *h.ConfigManager.CertificateManager, m.Reference()), nil +} + +func (m HostConfigManager) DateTimeSystem(ctx context.Context) (*HostDateTimeSystem, error) { + var h mo.HostSystem + + err := m.Properties(ctx, m.Reference(), []string{"configManager.dateTimeSystem"}, &h) + if err != nil { + return nil, err + } + + return NewHostDateTimeSystem(m.c, *h.ConfigManager.DateTimeSystem), nil +} diff --git a/vendor/github.com/vmware/govmomi/object/host_datastore_browser.go b/vendor/github.com/vmware/govmomi/object/host_datastore_browser.go index a2e205663..b0c9e08a1 100644 --- a/vendor/github.com/vmware/govmomi/object/host_datastore_browser.go +++ b/vendor/github.com/vmware/govmomi/object/host_datastore_browser.go @@ -17,10 +17,11 @@ limitations under the License. package object import ( + "context" + "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type HostDatastoreBrowser struct { diff --git a/vendor/github.com/vmware/govmomi/object/host_datastore_system.go b/vendor/github.com/vmware/govmomi/object/host_datastore_system.go index 632b7d255..7b738e611 100644 --- a/vendor/github.com/vmware/govmomi/object/host_datastore_system.go +++ b/vendor/github.com/vmware/govmomi/object/host_datastore_system.go @@ -17,10 +17,11 @@ limitations under the License. package object import ( + "context" + "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type HostDatastoreSystem struct { @@ -33,6 +34,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(), diff --git a/vendor/github.com/vmware/govmomi/object/host_date_time_system.go b/vendor/github.com/vmware/govmomi/object/host_date_time_system.go new file mode 100644 index 000000000..7c9203d7b --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_date_time_system.go @@ -0,0 +1,69 @@ +/* +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 ( + "context" + "time" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type HostDateTimeSystem struct { + Common +} + +func NewHostDateTimeSystem(c *vim25.Client, ref types.ManagedObjectReference) *HostDateTimeSystem { + return &HostDateTimeSystem{ + Common: NewCommon(c, ref), + } +} + +func (s HostDateTimeSystem) UpdateConfig(ctx context.Context, config types.HostDateTimeConfig) error { + req := types.UpdateDateTimeConfig{ + This: s.Reference(), + Config: config, + } + + _, err := methods.UpdateDateTimeConfig(ctx, s.c, &req) + return err +} + +func (s HostDateTimeSystem) Update(ctx context.Context, date time.Time) error { + req := types.UpdateDateTime{ + This: s.Reference(), + DateTime: date, + } + + _, err := methods.UpdateDateTime(ctx, s.c, &req) + return err +} + +func (s HostDateTimeSystem) Query(ctx context.Context) (*time.Time, error) { + req := types.QueryDateTime{ + This: s.Reference(), + } + + res, err := methods.QueryDateTime(ctx, s.c, &req) + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/host_firewall_system.go b/vendor/github.com/vmware/govmomi/object/host_firewall_system.go index 143f0983d..0b1440253 100644 --- a/vendor/github.com/vmware/govmomi/object/host_firewall_system.go +++ b/vendor/github.com/vmware/govmomi/object/host_firewall_system.go @@ -17,6 +17,7 @@ limitations under the License. package object import ( + "context" "errors" "fmt" "strings" @@ -25,7 +26,6 @@ import ( "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type HostFirewallSystem struct { diff --git a/vendor/github.com/vmware/govmomi/object/host_network_system.go b/vendor/github.com/vmware/govmomi/object/host_network_system.go index 1418de42f..c21e1ec35 100644 --- a/vendor/github.com/vmware/govmomi/object/host_network_system.go +++ b/vendor/github.com/vmware/govmomi/object/host_network_system.go @@ -17,10 +17,11 @@ limitations under the License. package object import ( + "context" + "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type HostNetworkSystem struct { diff --git a/vendor/github.com/vmware/govmomi/object/host_service_system.go b/vendor/github.com/vmware/govmomi/object/host_service_system.go new file mode 100644 index 000000000..a66b32c17 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_service_system.go @@ -0,0 +1,88 @@ +/* +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 ( + "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 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 +} diff --git a/vendor/github.com/vmware/govmomi/object/host_storage_system.go b/vendor/github.com/vmware/govmomi/object/host_storage_system.go index 36cd68e3a..2a433ff2a 100644 --- a/vendor/github.com/vmware/govmomi/object/host_storage_system.go +++ b/vendor/github.com/vmware/govmomi/object/host_storage_system.go @@ -17,12 +17,12 @@ limitations under the License. package object import ( + "context" "errors" "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type HostStorageSystem struct { @@ -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 +} diff --git a/vendor/github.com/vmware/govmomi/object/host_system.go b/vendor/github.com/vmware/govmomi/object/host_system.go index 0146d9ae5..a350edfde 100644 --- a/vendor/github.com/vmware/govmomi/object/host_system.go +++ b/vendor/github.com/vmware/govmomi/object/host_system.go @@ -17,6 +17,7 @@ limitations under the License. package object import ( + "context" "fmt" "net" @@ -24,20 +25,10 @@ import ( "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) 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()) } diff --git a/vendor/github.com/vmware/govmomi/object/host_virtual_nic_manager.go b/vendor/github.com/vmware/govmomi/object/host_virtual_nic_manager.go index 05338b82e..01e7e9cd4 100644 --- a/vendor/github.com/vmware/govmomi/object/host_virtual_nic_manager.go +++ b/vendor/github.com/vmware/govmomi/object/host_virtual_nic_manager.go @@ -17,11 +17,12 @@ limitations under the License. package object 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" - "golang.org/x/net/context" ) type HostVirtualNicManager struct { diff --git a/vendor/github.com/vmware/govmomi/object/host_vsan_internal_system.go b/vendor/github.com/vmware/govmomi/object/host_vsan_internal_system.go new file mode 100644 index 000000000..65e4587f6 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/host_vsan_internal_system.go @@ -0,0 +1,117 @@ +/* +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 object + +import ( + "context" + "encoding/json" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type HostVsanInternalSystem struct { + Common +} + +func NewHostVsanInternalSystem(c *vim25.Client, ref types.ManagedObjectReference) *HostVsanInternalSystem { + m := HostVsanInternalSystem{ + Common: NewCommon(c, ref), + } + + return &m +} + +// QueryVsanObjectUuidsByFilter returns vSAN DOM object uuids by filter. +func (m HostVsanInternalSystem) QueryVsanObjectUuidsByFilter(ctx context.Context, uuids []string, limit int32, version int32) ([]string, error) { + req := types.QueryVsanObjectUuidsByFilter{ + This: m.Reference(), + Uuids: uuids, + Limit: limit, + Version: version, + } + + res, err := methods.QueryVsanObjectUuidsByFilter(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +type VsanObjExtAttrs struct { + Type string `json:"Object type"` + Class string `json:"Object class"` + Size string `json:"Object size"` + Path string `json:"Object path"` + Name string `json:"User friendly name"` +} + +func (a *VsanObjExtAttrs) DatastorePath(dir string) string { + l := len(dir) + path := a.Path + + if len(path) >= l { + path = a.Path[l:] + } + + if path != "" { + return path + } + + return a.Name // vmnamespace +} + +// GetVsanObjExtAttrs is internal and intended for troubleshooting/debugging situations in the field. +// WARNING: This API can be slow because we do IOs (reads) to all the objects. +func (m HostVsanInternalSystem) GetVsanObjExtAttrs(ctx context.Context, uuids []string) (map[string]VsanObjExtAttrs, error) { + req := types.GetVsanObjExtAttrs{ + This: m.Reference(), + Uuids: uuids, + } + + res, err := methods.GetVsanObjExtAttrs(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + var attrs map[string]VsanObjExtAttrs + + err = json.Unmarshal([]byte(res.Returnval), &attrs) + + return attrs, err +} + +// DeleteVsanObjects is internal and intended for troubleshooting/debugging only. +// WARNING: This API can be slow because we do IOs to all the objects. +// DOM won't allow access to objects which have lost quorum. Such objects can be deleted with the optional "force" flag. +// These objects may however re-appear with quorum if the absent components come back (network partition gets resolved, etc.) +func (m HostVsanInternalSystem) DeleteVsanObjects(ctx context.Context, uuids []string, force *bool) ([]types.HostVsanInternalSystemDeleteVsanObjectsResult, error) { + req := types.DeleteVsanObjects{ + This: m.Reference(), + Uuids: uuids, + Force: force, + } + + res, err := methods.DeleteVsanObjects(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/host_vsan_system.go b/vendor/github.com/vmware/govmomi/object/host_vsan_system.go index 8c571421d..5ab234d5e 100644 --- a/vendor/github.com/vmware/govmomi/object/host_vsan_system.go +++ b/vendor/github.com/vmware/govmomi/object/host_vsan_system.go @@ -17,11 +17,12 @@ limitations under the License. package object 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" - "golang.org/x/net/context" ) type HostVsanSystem struct { diff --git a/vendor/github.com/vmware/govmomi/object/http_nfc_lease.go b/vendor/github.com/vmware/govmomi/object/http_nfc_lease.go index 3b06e3c3a..3ca53558b 100644 --- a/vendor/github.com/vmware/govmomi/object/http_nfc_lease.go +++ b/vendor/github.com/vmware/govmomi/object/http_nfc_lease.go @@ -17,6 +17,7 @@ limitations under the License. package object import ( + "context" "errors" "fmt" @@ -25,7 +26,6 @@ import ( "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type HttpNfcLease struct { diff --git a/vendor/github.com/vmware/govmomi/object/list_view.go b/vendor/github.com/vmware/govmomi/object/list_view.go deleted file mode 100644 index a79d33bc3..000000000 --- a/vendor/github.com/vmware/govmomi/object/list_view.go +++ /dev/null @@ -1,43 +0,0 @@ -/* -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 ListView struct { - Common -} - -func NewListView(c *vim25.Client, ref types.ManagedObjectReference) *ListView { - return &ListView{ - Common: NewCommon(c, ref), - } -} - -func (v ListView) Destroy(ctx context.Context) error { - req := types.DestroyView{ - This: v.Reference(), - } - - _, err := methods.DestroyView(ctx, v.c, &req) - return err -} diff --git a/vendor/github.com/vmware/govmomi/object/namespace_manager.go b/vendor/github.com/vmware/govmomi/object/namespace_manager.go new file mode 100644 index 000000000..f463b368c --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/namespace_manager.go @@ -0,0 +1,76 @@ +/* +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 ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +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 +} diff --git a/vendor/github.com/vmware/govmomi/object/network.go b/vendor/github.com/vmware/govmomi/object/network.go index 9963744aa..a76b17d91 100644 --- a/vendor/github.com/vmware/govmomi/object/network.go +++ b/vendor/github.com/vmware/govmomi/object/network.go @@ -17,17 +17,14 @@ limitations under the License. package object import ( - "path" + "context" "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type Network struct { Common - - InventoryPath string } func NewNetwork(c *vim25.Client, ref types.ManagedObjectReference) *Network { @@ -36,10 +33,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() diff --git a/vendor/github.com/vmware/govmomi/object/network_reference.go b/vendor/github.com/vmware/govmomi/object/network_reference.go index 98dd53813..7716bdb38 100644 --- a/vendor/github.com/vmware/govmomi/object/network_reference.go +++ b/vendor/github.com/vmware/govmomi/object/network_reference.go @@ -17,8 +17,9 @@ limitations under the License. package object import ( + "context" + "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) // The NetworkReference interface is implemented by managed objects diff --git a/vendor/github.com/vmware/govmomi/object/opaque_network.go b/vendor/github.com/vmware/govmomi/object/opaque_network.go new file mode 100644 index 000000000..47ce4cefe --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/opaque_network.go @@ -0,0 +1,57 @@ +/* +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 object + +import ( + "context" + "fmt" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type OpaqueNetwork struct { + Common +} + +func NewOpaqueNetwork(c *vim25.Client, ref types.ManagedObjectReference) *OpaqueNetwork { + return &OpaqueNetwork{ + Common: NewCommon(c, ref), + } +} + +// EthernetCardBackingInfo returns the VirtualDeviceBackingInfo for this Network +func (n OpaqueNetwork) EthernetCardBackingInfo(ctx context.Context) (types.BaseVirtualDeviceBackingInfo, error) { + var net mo.OpaqueNetwork + + if err := n.Properties(ctx, n.Reference(), []string{"summary"}, &net); err != nil { + return nil, err + } + + summary, ok := net.Summary.(*types.OpaqueNetworkSummary) + if !ok { + return nil, fmt.Errorf("%s unsupported network type: %T", n, net.Summary) + } + + backing := &types.VirtualEthernetCardOpaqueNetworkBackingInfo{ + OpaqueNetworkId: summary.OpaqueNetworkId, + OpaqueNetworkType: summary.OpaqueNetworkType, + } + + return backing, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/option_manager.go b/vendor/github.com/vmware/govmomi/object/option_manager.go index eae1223cc..7f93273aa 100644 --- a/vendor/github.com/vmware/govmomi/object/option_manager.go +++ b/vendor/github.com/vmware/govmomi/object/option_manager.go @@ -17,10 +17,11 @@ limitations under the License. package object import ( + "context" + "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type OptionManager struct { diff --git a/vendor/github.com/vmware/govmomi/object/ovf_manager.go b/vendor/github.com/vmware/govmomi/object/ovf_manager.go index e7912d0fd..7fedf689f 100644 --- a/vendor/github.com/vmware/govmomi/object/ovf_manager.go +++ b/vendor/github.com/vmware/govmomi/object/ovf_manager.go @@ -17,10 +17,11 @@ limitations under the License. package object import ( + "context" + "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type OvfManager struct { diff --git a/vendor/github.com/vmware/govmomi/object/resource_pool.go b/vendor/github.com/vmware/govmomi/object/resource_pool.go index e03460854..791fd3822 100644 --- a/vendor/github.com/vmware/govmomi/object/resource_pool.go +++ b/vendor/github.com/vmware/govmomi/object/resource_pool.go @@ -17,26 +17,15 @@ limitations under the License. package object import ( - "fmt" + "context" "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 +34,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(), diff --git a/vendor/github.com/vmware/govmomi/object/search_index.go b/vendor/github.com/vmware/govmomi/object/search_index.go index 638c8de2a..4b0a525d5 100644 --- a/vendor/github.com/vmware/govmomi/object/search_index.go +++ b/vendor/github.com/vmware/govmomi/object/search_index.go @@ -17,10 +17,11 @@ limitations under the License. package object import ( + "context" + "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type SearchIndex struct { diff --git a/vendor/github.com/vmware/govmomi/object/storage_resource_manager.go b/vendor/github.com/vmware/govmomi/object/storage_resource_manager.go index 54fd0d9e1..579bcd4d7 100644 --- a/vendor/github.com/vmware/govmomi/object/storage_resource_manager.go +++ b/vendor/github.com/vmware/govmomi/object/storage_resource_manager.go @@ -17,10 +17,11 @@ limitations under the License. package object import ( + "context" + "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type StorageResourceManager struct { diff --git a/vendor/github.com/vmware/govmomi/object/task.go b/vendor/github.com/vmware/govmomi/object/task.go index d70a417be..8572b4363 100644 --- a/vendor/github.com/vmware/govmomi/object/task.go +++ b/vendor/github.com/vmware/govmomi/object/task.go @@ -17,12 +17,13 @@ limitations under the License. package object import ( + "context" + "github.com/vmware/govmomi/property" "github.com/vmware/govmomi/task" "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/progress" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) // Task is a convenience wrapper around task.Task that keeps a reference to diff --git a/vendor/github.com/vmware/govmomi/object/types.go b/vendor/github.com/vmware/govmomi/object/types.go index f61aa362c..aefb611fd 100644 --- a/vendor/github.com/vmware/govmomi/object/types.go +++ b/vendor/github.com/vmware/govmomi/object/types.go @@ -47,7 +47,7 @@ func NewReference(c *vim25.Client, e types.ManagedObjectReference) Reference { return NewClusterComputeResource(c, e) case "HostSystem": return NewHostSystem(c, e) - case "Network": + case "Network", "OpaqueNetwork": return NewNetwork(c, e) case "ResourcePool": return NewResourcePool(c, e) diff --git a/vendor/github.com/vmware/govmomi/object/virtual_app.go b/vendor/github.com/vmware/govmomi/object/virtual_app.go index 5b93f618f..4811178f1 100644 --- a/vendor/github.com/vmware/govmomi/object/virtual_app.go +++ b/vendor/github.com/vmware/govmomi/object/virtual_app.go @@ -17,13 +17,10 @@ limitations under the License. package object import ( - "fmt" - - "golang.org/x/net/context" + "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,25 +34,7 @@ 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) { +func (p VirtualApp) CreateChildVM(ctx context.Context, config types.VirtualMachineConfigSpec, host *HostSystem) (*Task, error) { req := types.CreateChildVM_Task{ This: p.Reference(), Config: config, @@ -74,7 +53,7 @@ func (p VirtualApp) CreateChildVM_Task(ctx context.Context, config types.Virtual return NewTask(p.c, res.Returnval), nil } -func (p VirtualApp) UpdateVAppConfig(ctx context.Context, spec types.VAppConfigSpec) error { +func (p VirtualApp) UpdateConfig(ctx context.Context, spec types.VAppConfigSpec) error { req := types.UpdateVAppConfig{ This: p.Reference(), Spec: spec, @@ -84,7 +63,7 @@ func (p VirtualApp) UpdateVAppConfig(ctx context.Context, spec types.VAppConfigS return err } -func (p VirtualApp) PowerOnVApp_Task(ctx context.Context) (*Task, error) { +func (p VirtualApp) PowerOn(ctx context.Context) (*Task, error) { req := types.PowerOnVApp_Task{ This: p.Reference(), } @@ -97,7 +76,7 @@ func (p VirtualApp) PowerOnVApp_Task(ctx context.Context) (*Task, error) { return NewTask(p.c, res.Returnval), nil } -func (p VirtualApp) PowerOffVApp_Task(ctx context.Context, force bool) (*Task, error) { +func (p VirtualApp) PowerOff(ctx context.Context, force bool) (*Task, error) { req := types.PowerOffVApp_Task{ This: p.Reference(), Force: force, @@ -112,7 +91,7 @@ func (p VirtualApp) PowerOffVApp_Task(ctx context.Context, force bool) (*Task, e } -func (p VirtualApp) SuspendVApp_Task(ctx context.Context) (*Task, error) { +func (p VirtualApp) Suspend(ctx context.Context) (*Task, error) { req := types.SuspendVApp_Task{ This: p.Reference(), } diff --git a/vendor/github.com/vmware/govmomi/object/virtual_device_list.go b/vendor/github.com/vmware/govmomi/object/virtual_device_list.go index 327b5d27a..24821aa6b 100644 --- a/vendor/github.com/vmware/govmomi/object/virtual_device_list.go +++ b/vendor/github.com/vmware/govmomi/object/virtual_device_list.go @@ -84,6 +84,9 @@ func (l VirtualDeviceList) Select(f func(device types.BaseVirtualDevice) bool) V // SelectByType returns a new list with devices that are equal to or extend the given type. func (l VirtualDeviceList) SelectByType(deviceType types.BaseVirtualDevice) VirtualDeviceList { dtype := reflect.TypeOf(deviceType) + if dtype == nil { + return nil + } dname := dtype.Elem().Name() return l.Select(func(device types.BaseVirtualDevice) bool { @@ -242,6 +245,7 @@ func (l VirtualDeviceList) CreateSCSIController(name string) (types.BaseVirtualD scsi := c.GetVirtualSCSIController() scsi.BusNumber = l.newSCSIBusNumber() scsi.Key = l.NewKey() + scsi.ScsiCtlrUnitNumber = 7 return c.(types.BaseVirtualDevice), nil } @@ -270,6 +274,63 @@ func (l VirtualDeviceList) newSCSIBusNumber() int32 { return -1 } +// FindNVMEController will find the named NVME controller if given, otherwise will pick an available controller. +// An error is returned if the named controller is not found or not an NVME controller. Or, if name is not +// given and no available controller can be found. +func (l VirtualDeviceList) FindNVMEController(name string) (*types.VirtualNVMEController, error) { + if name != "" { + d := l.Find(name) + if d == nil { + return nil, fmt.Errorf("device '%s' not found", name) + } + if c, ok := d.(*types.VirtualNVMEController); ok { + return c, nil + } + return nil, fmt.Errorf("%s is not an NVME controller", name) + } + + c := l.PickController((*types.VirtualNVMEController)(nil)) + if c == nil { + return nil, errors.New("no available NVME controller") + } + + return c.(*types.VirtualNVMEController), nil +} + +// CreateNVMEController creates a new NVMWE controller. +func (l VirtualDeviceList) CreateNVMEController() (types.BaseVirtualDevice, error) { + nvme := &types.VirtualNVMEController{} + nvme.BusNumber = l.newNVMEBusNumber() + nvme.Key = l.NewKey() + + return nvme, nil +} + +var nvmeBusNumbers = []int{0, 1, 2, 3} + +// newNVMEBusNumber returns the bus number to use for adding a new NVME bus device. +// -1 is returned if there are no bus numbers available. +func (l VirtualDeviceList) newNVMEBusNumber() int32 { + var used []int + + for _, d := range l.SelectByType((*types.VirtualNVMEController)(nil)) { + num := d.(types.BaseVirtualController).GetVirtualController().BusNumber + if num >= 0 { + used = append(used, int(num)) + } // else caller is creating a new vm using NVMEControllerTypes + } + + sort.Ints(used) + + for i, n := range nvmeBusNumbers { + if i == len(used) || n != used[i] { + return int32(n) + } + } + + return -1 +} + // FindDiskController will find an existing ide or scsi disk controller. func (l VirtualDeviceList) FindDiskController(name string) (types.BaseVirtualController, error) { switch { @@ -277,6 +338,8 @@ func (l VirtualDeviceList) FindDiskController(name string) (types.BaseVirtualCon return l.FindIDEController("") case name == "scsi" || name == "": return l.FindSCSIController("") + case name == "nvme": + return l.FindNVMEController("") default: if c, ok := l.Find(name).(types.BaseVirtualController); ok { return c, nil @@ -296,6 +359,8 @@ func (l VirtualDeviceList) PickController(kind types.BaseVirtualController) type return num < 15 case *types.VirtualIDEController: return num < 2 + case *types.VirtualNVMEController: + return num < 8 default: return true } @@ -310,20 +375,31 @@ func (l VirtualDeviceList) PickController(kind types.BaseVirtualController) type // newUnitNumber returns the unit number to use for attaching a new device to the given controller. func (l VirtualDeviceList) newUnitNumber(c types.BaseVirtualController) int32 { + units := make([]bool, 30) + + switch sc := c.(type) { + case types.BaseVirtualSCSIController: + // The SCSI controller sits on its own bus + units[sc.GetVirtualSCSIController().ScsiCtlrUnitNumber] = true + } + key := c.GetVirtualController().Key - var max int32 = -1 for _, device := range l { d := device.GetVirtualDevice() - if d.ControllerKey == key { - if d.UnitNumber != nil && *d.UnitNumber > max { - max = *d.UnitNumber - } + if d.ControllerKey == key && d.UnitNumber != nil { + units[int(*d.UnitNumber)] = true } } - return max + 1 + for unit, used := range units { + if !used { + return int32(unit) + } + } + + return -1 } // NewKey returns the key to use for adding a new device to the device list. @@ -384,12 +460,14 @@ func (l VirtualDeviceList) CreateDisk(c types.BaseVirtualController, ds types.Ma func (l VirtualDeviceList) ChildDisk(parent *types.VirtualDisk) *types.VirtualDisk { disk := *parent backing := disk.Backing.(*types.VirtualDiskFlatVer2BackingInfo) - ds := strings.SplitN(backing.FileName[1:], "]", 2) + p := new(DatastorePath) + p.FromString(backing.FileName) + p.Path = "" // Use specified disk as parent backing to a new disk. disk.Backing = &types.VirtualDiskFlatVer2BackingInfo{ VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{ - FileName: fmt.Sprintf("[%s]", ds[0]), + FileName: p.String(), Datastore: backing.Datastore, }, Parent: backing, @@ -595,7 +673,17 @@ func (l VirtualDeviceList) CreateSerialPort() (*types.VirtualSerialPort, error) } // ConnectSerialPort connects a serial port to a server or client uri. -func (l VirtualDeviceList) ConnectSerialPort(device *types.VirtualSerialPort, uri string, client bool) *types.VirtualSerialPort { +func (l VirtualDeviceList) ConnectSerialPort(device *types.VirtualSerialPort, uri string, client bool, proxyuri string) *types.VirtualSerialPort { + if strings.HasPrefix(uri, "[") { + device.Backing = &types.VirtualSerialPortFileBackingInfo{ + VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{ + FileName: uri, + }, + } + + return device + } + direction := types.VirtualDeviceURIBackingOptionDirectionServer if client { direction = types.VirtualDeviceURIBackingOptionDirectionClient @@ -605,6 +693,7 @@ func (l VirtualDeviceList) ConnectSerialPort(device *types.VirtualSerialPort, ur VirtualDeviceURIBackingInfo: types.VirtualDeviceURIBackingInfo{ Direction: string(direction), ServiceURI: uri, + ProxyURI: proxyuri, }, } @@ -728,7 +817,11 @@ func (l VirtualDeviceList) SelectBootOrder(order []types.BaseVirtualMachineBootO // TypeName returns the vmodl type name of the device func (l VirtualDeviceList) TypeName(device types.BaseVirtualDevice) string { - return reflect.TypeOf(device).Elem().Name() + dtype := reflect.TypeOf(device) + if dtype == nil { + return "" + } + return dtype.Elem().Name() } var deviceNameRegexp = regexp.MustCompile(`(?:Virtual)?(?:Machine)?(\w+?)(?:Card|Device|Controller)?$`) @@ -754,6 +847,8 @@ func (l VirtualDeviceList) Type(device types.BaseVirtualDevice) string { return "pvscsi" case *types.VirtualLsiLogicSASController: return "lsilogic-sas" + case *types.VirtualNVMEController: + return "nvme" default: return l.deviceName(device) } diff --git a/vendor/github.com/vmware/govmomi/object/virtual_disk_manager.go b/vendor/github.com/vmware/govmomi/object/virtual_disk_manager.go index 800cfa076..b26e2f71c 100644 --- a/vendor/github.com/vmware/govmomi/object/virtual_disk_manager.go +++ b/vendor/github.com/vmware/govmomi/object/virtual_disk_manager.go @@ -17,10 +17,11 @@ limitations under the License. package object import ( + "context" + "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type VirtualDiskManager struct { @@ -143,3 +144,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 +} diff --git a/vendor/github.com/vmware/govmomi/object/virtual_disk_manager_internal.go b/vendor/github.com/vmware/govmomi/object/virtual_disk_manager_internal.go new file mode 100644 index 000000000..642cd62f6 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/virtual_disk_manager_internal.go @@ -0,0 +1,97 @@ +/* +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 object + +import ( + "context" + "reflect" + + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +func init() { + types.Add("ArrayOfVirtualDiskInfo", reflect.TypeOf((*arrayOfVirtualDiskInfo)(nil)).Elem()) + + types.Add("VirtualDiskInfo", reflect.TypeOf((*VirtualDiskInfo)(nil)).Elem()) +} + +type arrayOfVirtualDiskInfo struct { + VirtualDiskInfo []VirtualDiskInfo `xml:"VirtualDiskInfo,omitempty"` +} + +type queryVirtualDiskInfoTaskRequest struct { + This types.ManagedObjectReference `xml:"_this"` + Name string `xml:"name"` + Datacenter *types.ManagedObjectReference `xml:"datacenter,omitempty"` + IncludeParents bool `xml:"includeParents"` +} + +type queryVirtualDiskInfoTaskResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} + +type queryVirtualDiskInfoTaskBody struct { + Req *queryVirtualDiskInfoTaskRequest `xml:"urn:internalvim25 QueryVirtualDiskInfo_Task,omitempty"` + Res *queryVirtualDiskInfoTaskResponse `xml:"urn:vim25 QueryVirtualDiskInfo_TaskResponse,omitempty"` + Err *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *queryVirtualDiskInfoTaskBody) Fault() *soap.Fault { return b.Err } + +func queryVirtualDiskInfoTask(ctx context.Context, r soap.RoundTripper, req *queryVirtualDiskInfoTaskRequest) (*queryVirtualDiskInfoTaskResponse, error) { + var reqBody, resBody queryVirtualDiskInfoTaskBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type VirtualDiskInfo struct { + Name string `xml:"unit>name"` + DiskType string `xml:"diskType"` + Parent string `xml:"parent,omitempty"` +} + +func (m VirtualDiskManager) QueryVirtualDiskInfo(ctx context.Context, name string, dc *Datacenter, includeParents bool) ([]VirtualDiskInfo, error) { + req := queryVirtualDiskInfoTaskRequest{ + This: m.Reference(), + Name: name, + IncludeParents: includeParents, + } + + if dc != nil { + ref := dc.Reference() + req.Datacenter = &ref + } + + res, err := queryVirtualDiskInfoTask(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + info, err := NewTask(m.Client(), res.Returnval).WaitForResult(ctx, nil) + if err != nil { + return nil, err + } + + return info.Result.(arrayOfVirtualDiskInfo).VirtualDiskInfo, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/virtual_machine.go b/vendor/github.com/vmware/govmomi/object/virtual_machine.go index 4faeae75e..02c4e2371 100644 --- a/vendor/github.com/vmware/govmomi/object/virtual_machine.go +++ b/vendor/github.com/vmware/govmomi/object/virtual_machine.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2015 VMware, Inc. All Rights Reserved. +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. @@ -17,16 +17,17 @@ limitations under the License. package object import ( + "context" "errors" "fmt" "net" + "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" ) const ( @@ -35,15 +36,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 +44,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 @@ -248,9 +229,12 @@ func (v VirtualMachine) WaitForIP(ctx context.Context) (string, error) { // WaitForNetIP waits for the VM guest.net property to report an IP address for all VM NICs. // Only consider IPv4 addresses if the v4 param is true. +// By default, wait for all NICs to get an IP address, unless 1 or more device is given. +// A device can be specified by the MAC address or the device name, e.g. "ethernet-0". // Returns a map with MAC address as the key and IP address list as the value. -func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool) (map[string][]string, error) { +func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool, device ...string) (map[string][]string, error) { macs := make(map[string][]string) + eths := make(map[string]string) p := property.DefaultCollector(v.c) @@ -261,14 +245,15 @@ func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool) (map[string][ continue } - devices := c.Val.(types.ArrayOfVirtualDevice).VirtualDevice - for _, device := range devices { - if nic, ok := device.(types.BaseVirtualEthernetCard); ok { + devices := VirtualDeviceList(c.Val.(types.ArrayOfVirtualDevice).VirtualDevice) + for _, d := range devices { + if nic, ok := d.(types.BaseVirtualEthernetCard); ok { mac := nic.GetVirtualEthernetCard().MacAddress if mac == "" { return false } macs[mac] = nil + eths[devices.Name(d)] = mac } } } @@ -276,6 +261,17 @@ func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool) (map[string][ return true }) + if len(device) != 0 { + // Only wait for specific NIC(s) + macs = make(map[string][]string) + for _, mac := range device { + if eth, ok := eths[mac]; ok { + mac = eth // device name, e.g. "ethernet-0" + } + macs[mac] = nil + } + } + err = property.Wait(ctx, p, v.Reference(), []string{"guest.net"}, func(pc []types.PropertyChange) bool { for _, c := range pc { if c.Op != types.PropertyChangeOpAssign { @@ -321,18 +317,28 @@ func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool) (map[string][ func (v VirtualMachine) Device(ctx context.Context) (VirtualDeviceList, error) { var o mo.VirtualMachine - err := v.Properties(ctx, v.Reference(), []string{"config.hardware.device"}, &o) + err := v.Properties(ctx, v.Reference(), []string{"config.hardware.device", "summary.runtime.connectionState"}, &o) if err != nil { return nil, err } + // Quoting the SDK doc: + // The virtual machine configuration is not guaranteed to be available. + // For example, the configuration information would be unavailable if the server + // is unable to access the virtual machine files on disk, and is often also unavailable + // during the initial phases of virtual machine creation. + if o.Config == nil { + return nil, fmt.Errorf("%s Config is not available, connectionState=%s", + v.Reference(), o.Summary.Runtime.ConnectionState) + } + return VirtualDeviceList(o.Config.Hardware.Device), nil } func (v VirtualMachine) HostSystem(ctx context.Context) (*HostSystem, error) { var o mo.VirtualMachine - err := v.Properties(ctx, v.Reference(), []string{"summary"}, &o) + err := v.Properties(ctx, v.Reference(), []string{"summary.runtime.host"}, &o) if err != nil { return nil, err } @@ -491,28 +497,86 @@ func (v VirtualMachine) RemoveAllSnapshot(ctx context.Context, consolidate *bool return NewTask(v.c, res.Returnval), nil } -// RevertToSnapshot reverts to a named snapshot -func (v VirtualMachine) RevertToSnapshot(ctx context.Context, name string, suppressPowerOn bool) (*Task, error) { +type snapshotMap map[string][]Reference + +func (m snapshotMap) add(parent string, tree []types.VirtualMachineSnapshotTree) { + for i, st := range tree { + sname := st.Name + names := []string{sname, st.Snapshot.Value} + + if parent != "" { + sname = path.Join(parent, sname) + // Add full path as an option to resolve duplicate names + names = append(names, sname) + } + + for _, name := range names { + m[name] = append(m[name], &tree[i].Snapshot) + } + + m.add(sname, st.ChildSnapshotList) + } +} + +// FindSnapshot supports snapshot lookup by name, where name can be: +// 1) snapshot ManagedObjectReference.Value (unique) +// 2) snapshot name (may not be unique) +// 3) snapshot tree path (may not be unique) +func (v VirtualMachine) FindSnapshot(ctx context.Context, name string) (Reference, error) { var o mo.VirtualMachine err := v.Properties(ctx, v.Reference(), []string{"snapshot"}, &o) + if err != nil { + return nil, err + } - snapshotTree := o.Snapshot.RootSnapshotList - if len(snapshotTree) < 1 { + if o.Snapshot == nil || len(o.Snapshot.RootSnapshotList) == 0 { return nil, errors.New("No snapshots for this VM") } - snapshot, err := traverseSnapshotInTree(snapshotTree, name) + m := make(snapshotMap) + m.add("", o.Snapshot.RootSnapshotList) + + s := m[name] + switch len(s) { + case 0: + return nil, fmt.Errorf("snapshot %q not found", name) + case 1: + return s[0], nil + default: + return nil, fmt.Errorf("%q resolves to %d snapshots", name, len(s)) + } +} + +// RemoveSnapshot removes a named snapshot +func (v VirtualMachine) RemoveSnapshot(ctx context.Context, name string, removeChildren bool, consolidate *bool) (*Task, error) { + snapshot, err := v.FindSnapshot(ctx, name) if err != nil { return nil, err } - req := types.RevertToSnapshot_Task{ - This: snapshot, + req := types.RemoveSnapshot_Task{ + This: snapshot.Reference(), + RemoveChildren: removeChildren, + Consolidate: consolidate, + } + + res, err := methods.RemoveSnapshot_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +// RevertToCurrentSnapshot reverts to the current snapshot +func (v VirtualMachine) RevertToCurrentSnapshot(ctx context.Context, suppressPowerOn bool) (*Task, error) { + req := types.RevertToCurrentSnapshot_Task{ + This: v.Reference(), SuppressPowerOn: types.NewBool(suppressPowerOn), } - res, err := methods.RevertToSnapshot_Task(ctx, v.c, &req) + res, err := methods.RevertToCurrentSnapshot_Task(ctx, v.c, &req) if err != nil { return nil, err } @@ -520,30 +584,24 @@ func (v VirtualMachine) RevertToSnapshot(ctx context.Context, name string, suppr return NewTask(v.c, res.Returnval), nil } -// traverseSnapshotInTree is a recursive function that will traverse a snapshot tree to find a given snapshot -func traverseSnapshotInTree(tree []types.VirtualMachineSnapshotTree, name string) (types.ManagedObjectReference, error) { - var o types.ManagedObjectReference - if tree == nil { - return o, errors.New("Snapshot tree is empty") - } - for _, s := range tree { - if s.Name == name { - o = s.Snapshot - break - } else { - childTree := s.ChildSnapshotList - var err error - o, err = traverseSnapshotInTree(childTree, name) - if err != nil { - return o, err - } - } +// RevertToSnapshot reverts to a named snapshot +func (v VirtualMachine) RevertToSnapshot(ctx context.Context, name string, suppressPowerOn bool) (*Task, error) { + snapshot, err := v.FindSnapshot(ctx, name) + if err != nil { + return nil, err } - if o.Value == "" { - return o, errors.New("Snapshot not found") + + req := types.RevertToSnapshot_Task{ + This: snapshot.Reference(), + SuppressPowerOn: types.NewBool(suppressPowerOn), + } + + res, err := methods.RevertToSnapshot_Task(ctx, v.c, &req) + if err != nil { + return nil, err } - return o, nil + return NewTask(v.c, res.Returnval), nil } // IsToolsRunning returns true if VMware Tools is currently running in the guest OS, and false otherwise. @@ -612,3 +670,90 @@ func (v VirtualMachine) MarkAsVirtualMachine(ctx context.Context, pool ResourceP return nil } + +func (v VirtualMachine) Migrate(ctx context.Context, pool *ResourcePool, host *HostSystem, priority types.VirtualMachineMovePriority, state types.VirtualMachinePowerState) (*Task, error) { + req := types.MigrateVM_Task{ + This: v.Reference(), + Priority: priority, + State: state, + } + + if pool != nil { + ref := pool.Reference() + req.Pool = &ref + } + + if host != nil { + ref := host.Reference() + req.Host = &ref + } + + res, err := methods.MigrateVM_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + +func (v VirtualMachine) Unregister(ctx context.Context) error { + req := types.UnregisterVM{ + This: v.Reference(), + } + + _, err := methods.UnregisterVM(ctx, v.Client(), &req) + return err +} + +// QueryEnvironmentBrowser is a helper to get the environmentBrowser property. +func (v VirtualMachine) QueryConfigTarget(ctx context.Context) (*types.ConfigTarget, error) { + var vm mo.VirtualMachine + + err := v.Properties(ctx, v.Reference(), []string{"environmentBrowser"}, &vm) + if err != nil { + return nil, err + } + + req := types.QueryConfigTarget{ + This: vm.EnvironmentBrowser, + } + + res, err := methods.QueryConfigTarget(ctx, v.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (v VirtualMachine) MountToolsInstaller(ctx context.Context) error { + req := types.MountToolsInstaller{ + This: v.Reference(), + } + + _, err := methods.MountToolsInstaller(ctx, v.Client(), &req) + return err +} + +func (v VirtualMachine) UnmountToolsInstaller(ctx context.Context) error { + req := types.UnmountToolsInstaller{ + This: v.Reference(), + } + + _, err := methods.UnmountToolsInstaller(ctx, v.Client(), &req) + return err +} + +func (v VirtualMachine) UpgradeTools(ctx context.Context, options string) (*Task, error) { + req := types.UpgradeTools_Task{ + This: v.Reference(), + InstallerOptions: options, + } + + res, err := methods.UpgradeTools_Task(ctx, v.Client(), &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} diff --git a/vendor/github.com/vmware/govmomi/task/wait.go b/vendor/github.com/vmware/govmomi/task/wait.go index 9432ee734..19fee5384 100644 --- a/vendor/github.com/vmware/govmomi/task/wait.go +++ b/vendor/github.com/vmware/govmomi/task/wait.go @@ -17,10 +17,11 @@ limitations under the License. package task import ( + "context" + "github.com/vmware/govmomi/property" "github.com/vmware/govmomi/vim25/progress" "github.com/vmware/govmomi/vim25/types" - "golang.org/x/net/context" ) type taskProgress struct { @@ -67,6 +68,11 @@ func (t *taskCallback) fn(pc []types.PropertyChange) bool { t.info = &ti } + // t.info could be nil if pc can't satify the rules above + if t.info == nil { + return false + } + pr := taskProgress{t.info} // Store copy of error, so Wait() can return it as well. diff --git a/vendor/vendor.json b/vendor/vendor.json index a88cd63ca..73d23dbba 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -547,98 +547,131 @@ "versionExact": "v0.15.0" }, { - "checksumSHA1": "xyxo9nWPro79ae/TGNZOlWKSPUk=", + "checksumSHA1": "L/z6VeAmwdnp4Prod4EAlTcPYRY=", "comment": "v0.15.0", "path": "github.com/vmware/govmomi/find", - "revision": "9051bd6b44125d9472e0c148b5965692ab283d4a" + "revision": "b63044e5f833781eb7b305bc035392480ee06a82", + "revisionTime": "2017-06-19T23:14:37Z", + "tree": true, + "version": "v0.15.0", + "versionExact": "v0.15.0" }, { - "checksumSHA1": "lHxDz/33BD9IKrlJ3lRUicXWVfg=", + "checksumSHA1": "J3JrwZagGYMX6oNMkdsUFf8hHo8=", "comment": "v0.15.0", "path": "github.com/vmware/govmomi/list", - "revision": "9051bd6b44125d9472e0c148b5965692ab283d4a" + "revision": "b63044e5f833781eb7b305bc035392480ee06a82", + "revisionTime": "2017-06-19T23:14:37Z", + "version": "v0.15.0", + "versionExact": "v0.15.0" }, { - "checksumSHA1": "Tu98nr2K8FL8Bz/88ufPBWYR1xQ=", + "checksumSHA1": "zQz4weqDXCiYpathvULz3m48g/U=", "comment": "v0.15.0", "path": "github.com/vmware/govmomi/object", - "revision": "9051bd6b44125d9472e0c148b5965692ab283d4a" + "revision": "b63044e5f833781eb7b305bc035392480ee06a82", + "revisionTime": "2017-06-19T23:14:37Z", + "version": "v0.15.0", + "versionExact": "v0.15.0" }, { "checksumSHA1": "INNHeHhLFq+1BzuX/E3el2wZpVs=", "comment": "v0.15.0", "path": "github.com/vmware/govmomi/property", - "revision": "a5cb0a3430b074ce54ff873197b6ec881acf82fa", - "revisionTime": "2017-06-20T04:56:21Z" + "revision": "b63044e5f833781eb7b305bc035392480ee06a82", + "revisionTime": "2017-06-19T23:14:37Z", + "version": "v0.15.0", + "versionExact": "v0.15.0" }, { "checksumSHA1": "eqoHqcnyVN3klOJ89N7xmJhRgu0=", "comment": "v0.15.0", "path": "github.com/vmware/govmomi/session", - "revision": "a5cb0a3430b074ce54ff873197b6ec881acf82fa", - "revisionTime": "2017-06-20T04:56:21Z" + "revision": "b63044e5f833781eb7b305bc035392480ee06a82", + "revisionTime": "2017-06-19T23:14:37Z", + "version": "v0.15.0", + "versionExact": "v0.15.0" }, { - "checksumSHA1": "JtZUMXRXiFOaV8akUh+kbnLaf+E=", + "checksumSHA1": "FQR3yNgiShaqUiJREkeqQCKYJ84=", "comment": "v0.15.0", "path": "github.com/vmware/govmomi/task", - "revision": "9051bd6b44125d9472e0c148b5965692ab283d4a" + "revision": "b63044e5f833781eb7b305bc035392480ee06a82", + "revisionTime": "2017-06-19T23:14:37Z", + "version": "v0.15.0", + "versionExact": "v0.15.0" }, { "checksumSHA1": "zLg5y/6xx/yr8swoqdyxISyQfoU=", "comment": "v0.15.0", "path": "github.com/vmware/govmomi/vim25", - "revision": "a5cb0a3430b074ce54ff873197b6ec881acf82fa", - "revisionTime": "2017-06-20T04:56:21Z" + "revision": "b63044e5f833781eb7b305bc035392480ee06a82", + "revisionTime": "2017-06-19T23:14:37Z", + "version": "v0.15.0", + "versionExact": "v0.15.0" }, { "checksumSHA1": "xLvppq0NUD6Hv2GIx1gh75xUzyM=", "comment": "v0.15.0", "path": "github.com/vmware/govmomi/vim25/debug", - "revision": "a5cb0a3430b074ce54ff873197b6ec881acf82fa", - "revisionTime": "2017-06-20T04:56:21Z" + "revision": "b63044e5f833781eb7b305bc035392480ee06a82", + "revisionTime": "2017-06-19T23:14:37Z", + "version": "v0.15.0", + "versionExact": "v0.15.0" }, { "checksumSHA1": "FIwHoeb/lzICWAoECQkmKLJg4PE=", "comment": "v0.15.0", "path": "github.com/vmware/govmomi/vim25/methods", - "revision": "a5cb0a3430b074ce54ff873197b6ec881acf82fa", - "revisionTime": "2017-06-20T04:56:21Z" + "revision": "b63044e5f833781eb7b305bc035392480ee06a82", + "revisionTime": "2017-06-19T23:14:37Z", + "version": "v0.15.0", + "versionExact": "v0.15.0" }, { "checksumSHA1": "kiVMrAiW8EBFQvhDMHdE9SFe3N4=", "comment": "v0.15.0", "path": "github.com/vmware/govmomi/vim25/mo", - "revision": "a5cb0a3430b074ce54ff873197b6ec881acf82fa", - "revisionTime": "2017-06-20T04:56:21Z" + "revision": "b63044e5f833781eb7b305bc035392480ee06a82", + "revisionTime": "2017-06-19T23:14:37Z", + "version": "v0.15.0", + "versionExact": "v0.15.0" }, { "checksumSHA1": "tN9fHudMKhR3LjGw/V0fM4xXUJw=", "comment": "v0.15.0", "path": "github.com/vmware/govmomi/vim25/progress", - "revision": "a5cb0a3430b074ce54ff873197b6ec881acf82fa", - "revisionTime": "2017-06-20T04:56:21Z" + "revision": "b63044e5f833781eb7b305bc035392480ee06a82", + "revisionTime": "2017-06-19T23:14:37Z", + "version": "v0.15.0", + "versionExact": "v0.15.0" }, { "checksumSHA1": "c/IZCAPYN0p+ODQ/o/1vmfOgz6M=", "comment": "v0.15.0", "path": "github.com/vmware/govmomi/vim25/soap", - "revision": "a5cb0a3430b074ce54ff873197b6ec881acf82fa", - "revisionTime": "2017-06-20T04:56:21Z" + "revision": "b63044e5f833781eb7b305bc035392480ee06a82", + "revisionTime": "2017-06-19T23:14:37Z", + "version": "v0.15.0", + "versionExact": "v0.15.0" }, { "checksumSHA1": "zthVYB/EefaNfVGrhBluqkd8ZyE=", "comment": "v0.15.0", "path": "github.com/vmware/govmomi/vim25/types", - "revision": "a5cb0a3430b074ce54ff873197b6ec881acf82fa", - "revisionTime": "2017-06-20T04:56:21Z" + "revision": "b63044e5f833781eb7b305bc035392480ee06a82", + "revisionTime": "2017-06-19T23:14:37Z", + "version": "v0.15.0", + "versionExact": "v0.15.0" }, { "checksumSHA1": "6XLRzLEvncx5ORtvBjp41KfRTjc=", "comment": "v0.15.0", "path": "github.com/vmware/govmomi/vim25/xml", - "revision": "a5cb0a3430b074ce54ff873197b6ec881acf82fa", - "revisionTime": "2017-06-20T04:56:21Z" + "revision": "b63044e5f833781eb7b305bc035392480ee06a82", + "revisionTime": "2017-06-19T23:14:37Z", + "version": "v0.15.0", + "versionExact": "v0.15.0" }, { "checksumSHA1": "vE43s37+4CJ2CDU6TlOUOYE0K9c=",