Repository: vmware/govmomi
Pull request #2391 (2021-04-24 21:19:10)

ESX Agent Manager (EAM) Client & Simulator
This patch introduces the bindings, client, and simulator for the ESX Agent Manager (EAM). EAM is a long-lived service on vCenter that acts as an intermediary for provisioning agent virtual machines and VIB modules on behalf of the user.

The following packages include:

```
  * ./eam           - the EAM client
  * ./eam/types     - the EAM bindings - types
  * ./eam/methods   - the EAM bindings - methods
  * ./eam/object    - the EAM helper objects, ie. more than just MoRefs
  * ./eam/simulator - the EAM simulator
```

For more information on how to use EAM, please see the public, EAM SDK at http://bit.ly/eam-sdk.

This patch also updates the vC Simulator code so when containers are deployed as VMs, goroutines are created to monitor the containers and automatically update the runtime properties of the VM to match the underlying state of the container, such as power state, IP address, etc.

~~This patch still needs some work. Outstanding items include:~~

- [x] Finish implementing the functions on the helper types in `./eam/object/`
- [x] Create unit tests that use the EAM simulator for each of the functions on the helper types in `./eam/object/`. This will also be a forcing function to complete the simulator as well (this is not 100% completed, but enough that others can help. I am fine with the state of the current unit tests)
- [x] Create an e2e test utilizing the vC and EAM simulators to validate agency creation using a container-backed VM to replicate VM lifecycle


Patch:
diff --git a/.chglog/config.yml b/.chglog/config.yml
index b1fcd6a2..ab7f38e4 100755
--- a/.chglog/config.yml
+++ b/.chglog/config.yml
@@ -9,12 +9,10 @@ options:
       Type:
         - govc
         - vcsim
-        - chore
   commit_groups:
     title_maps:
       govc: 💫 `govc` (CLI)
       vcsim: 💫 `vcsim` (Simulator)
-      chore: 🧹 Chore
   header:
     pattern: "^(\\w*)\\:\\s(.*)$"
     pattern_maps:
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 88ca0540..00000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve
-title: "[BUG] "
-labels: bug
-assignees: ''
-
----
-
-**Describe the bug**
-A clear and concise description of what the bug is.
-
-**To Reproduce**
-Steps to reproduce the behavior:
-
-1. 
-1.
-1.
-
-**Expected behavior**
-A clear and concise description of what you expected to happen.
-
-**Affected version**
-Please provide details on the version used, e.g. release tag, commit, module version, etc.
-
-**Screenshots/Debug Output**
-If applicable, add screenshots or debug output to help explain your problem.
-
-**Additional context**
-Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index f8df48bb..00000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-title: ''
-labels: 'kind/feature'
-assignees: ''
-
----
-
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I cannot do X because [...]
-
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
-
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
-**Additional context**
-Add any other context or screenshots about the feature request here.
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
deleted file mode 100644
index 93f06de1..00000000
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ /dev/null
@@ -1,41 +0,0 @@
-## Description
-
-Please include a summary of the change and which issue is fixed. Please also
-include relevant motivation and context. List any dependencies that are required
-for this change.
-
-Closes: #(issue-number)
-
-## Type of change
-
-Please mark options that are relevant:
-
-- [ ] Bug fix (non-breaking change which fixes an issue)
-- [ ] New feature (non-breaking change which adds functionality)
-- [ ] Breaking change (fix or feature that would cause existing functionality to
-  not work as expected)
-- [ ] This change requires a documentation update
-
-## How Has This Been Tested?
-
-Please describe the tests that you ran to verify your changes. Provide
-instructions so we can reproduce. If applicable, please also list any relevant
-details for your test configuration.
-
-- [ ] Test Description 1
-- [ ] Test Description 2
-
-**Test Configuration**:
-* Toolchain:
-* SDK:
-* (add more if needed)
-
-## Checklist:
-
-- [ ] My code follows the CONTRIBUTION [guidelines](./../CONTRIBUTING.md) of
-  this project
-- [ ] I have commented my code, particularly in hard-to-understand areas
-- [ ] I have made corresponding changes to the documentation
-- [ ] I have added tests that prove my fix is effective or that my feature works
-- [ ] New and existing unit tests pass locally with my changes
-- [ ] Any dependent changes have been merged
\ No newline at end of file
diff --git a/.github/comment-template.md b/.github/comment-template.md
deleted file mode 100644
index c5272c3f..00000000
--- a/.github/comment-template.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Howdy 🖐 &nbsp; {{ .author }} ! Thank you for your interest in this project. We value your feedback and will respond soon.
-
-If you want to contribute to this project, please make yourself familiar with the `CONTRIBUTION` [guidelines](./../CONTRIBUTING.md).
\ No newline at end of file
diff --git a/.github/workflows/govmomi-check-wip.yaml b/.github/workflows/govmomi-check-wip.yaml
index 783a70ae..e25d9a89 100644
--- a/.github/workflows/govmomi-check-wip.yaml
+++ b/.github/workflows/govmomi-check-wip.yaml
@@ -13,15 +13,19 @@
 #  limitations under the License.
 
 # Perform "exit 1" if PR title starts with "WIP" to block accidental merges
-name: Check "WIP" in PR Title
+name: Check WIP
 
 on:
   pull_request:
-    types: [opened, synchronize, reopened, edited]
+    types: [ opened, synchronize, reopened, edited ]
 
 jobs:
-  wip:
+  WIP:
+    name: "Check WIP in PR title"
     runs-on: ubuntu-latest
+    if: startsWith(github.event.pull_request.title, 'WIP')
     steps:
