From 5c27b98ce0275ac4b5cb6cafec8035720f324fb9 Mon Sep 17 00:00:00 2001 From: Doug MacEachern Date: Tue, 30 Jan 2018 12:03:39 -0800 Subject: [PATCH] godep: update vmware/govmomi --- Godeps/Godeps.json | 88 ++-- vendor/github.com/vmware/govmomi/Makefile | 2 +- .../github.com/vmware/govmomi/find/finder.go | 21 + vendor/github.com/vmware/govmomi/nfc/lease.go | 4 +- .../object/cluster_compute_resource.go | 26 +- .../vmware/govmomi/object/compute_resource.go | 13 - .../vmware/govmomi/object/datastore.go | 17 +- .../vmware/govmomi/object/datastore_file.go | 4 +- .../govmomi/object/host_storage_system.go | 20 + .../govmomi/object/virtual_disk_manager.go | 41 ++ .../object/virtual_disk_manager_internal.go | 64 +++ .../vmware/govmomi/property/collector.go | 4 + .../github.com/vmware/govmomi/simulator/BUILD | 2 + .../simulator/authorization_manager.go | 3 +- .../simulator/cluster_compute_resource.go | 238 ++++++++++- .../simulator/custom_fields_manager.go | 8 +- .../vmware/govmomi/simulator/datacenter.go | 11 + .../vmware/govmomi/simulator/dvs.go | 15 +- .../vmware/govmomi/simulator/esx/BUILD | 1 + .../govmomi/simulator/esx/event_manager.go | 236 +++++++++++ .../vmware/govmomi/simulator/event_manager.go | 386 ++++++++++++++++++ .../vmware/govmomi/simulator/file_manager.go | 1 + .../vmware/govmomi/simulator/folder.go | 118 ++++-- .../simulator/host_datastore_system.go | 2 +- .../simulator/host_local_account_manager.go | 80 ++++ .../vmware/govmomi/simulator/host_system.go | 24 +- .../vmware/govmomi/simulator/model.go | 13 +- .../govmomi/simulator/option_manager.go | 39 ++ .../vmware/govmomi/simulator/portgroup.go | 15 +- .../govmomi/simulator/property_collector.go | 124 +++--- .../govmomi/simulator/property_filter.go | 2 +- .../vmware/govmomi/simulator/registry.go | 133 ++++-- .../vmware/govmomi/simulator/resource_pool.go | 16 +- .../govmomi/simulator/service_instance.go | 5 + .../govmomi/simulator/session_manager.go | 210 +++++++++- .../vmware/govmomi/simulator/simulator.go | 105 +++-- .../vmware/govmomi/simulator/snapshot.go | 16 +- .../govmomi/simulator/user_directory.go | 48 ++- .../vmware/govmomi/simulator/view_manager.go | 26 +- .../govmomi/simulator/virtual_disk_manager.go | 17 +- .../govmomi/simulator/virtual_machine.go | 296 +++++++++++--- .../vmware/govmomi/simulator/vpx/setting.go | 12 + .../vmware/govmomi/vim25/progress/reader.go | 25 +- .../vmware/govmomi/vim25/soap/client.go | 35 +- .../vmware/govmomi/vim25/types/helpers.go | 7 + .../vmware/govmomi/vim25/types/types.go | 2 +- 46 files changed, 2205 insertions(+), 370 deletions(-) create mode 100644 vendor/github.com/vmware/govmomi/simulator/esx/event_manager.go create mode 100644 vendor/github.com/vmware/govmomi/simulator/event_manager.go create mode 100644 vendor/github.com/vmware/govmomi/simulator/host_local_account_manager.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index b70aaf89c77..25d1d80fe2a 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -2644,113 +2644,113 @@ }, { "ImportPath": "github.com/vmware/govmomi", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/find", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/list", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/nfc", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/object", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/pbm", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/pbm/methods", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/pbm/types", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/property", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/session", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/simulator", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/simulator/esx", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/simulator/vpx", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/task", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/vim25", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/vim25/debug", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/vim25/methods", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/vim25/mo", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/vim25/progress", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/vim25/soap", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/vim25/types", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/govmomi/vim25/xml", - "Comment": "v0.16.0-5-g5f0f400", - "Rev": "5f0f4004a1f075f29e715f1b956ca0ab4b428f17" + "Comment": "v0.16.0-80-g8174315", + "Rev": "81743157fb5ccf548d6bd5088c25ee6156a359ee" }, { "ImportPath": "github.com/vmware/photon-controller-go-sdk/SSPI", diff --git a/vendor/github.com/vmware/govmomi/Makefile b/vendor/github.com/vmware/govmomi/Makefile index 9886b45ceb5..e0e03ecd3f5 100644 --- a/vendor/github.com/vmware/govmomi/Makefile +++ b/vendor/github.com/vmware/govmomi/Makefile @@ -18,7 +18,7 @@ install: go install -v github.com/vmware/govmomi/vcsim go-test: - go test -v $(TEST_OPTS) ./... + go test -race -v $(TEST_OPTS) ./... govc-test: install (cd govc/test && ./vendor/github.com/sstephenson/bats/libexec/bats -t .) diff --git a/vendor/github.com/vmware/govmomi/find/finder.go b/vendor/github.com/vmware/govmomi/find/finder.go index 04d0e891a9b..2e9727e4844 100644 --- a/vendor/github.com/vmware/govmomi/find/finder.go +++ b/vendor/github.com/vmware/govmomi/find/finder.go @@ -625,6 +625,15 @@ func (f *Finder) ClusterComputeResourceList(ctx context.Context, path string) ([ return ccrs, nil } +func (f *Finder) DefaultClusterComputeResource(ctx context.Context) (*object.ClusterComputeResource, error) { + cr, err := f.ClusterComputeResource(ctx, "*") + if err != nil { + return nil, toDefaultError(err) + } + + return cr, nil +} + func (f *Finder) ClusterComputeResource(ctx context.Context, path string) (*object.ClusterComputeResource, error) { ccrs, err := f.ClusterComputeResourceList(ctx, path) if err != nil { @@ -638,6 +647,18 @@ func (f *Finder) ClusterComputeResource(ctx context.Context, path string) (*obje return ccrs[0], nil } +func (f *Finder) ClusterComputeResourceOrDefault(ctx context.Context, path string) (*object.ClusterComputeResource, error) { + if path != "" { + cr, err := f.ClusterComputeResource(ctx, path) + if err != nil { + return nil, err + } + return cr, nil + } + + return f.DefaultClusterComputeResource(ctx) +} + func (f *Finder) HostSystemList(ctx context.Context, path string) ([]*object.HostSystem, error) { s := &spec{ Relative: f.hostFolder, diff --git a/vendor/github.com/vmware/govmomi/nfc/lease.go b/vendor/github.com/vmware/govmomi/nfc/lease.go index 393c648353f..3fb85ee6f6e 100644 --- a/vendor/github.com/vmware/govmomi/nfc/lease.go +++ b/vendor/github.com/vmware/govmomi/nfc/lease.go @@ -224,7 +224,7 @@ func (l *Lease) Upload(ctx context.Context, item FileItem, f io.Reader, opts soa opts.Type = "application/x-vnd.vmware-streamVmdk" } - return l.c.Upload(f, item.URL, &opts) + return l.c.Upload(ctx, f, item.URL, &opts) } func (l *Lease) DownloadFile(ctx context.Context, file string, item FileItem, opts soap.Download) error { @@ -234,5 +234,5 @@ func (l *Lease) DownloadFile(ctx context.Context, file string, item FileItem, op opts.Progress = progress.Tee(item, opts.Progress) } - return l.c.DownloadFile(file, item.URL, &opts) + return l.c.DownloadFile(ctx, file, item.URL, &opts) } 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 225f41b6d19..c9fe3aa035b 100644 --- a/vendor/github.com/vmware/govmomi/object/cluster_compute_resource.go +++ b/vendor/github.com/vmware/govmomi/object/cluster_compute_resource.go @@ -21,6 +21,7 @@ import ( "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/types" ) @@ -34,19 +35,15 @@ func NewClusterComputeResource(c *vim25.Client, ref types.ManagedObjectReference } } -func (c ClusterComputeResource) ReconfigureCluster(ctx context.Context, spec types.ClusterConfigSpec) (*Task, error) { - req := types.ReconfigureCluster_Task{ - This: c.Reference(), - Spec: spec, - Modify: true, - } +func (c ClusterComputeResource) Configuration(ctx context.Context) (*types.ClusterConfigInfoEx, error) { + var obj mo.ClusterComputeResource - res, err := methods.ReconfigureCluster_Task(ctx, c.c, &req) + err := c.Properties(ctx, c.Reference(), []string{"configurationEx"}, &obj) if err != nil { return nil, err } - return NewTask(c.c, res.Returnval), nil + return obj.ConfigurationEx.(*types.ClusterConfigInfoEx), nil } func (c ClusterComputeResource) AddHost(ctx context.Context, spec types.HostConnectSpec, asConnected bool, license *string, resourcePool *types.ManagedObjectReference) (*Task, error) { @@ -71,16 +68,3 @@ func (c ClusterComputeResource) AddHost(ctx context.Context, spec types.HostConn return NewTask(c.c, res.Returnval), nil } - -func (c ClusterComputeResource) Destroy(ctx context.Context) (*Task, error) { - req := types.Destroy_Task{ - This: c.Reference(), - } - - res, err := methods.Destroy_Task(ctx, c.c, &req) - if err != nil { - return nil, err - } - - return NewTask(c.c, res.Returnval), nil -} diff --git a/vendor/github.com/vmware/govmomi/object/compute_resource.go b/vendor/github.com/vmware/govmomi/object/compute_resource.go index ac1c73019fc..7645fddaf31 100644 --- a/vendor/github.com/vmware/govmomi/object/compute_resource.go +++ b/vendor/github.com/vmware/govmomi/object/compute_resource.go @@ -109,16 +109,3 @@ func (c ComputeResource) Reconfigure(ctx context.Context, spec types.BaseCompute return NewTask(c.c, res.Returnval), nil } - -func (c ComputeResource) Destroy(ctx context.Context) (*Task, error) { - req := types.Destroy_Task{ - This: c.Reference(), - } - - res, err := methods.Destroy_Task(ctx, c.c, &req) - if err != nil { - return nil, err - } - - return NewTask(c.c, res.Returnval), nil -} diff --git a/vendor/github.com/vmware/govmomi/object/datastore.go b/vendor/github.com/vmware/govmomi/object/datastore.go index fc696cdf213..dfe6603aa5c 100644 --- a/vendor/github.com/vmware/govmomi/object/datastore.go +++ b/vendor/github.com/vmware/govmomi/object/datastore.go @@ -284,7 +284,7 @@ func (d Datastore) Upload(ctx context.Context, f io.Reader, path string, param * if err != nil { return err } - return d.Client().Upload(f, u, p) + return d.Client().Upload(ctx, f, u, p) } // UploadFile via soap.Upload with an http service ticket @@ -293,7 +293,7 @@ func (d Datastore) UploadFile(ctx context.Context, file string, path string, par if err != nil { return err } - return d.Client().UploadFile(file, u, p) + return d.Client().UploadFile(ctx, file, u, p) } // Download via soap.Download with an http service ticket @@ -302,7 +302,7 @@ func (d Datastore) Download(ctx context.Context, path string, param *soap.Downlo if err != nil { return nil, 0, err } - return d.Client().Download(u, p) + return d.Client().Download(ctx, u, p) } // DownloadFile via soap.Download with an http service ticket @@ -311,7 +311,7 @@ func (d Datastore) DownloadFile(ctx context.Context, path string, file string, p if err != nil { return err } - return d.Client().DownloadFile(file, u, p) + return d.Client().DownloadFile(ctx, file, u, p) } // AttachedHosts returns hosts that have this Datastore attached, accessible and writable. @@ -406,12 +406,9 @@ func (d Datastore) Stat(ctx context.Context, file string) (types.BaseFileInfo, e info, err := task.WaitForResult(ctx, nil) if err != nil { - if info == nil || info.Error != nil { - _, ok := info.Error.Fault.(*types.FileNotFound) - if ok { - // FileNotFound means the base path doesn't exist. - return nil, DatastoreNoSuchDirectoryError{"stat", dsPath} - } + if types.IsFileNotFound(err) { + // FileNotFound means the base path doesn't exist. + return nil, DatastoreNoSuchDirectoryError{"stat", dsPath} } return nil, err diff --git a/vendor/github.com/vmware/govmomi/object/datastore_file.go b/vendor/github.com/vmware/govmomi/object/datastore_file.go index a73990f12cc..bc010fc36e8 100644 --- a/vendor/github.com/vmware/govmomi/object/datastore_file.go +++ b/vendor/github.com/vmware/govmomi/object/datastore_file.go @@ -172,7 +172,7 @@ func (f *DatastoreFile) Stat() (os.FileInfo, error) { return nil, err } - res, err := f.d.Client().DownloadRequest(u, p) + res, err := f.d.Client().DownloadRequest(f.ctx, u, p) if err != nil { return nil, err } @@ -202,7 +202,7 @@ func (f *DatastoreFile) get() (io.Reader, error) { } } - res, err := f.d.Client().DownloadRequest(u, p) + res, err := f.d.Client().DownloadRequest(f.ctx, u, p) if err != nil { return nil, 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 6785eecdcd3..5990a1d4e6b 100644 --- a/vendor/github.com/vmware/govmomi/object/host_storage_system.go +++ b/vendor/github.com/vmware/govmomi/object/host_storage_system.go @@ -97,6 +97,15 @@ func (s HostStorageSystem) Refresh(ctx context.Context) error { return err } +func (s HostStorageSystem) RescanVmfs(ctx context.Context) error { + req := types.RescanVmfs{ + This: s.Reference(), + } + + _, err := methods.RescanVmfs(ctx, s.c, &req) + return err +} + func (s HostStorageSystem) MarkAsSsd(ctx context.Context, uuid string) (*Task, error) { req := types.MarkAsSsd_Task{ This: s.Reference(), @@ -152,3 +161,14 @@ func (s HostStorageSystem) MarkAsNonLocal(ctx context.Context, uuid string) (*Ta return NewTask(s.c, res.Returnval), nil } + +func (s HostStorageSystem) AttachScsiLun(ctx context.Context, uuid string) error { + req := types.AttachScsiLun{ + This: s.Reference(), + LunUuid: uuid, + } + + _, err := methods.AttachScsiLun(ctx, s.c, &req) + + return err +} 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 b26e2f71c25..7bea49d51e2 100644 --- a/vendor/github.com/vmware/govmomi/object/virtual_disk_manager.go +++ b/vendor/github.com/vmware/govmomi/object/virtual_disk_manager.go @@ -145,6 +145,47 @@ func (m VirtualDiskManager) DeleteVirtualDisk(ctx context.Context, name string, return NewTask(m.c, res.Returnval), nil } +// InflateVirtualDisk inflates a virtual disk. +func (m VirtualDiskManager) InflateVirtualDisk(ctx context.Context, name string, dc *Datacenter) (*Task, error) { + req := types.InflateVirtualDisk_Task{ + This: m.Reference(), + Name: name, + } + + if dc != nil { + ref := dc.Reference() + req.Datacenter = &ref + } + + res, err := methods.InflateVirtualDisk_Task(ctx, m.c, &req) + if err != nil { + return nil, err + } + + return NewTask(m.c, res.Returnval), nil +} + +// ShrinkVirtualDisk shrinks a virtual disk. +func (m VirtualDiskManager) ShrinkVirtualDisk(ctx context.Context, name string, dc *Datacenter, copy *bool) (*Task, error) { + req := types.ShrinkVirtualDisk_Task{ + This: m.Reference(), + Name: name, + Copy: copy, + } + + if dc != nil { + ref := dc.Reference() + req.Datacenter = &ref + } + + res, err := methods.ShrinkVirtualDisk_Task(ctx, m.c, &req) + if err != nil { + return nil, err + } + + 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{ 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 index 642cd62f6e9..dc747c121ba 100644 --- a/vendor/github.com/vmware/govmomi/object/virtual_disk_manager_internal.go +++ b/vendor/github.com/vmware/govmomi/object/virtual_disk_manager_internal.go @@ -95,3 +95,67 @@ func (m VirtualDiskManager) QueryVirtualDiskInfo(ctx context.Context, name strin return info.Result.(arrayOfVirtualDiskInfo).VirtualDiskInfo, nil } + +type createChildDiskTaskRequest struct { + This types.ManagedObjectReference `xml:"_this"` + ChildName string `xml:"childName"` + ChildDatacenter *types.ManagedObjectReference `xml:"childDatacenter,omitempty"` + ParentName string `xml:"parentName"` + ParentDatacenter *types.ManagedObjectReference `xml:"parentDatacenter,omitempty"` + IsLinkedClone bool `xml:"isLinkedClone"` +} + +type createChildDiskTaskResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} + +type createChildDiskTaskBody struct { + Req *createChildDiskTaskRequest `xml:"urn:internalvim25 CreateChildDisk_Task,omitempty"` + Res *createChildDiskTaskResponse `xml:"urn:vim25 CreateChildDisk_TaskResponse,omitempty"` + InternalRes *createChildDiskTaskResponse `xml:"urn:internalvim25 CreateChildDisk_TaskResponse,omitempty"` + Err *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *createChildDiskTaskBody) Fault() *soap.Fault { return b.Err } + +func createChildDiskTask(ctx context.Context, r soap.RoundTripper, req *createChildDiskTaskRequest) (*createChildDiskTaskResponse, error) { + var reqBody, resBody createChildDiskTaskBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + if resBody.Res != nil { + return resBody.Res, nil // vim-version <= 6.5 + } + + return resBody.InternalRes, nil // vim-version >= 6.7 +} + +func (m VirtualDiskManager) CreateChildDisk(ctx context.Context, parent string, pdc *Datacenter, name string, dc *Datacenter, linked bool) (*Task, error) { + req := createChildDiskTaskRequest{ + This: m.Reference(), + ChildName: name, + ParentName: parent, + IsLinkedClone: linked, + } + + if dc != nil { + ref := dc.Reference() + req.ChildDatacenter = &ref + } + + if pdc != nil { + ref := pdc.Reference() + req.ParentDatacenter = &ref + } + + res, err := createChildDiskTask(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return NewTask(m.Client(), res.Returnval), nil +} diff --git a/vendor/github.com/vmware/govmomi/property/collector.go b/vendor/github.com/vmware/govmomi/property/collector.go index 04a9e77373f..ccf712cf9d3 100644 --- a/vendor/github.com/vmware/govmomi/property/collector.go +++ b/vendor/github.com/vmware/govmomi/property/collector.go @@ -121,6 +121,10 @@ func (p *Collector) RetrieveProperties(ctx context.Context, req types.RetrievePr // of the specified managed objects, with the relevant properties filled in. If // the properties slice is nil, all properties are loaded. func (p *Collector) Retrieve(ctx context.Context, objs []types.ManagedObjectReference, ps []string, dst interface{}) error { + if len(objs) == 0 { + return errors.New("object references is empty") + } + var propSpec *types.PropertySpec var objectSet []types.ObjectSpec diff --git a/vendor/github.com/vmware/govmomi/simulator/BUILD b/vendor/github.com/vmware/govmomi/simulator/BUILD index dafff93c675..5b55f233bb2 100644 --- a/vendor/github.com/vmware/govmomi/simulator/BUILD +++ b/vendor/github.com/vmware/govmomi/simulator/BUILD @@ -11,12 +11,14 @@ go_library( "doc.go", "dvs.go", "entity.go", + "event_manager.go", "file_manager.go", "folder.go", "guest_id.go", "host_datastore_browser.go", "host_datastore_system.go", "host_firewall_system.go", + "host_local_account_manager.go", "host_network_system.go", "host_system.go", "ip_pool_manager.go", diff --git a/vendor/github.com/vmware/govmomi/simulator/authorization_manager.go b/vendor/github.com/vmware/govmomi/simulator/authorization_manager.go index b65db933e8f..969ca36704f 100644 --- a/vendor/github.com/vmware/govmomi/simulator/authorization_manager.go +++ b/vendor/github.com/vmware/govmomi/simulator/authorization_manager.go @@ -39,7 +39,8 @@ type AuthorizationManager struct { func NewAuthorizationManager(ref types.ManagedObjectReference) object.Reference { m := &AuthorizationManager{} m.Self = ref - m.RoleList = esx.RoleList + m.RoleList = make([]types.AuthorizationRole, len(esx.RoleList)) + copy(m.RoleList, esx.RoleList) m.permissions = make(map[types.ManagedObjectReference][]types.Permission) l := object.AuthorizationRoleList(m.RoleList) diff --git a/vendor/github.com/vmware/govmomi/simulator/cluster_compute_resource.go b/vendor/github.com/vmware/govmomi/simulator/cluster_compute_resource.go index fe51ae3e7c2..9bad77b76e4 100644 --- a/vendor/github.com/vmware/govmomi/simulator/cluster_compute_resource.go +++ b/vendor/github.com/vmware/govmomi/simulator/cluster_compute_resource.go @@ -17,6 +17,9 @@ limitations under the License. package simulator import ( + "sync/atomic" + + "github.com/google/uuid" "github.com/vmware/govmomi/simulator/esx" "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/mo" @@ -26,6 +29,8 @@ import ( type ClusterComputeResource struct { mo.ClusterComputeResource + + ruleKey int32 } type addHost struct { @@ -44,18 +49,18 @@ func (add *addHost) Run(task *Task) (types.AnyType, types.BaseMethodFault) { host := NewHostSystem(esx.HostSystem) host.Summary.Config.Name = spec.HostName host.Name = host.Summary.Config.Name - host.Runtime.ConnectionState = types.HostSystemConnectionStateDisconnected + if add.req.AsConnected { + host.Runtime.ConnectionState = types.HostSystemConnectionStateConnected + } else { + host.Runtime.ConnectionState = types.HostSystemConnectionStateDisconnected + } cr := add.ClusterComputeResource Map.PutEntity(cr, Map.NewEntity(host)) + host.Summary.Host = &host.Self cr.Host = append(cr.Host, host.Reference()) - - if add.req.AsConnected { - host.Runtime.ConnectionState = types.HostSystemConnectionStateConnected - } - - addComputeResource(add.ClusterComputeResource.Summary.GetComputeResourceSummary(), host) + addComputeResource(cr.Summary.GetComputeResourceSummary(), host) return host.Reference(), nil } @@ -68,6 +73,224 @@ func (c *ClusterComputeResource) AddHostTask(add *types.AddHost_Task) soap.HasFa } } +func (c *ClusterComputeResource) updateRules(cfg *types.ClusterConfigInfoEx, cspec *types.ClusterConfigSpecEx) types.BaseMethodFault { + for _, spec := range cspec.RulesSpec { + var i int + exists := false + + match := func(info types.BaseClusterRuleInfo) bool { + return info.GetClusterRuleInfo().Name == spec.Info.GetClusterRuleInfo().Name + } + + if spec.Operation == types.ArrayUpdateOperationRemove { + match = func(rule types.BaseClusterRuleInfo) bool { + return rule.GetClusterRuleInfo().Key == spec.ArrayUpdateSpec.RemoveKey.(int32) + } + } + + for i = range cfg.Rule { + if match(cfg.Rule[i].GetClusterRuleInfo()) { + exists = true + break + } + } + + switch spec.Operation { + case types.ArrayUpdateOperationAdd: + if exists { + return new(types.InvalidArgument) + } + info := spec.Info.GetClusterRuleInfo() + info.Key = atomic.AddInt32(&c.ruleKey, 1) + info.RuleUuid = uuid.New().String() + cfg.Rule = append(cfg.Rule, spec.Info) + case types.ArrayUpdateOperationEdit: + if !exists { + return new(types.InvalidArgument) + } + cfg.Rule[i] = spec.Info + case types.ArrayUpdateOperationRemove: + if !exists { + return new(types.InvalidArgument) + } + cfg.Rule = append(cfg.Rule[:i], cfg.Rule[i+1:]...) + } + } + + return nil +} + +func (c *ClusterComputeResource) updateGroups(cfg *types.ClusterConfigInfoEx, cspec *types.ClusterConfigSpecEx) types.BaseMethodFault { + for _, spec := range cspec.GroupSpec { + var i int + exists := false + + match := func(info types.BaseClusterGroupInfo) bool { + return info.GetClusterGroupInfo().Name == spec.Info.GetClusterGroupInfo().Name + } + + if spec.Operation == types.ArrayUpdateOperationRemove { + match = func(info types.BaseClusterGroupInfo) bool { + return info.GetClusterGroupInfo().Name == spec.ArrayUpdateSpec.RemoveKey.(string) + } + } + + for i = range cfg.Group { + if match(cfg.Group[i].GetClusterGroupInfo()) { + exists = true + break + } + } + + switch spec.Operation { + case types.ArrayUpdateOperationAdd: + if exists { + return new(types.InvalidArgument) + } + cfg.Group = append(cfg.Group, spec.Info) + case types.ArrayUpdateOperationEdit: + if !exists { + return new(types.InvalidArgument) + } + cfg.Group[i] = spec.Info + case types.ArrayUpdateOperationRemove: + if !exists { + return new(types.InvalidArgument) + } + cfg.Group = append(cfg.Group[:i], cfg.Group[i+1:]...) + } + } + + return nil +} + +func (c *ClusterComputeResource) updateOverridesDAS(cfg *types.ClusterConfigInfoEx, cspec *types.ClusterConfigSpecEx) types.BaseMethodFault { + for _, spec := range cspec.DasVmConfigSpec { + var i int + var key types.ManagedObjectReference + exists := false + + if spec.Operation == types.ArrayUpdateOperationRemove { + key = spec.RemoveKey.(types.ManagedObjectReference) + } else { + key = spec.Info.Key + } + + for i = range cfg.DasVmConfig { + if cfg.DasVmConfig[i].Key == key { + exists = true + break + } + } + + switch spec.Operation { + case types.ArrayUpdateOperationAdd: + if exists { + return new(types.InvalidArgument) + } + cfg.DasVmConfig = append(cfg.DasVmConfig, *spec.Info) + case types.ArrayUpdateOperationEdit: + if !exists { + return new(types.InvalidArgument) + } + src := spec.Info.DasSettings + if src == nil { + return new(types.InvalidArgument) + } + dst := cfg.DasVmConfig[i].DasSettings + if src.RestartPriority != "" { + dst.RestartPriority = src.RestartPriority + } + if src.RestartPriorityTimeout != 0 { + dst.RestartPriorityTimeout = src.RestartPriorityTimeout + } + case types.ArrayUpdateOperationRemove: + if !exists { + return new(types.InvalidArgument) + } + cfg.DasVmConfig = append(cfg.DasVmConfig[:i], cfg.DasVmConfig[i+1:]...) + } + } + + return nil +} + +func (c *ClusterComputeResource) updateOverridesDRS(cfg *types.ClusterConfigInfoEx, cspec *types.ClusterConfigSpecEx) types.BaseMethodFault { + for _, spec := range cspec.DrsVmConfigSpec { + var i int + var key types.ManagedObjectReference + exists := false + + if spec.Operation == types.ArrayUpdateOperationRemove { + key = spec.RemoveKey.(types.ManagedObjectReference) + } else { + key = spec.Info.Key + } + + for i = range cfg.DrsVmConfig { + if cfg.DrsVmConfig[i].Key == key { + exists = true + break + } + } + + switch spec.Operation { + case types.ArrayUpdateOperationAdd: + if exists { + return new(types.InvalidArgument) + } + cfg.DrsVmConfig = append(cfg.DrsVmConfig, *spec.Info) + case types.ArrayUpdateOperationEdit: + if !exists { + return new(types.InvalidArgument) + } + if spec.Info.Enabled != nil { + cfg.DrsVmConfig[i].Enabled = spec.Info.Enabled + } + if spec.Info.Behavior != "" { + cfg.DrsVmConfig[i].Behavior = spec.Info.Behavior + } + case types.ArrayUpdateOperationRemove: + if !exists { + return new(types.InvalidArgument) + } + cfg.DrsVmConfig = append(cfg.DrsVmConfig[:i], cfg.DrsVmConfig[i+1:]...) + } + } + + return nil +} + +func (c *ClusterComputeResource) ReconfigureComputeResourceTask(req *types.ReconfigureComputeResource_Task) soap.HasFault { + task := CreateTask(c, "reconfigureCluster", func(*Task) (types.AnyType, types.BaseMethodFault) { + spec, ok := req.Spec.(*types.ClusterConfigSpecEx) + if !ok { + return nil, new(types.InvalidArgument) + } + + updates := []func(*types.ClusterConfigInfoEx, *types.ClusterConfigSpecEx) types.BaseMethodFault{ + c.updateRules, + c.updateGroups, + c.updateOverridesDAS, + c.updateOverridesDRS, + } + + for _, update := range updates { + if err := update(c.ConfigurationEx.(*types.ClusterConfigInfoEx), spec); err != nil { + return nil, err + } + } + + return nil, nil + }) + + return &methods.ReconfigureComputeResource_TaskBody{ + Res: &types.ReconfigureComputeResource_TaskResponse{ + Returnval: task.Run(), + }, + } +} + func CreateClusterComputeResource(f *Folder, name string, spec types.ClusterConfigSpecEx) (*ClusterComputeResource, types.BaseMethodFault) { if e := Map.FindByName(name, f.ChildEntity); e != nil { return nil, &types.DuplicateName{ @@ -85,6 +308,7 @@ func CreateClusterComputeResource(f *Folder, name string, spec types.ClusterConf config := &types.ClusterConfigInfoEx{} cluster.ConfigurationEx = config + config.VmSwapPlacement = string(types.VirtualMachineConfigInfoSwapPlacementTypeVmDirectory) config.DrsConfig.Enabled = types.NewBool(true) pool := NewResourcePool() diff --git a/vendor/github.com/vmware/govmomi/simulator/custom_fields_manager.go b/vendor/github.com/vmware/govmomi/simulator/custom_fields_manager.go index 3ae5ef0302f..93955908b99 100644 --- a/vendor/github.com/vmware/govmomi/simulator/custom_fields_manager.go +++ b/vendor/github.com/vmware/govmomi/simulator/custom_fields_manager.go @@ -101,9 +101,11 @@ func (c *CustomFieldsManager) SetField(req *types.SetField) soap.HasFault { body := &methods.SetFieldBody{} entity := Map.Get(req.Entity).(mo.Entity).Entity() - entity.CustomValue = append(entity.CustomValue, &types.CustomFieldStringValue{ - CustomFieldValue: types.CustomFieldValue{Key: req.Key}, - Value: req.Value, + Map.WithLock(entity, func() { + entity.CustomValue = append(entity.CustomValue, &types.CustomFieldStringValue{ + CustomFieldValue: types.CustomFieldValue{Key: req.Key}, + Value: req.Value, + }) }) body.Res = &types.SetFieldResponse{} diff --git a/vendor/github.com/vmware/govmomi/simulator/datacenter.go b/vendor/github.com/vmware/govmomi/simulator/datacenter.go index 15b5d432424..e563e71d14f 100644 --- a/vendor/github.com/vmware/govmomi/simulator/datacenter.go +++ b/vendor/github.com/vmware/govmomi/simulator/datacenter.go @@ -74,3 +74,14 @@ func createDatacenterFolders(dc *mo.Datacenter, isVC bool) { net.putChild(network) } } + +func datacenterEventArgument(obj mo.Entity) *types.DatacenterEventArgument { + dc, ok := obj.(*mo.Datacenter) + if !ok { + dc = Map.getEntityDatacenter(obj) + } + return &types.DatacenterEventArgument{ + Datacenter: dc.Self, + EntityEventArgument: types.EntityEventArgument{Name: dc.Name}, + } +} diff --git a/vendor/github.com/vmware/govmomi/simulator/dvs.go b/vendor/github.com/vmware/govmomi/simulator/dvs.go index e60b5601092..b82838bd9e5 100644 --- a/vendor/github.com/vmware/govmomi/simulator/dvs.go +++ b/vendor/github.com/vmware/govmomi/simulator/dvs.go @@ -67,9 +67,10 @@ func (s *DistributedVirtualSwitch) AddDVPortgroupTask(c *types.AddDVPortgroup_Ta s.Summary.PortgroupName = append(s.Summary.PortgroupName, pg.Name) for _, h := range s.Summary.HostMember { - pg.Host = AddReference(h, pg.Host) + pg.Host = append(pg.Host, h) + host := Map.Get(h).(*HostSystem) - host.Network = append(host.Network, pg.Reference()) + Map.AppendReference(host, &host.Network, pg.Reference()) } } @@ -101,13 +102,13 @@ func (s *DistributedVirtualSwitch) ReconfigureDvsTask(req *types.ReconfigureDvs_ return nil, &types.AlreadyExists{Name: host.Name} } - host.Network = append(host.Network, s.Self) - host.Network = append(host.Network, s.Portgroup...) + Map.AppendReference(host, &host.Network, s.Self) + Map.AppendReference(host, &host.Network, s.Portgroup...) s.Summary.HostMember = append(s.Summary.HostMember, member.Host) for _, ref := range s.Portgroup { pg := Map.Get(ref).(*DistributedVirtualPortgroup) - pg.Host = AddReference(member.Host, pg.Host) + Map.AddReference(pg, &pg.Host, member.Host) } case types.ConfigSpecOperationRemove: if pg := FindReference(host.Network, s.Portgroup...); pg != nil { @@ -117,8 +118,8 @@ func (s *DistributedVirtualSwitch) ReconfigureDvsTask(req *types.ReconfigureDvs_ } } - host.Network = RemoveReference(s.Self, host.Network) - s.Summary.HostMember = RemoveReference(s.Self, s.Summary.HostMember) + Map.RemoveReference(host, &host.Network, s.Self) + RemoveReference(&s.Summary.HostMember, s.Self) case types.ConfigSpecOperationEdit: return nil, &types.NotSupported{} } diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/BUILD b/vendor/github.com/vmware/govmomi/simulator/esx/BUILD index acfb87ca798..873d15fc12c 100644 --- a/vendor/github.com/vmware/govmomi/simulator/esx/BUILD +++ b/vendor/github.com/vmware/govmomi/simulator/esx/BUILD @@ -6,6 +6,7 @@ go_library( "authorization_manager.go", "datacenter.go", "doc.go", + "event_manager.go", "host_config_info.go", "host_firewall_system.go", "host_hardware_info.go", diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/event_manager.go b/vendor/github.com/vmware/govmomi/simulator/esx/event_manager.go new file mode 100644 index 00000000000..81995c4d00f --- /dev/null +++ b/vendor/github.com/vmware/govmomi/simulator/esx/event_manager.go @@ -0,0 +1,236 @@ +/* +Copyright (c) 2018 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package esx + +import "github.com/vmware/govmomi/vim25/types" + +// EventInfo is the default template for the EventManager description.eventInfo property. +// Capture method: +// govc object.collect -s -dump EventManager:ha-eventmgr description.eventInfo +// The captured list has been manually pruned and FullFormat fields changed to use Go's template variable syntax. +var EventInfo = []types.EventDescriptionEventDetail{ + { + Key: "UserLoginSessionEvent", + Description: "User login", + Category: "info", + FullFormat: "User {{.UserName}}@{{.IpAddress}} logged in as {{.UserAgent}}", + }, + { + Key: "UserLogoutSessionEvent", + Description: "User logout", + Category: "info", + FullFormat: "User {{.UserName}}@{{.IpAddress}} logged out (login time: {{.LoginTime}}, number of API invocations: {{.CallCount}}, user agent: {{.UserAgent}})", + }, + { + Key: "DatacenterCreatedEvent", + Description: "Datacenter created", + Category: "info", + FullFormat: "Created datacenter {{.Datacenter.Name}} in folder {{.Parent.Name}}", + }, + { + Key: "DatastoreFileMovedEvent", + Description: "File or directory moved to datastore", + Category: "info", + FullFormat: "Move of file or directory {{.SourceFile}} from {{.SourceDatastore.Name}} to {{.Datastore.Name}} as {{.TargetFile}}", + }, + { + Key: "DatastoreFileCopiedEvent", + Description: "File or directory copied to datastore", + Category: "info", + FullFormat: "Copy of file or directory {{.SourceFile}} from {{.SourceDatastore.Name}} to {{.Datastore.Name}} as {{.TargetFile}}", + }, + { + Key: "DatastoreFileDeletedEvent", + Description: "File or directory deleted", + Category: "info", + FullFormat: "Deletion of file or directory {{.TargetFile}} from {{.Datastore.Name}} was initiated", + }, + { + Key: "EnteringMaintenanceModeEvent", + Description: "Entering maintenance mode", + Category: "info", + FullFormat: "Host {{.Host.Name}} in {{.Datacenter.Name}} has started to enter maintenance mode", + }, + { + Key: "EnteredMaintenanceModeEvent", + Description: "Entered maintenance mode", + Category: "info", + FullFormat: "Host {{.Host.Name}} in {{.Datacenter.Name}} has entered maintenance mode", + }, + { + Key: "ExitMaintenanceModeEvent", + Description: "Exit maintenance mode", + Category: "info", + FullFormat: "Host {{.Host.Name}} in {{.Datacenter.Name}} has exited maintenance mode", + }, + { + Key: "VmSuspendedEvent", + Description: "VM suspended", + Category: "info", + FullFormat: "{{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}} is suspended", + }, + { + Key: "VmMigratedEvent", + Description: "VM migrated", + Category: "info", + FullFormat: "Migration of virtual machine {{.Vm.Name}} from {{.SourceHost.Name}, {{.SourceDatastore.Name}} to {{.Host.Name}, {{.Ds.Name}} completed", + }, + { + Key: "VmBeingMigratedEvent", + Description: "VM migrating", + Category: "info", + FullFormat: "Relocating {{.Vm.Name}} from {{.Host.Name}, {{.Ds.Name}} in {{.Datacenter.Name}} to {{.DestHost.Name}, {{.DestDatastore.Name}} in {{.DestDatacenter.Name}}", + }, + { + Key: "VmMacAssignedEvent", + Description: "VM MAC assigned", + Category: "info", + FullFormat: "New MAC address ({{.Mac}}) assigned to adapter {{.Adapter}} for {{.Vm.Name}}", + }, + { + Key: "VmRegisteredEvent", + Description: "VM registered", + Category: "info", + FullFormat: "Registered {{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}}", + }, + { + Key: "VmReconfiguredEvent", + Description: "VM reconfigured", + Category: "info", + FullFormat: "Reconfigured {{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}}", + }, + { + Key: "VmGuestRebootEvent", + Description: "Guest reboot", + Category: "info", + FullFormat: "Guest OS reboot for {{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}}", + }, + { + Key: "VmBeingClonedEvent", + Description: "VM being cloned", + Category: "info", + FullFormat: "Cloning {{.Vm.Name}} on host {{.Host.Name}} in {{.Datacenter.Name}} to {{.DestName}} on host {{.DestHost.Name}}", + }, + { + Key: "VmClonedEvent", + Description: "VM cloned", + Category: "info", + FullFormat: "Clone of {{.SourceVm.Name}} completed", + }, + { + Key: "VmBeingDeployedEvent", + Description: "Deploying VM", + Category: "info", + FullFormat: "Deploying {{.Vm.Name}} on host {{.Host.Name}} in {{.Datacenter.Name}} from template {{.SrcTemplate.Name}}", + }, + { + Key: "VmDeployedEvent", + Description: "VM deployed", + Category: "info", + FullFormat: "Template {{.SrcTemplate.Name}} deployed on host {{.Host.Name}}", + }, + { + Key: "VmInstanceUuidAssignedEvent", + Description: "Assign a new instance UUID", + Category: "info", + FullFormat: "Assign a new instance UUID ({{.InstanceUuid}}) to {{.Vm.Name}}", + }, + { + Key: "VmPoweredOnEvent", + Description: "VM powered on", + Category: "info", + FullFormat: "{{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}} is powered on", + }, + { + Key: "VmStartingEvent", + Description: "VM starting", + Category: "info", + FullFormat: "{{.Vm.Name}} on host {{.Host.Name}} in {{.Datacenter.Name}} is starting", + }, + { + Key: "VmSuspendingEvent", + Description: "VM being suspended", + Category: "info", + FullFormat: "{{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}} is being suspended", + }, + { + Key: "VmResumingEvent", + Description: "VM resuming", + Category: "info", + FullFormat: "{{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}} is resumed", + }, + { + Key: "VmBeingCreatedEvent", + Description: "Creating VM", + Category: "info", + FullFormat: "Creating {{.Vm.Name}} on host {{.Host.Name}} in {{.Datacenter.Name}}", + }, + { + Key: "VmCreatedEvent", + Description: "VM created", + Category: "info", + FullFormat: "Created virtual machine {{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}}", + }, + { + Key: "VmRemovedEvent", + Description: "VM removed", + Category: "info", + FullFormat: "Removed {{.Vm.Name}} on {{.Host.Name}} from {{.Datacenter.Name}}", + }, + { + Key: "VmResettingEvent", + Description: "VM resetting", + Category: "info", + FullFormat: "{{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}} is reset", + }, + { + Key: "VmGuestShutdownEvent", + Description: "Guest OS shut down", + Category: "info", + FullFormat: "Guest OS shut down for {{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}}", + }, + { + Key: "VmUuidAssignedEvent", + Description: "VM UUID assigned", + Category: "info", + FullFormat: "Assigned new BIOS UUID ({{.Uuid}}) to {{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}}", + }, + { + Key: "VmPoweredOffEvent", + Description: "VM powered off", + Category: "info", + FullFormat: "{{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}} is powered off", + }, + { + Key: "VmRelocatedEvent", + Description: "VM relocated", + Category: "info", + FullFormat: "Completed the relocation of the virtual machine", + }, + { + Key: "DrsVmMigratedEvent", + Description: "DRS VM migrated", + Category: "info", + FullFormat: "DRS migrated {{.Vm.Name}} from {{.SourceHost.Name}} to {{.Host.Name}} in cluster {{.ComputeResource.Name}} in {{.Datacenter.Name}}", + }, + { + Key: "DrsVmPoweredOnEvent", + Description: "DRS VM powered on", + Category: "info", + FullFormat: "DRS powered On {{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}}", + }, +} diff --git a/vendor/github.com/vmware/govmomi/simulator/event_manager.go b/vendor/github.com/vmware/govmomi/simulator/event_manager.go new file mode 100644 index 00000000000..2df705e15c9 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/simulator/event_manager.go @@ -0,0 +1,386 @@ +/* +Copyright (c) 2018 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package simulator + +import ( + "bytes" + "container/ring" + "log" + "reflect" + "text/template" + "time" + + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/simulator/esx" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +var ( + maxPageSize = 1000 + logEvents = false +) + +type EventManager struct { + mo.EventManager + + root types.ManagedObjectReference + page *ring.Ring + key int32 + collectors map[types.ManagedObjectReference]*EventHistoryCollector + templates map[string]*template.Template +} + +func NewEventManager(ref types.ManagedObjectReference) object.Reference { + return &EventManager{ + EventManager: mo.EventManager{ + Self: ref, + Description: types.EventDescription{ + EventInfo: esx.EventInfo, + }, + MaxCollector: 1000, + }, + root: Map.content().RootFolder, + page: ring.New(maxPageSize), + collectors: make(map[types.ManagedObjectReference]*EventHistoryCollector), + templates: make(map[string]*template.Template), + } +} + +func (m *EventManager) CreateCollectorForEvents(ctx *Context, req *types.CreateCollectorForEvents) soap.HasFault { + body := new(methods.CreateCollectorForEventsBody) + size, err := validatePageSize(req.Filter.MaxCount) + if err != nil { + body.Fault_ = err + return body + } + + if len(m.collectors) >= int(m.MaxCollector) { + body.Fault_ = Fault("Too many event collectors to create", new(types.InvalidState)) + return body + } + + collector := &EventHistoryCollector{ + m: m, + page: ring.New(size), + } + collector.Filter = req.Filter + collector.fillPage(size) + + ref := ctx.Session.Put(collector).Reference() + m.collectors[ref] = collector + + body.Res = &types.CreateCollectorForEventsResponse{ + Returnval: ref, + } + + return body +} + +// formatMessage applies the EventDescriptionEventDetail.FullFormat template to the given event's FullFormattedMessage field. +func (m *EventManager) formatMessage(event types.BaseEvent) { + id := reflect.ValueOf(event).Elem().Type().Name() + e := event.GetEvent() + + t, ok := m.templates[id] + if !ok { + for _, info := range m.Description.EventInfo { + if info.Key == id { + t = template.Must(template.New(id).Parse(info.FullFormat)) + m.templates[id] = t + break + } + } + } + + var buf bytes.Buffer + if err := t.Execute(&buf, event); err != nil { + log.Print(err) + } + e.FullFormattedMessage = buf.String() + + if logEvents { + log.Printf("[%s] %s", id, e.FullFormattedMessage) + } +} + +func (m *EventManager) PostEvent(ctx *Context, req *types.PostEvent) soap.HasFault { + m.key++ + event := req.EventToPost.GetEvent() + event.Key = m.key + event.ChainId = event.Key + event.CreatedTime = time.Now() + event.UserName = ctx.Session.UserName + + m.page = m.page.Next() + m.page.Value = req.EventToPost + m.formatMessage(req.EventToPost) + + for _, c := range m.collectors { + if c.eventMatches(req.EventToPost) { + c.page = c.page.Next() + c.page.Value = event + } + } + + return &methods.PostEventBody{ + Res: new(types.PostEventResponse), + } +} + +type EventHistoryCollector struct { + mo.EventHistoryCollector + + m *EventManager + page *ring.Ring +} + +// doEntityEventArgument calls f for each entity argument in the event. +// If f returns true, the iteration stops. +func doEntityEventArgument(event types.BaseEvent, f func(types.ManagedObjectReference, *types.EntityEventArgument) bool) bool { + e := event.GetEvent() + + if arg := e.Vm; arg != nil { + if f(arg.Vm, &arg.EntityEventArgument) { + return true + } + } + + if arg := e.Host; arg != nil { + if f(arg.Host, &arg.EntityEventArgument) { + return true + } + } + + if arg := e.ComputeResource; arg != nil { + if f(arg.ComputeResource, &arg.EntityEventArgument) { + return true + } + } + + if arg := e.Ds; arg != nil { + if f(arg.Datastore, &arg.EntityEventArgument) { + return true + } + } + + if arg := e.Net; arg != nil { + if f(arg.Network, &arg.EntityEventArgument) { + return true + } + } + + if arg := e.Dvs; arg != nil { + if f(arg.Dvs, &arg.EntityEventArgument) { + return true + } + } + + if arg := e.Datacenter; arg != nil { + if f(arg.Datacenter, &arg.EntityEventArgument) { + return true + } + } + + return false +} + +// eventFilterSelf returns true if self is one of the entity arguments in the event. +func eventFilterSelf(event types.BaseEvent, self types.ManagedObjectReference) bool { + return doEntityEventArgument(event, func(ref types.ManagedObjectReference, _ *types.EntityEventArgument) bool { + return self == ref + }) +} + +// eventFilterChildren returns true if a child of self is one of the entity arguments in the event. +func eventFilterChildren(event types.BaseEvent, self types.ManagedObjectReference) bool { + return doEntityEventArgument(event, func(ref types.ManagedObjectReference, _ *types.EntityEventArgument) bool { + seen := false + + var match func(types.ManagedObjectReference) + + match = func(child types.ManagedObjectReference) { + if child == self { + seen = true + return + } + + walk(child, match) + } + + walk(ref, match) + + return seen + }) +} + +// entityMatches returns true if the spec Entity filter matches the event. +func (c *EventHistoryCollector) entityMatches(event types.BaseEvent, spec *types.EventFilterSpec) bool { + e := spec.Entity + if e == nil { + return true + } + + isRootFolder := c.m.root == e.Entity + + switch e.Recursion { + case types.EventFilterSpecRecursionOptionSelf: + return isRootFolder || eventFilterSelf(event, e.Entity) + case types.EventFilterSpecRecursionOptionChildren: + return eventFilterChildren(event, e.Entity) + case types.EventFilterSpecRecursionOptionAll: + if isRootFolder || eventFilterSelf(event, e.Entity) { + return true + } + return eventFilterChildren(event, e.Entity) + } + + return false +} + +// typeMatches returns true if one of the spec EventTypeId types matches the event. +func (c *EventHistoryCollector) typeMatches(event types.BaseEvent, spec *types.EventFilterSpec) bool { + if len(spec.EventTypeId) == 0 { + return true + } + + matches := func(name string) bool { + for _, id := range spec.EventTypeId { + if id == name { + return true + } + } + return false + } + kind := reflect.ValueOf(event).Elem().Type() + + if matches(kind.Name()) { + return true // concrete type + } + + field, ok := kind.FieldByNameFunc(matches) + if ok { + return field.Anonymous // base type (embedded field) + } + return false +} + +// eventMatches returns true one of the filters matches the event. +func (c *EventHistoryCollector) eventMatches(event types.BaseEvent) bool { + spec := c.Filter.(types.EventFilterSpec) + + if !c.typeMatches(event, &spec) { + return false + } + + // TODO: spec.Time, spec.UserName, etc + + return c.entityMatches(event, &spec) +} + +// filePage copies the manager's latest events into the collector's page with Filter applied. +func (c *EventHistoryCollector) fillPage(size int) { + l := c.page.Len() + delta := size - l + + if delta < 0 { + // Shrink ring size + c.page = c.page.Unlink(-delta) + return + } + + matches := 0 + mpage := c.m.page + page := c.page + + if delta != 0 { + // Grow ring size + c.page = c.page.Link(ring.New(delta)) + } + + for i := 0; i < maxPageSize; i++ { + event, ok := mpage.Value.(types.BaseEvent) + mpage = mpage.Prev() + if !ok { + continue + } + + if c.eventMatches(event) { + page.Value = event + page = page.Prev() + matches++ + if matches == size { + break + } + } + } +} + +func validatePageSize(count int32) (int, *soap.Fault) { + size := int(count) + + if size == 0 { + size = 10 // defaultPageSize + } else if size < 0 || size > maxPageSize { + return -1, Fault("", &types.InvalidArgument{InvalidProperty: "maxCount"}) + } + + return size, nil +} + +func (c *EventHistoryCollector) SetCollectorPageSize(ctx *Context, req *types.SetCollectorPageSize) soap.HasFault { + body := new(methods.SetCollectorPageSizeBody) + size, err := validatePageSize(req.MaxCount) + if err != nil { + body.Fault_ = err + return body + } + + ctx.WithLock(c.m, func() { + c.fillPage(size) + }) + + body.Res = new(types.SetCollectorPageSizeResponse) + return body +} + +func (c *EventHistoryCollector) DestroyCollector(ctx *Context, req *types.DestroyCollector) soap.HasFault { + ctx.Session.Remove(req.This) + + ctx.WithLock(c.m, func() { + delete(c.m.collectors, req.This) + }) + + return &methods.DestroyCollectorBody{ + Res: new(types.DestroyCollectorResponse), + } +} + +func (c *EventHistoryCollector) Get() mo.Reference { + clone := *c + + c.page.Do(func(val interface{}) { + if val == nil { + return + } + clone.LatestPage = append(clone.LatestPage, val.(types.BaseEvent)) + }) + + return &clone +} diff --git a/vendor/github.com/vmware/govmomi/simulator/file_manager.go b/vendor/github.com/vmware/govmomi/simulator/file_manager.go index 6e76b5fd02e..a0bb0348670 100644 --- a/vendor/github.com/vmware/govmomi/simulator/file_manager.go +++ b/vendor/github.com/vmware/govmomi/simulator/file_manager.go @@ -160,6 +160,7 @@ func (f *FileManager) MakeDirectory(req *types.MakeDirectory) soap.HasFault { return body } + body.Res = new(types.MakeDirectoryResponse) return body } diff --git a/vendor/github.com/vmware/govmomi/simulator/folder.go b/vendor/github.com/vmware/govmomi/simulator/folder.go index f5dea3291e5..6bb695927da 100644 --- a/vendor/github.com/vmware/govmomi/simulator/folder.go +++ b/vendor/github.com/vmware/govmomi/simulator/folder.go @@ -20,7 +20,6 @@ import ( "fmt" "math/rand" "path" - "sync" "github.com/google/uuid" @@ -32,12 +31,17 @@ import ( type Folder struct { mo.Folder +} - m sync.Mutex +func (f *Folder) eventArgument() types.FolderEventArgument { + return types.FolderEventArgument{ + Folder: f.Self, + EntityEventArgument: types.EntityEventArgument{Name: f.Name}, + } } // update references when objects are added/removed from a Folder -func (f *Folder) update(o mo.Reference, u func(types.ManagedObjectReference, []types.ManagedObjectReference) []types.ManagedObjectReference) { +func (f *Folder) update(o mo.Reference, u func(mo.Reference, *[]types.ManagedObjectReference, types.ManagedObjectReference)) { ref := o.Reference() if f.Parent == nil { @@ -53,9 +57,9 @@ func (f *Folder) update(o mo.Reference, u func(types.ManagedObjectReference, []t switch ref.Type { case "Network", "DistributedVirtualSwitch", "DistributedVirtualPortgroup": - dc.Network = u(ref, dc.Network) + u(dc, &dc.Network, ref) case "Datastore": - dc.Datastore = u(ref, dc.Datastore) + u(dc, &dc.Datastore, ref) } } @@ -70,12 +74,9 @@ func networkSummary(n *mo.Network) *types.NetworkSummary { func (f *Folder) putChild(o mo.Entity) { Map.PutEntity(f, o) - f.m.Lock() - defer f.m.Unlock() + f.ChildEntity = append(f.ChildEntity, o.Reference()) - f.ChildEntity = AddReference(o.Reference(), f.ChildEntity) - - f.update(o, AddReference) + f.update(o, Map.AddReference) switch e := o.(type) { case *mo.Network: @@ -90,12 +91,9 @@ func (f *Folder) putChild(o mo.Entity) { func (f *Folder) removeChild(o mo.Reference) { Map.Remove(o.Reference()) - f.m.Lock() - defer f.m.Unlock() + RemoveReference(&f.ChildEntity, o.Reference()) - f.ChildEntity = RemoveReference(o.Reference(), f.ChildEntity) - - f.update(o, RemoveReference) + f.update(o, Map.RemoveReference) } func (f *Folder) hasChildType(kind string) bool { @@ -195,7 +193,7 @@ func (p *StoragePod) MoveIntoFolderTask(c *types.MoveIntoFolder_Task) soap.HasFa return (&Folder{Folder: p.Folder}).MoveIntoFolderTask(c) } -func (f *Folder) CreateDatacenter(c *types.CreateDatacenter) soap.HasFault { +func (f *Folder) CreateDatacenter(ctx *Context, c *types.CreateDatacenter) soap.HasFault { r := &methods.CreateDatacenterBody{} if f.hasChildType("Datacenter") && f.hasChildType("Folder") { @@ -210,6 +208,15 @@ func (f *Folder) CreateDatacenter(c *types.CreateDatacenter) soap.HasFault { r.Res = &types.CreateDatacenterResponse{ Returnval: dc.Self, } + + ctx.postEvent(&types.DatacenterCreatedEvent{ + DatacenterEvent: types.DatacenterEvent{ + Event: types.Event{ + Datacenter: datacenterEventArgument(dc), + }, + }, + Parent: f.eventArgument(), + }) } else { r.Fault_ = f.typeNotSupported() } @@ -240,6 +247,7 @@ func (f *Folder) CreateClusterEx(c *types.CreateClusterEx) soap.HasFault { type createVM struct { *Folder + ctx *Context req *types.CreateVM_Task register bool @@ -291,27 +299,50 @@ func (c *createVM) Run(task *Task) (types.AnyType, types.BaseMethodFault) { c.Folder.putChild(vm) host := Map.Get(*vm.Runtime.Host).(*HostSystem) - host.Vm = append(host.Vm, vm.Self) + Map.AppendReference(host, &host.Vm, vm.Self) for i := range vm.Datastore { ds := Map.Get(vm.Datastore[i]).(*Datastore) - ds.Vm = append(ds.Vm, vm.Self) + Map.AppendReference(ds, &ds.Vm, vm.Self) } - switch rp := Map.Get(*vm.ResourcePool).(type) { - case *ResourcePool: - rp.Vm = append(rp.Vm, vm.Self) - case *VirtualApp: - rp.Vm = append(rp.Vm, vm.Self) - } + pool := Map.Get(*vm.ResourcePool) + // This can be an internal call from VirtualApp.CreateChildVMTask, where pool is already locked. + c.ctx.WithLock(pool, func() { + switch rp := pool.(type) { + case *ResourcePool: + rp.Vm = append(rp.Vm, vm.Self) + case *VirtualApp: + rp.Vm = append(rp.Vm, vm.Self) + } + }) + + event := vm.event() + c.ctx.postEvent( + &types.VmBeingCreatedEvent{ + VmEvent: event, + ConfigSpec: &c.req.Config, + }, + &types.VmInstanceUuidAssignedEvent{ + VmEvent: event, + InstanceUuid: vm.Config.InstanceUuid, + }, + &types.VmUuidAssignedEvent{ + VmEvent: event, + Uuid: vm.Config.Uuid, + }, + &types.VmCreatedEvent{ + VmEvent: event, + }, + ) return vm.Reference(), nil } -func (f *Folder) CreateVMTask(c *types.CreateVM_Task) soap.HasFault { +func (f *Folder) CreateVMTask(ctx *Context, c *types.CreateVM_Task) soap.HasFault { return &methods.CreateVM_TaskBody{ Res: &types.CreateVM_TaskResponse{ - Returnval: NewTask(&createVM{f, c, false}).Run(), + Returnval: NewTask(&createVM{f, ctx, c, false}).Run(), }, } } @@ -319,6 +350,7 @@ func (f *Folder) CreateVMTask(c *types.CreateVM_Task) soap.HasFault { type registerVM struct { *Folder + ctx *Context req *types.RegisterVM_Task } @@ -367,6 +399,7 @@ func (c *registerVM) Run(task *Task) (types.AnyType, types.BaseMethodFault) { create := NewTask(&createVM{ Folder: c.Folder, register: true, + ctx: c.ctx, req: &types.CreateVM_Task{ This: c.Folder.Reference(), Config: types.VirtualMachineConfigSpec{ @@ -389,10 +422,12 @@ func (c *registerVM) Run(task *Task) (types.AnyType, types.BaseMethodFault) { return create.Info.Result, nil } -func (f *Folder) RegisterVMTask(c *types.RegisterVM_Task) soap.HasFault { +func (f *Folder) RegisterVMTask(ctx *Context, c *types.RegisterVM_Task) soap.HasFault { + ctx.Caller = &f.Self + return &methods.RegisterVM_TaskBody{ Res: &types.RegisterVM_TaskResponse{ - Returnval: NewTask(®isterVM{f, c}).Run(), + Returnval: NewTask(®isterVM{f, ctx, c}).Run(), }, } } @@ -445,6 +480,33 @@ func (f *Folder) CreateDVSTask(req *types.CreateDVS_Task) soap.HasFault { Description: spec.Description, } + configInfo := &types.VMwareDVSConfigInfo{ + DVSConfigInfo: types.DVSConfigInfo{ + Uuid: dvs.Uuid, + Name: spec.Name, + ConfigVersion: spec.ConfigVersion, + NumStandalonePorts: spec.NumStandalonePorts, + MaxPorts: spec.MaxPorts, + UplinkPortPolicy: spec.UplinkPortPolicy, + UplinkPortgroup: spec.UplinkPortgroup, + DefaultPortConfig: spec.DefaultPortConfig, + ExtensionKey: spec.ExtensionKey, + Description: spec.Description, + Policy: spec.Policy, + VendorSpecificConfig: spec.VendorSpecificConfig, + SwitchIpAddress: spec.SwitchIpAddress, + DefaultProxySwitchMaxNumPorts: spec.DefaultProxySwitchMaxNumPorts, + InfrastructureTrafficResourceConfig: spec.InfrastructureTrafficResourceConfig, + NetworkResourceControlVersion: spec.NetworkResourceControlVersion, + }, + } + + if spec.Contact != nil { + configInfo.Contact = *spec.Contact + } + + dvs.Config = configInfo + if dvs.Summary.ProductInfo == nil { product := Map.content().About dvs.Summary.ProductInfo = &types.DistributedVirtualSwitchProductSpec{ diff --git a/vendor/github.com/vmware/govmomi/simulator/host_datastore_system.go b/vendor/github.com/vmware/govmomi/simulator/host_datastore_system.go index ff3fce83d4a..e6a2dcf3080 100644 --- a/vendor/github.com/vmware/govmomi/simulator/host_datastore_system.go +++ b/vendor/github.com/vmware/govmomi/simulator/host_datastore_system.go @@ -72,7 +72,7 @@ func (dss *HostDatastoreSystem) add(ds *Datastore) *soap.Fault { dss.Datastore = append(dss.Datastore, ds.Self) dss.Host.Datastore = dss.Datastore parent := hostParent(dss.Host) - parent.Datastore = AddReference(ds.Self, parent.Datastore) + Map.AddReference(parent, &parent.Datastore, ds.Self) browser := &HostDatastoreBrowser{} browser.Datastore = dss.Datastore diff --git a/vendor/github.com/vmware/govmomi/simulator/host_local_account_manager.go b/vendor/github.com/vmware/govmomi/simulator/host_local_account_manager.go new file mode 100644 index 00000000000..0d463310569 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/simulator/host_local_account_manager.go @@ -0,0 +1,80 @@ +/* +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 simulator + +import ( + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +// As of vSphere API 5.1, local groups operations are deprecated, so it's not supported here. + +type HostLocalAccountManager struct { + mo.HostLocalAccountManager +} + +func NewHostLocalAccountManager(ref types.ManagedObjectReference) object.Reference { + m := &HostLocalAccountManager{} + m.Self = ref + + return m +} + +func (h *HostLocalAccountManager) CreateUser(req *types.CreateUser) soap.HasFault { + spec := req.User.GetHostAccountSpec() + userDirectory := Map.UserDirectory() + + found := userDirectory.search(true, false, compareFunc(spec.Id, true)) + if len(found) > 0 { + return &methods.CreateUserBody{ + Fault_: Fault("", &types.AlreadyExists{}), + } + } + + userDirectory.addUser(spec.Id) + + return &methods.CreateUserBody{ + Res: &types.CreateUserResponse{}, + } +} + +func (h *HostLocalAccountManager) RemoveUser(req *types.RemoveUser) soap.HasFault { + userDirectory := Map.UserDirectory() + + found := userDirectory.search(true, false, compareFunc(req.UserName, true)) + + if len(found) == 0 { + return &methods.RemoveUserBody{ + Fault_: Fault("", &types.UserNotFound{}), + } + } + + userDirectory.removeUser(req.UserName) + + return &methods.RemoveUserBody{ + Res: &types.RemoveUserResponse{}, + } +} + +func (h *HostLocalAccountManager) UpdateUser(req *types.UpdateUser) soap.HasFault { + return &methods.CreateUserBody{ + Res: &types.CreateUserResponse{}, + } +} diff --git a/vendor/github.com/vmware/govmomi/simulator/host_system.go b/vendor/github.com/vmware/govmomi/simulator/host_system.go index 600dbcf3885..7facda38e2d 100644 --- a/vendor/github.com/vmware/govmomi/simulator/host_system.go +++ b/vendor/github.com/vmware/govmomi/simulator/host_system.go @@ -71,6 +71,22 @@ func NewHostSystem(host mo.HostSystem) *HostSystem { return hs } +func (h *HostSystem) eventArgument() *types.HostEventArgument { + return &types.HostEventArgument{ + Host: h.Self, + EntityEventArgument: types.EntityEventArgument{Name: h.Name}, + } +} + +func (h *HostSystem) eventArgumentParent() *types.ComputeResourceEventArgument { + parent := hostParent(&h.HostSystem) + + return &types.ComputeResourceEventArgument{ + ComputeResource: parent.Self, + EntityEventArgument: types.EntityEventArgument{Name: parent.Name}, + } +} + func hostParent(host *mo.HostSystem) *mo.ComputeResource { switch parent := Map.Get(*host.Parent).(type) { case *mo.ComputeResource: @@ -137,9 +153,15 @@ func CreateStandaloneHost(f *Folder, spec types.HostConnectSpec) (*HostSystem, t summary := new(types.ComputeResourceSummary) addComputeResource(summary, host) - cr := &mo.ComputeResource{Summary: summary} + cr := &mo.ComputeResource{ + ConfigurationEx: &types.ComputeResourceConfigInfo{ + VmSwapPlacement: string(types.VirtualMachineConfigInfoSwapPlacementTypeVmDirectory), + }, + Summary: summary, + } Map.PutEntity(cr, Map.NewEntity(host)) + host.Summary.Host = &host.Self Map.PutEntity(cr, Map.NewEntity(pool)) diff --git a/vendor/github.com/vmware/govmomi/simulator/model.go b/vendor/github.com/vmware/govmomi/simulator/model.go index 4bc26f9793f..22cc14078b7 100644 --- a/vendor/github.com/vmware/govmomi/simulator/model.go +++ b/vendor/github.com/vmware/govmomi/simulator/model.go @@ -34,13 +34,13 @@ import ( // This is a simple helper for tests running against a simulator, to populate an inventory // with commonly used models. type Model struct { - Service *Service + Service *Service `json:"-"` - ServiceContent types.ServiceContent - RootFolder mo.Folder + ServiceContent types.ServiceContent `json:"-"` + RootFolder mo.Folder `json:"-"` // Autostart will power on Model created VMs when true - Autostart bool + Autostart bool `json:"-"` // Datacenter specifies the number of Datacenter entities to create Datacenter int @@ -49,13 +49,13 @@ type Model struct { Portgroup int // Host specifies the number of standalone HostSystems entities to create per Datacenter - Host int + Host int `json:",omitempty"` // Cluster specifies the number of ClusterComputeResource entities to create per Datacenter Cluster int // ClusterHost specifies the number of HostSystems entities to create within a Cluster - ClusterHost int + ClusterHost int `json:",omitempty"` // Pool specifies the number of ResourcePool entities to create per Cluster Pool int @@ -233,6 +233,7 @@ func (m *Model) Create() error { cdrom, _ := devices.CreateCdrom(ide.(*types.VirtualIDEController)) disk := devices.CreateDisk(scsi.(types.BaseVirtualController), ds, config.Files.VmPathName+" "+path.Join(name, "disk1.vmdk")) + disk.CapacityInKB = 1024 devices = append(devices, scsi, cdrom, disk, &nic) diff --git a/vendor/github.com/vmware/govmomi/simulator/option_manager.go b/vendor/github.com/vmware/govmomi/simulator/option_manager.go index 4615882c364..4e2496775af 100644 --- a/vendor/github.com/vmware/govmomi/simulator/option_manager.go +++ b/vendor/github.com/vmware/govmomi/simulator/option_manager.go @@ -57,3 +57,42 @@ func (m *OptionManager) QueryOptions(req *types.QueryOptions) soap.HasFault { return body } + +func (m *OptionManager) find(key string) *types.OptionValue { + for _, opt := range m.Setting { + setting := opt.GetOptionValue() + if setting.Key == key { + return setting + } + } + return nil +} + +func (m *OptionManager) UpdateOptions(req *types.UpdateOptions) soap.HasFault { + body := new(methods.UpdateOptionsBody) + + for _, change := range req.ChangedValue { + setting := change.GetOptionValue() + + // We don't currently include the entire list of default settings for ESX and vCenter, + // this prefix is currently used to test the failure path. + // Real vCenter seems to only allow new options if Key has a "config." prefix. + // TODO: consider behaving the same, which would require including 2 long lists of options in vpx.Setting and esx.Setting + if strings.HasPrefix(setting.Key, "ENOENT.") { + body.Fault_ = Fault("", &types.InvalidName{Name: setting.Key}) + return body + } + + opt := m.find(setting.Key) + if opt != nil { + // This is an existing option. + opt.Value = setting.Value + continue + } + + m.Setting = append(m.Setting, change) + } + + body.Res = new(types.UpdateOptionsResponse) + return body +} diff --git a/vendor/github.com/vmware/govmomi/simulator/portgroup.go b/vendor/github.com/vmware/govmomi/simulator/portgroup.go index 434f5fd4728..af93a50062b 100644 --- a/vendor/github.com/vmware/govmomi/simulator/portgroup.go +++ b/vendor/github.com/vmware/govmomi/simulator/portgroup.go @@ -53,23 +53,12 @@ func (s *DistributedVirtualPortgroup) ReconfigureDVPortgroupTask(req *types.Reco func (s *DistributedVirtualPortgroup) DestroyTask(req *types.Destroy_Task) soap.HasFault { task := CreateTask(s, "destroy", func(t *Task) (types.AnyType, types.BaseMethodFault) { vswitch := Map.Get(*s.Config.DistributedVirtualSwitch).(*DistributedVirtualSwitch) - for i, pg := range vswitch.Portgroup { - if pg.Reference() == s.Reference() { - vswitch.Portgroup = append(vswitch.Portgroup[:i], vswitch.Portgroup[i+1:]...) - break - } - } + Map.RemoveReference(vswitch, &vswitch.Portgroup, s.Reference()) + Map.removeString(vswitch, &vswitch.Summary.PortgroupName, s.Name) f := Map.getEntityParent(vswitch, "Folder").(*Folder) f.removeChild(s.Reference()) - for i, name := range vswitch.Summary.PortgroupName { - if name == s.Name { - vswitch.Summary.PortgroupName = append(vswitch.Summary.PortgroupName[:i], - vswitch.Summary.PortgroupName[i+1:]...) - } - } - return nil, nil }) diff --git a/vendor/github.com/vmware/govmomi/simulator/property_collector.go b/vendor/github.com/vmware/govmomi/simulator/property_collector.go index 8ef7898d84d..8dc31744680 100644 --- a/vendor/github.com/vmware/govmomi/simulator/property_collector.go +++ b/vendor/github.com/vmware/govmomi/simulator/property_collector.go @@ -43,12 +43,35 @@ func NewPropertyCollector(ref types.ManagedObjectReference) object.Reference { var errMissingField = errors.New("missing field") var errEmptyField = errors.New("empty field") -func getObject(ref types.ManagedObjectReference) (reflect.Value, bool) { - obj := Map.Get(ref) +func getObject(ctx *Context, ref types.ManagedObjectReference) (reflect.Value, bool) { + var obj mo.Reference + if ctx.Session == nil { + // Even without permissions to access an object or specific fields, RetrieveProperties + // returns an ObjectContent response as long as the object exists. See retrieveResult.add() + obj = Map.Get(ref) + } else { + obj = ctx.Session.Get(ref) + } + if obj == nil { return reflect.Value{}, false } + if ctx.Session == nil && ref.Type == "SessionManager" { + // RetrieveProperties on SessionManager without a session always returns empty, + // rather than MissingSet + Fault.NotAuthenticated for each field. + obj = &mo.SessionManager{Self: ref} + } + + // For objects that use internal types that differ from that of the vim25/mo field types. + // See EventHistoryCollector for example. + type get interface { + Get() mo.Reference + } + if o, ok := obj.(get); ok { + obj = o.Get() + } + rval := reflect.ValueOf(obj).Elem() rtype := rval.Type() @@ -110,7 +133,6 @@ func fieldValueInterface(f reflect.StructField, rval reflect.Value) interface{} func fieldValue(rval reflect.Value, p string) (interface{}, error) { var value interface{} - fields := strings.Split(p, ".") for i, name := range fields { @@ -170,7 +192,7 @@ func isEmpty(rval reflect.Value) bool { switch rval.Kind() { case reflect.Ptr: return rval.IsNil() - case reflect.String, reflect.Slice: + case reflect.String: return rval.Len() == 0 } @@ -200,7 +222,27 @@ type retrieveResult struct { specs map[string]*types.TraversalSpec } -func (rr *retrieveResult) collectAll(rval reflect.Value, rtype reflect.Type, content *types.ObjectContent) { +func (rr *retrieveResult) add(ctx *Context, name string, val types.AnyType, content *types.ObjectContent) { + if ctx.Session != nil { + content.PropSet = append(content.PropSet, types.DynamicProperty{ + Name: name, + Val: val, + }) + return + } + + content.MissingSet = append(content.MissingSet, types.MissingProperty{ + Path: name, + Fault: types.LocalizedMethodFault{Fault: &types.NotAuthenticated{ + NoPermission: types.NoPermission{ + Object: content.Obj, + PrivilegeId: "System.Read", + }}, + }, + }) +} + +func (rr *retrieveResult) collectAll(ctx *Context, rval reflect.Value, rtype reflect.Type, content *types.ObjectContent) { for i := 0; i < rval.NumField(); i++ { val := rval.Field(i) @@ -212,18 +254,15 @@ func (rr *retrieveResult) collectAll(rval reflect.Value, rtype reflect.Type, con if f.Anonymous { // recurse into embedded field - rr.collectAll(val, f.Type, content) + rr.collectAll(ctx, val, f.Type, content) continue } - content.PropSet = append(content.PropSet, types.DynamicProperty{ - Name: lcFirst(f.Name), - Val: fieldValueInterface(f, val), - }) + rr.add(ctx, lcFirst(f.Name), fieldValueInterface(f, val), content) } } -func (rr *retrieveResult) collectFields(rval reflect.Value, fields []string, content *types.ObjectContent) { +func (rr *retrieveResult) collectFields(ctx *Context, rval reflect.Value, fields []string, content *types.ObjectContent) { seen := make(map[string]bool) for i := range content.PropSet { @@ -240,12 +279,7 @@ func (rr *retrieveResult) collectFields(rval reflect.Value, fields []string, con val, err := fieldValue(rval, name) if err == nil { - prop := types.DynamicProperty{ - Name: name, - Val: val, - } - - content.PropSet = append(content.PropSet, prop) + rr.add(ctx, name, val, content) continue } @@ -263,7 +297,7 @@ func (rr *retrieveResult) collectFields(rval reflect.Value, fields []string, con } } -func (rr *retrieveResult) collect(ref types.ManagedObjectReference) { +func (rr *retrieveResult) collect(ctx *Context, ref types.ManagedObjectReference) { if rr.collected[ref] { return } @@ -272,7 +306,7 @@ func (rr *retrieveResult) collect(ref types.ManagedObjectReference) { Obj: ref, } - rval, ok := getObject(ref) + rval, ok := getObject(ctx, ref) if !ok { // Possible if a test uses Map.Remove instead of Destroy_Task log.Printf("object %s no longer exists", ref) @@ -293,11 +327,11 @@ func (rr *retrieveResult) collect(ref types.ManagedObjectReference) { } if isTrue(p.All) { - rr.collectAll(rval, rtype, &content) + rr.collectAll(ctx, rval, rtype, &content) continue } - rr.collectFields(rval, p.PathSet, &content) + rr.collectFields(ctx, rval, p.PathSet, &content) } } @@ -308,10 +342,9 @@ func (rr *retrieveResult) collect(ref types.ManagedObjectReference) { rr.collected[ref] = true } -func (rr *retrieveResult) selectSet(obj reflect.Value, s []types.BaseSelectionSpec, refs *[]types.ManagedObjectReference) types.BaseMethodFault { +func (rr *retrieveResult) selectSet(ctx *Context, obj reflect.Value, s []types.BaseSelectionSpec, refs *[]types.ManagedObjectReference) types.BaseMethodFault { for _, ss := range s { ts, ok := ss.(*types.TraversalSpec) - if ok { if ts.Name != "" { rr.specs[ts.Name] = ts @@ -335,9 +368,9 @@ func (rr *retrieveResult) selectSet(obj reflect.Value, s []types.BaseSelectionSp *refs = append(*refs, ref) } - rval, ok := getObject(ref) + rval, ok := getObject(ctx, ref) if ok { - if err := rr.selectSet(rval, ts.SelectSet, refs); err != nil { + if err := rr.selectSet(ctx, rval, ts.SelectSet, refs); err != nil { return err } } @@ -347,7 +380,7 @@ func (rr *retrieveResult) selectSet(obj reflect.Value, s []types.BaseSelectionSp return nil } -func (pc *PropertyCollector) collect(r *types.RetrievePropertiesEx) (*types.RetrieveResult, types.BaseMethodFault) { +func (pc *PropertyCollector) collect(ctx *Context, r *types.RetrievePropertiesEx) (*types.RetrieveResult, types.BaseMethodFault) { var refs []types.ManagedObjectReference rr := &retrieveResult{ @@ -360,8 +393,7 @@ func (pc *PropertyCollector) collect(r *types.RetrievePropertiesEx) (*types.Retr // Select object references for _, spec := range r.SpecSet { for _, o := range spec.ObjectSet { - rval, ok := getObject(o.Obj) - + rval, ok := getObject(ctx, o.Obj) if !ok { if isFalse(spec.ReportMissingObjectsInResults) { return nil, &types.ManagedObjectNotFound{Obj: o.Obj} @@ -373,27 +405,27 @@ func (pc *PropertyCollector) collect(r *types.RetrievePropertiesEx) (*types.Retr refs = append(refs, o.Obj) } - if err := rr.selectSet(rval, o.SelectSet, &refs); err != nil { + if err := rr.selectSet(ctx, rval, o.SelectSet, &refs); err != nil { return nil, err } } } for _, ref := range refs { - rr.collect(ref) + rr.collect(ctx, ref) } return rr.RetrieveResult, nil } -func (pc *PropertyCollector) CreateFilter(c *types.CreateFilter) soap.HasFault { +func (pc *PropertyCollector) CreateFilter(ctx *Context, c *types.CreateFilter) soap.HasFault { body := &methods.CreateFilterBody{} filter := &PropertyFilter{pc: pc} filter.PartialUpdates = c.PartialUpdates filter.Spec = c.Spec - pc.Filter = append(pc.Filter, Map.Put(filter).Reference()) + pc.Filter = append(pc.Filter, ctx.Session.Put(filter).Reference()) body.Res = &types.CreateFilterResponse{ Returnval: filter.Self, @@ -402,37 +434,37 @@ func (pc *PropertyCollector) CreateFilter(c *types.CreateFilter) soap.HasFault { return body } -func (pc *PropertyCollector) CreatePropertyCollector(c *types.CreatePropertyCollector) soap.HasFault { +func (pc *PropertyCollector) CreatePropertyCollector(ctx *Context, c *types.CreatePropertyCollector) soap.HasFault { body := &methods.CreatePropertyCollectorBody{} cpc := &PropertyCollector{} body.Res = &types.CreatePropertyCollectorResponse{ - Returnval: Map.Put(cpc).Reference(), + Returnval: ctx.Session.Put(cpc).Reference(), } return body } -func (pc *PropertyCollector) DestroyPropertyCollector(c *types.DestroyPropertyCollector) soap.HasFault { +func (pc *PropertyCollector) DestroyPropertyCollector(ctx *Context, c *types.DestroyPropertyCollector) soap.HasFault { body := &methods.DestroyPropertyCollectorBody{} for _, ref := range pc.Filter { - filter := Map.Get(ref).(*PropertyFilter) + filter := ctx.Session.Get(ref).(*PropertyFilter) filter.DestroyPropertyFilter(&types.DestroyPropertyFilter{This: ref}) } - Map.Remove(c.This) + ctx.Session.Remove(c.This) body.Res = &types.DestroyPropertyCollectorResponse{} return body } -func (pc *PropertyCollector) RetrievePropertiesEx(r *types.RetrievePropertiesEx) soap.HasFault { +func (pc *PropertyCollector) RetrievePropertiesEx(ctx *Context, r *types.RetrievePropertiesEx) soap.HasFault { body := &methods.RetrievePropertiesExBody{} - res, fault := pc.collect(r) + res, fault := pc.collect(ctx, r) if fault != nil { body.Fault_ = Fault("", fault) @@ -446,10 +478,10 @@ func (pc *PropertyCollector) RetrievePropertiesEx(r *types.RetrievePropertiesEx) } // RetrieveProperties is deprecated, but govmomi is still using it at the moment. -func (pc *PropertyCollector) RetrieveProperties(r *types.RetrieveProperties) soap.HasFault { +func (pc *PropertyCollector) RetrieveProperties(ctx *Context, r *types.RetrieveProperties) soap.HasFault { body := &methods.RetrievePropertiesBody{} - res := pc.RetrievePropertiesEx(&types.RetrievePropertiesEx{ + res := pc.RetrievePropertiesEx(ctx, &types.RetrievePropertiesEx{ This: r.This, SpecSet: r.SpecSet, }) @@ -469,7 +501,7 @@ func (pc *PropertyCollector) CancelWaitForUpdates(r *types.CancelWaitForUpdates) return &methods.CancelWaitForUpdatesBody{Res: new(types.CancelWaitForUpdatesResponse)} } -func (pc *PropertyCollector) WaitForUpdatesEx(r *types.WaitForUpdatesEx) soap.HasFault { +func (pc *PropertyCollector) WaitForUpdatesEx(ctx *Context, r *types.WaitForUpdatesEx) soap.HasFault { body := &methods.WaitForUpdatesExBody{} // At the moment we need to support Task completion. Handlers can simply set the Task @@ -485,12 +517,12 @@ func (pc *PropertyCollector) WaitForUpdatesEx(r *types.WaitForUpdatesEx) soap.Ha } for _, ref := range pc.Filter { - filter := Map.Get(ref).(*PropertyFilter) + filter := ctx.Session.Get(ref).(*PropertyFilter) r := &types.RetrievePropertiesEx{} r.SpecSet = append(r.SpecSet, filter.Spec) - res, fault := pc.collect(r) + res, fault := pc.collect(ctx, r) if fault != nil { body.Fault_ = Fault("", fault) return body @@ -528,10 +560,10 @@ func (pc *PropertyCollector) WaitForUpdatesEx(r *types.WaitForUpdatesEx) soap.Ha } // WaitForUpdates is deprecated, but pyvmomi is still using it at the moment. -func (pc *PropertyCollector) WaitForUpdates(r *types.WaitForUpdates) soap.HasFault { +func (pc *PropertyCollector) WaitForUpdates(ctx *Context, r *types.WaitForUpdates) soap.HasFault { body := &methods.WaitForUpdatesBody{} - res := pc.WaitForUpdatesEx(&types.WaitForUpdatesEx{ + res := pc.WaitForUpdatesEx(ctx, &types.WaitForUpdatesEx{ This: r.This, Version: r.Version, }) diff --git a/vendor/github.com/vmware/govmomi/simulator/property_filter.go b/vendor/github.com/vmware/govmomi/simulator/property_filter.go index 0d7d9a38daf..99a74fb1c13 100644 --- a/vendor/github.com/vmware/govmomi/simulator/property_filter.go +++ b/vendor/github.com/vmware/govmomi/simulator/property_filter.go @@ -32,7 +32,7 @@ type PropertyFilter struct { func (f *PropertyFilter) DestroyPropertyFilter(c *types.DestroyPropertyFilter) soap.HasFault { body := &methods.DestroyPropertyFilterBody{} - f.pc.Filter = RemoveReference(c.This, f.pc.Filter) + RemoveReference(&f.pc.Filter, c.This) Map.Remove(c.This) diff --git a/vendor/github.com/vmware/govmomi/simulator/registry.go b/vendor/github.com/vmware/govmomi/simulator/registry.go index 2fdc55f10ea..c5d567d98bc 100644 --- a/vendor/github.com/vmware/govmomi/simulator/registry.go +++ b/vendor/github.com/vmware/govmomi/simulator/registry.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2018 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,7 +17,9 @@ limitations under the License. package simulator import ( + "encoding/json" "fmt" + "os" "reflect" "strings" "sync" @@ -55,6 +57,7 @@ type Registry struct { m sync.Mutex objects map[types.ManagedObjectReference]mo.Reference handlers map[types.ManagedObjectReference]RegisterObject + locks map[types.ManagedObjectReference]sync.Locker counter int } @@ -63,6 +66,7 @@ func NewRegistry() *Registry { r := &Registry{ objects: make(map[types.ManagedObjectReference]mo.Reference), handlers: make(map[types.ManagedObjectReference]RegisterObject), + locks: make(map[types.ManagedObjectReference]sync.Locker), } return r @@ -99,6 +103,11 @@ func (r *Registry) newReference(item mo.Reference) types.ManagedObjectReference return ref } +func (r *Registry) setReference(item mo.Reference, ref types.ManagedObjectReference) { + // mo.Reference() returns a value, not a pointer so use reflect to set the Self field + reflect.ValueOf(item).Elem().FieldByName("Self").Set(reflect.ValueOf(ref)) +} + // AddHandler adds a RegisterObject handler to the Registry. func (r *Registry) AddHandler(h RegisterObject) { r.handlers[h.Reference()] = h @@ -156,8 +165,7 @@ func (r *Registry) Put(item mo.Reference) mo.Reference { ref := item.Reference() if ref.Type == "" || ref.Value == "" { ref = r.newReference(item) - // mo.Reference() returns a value, not a pointer so use reflect to set the Self field - reflect.ValueOf(item).Elem().FieldByName("Self").Set(reflect.ValueOf(ref)) + r.setReference(item, ref) } if me, ok := item.(mo.Entity); ok { @@ -186,6 +194,7 @@ func (r *Registry) Remove(item types.ManagedObjectReference) { delete(r.objects, item) delete(r.handlers, item) + delete(r.locks, item) } // getEntityParent traverses up the inventory and returns the first object of type kind. @@ -278,29 +287,48 @@ func FindReference(refs []types.ManagedObjectReference, match ...types.ManagedOb return nil } -// RemoveReference returns a slice with ref removed from refs -func RemoveReference(ref types.ManagedObjectReference, refs []types.ManagedObjectReference) []types.ManagedObjectReference { - var result []types.ManagedObjectReference - - for i, r := range refs { - if r == ref { - result = append(result, refs[i+1:]...) - break - } - - result = append(result, r) - } - - return result +// AppendReference appends the given refs to field. +func (r *Registry) AppendReference(obj mo.Reference, field *[]types.ManagedObjectReference, ref ...types.ManagedObjectReference) { + r.WithLock(obj, func() { + *field = append(*field, ref...) + }) } -// AddReference returns a slice with ref appended if not already in refs. -func AddReference(ref types.ManagedObjectReference, refs []types.ManagedObjectReference) []types.ManagedObjectReference { - if FindReference(refs, ref) == nil { - return append(refs, ref) - } +// AddReference appends ref to field if not already in the given field. +func (r *Registry) AddReference(obj mo.Reference, field *[]types.ManagedObjectReference, ref types.ManagedObjectReference) { + r.WithLock(obj, func() { + if FindReference(*field, ref) == nil { + *field = append(*field, ref) + } + }) +} - return refs +// RemoveReference removes ref from the given field. +func RemoveReference(field *[]types.ManagedObjectReference, ref types.ManagedObjectReference) { + for i, r := range *field { + if r == ref { + *field = append((*field)[:i], (*field)[i+1:]...) + break + } + } +} + +// RemoveReference removes ref from the given field. +func (r *Registry) RemoveReference(obj mo.Reference, field *[]types.ManagedObjectReference, ref types.ManagedObjectReference) { + r.WithLock(obj, func() { + RemoveReference(field, ref) + }) +} + +func (r *Registry) removeString(obj mo.Reference, field *[]string, val string) { + r.WithLock(obj, func() { + for i, name := range *field { + if name == val { + *field = append((*field)[:i], (*field)[i+1:]...) + break + } + } + }) } func (r *Registry) content() types.ServiceContent { @@ -322,6 +350,11 @@ func (r *Registry) SearchIndex() *SearchIndex { return r.Get(r.content().SearchIndex.Reference()).(*SearchIndex) } +// EventManager returns the EventManager singleton +func (r *Registry) EventManager() *EventManager { + return r.Get(r.content().EventManager.Reference()).(*EventManager) +} + // FileManager returns the FileManager singleton func (r *Registry) FileManager() *FileManager { return r.Get(r.content().FileManager.Reference()).(*FileManager) @@ -336,3 +369,57 @@ func (r *Registry) VirtualDiskManager() *VirtualDiskManager { func (r *Registry) ViewManager() *ViewManager { return r.Get(r.content().ViewManager.Reference()).(*ViewManager) } + +// UserDirectory returns the UserDirectory singleton +func (r *Registry) UserDirectory() *UserDirectory { + return r.Get(r.content().UserDirectory.Reference()).(*UserDirectory) +} + +// SessionManager returns the SessionManager singleton +func (r *Registry) SessionManager() *SessionManager { + return r.Get(r.content().SessionManager.Reference()).(*SessionManager) +} + +func (r *Registry) MarshalJSON() ([]byte, error) { + r.m.Lock() + defer r.m.Unlock() + + vars := struct { + Objects int + Locks int + }{ + len(r.objects), + len(r.locks), + } + + return json.Marshal(vars) +} + +func (r *Registry) locker(obj mo.Reference) sync.Locker { + if mu, ok := obj.(sync.Locker); ok { + return mu + } + + ref := obj.Reference() + r.m.Lock() + mu, ok := r.locks[ref] + if !ok { + mu = new(sync.Mutex) + r.locks[ref] = mu + } + r.m.Unlock() + + return mu +} + +var enableLocker = os.Getenv("VCSIM_LOCKER") != "false" + +// WithLock holds a lock for the given object while then given function is run. +func (r *Registry) WithLock(obj mo.Reference, f func()) { + if enableLocker { + mu := r.locker(obj) + mu.Lock() + defer mu.Unlock() + } + f() +} diff --git a/vendor/github.com/vmware/govmomi/simulator/resource_pool.go b/vendor/github.com/vmware/govmomi/simulator/resource_pool.go index 604f7b44dbd..81b909ae6cb 100644 --- a/vendor/github.com/vmware/govmomi/simulator/resource_pool.go +++ b/vendor/github.com/vmware/govmomi/simulator/resource_pool.go @@ -252,12 +252,13 @@ func (p *ResourcePool) CreateVApp(req *types.CreateVApp) soap.HasFault { return body } -func (a *VirtualApp) CreateChildVMTask(req *types.CreateChildVM_Task) soap.HasFault { +func (a *VirtualApp) CreateChildVMTask(ctx *Context, req *types.CreateChildVM_Task) soap.HasFault { + ctx.Caller = &a.Self body := &methods.CreateChildVM_TaskBody{} folder := Map.Get(*a.ParentFolder).(*Folder) - res := folder.CreateVMTask(&types.CreateVM_Task{ + res := folder.CreateVMTask(ctx, &types.CreateVM_Task{ This: folder.Self, Config: req.Config, Host: req.Host, @@ -286,18 +287,19 @@ func (p *ResourcePool) DestroyTask(req *types.Destroy_Task) soap.HasFault { parent := &pp.ResourcePool // Remove child reference from rp - parent.ResourcePool = RemoveReference(req.This, parent.ResourcePool) + Map.RemoveReference(parent, &parent.ResourcePool, req.This) // The grandchildren become children of the parent (rp) - parent.ResourcePool = append(parent.ResourcePool, p.ResourcePool.ResourcePool...) + Map.AppendReference(parent, &parent.ResourcePool, p.ResourcePool.ResourcePool...) // And VMs move to the parent vms := p.ResourcePool.Vm - for _, vm := range vms { - Map.Get(vm).(*VirtualMachine).ResourcePool = &parent.Self + for _, ref := range vms { + vm := Map.Get(ref).(*VirtualMachine) + Map.WithLock(vm, func() { vm.ResourcePool = &parent.Self }) } - parent.Vm = append(parent.Vm, vms...) + Map.AppendReference(parent, &parent.Vm, vms...) Map.Remove(req.This) diff --git a/vendor/github.com/vmware/govmomi/simulator/service_instance.go b/vendor/github.com/vmware/govmomi/simulator/service_instance.go index 4f6a3bbe7db..465b4ccdc19 100644 --- a/vendor/github.com/vmware/govmomi/simulator/service_instance.go +++ b/vendor/github.com/vmware/govmomi/simulator/service_instance.go @@ -62,6 +62,7 @@ func NewServiceInstance(content types.ServiceContent, folder mo.Folder) *Service NewLicenseManager(*s.Content.LicenseManager), NewSearchIndex(*s.Content.SearchIndex), NewViewManager(*s.Content.ViewManager), + NewEventManager(*s.Content.EventManager), NewTaskManager(*s.Content.TaskManager), NewUserDirectory(*s.Content.UserDirectory), NewOptionManager(s.Content.Setting, setting), @@ -75,6 +76,10 @@ func NewServiceInstance(content types.ServiceContent, folder mo.Folder) *Service objects = append(objects, NewIpPoolManager(*s.Content.IpPoolManager)) } + if s.Content.AccountManager != nil { + objects = append(objects, NewHostLocalAccountManager(*s.Content.AccountManager)) + } + for _, o := range objects { Map.Put(o) } diff --git a/vendor/github.com/vmware/govmomi/simulator/session_manager.go b/vendor/github.com/vmware/govmomi/simulator/session_manager.go index 92a8f9b0941..d6c47c468b2 100644 --- a/vendor/github.com/vmware/govmomi/simulator/session_manager.go +++ b/vendor/github.com/vmware/govmomi/simulator/session_manager.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2018 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,6 +17,10 @@ limitations under the License. package simulator import ( + "context" + "fmt" + "net/http" + "strings" "time" "github.com/google/uuid" @@ -33,26 +37,30 @@ type SessionManager struct { mo.SessionManager ServiceHostName string + + sessions map[string]Session } func NewSessionManager(ref types.ManagedObjectReference) object.Reference { - s := &SessionManager{} + s := &SessionManager{ + sessions: make(map[string]Session), + } s.Self = ref return s } -func (s *SessionManager) Login(login *types.Login) soap.HasFault { +func (s *SessionManager) Login(ctx *Context, login *types.Login) soap.HasFault { body := &methods.LoginBody{} if login.Locale == "" { login.Locale = session.Locale } - if login.UserName == "" || login.Password == "" { - body.Fault_ = Fault("Login failure", &types.InvalidLogin{}) + if login.UserName == "" || login.Password == "" || ctx.Session != nil { + body.Fault_ = invalidLogin } else { - body.Res = &types.LoginResponse{ - Returnval: types.UserSession{ + session := Session{ + UserSession: types.UserSession{ Key: uuid.New().String(), UserName: login.UserName, FullName: login.UserName, @@ -61,16 +69,80 @@ func (s *SessionManager) Login(login *types.Login) soap.HasFault { Locale: login.Locale, MessageLocale: login.Locale, }, + Registry: NewRegistry(), + } + + ctx.SetSession(session, true) + + body.Res = &types.LoginResponse{ + Returnval: session.UserSession, } } return body } -func (s *SessionManager) Logout(*types.Logout) soap.HasFault { +func (s *SessionManager) Logout(ctx *Context, _ *types.Logout) soap.HasFault { + session := ctx.Session + delete(s.sessions, session.Key) + + ctx.postEvent(&types.UserLogoutSessionEvent{ + IpAddress: session.IpAddress, + UserAgent: session.UserAgent, + SessionId: session.Key, + LoginTime: &session.LoginTime, + }) + return &methods.LogoutBody{Res: new(types.LogoutResponse)} } +func (s *SessionManager) TerminateSession(ctx *Context, req *types.TerminateSession) soap.HasFault { + body := new(methods.TerminateSessionBody) + + for _, id := range req.SessionId { + if id == ctx.Session.Key { + body.Fault_ = Fault("", new(types.InvalidArgument)) + return body + } + delete(s.sessions, id) + } + + body.Res = new(types.TerminateSessionResponse) + return body +} + +func (s *SessionManager) AcquireCloneTicket(ctx *Context, _ *types.AcquireCloneTicket) soap.HasFault { + session := *ctx.Session + session.Key = uuid.New().String() + s.sessions[session.Key] = session + + return &methods.AcquireCloneTicketBody{ + Res: &types.AcquireCloneTicketResponse{ + Returnval: session.Key, + }, + } +} + +func (s *SessionManager) CloneSession(ctx *Context, ticket *types.CloneSession) soap.HasFault { + body := new(methods.CloneSessionBody) + + session, exists := s.sessions[ticket.CloneTicket] + + if exists { + delete(s.sessions, ticket.CloneTicket) // A clone ticket can only be used once + session.Key = uuid.New().String() + ctx.SetSession(session, true) + + body.Res = &types.CloneSessionResponse{ + Returnval: session.UserSession, + } + } else { + body.Fault_ = invalidLogin + } + + return body +} + func (s *SessionManager) AcquireGenericServiceTicket(ticket *types.AcquireGenericServiceTicket) soap.HasFault { return &methods.AcquireGenericServiceTicketBody{ Res: &types.AcquireGenericServiceTicketResponse{ @@ -81,3 +153,125 @@ func (s *SessionManager) AcquireGenericServiceTicket(ticket *types.AcquireGeneri }, } } + +// internalContext is the session for use by the in-memory client (Service.RoundTrip) +var internalContext = &Context{ + Context: context.Background(), + Session: &Session{ + UserSession: types.UserSession{ + Key: uuid.New().String(), + }, + Registry: NewRegistry(), + }, +} + +var invalidLogin = Fault("Login failure", new(types.InvalidLogin)) + +// Context provides per-request Session management. +type Context struct { + req *http.Request + res http.ResponseWriter + m *SessionManager + + context.Context + Session *Session + Caller *types.ManagedObjectReference +} + +// mapSession maps an HTTP cookie to a Session. +func (c *Context) mapSession() { + if cookie, err := c.req.Cookie(soap.SessionCookieName); err == nil { + if val, ok := c.m.sessions[cookie.Value]; ok { + c.SetSession(val, false) + } + } +} + +// SetSession should be called after successful authentication. +func (c *Context) SetSession(session Session, login bool) { + session.UserAgent = c.req.UserAgent() + session.IpAddress = strings.Split(c.req.RemoteAddr, ":")[0] + session.LastActiveTime = time.Now() + + c.m.sessions[session.Key] = session + c.Session = &session + + if login { + http.SetCookie(c.res, &http.Cookie{ + Name: soap.SessionCookieName, + Value: session.Key, + }) + + c.postEvent(&types.UserLoginSessionEvent{ + SessionId: session.Key, + IpAddress: session.IpAddress, + UserAgent: session.UserAgent, + Locale: session.Locale, + }) + } +} + +// WithLock holds a lock for the given object while then given function is run. +func (c *Context) WithLock(obj mo.Reference, f func()) { + if c.Caller != nil && *c.Caller == obj.Reference() { + // Internal method invocation, obj is already locked + f() + return + } + Map.WithLock(obj, f) +} + +// postEvent wraps EventManager.PostEvent for internal use, with a lock on the EventManager. +func (c *Context) postEvent(events ...types.BaseEvent) { + m := Map.EventManager() + c.WithLock(m, func() { + for _, event := range events { + m.PostEvent(c, &types.PostEvent{EventToPost: event}) + } + }) +} + +// Session combines a UserSession and a Registry for per-session managed objects. +type Session struct { + types.UserSession + *Registry +} + +// Put wraps Registry.Put, setting the moref value to include the session key. +func (s *Session) Put(item mo.Reference) mo.Reference { + ref := item.Reference() + if ref.Value == "" { + ref.Value = fmt.Sprintf("session[%s]%s", s.Key, uuid.New()) + } + s.Registry.setReference(item, ref) + return s.Registry.Put(item) +} + +// Get wraps Registry.Get, session-izing singleton objects such as SessionManager and the root PropertyCollector. +func (s *Session) Get(ref types.ManagedObjectReference) mo.Reference { + obj := s.Registry.Get(ref) + if obj != nil { + return obj + } + + // Return a session "view" of certain singleton objects + switch ref.Type { + case "SessionManager": + // Clone SessionManager so the PropertyCollector can properly report CurrentSession + m := *Map.SessionManager() + m.CurrentSession = &s.UserSession + + // TODO: we could maintain SessionList as part of the SessionManager singleton + for _, session := range m.sessions { + m.SessionList = append(m.SessionList, session.UserSession) + } + + return &m + case "PropertyCollector": + if ref == Map.content().PropertyCollector { + return s.Put(NewPropertyCollector(ref)) + } + } + + return Map.Get(ref) +} diff --git a/vendor/github.com/vmware/govmomi/simulator/simulator.go b/vendor/github.com/vmware/govmomi/simulator/simulator.go index 9a9cf0194bf..f6a656f1096 100644 --- a/vendor/github.com/vmware/govmomi/simulator/simulator.go +++ b/vendor/github.com/vmware/govmomi/simulator/simulator.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2018 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -59,10 +59,12 @@ type Method struct { // Service decodes incoming requests and dispatches to a Handler type Service struct { client *vim25.Client + sm *SessionManager readAll func(io.Reader) ([]byte, error) - TLS *tls.Config + TLS *tls.Config + ServeMux *http.ServeMux } // Server provides a simulator Service over HTTP @@ -77,6 +79,7 @@ type Server struct { func New(instance *ServiceInstance) *Service { s := &Service{ readAll: ioutil.ReadAll, + sm: Map.SessionManager(), } s.client, _ = vim25.NewClient(context.Background(), s) @@ -106,8 +109,29 @@ func Fault(msg string, fault types.BaseMethodFault) *soap.Fault { return f } -func (s *Service) call(method *Method) soap.HasFault { +func (s *Service) call(ctx *Context, method *Method) soap.HasFault { handler := Map.Get(method.This) + session := ctx.Session + + if session == nil { + switch method.Name { + case "RetrieveServiceContent", "Login", "RetrieveProperties", "RetrievePropertiesEx", "CloneSession": + // ok for now, TODO: authz + default: + fault := &types.NotAuthenticated{ + NoPermission: types.NoPermission{ + Object: method.This, + PrivilegeId: "System.View", + }, + } + return &serverFaultBody{Reason: Fault("", fault)} + } + } else { + // Prefer the Session.Registry, ServiceContent.PropertyCollector filter field for example is per-session + if h := session.Get(method.This); h != nil { + handler = h + } + } if handler == nil { msg := fmt.Sprintf("managed object not found: %s", method.This) @@ -141,7 +165,14 @@ func (s *Service) call(method *Method) soap.HasFault { } } - res := m.Call([]reflect.Value{reflect.ValueOf(method.Body)}) + var args, res []reflect.Value + if m.Type().NumIn() == 2 { + args = append(args, reflect.ValueOf(ctx)) + } + args = append(args, reflect.ValueOf(method.Body)) + Map.WithLock(handler, func() { + res = m.Call(args) + }) return res[0].Interface().(soap.HasFault) } @@ -165,7 +196,10 @@ func (s *Service) RoundTrip(ctx context.Context, request, response soap.HasFault Body: req.Interface(), } - res := s.call(method) + res := s.call(&Context{ + Context: ctx, + Session: internalContext.Session, + }, method) if err := res.Fault(); err != nil { return soap.WrapSoapFault(err) @@ -226,7 +260,11 @@ func (s *Service) About(w http.ResponseWriter, r *http.Request) { } seen[m.Name] = true - if m.Type.NumIn() != 2 || m.Type.NumOut() != 1 || m.Type.Out(0) != f { + in := m.Type.NumIn() + if in < 2 || in > 3 { // at least 2 params (receiver and request), optionally a 3rd param (context) + continue + } + if m.Type.NumOut() != 1 || m.Type.Out(0) != f { // all methods return soap.HasFault continue } @@ -262,6 +300,15 @@ func (s *Service) ServeSDK(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(os.Stderr, "Request: %s\n", string(body)) } + ctx := &Context{ + req: r, + res: w, + m: s.sm, + + Context: context.Background(), + } + Map.WithLock(s.sm, ctx.mapSession) + var res soap.HasFault var soapBody interface{} @@ -269,7 +316,7 @@ func (s *Service) ServeSDK(w http.ResponseWriter, r *http.Request) { if err != nil { res = serverFault(err.Error()) } else { - res = s.call(method) + res = s.call(ctx, method) } if f := res.Fault(); f != nil { @@ -349,20 +396,10 @@ func (s *Service) ServeDatastore(w http.ResponseWriter, r *http.Request) { return } - file := strings.TrimPrefix(r.URL.Path, folderPrefix) - p := path.Join(ds.Info.GetDatastoreInfo().Url, file) + r.URL.Path = strings.TrimPrefix(r.URL.Path, folderPrefix) + p := path.Join(ds.Info.GetDatastoreInfo().Url, r.URL.Path) switch r.Method { - case "GET": - f, err := os.Open(p) - if err != nil { - log.Printf("failed to %s '%s': %s", r.Method, p, err) - w.WriteHeader(http.StatusNotFound) - return - } - defer f.Close() - - _, _ = io.Copy(w, f) case "POST": _, err := os.Stat(p) if err == nil { @@ -384,7 +421,9 @@ func (s *Service) ServeDatastore(w http.ResponseWriter, r *http.Request) { _, _ = io.Copy(f, r.Body) default: - w.WriteHeader(http.StatusMethodNotAllowed) + fs := http.FileServer(http.Dir(ds.Info.GetDatastoreInfo().Url)) + + fs.ServeHTTP(w, r) } } @@ -408,7 +447,11 @@ func (*Service) ServiceVersions(w http.ResponseWriter, r *http.Request) { // NewServer returns an http Server instance for the given service func (s *Service) NewServer() *Server { - mux := http.NewServeMux() + mux := s.ServeMux + if mux == nil { + mux = http.NewServeMux() + } + path := "/sdk" mux.HandleFunc(path, s.ServeSDK) @@ -428,7 +471,7 @@ func (s *Service) NewServer() *Server { } // Redirect clients to this http server, rather than HostSystem.Name - Map.Get(*s.client.ServiceContent.SessionManager).(*SessionManager).ServiceHostName = u.Host + Map.SessionManager().ServiceHostName = u.Host if f := flag.Lookup("httptest.serve"); f != nil { // Avoid the blocking behaviour of httptest.Server.Start() when this flag is set @@ -491,7 +534,23 @@ func (s *Server) Close() { } } -var typeFunc = types.TypeFunc() +var ( + vim25MapType = types.TypeFunc() + typeFunc = defaultMapType +) + +func defaultMapType(name string) (reflect.Type, bool) { + typ, ok := vim25MapType(name) + if !ok { + // See TestIssue945, in which case Go does not resolve the namespace and name == "ns1:TraversalSpec" + // Without this hack, the SelectSet would be all nil's + kind := strings.SplitN(name, ":", 2) + if len(kind) == 2 { + typ, ok = vim25MapType(kind[1]) + } + } + return typ, ok +} // UnmarshalBody extracts the Body from a soap.Envelope and unmarshals to the corresponding govmomi type func UnmarshalBody(data []byte) (*Method, error) { diff --git a/vendor/github.com/vmware/govmomi/simulator/snapshot.go b/vendor/github.com/vmware/govmomi/simulator/snapshot.go index ad98fbf3c42..d3b40b25dfe 100644 --- a/vendor/github.com/vmware/govmomi/simulator/snapshot.go +++ b/vendor/github.com/vmware/govmomi/simulator/snapshot.go @@ -32,13 +32,14 @@ func (v *VirtualMachineSnapshot) RemoveSnapshotTask(req *types.RemoveSnapshot_Ta Map.Remove(req.This) vm := Map.Get(v.Vm).(*VirtualMachine) + Map.WithLock(vm, func() { + if vm.Snapshot.CurrentSnapshot != nil && *vm.Snapshot.CurrentSnapshot == req.This { + parent := findParentSnapshotInTree(vm.Snapshot.RootSnapshotList, req.This) + vm.Snapshot.CurrentSnapshot = parent + } - if vm.Snapshot.CurrentSnapshot != nil && *vm.Snapshot.CurrentSnapshot == req.This { - parent := findParentSnapshotInTree(vm.Snapshot.RootSnapshotList, req.This) - vm.Snapshot.CurrentSnapshot = parent - } - - vm.Snapshot.RootSnapshotList = removeSnapshotInTree(vm.Snapshot.RootSnapshotList, req.This, req.RemoveChildren) + vm.Snapshot.RootSnapshotList = removeSnapshotInTree(vm.Snapshot.RootSnapshotList, req.This, req.RemoveChildren) + }) return nil, nil }) @@ -54,8 +55,7 @@ func (v *VirtualMachineSnapshot) RevertToSnapshotTask(req *types.RevertToSnapsho task := CreateTask(v, "revertToSnapshot", func(t *Task) (types.AnyType, types.BaseMethodFault) { vm := Map.Get(v.Vm).(*VirtualMachine) - ref := v.Reference() - vm.Snapshot.CurrentSnapshot = &ref + Map.WithLock(vm, func() { vm.Snapshot.CurrentSnapshot = &v.Self }) return nil, nil }) diff --git a/vendor/github.com/vmware/govmomi/simulator/user_directory.go b/vendor/github.com/vmware/govmomi/simulator/user_directory.go index 2a2f0a3aabc..6c474f9016e 100644 --- a/vendor/github.com/vmware/govmomi/simulator/user_directory.go +++ b/vendor/github.com/vmware/govmomi/simulator/user_directory.go @@ -50,14 +50,7 @@ func NewUserDirectory(ref types.ManagedObjectReference) object.Reference { func (u *UserDirectory) RetrieveUserGroups(req *types.RetrieveUserGroups) soap.HasFault { compare := compareFunc(req.SearchStr, req.ExactMatch) - var res []types.BaseUserSearchResult - for _, ug := range u.userGroup { - if req.FindUsers && !ug.Group || req.FindGroups && ug.Group { - if compare(ug.Principal) { - res = append(res, ug) - } - } - } + res := u.search(req.FindUsers, req.FindGroups, compare) body := &methods.RetrieveUserGroupsBody{ Res: &types.RetrieveUserGroupsResponse{ @@ -68,6 +61,45 @@ func (u *UserDirectory) RetrieveUserGroups(req *types.RetrieveUserGroups) soap.H return body } +func (u *UserDirectory) search(findUsers, findGroups bool, compare func(string) bool) (res []types.BaseUserSearchResult) { + for _, ug := range u.userGroup { + if findUsers && !ug.Group || findGroups && ug.Group { + if compare(ug.Principal) { + res = append(res, ug) + } + } + } + + return res +} + +func (u *UserDirectory) addUser(id string) { + u.add(id, false) +} + +func (u *UserDirectory) removeUser(id string) { + u.remove(id, false) +} + +func (u *UserDirectory) add(id string, group bool) { + user := &types.UserSearchResult{ + FullName: id, + Group: group, + Principal: id, + } + + u.userGroup = append(u.userGroup, user) +} + +func (u *UserDirectory) remove(id string, group bool) { + for i, ug := range u.userGroup { + if ug.Group == group && ug.Principal == id { + u.userGroup = append(u.userGroup[:i], u.userGroup[i+1:]...) + return + } + } +} + func compareFunc(compared string, exactly bool) func(string) bool { return func(s string) bool { if exactly { diff --git a/vendor/github.com/vmware/govmomi/simulator/view_manager.go b/vendor/github.com/vmware/govmomi/simulator/view_manager.go index 959f22847b9..157e7003a69 100644 --- a/vendor/github.com/vmware/govmomi/simulator/view_manager.go +++ b/vendor/github.com/vmware/govmomi/simulator/view_manager.go @@ -71,14 +71,14 @@ func NewViewManager(ref types.ManagedObjectReference) object.Reference { func destroyView(ref types.ManagedObjectReference) soap.HasFault { m := Map.ViewManager() - m.ViewList = RemoveReference(ref, m.ViewList) + RemoveReference(&m.ViewList, ref) return &methods.DestroyViewBody{ Res: &types.DestroyViewResponse{}, } } -func (m *ViewManager) CreateContainerView(req *types.CreateContainerView) soap.HasFault { +func (m *ViewManager) CreateContainerView(ctx *Context, req *types.CreateContainerView) soap.HasFault { body := &methods.CreateContainerViewBody{} root := Map.Get(req.Container) @@ -117,7 +117,7 @@ func (m *ViewManager) CreateContainerView(req *types.CreateContainerView) soap.H } } - Map.Put(container) + ctx.Session.Put(container) m.ViewList = append(m.ViewList, container.Reference()) @@ -125,7 +125,8 @@ func (m *ViewManager) CreateContainerView(req *types.CreateContainerView) soap.H Returnval: container.Self, } - container.add(root) + seen := make(map[types.ManagedObjectReference]bool) + container.add(root, seen) return body } @@ -148,7 +149,7 @@ func (v *ContainerView) include(o types.ManagedObjectReference) bool { return v.types[o.Type] } -func (v *ContainerView) add(root mo.Reference) { +func walk(root mo.Reference, f func(child types.ManagedObjectReference)) { var children []types.ManagedObjectReference switch e := root.(type) { @@ -173,12 +174,21 @@ func (v *ContainerView) add(root mo.Reference) { } for _, child := range children { + f(child) + } +} + +func (v *ContainerView) add(root mo.Reference, seen map[types.ManagedObjectReference]bool) { + walk(root, func(child types.ManagedObjectReference) { if v.include(child) { - v.View = AddReference(child, v.View) + if seen[child] == false { + seen[child] = true + v.View = append(v.View, child) + } } if v.Recursive { - v.add(Map.Get(child)) + v.add(Map.Get(child), seen) } - } + }) } diff --git a/vendor/github.com/vmware/govmomi/simulator/virtual_disk_manager.go b/vendor/github.com/vmware/govmomi/simulator/virtual_disk_manager.go index ba37e42ed6b..af4377d40cd 100644 --- a/vendor/github.com/vmware/govmomi/simulator/virtual_disk_manager.go +++ b/vendor/github.com/vmware/govmomi/simulator/virtual_disk_manager.go @@ -45,7 +45,7 @@ func (m *VirtualDiskManager) names(name string) []string { } } -func (m *VirtualDiskManager) createVirtualDisk(req *types.CreateVirtualDisk_Task) types.BaseMethodFault { +func (m *VirtualDiskManager) createVirtualDisk(op types.VirtualDeviceConfigSpecFileOperation, req *types.CreateVirtualDisk_Task) types.BaseMethodFault { fm := Map.FileManager() file, fault := fm.resolve(req.Datacenter, req.Name) @@ -53,10 +53,23 @@ func (m *VirtualDiskManager) createVirtualDisk(req *types.CreateVirtualDisk_Task return fault } + shouldReplace := op == types.VirtualDeviceConfigSpecFileOperationReplace + shouldExist := op == "" for _, name := range m.names(file) { _, err := os.Stat(name) if err == nil { + if shouldExist { + return nil + } + if shouldReplace { + if err = os.Truncate(file, 0); err != nil { + return fm.fault(name, err, new(types.CannotCreateFile)) + } + return nil + } return fm.fault(name, nil, new(types.FileAlreadyExists)) + } else if shouldExist { + return fm.fault(name, nil, new(types.FileNotFound)) } f, err := os.Create(name) @@ -72,7 +85,7 @@ func (m *VirtualDiskManager) createVirtualDisk(req *types.CreateVirtualDisk_Task func (m *VirtualDiskManager) CreateVirtualDiskTask(req *types.CreateVirtualDisk_Task) soap.HasFault { task := CreateTask(m, "createVirtualDisk", func(*Task) (types.AnyType, types.BaseMethodFault) { - return nil, m.createVirtualDisk(req) + return nil, m.createVirtualDisk(types.VirtualDeviceConfigSpecFileOperationCreate, req) }) return &methods.CreateVirtualDisk_TaskBody{ diff --git a/vendor/github.com/vmware/govmomi/simulator/virtual_machine.go b/vendor/github.com/vmware/govmomi/simulator/virtual_machine.go index 640a280dc58..0c3ba1cc459 100644 --- a/vendor/github.com/vmware/govmomi/simulator/virtual_machine.go +++ b/vendor/github.com/vmware/govmomi/simulator/virtual_machine.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2018 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,7 +18,6 @@ package simulator import ( "fmt" - "io" "log" "net" "os" @@ -40,8 +39,7 @@ import ( type VirtualMachine struct { mo.VirtualMachine - log *log.Logger - out io.Closer + log string sid int32 } @@ -58,15 +56,22 @@ func NewVirtualMachine(parent types.ManagedObjectReference, spec *types.VirtualM } rspec := types.DefaultResourceConfigSpec() + vm.Guest = &types.GuestInfo{} vm.Config = &types.VirtualMachineConfigInfo{ ExtraConfig: []types.BaseOptionValue{&types.OptionValue{Key: "govcsim", Value: "TRUE"}}, Tools: &types.ToolsConfigInfo{}, MemoryAllocation: &rspec.MemoryAllocation, CpuAllocation: &rspec.CpuAllocation, } + vm.Snapshot = &types.VirtualMachineSnapshotInfo{} + vm.Storage = &types.VirtualMachineStorageInfo{ + Timestamp: time.Now(), + } vm.Summary.Guest = &types.VirtualMachineGuestSummary{} - vm.Summary.Storage = &types.VirtualMachineStorageSummary{} vm.Summary.Vm = &vm.Self + vm.Summary.Storage = &types.VirtualMachineStorageSummary{ + Timestamp: time.Now(), + } // Append VM Name as the directory name if not specified if strings.HasSuffix(spec.Files.VmPathName, "]") { // e.g. "[datastore1]" @@ -84,6 +89,7 @@ func NewVirtualMachine(parent types.ManagedObjectReference, spec *types.VirtualM NumCoresPerSocket: 1, MemoryMB: 32, Uuid: uuid.New().String(), + InstanceUuid: uuid.New().String(), Version: "vmx-11", Files: &types.VirtualMachineFileInfo{ SnapshotDirectory: dsPath, @@ -111,6 +117,22 @@ func NewVirtualMachine(parent types.ManagedObjectReference, spec *types.VirtualM return vm, nil } +func (vm *VirtualMachine) event() types.VmEvent { + host := Map.Get(*vm.Runtime.Host).(*HostSystem) + + return types.VmEvent{ + Event: types.Event{ + Datacenter: datacenterEventArgument(host), + ComputeResource: host.eventArgumentParent(), + Host: host.eventArgument(), + Vm: &types.VmEventArgument{ + EntityEventArgument: types.EntityEventArgument{Name: vm.Name}, + Vm: vm.Self, + }, + }, + } +} + func (vm *VirtualMachine) apply(spec *types.VirtualMachineConfigSpec) { if spec.Files == nil { spec.Files = new(types.VirtualMachineFileInfo) @@ -120,6 +142,12 @@ func (vm *VirtualMachine) apply(spec *types.VirtualMachineConfigSpec) { src string dst *string }{ + {spec.AlternateGuestName, &vm.Config.AlternateGuestName}, + {spec.Annotation, &vm.Config.Annotation}, + {spec.Firmware, &vm.Config.Firmware}, + {spec.InstanceUuid, &vm.Config.InstanceUuid}, + {spec.LocationId, &vm.Config.LocationId}, + {spec.NpivWorldWideNameType, &vm.Config.NpivWorldWideNameType}, {spec.Name, &vm.Name}, {spec.Name, &vm.Config.Name}, {spec.Name, &vm.Summary.Config.Name}, @@ -129,6 +157,9 @@ func (vm *VirtualMachine) apply(spec *types.VirtualMachineConfigSpec) { {spec.GuestId, &vm.Summary.Config.GuestId}, {spec.GuestId, &vm.Summary.Config.GuestFullName}, {spec.Uuid, &vm.Config.Uuid}, + {spec.Uuid, &vm.Summary.Config.Uuid}, + {spec.InstanceUuid, &vm.Config.InstanceUuid}, + {spec.InstanceUuid, &vm.Summary.Config.InstanceUuid}, {spec.Version, &vm.Config.Version}, {spec.Files.VmPathName, &vm.Config.Files.VmPathName}, {spec.Files.VmPathName, &vm.Summary.Config.VmPathName}, @@ -142,6 +173,76 @@ func (vm *VirtualMachine) apply(spec *types.VirtualMachineConfigSpec) { } } + applyb := []struct { + src *bool + dst **bool + }{ + {spec.NestedHVEnabled, &vm.Config.NestedHVEnabled}, + {spec.CpuHotAddEnabled, &vm.Config.CpuHotAddEnabled}, + {spec.CpuHotRemoveEnabled, &vm.Config.CpuHotRemoveEnabled}, + {spec.GuestAutoLockEnabled, &vm.Config.GuestAutoLockEnabled}, + {spec.MemoryHotAddEnabled, &vm.Config.MemoryHotAddEnabled}, + {spec.MemoryReservationLockedToMax, &vm.Config.MemoryReservationLockedToMax}, + {spec.MessageBusTunnelEnabled, &vm.Config.MessageBusTunnelEnabled}, + {spec.NpivTemporaryDisabled, &vm.Config.NpivTemporaryDisabled}, + {spec.NpivOnNonRdmDisks, &vm.Config.NpivOnNonRdmDisks}, + {spec.ChangeTrackingEnabled, &vm.Config.ChangeTrackingEnabled}, + } + + for _, f := range applyb { + if f.src != nil { + *f.dst = f.src + } + } + + if spec.Flags != nil { + vm.Config.Flags = *spec.Flags + } + + if spec.LatencySensitivity != nil { + vm.Config.LatencySensitivity = spec.LatencySensitivity + } + + if spec.ManagedBy != nil { + vm.Config.ManagedBy = spec.ManagedBy + } + + if spec.BootOptions != nil { + vm.Config.BootOptions = spec.BootOptions + } + + if spec.RepConfig != nil { + vm.Config.RepConfig = spec.RepConfig + } + + if spec.Tools != nil { + vm.Config.Tools = spec.Tools + } + + if spec.ConsolePreferences != nil { + vm.Config.ConsolePreferences = spec.ConsolePreferences + } + + if spec.CpuAffinity != nil { + vm.Config.CpuAffinity = spec.CpuAffinity + } + + if spec.CpuAllocation != nil { + vm.Config.CpuAllocation = spec.CpuAllocation + } + + if spec.MemoryAffinity != nil { + vm.Config.MemoryAffinity = spec.MemoryAffinity + } + + if spec.MemoryAllocation != nil { + vm.Config.MemoryAllocation = spec.MemoryAllocation + } + + if spec.LatencySensitivity != nil { + vm.Config.LatencySensitivity = spec.LatencySensitivity + } + if spec.MemoryMB != 0 { vm.Config.Hardware.MemoryMB = int32(spec.MemoryMB) vm.Summary.Config.MemorySizeMB = vm.Config.Hardware.MemoryMB @@ -152,11 +253,13 @@ func (vm *VirtualMachine) apply(spec *types.VirtualMachineConfigSpec) { vm.Summary.Config.NumCpu = vm.Config.Hardware.NumCPU } + if spec.NumCoresPerSocket != 0 { + vm.Config.Hardware.NumCoresPerSocket = spec.NumCoresPerSocket + } + vm.Config.ExtraConfig = append(vm.Config.ExtraConfig, spec.ExtraConfig...) vm.Config.Modified = time.Now() - - vm.Summary.Config.Uuid = vm.Config.Uuid } func validateGuestID(id string) types.BaseMethodFault { @@ -198,16 +301,13 @@ func (vm *VirtualMachine) useDatastore(name string) *Datastore { ds := Map.FindByName(name, host.Datastore).(*Datastore) - vm.Datastore = AddReference(ds.Self, vm.Datastore) + if FindReference(vm.Datastore, ds.Self) == nil { + vm.Datastore = append(vm.Datastore, ds.Self) + } return ds } -func (vm *VirtualMachine) setLog(w io.WriteCloser) { - vm.out = w - vm.log = log.New(w, "vmx ", log.Flags()) -} - func (vm *VirtualMachine) createFile(spec string, name string, register bool) (*os.File, types.BaseMethodFault) { p, fault := parseDatastorePath(spec) if fault != nil { @@ -263,17 +363,29 @@ func (vm *VirtualMachine) createFile(spec string, name string, register bool) (* return f, nil } +// Rather than keep an fd open for each VM, open/close the log for each messages. +// This is ok for now as we do not do any heavy VM logging. +func (vm *VirtualMachine) logPrintf(format string, v ...interface{}) { + f, err := os.OpenFile(vm.log, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0) + if err != nil { + log.Println(err) + return + } + log.New(f, "vmx ", log.Flags()).Printf(format, v...) + _ = f.Close() +} + func (vm *VirtualMachine) create(spec *types.VirtualMachineConfigSpec, register bool) types.BaseMethodFault { vm.apply(spec) files := []struct { spec string name string - use func(w io.WriteCloser) + use *string }{ {vm.Config.Files.VmPathName, "", nil}, {vm.Config.Files.VmPathName, fmt.Sprintf("%s.nvram", vm.Name), nil}, - {vm.Config.Files.LogDirectory, "vmware.log", vm.setLog}, + {vm.Config.Files.LogDirectory, "vmware.log", &vm.log}, } for _, file := range files { @@ -281,15 +393,13 @@ func (vm *VirtualMachine) create(spec *types.VirtualMachineConfigSpec, register if err != nil { return err } - if file.use != nil { - file.use(f) - } else { - _ = f.Close() + *file.use = f.Name() } + _ = f.Close() } - vm.log.Print("created") + vm.logPrintf("created") return vm.configureDevices(spec) } @@ -310,7 +420,8 @@ func (vm *VirtualMachine) generateMAC() string { return mac.String() } -func (vm *VirtualMachine) configureDevice(devices object.VirtualDeviceList, device types.BaseVirtualDevice) types.BaseMethodFault { +func (vm *VirtualMachine) configureDevice(devices object.VirtualDeviceList, spec *types.VirtualDeviceConfigSpec) types.BaseMethodFault { + device := spec.Device d := device.GetVirtualDevice() var controller types.BaseVirtualController @@ -371,7 +482,7 @@ func (vm *VirtualMachine) configureDevice(devices object.VirtualDeviceList, devi info.FileName = filename } - err := dm.createVirtualDisk(&types.CreateVirtualDisk_Task{ + err := dm.createVirtualDisk(spec.FileOperation, &types.CreateVirtualDisk_Task{ Datacenter: &dc.Self, Name: info.FileName, }) @@ -381,10 +492,10 @@ func (vm *VirtualMachine) configureDevice(devices object.VirtualDeviceList, devi p, _ := parseDatastorePath(info.FileName) - info.Datastore = &types.ManagedObjectReference{ - Type: "Datastore", - Value: p.Datastore, - } + host := Map.Get(*vm.Runtime.Host).(*HostSystem) + ds := Map.FindByName(p.Datastore, host.Datastore).Reference() + + info.Datastore = &ds } } @@ -448,6 +559,9 @@ func (vm *VirtualMachine) genVmdkPath() (string, types.BaseMethodFault) { } func (vm *VirtualMachine) configureDevices(spec *types.VirtualMachineConfigSpec) types.BaseMethodFault { + dc := Map.getEntityDatacenter(Map.Get(*vm.Parent).(mo.Entity)) + dm := Map.VirtualDiskManager() + devices := object.VirtualDeviceList(vm.Config.Hardware.Device) for i, change := range spec.DeviceChange { @@ -466,7 +580,7 @@ func (vm *VirtualMachine) configureDevices(spec *types.VirtualMachineConfigSpec) devices = removeDevice(devices, device) } - err := vm.configureDevice(devices, dspec.Device) + err := vm.configureDevice(devices, dspec) if err != nil { return err } @@ -474,6 +588,23 @@ func (vm *VirtualMachine) configureDevices(spec *types.VirtualMachineConfigSpec) devices = append(devices, dspec.Device) case types.VirtualDeviceConfigSpecOperationRemove: devices = removeDevice(devices, dspec.Device) + + disk, ok := dspec.Device.(*types.VirtualDisk) + if ok && dspec.FileOperation == types.VirtualDeviceConfigSpecFileOperationDestroy { + var file string + + switch b := disk.Backing.(type) { + case types.BaseVirtualDeviceFileBackingInfo: + file = b.GetVirtualDeviceFileBackingInfo().FileName + } + + if file != "" { + dm.DeleteVirtualDiskTask(&types.DeleteVirtualDisk_Task{ + Name: file, + Datacenter: &dc.Self, + }) + } + } } } @@ -486,10 +617,11 @@ type powerVMTask struct { *VirtualMachine state types.VirtualMachinePowerState + ctx *Context } func (c *powerVMTask) Run(task *Task) (types.AnyType, types.BaseMethodFault) { - c.log.Printf("running power task: requesting %s, existing %s", + c.logPrintf("running power task: requesting %s, existing %s", c.state, c.VirtualMachine.Runtime.PowerState) if c.VirtualMachine.Runtime.PowerState == c.state { @@ -510,11 +642,28 @@ func (c *powerVMTask) Run(task *Task) (types.AnyType, types.BaseMethodFault) { *bt = nil } + event := c.event() + switch c.state { + case types.VirtualMachinePowerStatePoweredOn: + c.ctx.postEvent( + &types.VmStartingEvent{VmEvent: event}, + &types.VmPoweredOnEvent{VmEvent: event}, + ) + case types.VirtualMachinePowerStatePoweredOff: + c.ctx.postEvent(&types.VmPoweredOffEvent{VmEvent: event}) + } + return nil, nil } -func (vm *VirtualMachine) PowerOnVMTask(c *types.PowerOnVM_Task) soap.HasFault { - runner := &powerVMTask{vm, types.VirtualMachinePowerStatePoweredOn} +func (vm *VirtualMachine) PowerOnVMTask(ctx *Context, c *types.PowerOnVM_Task) soap.HasFault { + if vm.Config.Template { + return &methods.PowerOnVM_TaskBody{ + Fault_: Fault("cannot powerOn a template", &types.InvalidState{}), + } + } + + runner := &powerVMTask{vm, types.VirtualMachinePowerStatePoweredOn, ctx} task := CreateTask(runner.Reference(), "powerOn", runner.Run) return &methods.PowerOnVM_TaskBody{ @@ -524,8 +673,8 @@ func (vm *VirtualMachine) PowerOnVMTask(c *types.PowerOnVM_Task) soap.HasFault { } } -func (vm *VirtualMachine) PowerOffVMTask(c *types.PowerOffVM_Task) soap.HasFault { - runner := &powerVMTask{vm, types.VirtualMachinePowerStatePoweredOff} +func (vm *VirtualMachine) PowerOffVMTask(ctx *Context, c *types.PowerOffVM_Task) soap.HasFault { + runner := &powerVMTask{vm, types.VirtualMachinePowerStatePoweredOff, ctx} task := CreateTask(runner.Reference(), "powerOff", runner.Run) return &methods.PowerOffVM_TaskBody{ @@ -535,13 +684,18 @@ func (vm *VirtualMachine) PowerOffVMTask(c *types.PowerOffVM_Task) soap.HasFault } } -func (vm *VirtualMachine) ReconfigVMTask(req *types.ReconfigVM_Task) soap.HasFault { +func (vm *VirtualMachine) ReconfigVMTask(ctx *Context, req *types.ReconfigVM_Task) soap.HasFault { task := CreateTask(vm, "reconfigVm", func(t *Task) (types.AnyType, types.BaseMethodFault) { err := vm.configure(&req.Spec) if err != nil { return nil, err } + ctx.postEvent(&types.VmReconfiguredEvent{ + VmEvent: vm.event(), + ConfigSpec: req.Spec, + }) + return nil, nil }) @@ -552,9 +706,9 @@ func (vm *VirtualMachine) ReconfigVMTask(req *types.ReconfigVM_Task) soap.HasFau } } -func (vm *VirtualMachine) DestroyTask(req *types.Destroy_Task) soap.HasFault { +func (vm *VirtualMachine) DestroyTask(ctx *Context, req *types.Destroy_Task) soap.HasFault { task := CreateTask(vm, "destroy", func(t *Task) (types.AnyType, types.BaseMethodFault) { - r := vm.UnregisterVM(&types.UnregisterVM{ + r := vm.UnregisterVM(ctx, &types.UnregisterVM{ This: req.This, }) @@ -582,7 +736,7 @@ func (vm *VirtualMachine) DestroyTask(req *types.Destroy_Task) soap.HasFault { } } -func (vm *VirtualMachine) UnregisterVM(c *types.UnregisterVM) soap.HasFault { +func (vm *VirtualMachine) UnregisterVM(ctx *Context, c *types.UnregisterVM) soap.HasFault { r := &methods.UnregisterVMBody{} if vm.Runtime.PowerState == types.VirtualMachinePowerStatePoweredOn { @@ -594,34 +748,45 @@ func (vm *VirtualMachine) UnregisterVM(c *types.UnregisterVM) soap.HasFault { return r } - _ = vm.out.Close() // Close log fd - - Map.getEntityParent(vm, "Folder").(*Folder).removeChild(c.This) - host := Map.Get(*vm.Runtime.Host).(*HostSystem) - host.Vm = RemoveReference(vm.Self, host.Vm) + Map.RemoveReference(host, &host.Vm, vm.Self) switch pool := Map.Get(*vm.ResourcePool).(type) { case *ResourcePool: - pool.Vm = RemoveReference(vm.Self, pool.Vm) + Map.RemoveReference(pool, &pool.Vm, vm.Self) case *VirtualApp: - pool.Vm = RemoveReference(vm.Self, pool.Vm) + Map.RemoveReference(pool, &pool.Vm, vm.Self) } for i := range vm.Datastore { ds := Map.Get(vm.Datastore[i]).(*Datastore) - ds.Vm = RemoveReference(vm.Self, ds.Vm) + Map.RemoveReference(ds, &ds.Vm, vm.Self) } + ctx.postEvent(&types.VmRemovedEvent{VmEvent: vm.event()}) + Map.getEntityParent(vm, "Folder").(*Folder).removeChild(c.This) + r.Res = new(types.UnregisterVMResponse) return r } -func (vm *VirtualMachine) CloneVMTask(req *types.CloneVM_Task) soap.HasFault { - task := CreateTask(vm, "cloneVm", func(t *Task) (types.AnyType, types.BaseMethodFault) { - folder := Map.Get(req.Folder).(*Folder) +func (vm *VirtualMachine) CloneVMTask(ctx *Context, req *types.CloneVM_Task) soap.HasFault { + ctx.Caller = &vm.Self + folder := Map.Get(req.Folder).(*Folder) + host := Map.Get(*vm.Runtime.Host).(*HostSystem) + event := vm.event() + ctx.postEvent(&types.VmBeingClonedEvent{ + VmCloneEvent: types.VmCloneEvent{ + VmEvent: event, + }, + DestFolder: folder.eventArgument(), + DestName: req.Name, + DestHost: *host.eventArgument(), + }) + + task := CreateTask(vm, "cloneVm", func(t *Task) (types.AnyType, types.BaseMethodFault) { config := types.VirtualMachineConfigSpec{ Name: req.Name, GuestId: vm.Config.GuestId, @@ -630,10 +795,11 @@ func (vm *VirtualMachine) CloneVMTask(req *types.CloneVM_Task) soap.HasFault { }, } - res := folder.CreateVMTask(&types.CreateVM_Task{ + res := folder.CreateVMTask(ctx, &types.CreateVM_Task{ This: folder.Self, Config: config, Pool: *vm.ResourcePool, + Host: vm.Runtime.Host, }) ctask := Map.Get(res.(*methods.CreateVM_TaskBody).Res.Returnval).(*Task) @@ -641,7 +807,15 @@ func (vm *VirtualMachine) CloneVMTask(req *types.CloneVM_Task) soap.HasFault { return nil, ctask.Info.Error.Fault } - return ctask.Info.Result.(types.ManagedObjectReference), nil + ref := ctask.Info.Result.(types.ManagedObjectReference) + clone := Map.Get(ref).(*VirtualMachine) + + ctx.postEvent(&types.VmClonedEvent{ + VmCloneEvent: types.VmCloneEvent{VmEvent: clone.event()}, + SourceVm: *event.Vm, + }) + + return ref, nil }) return &methods.CloneVM_TaskBody{ @@ -655,7 +829,7 @@ func (vm *VirtualMachine) RelocateVMTask(req *types.RelocateVM_Task) soap.HasFau task := CreateTask(vm, "relocateVm", func(t *Task) (types.AnyType, types.BaseMethodFault) { if ref := req.Spec.Datastore; ref != nil { ds := Map.Get(*ref).(*Datastore) - ds.Vm = RemoveReference(*ref, ds.Vm) + Map.RemoveReference(ds, &ds.Vm, *ref) vm.Datastore = []types.ManagedObjectReference{*ref} @@ -664,14 +838,14 @@ func (vm *VirtualMachine) RelocateVMTask(req *types.RelocateVM_Task) soap.HasFau if ref := req.Spec.Pool; ref != nil { pool := Map.Get(*ref).(*ResourcePool) - pool.Vm = RemoveReference(*ref, pool.Vm) + Map.RemoveReference(pool, &pool.Vm, *ref) vm.ResourcePool = ref } if ref := req.Spec.Host; ref != nil { host := Map.Get(*ref).(*HostSystem) - host.Vm = RemoveReference(*ref, host.Vm) + Map.RemoveReference(host, &host.Vm, *ref) vm.Runtime.Host = ref } @@ -799,6 +973,24 @@ func (vm *VirtualMachine) ShutdownGuest(c *types.ShutdownGuest) soap.HasFault { return r } +func (vm *VirtualMachine) MarkAsTemplate(req *types.MarkAsTemplate) soap.HasFault { + r := &methods.MarkAsTemplateBody{} + + if vm.Runtime.PowerState != types.VirtualMachinePowerStatePoweredOff { + r.Fault_ = Fault("", &types.InvalidPowerState{ + RequestedState: types.VirtualMachinePowerStatePoweredOff, + ExistingState: vm.Runtime.PowerState, + }) + return r + } + + vm.Config.Template = true + + r.Res = &types.MarkAsTemplateResponse{} + + return r +} + func findSnapshotInTree(tree []types.VirtualMachineSnapshotTree, ref types.ManagedObjectReference) *types.VirtualMachineSnapshotTree { if tree == nil { return nil diff --git a/vendor/github.com/vmware/govmomi/simulator/vpx/setting.go b/vendor/github.com/vmware/govmomi/simulator/vpx/setting.go index dfbb28b7ab4..6ed4ba68e85 100644 --- a/vendor/github.com/vmware/govmomi/simulator/vpx/setting.go +++ b/vendor/github.com/vmware/govmomi/simulator/vpx/setting.go @@ -57,4 +57,16 @@ var Setting = []types.BaseOptionValue{ Key: "config.vpxd.sso.admin.uri", Value: "https://127.0.0.1/sso-adminserver/sdk/vsphere.local", }, + &types.OptionValue{ + Key: "event.batchsize", + Value: int32(2000), + }, + &types.OptionValue{ + Key: "event.maxAge", + Value: int32(30), + }, + &types.OptionValue{ + Key: "event.maxAgeEnabled", + Value: bool(true), + }, } diff --git a/vendor/github.com/vmware/govmomi/vim25/progress/reader.go b/vendor/github.com/vmware/govmomi/vim25/progress/reader.go index a981cb4e152..ba886750822 100644 --- a/vendor/github.com/vmware/govmomi/vim25/progress/reader.go +++ b/vendor/github.com/vmware/govmomi/vim25/progress/reader.go @@ -18,6 +18,7 @@ package progress import ( "container/list" + "context" "fmt" "io" "sync/atomic" @@ -75,16 +76,16 @@ type reader struct { pos int64 size int64 + bps uint64 - bps uint64 - - ch chan<- Report + ch chan<- Report + ctx context.Context } -func NewReader(s Sinker, r io.Reader, size int64) *reader { +func NewReader(ctx context.Context, s Sinker, r io.Reader, size int64) *reader { pr := reader{ - r: r, - + r: r, + ctx: ctx, size: size, } @@ -111,7 +112,10 @@ func (r *reader) Read(b []byte) (int, error) { bps: &r.bps, } - r.ch <- q + select { + case r.ch <- q: + case <-r.ctx.Done(): + } return n, err } @@ -127,8 +131,11 @@ func (r *reader) Done(err error) { err: err, } - r.ch <- q - close(r.ch) + select { + case r.ch <- q: + close(r.ch) + case <-r.ctx.Done(): + } } // newBpsLoop returns a sink that monitors and stores throughput. diff --git a/vendor/github.com/vmware/govmomi/vim25/soap/client.go b/vendor/github.com/vmware/govmomi/vim25/soap/client.go index 4c05a6c6297..76592493ccd 100644 --- a/vendor/github.com/vmware/govmomi/vim25/soap/client.go +++ b/vendor/github.com/vmware/govmomi/vim25/soap/client.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2014-2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2014-2018 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -56,6 +56,7 @@ const ( DefaultVimNamespace = "urn:vim25" DefaultVimVersion = "6.5" DefaultMinVimVersion = "5.5" + SessionCookieName = "vmware_soap_session" ) type header struct { @@ -168,7 +169,7 @@ func (c *Client) NewServiceClient(path string, namespace string) *Client { // Set SOAP Header cookie for _, cookie := range client.Jar.Cookies(u) { - if cookie.Name == "vmware_soap_session" { + if cookie.Name == SessionCookieName { client.cookie = cookie.Value break } @@ -458,6 +459,8 @@ func (c *Client) RoundTrip(ctx context.Context, reqBody, resBody HasFault) error panic(err) } + req = req.WithContext(ctx) + req.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`) soapAction := fmt.Sprintf("%s/%s", c.Namespace, c.Version) req.Header.Set(`SOAPAction`, soapAction) @@ -548,11 +551,11 @@ var DefaultUpload = Upload{ } // Upload PUTs the local file to the given URL -func (c *Client) Upload(f io.Reader, u *url.URL, param *Upload) error { +func (c *Client) Upload(ctx context.Context, f io.Reader, u *url.URL, param *Upload) error { var err error if param.Progress != nil { - pr := progress.NewReader(param.Progress, f, param.ContentLength) + pr := progress.NewReader(ctx, param.Progress, f, param.ContentLength) f = pr // Mark progress reader as done when returning from this function. @@ -566,6 +569,8 @@ func (c *Client) Upload(f io.Reader, u *url.URL, param *Upload) error { return err } + req = req.WithContext(ctx) + req.ContentLength = param.ContentLength req.Header.Set("Content-Type", param.Type) @@ -593,7 +598,7 @@ func (c *Client) Upload(f io.Reader, u *url.URL, param *Upload) error { } // UploadFile PUTs the local file to the given URL -func (c *Client) UploadFile(file string, u *url.URL, param *Upload) error { +func (c *Client) UploadFile(ctx context.Context, file string, u *url.URL, param *Upload) error { if param == nil { p := DefaultUpload // Copy since we set ContentLength param = &p @@ -612,7 +617,7 @@ func (c *Client) UploadFile(file string, u *url.URL, param *Upload) error { param.ContentLength = s.Size() - return c.Upload(f, u, param) + return c.Upload(ctx, f, u, param) } type Download struct { @@ -628,12 +633,14 @@ var DefaultDownload = Download{ } // DownloadRequest wraps http.Client.Do, returning the http.Response without checking its StatusCode -func (c *Client) DownloadRequest(u *url.URL, param *Download) (*http.Response, error) { +func (c *Client) DownloadRequest(ctx context.Context, u *url.URL, param *Download) (*http.Response, error) { req, err := http.NewRequest(param.Method, u.String(), nil) if err != nil { return nil, err } + req = req.WithContext(ctx) + for k, v := range param.Headers { req.Header.Add(k, v) } @@ -646,8 +653,8 @@ func (c *Client) DownloadRequest(u *url.URL, param *Download) (*http.Response, e } // Download GETs the remote file from the given URL -func (c *Client) Download(u *url.URL, param *Download) (io.ReadCloser, int64, error) { - res, err := c.DownloadRequest(u, param) +func (c *Client) Download(ctx context.Context, u *url.URL, param *Download) (io.ReadCloser, int64, error) { + res, err := c.DownloadRequest(ctx, u, param) if err != nil { return nil, 0, err } @@ -667,7 +674,7 @@ func (c *Client) Download(u *url.URL, param *Download) (io.ReadCloser, int64, er return r, res.ContentLength, nil } -func (c *Client) WriteFile(file string, src io.Reader, size int64, s progress.Sinker, w io.Writer) error { +func (c *Client) WriteFile(ctx context.Context, file string, src io.Reader, size int64, s progress.Sinker, w io.Writer) error { var err error r := src @@ -678,7 +685,7 @@ func (c *Client) WriteFile(file string, src io.Reader, size int64, s progress.Si } if s != nil { - pr := progress.NewReader(s, src, size) + pr := progress.NewReader(ctx, s, src, size) src = pr // Mark progress reader as done when returning from this function. @@ -705,16 +712,16 @@ func (c *Client) WriteFile(file string, src io.Reader, size int64, s progress.Si } // DownloadFile GETs the given URL to a local file -func (c *Client) DownloadFile(file string, u *url.URL, param *Download) error { +func (c *Client) DownloadFile(ctx context.Context, file string, u *url.URL, param *Download) error { var err error if param == nil { param = &DefaultDownload } - rc, contentLength, err := c.Download(u, param) + rc, contentLength, err := c.Download(ctx, u, param) if err != nil { return err } - return c.WriteFile(file, rc, contentLength, param.Progress, param.Writer) + return c.WriteFile(ctx, file, rc, contentLength, param.Progress, param.Writer) } diff --git a/vendor/github.com/vmware/govmomi/vim25/types/helpers.go b/vendor/github.com/vmware/govmomi/vim25/types/helpers.go index dd5f049fa80..7ccfd29b634 100644 --- a/vendor/github.com/vmware/govmomi/vim25/types/helpers.go +++ b/vendor/github.com/vmware/govmomi/vim25/types/helpers.go @@ -17,6 +17,7 @@ limitations under the License. package types import ( + "reflect" "strings" "time" ) @@ -86,3 +87,9 @@ func DefaultResourceConfigSpec() ResourceConfigSpec { MemoryAllocation: defaultResourceAllocationInfo(), } } + +func init() { + // Known 6.5 issue where this event type is sent even though it is internal. + // This workaround allows us to unmarshal and avoid NPEs. + t["HostSubSpecificationUpdateEvent"] = reflect.TypeOf((*HostEvent)(nil)).Elem() +} diff --git a/vendor/github.com/vmware/govmomi/vim25/types/types.go b/vendor/github.com/vmware/govmomi/vim25/types/types.go index 50cad1b6051..564fd18ea9e 100644 --- a/vendor/github.com/vmware/govmomi/vim25/types/types.go +++ b/vendor/github.com/vmware/govmomi/vim25/types/types.go @@ -48188,7 +48188,7 @@ func init() { type VirtualMachineAffinityInfo struct { DynamicData - AffinitySet []int32 `xml:"affinitySet,omitempty"` + AffinitySet []int32 `xml:"affinitySet"` } func init() {