-      - name: Check WIP in PR Title
-        uses: embano1/wip@v1
+      - name: Must Exit
+        run: |
+          echo "::error ::PR marked as Work in Progress!"
+          exit 1
diff --git a/.github/workflows/issue-greeting.yaml b/.github/workflows/issue-greeting.yaml
deleted file mode 100644
index 6c95232b..00000000
--- a/.github/workflows/issue-greeting.yaml
+++ /dev/null
@@ -1,33 +0,0 @@
-name: Greeting
-
-on:
-  issues:
-    types: ["opened"]
-
-jobs:
-  greeting:
-    name: Send Greeting
-    runs-on: ubuntu-latest
-    # only send message to users not (yet) associated with repo
-    # https://docs.github.com/en/graphql/reference/enums#commentauthorassociation
-    if: github.event.issue.author_association == 'NONE'
-
-    steps:
-      - name: Checkout
-        uses: actions/checkout@v2
-        with:
-          fetch-depth: 1
-
-      - name: Render template
-        id: template
-        uses: chuhlomin/render-template@v1.2
-        with:
-          template: .github/comment-template.md
-          vars: |
-            author: ${{ github.actor }}
-
-      - name: Create comment
-        uses: peter-evans/create-or-update-comment@v1
-        with:
-          issue-number: ${{ github.event.issue.number }}
-          body: ${{ steps.template.outputs.result }}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7461676e..cbba0ce3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -110,24 +110,6 @@ Message](http://chris.beams.io/posts/git-commit/).
 Be sure to include any related GitHub issue references in the commit message,
 e.g. `Closes: #<number>`.
 
-The [`CHANGELOG.md`](./CHANGELOG.md) and release page uses commit message
-prefixes for grouping and highlighting. A commit message that
-starts with `[prefix:] ` will place this commit under the respective
-section in the `CHANGELOG`. 
-
-The following example creates a commit referencing the `issue: 1234` and puts
-the commit message in the `govc` `CHANGELOG` section:
-
-```console
-$ git commit -s -m "govc: Add CLI command X" -m "Closes: #1234"
-```
-
-Currently the following prefixes are used:
-
-- `govc:` - CLI
-- `vcsim:` - Simulator
-- `chore:` - Repository related activities
-
 ### Running CI Checks and Tests
 You can run both `make check` and `make test` from the top level of the
 repository. 
diff --git a/Gopkg.lock b/Gopkg.lock
new file mode 100644
index 00000000..f45057fb
--- /dev/null
+++ b/Gopkg.lock
@@ -0,0 +1,60 @@
+# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
+
+
+[[projects]]
+  branch = "improvements"
+  digest = "1:b183578c34fabccaf65f1a57d2efeec2086abdce1446978d69ab3a0016cb750c"
+  name = "github.com/davecgh/go-xdr"
+  packages = ["xdr2"]
+  pruneopts = "NUT"
+  revision = "4930550ba2e22f87187498acfd78348b15f4e7a8"
+  source = "https://github.com/rasky/go-xdr"
+
+[[projects]]
+  digest = "1:1ab18cf8c2084968d6dca0dd46fbda9efba08664ecd7957b63c7ca57bb2455df"
+  name = "github.com/google/uuid"
+  packages = ["."]
+  pruneopts = "NUT"
+  revision = "6a5e28554805e78ea6141142aba763936c4761c0"
+
+[[projects]]
+  branch = "govmomi"
+  digest = "1:f49ed6cb2129e9a3ce9dde5037cb243b5849c0ec0c7973b9d1e987872d8b8cc6"
+  name = "github.com/kr/pretty"
+  packages = ["."]
+  pruneopts = "NUT"
+  revision = "2ee9d7453c02ef7fa518a83ae23644eb8872186a"
+  source = "https://github.com/dougm/pretty"
+
+[[projects]]
+  branch = "master"
+  digest = "1:c3a7836b5904db0f8b609595b619916a6831cb35b8b714aec39f96d00c6155d8"
+  name = "github.com/kr/text"
+  packages = ["."]
+  pruneopts = "NUT"
+  revision = "7cafcd837844e784b526369c9bce262804aebc60"
+
+[[projects]]
+  branch = "master"
+  digest = "1:4bea31865971675c482ed875caeabe7d2182dcb47d52900b7da5236d66dc9970"
+  name = "github.com/vmware/vmw-guestinfo"
+  packages = [
+    "bdoor",
+    "message",
+    "vmcheck",
+  ]
+  pruneopts = "NUT"
+  revision = "25eff159a728be87e103a0b8045e08273f4dbec4"
+
+[solve-meta]
+  analyzer-name = "dep"
+  analyzer-version = 1
+  input-imports = [
+    "github.com/davecgh/go-xdr/xdr2",
+    "github.com/google/uuid",
+    "github.com/kr/pretty",
+    "github.com/vmware/vmw-guestinfo/message",
+    "github.com/vmware/vmw-guestinfo/vmcheck",
+  ]
+  solver-name = "gps-cdcl"
+  solver-version = 1
diff --git a/Gopkg.toml b/Gopkg.toml
new file mode 100644
index 00000000..4c4d6765
--- /dev/null
+++ b/Gopkg.toml
@@ -0,0 +1,19 @@
+# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
+# for detailed Gopkg.toml documentation.
+#
+# Refer to https://github.com/toml-lang/toml for detailed TOML docs.
+
+[prune]
+  non-go = true
+  go-tests = true
+  unused-packages = true
+
+[[constraint]]
+  branch = "improvements"
+  name = "github.com/davecgh/go-xdr"
+  source = "https://github.com/rasky/go-xdr"
+
+[[constraint]]
+  branch = "govmomi"
+  name = "github.com/kr/pretty"
+  source = "https://github.com/dougm/pretty"
diff --git a/Makefile b/Makefile
index f541651f..38e3b5b8 100644
--- a/Makefile
+++ b/Makefile
@@ -26,15 +26,8 @@ govc-test: install
 	./govc/test/images/update.sh
 	(cd govc/test && ./vendor/github.com/sstephenson/bats/libexec/bats -t .)
 
-govc-test-sso: install
-	./govc/test/images/update.sh
-	(cd govc/test && SSO_BATS=1 ./vendor/github.com/sstephenson/bats/libexec/bats -t sso.bats)
-
-govc-test-sso-assert-cert:
-	SSO_BATS_ASSERT_CERT=1 $(MAKE) govc-test-sso
-
 .PHONY: test
 test: go-test govc-test
 
 doc: install
-	./govc/usage.sh > ./govc/USAGE.md
\ No newline at end of file
+	./govc/usage.sh > ./govc/USAGE.md
diff --git a/README.md b/README.md
index 7440c627..1699583d 100644
--- a/README.md
+++ b/README.md
@@ -74,7 +74,9 @@ Refer to the [CHANGELOG](CHANGELOG.md) for version to version changes.
 
 * [Juju](https://github.com/juju/juju)
 
-* [Kubernetes vSphere Cloud Provider](https://github.com/kubernetes/cloud-provider-vsphere)
+* [Kubernetes](https://github.com/kubernetes/kubernetes/tree/master/pkg/cloudprovider/providers/vsphere)
+
+* [Kubernetes Cloud Provider](https://github.com/kubernetes/cloud-provider-vsphere)
 
 * [Kubernetes Cluster API](https://github.com/kubernetes-sigs/cluster-api-provider-vsphere)
 
diff --git a/eam/README.md b/eam/README.md
new file mode 100644
index 00000000..6d2a0eaa
--- /dev/null
+++ b/eam/README.md
@@ -0,0 +1,11 @@
+# ESX Agent Manager (EAM)
+
+ESX Agent Manager ([EAM](https://vdc-download.vmware.com/vmwb-repository/dcr-public/3d076a12-29a2-4d17-9269-cb8150b5a37f/8b5969e2-1a66-4425-af17-feff6d6f705d/SDK/eam/doc/index.html)) is a long-lived service on vCenter that acts as an intermediary for provisioning agent virtual machines and VIB modules on behalf of the user.
+
+## HowTo
+
+Please refer to [`simulator/simulator_test.go`](./simulator/simulator_test.go) for an example on how to use this package.
+
+## Simulator
+
+The [`simulator`](./simulator/) package provides an EAM simulator that can even simulate the lifecycle of agent VMs using containers.
diff --git a/eam/client.go b/eam/client.go
new file mode 100644
index 00000000..9cb4c1ca
--- /dev/null
+++ b/eam/client.go
@@ -0,0 +1,42 @@
+/*
+Copyright (c) 2021 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 eam
+
+import (
+	"github.com/vmware/govmomi/vim25"
+	"github.com/vmware/govmomi/vim25/soap"
+)
+
+const (
+	// Namespace is the namespace for EAM SOAP operations.
+	Namespace = "eam"
+
+	// Path is the path to the EAM service.
+	Path = "/eam/sdk"
+)
+
+// Client is a client for the ESX Agent Manager API.
+type Client struct {
+	*soap.Client
+}
+
+// NewClient returns a new EAM client.
+func NewClient(c *vim25.Client) *Client {
+	return &Client{
+		Client: c.Client.NewServiceClient(Path, Namespace),
+	}
+}
diff --git a/eam/eam.go b/eam/eam.go
new file mode 100644
index 00000000..c832aaca
--- /dev/null
+++ b/eam/eam.go
@@ -0,0 +1,27 @@
+/*
+Copyright (c) 2021 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 eam
+
+import (
+	"github.com/vmware/govmomi/eam/internal"
+	"github.com/vmware/govmomi/vim25/types"
+)
+
+var EsxAgentManager = types.ManagedObjectReference{
+	Type:  internal.EsxAgentManager,
+	Value: internal.EsxAgentManager,
+}
diff --git a/eam/internal/internal.go b/eam/internal/internal.go
new file mode 100644
index 00000000..d488a80f
--- /dev/null
+++ b/eam/internal/internal.go
@@ -0,0 +1,32 @@
+/*
+Copyright (c) 2021 VMware, Inc. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package internal
+
+const (
+	// EamObject is the managed object type for the EamObject base class.
+	EamObject = "EamObject"
+
+	// EsxAgentManager is both the managed object type and ID for the
+	// EsxAgentManager class.
+	EsxAgentManager = "EsxAgentManager"
+
+	// Agency is the managed object type for the Agency class.
+	Agency = "Agency"
+
+	// Agent is the managed object type for the Agency class.
+	Agent = "Agent"
+)
diff --git a/eam/methods/methods.go b/eam/methods/methods.go
new file mode 100644
index 00000000..a6a064bc
--- /dev/null
+++ b/eam/methods/methods.go
@@ -0,0 +1,444 @@
+/*
+Copyright (c) 2021 VMware, Inc. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package methods
+
+import (
+	"context"
+
+	"github.com/vmware/govmomi/eam/types"
+	"github.com/vmware/govmomi/vim25/soap"
+)
+
+type AddIssueBody struct {
+	Req    *types.AddIssue         `xml:"urn:eam AddIssue,omitempty"`
+	Res    *types.AddIssueResponse `xml:"urn:eam AddIssueResponse,omitempty"`
+	Fault_ *soap.Fault             `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *AddIssueBody) Fault() *soap.Fault { return b.Fault_ }
+
+func AddIssue(ctx context.Context, r soap.RoundTripper, req *types.AddIssue) (*types.AddIssueResponse, error) {
+	var reqBody, resBody AddIssueBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type AgencyQueryRuntimeBody struct {
+	Req    *types.AgencyQueryRuntime         `xml:"urn:eam AgencyQueryRuntime,omitempty"`
+	Res    *types.AgencyQueryRuntimeResponse `xml:"urn:eam AgencyQueryRuntimeResponse,omitempty"`
+	Fault_ *soap.Fault                       `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *AgencyQueryRuntimeBody) Fault() *soap.Fault { return b.Fault_ }
+
+func AgencyQueryRuntime(ctx context.Context, r soap.RoundTripper, req *types.AgencyQueryRuntime) (*types.AgencyQueryRuntimeResponse, error) {
+	var reqBody, resBody AgencyQueryRuntimeBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type AgentQueryConfigBody struct {
+	Req    *types.AgentQueryConfig         `xml:"urn:eam AgentQueryConfig,omitempty"`
+	Res    *types.AgentQueryConfigResponse `xml:"urn:eam AgentQueryConfigResponse,omitempty"`
+	Fault_ *soap.Fault                     `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *AgentQueryConfigBody) Fault() *soap.Fault { return b.Fault_ }
+
+func AgentQueryConfig(ctx context.Context, r soap.RoundTripper, req *types.AgentQueryConfig) (*types.AgentQueryConfigResponse, error) {
+	var reqBody, resBody AgentQueryConfigBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type AgentQueryRuntimeBody struct {
+	Req    *types.AgentQueryRuntime         `xml:"urn:eam AgentQueryRuntime,omitempty"`
+	Res    *types.AgentQueryRuntimeResponse `xml:"urn:eam AgentQueryRuntimeResponse,omitempty"`
+	Fault_ *soap.Fault                      `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *AgentQueryRuntimeBody) Fault() *soap.Fault { return b.Fault_ }
+
+func AgentQueryRuntime(ctx context.Context, r soap.RoundTripper, req *types.AgentQueryRuntime) (*types.AgentQueryRuntimeResponse, error) {
+	var reqBody, resBody AgentQueryRuntimeBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type CreateAgencyBody struct {
+	Req    *types.CreateAgency         `xml:"urn:eam CreateAgency,omitempty"`
+	Res    *types.CreateAgencyResponse `xml:"urn:eam CreateAgencyResponse,omitempty"`
+	Fault_ *soap.Fault                 `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *CreateAgencyBody) Fault() *soap.Fault { return b.Fault_ }
+
+func CreateAgency(ctx context.Context, r soap.RoundTripper, req *types.CreateAgency) (*types.CreateAgencyResponse, error) {
+	var reqBody, resBody CreateAgencyBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type DestroyAgencyBody struct {
+	Req    *types.DestroyAgency         `xml:"urn:eam DestroyAgency,omitempty"`
+	Res    *types.DestroyAgencyResponse `xml:"urn:eam DestroyAgencyResponse,omitempty"`
+	Fault_ *soap.Fault                  `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *DestroyAgencyBody) Fault() *soap.Fault { return b.Fault_ }
+
+func DestroyAgency(ctx context.Context, r soap.RoundTripper, req *types.DestroyAgency) (*types.DestroyAgencyResponse, error) {
+	var reqBody, resBody DestroyAgencyBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type DisableBody struct {
+	Req    *types.Disable         `xml:"urn:eam Disable,omitempty"`
+	Res    *types.DisableResponse `xml:"urn:eam DisableResponse,omitempty"`
+	Fault_ *soap.Fault            `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *DisableBody) Fault() *soap.Fault { return b.Fault_ }
+
+func Disable(ctx context.Context, r soap.RoundTripper, req *types.Disable) (*types.DisableResponse, error) {
+	var reqBody, resBody DisableBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type EnableBody struct {
+	Req    *types.Enable         `xml:"urn:eam Enable,omitempty"`
+	Res    *types.EnableResponse `xml:"urn:eam EnableResponse,omitempty"`
+	Fault_ *soap.Fault           `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *EnableBody) Fault() *soap.Fault { return b.Fault_ }
+
+func Enable(ctx context.Context, r soap.RoundTripper, req *types.Enable) (*types.EnableResponse, error) {
+	var reqBody, resBody EnableBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type MarkAsAvailableBody struct {
+	Req    *types.MarkAsAvailable         `xml:"urn:eam MarkAsAvailable,omitempty"`
+	Res    *types.MarkAsAvailableResponse `xml:"urn:eam MarkAsAvailableResponse,omitempty"`
+	Fault_ *soap.Fault                    `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *MarkAsAvailableBody) Fault() *soap.Fault { return b.Fault_ }
+
+func MarkAsAvailable(ctx context.Context, r soap.RoundTripper, req *types.MarkAsAvailable) (*types.MarkAsAvailableResponse, error) {
+	var reqBody, resBody MarkAsAvailableBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type QueryAgencyBody struct {
+	Req    *types.QueryAgency         `xml:"urn:eam QueryAgency,omitempty"`
+	Res    *types.QueryAgencyResponse `xml:"urn:eam QueryAgencyResponse,omitempty"`
+	Fault_ *soap.Fault                `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *QueryAgencyBody) Fault() *soap.Fault { return b.Fault_ }
+
+func QueryAgency(ctx context.Context, r soap.RoundTripper, req *types.QueryAgency) (*types.QueryAgencyResponse, error) {
+	var reqBody, resBody QueryAgencyBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type QueryAgentBody struct {
+	Req    *types.QueryAgent         `xml:"urn:eam QueryAgent,omitempty"`
+	Res    *types.QueryAgentResponse `xml:"urn:eam QueryAgentResponse,omitempty"`
+	Fault_ *soap.Fault               `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *QueryAgentBody) Fault() *soap.Fault { return b.Fault_ }
+
+func QueryAgent(ctx context.Context, r soap.RoundTripper, req *types.QueryAgent) (*types.QueryAgentResponse, error) {
+	var reqBody, resBody QueryAgentBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type QueryConfigBody struct {
+	Req    *types.QueryConfig         `xml:"urn:eam QueryConfig,omitempty"`
+	Res    *types.QueryConfigResponse `xml:"urn:eam QueryConfigResponse,omitempty"`
+	Fault_ *soap.Fault                `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *QueryConfigBody) Fault() *soap.Fault { return b.Fault_ }
+
+func QueryConfig(ctx context.Context, r soap.RoundTripper, req *types.QueryConfig) (*types.QueryConfigResponse, error) {
+	var reqBody, resBody QueryConfigBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type QueryIssueBody struct {
+	Req    *types.QueryIssue         `xml:"urn:eam QueryIssue,omitempty"`
+	Res    *types.QueryIssueResponse `xml:"urn:eam QueryIssueResponse,omitempty"`
+	Fault_ *soap.Fault               `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *QueryIssueBody) Fault() *soap.Fault { return b.Fault_ }
+
+func QueryIssue(ctx context.Context, r soap.RoundTripper, req *types.QueryIssue) (*types.QueryIssueResponse, error) {
+	var reqBody, resBody QueryIssueBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type QuerySolutionIdBody struct {
+	Req    *types.QuerySolutionId         `xml:"urn:eam QuerySolutionId,omitempty"`
+	Res    *types.QuerySolutionIdResponse `xml:"urn:eam QuerySolutionIdResponse,omitempty"`
+	Fault_ *soap.Fault                    `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *QuerySolutionIdBody) Fault() *soap.Fault { return b.Fault_ }
+
+func QuerySolutionId(ctx context.Context, r soap.RoundTripper, req *types.QuerySolutionId) (*types.QuerySolutionIdResponse, error) {
+	var reqBody, resBody QuerySolutionIdBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type RegisterAgentVmBody struct {
+	Req    *types.RegisterAgentVm         `xml:"urn:eam RegisterAgentVm,omitempty"`
+	Res    *types.RegisterAgentVmResponse `xml:"urn:eam RegisterAgentVmResponse,omitempty"`
+	Fault_ *soap.Fault                    `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *RegisterAgentVmBody) Fault() *soap.Fault { return b.Fault_ }
+
+func RegisterAgentVm(ctx context.Context, r soap.RoundTripper, req *types.RegisterAgentVm) (*types.RegisterAgentVmResponse, error) {
+	var reqBody, resBody RegisterAgentVmBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type ResolveBody struct {
+	Req    *types.Resolve         `xml:"urn:eam Resolve,omitempty"`
+	Res    *types.ResolveResponse `xml:"urn:eam ResolveResponse,omitempty"`
+	Fault_ *soap.Fault            `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *ResolveBody) Fault() *soap.Fault { return b.Fault_ }
+
+func Resolve(ctx context.Context, r soap.RoundTripper, req *types.Resolve) (*types.ResolveResponse, error) {
+	var reqBody, resBody ResolveBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type ResolveAllBody struct {
+	Req    *types.ResolveAll         `xml:"urn:eam ResolveAll,omitempty"`
+	Res    *types.ResolveAllResponse `xml:"urn:eam ResolveAllResponse,omitempty"`
+	Fault_ *soap.Fault               `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *ResolveAllBody) Fault() *soap.Fault { return b.Fault_ }
+
+func ResolveAll(ctx context.Context, r soap.RoundTripper, req *types.ResolveAll) (*types.ResolveAllResponse, error) {
+	var reqBody, resBody ResolveAllBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type ScanForUnknownAgentVmBody struct {
+	Req    *types.ScanForUnknownAgentVm         `xml:"urn:eam ScanForUnknownAgentVm,omitempty"`
+	Res    *types.ScanForUnknownAgentVmResponse `xml:"urn:eam ScanForUnknownAgentVmResponse,omitempty"`
+	Fault_ *soap.Fault                          `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *ScanForUnknownAgentVmBody) Fault() *soap.Fault { return b.Fault_ }
+
+func ScanForUnknownAgentVm(ctx context.Context, r soap.RoundTripper, req *types.ScanForUnknownAgentVm) (*types.ScanForUnknownAgentVmResponse, error) {
+	var reqBody, resBody ScanForUnknownAgentVmBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type UninstallBody struct {
+	Req    *types.Uninstall         `xml:"urn:eam Uninstall,omitempty"`
+	Res    *types.UninstallResponse `xml:"urn:eam UninstallResponse,omitempty"`
+	Fault_ *soap.Fault              `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *UninstallBody) Fault() *soap.Fault { return b.Fault_ }
+
+func Uninstall(ctx context.Context, r soap.RoundTripper, req *types.Uninstall) (*types.UninstallResponse, error) {
+	var reqBody, resBody UninstallBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type UnregisterAgentVmBody struct {
+	Req    *types.UnregisterAgentVm         `xml:"urn:eam UnregisterAgentVm,omitempty"`
+	Res    *types.UnregisterAgentVmResponse `xml:"urn:eam UnregisterAgentVmResponse,omitempty"`
+	Fault_ *soap.Fault                      `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *UnregisterAgentVmBody) Fault() *soap.Fault { return b.Fault_ }
+
+func UnregisterAgentVm(ctx context.Context, r soap.RoundTripper, req *types.UnregisterAgentVm) (*types.UnregisterAgentVmResponse, error) {
+	var reqBody, resBody UnregisterAgentVmBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
+
+type UpdateBody struct {
+	Req    *types.Update         `xml:"urn:eam Update,omitempty"`
+	Res    *types.UpdateResponse `xml:"urn:eam UpdateResponse,omitempty"`
+	Fault_ *soap.Fault           `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
+}
+
+func (b *UpdateBody) Fault() *soap.Fault { return b.Fault_ }
+
+func Update(ctx context.Context, r soap.RoundTripper, req *types.Update) (*types.UpdateResponse, error) {
+	var reqBody, resBody UpdateBody
+
+	reqBody.Req = req
+
+	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
+		return nil, err
+	}
+
+	return resBody.Res, nil
+}
diff --git a/eam/mo/agency.go b/eam/mo/agency.go
new file mode 100644
index 00000000..e00e939b
--- /dev/null
+++ b/eam/mo/agency.go
@@ -0,0 +1,33 @@
+/*
+Copyright (c) 2021 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 mo
+
+import (
+	"github.com/vmware/govmomi/eam/types"
+	vim "github.com/vmware/govmomi/vim25/types"
+)
+
+// Agency handles the deployment of a single type of agent virtual
+// machine and any associated VIB bundle, on a set of compute resources.
+type Agency struct {
+	EamObject `yaml:",inline"`
+
+	Agent      []vim.ManagedObjectReference `json:"agent,omitempty"`
+	Config     types.AgencyConfigInfo       `json:"config"`
+	Runtime    types.EamObjectRuntimeInfo   `json:"runtime"`
+	SolutionId string                       `json:"solutionId,omitempty"`
+}
diff --git a/eam/mo/agent.go b/eam/mo/agent.go
new file mode 100644
index 00000000..e20983cd
--- /dev/null
+++ b/eam/mo/agent.go
@@ -0,0 +1,31 @@
+/*
+Copyright (c) 2021 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 mo
+
+import (
+	"github.com/vmware/govmomi/eam/types"
+)
+
+// Agenct is the vSphere ESX Agent Manager managed object responsible
+// fordeploying an Agency on a single host. The Agent maintains the state
+// of the current deployment in its runtime information
+type Agent struct {
+	EamObject `yaml:",inline"`
+
+	Config  types.AgentConfigInfo  `json:"config,omitempty"`
+	Runtime types.AgentRuntimeInfo `json:"runtime,omitempty"`
+}
diff --git a/eam/mo/eam_object.go b/eam/mo/eam_object.go
new file mode 100644
index 00000000..fc3c70f2
--- /dev/null
+++ b/eam/mo/eam_object.go
@@ -0,0 +1,36 @@
+/*
+Copyright (c) 2021 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 mo
+
+import (
+	"github.com/vmware/govmomi/eam/types"
+	vim "github.com/vmware/govmomi/vim25/types"
+)
+
+// EamObject contains the fields common to all EAM objects.
+type EamObject struct {
+	Self  vim.ManagedObjectReference `json:"self"`
+	Issue []types.BaseIssue          `json:"issue,omitempty"`
+}
+
+func (m EamObject) String() string {
+	return m.Self.String()
+}
+
+func (m EamObject) Reference() vim.ManagedObjectReference {
+	return m.Self
+}
diff --git a/eam/mo/esx_agent_manager.go b/eam/mo/esx_agent_manager.go
new file mode 100644
index 00000000..148c88f4
--- /dev/null
+++ b/eam/mo/esx_agent_manager.go
@@ -0,0 +1,29 @@
+/*
+Copyright (c) 2021 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 mo
+
+import (
+	vim "github.com/vmware/govmomi/vim25/types"
+)
+
+// EsxAgentManager is the main entry point for a solution to create
+// agencies in the vSphere ESX Agent Manager server.
+type EsxAgentManager struct {
+	EamObject `yaml:",inline"`
+
+	Agency []vim.ManagedObjectReference `json:"agency,omitempty"`
+}
diff --git a/eam/object/agency.go b/eam/object/agency.go
new file mode 100644
index 00000000..64246974
--- /dev/null
+++ b/eam/object/agency.go
@@ -0,0 +1,166 @@
+/*
+Copyright (c) 2021 VMware, Inc. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package object
+
+import (
+	"context"
+
+	"github.com/vmware/govmomi/eam"
+	"github.com/vmware/govmomi/eam/methods"
+	"github.com/vmware/govmomi/eam/types"
+	vim "github.com/vmware/govmomi/vim25/types"
+)
+
+type Agency struct {
+	EamObject
+}
+
+// NewAgency returns a wrapper for an Agency managed object.
+func NewAgency(c *eam.Client, ref vim.ManagedObjectReference) Agency {
+	return Agency{
+		EamObject: EamObject{
+			c: c,
+			r: ref,
+		},
+	}
+}
+
+func (m Agency) Agents(ctx context.Context) ([]Agent, error) {
+	resp, err := methods.QueryAgent(ctx, m.c, &types.QueryAgent{
+		This: m.r,
+	})
+	if err != nil {
+		return nil, err
+	}
+	objs := make([]Agent, len(resp.Returnval))
+	for i := range resp.Returnval {
+		objs[i].c = m.c
+		objs[i].r = resp.Returnval[i]
+	}
+	return objs, nil
+}
+
+func (m Agency) Config(ctx context.Context) (*types.AgencyConfigInfo, error) {
+	resp, err := methods.QueryConfig(ctx, m.c, &types.QueryConfig{
+		This: m.r,
+	})
+	if err != nil {
+		return nil, err
+	}
+	return &resp.Returnval, nil
+}
+
+func (m Agency) Runtime(ctx context.Context) (*types.EamObjectRuntimeInfo, error) {
+	resp, err := methods.AgencyQueryRuntime(ctx, m.c, &types.AgencyQueryRuntime{
+		This: m.r,
+	})
+	if err != nil {
+		return nil, err
+	}
+	return resp.Returnval.GetEamObjectRuntimeInfo(), nil
+}
+
+func (m Agency) SolutionId(ctx context.Context) (string, error) {
+	resp, err := methods.QuerySolutionId(ctx, m.c, &types.QuerySolutionId{
+		This: m.r,
+	})
+	if err != nil {
+		return "", err
+	}
+	return resp.Returnval, nil
+}
+
+func (m Agency) Destroy(ctx context.Context) error {
+	_, err := methods.DestroyAgency(ctx, m.c, &types.DestroyAgency{
+		This: m.r,
+	})
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (m Agency) Disable(ctx context.Context) error {
+	_, err := methods.Disable(ctx, m.c, &types.Disable{
+		This: m.r,
+	})
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (m Agency) Enable(ctx context.Context) error {
+	_, err := methods.Enable(ctx, m.c, &types.Enable{
+		This: m.r,
+	})
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (m Agency) RegisterAgentVm(
+	ctx context.Context,
+	agentVmMoRef vim.ManagedObjectReference) (*Agent, error) {
+
+	resp, err := methods.RegisterAgentVm(ctx, m.c, &types.RegisterAgentVm{
+		This:    m.r,
+		AgentVm: agentVmMoRef,
+	})
+	if err != nil {
+		return nil, err
+	}
+	return NewAgent(m.c, resp.Returnval), nil
+}
+
+func (m Agency) Uninstall(ctx context.Context) error {
+	_, err := methods.Uninstall(ctx, m.c, &types.Uninstall{
+		This: m.r,
+	})
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (m Agency) UnregisterAgentVm(
+	ctx context.Context,
+	agentVmMoRef vim.ManagedObjectReference) error {
+
+	_, err := methods.UnregisterAgentVm(ctx, m.c, &types.UnregisterAgentVm{
+		This:    m.r,
+		AgentVm: agentVmMoRef,
+	})
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (m Agency) Update(
+	ctx context.Context,
+	config types.AgencyConfigInfo) error {
+
+	_, err := methods.Update(ctx, m.c, &types.Update{
+		This: m.r,
+	})
+	if err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/eam/object/agent.go b/eam/object/agent.go
new file mode 100644
index 00000000..72bef4d9
--- /dev/null
+++ b/eam/object/agent.go
@@ -0,0 +1,70 @@
+/*
+Copyright (c) 2021 VMware, Inc. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package object
+
+import (
+	"context"
+
+	"github.com/vmware/govmomi/eam"
+	"github.com/vmware/govmomi/eam/methods"
+	"github.com/vmware/govmomi/eam/types"
+	vim "github.com/vmware/govmomi/vim25/types"
+)
+
+type Agent struct {
+	EamObject
+}
+
+// NewAgent returns a wrapper for an Agent managed object.
+func NewAgent(c *eam.Client, ref vim.ManagedObjectReference) *Agent {
+	return &Agent{
+		EamObject: EamObject{
+			c: c,
+			r: ref,
+		},
+	}
+}
+
+func (m Agent) Config(ctx context.Context) (*types.AgentConfigInfo, error) {
+	resp, err := methods.AgentQueryConfig(ctx, m.c, &types.AgentQueryConfig{
+		This: m.r,
+	})
+	if err != nil {
+		return nil, err
+	}
+	return &resp.Returnval, nil
+}
+
+func (m Agent) Runtime(ctx context.Context) (*types.AgentRuntimeInfo, error) {
+	resp, err := methods.AgentQueryRuntime(ctx, m.c, &types.AgentQueryRuntime{
+		This: m.r,
+	})
+	if err != nil {
+		return nil, err
+	}
+	return &resp.Returnval, nil
+}
+
+func (m Agent) MarkAsAvailable(ctx context.Context) error {
+	_, err := methods.MarkAsAvailable(ctx, m.c, &types.MarkAsAvailable{
+		This: m.r,
+	})
+	if err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/eam/object/eam_object.go b/eam/object/eam_object.go
new file mode 100644
index 00000000..2c045f7c
--- /dev/null
+++ b/eam/object/eam_object.go
@@ -0,0 +1,98 @@
+/*
+Copyright (c) 2021 VMware, Inc. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package object
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/vmware/govmomi/eam"
+	"github.com/vmware/govmomi/eam/methods"
+	"github.com/vmware/govmomi/eam/types"
+	vim "github.com/vmware/govmomi/vim25/types"
+)
+
+// EamObject contains the fields and functions common to all objects.
+type EamObject struct {
+	c *eam.Client
+	r vim.ManagedObjectReference
+}
+
+func (m EamObject) String() string {
+	return fmt.Sprintf("%v", m.Reference())
+}
+
+func (m EamObject) Reference() vim.ManagedObjectReference {
+	return m.r
+}
+
+func (m EamObject) Client() *eam.Client {
+	return m.c
+}
+
+func (m EamObject) AddIssue(
+	ctx context.Context,
+	issue types.BaseIssue) (types.BaseIssue, error) {
+
+	resp, err := methods.AddIssue(ctx, m.c, &types.AddIssue{
+		This:  m.r,
+		Issue: issue,
+	})
+	if err != nil {
+		return nil, err
+	}
+	return resp.Returnval, nil
+}
+
+func (m EamObject) Issues(
+	ctx context.Context,
+	issueKeys ...int32) ([]types.BaseIssue, error) {
+
+	resp, err := methods.QueryIssue(ctx, m.c, &types.QueryIssue{
+		This:     m.r,
+		IssueKey: issueKeys,
+	})
+	if err != nil {
+		return nil, err
+	}
+	return resp.Returnval, nil
+}
+
+func (m EamObject) Resolve(
+	ctx context.Context,
+	issueKeys []int32) ([]int32, error) {
+
+	resp, err := methods.Resolve(ctx, m.c, &types.Resolve{
+		This:     m.r,
+		IssueKey: issueKeys,
+	})
+	if err != nil {
+		return nil, err
+	}
+	return resp.Returnval, nil
+}
+
+func (m EamObject) ResolveAll(ctx context.Context) error {
+
+	_, err := methods.ResolveAll(ctx, m.c, &types.ResolveAll{
+		This: m.r,
+	})
+	if err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/eam/object/esx_agent_manager.go b/eam/object/esx_agent_manager.go
new file mode 100644
index 00000000..d400b194
--- /dev/null
+++ b/eam/object/esx_agent_manager.go
@@ -0,0 +1,84 @@
+/*
+Copyright (c) 2021 VMware, Inc. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package object
+
+import (
+	"context"
+
+	"github.com/vmware/govmomi/eam"
+	"github.com/vmware/govmomi/eam/methods"
+	"github.com/vmware/govmomi/eam/types"
+	vim "github.com/vmware/govmomi/vim25/types"
+)
+
+type EsxAgentManager struct {
+	EamObject
+}
+
+// NewEsxAgentManager returns a wrapper for an EsxAgentManager managed object.
+func NewEsxAgentManager(c *eam.Client, ref vim.ManagedObjectReference) EsxAgentManager {
+	return EsxAgentManager{
+		EamObject: EamObject{
+			c: c,
+			r: ref,
+		},
+	}
+}
+
+func (m EsxAgentManager) CreateAgency(
+	ctx context.Context,
+	config types.AgencyConfigInfo,
+	initialGoalState string) (Agency, error) {
+
+	var agency Agency
+	resp, err := methods.CreateAgency(ctx, m.c, &types.CreateAgency{
+		This:             m.r,
+		AgencyConfigInfo: config,
+		InitialGoalState: initialGoalState,
+	})
+	if err != nil {
+		return agency, err
+	}
+	agency.c = m.c
+	agency.r = resp.Returnval
+	return agency, nil
+}
+
+func (m EsxAgentManager) Agencies(ctx context.Context) ([]Agency, error) {
+	resp, err := methods.QueryAgency(ctx, m.c, &types.QueryAgency{
+		This: m.r,
+	})
+	if err != nil {
+		return nil, err
+	}
+	objs := make([]Agency, len(resp.Returnval))
+	for i := range resp.Returnval {
+		objs[i].c = m.c
+		objs[i].r = resp.Returnval[i]
+	}
+	return objs, nil
+}
+
+func (m EsxAgentManager) ScanForUnknownAgentVm(ctx context.Context) error {
+	_, err := methods.ScanForUnknownAgentVm(ctx, m.c, &types.ScanForUnknownAgentVm{
+		This: m.r,
+	})
+	if err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/eam/simulator/README.md b/eam/simulator/README.md
new file mode 100644
index 00000000..d3805956
--- /dev/null
+++ b/eam/simulator/README.md
@@ -0,0 +1,23 @@
+# ESX Agent Manager (EAM) Simulator
+
+This simulator package works with the existing vC Sim. Please see [`simulator_test.go`](simulator_test.go) for an example of how to use the EAM simulator with vC Sim.
+
+## Use Docker to Simulate Agent VMs
+
+It is possible to run the simulator test whereby the creation of agent VMs results in the creation of containers in Docker to simulate the lifecycle of the VMs. Docker must be installed and running, but other than that, simply set the value of the `AgentConfigInfo.OvfPackageUrl` field to a:
+
+* non-empty string,
+* that does not start with `./`, `/`, or `https?:`.
+
+If those conditions are met, then the EAM simulator treats this value as the name of a Docker image, and will create a simualted VM with `RUN.container` key set to the value, causing the core vC Simulator to simulate the VM with a container based on the specified image.
+
+
+### Example of Simulated Agent VMs
+
+There is a test that provides an example of this simulated agent VM behavior. Again, Docker must be installed and running, but otherwise just execute the following:
+
+```shell
+go test -v ./simulator/ -powerOnVMs
+```
+
+The flag `-powerOnVMs` causes the the simulator test code to create the agencies with agent configuration information that uses the `nginx` container to simulate two VMs. The presence of the flag then causes the VMs to be powered on, and the test waits for the agent runtime information to report the VMs' power state and IP addresses.
diff --git a/eam/simulator/agency.go b/eam/simulator/agency.go
new file mode 100644
index 00000000..01dc9d81
--- /dev/null
+++ b/eam/simulator/agency.go
@@ -0,0 +1,245 @@
+/*
+Copyright (c) 2021 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 (
+	"fmt"
+	"math/rand"
+	"time"
+
+	"github.com/google/uuid"
+
+	"github.com/vmware/govmomi/eam/internal"
+	"github.com/vmware/govmomi/eam/methods"
+	"github.com/vmware/govmomi/eam/mo"
+	"github.com/vmware/govmomi/eam/types"
+	"github.com/vmware/govmomi/simulator"
+	"github.com/vmware/govmomi/vim25/soap"
+	vim "github.com/vmware/govmomi/vim25/types"
+)
+
+// Agency handles the deployment of a single type of agent virtual
+// machine and any associated VIB bundle, on a set of compute resources.
+type Agency struct {
+	EamObject
+	mo.Agency
+}
+
+// NewAgency returns a new Agency as if CreateAgency were called on the
+// EsxAgentManager object.
+func NewAgency(
+	ctx *simulator.Context,
+	agencyConfig types.AgencyConfigInfo,
+	initialGoalState string) (*Agency, vim.BaseMethodFault) {
+
+	if agencyConfig.AgentName == "" {
+		agencyConfig.AgentName = agencyConfig.AgencyName
+	}
+
+	// Define a new Agency object.
+	agency := &Agency{
+		EamObject: EamObject{
+			Self: vim.ManagedObjectReference{
+				Type:  internal.Agency,
+				Value: uuid.New().String(),
+			},
+		},
+		Agency: mo.Agency{
+			Config: agencyConfig,
+			Runtime: types.EamObjectRuntimeInfo{
+				GoalState: initialGoalState,
+			},
+		},
+	}
+
+	// Register the agency with the registry in order for the agency to
+	// start receiving API calls from clients.
+	ctx.Map.Put(agency)
+
+	// Define a random numbrer generator to help select resources for the
+	// agent VMs.
+	rng := rand.New(rand.NewSource(time.Now().UnixNano()))
+
+	// Alias the registry that contains the vim25 objects.
+	vimMap := simulator.Map
+
+	// Create the agents.
+	for i, agentConfig := range agencyConfig.AgentConfig {
+
+		// vmName follows the defined pattern for naming agent VMs
+		vmName := fmt.Sprintf("%s (%d)", agencyConfig.AgentName, i+1)
+
+		// vmPlacement contains MoRefs to the resources required to create and
+		// place the VM inside of the inventory.
+		vmPlacement, err := getAgentVMPlacementOptions(
+			ctx,
+			vimMap,
+			rng,
+			i,
+			agencyConfig)
+		if err != nil {
+			return nil, &vim.MethodFault{
+				FaultCause: &vim.LocalizedMethodFault{
+					LocalizedMessage: err.Error(),
+				},
+			}
+		}
+
+		if _, fault := NewAgent(
+			ctx,
+			agency.Self,
+			agentConfig,
+			vmName,
+			vmPlacement); fault != nil {
+
+			return nil, fault
+		}
+	}
+
+	return agency, nil
+}
+
+func (m *Agency) AgencyQueryRuntime(
+	ctx *simulator.Context,
+	req *types.AgencyQueryRuntime) soap.HasFault {
+
+	// Copy the agency's issues into its runtime object upon return.
+	m.Runtime.Issue = make([]types.BaseIssue, len(m.Issue))
+	i := 0
+	for _, issue := range m.Issue {
+		m.Runtime.Issue[i] = issue
+		i++
+	}
+
+	return &methods.AgencyQueryRuntimeBody{
+		Res: &types.AgencyQueryRuntimeResponse{
+			Returnval: &m.Runtime,
+		},
+	}
+}
+
+func (m *Agency) DestroyAgency(
+	ctx *simulator.Context,
+	req *types.DestroyAgency) soap.HasFault {
+
+	// Remove any agents associated with this agency.
+	agentObjs := ctx.Map.AllReference(internal.Agent)
+	for _, obj := range agentObjs {
+		agent := obj.(*Agent)
+		if *agent.Runtime.Agency == m.Self {
+			ctx.Map.Remove(ctx, agent.Self)
+		}
+	}
+
+	ctx.Map.Remove(ctx, m.Self)
+	return &methods.DestroyAgencyBody{
+		Res: &types.DestroyAgencyResponse{},
+	}
+}
+
+func (m *Agency) Disable(
+	ctx *simulator.Context,
+	req *types.Disable) soap.HasFault {
+
+	m.Runtime.GoalState = string(types.EamObjectRuntimeInfoGoalStateDisabled)
+
+	return &methods.DisableBody{
+		Res: &types.DisableResponse{},
+	}
+}
+
+func (m *Agency) Enable(
+	ctx *simulator.Context,
+	req *types.Enable) soap.HasFault {
+
+	m.Runtime.GoalState = string(types.EamObjectRuntimeInfoGoalStateEnabled)
+
+	return &methods.EnableBody{
+		Res: &types.EnableResponse{},
+	}
+}
+
+func (m *Agency) QueryAgent(
+	ctx *simulator.Context,
+	req *types.QueryAgent) soap.HasFault {
+
+	objs := ctx.Map.AllReference(internal.Agent)
+	moRefs := make([]vim.ManagedObjectReference, len(objs))
+	i := 0
+	for _, ref := range objs {
+		moRefs[i] = ref.Reference()
+		i++
+	}
+	return &methods.QueryAgentBody{
+		Res: &types.QueryAgentResponse{
+			Returnval: moRefs,
+		},
+	}
+}
+
+func (m *Agency) QueryConfig(
+	ctx *simulator.Context,
+	req *types.QueryConfig) soap.HasFault {
+
+	return &methods.QueryConfigBody{
+		Res: &types.QueryConfigResponse{
+			Returnval: m.Config,
+		},
+	}
+}
+
+func (m *Agency) RegisterAgentVm(
+	ctx *simulator.Context,
+	req *types.RegisterAgentVm) soap.HasFault {
+
+	return &methods.RegisterAgentVmBody{
+		Res: &types.RegisterAgentVmResponse{
+			Returnval: vim.ManagedObjectReference{},
+		},
+	}
+}
+
+func (m *Agency) Uninstall(
+	ctx *simulator.Context,
+	req *types.Uninstall) soap.HasFault {
+
+	m.Runtime.GoalState = string(types.EamObjectRuntimeInfoGoalStateUninstalled)
+
+	return &methods.UninstallBody{
+		Res: &types.UninstallResponse{},
+	}
+}
+
+func (m *Agency) UnregisterAgentVm(
+	ctx *simulator.Context,
+	req *types.UnregisterAgentVm) soap.HasFault {
+
+	return &methods.UnregisterAgentVmBody{
+		Res: &types.UnregisterAgentVmResponse{},
+	}
+}
+
+func (m *Agency) Update(
+	ctx *simulator.Context,
+	req *types.Update) soap.HasFault {
+
+	m.Config = req.Config
+
+	return &methods.UpdateBody{
+		Res: &types.UpdateResponse{},
+	}
+}
diff --git a/eam/simulator/agent.go b/eam/simulator/agent.go
new file mode 100644
index 00000000..2ed8e886
--- /dev/null
+++ b/eam/simulator/agent.go
@@ -0,0 +1,266 @@
+/*
+Copyright (c) 2021 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 (
+	"fmt"
+	"log"
+	"time"
+
+	"github.com/google/uuid"
+
+	"github.com/vmware/govmomi/simulator"
+	vimmethods "github.com/vmware/govmomi/vim25/methods"
+	"github.com/vmware/govmomi/vim25/soap"
+	vim "github.com/vmware/govmomi/vim25/types"
+
+	"github.com/vmware/govmomi/eam/internal"
+	"github.com/vmware/govmomi/eam/methods"
+	"github.com/vmware/govmomi/eam/mo"
+	"github.com/vmware/govmomi/eam/types"
+)
+
+// Agenct is the vSphere ESX Agent Manager managed object responsible
+// fordeploying an Agency on a single host. The Agent maintains the state
+// of the current deployment in its runtime information
+type Agent struct {
+	EamObject
+	mo.Agent
+}
+
+type AgentVMPlacementOptions struct {
+	computeResource vim.ManagedObjectReference
+	datacenter      vim.ManagedObjectReference
+	datastore       vim.ManagedObjectReference
+	folder          vim.ManagedObjectReference
+	host            vim.ManagedObjectReference
+	network         vim.ManagedObjectReference
+	pool            vim.ManagedObjectReference
+}
+
+// NewAgent returns a new Agent as if CreateAgency were called on the
+// EsxAgentManager object.
+func NewAgent(
+	ctx *simulator.Context,
+	agency vim.ManagedObjectReference,
+	config types.AgentConfigInfo,
+	vmName string,
+	vmPlacement AgentVMPlacementOptions) (*Agent, vim.BaseMethodFault) {
+
+	vimMap := simulator.Map
+
+	agent := &Agent{
+		EamObject: EamObject{
+			Self: vim.ManagedObjectReference{
+				Type:  internal.Agent,
+				Value: uuid.New().String(),
+			},
+		},
+		Agent: mo.Agent{
+			Config: config,
+			Runtime: types.AgentRuntimeInfo{
+				Agency:               &agency,
+				VmName:               vmName,
+				Host:                 &vmPlacement.host,
+				EsxAgentFolder:       &vmPlacement.folder,
+				EsxAgentResourcePool: &vmPlacement.pool,
+			},
+		},
+	}
+
+	// Register the agent with the registry in order for the agent to start
+	// receiving API calls from clients.
+	ctx.Map.Put(agent)
+
+	createVm := func() (vim.ManagedObjectReference, *vim.LocalizedMethodFault) {
+		var vmRef vim.ManagedObjectReference
+
+		// vmExtraConfig is used when creating the VM for this agent.
+		vmExtraConfig := []vim.BaseOptionValue{}
+
+		// If config.OvfPackageUrl is non-empty and does not appear to point to
+		// a local file or an HTTP URI, then assume it is a container.
+		if url := config.OvfPackageUrl; url != "" && !fsOrHTTPRx.MatchString(url) {
+			vmExtraConfig = append(
+				vmExtraConfig,
+				&vim.OptionValue{
+					Key:   "RUN.container",
+					Value: url,
+				})
+		}
+
+		// Copy the OVF environment properties into the VM's ExtraConfig property.
+		if ovfEnv := config.OvfEnvironment; ovfEnv != nil {
+			for _, ovfProp := range ovfEnv.OvfProperty {
+				vmExtraConfig = append(
+					vmExtraConfig,
+					&vim.OptionValue{
+						Key:   ovfProp.Key,
+						Value: ovfProp.Value,
+					})
+			}
+		}
+
+		datastore := vimMap.Get(vmPlacement.datastore).(*simulator.Datastore)
+		vmPathName := fmt.Sprintf("[%[1]s] %[2]s/%[2]s.vmx", datastore.Name, vmName)
+		vmConfigSpec := vim.VirtualMachineConfigSpec{
+			Name:        vmName,
+			ExtraConfig: vmExtraConfig,
+			Files: &vim.VirtualMachineFileInfo{
+				VmPathName: vmPathName,
+			},
+		}
+
+		// Create the VM for this agent.
+		vmFolder := vimMap.Get(vmPlacement.folder).(*simulator.Folder)
+		createVmTaskRef := vmFolder.CreateVMTask(ctx, &vim.CreateVM_Task{
+			This:   vmFolder.Self,
+			Config: vmConfigSpec,
+			Pool:   vmPlacement.pool,
+			Host:   &vmPlacement.host,
+		}).(*vimmethods.CreateVM_TaskBody).Res.Returnval
+		createVmTask := vimMap.Get(createVmTaskRef).(*simulator.Task)
+
+		// Wait for the task to complete and see if there is an error.
+		createVmTask.Wait()
+		if createVmTask.Info.Error != nil {
+			return vmRef, createVmTask.Info.Error
+		}
+
+		vmRef = createVmTask.Info.Result.(vim.ManagedObjectReference)
+		vm := vimMap.Get(vmRef).(*simulator.VirtualMachine)
+		log.Printf("created agent vm: MoRef=%v, Name=%s", vm.Self, vm.Name)
+
+		// Link the agent to this VM.
+		agent.Runtime.Vm = &vm.Self
+
+		return vm.Self, nil
+	}
+
+	vmRef, err := createVm()
+	if err != nil {
+		return nil, &vim.RuntimeFault{
+			MethodFault: vim.MethodFault{
+				FaultCause: err,
+			},
+		}
+	}
+
+	// Start watching this VM and updating the agent's information about the VM.
+	go func(eamReg, vimReg *simulator.Registry) {
+		var (
+			ctx    = simulator.SpoofContext()
+			ticker = time.NewTicker(1 * time.Second)
+			vmName string
+		)
+		for range ticker.C {
+			eamReg.WithLock(ctx, agent.Self, func() {
+				agentObj := eamReg.Get(agent.Self)
+				if agentObj == nil {
+					log.Printf("not found: %v", agent.Self)
+					// If the agent no longer exists then stop watching it.
+					ticker.Stop()
+					return
+				}
+
+				updateAgent := func(vm *simulator.VirtualMachine) {
+					if vmName == "" {
+						vmName = vm.Config.Name
+					}
+
+					// Update the agent's properties from the VM.
+					agent := agentObj.(*Agent)
+					agent.Runtime.VmPowerState = vm.Runtime.PowerState
+					if guest := vm.Summary.Guest; guest == nil {
+						agent.Runtime.VmIp = ""
+					} else {
+						agent.Runtime.VmIp = guest.IpAddress
+					}
+				}
+
+				vimReg.WithLock(ctx, vmRef, func() {
+					if vmObj := vimReg.Get(vmRef); vmObj != nil {
+						updateAgent(vmObj.(*simulator.VirtualMachine))
+					} else {
+						// If the VM no longer exists then create a new agent VM.
+						log.Printf(
+							"creating new agent vm: %v, %v, vmName=%s",
+							agent.Self, vmRef, vmName)
+
+						newVmRef, err := createVm()
+						if err != nil {
+							log.Printf(
+								"failed to create new agent vm: %v, %v, vmName=%s, err=%v",
+								agent.Self, vmRef, vmName, *err)
+							ticker.Stop()
+							return
+						}
+
+						// Make sure the vmRef variable is assigned to the new
+						// VM's reference for the next time through this loop.
+						vmRef = newVmRef
+
+						// Get a lock for the *new* VM.
+						vimReg.WithLock(ctx, vmRef, func() {
+							vmObj = vimReg.Get(vmRef)
+							if vmObj == nil {
+								log.Printf("not found: %v", vmRef)
+								ticker.Stop()
+								return
+							}
+							updateAgent(vmObj.(*simulator.VirtualMachine))
+						})
+					}
+
+				})
+			})
+		}
+	}(ctx.Map, vimMap)
+
+	return agent, nil
+}
+
+func (m *Agent) AgentQueryConfig(
+	ctx *simulator.Context,
+	req *types.AgentQueryConfig) soap.HasFault {
+
+	return &methods.AgentQueryConfigBody{
+		Res: &types.AgentQueryConfigResponse{
+			Returnval: m.Config,
+		},
+	}
+}
+
+func (m *Agent) AgentQueryRuntime(
+	ctx *simulator.Context,
+	req *types.AgentQueryRuntime) soap.HasFault {
+
+	return &methods.AgentQueryRuntimeBody{
+		Res: &types.AgentQueryRuntimeResponse{
+			Returnval: m.Runtime,
+		},
+	}
+}
+
+func (m *Agent) MarkAsAvailable(
+	ctx *simulator.Context,
+	req *types.MarkAsAvailable) soap.HasFault {
+
+	return &methods.MarkAsAvailableBody{
+		Res: &types.MarkAsAvailableResponse{},
+	}
+}
diff --git a/eam/simulator/eam_object.go b/eam/simulator/eam_object.go
new file mode 100644
index 00000000..ddb57329
--- /dev/null
+++ b/eam/simulator/eam_object.go
@@ -0,0 +1,145 @@
+/*
+Copyright (c) 2021 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 (
+	"time"
+
+	"github.com/vmware/govmomi/eam/methods"
+	"github.com/vmware/govmomi/eam/mo"
+	"github.com/vmware/govmomi/eam/types"
+	"github.com/vmware/govmomi/simulator"
+	"github.com/vmware/govmomi/vim25/soap"
+	vim "github.com/vmware/govmomi/vim25/types"
+)
+
+// EamObject contains the fields and functions common to all objects.
+type EamObject mo.EamObject
+
+func (m *EamObject) Reference() vim.ManagedObjectReference {
+	return m.Self
+}
+
+func (m *EamObject) AddIssue(
+	ctx *simulator.Context,
+	req *types.AddIssue) soap.HasFault {
+
+	// Get the typed issue to ensure the correct type of issue is stored and
+	// returned to the caller.
+	issue := issueType(req.Issue)
+
+	// Get the base issue in order to assign an issue key and timestamp.
+	baseIssue := issue.GetIssue()
+	baseIssue.Key = nextAvailableIssueKey()
+	baseIssue.Time = time.Now().UTC()
+
+	// Store and return the typed issue.
+	m.Issue = append(m.Issue, issue)
+
+	return &methods.AddIssueBody{
+		Res: &types.AddIssueResponse{
+			Returnval: issue,
+		},
+	}
+}
+
+func (m *EamObject) QueryIssue(
+	ctx *simulator.Context,
+	req *types.QueryIssue) soap.HasFault {
+
+	var issues []types.BaseIssue
+
+	if len(req.IssueKey) == 0 {
+		// If no keys were specified then return all issues.
+		issues = m.Issue
+	} else {
+		// Get only the issues for the specified keys.
+		for _, issueKey := range req.IssueKey {
+			for _, issue := range m.Issue {
+				if issue.GetIssue().Key == issueKey {
+					issues = append(issues, issue)
+				}
+			}
+		}
+	}
+
+	return &methods.QueryIssueBody{
+		Res: &types.QueryIssueResponse{
+			Returnval: issues,
+		},
+	}
+}
+
+func (m *EamObject) Resolve(
+	ctx *simulator.Context,
+	req *types.Resolve) soap.HasFault {
+
+	// notFoundKeys is a list of issue keys that were sent but
+	// not found for the given object.
+	notFoundKeys := []int32{}
+
+	// issueExists is a helper function that returns true
+	issueExists := func(issueKey int32) bool {
+		for _, k := range req.IssueKey {
+			if k == issueKey {
+				return true
+			}
+		}
+		return false
+	}
+
+	// Iterate over the object's issues, and if a key matches, then remove
+	// the issue from the list of the object's issues. If a key does not match
+	// then record the key as notFound.
+	for i := 0; i < len(m.Issue); i++ {
+		issueKey := m.Issue[i].GetIssue().Key
+
+		if ok := issueExists(issueKey); ok {
+			// Update the object's issue list so that it no longer includes
+			// the current issue.
+			m.Issue = append(m.Issue[:i], m.Issue[i+1:]...)
+			i--
+
+			// Ensure the key is removed from the global key space.
+			freeIssueKey(issueKey)
+		} else {
+			notFoundKeys = append(notFoundKeys, issueKey)
+		}
+	}
+
+	return &methods.ResolveBody{
+		Res: &types.ResolveResponse{
+			Returnval: notFoundKeys,
+		},
+	}
+}
+
+func (m *EamObject) ResolveAll(
+	ctx *simulator.Context,
+	req *types.ResolveAll) soap.HasFault {
+
+	// Iterate over the issues and ensure each one of their keys are removed
+	// from the global key space.
+	for _, issue := range m.Issue {
+		freeIssueKey(issue.GetIssue().Key)
+	}
+
+	// Reset the object's issues.
+	m.Issue = m.Issue[:0]
+
+	return &methods.ResolveAllBody{Res: &types.ResolveAllResponse{}}
+}
diff --git a/eam/simulator/esx_agent_manager.go b/eam/simulator/esx_agent_manager.go
new file mode 100644
index 00000000..db240b90
--- /dev/null
+++ b/eam/simulator/esx_agent_manager.go
@@ -0,0 +1,81 @@
+/*
+Copyright (c) 2021 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/eam/internal"
+	"github.com/vmware/govmomi/eam/methods"
+	"github.com/vmware/govmomi/eam/types"
+	"github.com/vmware/govmomi/simulator"
+	"github.com/vmware/govmomi/vim25/soap"
+	vim "github.com/vmware/govmomi/vim25/types"
+)
+
+// EsxAgentManager is the main entry point for a solution to create
+// agencies in the vSphere ESX Agent Manager server.
+type EsxAgentManager struct {
+	EamObject
+}
+
+func (m *EsxAgentManager) CreateAgency(
+	ctx *simulator.Context,
+	req *types.CreateAgency) soap.HasFault {
+
+	var res methods.CreateAgencyBody
+
+	if agency, err := NewAgency(
+		ctx,
+		req.AgencyConfigInfo,
+		req.InitialGoalState); err != nil {
+
+		res.Fault_ = simulator.Fault("", err)
+
+	} else {
+		res.Res = &types.CreateAgencyResponse{
+			Returnval: agency.Self,
+		}
+	}
+
+	return &res
+}
+
+func (m *EsxAgentManager) QueryAgency(
+	ctx *simulator.Context,
+	req *types.QueryAgency) soap.HasFault {
+
+	objs := ctx.Map.AllReference(internal.Agency)
+	moRefs := make([]vim.ManagedObjectReference, len(objs))
+	i := 0
+	for _, ref := range objs {
+		moRefs[i] = ref.Reference()
+		i++
+	}
+	return &methods.QueryAgencyBody{
+		Res: &types.QueryAgencyResponse{
+			Returnval: moRefs,
+		},
+	}
+}
+
+func (m *EsxAgentManager) ScanForUnknownAgentVm(
+	ctx *simulator.Context,
+	req *types.ScanForUnknownAgentVm) soap.HasFault {
+
+	return &methods.ScanForUnknownAgentVmBody{
+		Res: &types.ScanForUnknownAgentVmResponse{},
+	}
+}
diff --git a/eam/simulator/issue.go b/eam/simulator/issue.go
new file mode 100644
index 00000000..bbe597ec
--- /dev/null
+++ b/eam/simulator/issue.go
@@ -0,0 +1,70 @@
+/*
+Copyright (c) 2021 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 (
+	"sync"
+
+	"github.com/vmware/govmomi/eam/types"
+)
+
+var (
+	activeIssueKeys   = map[int32]struct{}{}
+	activeIssueKeysMu sync.RWMutex
+)
+
+func nextAvailableIssueKey() int32 {
+	activeIssueKeysMu.Lock()
+	defer activeIssueKeysMu.Unlock()
+	for i := int32(1); ; i++ {
+		if _, isActiveKey := activeIssueKeys[i]; !isActiveKey {
+			activeIssueKeys[i] = struct{}{}
+			return i
+		}
+	}
+}
+
+func freeIssueKey(i int32) {
+	activeIssueKeysMu.Lock()
+	defer activeIssueKeysMu.Unlock()
+	delete(activeIssueKeys, i)
+}
+
+func issueType(issue types.BaseIssue) types.BaseIssue {
+	switch typedIssue := issue.(type) {
+	case types.BaseVmNotDeployed:
+		return typedIssue.GetVmNotDeployed()
+	case types.BaseVmDeployed:
+		return typedIssue.GetVmDeployed()
+	case types.BaseVmPoweredOff:
+		return typedIssue.GetVmPoweredOff()
+	case types.BaseVmIssue:
+		return typedIssue.GetVmIssue()
+	case types.BaseVibNotInstalled:
+		return typedIssue.GetVibNotInstalled()
+	case types.BaseVibIssue:
+		return typedIssue.GetVibIssue()
+	case types.BaseAgentIssue:
+		return typedIssue.GetAgentIssue()
+	case types.BaseAgencyIssue:
+		return typedIssue.GetAgencyIssue()
+	case types.BaseHostIssue:
+		return typedIssue.GetHostIssue()
+	default:
+		return issue
+	}
+}
diff --git a/eam/simulator/simulator.go b/eam/simulator/simulator.go
new file mode 100644
index 00000000..19f01c7a
--- /dev/null
+++ b/eam/simulator/simulator.go
@@ -0,0 +1,44 @@
+/*
+Copyright (c) 2021 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/eam"
+	"github.com/vmware/govmomi/simulator"
+)
+
+func init() {
+	simulator.RegisterEndpoint(func(s *simulator.Service, r *simulator.Registry) {
+		if r.IsVPX() {
+			s.RegisterSDK(New())
+		}
+	})
+}
+
+func New() *simulator.Registry {
+	r := simulator.NewRegistry()
+	r.Namespace = eam.Namespace
+	r.Path = eam.Path
+
+	r.Put(&EsxAgentManager{
+		EamObject: EamObject{
+			Self: eam.EsxAgentManager,
+		},
+	})
+
+	return r
+}
diff --git a/eam/simulator/utils.go b/eam/simulator/utils.go
new file mode 100644
index 00000000..2e2c6a7d
--- /dev/null
+++ b/eam/simulator/utils.go
@@ -0,0 +1,209 @@
+/*
+Copyright (c) 2021 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 (
+	"errors"
+	"fmt"
+	"math/rand"
+	"regexp"
+
+	"github.com/vmware/govmomi/eam/types"
+	vimobj "github.com/vmware/govmomi/object"
+	"github.com/vmware/govmomi/simulator"
+	vimmo "github.com/vmware/govmomi/vim25/mo"
+	vim "github.com/vmware/govmomi/vim25/types"
+)
+
+var (
+	// fsOrHTTPRx matches a URI that is either on the local file
+	// system or an HTTP endpoint.
+	fsOrHTTPRx = regexp.MustCompile(`^(?:\.?/)|(?:http[s]?:)`)
+)
+
+var (
+	agentVmDatastoreEmptyErr     = errors.New("AgentVmDatastore is empty")
+	agentVmNetworkEmptyErr       = errors.New("AgentVmNetwork is empty")
+	foldersEmptyErr              = errors.New("Folders is empty")
+	scopeComputeResourceEmptyErr = errors.New("Scope.ComputeResource is empty")
+	poolRefNilErr                = errors.New("Unable to determine ResourcePool from ComputeResource")
+)
+
+func getAgentVMPlacementOptions(
+	ctx *simulator.Context,
+	reg *simulator.Registry,
+	r *rand.Rand, i int,
+	agencyConfig types.AgencyConfigInfo) (AgentVMPlacementOptions, error) {
+
+	var opts AgentVMPlacementOptions
+
+	if l := len(agencyConfig.AgentVmDatastore); l == 0 {
+		return opts, agentVmDatastoreEmptyErr
+	} else if l == len(agencyConfig.AgentConfig) {
+		opts.datastore = agencyConfig.AgentVmDatastore[i]
+	} else {
+		opts.datastore = agencyConfig.AgentVmDatastore[r.Intn(l)]
+	}
+
+	if l := len(agencyConfig.AgentVmNetwork); l == 0 {
+		return opts, agentVmNetworkEmptyErr
+	} else if l == len(agencyConfig.AgentConfig) {
+		opts.network = agencyConfig.AgentVmNetwork[i]
+	} else {
+		opts.network = agencyConfig.AgentVmNetwork[r.Intn(l)]
+	}
+
+	if l := len(agencyConfig.Folders); l == 0 {
+		return opts, foldersEmptyErr
+	} else if l == len(agencyConfig.AgentConfig) {
+		opts.folder = agencyConfig.Folders[i].FolderId
+		opts.datacenter = agencyConfig.Folders[i].DatacenterId
+	} else {
+		j := r.Intn(l)
+		opts.folder = agencyConfig.Folders[j].FolderId
+		opts.datacenter = agencyConfig.Folders[j].DatacenterId
+	}
+
+	if l := len(agencyConfig.ResourcePools); l == 0 {
+		switch tscope := agencyConfig.Scope.(type) {
+		case *types.AgencyComputeResourceScope:
+			crRefs := tscope.ComputeResource
+			if l := len(crRefs); l == 0 {
+				return opts, scopeComputeResourceEmptyErr
+			} else if l == len(agencyConfig.AgentConfig) {
+				opts.computeResource = crRefs[i]
+			} else {
+				opts.computeResource = crRefs[r.Intn(l)]
+			}
+			poolRef, err := getPoolFromComputeResource(ctx, reg, opts.computeResource)
+			if err != nil {
+				return opts, err
+			}
+			opts.pool = *poolRef
+		}
+	} else if l == len(agencyConfig.AgentConfig) {
+		opts.pool = agencyConfig.ResourcePools[i].ResourcePoolId
+		opts.computeResource = agencyConfig.ResourcePools[i].ComputeResourceId
+	} else {
+		j := r.Intn(l)
+		opts.pool = agencyConfig.ResourcePools[j].ResourcePoolId
+		opts.computeResource = agencyConfig.ResourcePools[j].ComputeResourceId
+	}
+
+	hosts := getHostsFromPool(ctx, reg, opts.pool)
+	if l := len(hosts); l == 0 {
+		return opts, fmt.Errorf("HostSystems not found for %v", opts.pool)
+	} else if l == len(agencyConfig.AgentConfig) {
+		opts.host = hosts[i]
+	} else {
+		opts.host = hosts[r.Intn(l)]
+	}
+
+	return opts, nil
+}
+
+func getPoolFromComputeResource(
+	ctx *simulator.Context,
+	reg *simulator.Registry,
+	computeResource vim.ManagedObjectReference) (*vim.ManagedObjectReference, error) {
+
+	var poolRef *vim.ManagedObjectReference
+	crObj := reg.Get(computeResource)
+	if crObj == nil {
+		return nil, fmt.Errorf("%v not in registry", computeResource)
+	}
+	ctx.WithLock(crObj, func() {
+		switch cr := crObj.(type) {
+		case *vimmo.ComputeResource:
+			poolRef = cr.ResourcePool
+		case *simulator.ClusterComputeResource:
+			poolRef = cr.ResourcePool
+		default:
+			panic(fmt.Errorf(
+				"%v is not a %s or %s",
+				crObj,
+				"*mo.ComputeResource",
+				"*simulator.ClusterComputeResource",
+			))
+		}
+	})
+	if poolRef == nil {
+		return nil, poolRefNilErr
+	}
+	return poolRef, nil
+}
+
+// getHostsFromPool returns the host(s) for the provided compute resource.
+func getHostsFromPool(
+	ctx *simulator.Context,
+	reg *simulator.Registry,
+	poolRef vim.ManagedObjectReference) []vim.ManagedObjectReference {
+
+	pool := reg.Get(poolRef).(vimmo.Entity)
+	cr := getEntityComputeResource(reg, pool)
+
+	var hosts []vim.ManagedObjectReference
+
+	ctx.WithLock(cr, func() {
+		switch cr := cr.(type) {
+		case *vimmo.ComputeResource:
+			hosts = cr.Host
+		case *simulator.ClusterComputeResource:
+			hosts = cr.Host
+		}
+	})
+
+	return hosts
+}
+
+// hostsWithDatastore returns hosts that have access to the given datastore path
+func hostsWithDatastore( // nolint:unused nolint:deadcode
+	reg *simulator.Registry,
+	hosts []vim.ManagedObjectReference, path string) []vim.ManagedObjectReference {
+
+	attached := hosts[:0]
+	var p vimobj.DatastorePath
+	p.FromString(path)
+
+	for _, host := range hosts {
+		h := reg.Get(host).(*simulator.HostSystem)
+		if reg.FindByName(p.Datastore, h.Datastore) != nil {
+			attached = append(attached, host)
+		}
+	}
+
+	return attached
+}
+
+// getEntityComputeResource returns the ComputeResource parent for the given item.
+// A ResourcePool for example may have N Parents of type ResourcePool, but the top
+// most Parent pool is always a ComputeResource child.
+func getEntityComputeResource(
+	reg *simulator.Registry,
+	item vimmo.Entity) vimmo.Entity {
+
+	for {
+		parent := item.Entity().Parent
+		item = reg.Get(*parent).(vimmo.Entity)
+		switch item.Reference().Type {
+		case "ComputeResource":
+			return item
+		case "ClusterComputeResource":
+			return item
+		}
+	}
+}
diff --git a/eam/types/enum.go b/eam/types/enum.go
new file mode 100644
index 00000000..41054be0
--- /dev/null
+++ b/eam/types/enum.go
@@ -0,0 +1,93 @@
+/*
+Copyright (c) 2021 VMware, Inc. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package types
+
+import (
+	"reflect"
+
+	"github.com/vmware/govmomi/vim25/types"
+)
+
+type AgencyVMPlacementPolicyVMAntiAffinity string
+
+const (
+	AgencyVMPlacementPolicyVMAntiAffinityNone = AgencyVMPlacementPolicyVMAntiAffinity("none")
+	AgencyVMPlacementPolicyVMAntiAffinitySoft = AgencyVMPlacementPolicyVMAntiAffinity("soft")
+)
+
+func init() {
+	types.Add("eam:AgencyVMPlacementPolicyVMAntiAffinity", reflect.TypeOf((*AgencyVMPlacementPolicyVMAntiAffinity)(nil)).Elem())
+}
+
+type AgencyVMPlacementPolicyVMDataAffinity string
+
+const (
+	AgencyVMPlacementPolicyVMDataAffinityNone = AgencyVMPlacementPolicyVMDataAffinity("none")
+	AgencyVMPlacementPolicyVMDataAffinitySoft = AgencyVMPlacementPolicyVMDataAffinity("soft")
+)
+
+func init() {
+	types.Add("eam:AgencyVMPlacementPolicyVMDataAffinity", reflect.TypeOf((*AgencyVMPlacementPolicyVMDataAffinity)(nil)).Elem())
+}
+
+type AgentConfigInfoOvfDiskProvisioning string
+
+const (
+	AgentConfigInfoOvfDiskProvisioningNone  = AgentConfigInfoOvfDiskProvisioning("none")
+	AgentConfigInfoOvfDiskProvisioningThin  = AgentConfigInfoOvfDiskProvisioning("thin")
+	AgentConfigInfoOvfDiskProvisioningThick = AgentConfigInfoOvfDiskProvisioning("thick")
+)
+
+func init() {
+	types.Add("eam:AgentConfigInfoOvfDiskProvisioning", reflect.TypeOf((*AgentConfigInfoOvfDiskProvisioning)(nil)).Elem())
+}
+
+type AgentVmHookVmState string
+
+const (
+	AgentVmHookVmStateProvisioned = AgentVmHookVmState("provisioned")
+	AgentVmHookVmStatePoweredOn   = AgentVmHookVmState("poweredOn")
+	AgentVmHookVmStatePrePowerOn  = AgentVmHookVmState("prePowerOn")
+)
+
+func init() {
+	types.Add("eam:AgentVmHookVmState", reflect.TypeOf((*AgentVmHookVmState)(nil)).Elem())
+}
+
+type EamObjectRuntimeInfoGoalState string
+
+const (
+	EamObjectRuntimeInfoGoalStateEnabled     = EamObjectRuntimeInfoGoalState("enabled")
+	EamObjectRuntimeInfoGoalStateDisabled    = EamObjectRuntimeInfoGoalState("disabled")
+	EamObjectRuntimeInfoGoalStateUninstalled = EamObjectRuntimeInfoGoalState("uninstalled")
+)
+
+func init() {
+	types.Add("eam:EamObjectRuntimeInfoGoalState", reflect.TypeOf((*EamObjectRuntimeInfoGoalState)(nil)).Elem())
+}
+
+type EamObjectRuntimeInfoStatus string
+
+const (
+	EamObjectRuntimeInfoStatusGreen  = EamObjectRuntimeInfoStatus("green")
+	EamObjectRuntimeInfoStatusYellow = EamObjectRuntimeInfoStatus("yellow")
+	EamObjectRuntimeInfoStatusRed    = EamObjectRuntimeInfoStatus("red")
+)
+
+func init() {
+	types.Add("eam:EamObjectRuntimeInfoStatus", reflect.TypeOf((*EamObjectRuntimeInfoStatus)(nil)).Elem())
+}
diff --git a/eam/types/if.go b/eam/types/if.go
new file mode 100644
index 00000000..7d460d11
--- /dev/null
+++ b/eam/types/if.go
@@ -0,0 +1,287 @@
+/*
+Copyright (c) 2021 VMware, Inc. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package types
+
+import (
+	"reflect"
+
+	"github.com/vmware/govmomi/vim25/types"
+)
+
+func (b *AgencyIssue) GetAgencyIssue() *AgencyIssue { return b }
+
+type BaseAgencyIssue interface {
+	GetAgencyIssue() *AgencyIssue
+}
+
+func init() {
+	types.Add("BaseAgencyIssue", reflect.TypeOf((*AgencyIssue)(nil)).Elem())
+}
+
+func (b *AgencyScope) GetAgencyScope() *AgencyScope { return b }
+
+type BaseAgencyScope interface {
+	GetAgencyScope() *AgencyScope
+}
+
+func init() {
+	types.Add("BaseAgencyScope", reflect.TypeOf((*AgencyScope)(nil)).Elem())
+}
+
+func (b *AgentIssue) GetAgentIssue() *AgentIssue { return b }
+
+type BaseAgentIssue interface {
+	GetAgentIssue() *AgentIssue
+}
+
+func init() {
+	types.Add("BaseAgentIssue", reflect.TypeOf((*AgentIssue)(nil)).Elem())
+}
+
+func (b *AgentStoragePolicy) GetAgentStoragePolicy() *AgentStoragePolicy { return b }
+
+type BaseAgentStoragePolicy interface {
+	GetAgentStoragePolicy() *AgentStoragePolicy
+}
+
+func init() {
+	types.Add("BaseAgentStoragePolicy", reflect.TypeOf((*AgentStoragePolicy)(nil)).Elem())
+}
+
+func (b *ClusterAgentAgentIssue) GetClusterAgentAgentIssue() *ClusterAgentAgentIssue { return b }
+
+type BaseClusterAgentAgentIssue interface {
+	GetClusterAgentAgentIssue() *ClusterAgentAgentIssue
+}
+
+func init() {
+	types.Add("BaseClusterAgentAgentIssue", reflect.TypeOf((*ClusterAgentAgentIssue)(nil)).Elem())
+}
+
+func (b *ClusterAgentVmIssue) GetClusterAgentVmIssue() *ClusterAgentVmIssue { return b }
+
+type BaseClusterAgentVmIssue interface {
+	GetClusterAgentVmIssue() *ClusterAgentVmIssue
+}
+
+func init() {
+	types.Add("BaseClusterAgentVmIssue", reflect.TypeOf((*ClusterAgentVmIssue)(nil)).Elem())
+}
+
+func (b *ClusterAgentVmNotDeployed) GetClusterAgentVmNotDeployed() *ClusterAgentVmNotDeployed {
+	return b
+}
+
+type BaseClusterAgentVmNotDeployed interface {
+	GetClusterAgentVmNotDeployed() *ClusterAgentVmNotDeployed
+}
+
+func init() {
+	types.Add("BaseClusterAgentVmNotDeployed", reflect.TypeOf((*ClusterAgentVmNotDeployed)(nil)).Elem())
+}
+
+func (b *ClusterAgentVmPoweredOff) GetClusterAgentVmPoweredOff() *ClusterAgentVmPoweredOff { return b }
+
+type BaseClusterAgentVmPoweredOff interface {
+	GetClusterAgentVmPoweredOff() *ClusterAgentVmPoweredOff
+}
+
+func init() {
+	types.Add("BaseClusterAgentVmPoweredOff", reflect.TypeOf((*ClusterAgentVmPoweredOff)(nil)).Elem())
+}
+
+func (b *EamAppFault) GetEamAppFault() *EamAppFault { return b }
+
+type BaseEamAppFault interface {
+	GetEamAppFault() *EamAppFault
+}
+
+func init() {
+	types.Add("BaseEamAppFault", reflect.TypeOf((*EamAppFault)(nil)).Elem())
+}
+
+func (b *EamFault) GetEamFault() *EamFault { return b }
+
+type BaseEamFault interface {
+	GetEamFault() *EamFault
+}
+
+func init() {
+	types.Add("BaseEamFault", reflect.TypeOf((*EamFault)(nil)).Elem())
+}
+
+func (b *EamObjectRuntimeInfo) GetEamObjectRuntimeInfo() *EamObjectRuntimeInfo { return b }
+
+type BaseEamObjectRuntimeInfo interface {
+	GetEamObjectRuntimeInfo() *EamObjectRuntimeInfo
+}
+
+func init() {
+	types.Add("BaseEamObjectRuntimeInfo", reflect.TypeOf((*EamObjectRuntimeInfo)(nil)).Elem())
+}
+
+func (b *EamRuntimeFault) GetEamRuntimeFault() *EamRuntimeFault { return b }
+
+type BaseEamRuntimeFault interface {
+	GetEamRuntimeFault() *EamRuntimeFault
+}
+
+func init() {
+	types.Add("BaseEamRuntimeFault", reflect.TypeOf((*EamRuntimeFault)(nil)).Elem())
+}
+
+func (b *HostIssue) GetHostIssue() *HostIssue { return b }
+
+type BaseHostIssue interface {
+	GetHostIssue() *HostIssue
+}
+
+func init() {
+	types.Add("BaseHostIssue", reflect.TypeOf((*HostIssue)(nil)).Elem())
+}
+
+func (b *IntegrityAgencyVUMIssue) GetIntegrityAgencyVUMIssue() *IntegrityAgencyVUMIssue { return b }
+
+type BaseIntegrityAgencyVUMIssue interface {
+	GetIntegrityAgencyVUMIssue() *IntegrityAgencyVUMIssue
+}
+
+func init() {
+	types.Add("BaseIntegrityAgencyVUMIssue", reflect.TypeOf((*IntegrityAgencyVUMIssue)(nil)).Elem())
+}
+
+func (b *Issue) GetIssue() *Issue { return b }
+
+type BaseIssue interface {
+	GetIssue() *Issue
+}
+
+func init() {
+	types.Add("BaseIssue", reflect.TypeOf((*Issue)(nil)).Elem())
+}
+
+func (b *NoAgentVmDatastore) GetNoAgentVmDatastore() *NoAgentVmDatastore { return b }
+
+type BaseNoAgentVmDatastore interface {
+	GetNoAgentVmDatastore() *NoAgentVmDatastore
+}
+
+func init() {
+	types.Add("BaseNoAgentVmDatastore", reflect.TypeOf((*NoAgentVmDatastore)(nil)).Elem())
+}
+
+func (b *NoAgentVmNetwork) GetNoAgentVmNetwork() *NoAgentVmNetwork { return b }
+
+type BaseNoAgentVmNetwork interface {
+	GetNoAgentVmNetwork() *NoAgentVmNetwork
+}
+
+func init() {
+	types.Add("BaseNoAgentVmNetwork", reflect.TypeOf((*NoAgentVmNetwork)(nil)).Elem())
+}
+
+func (b *PersonalityAgencyDepotIssue) GetPersonalityAgencyDepotIssue() *PersonalityAgencyDepotIssue {
+	return b
+}
+
+type BasePersonalityAgencyDepotIssue interface {
+	GetPersonalityAgencyDepotIssue() *PersonalityAgencyDepotIssue
+}
+
+func init() {
+	types.Add("BasePersonalityAgencyDepotIssue", reflect.TypeOf((*PersonalityAgencyDepotIssue)(nil)).Elem())
+}
+
+func (b *PersonalityAgencyPMIssue) GetPersonalityAgencyPMIssue() *PersonalityAgencyPMIssue { return b }
+
+type BasePersonalityAgencyPMIssue interface {
+	GetPersonalityAgencyPMIssue() *PersonalityAgencyPMIssue
+}
+
+func init() {
+	types.Add("BasePersonalityAgencyPMIssue", reflect.TypeOf((*PersonalityAgencyPMIssue)(nil)).Elem())
+}
+
+func (b *PersonalityAgentPMIssue) GetPersonalityAgentPMIssue() *PersonalityAgentPMIssue { return b }
+
+type BasePersonalityAgentPMIssue interface {
+	GetPersonalityAgentPMIssue() *PersonalityAgentPMIssue
+}
+
+func init() {
+	types.Add("BasePersonalityAgentPMIssue", reflect.TypeOf((*PersonalityAgentPMIssue)(nil)).Elem())
+}
+
+func (b *VibIssue) GetVibIssue() *VibIssue { return b }
+
+type BaseVibIssue interface {
+	GetVibIssue() *VibIssue
+}
+
+func init() {
+	types.Add("BaseVibIssue", reflect.TypeOf((*VibIssue)(nil)).Elem())
+}
+
+func (b *VibNotInstalled) GetVibNotInstalled() *VibNotInstalled { return b }
+
+type BaseVibNotInstalled interface {
+	GetVibNotInstalled() *VibNotInstalled
+}
+
+func init() {
+	types.Add("BaseVibNotInstalled", reflect.TypeOf((*VibNotInstalled)(nil)).Elem())
+}
+
+func (b *VmDeployed) GetVmDeployed() *VmDeployed { return b }
+
+type BaseVmDeployed interface {
+	GetVmDeployed() *VmDeployed
+}
+
+func init() {
+	types.Add("BaseVmDeployed", reflect.TypeOf((*VmDeployed)(nil)).Elem())
+}
+
+func (b *VmIssue) GetVmIssue() *VmIssue { return b }
+
+type BaseVmIssue interface {
+	GetVmIssue() *VmIssue
+}
+
+func init() {
+	types.Add("BaseVmIssue", reflect.TypeOf((*VmIssue)(nil)).Elem())
+}
+
+func (b *VmNotDeployed) GetVmNotDeployed() *VmNotDeployed { return b }
+
+type BaseVmNotDeployed interface {
+	GetVmNotDeployed() *VmNotDeployed
+}
+
+func init() {
+	types.Add("BaseVmNotDeployed", reflect.TypeOf((*VmNotDeployed)(nil)).Elem())
+}
+
+func (b *VmPoweredOff) GetVmPoweredOff() *VmPoweredOff { return b }
+
+type BaseVmPoweredOff interface {
+	GetVmPoweredOff() *VmPoweredOff
+}
+
+func init() {
+	types.Add("BaseVmPoweredOff", reflect.TypeOf((*VmPoweredOff)(nil)).Elem())
+}
diff --git a/eam/types/types.go b/eam/types/types.go
new file mode 100644
index 00000000..b77445a1
--- /dev/null
+++ b/eam/types/types.go
@@ -0,0 +1,1605 @@
+/*
+Copyright (c) 2021 VMware, Inc. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package types
+
+import (
+	"reflect"
+	"time"
+
+	"github.com/vmware/govmomi/vim25/types"
+)
+
+type AddIssue AddIssueRequestType
+
+func init() {
+	types.Add("eam:AddIssue", reflect.TypeOf((*AddIssue)(nil)).Elem())
+}
+
+type AddIssueRequestType struct {
+	This  types.ManagedObjectReference `xml:"_this"`
+	Issue BaseIssue                    `xml:"issue,typeattr"`
+}
+
+func init() {
+	types.Add("eam:AddIssueRequestType", reflect.TypeOf((*AddIssueRequestType)(nil)).Elem())
+}
+
+type AddIssueResponse struct {
+	Returnval BaseIssue `xml:"returnval,typeattr"`
+}
+
+type AgencyComputeResourceScope struct {
+	AgencyScope
+
+	ComputeResource []types.ManagedObjectReference `xml:"computeResource,omitempty"`
+}
+
+func init() {
+	types.Add("eam:AgencyComputeResourceScope", reflect.TypeOf((*AgencyComputeResourceScope)(nil)).Elem())
+}
+
+type AgencyConfigInfo struct {
+	types.DynamicData
+
+	AgentConfig                                   []AgentConfigInfo              `xml:"agentConfig,omitempty"`
+	Scope                                         BaseAgencyScope                `xml:"scope,omitempty,typeattr"`
+	ManuallyMarkAgentVmAvailableAfterProvisioning *bool                          `xml:"manuallyMarkAgentVmAvailableAfterProvisioning"`
+	ManuallyMarkAgentVmAvailableAfterPowerOn      *bool                          `xml:"manuallyMarkAgentVmAvailableAfterPowerOn"`
+	OptimizedDeploymentEnabled                    *bool                          `xml:"optimizedDeploymentEnabled"`
+	AgentName                                     string                         `xml:"agentName,omitempty"`
+	AgencyName                                    string                         `xml:"agencyName,omitempty"`
+	ManuallyProvisioned                           *bool                          `xml:"manuallyProvisioned"`
+	ManuallyMonitored                             *bool                          `xml:"manuallyMonitored"`
+	BypassVumEnabled                              *bool                          `xml:"bypassVumEnabled"`
+	AgentVmNetwork                                []types.ManagedObjectReference `xml:"agentVmNetwork,omitempty"`
+	AgentVmDatastore                              []types.ManagedObjectReference `xml:"agentVmDatastore,omitempty"`
+	PreferHostConfiguration                       *bool                          `xml:"preferHostConfiguration"`
+	IpPool                                        *types.IpPool                  `xml:"ipPool,omitempty"`
+	ResourcePools                                 []AgencyVMResourcePool         `xml:"resourcePools,omitempty"`
+	Folders                                       []AgencyVMFolder               `xml:"folders,omitempty"`
+}
+
+func init() {
+	types.Add("eam:AgencyConfigInfo", reflect.TypeOf((*AgencyConfigInfo)(nil)).Elem())
+}
+
+type AgencyIssue struct {
+	Issue
+
+	Agency       types.ManagedObjectReference `xml:"agency"`
+	AgencyName   string                       `xml:"agencyName"`
+	SolutionId   string                       `xml:"solutionId"`
+	SolutionName string                       `xml:"solutionName"`
+}
+
+func init() {
+	types.Add("eam:AgencyIssue", reflect.TypeOf((*AgencyIssue)(nil)).Elem())
+}
+
+type AgencyQueryRuntime AgencyQueryRuntimeRequestType
+
+func init() {
+	types.Add("eam:AgencyQueryRuntime", reflect.TypeOf((*AgencyQueryRuntime)(nil)).Elem())
+}
+
+type AgencyQueryRuntimeRequestType struct {
+	This types.ManagedObjectReference `xml:"_this"`
+}
+
+func init() {
+	types.Add("eam:AgencyQueryRuntimeRequestType", reflect.TypeOf((*AgencyQueryRuntimeRequestType)(nil)).Elem())
+}
+
+type AgencyQueryRuntimeResponse struct {
+	Returnval BaseEamObjectRuntimeInfo `xml:"returnval,typeattr"`
+}
+
+type AgencyScope struct {
+	types.DynamicData
+}
+
+func init() {
+	types.Add("eam:AgencyScope", reflect.TypeOf((*AgencyScope)(nil)).Elem())
+}
+
+type AgencyVMFolder struct {
+	types.DynamicData
+
+	FolderId     types.ManagedObjectReference `xml:"folderId"`
+	DatacenterId types.ManagedObjectReference `xml:"datacenterId"`
+}
+
+func init() {
+	types.Add("eam:AgencyVMFolder", reflect.TypeOf((*AgencyVMFolder)(nil)).Elem())
+}
+
+type AgencyVMResourcePool struct {
+	types.DynamicData
+
+	ResourcePoolId    types.ManagedObjectReference `xml:"resourcePoolId"`
+	ComputeResourceId types.ManagedObjectReference `xml:"computeResourceId"`
+}
+
+func init() {
+	types.Add("eam:AgencyVMResourcePool", reflect.TypeOf((*AgencyVMResourcePool)(nil)).Elem())
+}
+
+type AgentConfigInfo struct {
+	types.DynamicData
+
+	ProductLineId               string                   `xml:"productLineId,omitempty"`
+	HostVersion                 string                   `xml:"hostVersion,omitempty"`
+	OvfPackageUrl               string                   `xml:"ovfPackageUrl,omitempty"`
+	OvfEnvironment              *AgentOvfEnvironmentInfo `xml:"ovfEnvironment,omitempty"`
+	VibUrl                      string                   `xml:"vibUrl,omitempty"`
+	VibMatchingRules            []AgentVibMatchingRule   `xml:"vibMatchingRules,omitempty"`
+	VibName                     string                   `xml:"vibName,omitempty"`
+	DvFilterEnabled             *bool                    `xml:"dvFilterEnabled"`
+	RebootHostAfterVibUninstall *bool                    `xml:"rebootHostAfterVibUninstall"`
+	VmciService                 []string                 `xml:"vmciService,omitempty"`
+	OvfDiskProvisioning         string                   `xml:"ovfDiskProvisioning,omitempty"`
+	VmStoragePolicies           []BaseAgentStoragePolicy `xml:"vmStoragePolicies,omitempty,typeattr"`
+}
+
+func init() {
+	types.Add("eam:AgentConfigInfo", reflect.TypeOf((*AgentConfigInfo)(nil)).Elem())
+}
+
+type AgentIssue struct {
+	AgencyIssue
+
+	Agent     types.ManagedObjectReference `xml:"agent"`
+	AgentName string                       `xml:"agentName"`
+	Host      types.ManagedObjectReference `xml:"host"`
+	HostName  string                       `xml:"hostName"`
+}
+
+func init() {
+	types.Add("eam:AgentIssue", reflect.TypeOf((*AgentIssue)(nil)).Elem())
+}
+
+type AgentOvfEnvironmentInfo struct {
+	types.DynamicData
+
+	OvfProperty []AgentOvfEnvironmentInfoOvfProperty `xml:"ovfProperty,omitempty"`
+}
+
+func init() {
+	types.Add("eam:AgentOvfEnvironmentInfo", reflect.TypeOf((*AgentOvfEnvironmentInfo)(nil)).Elem())
+}
+
+type AgentOvfEnvironmentInfoOvfProperty struct {
+	types.DynamicData
+
+	Key   string `xml:"key"`
+	Value string `xml:"value"`
+}
+
+func init() {
+	types.Add("eam:AgentOvfEnvironmentInfoOvfProperty", reflect.TypeOf((*AgentOvfEnvironmentInfoOvfProperty)(nil)).Elem())
+}
+
+type AgentQueryConfig AgentQueryConfigRequestType
+
+func init() {
+	types.Add("eam:AgentQueryConfig", reflect.TypeOf((*AgentQueryConfig)(nil)).Elem())
+}
+
+type AgentQueryConfigRequestType struct {
+	This types.ManagedObjectReference `xml:"_this"`
+}
+
+func init() {
+	types.Add("eam:AgentQueryConfigRequestType", reflect.TypeOf((*AgentQueryConfigRequestType)(nil)).Elem())
+}
+
+type AgentQueryConfigResponse struct {
+	Returnval AgentConfigInfo `xml:"returnval"`
+}
+
+type AgentQueryRuntime AgentQueryRuntimeRequestType
+
+func init() {
+	types.Add("eam:AgentQueryRuntime", reflect.TypeOf((*AgentQueryRuntime)(nil)).Elem())
+}
+
+type AgentQueryRuntimeRequestType struct {
+	This types.ManagedObjectReference `xml:"_this"`
+}
+
+func init() {
+	types.Add("eam:AgentQueryRuntimeRequestType", reflect.TypeOf((*AgentQueryRuntimeRequestType)(nil)).Elem())
+}
+
+type AgentQueryRuntimeResponse struct {
+	Returnval AgentRuntimeInfo `xml:"returnval"`
+}
+
+type AgentRuntimeInfo struct {
+	EamObjectRuntimeInfo
+
+	VmPowerState         types.VirtualMachinePowerState `xml:"vmPowerState"`
+	ReceivingHeartBeat   bool                           `xml:"receivingHeartBeat"`
+	Host                 *types.ManagedObjectReference  `xml:"host,omitempty"`
+	Vm                   *types.ManagedObjectReference  `xml:"vm,omitempty"`
+	VmIp                 string                         `xml:"vmIp,omitempty"`
+	VmName               string                         `xml:"vmName"`
+	EsxAgentResourcePool *types.ManagedObjectReference  `xml:"esxAgentResourcePool,omitempty"`
+	EsxAgentFolder       *types.ManagedObjectReference  `xml:"esxAgentFolder,omitempty"`
+	InstalledBulletin    []string                       `xml:"installedBulletin,omitempty"`
+	InstalledVibs        []VibVibInfo                   `xml:"installedVibs,omitempty"`
+	Agency               *types.ManagedObjectReference  `xml:"agency,omitempty"`
+	VmHook               *AgentVmHook                   `xml:"vmHook,omitempty"`
+}
+
+func init() {
+	types.Add("eam:AgentRuntimeInfo", reflect.TypeOf((*AgentRuntimeInfo)(nil)).Elem())
+}
+
+type AgentStoragePolicy struct {
+	types.DynamicData
+}
+
+func init() {
+	types.Add("eam:AgentStoragePolicy", reflect.TypeOf((*AgentStoragePolicy)(nil)).Elem())
+}
+
+type AgentVibMatchingRule struct {
+	types.DynamicData
+
+	VibNameRegex    string `xml:"vibNameRegex"`
+	VibVersionRegex string `xml:"vibVersionRegex"`
+}
+
+func init() {
+	types.Add("eam:AgentVibMatchingRule", reflect.TypeOf((*AgentVibMatchingRule)(nil)).Elem())
+}
+
+type AgentVmHook struct {
+	types.DynamicData
+
+	Vm      types.ManagedObjectReference `xml:"vm"`
+	VmState string                       `xml:"vmState"`
+}
+
+func init() {
+	types.Add("eam:AgentVmHook", reflect.TypeOf((*AgentVmHook)(nil)).Elem())
+}
+
+type AgentVsanStoragePolicy struct {
+	AgentStoragePolicy
+
+	ProfileId string `xml:"profileId"`
+}
+
+func init() {
+	types.Add("eam:AgentVsanStoragePolicy", reflect.TypeOf((*AgentVsanStoragePolicy)(nil)).Elem())
+}
+
+type ArrayOfAgencyVMFolder struct {
+	AgencyVMFolder []AgencyVMFolder `xml:"AgencyVMFolder,omitempty"`
+}
+
+func init() {
+	types.Add("eam:ArrayOfAgencyVMFolder", reflect.TypeOf((*ArrayOfAgencyVMFolder)(nil)).Elem())
+}
+
+type ArrayOfAgencyVMResourcePool struct {
+	AgencyVMResourcePool []AgencyVMResourcePool `xml:"AgencyVMResourcePool,omitempty"`
+}
+
+func init() {
+	types.Add("eam:ArrayOfAgencyVMResourcePool", reflect.TypeOf((*ArrayOfAgencyVMResourcePool)(nil)).Elem())
+}
+
+type ArrayOfAgentConfigInfo struct {
+	AgentConfigInfo []AgentConfigInfo `xml:"AgentConfigInfo,omitempty"`
+}
+
+func init() {
+	types.Add("eam:ArrayOfAgentConfigInfo", reflect.TypeOf((*ArrayOfAgentConfigInfo)(nil)).Elem())
+}
+
+type ArrayOfAgentOvfEnvironmentInfoOvfProperty struct {
+	AgentOvfEnvironmentInfoOvfProperty []AgentOvfEnvironmentInfoOvfProperty `xml:"AgentOvfEnvironmentInfoOvfProperty,omitempty"`
+}
+
+func init() {
+	types.Add("eam:ArrayOfAgentOvfEnvironmentInfoOvfProperty", reflect.TypeOf((*ArrayOfAgentOvfEnvironmentInfoOvfProperty)(nil)).Elem())
+}
+
+type ArrayOfAgentStoragePolicy struct {
+	AgentStoragePolicy []BaseAgentStoragePolicy `xml:"AgentStoragePolicy,omitempty,typeattr"`
+}
+
+func init() {
+	types.Add("eam:ArrayOfAgentStoragePolicy", reflect.TypeOf((*ArrayOfAgentStoragePolicy)(nil)).Elem())
+}
+
+type ArrayOfAgentVibMatchingRule struct {
+	AgentVibMatchingRule []AgentVibMatchingRule `xml:"AgentVibMatchingRule,omitempty"`
+}
+
+func init() {
+	types.Add("eam:ArrayOfAgentVibMatchingRule", reflect.TypeOf((*ArrayOfAgentVibMatchingRule)(nil)).Elem())
+}
+
+type ArrayOfIssue struct {
+	Issue []BaseIssue `xml:"Issue,omitempty,typeattr"`
+}
+
+func init() {
+	types.Add("eam:ArrayOfIssue", reflect.TypeOf((*ArrayOfIssue)(nil)).Elem())
+}
+
+type ArrayOfVibVibInfo struct {
+	VibVibInfo []VibVibInfo `xml:"VibVibInfo,omitempty"`
+}
+
+func init() {
+	types.Add("eam:ArrayOfVibVibInfo", reflect.TypeOf((*ArrayOfVibVibInfo)(nil)).Elem())
+}
+
+type CannotAccessAgentOVF struct {
+	VmNotDeployed
+
+	DownloadUrl string `xml:"downloadUrl"`
+}
+
+func init() {
+	types.Add("eam:CannotAccessAgentOVF", reflect.TypeOf((*CannotAccessAgentOVF)(nil)).Elem())
+}
+
+type CannotAccessAgentVib struct {
+	VibNotInstalled
+
+	DownloadUrl string `xml:"downloadUrl"`
+}
+
+func init() {
+	types.Add("eam:CannotAccessAgentVib", reflect.TypeOf((*CannotAccessAgentVib)(nil)).Elem())
+}
+
+type ClusterAgentAgentIssue struct {
+	AgencyIssue
+
+	Agent   types.ManagedObjectReference  `xml:"agent"`
+	Cluster *types.ManagedObjectReference `xml:"cluster,omitempty"`
+}
+
+func init() {
+	types.Add("eam:ClusterAgentAgentIssue", reflect.TypeOf((*ClusterAgentAgentIssue)(nil)).Elem())
+}
+
+type ClusterAgentInsufficientClusterResources struct {
+	ClusterAgentVmPoweredOff
+}
+
+func init() {
+	types.Add("eam:ClusterAgentInsufficientClusterResources", reflect.TypeOf((*ClusterAgentInsufficientClusterResources)(nil)).Elem())
+}
+
+type ClusterAgentInsufficientClusterSpace struct {
+	ClusterAgentVmNotDeployed
+}
+
+func init() {
+	types.Add("eam:ClusterAgentInsufficientClusterSpace", reflect.TypeOf((*ClusterAgentInsufficientClusterSpace)(nil)).Elem())
+}
+
+type ClusterAgentInvalidConfig struct {
+	ClusterAgentVmIssue
+
+	Error types.AnyType `xml:"error,typeattr"`
+}
+
+func init() {
+	types.Add("eam:ClusterAgentInvalidConfig", reflect.TypeOf((*ClusterAgentInvalidConfig)(nil)).Elem())
+}
+
+type ClusterAgentMissingClusterVmDatastore struct {
+	ClusterAgentVmNotDeployed
+
+	MissingDatastores []types.ManagedObjectReference `xml:"missingDatastores,omitempty"`
+}
+
+func init() {
+	types.Add("eam:ClusterAgentMissingClusterVmDatastore", reflect.TypeOf((*ClusterAgentMissingClusterVmDatastore)(nil)).Elem())
+}
+
+type ClusterAgentMissingClusterVmNetwork struct {
+	ClusterAgentVmNotDeployed
+
+	MissingNetworks []types.ManagedObjectReference `xml:"missingNetworks,omitempty"`
+	NetworkNames    []string                       `xml:"networkNames,omitempty"`
+}
+
+func init() {
+	types.Add("eam:ClusterAgentMissingClusterVmNetwork", reflect.TypeOf((*ClusterAgentMissingClusterVmNetwork)(nil)).Elem())
+}
+
+type ClusterAgentOvfInvalidProperty struct {
+	ClusterAgentAgentIssue
+
+	Error []types.LocalizedMethodFault `xml:"error,omitempty"`
+}
+
+func init() {
+	types.Add("eam:ClusterAgentOvfInvalidProperty", reflect.TypeOf((*ClusterAgentOvfInvalidProperty)(nil)).Elem())
+}
+
+type ClusterAgentVmIssue struct {
+	ClusterAgentAgentIssue
+
+	Vm types.ManagedObjectReference `xml:"vm"`
+}
+
+func init() {
+	types.Add("eam:ClusterAgentVmIssue", reflect.TypeOf((*ClusterAgentVmIssue)(nil)).Elem())
+}
+
+type ClusterAgentVmNotDeployed struct {
+	ClusterAgentAgentIssue
+}
+
+func init() {
+	types.Add("eam:ClusterAgentVmNotDeployed", reflect.TypeOf((*ClusterAgentVmNotDeployed)(nil)).Elem())
+}
+
+type ClusterAgentVmNotRemoved struct {
+	ClusterAgentVmIssue
+}
+
+func init() {
+	types.Add("eam:ClusterAgentVmNotRemoved", reflect.TypeOf((*ClusterAgentVmNotRemoved)(nil)).Elem())
+}
+
+type ClusterAgentVmPoweredOff struct {
+	ClusterAgentVmIssue
+}
+
+func init() {
+	types.Add("eam:ClusterAgentVmPoweredOff", reflect.TypeOf((*ClusterAgentVmPoweredOff)(nil)).Elem())
+}
+
+type ClusterAgentVmPoweredOn struct {
+	ClusterAgentVmIssue
+}
+
+func init() {
+	types.Add("eam:ClusterAgentVmPoweredOn", reflect.TypeOf((*ClusterAgentVmPoweredOn)(nil)).Elem())
+}
+
+type ClusterAgentVmSuspended struct {
+	ClusterAgentVmIssue
+}
+
+func init() {
+	types.Add("eam:ClusterAgentVmSuspended", reflect.TypeOf((*ClusterAgentVmSuspended)(nil)).Elem())
+}
+
+type CreateAgency CreateAgencyRequestType
+
+func init() {
+	types.Add("eam:CreateAgency", reflect.TypeOf((*CreateAgency)(nil)).Elem())
+}
+
+type CreateAgencyRequestType struct {
+	This             types.ManagedObjectReference `xml:"_this"`
+	AgencyConfigInfo AgencyConfigInfo             `xml:"agencyConfigInfo"`
+	InitialGoalState string                       `xml:"initialGoalState"`
+}
+
+func init() {
+	types.Add("eam:CreateAgencyRequestType", reflect.TypeOf((*CreateAgencyRequestType)(nil)).Elem())
+}
+
+type CreateAgencyResponse struct {
+	Returnval types.ManagedObjectReference `xml:"returnval"`
+}
+
+type DestroyAgency DestroyAgencyRequestType
+
+func init() {
+	types.Add("eam:DestroyAgency", reflect.TypeOf((*DestroyAgency)(nil)).Elem())
+}
+
+type DestroyAgencyRequestType struct {
+	This types.ManagedObjectReference `xml:"_this"`
+}
+
+func init() {
+	types.Add("eam:DestroyAgencyRequestType", reflect.TypeOf((*DestroyAgencyRequestType)(nil)).Elem())
+}
+
+type DestroyAgencyResponse struct {
+}
+
+type Disable DisableRequestType
+
+func init() {
+	types.Add("eam:Disable", reflect.TypeOf((*Disable)(nil)).Elem())
+}
+
+type DisableRequestType struct {
+	This types.ManagedObjectReference `xml:"_this"`
+}
+
+func init() {
+	types.Add("eam:DisableRequestType", reflect.TypeOf((*DisableRequestType)(nil)).Elem())
+}
+
+type DisableResponse struct {
+}
+
+type EamAppFault struct {
+	EamRuntimeFault
+}
+
+func init() {
+	types.Add("eam:EamAppFault", reflect.TypeOf((*EamAppFault)(nil)).Elem())
+}
+
+type EamAppFaultFault BaseEamAppFault
+
+func init() {
+	types.Add("eam:EamAppFaultFault", reflect.TypeOf((*EamAppFaultFault)(nil)).Elem())
+}
+
+type EamFault struct {
+	types.MethodFault
+}
+
+func init() {
+	types.Add("eam:EamFault", reflect.TypeOf((*EamFault)(nil)).Elem())
+}
+
+type EamFaultFault BaseEamFault
+
+func init() {
+	types.Add("eam:EamFaultFault", reflect.TypeOf((*EamFaultFault)(nil)).Elem())
+}
+
+type EamIOFault struct {
+	EamRuntimeFault
+}
+
+func init() {
+	types.Add("eam:EamIOFault", reflect.TypeOf((*EamIOFault)(nil)).Elem())
+}
+
+type EamIOFaultFault EamIOFault
+
+func init() {
+	types.Add("eam:EamIOFaultFault", reflect.TypeOf((*EamIOFaultFault)(nil)).Elem())
+}
+
+type EamInvalidLogin struct {
+	EamRuntimeFault
+}
+
+func init() {
+	types.Add("eam:EamInvalidLogin", reflect.TypeOf((*EamInvalidLogin)(nil)).Elem())
+}
+
+type EamInvalidLoginFault EamInvalidLogin
+
+func init() {
+	types.Add("eam:EamInvalidLoginFault", reflect.TypeOf((*EamInvalidLoginFault)(nil)).Elem())
+}
+
+type EamInvalidState struct {
+	EamAppFault
+}
+
+func init() {
+	types.Add("eam:EamInvalidState", reflect.TypeOf((*EamInvalidState)(nil)).Elem())
+}
+
+type EamInvalidStateFault EamInvalidState
+
+func init() {
+	types.Add("eam:EamInvalidStateFault", reflect.TypeOf((*EamInvalidStateFault)(nil)).Elem())
+}
+
+type EamInvalidVibPackage struct {
+	EamRuntimeFault
+}
+
+func init() {
+	types.Add("eam:EamInvalidVibPackage", reflect.TypeOf((*EamInvalidVibPackage)(nil)).Elem())
+}
+
+type EamInvalidVibPackageFault EamInvalidVibPackage
+
+func init() {
+	types.Add("eam:EamInvalidVibPackageFault", reflect.TypeOf((*EamInvalidVibPackageFault)(nil)).Elem())
+}
+
+type EamObjectRuntimeInfo struct {
+	types.DynamicData
+
+	Status    string                       `xml:"status"`
+	Issue     []BaseIssue                  `xml:"issue,omitempty,typeattr"`
+	GoalState string                       `xml:"goalState"`
+	Entity    types.ManagedObjectReference `xml:"entity"`
+}
+
+func init() {
+	types.Add("eam:EamObjectRuntimeInfo", reflect.TypeOf((*EamObjectRuntimeInfo)(nil)).Elem())
+}
+
+type EamRuntimeFault struct {
+	types.RuntimeFault
+}
+
+func init() {
+	types.Add("eam:EamRuntimeFault", reflect.TypeOf((*EamRuntimeFault)(nil)).Elem())
+}
+
+type EamRuntimeFaultFault BaseEamRuntimeFault
+
+func init() {
+	types.Add("eam:EamRuntimeFaultFault", reflect.TypeOf((*EamRuntimeFaultFault)(nil)).Elem())
+}
+
+type EamServiceNotInitialized struct {
+	EamRuntimeFault
+}
+
+func init() {
+	types.Add("eam:EamServiceNotInitialized", reflect.TypeOf((*EamServiceNotInitialized)(nil)).Elem())
+}
+
+type EamServiceNotInitializedFault EamServiceNotInitialized
+
+func init() {
+	types.Add("eam:EamServiceNotInitializedFault", reflect.TypeOf((*EamServiceNotInitializedFault)(nil)).Elem())
+}
+
+type EamSystemFault struct {
+	EamRuntimeFault
+}
+
+func init() {
+	types.Add("eam:EamSystemFault", reflect.TypeOf((*EamSystemFault)(nil)).Elem())
+}
+
+type EamSystemFaultFault EamSystemFault
+
+func init() {
+	types.Add("eam:EamSystemFaultFault", reflect.TypeOf((*EamSystemFaultFault)(nil)).Elem())
+}
+
+type Enable EnableRequestType
+
+func init() {
+	types.Add("eam:Enable", reflect.TypeOf((*Enable)(nil)).Elem())
+}
+
+type EnableRequestType struct {
+	This types.ManagedObjectReference `xml:"_this"`
+}
+
+func init() {
+	types.Add("eam:EnableRequestType", reflect.TypeOf((*EnableRequestType)(nil)).Elem())
+}
+
+type EnableResponse struct {
+}
+
+type ExtensibleIssue struct {
+	Issue
+
+	TypeId   string                        `xml:"typeId"`
+	Argument []types.KeyAnyValue           `xml:"argument,omitempty"`
+	Target   *types.ManagedObjectReference `xml:"target,omitempty"`
+	Agent    *types.ManagedObjectReference `xml:"agent,omitempty"`
+	Agency   *types.ManagedObjectReference `xml:"agency,omitempty"`
+}
+
+func init() {
+	types.Add("eam:ExtensibleIssue", reflect.TypeOf((*ExtensibleIssue)(nil)).Elem())
+}
+
+type HostInMaintenanceMode struct {
+	VmDeployed
+}
+
+func init() {
+	types.Add("eam:HostInMaintenanceMode", reflect.TypeOf((*HostInMaintenanceMode)(nil)).Elem())
+}
+
+type HostInStandbyMode struct {
+	VmDeployed
+}
+
+func init() {
+	types.Add("eam:HostInStandbyMode", reflect.TypeOf((*HostInStandbyMode)(nil)).Elem())
+}
+
+type HostIssue struct {
+	Issue
+
+	Host types.ManagedObjectReference `xml:"host"`
+}
+
+func init() {
+	types.Add("eam:HostIssue", reflect.TypeOf((*HostIssue)(nil)).Elem())
+}
+
+type HostPoweredOff struct {
+	VmDeployed
+}
+
+func init() {
+	types.Add("eam:HostPoweredOff", reflect.TypeOf((*HostPoweredOff)(nil)).Elem())
+}
+
+type ImmediateHostRebootRequired struct {
+	VibIssue
+}
+
+func init() {
+	types.Add("eam:ImmediateHostRebootRequired", reflect.TypeOf((*ImmediateHostRebootRequired)(nil)).Elem())
+}
+
+type IncompatibleHostVersion struct {
+	VmNotDeployed
+}
+
+func init() {
+	types.Add("eam:IncompatibleHostVersion", reflect.TypeOf((*IncompatibleHostVersion)(nil)).Elem())
+}
+
+type InsufficientIpAddresses struct {
+	VmPoweredOff
+
+	Network types.ManagedObjectReference `xml:"network"`
+}
+
+func init() {
+	types.Add("eam:InsufficientIpAddresses", reflect.TypeOf((*InsufficientIpAddresses)(nil)).Elem())
+}
+
+type InsufficientResources struct {
+	VmNotDeployed
+}
+
+func init() {
+	types.Add("eam:InsufficientResources", reflect.TypeOf((*InsufficientResources)(nil)).Elem())
+}
+
+type InsufficientSpace struct {
+	VmNotDeployed
+}
+
+func init() {
+	types.Add("eam:InsufficientSpace", reflect.TypeOf((*InsufficientSpace)(nil)).Elem())
+}
+
+type IntegrityAgencyCannotDeleteSoftware struct {
+	IntegrityAgencyVUMIssue
+}
+
+func init() {
+	types.Add("eam:IntegrityAgencyCannotDeleteSoftware", reflect.TypeOf((*IntegrityAgencyCannotDeleteSoftware)(nil)).Elem())
+}
+
+type IntegrityAgencyCannotStageSoftware struct {
+	IntegrityAgencyVUMIssue
+}
+
+func init() {
+	types.Add("eam:IntegrityAgencyCannotStageSoftware", reflect.TypeOf((*IntegrityAgencyCannotStageSoftware)(nil)).Elem())
+}
+
+type IntegrityAgencyVUMIssue struct {
+	AgencyIssue
+}
+
+func init() {
+	types.Add("eam:IntegrityAgencyVUMIssue", reflect.TypeOf((*IntegrityAgencyVUMIssue)(nil)).Elem())
+}
+
+type IntegrityAgencyVUMUnavailable struct {
+	IntegrityAgencyVUMIssue
+}
+
+func init() {
+	types.Add("eam:IntegrityAgencyVUMUnavailable", reflect.TypeOf((*IntegrityAgencyVUMUnavailable)(nil)).Elem())
+}
+
+type InvalidAgencyScope struct {
+	EamFault
+
+	UnknownComputeResource []types.ManagedObjectReference `xml:"unknownComputeResource,omitempty"`
+}
+
+func init() {
+	types.Add("eam:InvalidAgencyScope", reflect.TypeOf((*InvalidAgencyScope)(nil)).Elem())
+}
+
+type InvalidAgencyScopeFault InvalidAgencyScope
+
+func init() {
+	types.Add("eam:InvalidAgencyScopeFault", reflect.TypeOf((*InvalidAgencyScopeFault)(nil)).Elem())
+}
+
+type InvalidAgentConfiguration struct {
+	EamFault
+
+	InvalidAgentConfiguration *AgentConfigInfo `xml:"invalidAgentConfiguration,omitempty"`
+	InvalidField              string           `xml:"invalidField,omitempty"`
+}
+
+func init() {
+	types.Add("eam:InvalidAgentConfiguration", reflect.TypeOf((*InvalidAgentConfiguration)(nil)).Elem())
+}
+
+type InvalidAgentConfigurationFault InvalidAgentConfiguration
+
+func init() {
+	types.Add("eam:InvalidAgentConfigurationFault", reflect.TypeOf((*InvalidAgentConfigurationFault)(nil)).Elem())
+}
+
+type InvalidConfig struct {
+	VmIssue
+
+	Error types.AnyType `xml:"error,typeattr"`
+}
+
+func init() {
+	types.Add("eam:InvalidConfig", reflect.TypeOf((*InvalidConfig)(nil)).Elem())
+}
+
+type InvalidUrl struct {
+	EamFault
+
+	Url               string `xml:"url"`
+	MalformedUrl      bool   `xml:"malformedUrl"`
+	UnknownHost       bool   `xml:"unknownHost"`
+	ConnectionRefused bool   `xml:"connectionRefused"`
+	ResponseCode      int32  `xml:"responseCode,omitempty"`
+}
+
+func init() {
+	types.Add("eam:InvalidUrl", reflect.TypeOf((*InvalidUrl)(nil)).Elem())
+}
+
+type InvalidUrlFault InvalidUrl
+
+func init() {
+	types.Add("eam:InvalidUrlFault", reflect.TypeOf((*InvalidUrlFault)(nil)).Elem())
+}
+
+type Issue struct {
+	types.DynamicData
+
+	Key         int32     `xml:"key"`
+	Description string    `xml:"description"`
+	Time        time.Time `xml:"time"`
+}
+
+func init() {
+	types.Add("eam:Issue", reflect.TypeOf((*Issue)(nil)).Elem())
+}
+
+type ManagedHostNotReachable struct {
+	AgentIssue
+}
+
+func init() {
+	types.Add("eam:ManagedHostNotReachable", reflect.TypeOf((*ManagedHostNotReachable)(nil)).Elem())
+}
+
+type MarkAsAvailable MarkAsAvailableRequestType
+
+func init() {
+	types.Add("eam:MarkAsAvailable", reflect.TypeOf((*MarkAsAvailable)(nil)).Elem())
+}
+
+type MarkAsAvailableRequestType struct {
+	This types.ManagedObjectReference `xml:"_this"`
+}
+
+func init() {
+	types.Add("eam:MarkAsAvailableRequestType", reflect.TypeOf((*MarkAsAvailableRequestType)(nil)).Elem())
+}
+
+type MarkAsAvailableResponse struct {
+}
+
+type MissingAgentIpPool struct {
+	VmPoweredOff
+
+	Network types.ManagedObjectReference `xml:"network"`
+}
+
+func init() {
+	types.Add("eam:MissingAgentIpPool", reflect.TypeOf((*MissingAgentIpPool)(nil)).Elem())
+}
+
+type MissingDvFilterSwitch struct {
+	AgentIssue
+}
+
+func init() {
+	types.Add("eam:MissingDvFilterSwitch", reflect.TypeOf((*MissingDvFilterSwitch)(nil)).Elem())
+}
+
+type NoAgentVmDatastore struct {
+	VmNotDeployed
+}
+
+func init() {
+	types.Add("eam:NoAgentVmDatastore", reflect.TypeOf((*NoAgentVmDatastore)(nil)).Elem())
+}
+
+type NoAgentVmNetwork struct {
+	VmNotDeployed
+}
+
+func init() {
+	types.Add("eam:NoAgentVmNetwork", reflect.TypeOf((*NoAgentVmNetwork)(nil)).Elem())
+}
+
+type NoConnectionToVCenter struct {
+	EamRuntimeFault
+}
+
+func init() {
+	types.Add("eam:NoConnectionToVCenter", reflect.TypeOf((*NoConnectionToVCenter)(nil)).Elem())
+}
+
+type NoConnectionToVCenterFault NoConnectionToVCenter
+
+func init() {
+	types.Add("eam:NoConnectionToVCenterFault", reflect.TypeOf((*NoConnectionToVCenterFault)(nil)).Elem())
+}
+
+type NoCustomAgentVmDatastore struct {
+	NoAgentVmDatastore
+
+	CustomAgentVmDatastore     []types.ManagedObjectReference `xml:"customAgentVmDatastore"`
+	CustomAgentVmDatastoreName []string                       `xml:"customAgentVmDatastoreName"`
+}
+
+func init() {
+	types.Add("eam:NoCustomAgentVmDatastore", reflect.TypeOf((*NoCustomAgentVmDatastore)(nil)).Elem())
+}
+
+type NoCustomAgentVmNetwork struct {
+	NoAgentVmNetwork
+
+	CustomAgentVmNetwork     []types.ManagedObjectReference `xml:"customAgentVmNetwork"`
+	CustomAgentVmNetworkName []string                       `xml:"customAgentVmNetworkName"`
+}
+
+func init() {
+	types.Add("eam:NoCustomAgentVmNetwork", reflect.TypeOf((*NoCustomAgentVmNetwork)(nil)).Elem())
+}
+
+type NoDiscoverableAgentVmDatastore struct {
+	VmNotDeployed
+}
+
+func init() {
+	types.Add("eam:NoDiscoverableAgentVmDatastore", reflect.TypeOf((*NoDiscoverableAgentVmDatastore)(nil)).Elem())
+}
+
+type NoDiscoverableAgentVmNetwork struct {
+	VmNotDeployed
+}
+
+func init() {
+	types.Add("eam:NoDiscoverableAgentVmNetwork", reflect.TypeOf((*NoDiscoverableAgentVmNetwork)(nil)).Elem())
+}
+
+type NotAuthorized struct {
+	EamRuntimeFault
+}
+
+func init() {
+	types.Add("eam:NotAuthorized", reflect.TypeOf((*NotAuthorized)(nil)).Elem())
+}
+
+type NotAuthorizedFault NotAuthorized
+
+func init() {
+	types.Add("eam:NotAuthorizedFault", reflect.TypeOf((*NotAuthorizedFault)(nil)).Elem())
+}
+
+type OrphanedAgency struct {
+	AgencyIssue
+}
+
+func init() {
+	types.Add("eam:OrphanedAgency", reflect.TypeOf((*OrphanedAgency)(nil)).Elem())
+}
+
+type OrphanedDvFilterSwitch struct {
+	HostIssue
+}
+
+func init() {
+	types.Add("eam:OrphanedDvFilterSwitch", reflect.TypeOf((*OrphanedDvFilterSwitch)(nil)).Elem())
+}
+
+type OvfInvalidFormat struct {
+	VmNotDeployed
+
+	Error []types.LocalizedMethodFault `xml:"error,omitempty"`
+}
+
+func init() {
+	types.Add("eam:OvfInvalidFormat", reflect.TypeOf((*OvfInvalidFormat)(nil)).Elem())
+}
+
+type OvfInvalidProperty struct {
+	AgentIssue
+
+	Error []types.LocalizedMethodFault `xml:"error,omitempty"`
+}
+
+func init() {
+	types.Add("eam:OvfInvalidProperty", reflect.TypeOf((*OvfInvalidProperty)(nil)).Elem())
+}
+
+type PersonalityAgencyCannotConfigureSolutions struct {
+	PersonalityAgencyPMIssue
+
+	Cr                types.ManagedObjectReference `xml:"cr"`
+	SolutionsToModify []string                     `xml:"solutionsToModify,omitempty"`
+	SolutionsToRemove []string                     `xml:"solutionsToRemove,omitempty"`
+}
+
+func init() {
+	types.Add("eam:PersonalityAgencyCannotConfigureSolutions", reflect.TypeOf((*PersonalityAgencyCannotConfigureSolutions)(nil)).Elem())
+}
+
+type PersonalityAgencyCannotUploadDepot struct {
+	PersonalityAgencyDepotIssue
+
+	LocalDepotUrl string `xml:"localDepotUrl"`
+}
+
+func init() {
+	types.Add("eam:PersonalityAgencyCannotUploadDepot", reflect.TypeOf((*PersonalityAgencyCannotUploadDepot)(nil)).Elem())
+}
+
+type PersonalityAgencyDepotIssue struct {
+	PersonalityAgencyPMIssue
+
+	RemoteDepotUrl string `xml:"remoteDepotUrl"`
+}
+
+func init() {
+	types.Add("eam:PersonalityAgencyDepotIssue", reflect.TypeOf((*PersonalityAgencyDepotIssue)(nil)).Elem())
+}
+
+type PersonalityAgencyInaccessibleDepot struct {
+	PersonalityAgencyDepotIssue
+}
+
+func init() {
+	types.Add("eam:PersonalityAgencyInaccessibleDepot", reflect.TypeOf((*PersonalityAgencyInaccessibleDepot)(nil)).Elem())
+}
+
+type PersonalityAgencyInvalidDepot struct {
+	PersonalityAgencyDepotIssue
+}
+
+func init() {
+	types.Add("eam:PersonalityAgencyInvalidDepot", reflect.TypeOf((*PersonalityAgencyInvalidDepot)(nil)).Elem())
+}
+
+type PersonalityAgencyPMIssue struct {
+	AgencyIssue
+}
+
+func init() {
+	types.Add("eam:PersonalityAgencyPMIssue", reflect.TypeOf((*PersonalityAgencyPMIssue)(nil)).Elem())
+}
+
+type PersonalityAgencyPMUnavailable struct {
+	PersonalityAgencyPMIssue
+}
+
+func init() {
+	types.Add("eam:PersonalityAgencyPMUnavailable", reflect.TypeOf((*PersonalityAgencyPMUnavailable)(nil)).Elem())
+}
+
+type PersonalityAgentAwaitingPMRemediation struct {
+	PersonalityAgentPMIssue
+}
+
+func init() {
+	types.Add("eam:PersonalityAgentAwaitingPMRemediation", reflect.TypeOf((*PersonalityAgentAwaitingPMRemediation)(nil)).Elem())
+}
+
+type PersonalityAgentBlockedByAgencyOperation struct {
+	PersonalityAgentPMIssue
+}
+
+func init() {
+	types.Add("eam:PersonalityAgentBlockedByAgencyOperation", reflect.TypeOf((*PersonalityAgentBlockedByAgencyOperation)(nil)).Elem())
+}
+
+type PersonalityAgentPMIssue struct {
+	AgentIssue
+}
+
+func init() {
+	types.Add("eam:PersonalityAgentPMIssue", reflect.TypeOf((*PersonalityAgentPMIssue)(nil)).Elem())
+}
+
+type QueryAgency QueryAgencyRequestType
+
+func init() {
+	types.Add("eam:QueryAgency", reflect.TypeOf((*QueryAgency)(nil)).Elem())
+}
+
+type QueryAgencyRequestType struct {
+	This types.ManagedObjectReference `xml:"_this"`
+}
+
+func init() {
+	types.Add("eam:QueryAgencyRequestType", reflect.TypeOf((*QueryAgencyRequestType)(nil)).Elem())
+}
+
+type QueryAgencyResponse struct {
+	Returnval []types.ManagedObjectReference `xml:"returnval,omitempty"`
+}
+
+type QueryAgent QueryAgentRequestType
+
+func init() {
+	types.Add("eam:QueryAgent", reflect.TypeOf((*QueryAgent)(nil)).Elem())
+}
+
+type QueryAgentRequestType struct {
+	This types.ManagedObjectReference `xml:"_this"`
+}
+
+func init() {
+	types.Add("eam:QueryAgentRequestType", reflect.TypeOf((*QueryAgentRequestType)(nil)).Elem())
+}
+
+type QueryAgentResponse struct {
+	Returnval []types.ManagedObjectReference `xml:"returnval,omitempty"`
+}
+
+type QueryConfig QueryConfigRequestType
+
+func init() {
+	types.Add("eam:QueryConfig", reflect.TypeOf((*QueryConfig)(nil)).Elem())
+}
+
+type QueryConfigRequestType struct {
+	This types.ManagedObjectReference `xml:"_this"`
+}
+
+func init() {
+	types.Add("eam:QueryConfigRequestType", reflect.TypeOf((*QueryConfigRequestType)(nil)).Elem())
+}
+
+type QueryConfigResponse struct {
+	Returnval AgencyConfigInfo `xml:"returnval"`
+}
+
+type QueryIssue QueryIssueRequestType
+
+func init() {
+	types.Add("eam:QueryIssue", reflect.TypeOf((*QueryIssue)(nil)).Elem())
+}
+
+type QueryIssueRequestType struct {
+	This     types.ManagedObjectReference `xml:"_this"`
+	IssueKey []int32                      `xml:"issueKey,omitempty"`
+}
+
+func init() {
+	types.Add("eam:QueryIssueRequestType", reflect.TypeOf((*QueryIssueRequestType)(nil)).Elem())
+}
+
+type QueryIssueResponse struct {
+	Returnval []BaseIssue `xml:"returnval,omitempty,typeattr"`
+}
+
+type QuerySolutionId QuerySolutionIdRequestType
+
+func init() {
+	types.Add("eam:QuerySolutionId", reflect.TypeOf((*QuerySolutionId)(nil)).Elem())
+}
+
+type QuerySolutionIdRequestType struct {
+	This types.ManagedObjectReference `xml:"_this"`
+}
+
+func init() {
+	types.Add("eam:QuerySolutionIdRequestType", reflect.TypeOf((*QuerySolutionIdRequestType)(nil)).Elem())
+}
+
+type QuerySolutionIdResponse struct {
+	Returnval string `xml:"returnval"`
+}
+
+type RegisterAgentVm RegisterAgentVmRequestType
+
+func init() {
+	types.Add("eam:RegisterAgentVm", reflect.TypeOf((*RegisterAgentVm)(nil)).Elem())
+}
+
+type RegisterAgentVmRequestType struct {
+	This    types.ManagedObjectReference `xml:"_this"`
+	AgentVm types.ManagedObjectReference `xml:"agentVm"`
+}
+
+func init() {
+	types.Add("eam:RegisterAgentVmRequestType", reflect.TypeOf((*RegisterAgentVmRequestType)(nil)).Elem())
+}
+
+type RegisterAgentVmResponse struct {
+	Returnval types.ManagedObjectReference `xml:"returnval"`
+}
+
+type Resolve ResolveRequestType
+
+func init() {
+	types.Add("eam:Resolve", reflect.TypeOf((*Resolve)(nil)).Elem())
+}
+
+type ResolveAll ResolveAllRequestType
+
+func init() {
+	types.Add("eam:ResolveAll", reflect.TypeOf((*ResolveAll)(nil)).Elem())
+}
+
+type ResolveAllRequestType struct {
+	This types.ManagedObjectReference `xml:"_this"`
+}
+
+func init() {
+	types.Add("eam:ResolveAllRequestType", reflect.TypeOf((*ResolveAllRequestType)(nil)).Elem())
+}
+
+type ResolveAllResponse struct {
+}
+
+type ResolveRequestType struct {
+	This     types.ManagedObjectReference `xml:"_this"`
+	IssueKey []int32                      `xml:"issueKey"`
+}
+
+func init() {
+	types.Add("eam:ResolveRequestType", reflect.TypeOf((*ResolveRequestType)(nil)).Elem())
+}
+
+type ResolveResponse struct {
+	Returnval []int32 `xml:"returnval,omitempty"`
+}
+
+type ScanForUnknownAgentVm ScanForUnknownAgentVmRequestType
+
+func init() {
+	types.Add("eam:ScanForUnknownAgentVm", reflect.TypeOf((*ScanForUnknownAgentVm)(nil)).Elem())
+}
+
+type ScanForUnknownAgentVmRequestType struct {
+	This types.ManagedObjectReference `xml:"_this"`
+}
+
+func init() {
+	types.Add("eam:ScanForUnknownAgentVmRequestType", reflect.TypeOf((*ScanForUnknownAgentVmRequestType)(nil)).Elem())
+}
+
+type ScanForUnknownAgentVmResponse struct {
+}
+
+type Uninstall UninstallRequestType
+
+func init() {
+	types.Add("eam:Uninstall", reflect.TypeOf((*Uninstall)(nil)).Elem())
+}
+
+type UninstallRequestType struct {
+	This types.ManagedObjectReference `xml:"_this"`
+}
+
+func init() {
+	types.Add("eam:UninstallRequestType", reflect.TypeOf((*UninstallRequestType)(nil)).Elem())
+}
+
+type UninstallResponse struct {
+}
+
+type UnknownAgentVm struct {
+	HostIssue
+
+	Vm types.ManagedObjectReference `xml:"vm"`
+}
+
+func init() {
+	types.Add("eam:UnknownAgentVm", reflect.TypeOf((*UnknownAgentVm)(nil)).Elem())
+}
+
+type UnregisterAgentVm UnregisterAgentVmRequestType
+
+func init() {
+	types.Add("eam:UnregisterAgentVm", reflect.TypeOf((*UnregisterAgentVm)(nil)).Elem())
+}
+
+type UnregisterAgentVmRequestType struct {
+	This    types.ManagedObjectReference `xml:"_this"`
+	AgentVm types.ManagedObjectReference `xml:"agentVm"`
+}
+
+func init() {
+	types.Add("eam:UnregisterAgentVmRequestType", reflect.TypeOf((*UnregisterAgentVmRequestType)(nil)).Elem())
+}
+
+type UnregisterAgentVmResponse struct {
+}
+
+type Update UpdateRequestType
+
+func init() {
+	types.Add("eam:Update", reflect.TypeOf((*Update)(nil)).Elem())
+}
+
+type UpdateRequestType struct {
+	This   types.ManagedObjectReference `xml:"_this"`
+	Config AgencyConfigInfo             `xml:"config"`
+}
+
+func init() {
+	types.Add("eam:UpdateRequestType", reflect.TypeOf((*UpdateRequestType)(nil)).Elem())
+}
+
+type UpdateResponse struct {
+}
+
+type VibCannotPutHostInMaintenanceMode struct {
+	VibIssue
+}
+
+func init() {
+	types.Add("eam:VibCannotPutHostInMaintenanceMode", reflect.TypeOf((*VibCannotPutHostInMaintenanceMode)(nil)).Elem())
+}
+
+type VibCannotPutHostOutOfMaintenanceMode struct {
+	VibIssue
+}
+
+func init() {
+	types.Add("eam:VibCannotPutHostOutOfMaintenanceMode", reflect.TypeOf((*VibCannotPutHostOutOfMaintenanceMode)(nil)).Elem())
+}
+
+type VibDependenciesNotMetByHost struct {
+	VibNotInstalled
+}
+
+func init() {
+	types.Add("eam:VibDependenciesNotMetByHost", reflect.TypeOf((*VibDependenciesNotMetByHost)(nil)).Elem())
+}
+
+type VibInvalidFormat struct {
+	VibNotInstalled
+}
+
+func init() {
+	types.Add("eam:VibInvalidFormat", reflect.TypeOf((*VibInvalidFormat)(nil)).Elem())
+}
+
+type VibIssue struct {
+	AgentIssue
+}
+
+func init() {
+	types.Add("eam:VibIssue", reflect.TypeOf((*VibIssue)(nil)).Elem())
+}
+
+type VibNotInstalled struct {
+	VibIssue
+}
+
+func init() {
+	types.Add("eam:VibNotInstalled", reflect.TypeOf((*VibNotInstalled)(nil)).Elem())
+}
+
+type VibRequirementsNotMetByHost struct {
+	VibNotInstalled
+}
+
+func init() {
+	types.Add("eam:VibRequirementsNotMetByHost", reflect.TypeOf((*VibRequirementsNotMetByHost)(nil)).Elem())
+}
+
+type VibRequiresHostInMaintenanceMode struct {
+	VibIssue
+}
+
+func init() {
+	types.Add("eam:VibRequiresHostInMaintenanceMode", reflect.TypeOf((*VibRequiresHostInMaintenanceMode)(nil)).Elem())
+}
+
+type VibRequiresHostReboot struct {
+	VibIssue
+}
+
+func init() {
+	types.Add("eam:VibRequiresHostReboot", reflect.TypeOf((*VibRequiresHostReboot)(nil)).Elem())
+}
+
+type VibRequiresManualInstallation struct {
+	VibIssue
+
+	Bulletin []string `xml:"bulletin"`
+}
+
+func init() {
+	types.Add("eam:VibRequiresManualInstallation", reflect.TypeOf((*VibRequiresManualInstallation)(nil)).Elem())
+}
+
+type VibRequiresManualUninstallation struct {
+	VibIssue
+
+	Bulletin []string `xml:"bulletin"`
+}
+
+func init() {
+	types.Add("eam:VibRequiresManualUninstallation", reflect.TypeOf((*VibRequiresManualUninstallation)(nil)).Elem())
+}
+
+type VibVibInfo struct {
+	types.DynamicData
+
+	Id           string                  `xml:"id"`
+	Name         string                  `xml:"name"`
+	Version      string                  `xml:"version"`
+	Vendor       string                  `xml:"vendor"`
+	Summary      string                  `xml:"summary"`
+	SoftwareTags *VibVibInfoSoftwareTags `xml:"softwareTags,omitempty"`
+	ReleaseDate  time.Time               `xml:"releaseDate"`
+}
+
+func init() {
+	types.Add("eam:VibVibInfo", reflect.TypeOf((*VibVibInfo)(nil)).Elem())
+}
+
+type VibVibInfoSoftwareTags struct {
+	types.DynamicData
+
+	Tags []string `xml:"tags,omitempty"`
+}
+
+func init() {
+	types.Add("eam:VibVibInfoSoftwareTags", reflect.TypeOf((*VibVibInfoSoftwareTags)(nil)).Elem())
+}
+
+type VmCorrupted struct {
+	VmIssue
+
+	MissingFile string `xml:"missingFile,omitempty"`
+}
+
+func init() {
+	types.Add("eam:VmCorrupted", reflect.TypeOf((*VmCorrupted)(nil)).Elem())
+}
+
+type VmDeployed struct {
+	VmIssue
+}
+
+func init() {
+	types.Add("eam:VmDeployed", reflect.TypeOf((*VmDeployed)(nil)).Elem())
+}
+
+type VmIssue struct {
+	AgentIssue
+
+	Vm types.ManagedObjectReference `xml:"vm"`
+}
+
+func init() {
+	types.Add("eam:VmIssue", reflect.TypeOf((*VmIssue)(nil)).Elem())
+}
+
+type VmMarkedAsTemplate struct {
+	VmIssue
+}
+
+func init() {
+	types.Add("eam:VmMarkedAsTemplate", reflect.TypeOf((*VmMarkedAsTemplate)(nil)).Elem())
+}
+
+type VmNotDeployed struct {
+	AgentIssue
+}
+
+func init() {
+	types.Add("eam:VmNotDeployed", reflect.TypeOf((*VmNotDeployed)(nil)).Elem())
+}
+
+type VmOrphaned struct {
+	VmIssue
+}
+
+func init() {
+	types.Add("eam:VmOrphaned", reflect.TypeOf((*VmOrphaned)(nil)).Elem())
+}
+
+type VmPoweredOff struct {
+	VmIssue
+}
+
+func init() {
+	types.Add("eam:VmPoweredOff", reflect.TypeOf((*VmPoweredOff)(nil)).Elem())
+}
+
+type VmPoweredOn struct {
+	VmIssue
+}
+
+func init() {
+	types.Add("eam:VmPoweredOn", reflect.TypeOf((*VmPoweredOn)(nil)).Elem())
+}
+
+type VmRequiresHostOutOfMaintenanceMode struct {
+	VmNotDeployed
+}
+
+func init() {
+	types.Add("eam:VmRequiresHostOutOfMaintenanceMode", reflect.TypeOf((*VmRequiresHostOutOfMaintenanceMode)(nil)).Elem())
+}
+
+type VmSuspended struct {
+	VmIssue
+}
+
+func init() {
+	types.Add("eam:VmSuspended", reflect.TypeOf((*VmSuspended)(nil)).Elem())
+}
+
+type VmWrongFolder struct {
+	VmIssue
+
+	CurrentFolder  types.ManagedObjectReference `xml:"currentFolder"`
+	RequiredFolder types.ManagedObjectReference `xml:"requiredFolder"`
+}
+
+func init() {
+	types.Add("eam:VmWrongFolder", reflect.TypeOf((*VmWrongFolder)(nil)).Elem())
+}
+
+type VmWrongResourcePool struct {
+	VmIssue
+
+	CurrentResourcePool  types.ManagedObjectReference `xml:"currentResourcePool"`
+	RequiredResourcePool types.ManagedObjectReference `xml:"requiredResourcePool"`
+}
+
+func init() {
+	types.Add("eam:VmWrongResourcePool", reflect.TypeOf((*VmWrongResourcePool)(nil)).Elem())
+}
+
+type VersionURI string
+
+func init() {
+	types.Add("eam:versionURI", reflect.TypeOf((*VersionURI)(nil)).Elem())
+}
diff --git a/gen/.gitignore b/gen/.gitignore
new file mode 100644
index 00000000..db872fac
--- /dev/null
+++ b/gen/.gitignore
@@ -0,0 +1,1 @@
+sdk/
diff --git a/gen/gen.sh b/gen/gen.sh
index 4386a952..b1961158 100755
--- a/gen/gen.sh
+++ b/gen/gen.sh
@@ -53,6 +53,17 @@ generate "../vim25" "vim" "./rbvmomi/vmodl.db" # from github.com/vmware/rbvmomi@
 generate "../pbm" "pbm"
 generate "../vslm" "vslm"
 generate "../sms" "sms"
+
+# ./sdk/ contains the files eam-messagetypes.xsd and eam-types.xsd from
+# eam-wsdl.zip, from eam-vcenter build 17073099 (vSphere 7.0U1), a
+# dependency component of the aforementioned vimbase build 17097359.
+#
+# Please note the EAM files are also available at the following, public URL --
+# http://bit.ly/eam-sdk, therefore the WSDL resource for EAM are in fact
+# public. A specific build was obtained in order to match the same build as
+# used for the file from above, wsdl.zip.
+COPYRIGHT_DATE_RANGE=2021 generate "../eam" "eam"
+
 # originally generated, then manually pruned as there are several vim25 types that are duplicated.
 # generate "../lookup" "lookup" # lookup.wsdl from build 4571810
 # originally generated, then manually pruned.
diff --git a/gen/vim_wsdl.rb b/gen/vim_wsdl.rb
index ba404cda..1ea3b440 100644
--- a/gen/vim_wsdl.rb
+++ b/gen/vim_wsdl.rb
@@ -866,7 +866,7 @@ class WSDL
   def self.header(name)
     return <<EOF
 /*
-Copyright (c) 2014-2018 VMware, Inc. All Rights Reserved.
+Copyright (c) #{ENV['COPYRIGHT_DATE_RANGE'] || '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.
diff --git a/govc/README.md b/govc/README.md
index 66433c86..efcbffac 100644
--- a/govc/README.md
+++ b/govc/README.md
@@ -1,9 +1,9 @@
 # govc
 
-`govc` is a vSphere CLI built on top of `govmomi`.
+`govc` is a vSphere CLI built on top of govmomi.
 
 The CLI is designed to be a user friendly CLI alternative to the GUI and well suited for automation tasks.
-It also acts as a [test harness](test) for the `govmomi` APIs and provides working examples of how to use the APIs.
+It also acts as a [test harness](test) for the govmomi APIs and provides working examples of how to use the APIs.
 
 ## Installation
 
@@ -16,7 +16,7 @@ You can find prebuilt `govc` binaries on the [releases page](https://github.com/
 
 You can download and install a binary locally like this:
 
-```console
+``` console
 # get version from https://github.com/vmware/govmomi/releases/latest
 $ VERSION=v0.25.0
 $ URL=https://github.com/vmware/govmomi/releases/download/${VERSION}/govc_$(uname -s)_$(uname -m).tar.gz
@@ -27,57 +27,25 @@ $ curl -L -o - $URL | tar -C /usr/local/bin -xvzf - govc
 
 ### Source
 
-#### Install via `go get`
-
 To build `govc` from source, first install the [Go
 toolchain](https://golang.org/dl/). You can then install the latest `govc` from
 Github using:
 
-```console
+``` console
 $ go get -u github.com/vmware/govmomi/govc
 ```
 
-**Note:** `govmomi` and its binaries use [Go
-modules](https://golang.org/ref/mod), i.e. explicitly setting `GOPATH` is not
-required anymore. To inject build variables (see details
-[below](#install-via-goreleaser)) used by `govc version [-l]`, `GOFLAGS` can be
-defined and are honored by `go get`.
+**Note:** govmomi and its binaries use [Go modules](https://golang.org/ref/mod),
+i.e. explicitly setting `GOPATH` is not required anymore.
 
-⚠️ Make sure `$GOPATH/bin` is in your `PATH` to use the version installed from
-source.
+Make sure `$GOPATH/bin` is in your `PATH` to use the version installed from source.
 
-If you've made local modifications to the repository at
-`$GOPATH/src/github.com/vmware/govmomi`, you can install using:
+If you've made local modifications to the repository at `$GOPATH/src/github.com/vmware/govmomi`, you can install using:
 
-```console
+``` console
 $ go install github.com/vmware/govmomi/govc
 ```
 
-#### Install via `goreleaser`
-
-You can also build `govc` following our release process using `goreleaser`
-(requires [Go toolchain](https://golang.org/dl/)). This will ensure that build
-time variables are correctly injected. Build (linker) flags and injection are
-defined in [.goreleaser.yaml](./../.goreleaser.yml) and automatically set as
-`GOFLAGS` when building with `goreleaser`.
-
-Install `goreleaser` as per the installation
-[instructions](https://goreleaser.com/install/), then:
-
-```console
-$ git clone https://github.com/vmware/govmomi.git
-$ cd govmomi
-
-# pick a tag (>=v0.25.0)
-$ RELEASE=v0.25.0
-
-$ git checkout ${RELEASE}
-
-# build for the host OS/ARCH, otherwise omit --single-target
-# binaries are placed in respective subdirectories in ./dist/
-$ goreleaser build --rm-dist --single-target
-```
-
 ## Usage
 
 For the complete list of commands and flags, refer to the [USAGE](USAGE.md) document.
@@ -125,7 +93,7 @@ using environment variables. The following environment variables are used by
 
 * `GOVC_TLS_CA_CERTS`: Override system root certificate authorities.
 
-    ```console
+    ``` console
     $ export GOVC_TLS_CA_CERTS=~/.govc_ca.crt
     # Use path separator to specify multiple files:
     $ export GOVC_TLS_CA_CERTS=~/ca-certificates/bar.crt:~/ca-certificates/foo.crt
@@ -136,7 +104,7 @@ using environment variables. The following environment variables are used by
     Thumbprint based verification can be used in addition to or as an alternative to
     `GOVC_TLS_CA_CERTS` for self-signed certificates.  Example:
 
-    ```console
+    ``` console
     $ export GOVC_TLS_KNOWN_HOSTS=~/.govc_known_hosts
     $ govc about.cert -u host -k -thumbprint | tee -a $GOVC_TLS_KNOWN_HOSTS
     $ govc about -u user:pass@host
@@ -232,7 +200,7 @@ by setting the debug path to a dash: `export GOVC_DEBUG_PATH=-`
 
 If you're using environment variables to set `GOVC_URL`, verify the values are set as expected:
 
-```console
+``` console
 $ govc env
 ```
 
@@ -240,12 +208,12 @@ $ govc env
 
 Check your proxy settings:
 
-```console
+``` console
 $ env | grep -i https_proxy
 ```
 
 Test connection using curl:
-```console
+``` console
 $ curl --verbose -k -X POST https://x.x.x.x/sdk
 ```
 
@@ -261,7 +229,7 @@ cookies, resulting in a `NotAuthenticated` error. For example, running `govc`
 directly against the vCenter vpxd endpoint at `http://127.0.0.1:8085`. Set the
 environment variable `GOVMOMI_INSECURE_COOKIES=true` to workaround this:
 
-```console
+``` console
 $ GOVMOMI_INSECURE_COOKIES=true govc ls -u http://user:pass@127.0.0.1:8085
 ```
 
@@ -293,7 +261,7 @@ When new `govc` commands or flags are added, the PATCH version will be
 incremented.  This enables you to require a minimum version from within a
 script, for example:
 
-```console
+``` console
 $ govc version -require 0.24
 ```
 
@@ -301,7 +269,7 @@ $ govc version -require 0.24
 
 * [Emacs govc package](./emacs)
 
-* [Kubernetes vSphere Cloud Provider](https://github.com/kubernetes/cloud-provider-vsphere)
+* [Kubernetes vSphere Provider](https://github.com/kubernetes/kubernetes/tree/master/cluster/vsphere)
 
 * [VMware VIC Engine](https://github.com/vmware/vic)
 
diff --git a/govc/host/info.go b/govc/host/info.go
index 56467cc8..7828d5e9 100644
--- a/govc/host/info.go
+++ b/govc/host/info.go
@@ -153,7 +153,7 @@ func (r *infoResult) Write(w io.Writer) error {
 		fmt.Fprintf(tw, "  Memory usage:\t%d MB (%.1f%%)\n", z.OverallMemoryUsage, memUsage)
 		fmt.Fprintf(tw, "  Boot time:\t%s\n", s.Runtime.BootTime)
 		if s.Runtime.InMaintenanceMode {
-			fmt.Fprint(tw, "  State:\tMaintenance Mode\n")
+			fmt.Fprint(tw, "  State: Maintenance Mode")
 		} else {
 			fmt.Fprintf(tw, "  State:\t%s\n", s.Runtime.ConnectionState)
 		}
diff --git a/govc/main.go b/govc/main.go
index 6e028cc4..ff6f66c6 100644
--- a/govc/main.go
+++ b/govc/main.go
@@ -88,7 +88,6 @@ import (
 	_ "github.com/vmware/govmomi/govc/task"
 	_ "github.com/vmware/govmomi/govc/vapp"
 	_ "github.com/vmware/govmomi/govc/vcsa/log"
-	_ "github.com/vmware/govmomi/govc/vcsa/proxy"
 	_ "github.com/vmware/govmomi/govc/version"
 	_ "github.com/vmware/govmomi/govc/vm"
 	_ "github.com/vmware/govmomi/govc/vm/disk"
diff --git a/govc/vcsa/proxy/proxy.go b/govc/vcsa/proxy/proxy.go
deleted file mode 100644
index a142bf83..00000000
--- a/govc/vcsa/proxy/proxy.go
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
-Copyright (c) 2021 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 net
-
-import (
-	"context"
-	"flag"
-	"fmt"
-	"io"
-	"strings"
-	"text/tabwriter"
-
-	"github.com/vmware/govmomi/govc/cli"
-	"github.com/vmware/govmomi/govc/flags"
-	vnetworking "github.com/vmware/govmomi/vapi/appliance/networking"
-)
-
-type info struct {
-	*flags.ClientFlag
-	*flags.OutputFlag
-}
-
-func init() {
-	cli.Register("vcsa.net.proxy.info", &info{})
-}
-
-func (cmd *info) Register(ctx context.Context, f *flag.FlagSet) {
-	cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
-	cmd.ClientFlag.Register(ctx, f)
-
-	cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
-	cmd.OutputFlag.Register(ctx, f)
-}
-
-func (cmd *info) Process(ctx context.Context) error {
-	if err := cmd.ClientFlag.Process(ctx); err != nil {
-		return err
-	}
-	if err := cmd.OutputFlag.Process(ctx); err != nil {
-		return err
-	}
-	return nil
-}
-
-func (cmd *info) Description() string {
-	return `Retrieve the VC networking proxy configuration
-
-Examples:
-  govc vcsa.net.proxy.info`
-}
-
-type proxyResult struct {
-	proxy   *vnetworking.ProxyList
-	noProxy []string
-}
-
-func (cmd *info) Run(ctx context.Context, f *flag.FlagSet) error {
-	c, err := cmd.RestClient()
-	if err != nil {
-		return err
-	}
-
-	fwd := vnetworking.NewManager(c)
-
-	proxyRes, err := fwd.ProxyList(ctx)
-	if err != nil {
-		fmt.Println(err)
-		return nil
-	}
-
-	noProxyRes, err := fwd.NoProxy(ctx)
-	if err != nil {
-		fmt.Println(err)
-		return nil
-	}
-
-	return cmd.WriteResult(&proxyResult{proxyRes, noProxyRes})
-}
-
-func (res proxyResult) Write(w io.Writer) error {
-	tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0)
-	printProxyConfig("HTTP", res.proxy.Http, tw)
-	printProxyConfig("HTTPS", res.proxy.Https, tw)
-	printProxyConfig("FTP", res.proxy.Ftp, tw)
-	fmt.Fprintf(tw, "No Proxy addresses:\t%s\n", strings.Join(res.noProxy, ", "))
-
-	return tw.Flush()
-}
-
-func printProxyConfig(proxyName string, proxyProtocolConfig vnetworking.Proxy, w io.Writer) {
-	if !proxyProtocolConfig.Enabled {
-		fmt.Fprintf(w, "%s proxy:\tDisabled\n", proxyName)
-		return
-	}
-
-	fmt.Fprintf(w, "%s proxy:\tEnabled\n", proxyName)
-	fmt.Fprintf(w, "\tServer:\t%s\n", proxyProtocolConfig.Server)
-	fmt.Fprintf(w, "\tPort:\t%d\n", proxyProtocolConfig.Port)
-	if proxyProtocolConfig.Username != "" {
-		fmt.Fprintf(w, "\tUsername:\t%s\n", proxyProtocolConfig.Username)
-	}
-}
diff --git a/simulator/container.go b/simulator/container.go
index 73f00fb7..1042a0d8 100644
--- a/simulator/container.go
+++ b/simulator/container.go
@@ -28,12 +28,14 @@ import (
 	"os"
 	"os/exec"
 	"path"
+	"regexp"
 	"strconv"
 	"strings"
 	"time"
 
 	"github.com/google/uuid"
 
+	"github.com/vmware/govmomi/vim25/methods"
 	"github.com/vmware/govmomi/vim25/types"
 )
 
@@ -67,6 +69,10 @@ func (c *container) inspect(vm *VirtualMachine) error {
 	}
 
 	var objects []struct {
+		State struct {
+			Running bool
+			Paused  bool
+		}
 		NetworkSettings struct {
 			networkSettings
 			Networks map[string]networkSettings
@@ -93,8 +99,12 @@ func (c *container) inspect(vm *VirtualMachine) error {
 			break
 		}
 
-		if s.IPAddress == "" {
-			continue
+		if o.State.Paused {
+			vm.Runtime.PowerState = types.VirtualMachinePowerStateSuspended
+		} else if o.State.Running {
+			vm.Runtime.PowerState = types.VirtualMachinePowerStatePoweredOn
+		} else {
+			vm.Runtime.PowerState = types.VirtualMachinePowerStatePoweredOff
 		}
 
 		vm.Guest.IpAddress = s.IPAddress
@@ -131,12 +141,19 @@ func (c *container) prepareGuestOperation(vm *VirtualMachine, auth types.BaseGue
 	return nil
 }
 
+var sanitizeNameRx = regexp.MustCompile(`[\(\)\s]`)
+
+func sanitizeName(name string) string {
+	return sanitizeNameRx.ReplaceAllString(name, "-")
+}
+
 // createDMI writes BIOS UUID DMI files to a container volume
 func (c *container) createDMI(vm *VirtualMachine, name string) error {
 	image := os.Getenv("VCSIM_BUSYBOX")
 	if image == "" {
 		image = "busybox"
 	}
+
 	cmd := exec.Command("docker", "run", "--rm", "-i", "-v", name+":"+"/"+name, image, "tar", "-C", "/"+name, "-xf", "-")
 	stdin, err := cmd.StdinPipe()
 	if err != nil {
@@ -172,15 +189,16 @@ func (c *container) createDMI(vm *VirtualMachine, name string) error {
 	_ = tw.Close()
 	_ = stdin.Close()
 
-	err = cmd.Wait()
-	if err != nil {
+	if err := cmd.Wait(); err != nil {
 		stderr := ""
 		if xerr, ok := err.(*exec.ExitError); ok {
 			stderr = string(xerr.Stderr)
 		}
 		log.Printf("%s %s: %s %s", vm.Name, cmd.Args, err, stderr)
+		return err
 	}
-	return err
+
+	return nil
 }
 
 var (
@@ -240,7 +258,7 @@ func (c *container) start(ctx *Context, vm *VirtualMachine) {
 		env = append(env, "--env", "VMX_GUESTINFO=true")
 	}
 
-	c.name = fmt.Sprintf("vcsim-%s-%s", vm.Name, vm.uid)
+	c.name = fmt.Sprintf("vcsim-%s-%s", sanitizeName(vm.Name), vm.uid)
 	run := append([]string{"docker", "run", "-d", "--name", c.name}, env...)
 
 	if err := c.createDMI(vm, c.name); err != nil {
@@ -268,6 +286,47 @@ func (c *container) start(ctx *Context, vm *VirtualMachine) {
 	if err = c.inspect(vm); err != nil {
 		log.Printf("%s inspect %s: %s", vm.Name, c.id, err)
 	}
+
+	// Keep updating the VM properties by inspecting the container until
+	// an inspect call fails.
+	inspectInterval := time.Duration(5 * time.Second)
+	if d, err := time.ParseDuration(os.Getenv("VCSIM_INSPECT_INTERVAL")); err == nil {
+		inspectInterval = d
+	}
+
+	go func() {
+		if inspectInterval == 0 {
+			return
+		}
+		for {
+			// Exit the monitor loop if the VM was removed from the API side.
+			if c.id == "" {
+				return
+			}
+
+			time.Sleep(inspectInterval)
+			if err := c.inspect(vm); err != nil {
+				stderr := ""
+				if xerr, ok := err.(*exec.ExitError); ok {
+					stderr = string(xerr.Stderr)
+				}
+				if strings.Contains(stderr, "No such object") {
+					// If the container cannot be found then destroy this VM.
+					taskRef := vm.DestroyTask(ctx, &types.Destroy_Task{
+						This: vm.Self,
+					}).(*methods.Destroy_TaskBody).Res.Returnval
+					task := ctx.Map.Get(taskRef).(*Task)
+
+					// Wait for the task to complete and see if there is an error.
+					task.Wait()
+					if task.Info.Error != nil {
+						vm.logPrintf("failed to destroy vm: err=%v", *task.Info.Error)
+					}
+				}
+				return
+			}
+		}
+	}()
 }
 
 // stop the container (if any) for the given vm.
diff --git a/simulator/internal/object_lock.go b/simulator/internal/object_lock.go
index 8c80f817..7ec8e10d 100644
--- a/simulator/internal/object_lock.go
+++ b/simulator/internal/object_lock.go
@@ -6,7 +6,7 @@ import (
 )
 
 // SharedLockingContext is used to identify when locks can be shared. In
-// practice, simulator code uses the simulator.Context for a requst, but in
+// practice, simulator code uses the simulator.Context for a request, but in
 // principle this could be anything.
 type SharedLockingContext interface{}
 
diff --git a/simulator/registry.go b/simulator/registry.go
index 914f2023..8f0334cb 100644
--- a/simulator/registry.go
+++ b/simulator/registry.go
@@ -217,6 +217,22 @@ func (r *Registry) All(kind string) []mo.Entity {
 	return entities
 }
 
+// AllReference returns all mo.Reference objects of type specified by kind.
+// If kind is empty - all objects will be returned.
+func (r *Registry) AllReference(kind string) []mo.Reference {
+	r.m.Lock()
+	defer r.m.Unlock()
+
+	var objs []mo.Reference
+	for ref, val := range r.objects {
+		if kind == "" || ref.Type == kind {
+			objs = append(objs, val)
+		}
+	}
+
+	return objs
+}
+
 // applyHandlers calls the given func for each r.handlers
 func (r *Registry) applyHandlers(f func(o RegisterObject)) {
 	r.m.Lock()
diff --git a/simulator/simulator.go b/simulator/simulator.go
index b26451ae..f8f8e524 100644
--- a/simulator/simulator.go
+++ b/simulator/simulator.go
@@ -335,34 +335,32 @@ func (s *Service) About(w http.ResponseWriter, r *http.Request) {
 
 	f := reflect.TypeOf((*soap.HasFault)(nil)).Elem()
 
-	for _, sdk := range s.sdk {
-		for _, obj := range sdk.objects {
-			kind := obj.Reference().Type
-			if seen[kind] {
-				continue
-			}
-			seen[kind] = true
-
-			about.Types = append(about.Types, kind)
+	for _, obj := range Map.objects {
+		kind := obj.Reference().Type
+		if seen[kind] {
+			continue
+		}
+		seen[kind] = true
 
-			t := reflect.TypeOf(obj)
-			for i := 0; i < t.NumMethod(); i++ {
-				m := t.Method(i)
-				if seen[m.Name] {
-					continue
-				}
-				seen[m.Name] = true
+		about.Types = append(about.Types, kind)
 
-				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
-				}
+		t := reflect.TypeOf(obj)
+		for i := 0; i < t.NumMethod(); i++ {
+			m := t.Method(i)
+			if seen[m.Name] {
+				continue
+			}
+			seen[m.Name] = true
 
-				about.Methods = append(about.Methods, strings.Replace(m.Name, "Task", "_Task", 1))
+			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
+			}
+
+			about.Methods = append(about.Methods, strings.Replace(m.Name, "Task", "_Task", 1))
 		}
 	}
 
diff --git a/simulator/virtual_machine.go b/simulator/virtual_machine.go
index 098b9d97..b05fa4c9 100644
--- a/simulator/virtual_machine.go
+++ b/simulator/virtual_machine.go
@@ -1382,9 +1382,7 @@ func (vm *VirtualMachine) configureDevices(ctx *Context, spec *types.VirtualMach
 				return invalid
 			}
 			devices = vm.removeDevice(ctx, devices, &rspec)
-			if device.DeviceInfo != nil {
-				device.DeviceInfo.GetDescription().Summary = "" // regenerate summary
-			}
+			device.DeviceInfo.GetDescription().Summary = "" // regenerate summary
 
 			err := vm.configureDevice(ctx, devices, dspec)
 			if err != nil {
diff --git a/vapi/appliance/networking/proxy.go b/vapi/appliance/networking/proxy.go
deleted file mode 100644
index 556e1e76..00000000
--- a/vapi/appliance/networking/proxy.go
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
-Copyright (c) 2021 VMware, Inc. All Rights Reserved.
-
-SPDX-License-Identifier: Apache-2.0.
-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 networking
-
-import (
-	"context"
-	"net/http"
-
-	"github.com/vmware/govmomi/vapi/rest"
-)
-
-const applianceProxyConfigPath = "/appliance/networking/proxy"
-const applianceNoProxyConfigPath = "/appliance/networking/noproxy"
-
-// Manager provides convenience methods to configure appliance proxy.
-type Manager struct {
-	*rest.Client
-}
-
-// NewManager creates a new Manager with the given client
-func NewManager(client *rest.Client) *Manager {
-	return &Manager{
-		Client: client,
-	}
-}
-
-// Proxy represents configuration for specific proxy - ftp, http, https.
-type Proxy struct {
-	Server   string `json:"server,omitempty"`
-	Port     int    `json:"port,omitempty"`
-	Username string `json:"username,omitempty"`
-	Password string `json:"password,omitempty"`
-	Enabled  bool   `json:"enabled,omitempty"`
-}
-
-// ProxyList represents configuration for vcenter proxy.
-type ProxyList struct {
-	Ftp   Proxy `json:"ftp,omitempty"`
-	Http  Proxy `json:"http,omitempty"`
-	Https Proxy `json:"https,omitempty"`
-}
-
-// ProxyList returns all Proxy configuration.
-func (m *Manager) ProxyList(ctx context.Context) (*ProxyList, error) {
-	var res ProxyList
-	var rawRes []struct {
-		Key   string
-		Value Proxy
-	}
-
-	r := m.Resource(applianceProxyConfigPath)
-	err := m.Do(ctx, r.Request(http.MethodGet), &rawRes)
-	if err != nil {
-		return &res, err
-	}
-
-	for _, c := range rawRes {
-		switch c.Key {
-		case "http":
-			res.Http = c.Value
-		case "https":
-			res.Https = c.Value
-		case "ftp":
-			res.Ftp = c.Value
-		}
-	}
-
-	return &res, nil
-}
-
-// NoProxy returns all excluded servers for proxying.
-func (m *Manager) NoProxy(ctx context.Context) ([]string, error) {
-	r := m.Resource(applianceNoProxyConfigPath)
-	var res []string
-	return res, m.Do(ctx, r.Request(http.MethodGet), &res)
-}
diff --git a/vcsim/README.md b/vcsim/README.md
index 77302893..8901e89a 100644
--- a/vcsim/README.md
+++ b/vcsim/README.md
@@ -26,50 +26,17 @@ $ curl -L -o - $URL | tar -C /usr/local/bin -xvzf - vcsim
 
 ### Source
 
-#### Install via `go get`
+To build `vcsim` from source, first install the [Go toolchain](https://golang.org/dl/).
 
-To build `vcsim` from source, first install the [Go
-toolchain](https://golang.org/dl/). You can then install the latest `vcsim` from
-Github using:
+You can then install the latest `vcsim` from Github using:
 
 ```console
 $ go get -u github.com/vmware/govmomi/vcsim
 $ $GOPATH/bin/vcsim -h
 ```
 
-**Note:** `govmomi` and its binaries use [Go
-modules](https://golang.org/ref/mod), i.e. explicitly setting `GOPATH` is not
-required anymore. To inject build variables (see details
-[below](#install-via-goreleaser)) used by `vcsim version`, `GOFLAGS` can be
-defined and are honored by `go get`.
-
-⚠️ Make sure `$GOPATH/bin` is in your `PATH` to use the version installed from
-source.
-
-#### Install via `goreleaser`
-
-You can also build `vcsim` following our release process using `goreleaser`
-(requires [Go toolchain](https://golang.org/dl/)). This will ensure that build
-time variables are correctly injected. Build (linker) flags and injection are
-defined in [.goreleaser.yaml](./../.goreleaser.yml) and automatically set as
-`GOFLAGS` when building with `goreleaser`.
-
-Install `goreleaser` as per the installation
-[instructions](https://goreleaser.com/install/), then:
-
-```console
-$ git clone https://github.com/vmware/govmomi.git
-$ cd govmomi
-
-# pick a tag (>=v0.25.0)
-$ RELEASE=v0.25.0
-
-$ git checkout ${RELEASE}
-
-# build for the host OS/ARCH, otherwise omit --single-target
-# binaries are placed in respective subdirectories in ./dist/
-$ goreleaser build --rm-dist --single-target
-```
+**Note:** govmomi and its binaries use [Go modules](https://golang.org/ref/mod),
+i.e. explicitly setting `GOPATH` is not required anymore.
 
 ## Usage
 
diff --git a/vcsim/main.go b/vcsim/main.go
index c8bb854a..1370277a 100644
--- a/vcsim/main.go
+++ b/vcsim/main.go
@@ -40,6 +40,7 @@ import (
 
 	// Register vcsim optional endpoints
 	_ "github.com/vmware/govmomi/cns/simulator"
+	_ "github.com/vmware/govmomi/eam/simulator"
 	_ "github.com/vmware/govmomi/lookup/simulator"
 	_ "github.com/vmware/govmomi/pbm/simulator"
 	_ "github.com/vmware/govmomi/sts/simulator"


Test patch:
diff --git a/.github/workflows/govmomi-govc-tests.yaml b/.github/workflows/govmomi-govc-tests.yaml
index c9e6efc7..3519366c 100644
--- a/.github/workflows/govmomi-govc-tests.yaml
+++ b/.github/workflows/govmomi-govc-tests.yaml
@@ -27,25 +27,11 @@ jobs:
     strategy:
       matrix:
         go-version: ["1.15", "1.16"]
+        # tests randomly hang on ubuntu-20.04 go v1.16
         platform: ["ubuntu-18.04"]
-        cmd: ["govc-test"]
-        experimental: [false]
-        timeout: [10]
-        include:
-          - go-version: "1.15"
-            platform: "ubuntu-18.04"
-            cmd: "govc-test-sso"
-            experimental: true
-            timeout: 3
-          - go-version: "1.15"
-            platform: "ubuntu-18.04"
-            cmd: "govc-test-sso-assert-cert"
-            experimental: true
-            timeout: 3
 
     runs-on: ${{ matrix.platform }}
-    continue-on-error: ${{ matrix.experimental }}
-    timeout-minutes: ${{ matrix.timeout }}
+    timeout-minutes: 20
 
     steps:
       - name: Set up Go ${{ matrix.go-version }}
@@ -57,5 +43,5 @@ jobs:
       - name: Check out code
         uses: actions/checkout@v2
 
-      - name: Run ${{ matrix.cmd }}
-        run: make ${{ matrix.cmd }}
+      - name: Run govc Tests
+        run: make govc-test
diff --git a/eam/object/agency_test.go b/eam/object/agency_test.go
new file mode 100644
index 00000000..0970b3cb
--- /dev/null
+++ b/eam/object/agency_test.go
@@ -0,0 +1,452 @@
+/*
+Copyright (c) 2021 VMware, Inc. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package object_test
+
+import (
+	"errors"
+	"fmt"
+	"testing"
+	"time"
+
+	"github.com/vmware/govmomi/eam/object"
+	"github.com/vmware/govmomi/eam/types"
+	"github.com/vmware/govmomi/find"
+	"github.com/vmware/govmomi/vim25/soap"
+	vim "github.com/vmware/govmomi/vim25/types"
+)
+
+func TestAgency(t *testing.T) {
+
+	// Create a finder that sets the default datacenter.
+	finder := find.NewFinder(client.vim, true)
+
+	// Get the datacenter to use when creating the agency.
+	datacenter, err := finder.DefaultDatacenter(client.ctx)
+	if err != nil {
+		t.Fatal(err)
+	}
+	finder.SetDatacenter(datacenter)
+
+	// Get the "vm" folder.
+	folder, err := finder.DefaultFolder(client.ctx)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Get the cluster to use when creating the agency.
+	computeResource, err := finder.ClusterComputeResourceOrDefault(client.ctx, "")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Get the resource pool to use when creating the agency.
+	pool, err := computeResource.ResourcePool(client.ctx)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Get the datastore to use when creating the agency.
+	datastore, err := finder.DatastoreOrDefault(client.ctx, "")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Get the network to use when creating the agency.
+	network, err := finder.NetworkOrDefault(client.ctx, "DVS0")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	const (
+		initialGoalState = string(types.EamObjectRuntimeInfoGoalStateEnabled)
+	)
+	var (
+		agency       object.Agency
+		agencyConfig = types.AgencyConfigInfo{
+			AgencyName: t.Name(),
+			AgentName:  t.Name(),
+			AgentConfig: []types.AgentConfigInfo{
+				{
+					HostVersion: "1",
+				},
+			},
+			AgentVmDatastore: []vim.ManagedObjectReference{
+				datastore.Reference(),
+			},
+			Folders: []types.AgencyVMFolder{
+				{
+					FolderId:     folder.Reference(),
+					DatacenterId: datacenter.Reference(),
+				},
+			},
+			ResourcePools: []types.AgencyVMResourcePool{
+				{
+					ResourcePoolId:    pool.Reference(),
+					ComputeResourceId: computeResource.Reference(),
+				},
+			},
+			AgentVmNetwork: []vim.ManagedObjectReference{
+				network.Reference(),
+			},
+		}
+	)
+
+	agencyExists := func(agency object.Agency) (bool, error) {
+		agencies, err := client.eam.Agencies(client.ctx)
+		if err != nil {
+			return false, err
+		}
+		for _, a := range agencies {
+			if a.Reference() == agency.Reference() {
+				return true, nil
+			}
+		}
+		return false, nil
+	}
+
+	testCreate := func(t *testing.T) {
+		var err error
+		if agency, err = client.eam.CreateAgency(
+			client.ctx, agencyConfig, initialGoalState); err != nil {
+			t.Fatal(err)
+		}
+		if ok, err := agencyExists(agency); !ok {
+			if err != nil {
+				t.Fatal(err)
+			}
+			t.Fatal("agency not returned by Agencies")
+		}
+	}
+
+	testConfig := func(t *testing.T) {
+		t.Parallel()
+
+		config, err := agency.Config(client.ctx)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if config.AgencyName != agencyConfig.AgencyName {
+			t.Fatalf(
+				"unexpected agency name: exp=%v, act=%v",
+				agencyConfig.AgencyName,
+				config.AgencyName)
+		}
+		if config.AgentName != agencyConfig.AgentName {
+			t.Fatalf(
+				"unexpected agency agent name: exp=%v, act=%v",
+				agencyConfig.AgentName,
+				config.AgentName)
+		}
+	}
+
+	// This test waits up to 10 seconds for the agency.runtime.issue
+	// list to be non-empty. Because this test is run in parallel with
+	// the TestAgency.Created.Runtime.Issues.Add test, there should be an
+	// issue returned by the tested call before 10 seconds has elapsed.
+	testRuntimeIssues := func(t *testing.T) {
+		t.Parallel()
+		const (
+			waitTotalSecs    = 10
+			waitIntervalSecs = time.Duration(1) * time.Second
+		)
+		hasIssues := false
+		for i := 0; i < waitTotalSecs; i++ {
+			runtime, err := agency.Runtime(client.ctx)
+			if err != nil {
+				t.Fatal(err)
+			}
+			if len(runtime.Issue) > 0 {
+				hasIssues = true
+				break
+			}
+			time.Sleep(waitIntervalSecs)
+		}
+		if !hasIssues {
+			t.Fatalf(
+				"agency.runtime had no issues after %d seconds",
+				waitTotalSecs)
+		}
+	}
+
+	testRuntimeGoalState := func(t *testing.T) {
+		validateExpectedGoalState := func(expGoalState interface{}) error {
+			runtime, err := agency.Runtime(client.ctx)
+			if err != nil {
+				return err
+			}
+			if runtime.GoalState != fmt.Sprintf("%s", expGoalState) {
+				return fmt.Errorf(
+					"unexpected agency goal state: exp=%v, act=%v",
+					expGoalState,
+					runtime.GoalState)
+			}
+			return nil
+		}
+
+		t.Run("Initial", func(t *testing.T) {
+			if err := validateExpectedGoalState(
+				initialGoalState); err != nil {
+				t.Fatal(err)
+			}
+		})
+		t.Run("Disabled", func(t *testing.T) {
+			if err := agency.Disable(client.ctx); err != nil {
+				t.Fatal(err)
+			}
+			if err := validateExpectedGoalState(
+				types.EamObjectRuntimeInfoGoalStateDisabled); err != nil {
+				t.Fatal(err)
+			}
+		})
+		t.Run("Uninstalled", func(t *testing.T) {
+			if err := agency.Uninstall(client.ctx); err != nil {
+				t.Fatal(err)
+			}
+			if err := validateExpectedGoalState(
+				types.EamObjectRuntimeInfoGoalStateUninstalled); err != nil {
+				t.Fatal(err)
+			}
+		})
+		t.Run("Enabled", func(t *testing.T) {
+			if err := agency.Enable(client.ctx); err != nil {
+				t.Fatal(err)
+			}
+			if err := validateExpectedGoalState(
+				types.EamObjectRuntimeInfoGoalStateEnabled); err != nil {
+				t.Fatal(err)
+			}
+		})
+	}
+
+	testRuntime := func(t *testing.T) {
+		t.Parallel()
+
+		runtime, err := agency.Runtime(client.ctx)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if runtime.GoalState != initialGoalState {
+			t.Fatalf(
+				"unexpected agency goal state: exp=%v, act=%v",
+				initialGoalState,
+				runtime.GoalState)
+		}
+
+		t.Run("Issues", testRuntimeIssues)
+		t.Run("GoalState", testRuntimeGoalState)
+	}
+
+	testIssues := func(t *testing.T) {
+		t.Parallel()
+
+		var issueKey int32
+
+		t.Run("Add", func(t *testing.T) {
+			baseIssue, err := agency.AddIssue(client.ctx, &types.OrphanedAgency{
+				AgencyIssue: types.AgencyIssue{
+					Agency:     agency.Reference(),
+					AgencyName: agencyConfig.AgencyName,
+				},
+			})
+			if err != nil {
+				t.Fatal(err)
+			}
+			baseAgencyIssue, ok := baseIssue.(types.BaseAgencyIssue)
+			if !ok {
+				t.Fatalf(
+					"unexpected issue type: exp=%v, act=%T",
+					"types.BaseAgencyIssue",
+					baseIssue)
+			}
+			issue := baseAgencyIssue.GetAgencyIssue()
+			if issue == nil {
+				t.Fatal("returned issue is nil")
+			}
+			if issue.Key == 0 {
+				t.Fatal("issue.Key == 0")
+			}
+			if issue.Time.IsZero() {
+				t.Fatal("issue.Time is not set")
+			}
+			if issue.Agency != agency.Reference() {
+				t.Fatalf(
+					"unexpected agency moRef: exp=%v, act=%v",
+					agency.Reference(),
+					issue.Agency)
+			}
+			if issue.AgencyName != agencyConfig.AgencyName {
+				t.Fatalf(
+					"unexpected agency name: exp=%v, act=%v",
+					agencyConfig.AgencyName,
+					issue.AgencyName)
+			}
+			issueKey = issue.Key
+			t.Logf("added new issue to agency: agency=%v, issueKey=%d",
+				agency.Reference(), issueKey)
+		})
+
+		t.Run("Query", func(t *testing.T) {
+			validateIssueIsInList := func(
+				issues []types.BaseIssue,
+				inErr error) error {
+
+				if inErr != nil {
+					return inErr
+				}
+				if len(issues) == 0 {
+					return errors.New("no issues returned")
+				}
+				foundIssueKey := false
+				for _, baseIssue := range issues {
+					issue := baseIssue.GetIssue()
+					if issue == nil {
+						return errors.New("returned issue is nil")
+					}
+					if issue.Key == issueKey {
+						foundIssueKey = true
+						break
+					}
+				}
+				if !foundIssueKey {
+					return fmt.Errorf(
+						"did not find expected issue: key=%d", issueKey)
+				}
+				return nil
+			}
+
+			t.Run("All", func(t *testing.T) {
+				t.Parallel()
+				if err := validateIssueIsInList(
+					agency.Issues(client.ctx)); err != nil {
+					t.Fatal(err)
+				}
+			})
+			t.Run("ByKey", func(t *testing.T) {
+				t.Parallel()
+				if err := validateIssueIsInList(
+					agency.Issues(client.ctx, issueKey)); err != nil {
+					t.Fatal(err)
+				}
+			})
+		})
+	}
+
+	testAgents := func(t *testing.T) {
+		t.Parallel()
+
+		var agent *object.Agent
+
+		t.Run("Query", func(t *testing.T) {
+			agents, err := agency.Agents(client.ctx)
+			if err != nil {
+				t.Fatal(err)
+			}
+			if len(agents) != 1 {
+				t.Fatal("expected one agent")
+			}
+			agent = &agents[0]
+		})
+
+		t.Run("Queried", func(t *testing.T) {
+			t.Run("Config", func(t *testing.T) {
+				t.Parallel()
+				config, err := agent.Config(client.ctx)
+				if err != nil {
+					t.Fatal(err)
+				}
+				if config.HostVersion != "1" {
+					t.Fatalf(
+						"unexpected agent config host version: exp=%v, act=%v",
+						"1",
+						config.HostVersion)
+				}
+			})
+			t.Run("Runtime", func(t *testing.T) {
+				t.Parallel()
+				var runtime *types.AgentRuntimeInfo
+
+				t.Run("Query", func(t *testing.T) {
+					var err error
+					if runtime, err = agent.Runtime(client.ctx); err != nil {
+						t.Fatal(err)
+					} else if runtime.Agency == nil {
+						t.Fatal("agent runtime.Agency is nil")
+					}
+				})
+				t.Run("Properties", func(t *testing.T) {
+					t.Run("Agency", func(t *testing.T) {
+						t.Parallel()
+						if *runtime.Agency != agency.Reference() {
+							t.Fatalf(
+								"unexpected agent runtime.Agency: exp=%v, act=%v",
+								agency.Reference(),
+								*runtime.Agency)
+						}
+					})
+					t.Run("VirtualMachine", func(t *testing.T) {
+						t.Parallel()
+						if runtime.Vm == nil {
+							t.Fatal("runtime.Vm is nil")
+						}
+					})
+				})
+			})
+		})
+	}
+
+	testDestroy := func(t *testing.T) {
+		t.Run("HappyPath", func(t *testing.T) {
+			if err := agency.Destroy(client.ctx); err != nil {
+				t.Fatal(err)
+			}
+		})
+
+		// Attempt to destroy the agency a second time, asserting that a
+		// ManagedObjectNotFound error will occur.
+		t.Run("NotFound", func(t *testing.T) {
+			if err := agency.Destroy(client.ctx); err == nil {
+				t.Fatal("error did not occur")
+			} else if fault := soap.ToSoapFault(err); fault == nil {
+				t.Fatalf("soap fault did not occur: %+v", err)
+			} else if fault, ok := fault.VimFault().(vim.ManagedObjectNotFound); !ok {
+				t.Fatalf("expected soap fault did not occur: %+v", fault)
+			} else if fault.Obj != agency.Reference() {
+				t.Fatalf("unexpected error details: exp=%v, act=%v",
+					agency.Reference(), fault.Obj)
+			}
+		})
+
+		t.Run("Verify", func(t *testing.T) {
+			if ok, err := agencyExists(agency); err != nil {
+				t.Fatal(err)
+			} else if ok {
+				t.Fatal("agency still returned after being destroyed")
+			}
+		})
+	}
+
+	t.Run("Create", testCreate)
+
+	t.Run("Created", func(t *testing.T) {
+		t.Run("Config", testConfig)
+		t.Run("Issues", testIssues)
+		t.Run("Runtime", testRuntime)
+		t.Run("Agents", testAgents)
+	})
+
+	t.Run("Destroy", testDestroy)
+}
diff --git a/eam/object/object_test.go b/eam/object/object_test.go
new file mode 100644
index 00000000..0316883e
--- /dev/null
+++ b/eam/object/object_test.go
@@ -0,0 +1,76 @@
+/*
+Copyright (c) 2021 VMware, Inc. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package object_test
+
+import (
+	"context"
+	"log"
+	"os"
+	"testing"
+
+	"github.com/vmware/govmomi"
+	"github.com/vmware/govmomi/eam"
+	"github.com/vmware/govmomi/eam/object"
+	"github.com/vmware/govmomi/eam/simulator"
+	vcsim "github.com/vmware/govmomi/simulator"
+	"github.com/vmware/govmomi/vim25"
+)
+
+var (
+	client struct {
+		*eam.Client
+		ctx context.Context
+		eam object.EsxAgentManager
+		vim *vim25.Client
+	}
+)
+
+func TestMain(m *testing.M) {
+	client.ctx = context.Background()
+
+	// Define a new model for vC Sim.
+	model := vcsim.VPX()
+	defer model.Remove()
+
+	// Create the resources from the model.
+	if err := model.Create(); err != nil {
+		log.Fatal(err)
+	}
+
+	// Register the EAM endpoint.
+	model.Service.RegisterSDK(simulator.New())
+
+	// Start the simulator.
+	server := model.Service.NewServer()
+	defer server.Close()
+
+	// Get a vCenter client to the simulator.
+	govmomiClient, err := govmomi.NewClient(client.ctx, server.URL, true)
+	if err != nil {
+		log.Fatal(err)
+	}
+	client.vim = govmomiClient.Client
+
+	// Get an EAM client.
+	client.Client = eam.NewClient(client.vim)
+
+	// Get the EAM root object.
+	client.eam = object.NewEsxAgentManager(client.Client, eam.EsxAgentManager)
+
+	// Run the tests.
+	os.Exit(m.Run())
+}
diff --git a/eam/simulator/simulator_test.go b/eam/simulator/simulator_test.go
new file mode 100644
index 00000000..7232a117
--- /dev/null
+++ b/eam/simulator/simulator_test.go
@@ -0,0 +1,342 @@
+/*
+Copyright (c) 2021 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_test
+
+import (
+	"context"
+	"flag"
+	"fmt"
+	"os"
+	"os/signal"
+	"sync"
+	"testing"
+	"time"
+
+	"github.com/vmware/govmomi/eam"
+	"github.com/vmware/govmomi/eam/object"
+	"github.com/vmware/govmomi/eam/types"
+	"github.com/vmware/govmomi/find"
+	vimobject "github.com/vmware/govmomi/object"
+	vcsim "github.com/vmware/govmomi/simulator"
+	"github.com/vmware/govmomi/vim25"
+	"github.com/vmware/govmomi/vim25/soap"
+	vim "github.com/vmware/govmomi/vim25/types"
+)
+
+var (
+	flagPowerOnVMs = flag.Bool("powerOnVMs", false, "Powers on the VMs in the test with Docker")
+	flagWaitToExit = flag.Bool("waitToExit", false, "Waits for user input to exit the test")
+)
+
+func TestSimulator(t *testing.T) {
+	vcsim.Test(func(ctx context.Context, vimClient *vim25.Client) {
+		// Create a finder that sets the default datacenter.
+		finder := find.NewFinder(vimClient, true)
+
+		// Get the datacenter to use when creating the agency.
+		datacenter, err := finder.DefaultDatacenter(ctx)
+		if err != nil {
+			t.Fatal(err)
+		}
+		finder.SetDatacenter(datacenter)
+
+		// Get the "vm" folder.
+		folder, err := finder.DefaultFolder(ctx)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		// Get the cluster to use when creating the agency.
+		computeResource, err := finder.ClusterComputeResourceOrDefault(ctx, "")
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		// Get the resource pool to use when creating the agency.
+		pool, err := computeResource.ResourcePool(ctx)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		// Get the datastore to use when creating the agency.
+		datastore, err := finder.DatastoreOrDefault(ctx, "")
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		// Get the network to use when creating the agency.
+		network, err := finder.NetworkOrDefault(ctx, "DVS0")
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		// Get an EAM client.
+		eamClient := eam.NewClient(vimClient)
+
+		// Get the EAM root object.
+		mgr := object.NewEsxAgentManager(eamClient, eam.EsxAgentManager)
+
+		// Define a function that will list and print the agency MoRefs.
+		listAgencies := func() int {
+			t.Log("listing agencies")
+			agencies, err := mgr.Agencies(ctx)
+			if err != nil {
+				t.Fatal(err)
+			}
+			if len(agencies) == 0 {
+				t.Log("no agencies")
+				return 0
+			}
+			for _, obj := range agencies {
+				t.Logf("agency: %v", obj.Reference())
+				config, err := obj.Config(ctx)
+				if err != nil {
+					t.Fatal(err)
+				}
+				t.Logf("agency config: %+v", config)
+				runtime, err := obj.Runtime(ctx)
+				if err != nil {
+					t.Fatal(err)
+				}
+				t.Logf("agency runtime: %+v", runtime)
+
+				agents, err := obj.Agents(ctx)
+				if err != nil {
+					t.Fatal(err)
+				}
+				if len(agents) == 0 {
+					t.Log("no agents")
+				} else {
+					for _, a := range agents {
+						t.Logf("agent: %v", a.Reference())
+						config, err := a.Config(ctx)
+						if err != nil {
+							t.Fatal(err)
+						}
+						t.Logf("agent config: %+v", config)
+						runtime, err := a.Runtime(ctx)
+						if err != nil {
+							t.Fatal(err)
+						}
+						t.Logf("agent runtime: %+v", runtime)
+					}
+				}
+			}
+			return len(agencies)
+		}
+
+		// List and print the agency MoRefs. There are none.
+		if listAgencies() > 0 {
+			t.Fatal("no agencies expected")
+		}
+
+		// Create a new agency.
+		t.Log("creating a new agency")
+		agency, err := mgr.CreateAgency(
+			ctx,
+			types.AgencyConfigInfo{
+				AgencyName: "nginx",
+				AgentVmDatastore: []vim.ManagedObjectReference{
+					datastore.Reference(),
+				},
+				Folders: []types.AgencyVMFolder{
+					{
+						FolderId:     folder.Reference(),
+						DatacenterId: datacenter.Reference(),
+					},
+				},
+				ResourcePools: []types.AgencyVMResourcePool{
+					{
+						ResourcePoolId:    pool.Reference(),
+						ComputeResourceId: computeResource.Reference(),
+					},
+				},
+				AgentVmNetwork: []vim.ManagedObjectReference{
+					network.Reference(),
+				},
+				AgentConfig: []types.AgentConfigInfo{
+					{
+						OvfPackageUrl: "nginx",
+					},
+					{
+						OvfPackageUrl: "nginx",
+					},
+				},
+			},
+			string(types.EamObjectRuntimeInfoGoalStateEnabled),
+		)
+		if err != nil {
+			if soap.IsSoapFault(err) {
+				fault := soap.ToSoapFault(err).VimFault()
+				t.Fatalf("%[1]T %[1]v", fault)
+			} else {
+				t.Fatalf("%[1]T %[1]v", err)
+			}
+		}
+		t.Logf("created agency: %v", agency.Reference())
+
+		// List the agencies again, and this time the newly created agency will be
+		// printed to the console.
+		if listAgencies() != 1 {
+			t.Fatal("one agency expected")
+		}
+
+		// Check whether or not we want to power on the VMs with Docker.
+		if *flagPowerOnVMs {
+			agencies, err := mgr.Agencies(ctx)
+			if err != nil {
+				t.Fatal(err)
+			}
+			if len(agencies) == 0 {
+				t.Fatal("no agencies")
+			}
+			agency := agencies[0]
+
+			// Wait for the agent VMs to have IP addresses
+			{
+				agents, err := agency.Agents(ctx)
+				if err != nil {
+					t.Fatal(err)
+				}
+				if len(agents) == 0 {
+					t.Fatal("no agents")
+				}
+
+				wait := make(chan struct{})
+				done := make(chan struct{})
+				errs := make(chan error)
+				msgs := make(chan string)
+				var wg sync.WaitGroup
+				wg.Add(len(agents))
+
+				for _, agent := range agents {
+					agent := agent
+					go func() {
+						var (
+							vmPowerState string
+							vmIp         string
+							once         sync.Once
+							vmon         = map[vim.ManagedObjectReference]struct{}{}
+						)
+						for {
+							runtime, err := agent.Runtime(ctx)
+							if err != nil {
+								errs <- err
+								return
+							}
+							if runtime.Vm == nil {
+								errs <- fmt.Errorf("vm is nil for agent %s", agent.Reference())
+								return
+							}
+							if _, ok := vmon[*runtime.Vm]; !ok {
+								vm := vimobject.NewVirtualMachine(vimClient, *runtime.Vm)
+								if _, err := vm.PowerOn(ctx); err != nil {
+									errs <- err
+									return
+								}
+								vmon[*runtime.Vm] = struct{}{}
+							}
+
+							if vmIp != runtime.VmIp || vmPowerState != string(runtime.VmPowerState) {
+								vmIp = runtime.VmIp
+								vmPowerState = string(runtime.VmPowerState)
+								msgs <- fmt.Sprintf(
+									"%v: name=%s, powerState=%s, ipAddr=%s",
+									*runtime.Vm,
+									runtime.VmName,
+									vmPowerState,
+									vmIp)
+							}
+							if vmIp != "" {
+								once.Do(func() {
+									wg.Done()
+								})
+							}
+							select {
+							case <-time.After(1 * time.Second):
+							case <-done:
+								return
+							}
+						}
+					}()
+				}
+
+				go func() {
+					wg.Wait()
+					if *flagWaitToExit {
+						<-wait
+					}
+					close(done)
+				}()
+
+				go func() {
+					defer close(wait)
+					if !*flagWaitToExit {
+						return
+					}
+					t.Log(waitLoopMessage)
+					c := make(chan os.Signal, 1)
+					signal.Notify(c, os.Interrupt)
+					for {
+						select {
+						case <-time.After(1 * time.Second):
+						case <-c:
+							return
+						}
+					}
+				}()
+
+				t.Log("waiting for the agent VMs to power on and get IP addresses")
+				timeout := time.After(10 * time.Minute)
+				func() {
+					for {
+						select {
+						case msg := <-msgs:
+							t.Log(msg)
+						case err := <-errs:
+							t.Fatal(err)
+						case <-done:
+							return
+						case <-timeout:
+							t.Fatal("timed out waiting for agent VMs to power on and get IP addresses")
+							return
+						}
+					}
+				}()
+			}
+		}
+
+		// Destroy the agency.
+		t.Log("destroying agency")
+		if err := agency.Destroy(ctx); err != nil {
+			t.Fatal(err)
+		}
+
+		if listAgencies() != 0 {
+			t.Fatal("no agencies expected")
+		}
+	})
+}
+
+const waitLoopMessage = `
+
+################################################################################
+# When executed with the flags -powerOnVMs and -waitForExit, this test will    #
+# pause here and update the screen with the status of the agent VMs until      #
+# SIGINT is sent to this process.                                              #
+################################################################################
+`
diff --git a/govc/test/README.md b/govc/test/README.md
index 5a4ef346..da486386 100644
--- a/govc/test/README.md
+++ b/govc/test/README.md
@@ -1,115 +1,59 @@
-# Functional Tests for govc
+# Functional tests for govc
 
-The govc tests use [bats](https://github.com/sstephenson/bats/), a framework that provides a simple way to verify *NIX programs behave as expected.
+The govc tests use [bats](https://github.com/sstephenson/bats/)
 
-## Enabling ESX Tests
+## Download test images
 
-Some of the govc tests require an ESX instance. These tests may be enabled with any ESX host with the following environment variable:
+Some tests depend on ttylinux images, these can be downloaded by running:
 
 ```
-GOVC_TEST_URL=user:pass@<ESX_HOST>
+./images/update.sh
 ```
 
-## Running Tests
+These images are uploaded to the `$GOVC_TEST_URL` as needed by tests and can be
+removed with the following command:
 
-There are two ways to run the tests locally:
-
-1. [_Via GitHub Actions in Docker_](#run-tests-via-github-actions-in-docker) - mimics how GitHub actions will execute the tests
-2. [_Natively on Linux and macOS_](#run-tests-natively-on-linux-and-macos) - the fastest way to run the tests
-
-### Run Tests via GitHub Actions in Docker
-
-This method of running the govc functional tests mimics how the project's associated GitHub actions will execute the tests when new pull requests are opened:
-
-1. Install [`act`](https://github.com/nektos/act):
-
-    * Linux (curl bash)
-
-        ```shell
-        curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash
-        ```
-
-    * macOS
-
-        ```shell
-        brew install act
-        ```
-
-    * [_Documentation for other installation methods_](https://github.com/nektos/act#installation)
-
-2. Run the `govc-tests` action:
-
-    ```shell
-    act --env USER=user -j govc-tests
-    ```
-
-    ---
-
-    **Note**: To run the ESX tests with `act`, execute the following command:
-
-    ```shell
-    act --env USER=user --env GOVC_TEST_URL="user:pass@<ESX_HOST>" -j govc-tests
-    ```
-
-    ---
-
-### Run Tests Natively on Linux and macOS
-
-The fastest way to run the tests is to do so natively on Linux or macOS:
-
-1. Install [bats](https://github.com/sstephenson/bats/):
-
-    * Debian / Ubuntu Linux
-
-        ```shell
-        apt-get install bats
-        ```
-
-    * macOS
-
-        ```shell
-        brew install bats
-        ```
-
-    * [_Installing bats from source_](https://github.com/sstephenson/bats#installing-bats-from-source)
+```
+./clean.sh
+```
 
+## GOVC_TEST_URL
 
-2. Some tests depend on the `ttylinux` images, and they can be downloaded with the following command:
+Some of the govc tests need an ESX instance to run against.  Any ESX box can be used by exporting the following variable:
 
-    ```shell
-    ./govc/test/images/update.sh
-    ```
+```
+export GOVC_TEST_URL=user:pass@hostname
+```
 
-    The images are uploaded to the `$GOVC_TEST_URL` as needed by tests and can be removed with the following command:
+## Running tests
 
-    ```shell
-    ./govc/test/images/clean.sh
-    ```
+Tests can be run using the top-level Makefile:
 
----
+```
+make govc-test
+```
 
-**Note**: Users of macOS will want to install `gxargs`, `greadlink`, and `gmktemp` with the following command:
+Or the following command:
 
-```shell
-brew install coreutils findutils
+```
+bats .
 ```
 
----
+Or individually, for example:
 
-3. The easiest way to run the tests is with the top-level Makefile:
+```
+./cli.bats
+```
 
-    ```shell
-    make govc-test
-    ```
+Note that the test helper prepends `$GOPATH/bin` to `PATH` as the tests depend on both the *govc* and *vcsim* binaries.
 
-    The tests can also be run directly with the `bats` command:
+## Platform specific notes
 
-    ```shell
-    bats -t ./govc/test/
-    ```
+### Darwin (MacOSX)
 
-    Finally, it's also possible to run the tests individually with:
+Install gxargs, greadlink and gmktemp on Darwin
 
-    ```shell
-    ./govc/test/cli.bats
-    ```
+```
+brew install coreutils
+brew install findutils
+```
diff --git a/govc/test/sso.bats b/govc/test/sso.bats
index ff67ddb1..dd19ed8f 100755
--- a/govc/test/sso.bats
+++ b/govc/test/sso.bats
@@ -3,10 +3,6 @@
 load test_helper
 
 @test "sso.service.ls" {
-  if [ ! "${SSO_BATS}" = "1" ]; then
-    skip "skip sso.service.ls by default"
-  fi
-
   vcsim_env
 
   sts=$(govc option.ls config.vpxd.sso.sts.uri | awk '{print $2}')
@@ -34,15 +30,13 @@ load test_helper
   run govc sso.service.ls -t sso:sts -U
   assert_success "$sts"
 
-  if [ "${SSO_BATS_ASSERT_CERT}" = "1" ]; then
-    cert=$(govc about.cert -show | grep -v CERTIFICATE | tr -d '\n')
-    trust=$(govc sso.service.ls -json -t sso:sts | jq -r .[].ServiceEndpoints[].SslTrust[0])
-    assert_equal "$cert" "$trust"
-  fi
+  cert=$(govc about.cert -show | grep -v CERTIFICATE | tr -d '\n')
+  trust=$(govc sso.service.ls -json -t sso:sts | jq -r .[].ServiceEndpoints[].SslTrust[0])
+  assert_equal "$cert" "$trust"
 
   govc sso.service.ls -t cs.identity | grep com.vmware.cis | grep -v https:
   govc sso.service.ls -t cs.identity -l | grep https:
   govc sso.service.ls -p com.vmware.cis -t cs.identity -P wsTrust -T com.vmware.cis.cs.identity.sso -l | grep wsTrust
   govc sso.service.ls -P vmomi | grep vcenterserver | grep -v https:
   govc sso.service.ls -P vmomi -l | grep https:
-}
\ No newline at end of file
+}
diff --git a/govc/test/vcsim.bats b/govc/test/vcsim.bats
index 879c1cc8..1f2ea270 100755
--- a/govc/test/vcsim.bats
+++ b/govc/test/vcsim.bats
@@ -48,8 +48,6 @@ EOF
   run curl -skf "$url/about"
   assert_matches "CurrentTime" # 1 param (without Context)
   assert_matches "TerminateSession" # 2 params (with Context)
-  assert_matches "CnsAttachVolume" # method from namespace vsan
-  assert_matches "PbmCreate" # method from namespace pbm
 
   run curl -skf "$url/debug/vars"
   assert_success
@@ -144,7 +142,7 @@ EOF
   run govc vm.info -vm.dns localhost.localdomain
   assert_success
 
-  uuid=$(vcsim uuidgen)
+  uuid=$(uuidgen)
   run govc vm.change -vm $vm -e SET.config.uuid="$uuid"
   assert_success
 
diff --git a/govc/test/vm.bats b/govc/test/vm.bats
index d48b666b..034b95bc 100755
--- a/govc/test/vm.bats
+++ b/govc/test/vm.bats
@@ -134,7 +134,7 @@ load test_helper
   run govc object.collect -s "vm/$id" config.annotation
   assert_success $$
 
-  uuid=$(vcsim uuidgen)
+  uuid=$(uuidgen)
   run govc vm.change -vm $id -uuid "$uuid"
   assert_success
   run govc object.collect -s "vm/$id" config.uuid
diff --git a/simulator/virtual_machine_test.go b/simulator/virtual_machine_test.go
index 1f7b4cb4..2055c912 100644
--- a/simulator/virtual_machine_test.go
+++ b/simulator/virtual_machine_test.go
@@ -374,11 +374,6 @@ func TestReconfigVmDevice(t *testing.T) {
 			t.Error(err)
 		}
 
-		d.GetVirtualDevice().DeviceInfo = nil
-		if err = vm.EditDevice(ctx, d); err != nil {
-			t.Error(err)
-		}
-
 		// RemoveDevice and delete the file backing
 		if err = vm.RemoveDevice(ctx, false, d); err != nil {
 			t.Error(err)