VMware vSphere Integrated Containers provider (#206)
* Add Virtual Kubelet provider for VIC Initial virtual kubelet provider for VMware VIC. This provider currently handles creating and starting of a pod VM via the VIC portlayer and persona server. Image store handling via the VIC persona server. This provider currently requires the feature/wolfpack branch of VIC. * Added pod stop and delete. Also added node capacity. Added the ability to stop and delete pod VMs via VIC. Also retrieve node capacity information from the VCH. * Cleanup and readme file Some file clean up and added a Readme.md markdown file for the VIC provider. * Cleaned up errors, added function comments, moved operation code 1. Cleaned up error handling. Set standard for creating errors. 2. Added method prototype comments for all interface functions. 3. Moved PodCreator, PodStarter, PodStopper, and PodDeleter to a new folder. * Add mocking code and unit tests for podcache, podcreator, and podstarter Used the unit test framework used in VIC to handle assertions in the provider's unit test. Mocking code generated using OSS project mockery, which is compatible with the testify assertion framework. * Vendored packages for the VIC provider Requires feature/wolfpack branch of VIC and a few specific commit sha of projects used within VIC. * Implementation of POD Stopper and Deleter unit tests (#4) * Updated files for initial PR
This commit is contained in:
258
vendor/github.com/vmware/govmomi/simulator/authorization_manager.go
generated
vendored
Normal file
258
vendor/github.com/vmware/govmomi/simulator/authorization_manager.go
generated
vendored
Normal file
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type AuthorizationManager struct {
|
||||
mo.AuthorizationManager
|
||||
|
||||
permissions map[types.ManagedObjectReference][]types.Permission
|
||||
privileges map[string]struct{}
|
||||
system []string
|
||||
nextID int32
|
||||
}
|
||||
|
||||
func NewAuthorizationManager(ref types.ManagedObjectReference) object.Reference {
|
||||
m := &AuthorizationManager{}
|
||||
m.Self = ref
|
||||
m.RoleList = make([]types.AuthorizationRole, len(esx.RoleList))
|
||||
copy(m.RoleList, esx.RoleList)
|
||||
m.permissions = make(map[types.ManagedObjectReference][]types.Permission)
|
||||
|
||||
l := object.AuthorizationRoleList(m.RoleList)
|
||||
m.system = l.ByName("ReadOnly").Privilege
|
||||
admin := l.ByName("Admin")
|
||||
m.privileges = make(map[string]struct{}, len(admin.Privilege))
|
||||
|
||||
for _, id := range admin.Privilege {
|
||||
m.privileges[id] = struct{}{}
|
||||
}
|
||||
|
||||
root := Map.content().RootFolder
|
||||
|
||||
for _, u := range DefaultUserGroup {
|
||||
m.permissions[root] = append(m.permissions[root], types.Permission{
|
||||
Entity: &root,
|
||||
Principal: u.Principal,
|
||||
Group: u.Group,
|
||||
RoleId: admin.RoleId,
|
||||
Propagate: true,
|
||||
})
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *AuthorizationManager) RetrieveEntityPermissions(req *types.RetrieveEntityPermissions) soap.HasFault {
|
||||
e := Map.Get(req.Entity).(mo.Entity)
|
||||
|
||||
p := m.permissions[e.Reference()]
|
||||
|
||||
if req.Inherited {
|
||||
for {
|
||||
parent := e.Entity().Parent
|
||||
if parent == nil {
|
||||
break
|
||||
}
|
||||
|
||||
e = Map.Get(parent.Reference()).(mo.Entity)
|
||||
|
||||
p = append(p, m.permissions[e.Reference()]...)
|
||||
}
|
||||
}
|
||||
|
||||
return &methods.RetrieveEntityPermissionsBody{
|
||||
Res: &types.RetrieveEntityPermissionsResponse{
|
||||
Returnval: p,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *AuthorizationManager) RetrieveAllPermissions(req *types.RetrieveAllPermissions) soap.HasFault {
|
||||
var p []types.Permission
|
||||
|
||||
for _, v := range m.permissions {
|
||||
p = append(p, v...)
|
||||
}
|
||||
|
||||
return &methods.RetrieveAllPermissionsBody{
|
||||
Res: &types.RetrieveAllPermissionsResponse{
|
||||
Returnval: p,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *AuthorizationManager) RemoveEntityPermission(req *types.RemoveEntityPermission) soap.HasFault {
|
||||
var p []types.Permission
|
||||
|
||||
for _, v := range m.permissions[req.Entity] {
|
||||
if v.Group == req.IsGroup && v.Principal == req.User {
|
||||
continue
|
||||
}
|
||||
p = append(p, v)
|
||||
}
|
||||
|
||||
m.permissions[req.Entity] = p
|
||||
|
||||
return &methods.RemoveEntityPermissionBody{
|
||||
Res: &types.RemoveEntityPermissionResponse{},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *AuthorizationManager) SetEntityPermissions(req *types.SetEntityPermissions) soap.HasFault {
|
||||
m.permissions[req.Entity] = req.Permission
|
||||
|
||||
return &methods.SetEntityPermissionsBody{
|
||||
Res: &types.SetEntityPermissionsResponse{},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *AuthorizationManager) RetrieveRolePermissions(req *types.RetrieveRolePermissions) soap.HasFault {
|
||||
var p []types.Permission
|
||||
|
||||
for _, set := range m.permissions {
|
||||
for _, v := range set {
|
||||
if v.RoleId == req.RoleId {
|
||||
p = append(p, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &methods.RetrieveRolePermissionsBody{
|
||||
Res: &types.RetrieveRolePermissionsResponse{
|
||||
Returnval: p,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *AuthorizationManager) AddAuthorizationRole(req *types.AddAuthorizationRole) soap.HasFault {
|
||||
body := &methods.AddAuthorizationRoleBody{}
|
||||
|
||||
for _, role := range m.RoleList {
|
||||
if role.Name == req.Name {
|
||||
body.Fault_ = Fault("", &types.AlreadyExists{})
|
||||
return body
|
||||
}
|
||||
}
|
||||
|
||||
ids, err := m.privIDs(req.PrivIds)
|
||||
if err != nil {
|
||||
body.Fault_ = err
|
||||
return body
|
||||
}
|
||||
|
||||
m.RoleList = append(m.RoleList, types.AuthorizationRole{
|
||||
Info: &types.Description{
|
||||
Label: req.Name,
|
||||
Summary: req.Name,
|
||||
},
|
||||
RoleId: m.nextID,
|
||||
Privilege: ids,
|
||||
Name: req.Name,
|
||||
System: false,
|
||||
})
|
||||
|
||||
m.nextID++
|
||||
|
||||
body.Res = &types.AddAuthorizationRoleResponse{}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (m *AuthorizationManager) UpdateAuthorizationRole(req *types.UpdateAuthorizationRole) soap.HasFault {
|
||||
body := &methods.UpdateAuthorizationRoleBody{}
|
||||
|
||||
for _, role := range m.RoleList {
|
||||
if role.Name == req.NewName && role.RoleId != req.RoleId {
|
||||
body.Fault_ = Fault("", &types.AlreadyExists{})
|
||||
return body
|
||||
}
|
||||
}
|
||||
|
||||
for i, role := range m.RoleList {
|
||||
if role.RoleId == req.RoleId {
|
||||
if len(req.PrivIds) != 0 {
|
||||
ids, err := m.privIDs(req.PrivIds)
|
||||
if err != nil {
|
||||
body.Fault_ = err
|
||||
return body
|
||||
}
|
||||
m.RoleList[i].Privilege = ids
|
||||
}
|
||||
|
||||
m.RoleList[i].Name = req.NewName
|
||||
|
||||
body.Res = &types.UpdateAuthorizationRoleResponse{}
|
||||
return body
|
||||
}
|
||||
}
|
||||
|
||||
body.Fault_ = Fault("", &types.NotFound{})
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (m *AuthorizationManager) RemoveAuthorizationRole(req *types.RemoveAuthorizationRole) soap.HasFault {
|
||||
body := &methods.RemoveAuthorizationRoleBody{}
|
||||
|
||||
for i, role := range m.RoleList {
|
||||
if role.RoleId == req.RoleId {
|
||||
m.RoleList = append(m.RoleList[:i], m.RoleList[i+1:]...)
|
||||
|
||||
body.Res = &types.RemoveAuthorizationRoleResponse{}
|
||||
return body
|
||||
}
|
||||
}
|
||||
|
||||
body.Fault_ = Fault("", &types.NotFound{})
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (m *AuthorizationManager) privIDs(ids []string) ([]string, *soap.Fault) {
|
||||
system := make(map[string]struct{}, len(m.system))
|
||||
|
||||
for _, id := range ids {
|
||||
if _, ok := m.privileges[id]; !ok {
|
||||
return nil, Fault("", &types.InvalidArgument{InvalidProperty: "privIds"})
|
||||
}
|
||||
|
||||
if strings.HasPrefix(id, "System.") {
|
||||
system[id] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
for _, id := range m.system {
|
||||
if _, ok := system[id]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
ids = append(ids, id)
|
||||
}
|
||||
|
||||
return ids, nil
|
||||
}
|
||||
37
vendor/github.com/vmware/govmomi/simulator/authorization_manager_test.go
generated
vendored
Normal file
37
vendor/github.com/vmware/govmomi/simulator/authorization_manager_test.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi/simulator/vpx"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestAuthorizationManager(t *testing.T) {
|
||||
for i := 0; i < 2; i++ {
|
||||
model := VPX()
|
||||
|
||||
_ = New(NewServiceInstance(model.ServiceContent, model.RootFolder)) // 2nd pass panics w/o copying RoleList
|
||||
|
||||
authz := Map.Get(*vpx.ServiceContent.AuthorizationManager).(*AuthorizationManager)
|
||||
authz.RemoveAuthorizationRole(&types.RemoveAuthorizationRole{
|
||||
RoleId: -2, // ReadOnly
|
||||
})
|
||||
}
|
||||
}
|
||||
322
vendor/github.com/vmware/govmomi/simulator/cluster_compute_resource.go
generated
vendored
Normal file
322
vendor/github.com/vmware/govmomi/simulator/cluster_compute_resource.go
generated
vendored
Normal file
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type ClusterComputeResource struct {
|
||||
mo.ClusterComputeResource
|
||||
|
||||
ruleKey int32
|
||||
}
|
||||
|
||||
type addHost struct {
|
||||
*ClusterComputeResource
|
||||
|
||||
req *types.AddHost_Task
|
||||
}
|
||||
|
||||
func (add *addHost) Run(task *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
spec := add.req.Spec
|
||||
|
||||
if spec.HostName == "" {
|
||||
return nil, &types.NoHost{}
|
||||
}
|
||||
|
||||
host := NewHostSystem(esx.HostSystem)
|
||||
host.Summary.Config.Name = spec.HostName
|
||||
host.Name = host.Summary.Config.Name
|
||||
if add.req.AsConnected {
|
||||
host.Runtime.ConnectionState = types.HostSystemConnectionStateConnected
|
||||
} else {
|
||||
host.Runtime.ConnectionState = types.HostSystemConnectionStateDisconnected
|
||||
}
|
||||
|
||||
cr := add.ClusterComputeResource
|
||||
Map.PutEntity(cr, Map.NewEntity(host))
|
||||
host.Summary.Host = &host.Self
|
||||
|
||||
cr.Host = append(cr.Host, host.Reference())
|
||||
addComputeResource(cr.Summary.GetComputeResourceSummary(), host)
|
||||
|
||||
return host.Reference(), nil
|
||||
}
|
||||
|
||||
func (c *ClusterComputeResource) AddHostTask(add *types.AddHost_Task) soap.HasFault {
|
||||
return &methods.AddHost_TaskBody{
|
||||
Res: &types.AddHost_TaskResponse{
|
||||
Returnval: NewTask(&addHost{c, add}).Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ClusterComputeResource) updateRules(cfg *types.ClusterConfigInfoEx, cspec *types.ClusterConfigSpecEx) types.BaseMethodFault {
|
||||
for _, spec := range cspec.RulesSpec {
|
||||
var i int
|
||||
exists := false
|
||||
|
||||
match := func(info types.BaseClusterRuleInfo) bool {
|
||||
return info.GetClusterRuleInfo().Name == spec.Info.GetClusterRuleInfo().Name
|
||||
}
|
||||
|
||||
if spec.Operation == types.ArrayUpdateOperationRemove {
|
||||
match = func(rule types.BaseClusterRuleInfo) bool {
|
||||
return rule.GetClusterRuleInfo().Key == spec.ArrayUpdateSpec.RemoveKey.(int32)
|
||||
}
|
||||
}
|
||||
|
||||
for i = range cfg.Rule {
|
||||
if match(cfg.Rule[i].GetClusterRuleInfo()) {
|
||||
exists = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
switch spec.Operation {
|
||||
case types.ArrayUpdateOperationAdd:
|
||||
if exists {
|
||||
return new(types.InvalidArgument)
|
||||
}
|
||||
info := spec.Info.GetClusterRuleInfo()
|
||||
info.Key = atomic.AddInt32(&c.ruleKey, 1)
|
||||
info.RuleUuid = uuid.New().String()
|
||||
cfg.Rule = append(cfg.Rule, spec.Info)
|
||||
case types.ArrayUpdateOperationEdit:
|
||||
if !exists {
|
||||
return new(types.InvalidArgument)
|
||||
}
|
||||
cfg.Rule[i] = spec.Info
|
||||
case types.ArrayUpdateOperationRemove:
|
||||
if !exists {
|
||||
return new(types.InvalidArgument)
|
||||
}
|
||||
cfg.Rule = append(cfg.Rule[:i], cfg.Rule[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClusterComputeResource) updateGroups(cfg *types.ClusterConfigInfoEx, cspec *types.ClusterConfigSpecEx) types.BaseMethodFault {
|
||||
for _, spec := range cspec.GroupSpec {
|
||||
var i int
|
||||
exists := false
|
||||
|
||||
match := func(info types.BaseClusterGroupInfo) bool {
|
||||
return info.GetClusterGroupInfo().Name == spec.Info.GetClusterGroupInfo().Name
|
||||
}
|
||||
|
||||
if spec.Operation == types.ArrayUpdateOperationRemove {
|
||||
match = func(info types.BaseClusterGroupInfo) bool {
|
||||
return info.GetClusterGroupInfo().Name == spec.ArrayUpdateSpec.RemoveKey.(string)
|
||||
}
|
||||
}
|
||||
|
||||
for i = range cfg.Group {
|
||||
if match(cfg.Group[i].GetClusterGroupInfo()) {
|
||||
exists = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
switch spec.Operation {
|
||||
case types.ArrayUpdateOperationAdd:
|
||||
if exists {
|
||||
return new(types.InvalidArgument)
|
||||
}
|
||||
cfg.Group = append(cfg.Group, spec.Info)
|
||||
case types.ArrayUpdateOperationEdit:
|
||||
if !exists {
|
||||
return new(types.InvalidArgument)
|
||||
}
|
||||
cfg.Group[i] = spec.Info
|
||||
case types.ArrayUpdateOperationRemove:
|
||||
if !exists {
|
||||
return new(types.InvalidArgument)
|
||||
}
|
||||
cfg.Group = append(cfg.Group[:i], cfg.Group[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClusterComputeResource) updateOverridesDAS(cfg *types.ClusterConfigInfoEx, cspec *types.ClusterConfigSpecEx) types.BaseMethodFault {
|
||||
for _, spec := range cspec.DasVmConfigSpec {
|
||||
var i int
|
||||
var key types.ManagedObjectReference
|
||||
exists := false
|
||||
|
||||
if spec.Operation == types.ArrayUpdateOperationRemove {
|
||||
key = spec.RemoveKey.(types.ManagedObjectReference)
|
||||
} else {
|
||||
key = spec.Info.Key
|
||||
}
|
||||
|
||||
for i = range cfg.DasVmConfig {
|
||||
if cfg.DasVmConfig[i].Key == key {
|
||||
exists = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
switch spec.Operation {
|
||||
case types.ArrayUpdateOperationAdd:
|
||||
if exists {
|
||||
return new(types.InvalidArgument)
|
||||
}
|
||||
cfg.DasVmConfig = append(cfg.DasVmConfig, *spec.Info)
|
||||
case types.ArrayUpdateOperationEdit:
|
||||
if !exists {
|
||||
return new(types.InvalidArgument)
|
||||
}
|
||||
src := spec.Info.DasSettings
|
||||
if src == nil {
|
||||
return new(types.InvalidArgument)
|
||||
}
|
||||
dst := cfg.DasVmConfig[i].DasSettings
|
||||
if src.RestartPriority != "" {
|
||||
dst.RestartPriority = src.RestartPriority
|
||||
}
|
||||
if src.RestartPriorityTimeout != 0 {
|
||||
dst.RestartPriorityTimeout = src.RestartPriorityTimeout
|
||||
}
|
||||
case types.ArrayUpdateOperationRemove:
|
||||
if !exists {
|
||||
return new(types.InvalidArgument)
|
||||
}
|
||||
cfg.DasVmConfig = append(cfg.DasVmConfig[:i], cfg.DasVmConfig[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClusterComputeResource) updateOverridesDRS(cfg *types.ClusterConfigInfoEx, cspec *types.ClusterConfigSpecEx) types.BaseMethodFault {
|
||||
for _, spec := range cspec.DrsVmConfigSpec {
|
||||
var i int
|
||||
var key types.ManagedObjectReference
|
||||
exists := false
|
||||
|
||||
if spec.Operation == types.ArrayUpdateOperationRemove {
|
||||
key = spec.RemoveKey.(types.ManagedObjectReference)
|
||||
} else {
|
||||
key = spec.Info.Key
|
||||
}
|
||||
|
||||
for i = range cfg.DrsVmConfig {
|
||||
if cfg.DrsVmConfig[i].Key == key {
|
||||
exists = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
switch spec.Operation {
|
||||
case types.ArrayUpdateOperationAdd:
|
||||
if exists {
|
||||
return new(types.InvalidArgument)
|
||||
}
|
||||
cfg.DrsVmConfig = append(cfg.DrsVmConfig, *spec.Info)
|
||||
case types.ArrayUpdateOperationEdit:
|
||||
if !exists {
|
||||
return new(types.InvalidArgument)
|
||||
}
|
||||
if spec.Info.Enabled != nil {
|
||||
cfg.DrsVmConfig[i].Enabled = spec.Info.Enabled
|
||||
}
|
||||
if spec.Info.Behavior != "" {
|
||||
cfg.DrsVmConfig[i].Behavior = spec.Info.Behavior
|
||||
}
|
||||
case types.ArrayUpdateOperationRemove:
|
||||
if !exists {
|
||||
return new(types.InvalidArgument)
|
||||
}
|
||||
cfg.DrsVmConfig = append(cfg.DrsVmConfig[:i], cfg.DrsVmConfig[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClusterComputeResource) ReconfigureComputeResourceTask(req *types.ReconfigureComputeResource_Task) soap.HasFault {
|
||||
task := CreateTask(c, "reconfigureCluster", func(*Task) (types.AnyType, types.BaseMethodFault) {
|
||||
spec, ok := req.Spec.(*types.ClusterConfigSpecEx)
|
||||
if !ok {
|
||||
return nil, new(types.InvalidArgument)
|
||||
}
|
||||
|
||||
updates := []func(*types.ClusterConfigInfoEx, *types.ClusterConfigSpecEx) types.BaseMethodFault{
|
||||
c.updateRules,
|
||||
c.updateGroups,
|
||||
c.updateOverridesDAS,
|
||||
c.updateOverridesDRS,
|
||||
}
|
||||
|
||||
for _, update := range updates {
|
||||
if err := update(c.ConfigurationEx.(*types.ClusterConfigInfoEx), spec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.ReconfigureComputeResource_TaskBody{
|
||||
Res: &types.ReconfigureComputeResource_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func CreateClusterComputeResource(f *Folder, name string, spec types.ClusterConfigSpecEx) (*ClusterComputeResource, types.BaseMethodFault) {
|
||||
if e := Map.FindByName(name, f.ChildEntity); e != nil {
|
||||
return nil, &types.DuplicateName{
|
||||
Name: e.Entity().Name,
|
||||
Object: e.Reference(),
|
||||
}
|
||||
}
|
||||
|
||||
cluster := &ClusterComputeResource{}
|
||||
cluster.Name = name
|
||||
cluster.Summary = &types.ClusterComputeResourceSummary{
|
||||
UsageSummary: new(types.ClusterUsageSummary),
|
||||
}
|
||||
|
||||
config := &types.ClusterConfigInfoEx{}
|
||||
cluster.ConfigurationEx = config
|
||||
|
||||
config.VmSwapPlacement = string(types.VirtualMachineConfigInfoSwapPlacementTypeVmDirectory)
|
||||
config.DrsConfig.Enabled = types.NewBool(true)
|
||||
|
||||
pool := NewResourcePool()
|
||||
Map.PutEntity(cluster, Map.NewEntity(pool))
|
||||
cluster.ResourcePool = &pool.Self
|
||||
|
||||
f.putChild(cluster)
|
||||
pool.Owner = cluster.Self
|
||||
|
||||
return cluster, nil
|
||||
}
|
||||
112
vendor/github.com/vmware/govmomi/simulator/cluster_compute_resource_test.go
generated
vendored
Normal file
112
vendor/github.com/vmware/govmomi/simulator/cluster_compute_resource_test.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/simulator/vpx"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestClusterESX(t *testing.T) {
|
||||
content := esx.ServiceContent
|
||||
s := New(NewServiceInstance(content, esx.RootFolder))
|
||||
|
||||
ts := s.NewServer()
|
||||
defer ts.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
c, err := govmomi.NewClient(ctx, ts.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dc := object.NewDatacenter(c.Client, esx.Datacenter.Reference())
|
||||
|
||||
folders, err := dc.Folders(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = folders.HostFolder.CreateCluster(ctx, "cluster1", types.ClusterConfigSpecEx{})
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClusterVC(t *testing.T) {
|
||||
content := vpx.ServiceContent
|
||||
s := New(NewServiceInstance(content, vpx.RootFolder))
|
||||
|
||||
ts := s.NewServer()
|
||||
defer ts.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
c, err := govmomi.NewClient(ctx, ts.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
f := object.NewRootFolder(c.Client)
|
||||
|
||||
dc, err := f.CreateDatacenter(ctx, "foo")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
folders, err := dc.Folders(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cluster, err := folders.HostFolder.CreateCluster(ctx, "cluster1", types.ClusterConfigSpecEx{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = folders.HostFolder.CreateCluster(ctx, "cluster1", types.ClusterConfigSpecEx{})
|
||||
if err == nil {
|
||||
t.Error("expected DuplicateName error")
|
||||
}
|
||||
|
||||
spec := types.HostConnectSpec{}
|
||||
|
||||
for _, fail := range []bool{true, false} {
|
||||
task, err := cluster.AddHost(ctx, spec, true, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = task.WaitForResult(ctx, nil)
|
||||
|
||||
if fail {
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
spec.HostName = "localhost"
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
113
vendor/github.com/vmware/govmomi/simulator/custom_fields_manager.go
generated
vendored
Normal file
113
vendor/github.com/vmware/govmomi/simulator/custom_fields_manager.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type CustomFieldsManager struct {
|
||||
mo.CustomFieldsManager
|
||||
|
||||
nextKey int32
|
||||
}
|
||||
|
||||
func NewCustomFieldsManager(ref types.ManagedObjectReference) object.Reference {
|
||||
m := &CustomFieldsManager{}
|
||||
m.Self = ref
|
||||
return m
|
||||
}
|
||||
|
||||
func (c *CustomFieldsManager) find(key int32) (int, *types.CustomFieldDef) {
|
||||
for i, field := range c.Field {
|
||||
if field.Key == key {
|
||||
return i, &c.Field[i]
|
||||
}
|
||||
}
|
||||
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
func (c *CustomFieldsManager) AddCustomFieldDef(req *types.AddCustomFieldDef) soap.HasFault {
|
||||
body := &methods.AddCustomFieldDefBody{}
|
||||
|
||||
def := types.CustomFieldDef{
|
||||
Key: c.nextKey,
|
||||
Name: req.Name,
|
||||
ManagedObjectType: req.MoType,
|
||||
Type: req.MoType,
|
||||
FieldDefPrivileges: req.FieldDefPolicy,
|
||||
FieldInstancePrivileges: req.FieldPolicy,
|
||||
}
|
||||
|
||||
c.Field = append(c.Field, def)
|
||||
c.nextKey++
|
||||
|
||||
body.Res = &types.AddCustomFieldDefResponse{
|
||||
Returnval: def,
|
||||
}
|
||||
return body
|
||||
}
|
||||
|
||||
func (c *CustomFieldsManager) RemoveCustomFieldDef(req *types.RemoveCustomFieldDef) soap.HasFault {
|
||||
body := &methods.RemoveCustomFieldDefBody{}
|
||||
|
||||
i, field := c.find(req.Key)
|
||||
if field == nil {
|
||||
body.Fault_ = Fault("", &types.NotFound{})
|
||||
return body
|
||||
}
|
||||
|
||||
c.Field = append(c.Field[:i], c.Field[i+1:]...)
|
||||
|
||||
body.Res = &types.RemoveCustomFieldDefResponse{}
|
||||
return body
|
||||
}
|
||||
|
||||
func (c *CustomFieldsManager) RenameCustomFieldDef(req *types.RenameCustomFieldDef) soap.HasFault {
|
||||
body := &methods.RenameCustomFieldDefBody{}
|
||||
|
||||
_, field := c.find(req.Key)
|
||||
if field == nil {
|
||||
body.Fault_ = Fault("", &types.NotFound{})
|
||||
return body
|
||||
}
|
||||
|
||||
field.Name = req.Name
|
||||
|
||||
body.Res = &types.RenameCustomFieldDefResponse{}
|
||||
return body
|
||||
}
|
||||
|
||||
func (c *CustomFieldsManager) SetField(req *types.SetField) soap.HasFault {
|
||||
body := &methods.SetFieldBody{}
|
||||
|
||||
entity := Map.Get(req.Entity).(mo.Entity).Entity()
|
||||
Map.WithLock(entity, func() {
|
||||
entity.CustomValue = append(entity.CustomValue, &types.CustomFieldStringValue{
|
||||
CustomFieldValue: types.CustomFieldValue{Key: req.Key},
|
||||
Value: req.Value,
|
||||
})
|
||||
})
|
||||
|
||||
body.Res = &types.SetFieldResponse{}
|
||||
return body
|
||||
}
|
||||
123
vendor/github.com/vmware/govmomi/simulator/custom_fields_manager_test.go
generated
vendored
Normal file
123
vendor/github.com/vmware/govmomi/simulator/custom_fields_manager_test.go
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/simulator/vpx"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestCustomFieldsManager(t *testing.T) {
|
||||
s := New(NewServiceInstance(vpx.ServiceContent, vpx.RootFolder))
|
||||
|
||||
ts := s.NewServer()
|
||||
defer ts.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, ts.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fieldsManager, err := object.GetCustomFieldsManager(c.Client)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
field, err := fieldsManager.Add(ctx, "field_name", "VirtualMachine", nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if field.Name != "field_name" && field.Type != "VirtualMachine" {
|
||||
t.Fatal("field add result mismatched with the inserted")
|
||||
}
|
||||
|
||||
fields, err := fieldsManager.Field(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(fields) != 1 {
|
||||
t.Fatalf("expect len(fields)=1; got %d", len(fields))
|
||||
}
|
||||
if !reflect.DeepEqual(&fields[0], field) {
|
||||
t.Fatalf("expect fields[0]==field; got %+v,%+v", fields[0], field)
|
||||
}
|
||||
|
||||
key, err := fieldsManager.FindKey(ctx, field.Name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if key != field.Key {
|
||||
t.Fatalf("expect key == field.Key; got %d != %d", key, field.Key)
|
||||
}
|
||||
|
||||
err = fieldsManager.Rename(ctx, key, "new_field_name")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fields, err = fieldsManager.Field(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(fields) != 1 {
|
||||
t.Fatalf("expect len(fields)=1; got %d", len(fields))
|
||||
}
|
||||
if fields[0].Name != "new_field_name" {
|
||||
t.Fatalf("expect field.name to be %s; got %s", "new_field_name", fields[0].Name)
|
||||
}
|
||||
|
||||
folder := Map.content().RootFolder
|
||||
err = fieldsManager.Set(ctx, folder, 1, "value")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
values := Map.Get(folder.Reference()).(mo.Entity).Entity().CustomValue
|
||||
if len(values) != 1 {
|
||||
t.Fatalf("expect CustomValue has 1 item; got %d", len(values))
|
||||
}
|
||||
fkey := values[0].GetCustomFieldValue().Key
|
||||
if fkey != 1 {
|
||||
t.Fatalf("expect value.Key to be 1; got %d", fkey)
|
||||
}
|
||||
value := values[0].(*types.CustomFieldStringValue).Value
|
||||
if value != "value" {
|
||||
t.Fatalf("expect value.Value to be %q; got %q", "value", value)
|
||||
}
|
||||
|
||||
err = fieldsManager.Remove(ctx, field.Key)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fields, err = fieldsManager.Field(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(fields) != 0 {
|
||||
t.Fatalf("expect fields to be empty; got %+v", fields)
|
||||
}
|
||||
}
|
||||
160
vendor/github.com/vmware/govmomi/simulator/datacenter.go
generated
vendored
Normal file
160
vendor/github.com/vmware/govmomi/simulator/datacenter.go
generated
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type Datacenter struct {
|
||||
mo.Datacenter
|
||||
|
||||
isESX bool
|
||||
}
|
||||
|
||||
// NewDatacenter creates a Datacenter and its child folders.
|
||||
func NewDatacenter(f *Folder) *Datacenter {
|
||||
dc := &Datacenter{
|
||||
isESX: f.Self == esx.RootFolder.Self,
|
||||
}
|
||||
|
||||
if dc.isESX {
|
||||
dc.Datacenter = esx.Datacenter
|
||||
}
|
||||
|
||||
f.putChild(dc)
|
||||
|
||||
dc.createFolders()
|
||||
|
||||
return dc
|
||||
}
|
||||
|
||||
// Create Datacenter Folders.
|
||||
// Every Datacenter has 4 inventory Folders: Vm, Host, Datastore and Network.
|
||||
// The ESX folder child types are limited to 1 type.
|
||||
// The VC folders have additional child types, including nested folders.
|
||||
func (dc *Datacenter) createFolders() {
|
||||
folders := []struct {
|
||||
ref *types.ManagedObjectReference
|
||||
name string
|
||||
types []string
|
||||
}{
|
||||
{&dc.VmFolder, "vm", []string{"VirtualMachine", "VirtualApp", "Folder"}},
|
||||
{&dc.HostFolder, "host", []string{"ComputeResource", "Folder"}},
|
||||
{&dc.DatastoreFolder, "datastore", []string{"Datastore", "StoragePod", "Folder"}},
|
||||
{&dc.NetworkFolder, "network", []string{"Network", "DistributedVirtualSwitch", "Folder"}},
|
||||
}
|
||||
|
||||
for _, f := range folders {
|
||||
folder := &Folder{}
|
||||
folder.Name = f.name
|
||||
|
||||
if dc.isESX {
|
||||
folder.ChildType = f.types[:1]
|
||||
folder.Self = *f.ref
|
||||
Map.PutEntity(dc, folder)
|
||||
} else {
|
||||
folder.ChildType = f.types
|
||||
e := Map.PutEntity(dc, folder)
|
||||
|
||||
// propagate the generated morefs to Datacenter
|
||||
ref := e.Reference()
|
||||
f.ref.Type = ref.Type
|
||||
f.ref.Value = ref.Value
|
||||
}
|
||||
}
|
||||
|
||||
net := Map.Get(dc.NetworkFolder).(*Folder)
|
||||
|
||||
for _, ref := range esx.Datacenter.Network {
|
||||
// Add VM Network by default to each Datacenter
|
||||
network := &mo.Network{}
|
||||
network.Self = ref
|
||||
network.Name = strings.Split(ref.Value, "-")[1]
|
||||
network.Entity().Name = network.Name
|
||||
if !dc.isESX {
|
||||
network.Self.Value = "" // we want a different moid per-DC
|
||||
}
|
||||
|
||||
net.putChild(network)
|
||||
}
|
||||
}
|
||||
|
||||
func datacenterEventArgument(obj mo.Entity) *types.DatacenterEventArgument {
|
||||
dc, ok := obj.(*Datacenter)
|
||||
if !ok {
|
||||
dc = Map.getEntityDatacenter(obj)
|
||||
}
|
||||
return &types.DatacenterEventArgument{
|
||||
Datacenter: dc.Self,
|
||||
EntityEventArgument: types.EntityEventArgument{Name: dc.Name},
|
||||
}
|
||||
}
|
||||
|
||||
func (dc *Datacenter) PowerOnMultiVMTask(ctx *Context, req *types.PowerOnMultiVM_Task) soap.HasFault {
|
||||
task := CreateTask(dc, "powerOnMultiVM", func(_ *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
if dc.isESX {
|
||||
return nil, new(types.NotImplemented)
|
||||
}
|
||||
|
||||
for _, ref := range req.Vm {
|
||||
vm := Map.Get(ref).(*VirtualMachine)
|
||||
Map.WithLock(vm, func() {
|
||||
vm.PowerOnVMTask(ctx, &types.PowerOnVM_Task{})
|
||||
})
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.PowerOnMultiVM_TaskBody{
|
||||
Res: &types.PowerOnMultiVM_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Datacenter) DestroyTask(req *types.Destroy_Task) soap.HasFault {
|
||||
task := CreateTask(d, "destroy", func(t *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
folders := []types.ManagedObjectReference{
|
||||
d.VmFolder,
|
||||
d.HostFolder,
|
||||
}
|
||||
|
||||
for _, ref := range folders {
|
||||
if len(Map.Get(ref).(*Folder).ChildEntity) != 0 {
|
||||
return nil, &types.ResourceInUse{}
|
||||
}
|
||||
}
|
||||
|
||||
Map.Get(*d.Parent).(*Folder).removeChild(d.Self)
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.Destroy_TaskBody{
|
||||
Res: &types.Destroy_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
85
vendor/github.com/vmware/govmomi/simulator/datacenter_test.go
generated
vendored
Normal file
85
vendor/github.com/vmware/govmomi/simulator/datacenter_test.go
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/simulator/vpx"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestDatacenterCreateFolders(t *testing.T) {
|
||||
// For this test we only want the RootFolder, 1 Datacenter and its child folders
|
||||
models := []Model{
|
||||
Model{
|
||||
ServiceContent: esx.ServiceContent,
|
||||
RootFolder: esx.RootFolder,
|
||||
},
|
||||
Model{
|
||||
ServiceContent: vpx.ServiceContent,
|
||||
RootFolder: vpx.RootFolder,
|
||||
Datacenter: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, model := range models {
|
||||
_ = model.Create()
|
||||
|
||||
dc := Map.Any("Datacenter").(*Datacenter)
|
||||
|
||||
folders := []types.ManagedObjectReference{
|
||||
dc.VmFolder,
|
||||
dc.HostFolder,
|
||||
dc.DatastoreFolder,
|
||||
dc.NetworkFolder,
|
||||
}
|
||||
|
||||
for _, ref := range folders {
|
||||
if ref.Type == "" || ref.Value == "" {
|
||||
t.Errorf("invalid moref=%#v", ref)
|
||||
}
|
||||
|
||||
e := Map.Get(ref).(mo.Entity)
|
||||
|
||||
if e.Entity().Name == "" {
|
||||
t.Error("empty name")
|
||||
}
|
||||
|
||||
if *e.Entity().Parent != dc.Self {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
f, ok := e.(*Folder)
|
||||
if !ok {
|
||||
t.Fatalf("unexpected type (%T) for %#v", e, ref)
|
||||
}
|
||||
|
||||
if Map.IsVPX() {
|
||||
if len(f.ChildType) < 2 {
|
||||
t.Fail()
|
||||
}
|
||||
} else {
|
||||
if len(f.ChildType) != 1 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
59
vendor/github.com/vmware/govmomi/simulator/datastore.go
generated
vendored
Normal file
59
vendor/github.com/vmware/govmomi/simulator/datastore.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type Datastore struct {
|
||||
mo.Datastore
|
||||
}
|
||||
|
||||
func parseDatastorePath(dsPath string) (*object.DatastorePath, types.BaseMethodFault) {
|
||||
var p object.DatastorePath
|
||||
|
||||
if p.FromString(dsPath) {
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
return nil, &types.InvalidDatastorePath{DatastorePath: dsPath}
|
||||
}
|
||||
|
||||
func (ds *Datastore) RefreshDatastore(*types.RefreshDatastore) soap.HasFault {
|
||||
r := &methods.RefreshDatastoreBody{}
|
||||
|
||||
err := ds.stat()
|
||||
if err != nil {
|
||||
r.Fault_ = Fault(err.Error(), &types.HostConfigFault{})
|
||||
return r
|
||||
}
|
||||
|
||||
info := ds.Info.GetDatastoreInfo()
|
||||
|
||||
now := time.Now()
|
||||
|
||||
info.Timestamp = &now
|
||||
|
||||
return r
|
||||
}
|
||||
484
vendor/github.com/vmware/govmomi/simulator/datastore_test.go
generated
vendored
Normal file
484
vendor/github.com/vmware/govmomi/simulator/datastore_test.go
generated
vendored
Normal file
@@ -0,0 +1,484 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/find"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestParseDatastorePath(t *testing.T) {
|
||||
tests := []struct {
|
||||
dsPath string
|
||||
dsFile string
|
||||
fail bool
|
||||
}{
|
||||
{"", "", true},
|
||||
{"x", "", true},
|
||||
{"[", "", true},
|
||||
{"[nope", "", true},
|
||||
{"[test]", "", false},
|
||||
{"[test] foo", "foo", false},
|
||||
{"[test] foo/foo.vmx", "foo/foo.vmx", false},
|
||||
{"[test]foo bar/foo bar.vmx", "foo bar/foo bar.vmx", false},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
p, err := parseDatastorePath(test.dsPath)
|
||||
if test.fail {
|
||||
if err == nil {
|
||||
t.Errorf("expected error for: %s", test.dsPath)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error '%#v' for: %s", err, test.dsPath)
|
||||
} else {
|
||||
if test.dsFile != p.Path {
|
||||
t.Errorf("dsFile=%s", p.Path)
|
||||
}
|
||||
if p.Datastore != "test" {
|
||||
t.Errorf("ds=%s", p.Datastore)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefreshDatastore(t *testing.T) {
|
||||
tests := []struct {
|
||||
dir string
|
||||
fail bool
|
||||
}{
|
||||
{".", false},
|
||||
{"-", true},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
ds := &Datastore{}
|
||||
ds.Info = &types.LocalDatastoreInfo{
|
||||
DatastoreInfo: types.DatastoreInfo{
|
||||
Url: test.dir,
|
||||
},
|
||||
}
|
||||
|
||||
res := ds.RefreshDatastore(nil)
|
||||
err := res.Fault()
|
||||
|
||||
if test.fail {
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDatastoreHTTP(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
src := "datastore_test.go"
|
||||
dst := "tmp.go"
|
||||
|
||||
for i, model := range []*Model{ESX(), VPX()} {
|
||||
defer model.Remove()
|
||||
err := model.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := model.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
if i == 0 {
|
||||
// Enable use of SessionManagerGenericServiceTicket.HostName in govmomi, disabled by default.
|
||||
opts := s.URL.Query()
|
||||
opts.Set("GOVMOMI_USE_SERVICE_TICKET_HOSTNAME", "true")
|
||||
s.URL.RawQuery = opts.Encode()
|
||||
}
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder := find.NewFinder(c.Client, false)
|
||||
|
||||
dc, err := finder.DefaultDatacenter(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder.SetDatacenter(dc)
|
||||
|
||||
ds, err := finder.DefaultDatastore(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
// Cover the service ticket path
|
||||
// TODO: govmomi requires HostSystem.Config.VirtualNicManagerInfo
|
||||
// ctx = ds.HostContext(ctx, object.NewHostSystem(c.Client, esx.HostSystem.Reference()))
|
||||
}
|
||||
|
||||
dsPath := ds.Path
|
||||
|
||||
if !c.IsVC() {
|
||||
dc = nil // test using the default
|
||||
}
|
||||
|
||||
fm := object.NewFileManager(c.Client)
|
||||
browser, err := ds.Browser(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
download := func(name string, fail bool) {
|
||||
st, serr := ds.Stat(ctx, name)
|
||||
|
||||
_, _, err = ds.Download(ctx, name, nil)
|
||||
if fail {
|
||||
if err == nil {
|
||||
t.Fatal("expected Download error")
|
||||
}
|
||||
if serr == nil {
|
||||
t.Fatal("expected Stat error")
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("Download error: %s", err)
|
||||
}
|
||||
if serr != nil {
|
||||
t.Errorf("Stat error: %s", serr)
|
||||
}
|
||||
|
||||
p := st.GetFileInfo().Path
|
||||
if p != name {
|
||||
t.Errorf("path=%s", p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
upload := func(name string, fail bool, method string) {
|
||||
f, err := os.Open(src)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
p := soap.DefaultUpload
|
||||
p.Method = method
|
||||
|
||||
err = ds.Upload(ctx, f, name, &p)
|
||||
if fail {
|
||||
if err == nil {
|
||||
t.Fatalf("%s %s: expected error", method, name)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rm := func(name string, fail bool) {
|
||||
task, err := fm.DeleteDatastoreFile(ctx, dsPath(name), dc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if fail {
|
||||
if err == nil {
|
||||
t.Fatalf("rm %s: expected error", name)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mv := func(src string, dst string, fail bool, force bool) {
|
||||
task, err := fm.MoveDatastoreFile(ctx, dsPath(src), dc, dsPath(dst), dc, force)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if fail {
|
||||
if err == nil {
|
||||
t.Fatalf("mv %s %s: expected error", src, dst)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mkdir := func(name string, fail bool, p bool) {
|
||||
err := fm.MakeDirectory(ctx, dsPath(name), dc, p)
|
||||
if fail {
|
||||
if err == nil {
|
||||
t.Fatalf("mkdir %s: expected error", name)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stat := func(name string, fail bool) {
|
||||
_, err := ds.Stat(ctx, name)
|
||||
if fail {
|
||||
if err == nil {
|
||||
t.Fatalf("stat %s: expected error", name)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ls := func(name string, fail bool) []types.BaseFileInfo {
|
||||
spec := types.HostDatastoreBrowserSearchSpec{
|
||||
MatchPattern: []string{"*"},
|
||||
}
|
||||
|
||||
task, err := browser.SearchDatastore(ctx, dsPath(name), &spec)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
info, err := task.WaitForResult(ctx, nil)
|
||||
if err != nil {
|
||||
if fail {
|
||||
if err == nil {
|
||||
t.Fatalf("ls %s: expected error", name)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return info.Result.(types.HostDatastoreBrowserSearchResults).File
|
||||
}
|
||||
|
||||
lsr := func(name string, fail bool, query ...types.BaseFileQuery) []types.HostDatastoreBrowserSearchResults {
|
||||
spec := types.HostDatastoreBrowserSearchSpec{
|
||||
MatchPattern: []string{"*"},
|
||||
Query: query,
|
||||
}
|
||||
|
||||
task, err := browser.SearchDatastoreSubFolders(ctx, dsPath(name), &spec)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
info, err := task.WaitForResult(ctx, nil)
|
||||
if err != nil {
|
||||
if fail {
|
||||
if err == nil {
|
||||
t.Fatalf("find %s: expected error", name)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return info.Result.(types.ArrayOfHostDatastoreBrowserSearchResults).HostDatastoreBrowserSearchResults
|
||||
}
|
||||
|
||||
// GET file does not exist = fail
|
||||
download(dst, true)
|
||||
stat(dst, true)
|
||||
ls(dst, true)
|
||||
lsr(dst, true)
|
||||
|
||||
// delete file does not exist = fail
|
||||
rm(dst, true)
|
||||
|
||||
// PUT file = ok
|
||||
upload(dst, false, "PUT")
|
||||
stat(dst, false)
|
||||
ls("", false)
|
||||
lsr("", false)
|
||||
|
||||
// GET file exists = ok
|
||||
download(dst, false)
|
||||
|
||||
// POST file exists = fail
|
||||
upload(dst, true, "POST")
|
||||
|
||||
// delete existing file = ok
|
||||
rm(dst, false)
|
||||
stat(dst, true)
|
||||
|
||||
// GET file does not exist = fail
|
||||
download(dst, true)
|
||||
|
||||
// POST file does not exist = ok
|
||||
upload(dst, false, "POST")
|
||||
|
||||
// PATCH method not supported = fail
|
||||
upload(dst+".patch", true, "PATCH")
|
||||
|
||||
// PUT path is directory = fail
|
||||
upload("", true, "PUT")
|
||||
|
||||
// mkdir parent does not exist = fail
|
||||
mkdir("foo/bar", true, false)
|
||||
|
||||
// mkdir -p parent does not exist = ok
|
||||
mkdir("foo/bar", false, true)
|
||||
|
||||
// mkdir = ok
|
||||
mkdir("foo/bar/baz", false, false)
|
||||
|
||||
target := path.Join("foo", dst)
|
||||
|
||||
// mv dst not exist = ok
|
||||
mv(dst, target, false, false)
|
||||
|
||||
// POST file does not exist = ok
|
||||
upload(dst, false, "POST")
|
||||
|
||||
// mv dst exists = fail
|
||||
mv(dst, target, true, false)
|
||||
|
||||
// mv dst exists, force=true = ok
|
||||
mv(dst, target, false, true)
|
||||
|
||||
// mv src does not exist = fail
|
||||
mv(dst, target, true, true)
|
||||
|
||||
// ls -R = ok
|
||||
res := lsr("foo", false)
|
||||
|
||||
count := func(s string) int {
|
||||
n := 0
|
||||
for _, dir := range res {
|
||||
for _, f := range dir.File {
|
||||
if strings.HasSuffix(f.GetFileInfo().Path, s) {
|
||||
n++
|
||||
}
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
n := len(res) + count("")
|
||||
|
||||
if n != 6 {
|
||||
t.Errorf("ls -R foo==%d", n)
|
||||
}
|
||||
|
||||
// test FileQuery
|
||||
res = lsr("", false)
|
||||
all := count(".vmdk") // foo-flat.vmdk + foo.vmdk
|
||||
|
||||
res = lsr("", false, new(types.VmDiskFileQuery))
|
||||
allq := count(".vmdk") // foo.vmdk only
|
||||
if allq*2 != all {
|
||||
t.Errorf("ls -R *.vmdk: %d vs %d", all, allq)
|
||||
}
|
||||
|
||||
res = lsr("", false, new(types.VmLogFileQuery), new(types.VmConfigFileQuery))
|
||||
all = count("")
|
||||
if all != model.Count().Machine*2 {
|
||||
t.Errorf("ls -R vmware.log+.vmx: %d", all)
|
||||
}
|
||||
|
||||
invalid := []string{
|
||||
"", //InvalidDatastorePath
|
||||
"[nope]", // InvalidDatastore
|
||||
}
|
||||
|
||||
// test FileType details
|
||||
mkdir("exts", false, false)
|
||||
stat("exts", false)
|
||||
exts := []string{"img", "iso", "log", "nvram", "vmdk", "vmx"}
|
||||
for _, ext := range exts {
|
||||
name := dst + "." + ext
|
||||
upload(name, false, "POST")
|
||||
stat(name, false)
|
||||
}
|
||||
|
||||
for _, p := range invalid {
|
||||
dsPath = func(name string) string {
|
||||
return p
|
||||
}
|
||||
mv(target, dst, true, false)
|
||||
mkdir("sorry", true, false)
|
||||
rm(target, true)
|
||||
ls(target, true)
|
||||
}
|
||||
|
||||
// cover the dst failure path
|
||||
for _, p := range invalid {
|
||||
dsPath = func(name string) string {
|
||||
if name == dst {
|
||||
return p
|
||||
}
|
||||
return ds.Path(name)
|
||||
}
|
||||
mv(target, dst, true, false)
|
||||
}
|
||||
|
||||
dsPath = func(name string) string {
|
||||
return ds.Path("enoent")
|
||||
}
|
||||
ls(target, true)
|
||||
|
||||
// cover the case where datacenter or datastore lookup fails
|
||||
for _, q := range []string{"dcName=nope", "dsName=nope"} {
|
||||
u := *s.URL
|
||||
u.RawQuery = q
|
||||
u.Path = path.Join(folderPrefix, dst)
|
||||
|
||||
r, err := http.Get(u.String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if r.StatusCode == http.StatusOK {
|
||||
t.Error("expected failure")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
vendor/github.com/vmware/govmomi/simulator/doc.go
generated
vendored
Normal file
22
vendor/github.com/vmware/govmomi/simulator/doc.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Package simulator is a mock framework for the vSphere API.
|
||||
|
||||
See also: https://github.com/vmware/govmomi/blob/master/vcsim/README.md
|
||||
*/
|
||||
package simulator
|
||||
195
vendor/github.com/vmware/govmomi/simulator/dvs.go
generated
vendored
Normal file
195
vendor/github.com/vmware/govmomi/simulator/dvs.go
generated
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type DistributedVirtualSwitch struct {
|
||||
mo.DistributedVirtualSwitch
|
||||
}
|
||||
|
||||
func (s *DistributedVirtualSwitch) AddDVPortgroupTask(c *types.AddDVPortgroup_Task) soap.HasFault {
|
||||
task := CreateTask(s, "addDVPortgroup", func(t *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
f := Map.getEntityParent(s, "Folder").(*Folder)
|
||||
|
||||
for _, spec := range c.Spec {
|
||||
pg := &DistributedVirtualPortgroup{}
|
||||
pg.Name = spec.Name
|
||||
pg.Entity().Name = pg.Name
|
||||
|
||||
if obj := Map.FindByName(pg.Name, f.ChildEntity); obj != nil {
|
||||
return nil, &types.DuplicateName{
|
||||
Name: pg.Name,
|
||||
Object: obj.Reference(),
|
||||
}
|
||||
}
|
||||
|
||||
f.putChild(pg)
|
||||
|
||||
pg.Key = pg.Self.Value
|
||||
pg.Config = types.DVPortgroupConfigInfo{
|
||||
Key: pg.Key,
|
||||
Name: pg.Name,
|
||||
NumPorts: spec.NumPorts,
|
||||
DistributedVirtualSwitch: &s.Self,
|
||||
DefaultPortConfig: spec.DefaultPortConfig,
|
||||
Description: spec.Description,
|
||||
Type: spec.Type,
|
||||
Policy: spec.Policy,
|
||||
PortNameFormat: spec.PortNameFormat,
|
||||
Scope: spec.Scope,
|
||||
VendorSpecificConfig: spec.VendorSpecificConfig,
|
||||
ConfigVersion: spec.ConfigVersion,
|
||||
AutoExpand: spec.AutoExpand,
|
||||
VmVnicNetworkResourcePoolKey: spec.VmVnicNetworkResourcePoolKey,
|
||||
}
|
||||
|
||||
if pg.Config.DefaultPortConfig == nil {
|
||||
pg.Config.DefaultPortConfig = &types.VMwareDVSPortSetting{
|
||||
Vlan: new(types.VmwareDistributedVirtualSwitchVlanIdSpec),
|
||||
}
|
||||
}
|
||||
|
||||
pg.PortKeys = []string{}
|
||||
|
||||
s.Portgroup = append(s.Portgroup, pg.Self)
|
||||
s.Summary.PortgroupName = append(s.Summary.PortgroupName, pg.Name)
|
||||
|
||||
for _, h := range s.Summary.HostMember {
|
||||
pg.Host = append(pg.Host, h)
|
||||
|
||||
host := Map.Get(h).(*HostSystem)
|
||||
Map.AppendReference(host, &host.Network, pg.Reference())
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.AddDVPortgroup_TaskBody{
|
||||
Res: &types.AddDVPortgroup_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DistributedVirtualSwitch) ReconfigureDvsTask(req *types.ReconfigureDvs_Task) soap.HasFault {
|
||||
task := CreateTask(s, "reconfigureDvs", func(t *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
spec := req.Spec.GetDVSConfigSpec()
|
||||
|
||||
for _, member := range spec.Host {
|
||||
h := Map.Get(member.Host)
|
||||
if h == nil {
|
||||
return nil, &types.ManagedObjectNotFound{Obj: member.Host}
|
||||
}
|
||||
|
||||
host := h.(*HostSystem)
|
||||
|
||||
switch types.ConfigSpecOperation(member.Operation) {
|
||||
case types.ConfigSpecOperationAdd:
|
||||
if FindReference(host.Network, s.Self) != nil {
|
||||
return nil, &types.AlreadyExists{Name: host.Name}
|
||||
}
|
||||
|
||||
Map.AppendReference(host, &host.Network, s.Self)
|
||||
Map.AppendReference(host, &host.Network, s.Portgroup...)
|
||||
s.Summary.HostMember = append(s.Summary.HostMember, member.Host)
|
||||
|
||||
for _, ref := range s.Portgroup {
|
||||
pg := Map.Get(ref).(*DistributedVirtualPortgroup)
|
||||
Map.AddReference(pg, &pg.Host, member.Host)
|
||||
}
|
||||
case types.ConfigSpecOperationRemove:
|
||||
for _, ref := range host.Vm {
|
||||
vm := Map.Get(ref).(*VirtualMachine)
|
||||
if pg := FindReference(vm.Network, s.Portgroup...); pg != nil {
|
||||
return nil, &types.ResourceInUse{
|
||||
Type: pg.Type,
|
||||
Name: pg.Value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map.RemoveReference(host, &host.Network, s.Self)
|
||||
RemoveReference(&s.Summary.HostMember, s.Self)
|
||||
case types.ConfigSpecOperationEdit:
|
||||
return nil, &types.NotSupported{}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.ReconfigureDvs_TaskBody{
|
||||
Res: &types.ReconfigureDvs_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DistributedVirtualSwitch) FetchDVPorts(req *types.FetchDVPorts) soap.HasFault {
|
||||
body := &methods.FetchDVPortsBody{}
|
||||
body.Res = &types.FetchDVPortsResponse{
|
||||
Returnval: s.dvPortgroups(req.Criteria),
|
||||
}
|
||||
return body
|
||||
}
|
||||
|
||||
func (s *DistributedVirtualSwitch) DestroyTask(req *types.Destroy_Task) soap.HasFault {
|
||||
task := CreateTask(s, "destroy", func(t *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
f := Map.getEntityParent(s, "Folder").(*Folder)
|
||||
f.removeChild(s.Reference())
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.Destroy_TaskBody{
|
||||
Res: &types.Destroy_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DistributedVirtualSwitch) dvPortgroups(_ *types.DistributedVirtualSwitchPortCriteria) []types.DistributedVirtualPort {
|
||||
// TODO(agui): Filter is not implemented yet
|
||||
var res []types.DistributedVirtualPort
|
||||
for _, ref := range s.Portgroup {
|
||||
pg := Map.Get(ref).(*DistributedVirtualPortgroup)
|
||||
res = append(res, types.DistributedVirtualPort{
|
||||
DvsUuid: s.Uuid,
|
||||
Key: pg.Key,
|
||||
Config: types.DVPortConfigInfo{
|
||||
Setting: pg.Config.DefaultPortConfig,
|
||||
},
|
||||
})
|
||||
|
||||
for _, key := range pg.PortKeys {
|
||||
res = append(res, types.DistributedVirtualPort{
|
||||
DvsUuid: s.Uuid,
|
||||
Key: key,
|
||||
Config: types.DVPortConfigInfo{
|
||||
Setting: pg.Config.DefaultPortConfig,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
154
vendor/github.com/vmware/govmomi/simulator/dvs_test.go
generated
vendored
Normal file
154
vendor/github.com/vmware/govmomi/simulator/dvs_test.go
generated
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi/find"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/task"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestDVS(t *testing.T) {
|
||||
m := VPX()
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
c := m.Service.client
|
||||
|
||||
finder := find.NewFinder(c, false)
|
||||
dc, _ := finder.DatacenterList(ctx, "*")
|
||||
finder.SetDatacenter(dc[0])
|
||||
folders, _ := dc[0].Folders(ctx)
|
||||
hosts, _ := finder.HostSystemList(ctx, "*/*")
|
||||
dvs0 := object.NewDistributedVirtualSwitch(c, Map.Any("DistributedVirtualSwitch").Reference())
|
||||
|
||||
var spec types.DVSCreateSpec
|
||||
spec.ConfigSpec = &types.VMwareDVSConfigSpec{}
|
||||
spec.ConfigSpec.GetDVSConfigSpec().Name = "DVS1"
|
||||
|
||||
dtask, err := folders.NetworkFolder.CreateDVS(ctx, spec)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
info, err := dtask.WaitForResult(ctx, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dvs := object.NewDistributedVirtualSwitch(c, info.Result.(types.ManagedObjectReference))
|
||||
|
||||
config := &types.DVSConfigSpec{}
|
||||
|
||||
for _, host := range hosts {
|
||||
config.Host = append(config.Host, types.DistributedVirtualSwitchHostMemberConfigSpec{
|
||||
Host: host.Reference(),
|
||||
})
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
op types.ConfigSpecOperation
|
||||
pg string
|
||||
err types.BaseMethodFault
|
||||
}{
|
||||
{types.ConfigSpecOperationAdd, "", nil}, // Add == OK
|
||||
{types.ConfigSpecOperationAdd, "", &types.AlreadyExists{}}, // Add == fail (AlreadyExists)
|
||||
{types.ConfigSpecOperationEdit, "", &types.NotSupported{}}, // Edit == fail (NotSupported)
|
||||
{types.ConfigSpecOperationRemove, "", nil}, // Remove == OK
|
||||
{types.ConfigSpecOperationAdd, "", nil}, // Add == OK
|
||||
{types.ConfigSpecOperationAdd, "DVPG0", nil}, // Add PG == OK
|
||||
{types.ConfigSpecOperationRemove, "", &types.ResourceInUse{}}, // Remove dvs0 == fail (ResourceInUse)
|
||||
{types.ConfigSpecOperationRemove, "", nil}, // Remove dvs1 == OK (no VMs attached)
|
||||
{types.ConfigSpecOperationRemove, "", &types.ManagedObjectNotFound{}}, // Remove == fail (ManagedObjectNotFound)
|
||||
}
|
||||
|
||||
for x, test := range tests {
|
||||
dswitch := dvs
|
||||
|
||||
switch test.err.(type) {
|
||||
case *types.ManagedObjectNotFound:
|
||||
for i := range config.Host {
|
||||
config.Host[i].Host.Value = "enoent"
|
||||
}
|
||||
case *types.ResourceInUse:
|
||||
dswitch = dvs0
|
||||
}
|
||||
|
||||
if test.pg == "" {
|
||||
for i := range config.Host {
|
||||
config.Host[i].Operation = string(test.op)
|
||||
}
|
||||
|
||||
dtask, err = dswitch.Reconfigure(ctx, config)
|
||||
} else {
|
||||
switch test.op {
|
||||
case types.ConfigSpecOperationAdd:
|
||||
dtask, err = dswitch.AddPortgroup(ctx, []types.DVPortgroupConfigSpec{{Name: test.pg}})
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = dtask.Wait(ctx)
|
||||
|
||||
if test.err == nil {
|
||||
if err != nil {
|
||||
t.Fatalf("%d: %s", x, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
t.Errorf("expected error in test %d", x)
|
||||
}
|
||||
|
||||
if reflect.TypeOf(test.err) != reflect.TypeOf(err.(task.Error).Fault()) {
|
||||
t.Errorf("expected %T fault in test %d", test.err, x)
|
||||
}
|
||||
}
|
||||
|
||||
ports, err := dvs.FetchDVPorts(ctx, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(ports) != 2 {
|
||||
t.Fatalf("expected 2 ports in DVPorts; got %d", len(ports))
|
||||
}
|
||||
|
||||
dtask, err = dvs.Destroy(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = dtask.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
46
vendor/github.com/vmware/govmomi/simulator/entity.go
generated
vendored
Normal file
46
vendor/github.com/vmware/govmomi/simulator/entity.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func RenameTask(e mo.Entity, r *types.Rename_Task) soap.HasFault {
|
||||
task := CreateTask(e, "rename", func(t *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
obj := Map.Get(r.This).(mo.Entity).Entity()
|
||||
|
||||
if parent, ok := Map.Get(*obj.Parent).(*Folder); ok {
|
||||
if Map.FindByName(r.NewName, parent.ChildEntity) != nil {
|
||||
return nil, &types.InvalidArgument{InvalidProperty: "name"}
|
||||
}
|
||||
}
|
||||
|
||||
obj.Name = r.NewName
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.Rename_TaskBody{
|
||||
Res: &types.Rename_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
70
vendor/github.com/vmware/govmomi/simulator/entity_test.go
generated
vendored
Normal file
70
vendor/github.com/vmware/govmomi/simulator/entity_test.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestRename(t *testing.T) {
|
||||
m := VPX()
|
||||
m.Datacenter = 2
|
||||
m.Folder = 2
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
dc := Map.Any("Datacenter").(*Datacenter)
|
||||
vmFolder := Map.Get(dc.VmFolder).(*Folder)
|
||||
|
||||
f1 := Map.Get(vmFolder.ChildEntity[0]).(*Folder) // "F1"
|
||||
|
||||
id := vmFolder.CreateFolder(&types.CreateFolder{
|
||||
This: vmFolder.Reference(),
|
||||
Name: "F2",
|
||||
}).(*methods.CreateFolderBody).Res.Returnval
|
||||
|
||||
f2 := Map.Get(id).(*Folder) // "F2"
|
||||
|
||||
states := []types.TaskInfoState{types.TaskInfoStateError, types.TaskInfoStateSuccess}
|
||||
name := f1.Name
|
||||
|
||||
for _, expect := range states {
|
||||
id = f2.RenameTask(&types.Rename_Task{
|
||||
This: f2.Reference(),
|
||||
NewName: name,
|
||||
}).(*methods.Rename_TaskBody).Res.Returnval
|
||||
|
||||
task := Map.Get(id).(*Task)
|
||||
|
||||
if task.Info.State != expect {
|
||||
t.Errorf("state=%s", task.Info.State)
|
||||
}
|
||||
|
||||
name = name + "-uniq"
|
||||
}
|
||||
}
|
||||
85
vendor/github.com/vmware/govmomi/simulator/esx/authorization_manager.go
generated
vendored
Normal file
85
vendor/github.com/vmware/govmomi/simulator/esx/authorization_manager.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
60
vendor/github.com/vmware/govmomi/simulator/esx/datacenter.go
generated
vendored
Normal file
60
vendor/github.com/vmware/govmomi/simulator/esx/datacenter.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package esx
|
||||
|
||||
import (
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
// Datacenter is the default template for Datacenter properties.
|
||||
// Capture method:
|
||||
// govc datacenter.info -dump
|
||||
var Datacenter = mo.Datacenter{
|
||||
ManagedEntity: mo.ManagedEntity{
|
||||
ExtensibleManagedObject: mo.ExtensibleManagedObject{
|
||||
Self: types.ManagedObjectReference{Type: "Datacenter", Value: "ha-datacenter"},
|
||||
Value: nil,
|
||||
AvailableField: nil,
|
||||
},
|
||||
Parent: (*types.ManagedObjectReference)(nil),
|
||||
CustomValue: nil,
|
||||
OverallStatus: "",
|
||||
ConfigStatus: "",
|
||||
ConfigIssue: nil,
|
||||
EffectiveRole: nil,
|
||||
Permission: nil,
|
||||
Name: "ha-datacenter",
|
||||
DisabledMethod: nil,
|
||||
RecentTask: nil,
|
||||
DeclaredAlarmState: nil,
|
||||
TriggeredAlarmState: nil,
|
||||
AlarmActionsEnabled: (*bool)(nil),
|
||||
Tag: nil,
|
||||
},
|
||||
VmFolder: types.ManagedObjectReference{Type: "Folder", Value: "ha-folder-vm"},
|
||||
HostFolder: types.ManagedObjectReference{Type: "Folder", Value: "ha-folder-host"},
|
||||
DatastoreFolder: types.ManagedObjectReference{Type: "Folder", Value: "ha-folder-datastore"},
|
||||
NetworkFolder: types.ManagedObjectReference{Type: "Folder", Value: "ha-folder-network"},
|
||||
Datastore: []types.ManagedObjectReference{
|
||||
{Type: "Datastore", Value: "57089c25-85e3ccd4-17b6-000c29d0beb3"},
|
||||
},
|
||||
Network: []types.ManagedObjectReference{
|
||||
{Type: "Network", Value: "HaNetwork-VM Network"},
|
||||
},
|
||||
Configuration: types.DatacenterConfigInfo{},
|
||||
}
|
||||
20
vendor/github.com/vmware/govmomi/simulator/esx/doc.go
generated
vendored
Normal file
20
vendor/github.com/vmware/govmomi/simulator/esx/doc.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Package esx contains SOAP responses from an ESX server, captured using `govc ... -dump`.
|
||||
*/
|
||||
package esx
|
||||
236
vendor/github.com/vmware/govmomi/simulator/esx/event_manager.go
generated
vendored
Normal file
236
vendor/github.com/vmware/govmomi/simulator/esx/event_manager.go
generated
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package esx
|
||||
|
||||
import "github.com/vmware/govmomi/vim25/types"
|
||||
|
||||
// EventInfo is the default template for the EventManager description.eventInfo property.
|
||||
// Capture method:
|
||||
// govc object.collect -s -dump EventManager:ha-eventmgr description.eventInfo
|
||||
// The captured list has been manually pruned and FullFormat fields changed to use Go's template variable syntax.
|
||||
var EventInfo = []types.EventDescriptionEventDetail{
|
||||
{
|
||||
Key: "UserLoginSessionEvent",
|
||||
Description: "User login",
|
||||
Category: "info",
|
||||
FullFormat: "User {{.UserName}}@{{.IpAddress}} logged in as {{.UserAgent}}",
|
||||
},
|
||||
{
|
||||
Key: "UserLogoutSessionEvent",
|
||||
Description: "User logout",
|
||||
Category: "info",
|
||||
FullFormat: "User {{.UserName}}@{{.IpAddress}} logged out (login time: {{.LoginTime}}, number of API invocations: {{.CallCount}}, user agent: {{.UserAgent}})",
|
||||
},
|
||||
{
|
||||
Key: "DatacenterCreatedEvent",
|
||||
Description: "Datacenter created",
|
||||
Category: "info",
|
||||
FullFormat: "Created datacenter {{.Datacenter.Name}} in folder {{.Parent.Name}}",
|
||||
},
|
||||
{
|
||||
Key: "DatastoreFileMovedEvent",
|
||||
Description: "File or directory moved to datastore",
|
||||
Category: "info",
|
||||
FullFormat: "Move of file or directory {{.SourceFile}} from {{.SourceDatastore.Name}} to {{.Datastore.Name}} as {{.TargetFile}}",
|
||||
},
|
||||
{
|
||||
Key: "DatastoreFileCopiedEvent",
|
||||
Description: "File or directory copied to datastore",
|
||||
Category: "info",
|
||||
FullFormat: "Copy of file or directory {{.SourceFile}} from {{.SourceDatastore.Name}} to {{.Datastore.Name}} as {{.TargetFile}}",
|
||||
},
|
||||
{
|
||||
Key: "DatastoreFileDeletedEvent",
|
||||
Description: "File or directory deleted",
|
||||
Category: "info",
|
||||
FullFormat: "Deletion of file or directory {{.TargetFile}} from {{.Datastore.Name}} was initiated",
|
||||
},
|
||||
{
|
||||
Key: "EnteringMaintenanceModeEvent",
|
||||
Description: "Entering maintenance mode",
|
||||
Category: "info",
|
||||
FullFormat: "Host {{.Host.Name}} in {{.Datacenter.Name}} has started to enter maintenance mode",
|
||||
},
|
||||
{
|
||||
Key: "EnteredMaintenanceModeEvent",
|
||||
Description: "Entered maintenance mode",
|
||||
Category: "info",
|
||||
FullFormat: "Host {{.Host.Name}} in {{.Datacenter.Name}} has entered maintenance mode",
|
||||
},
|
||||
{
|
||||
Key: "ExitMaintenanceModeEvent",
|
||||
Description: "Exit maintenance mode",
|
||||
Category: "info",
|
||||
FullFormat: "Host {{.Host.Name}} in {{.Datacenter.Name}} has exited maintenance mode",
|
||||
},
|
||||
{
|
||||
Key: "VmSuspendedEvent",
|
||||
Description: "VM suspended",
|
||||
Category: "info",
|
||||
FullFormat: "{{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}} is suspended",
|
||||
},
|
||||
{
|
||||
Key: "VmMigratedEvent",
|
||||
Description: "VM migrated",
|
||||
Category: "info",
|
||||
FullFormat: "Migration of virtual machine {{.Vm.Name}} from {{.SourceHost.Name}, {{.SourceDatastore.Name}} to {{.Host.Name}, {{.Ds.Name}} completed",
|
||||
},
|
||||
{
|
||||
Key: "VmBeingMigratedEvent",
|
||||
Description: "VM migrating",
|
||||
Category: "info",
|
||||
FullFormat: "Relocating {{.Vm.Name}} from {{.Host.Name}, {{.Ds.Name}} in {{.Datacenter.Name}} to {{.DestHost.Name}, {{.DestDatastore.Name}} in {{.DestDatacenter.Name}}",
|
||||
},
|
||||
{
|
||||
Key: "VmMacAssignedEvent",
|
||||
Description: "VM MAC assigned",
|
||||
Category: "info",
|
||||
FullFormat: "New MAC address ({{.Mac}}) assigned to adapter {{.Adapter}} for {{.Vm.Name}}",
|
||||
},
|
||||
{
|
||||
Key: "VmRegisteredEvent",
|
||||
Description: "VM registered",
|
||||
Category: "info",
|
||||
FullFormat: "Registered {{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}}",
|
||||
},
|
||||
{
|
||||
Key: "VmReconfiguredEvent",
|
||||
Description: "VM reconfigured",
|
||||
Category: "info",
|
||||
FullFormat: "Reconfigured {{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}}",
|
||||
},
|
||||
{
|
||||
Key: "VmGuestRebootEvent",
|
||||
Description: "Guest reboot",
|
||||
Category: "info",
|
||||
FullFormat: "Guest OS reboot for {{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}}",
|
||||
},
|
||||
{
|
||||
Key: "VmBeingClonedEvent",
|
||||
Description: "VM being cloned",
|
||||
Category: "info",
|
||||
FullFormat: "Cloning {{.Vm.Name}} on host {{.Host.Name}} in {{.Datacenter.Name}} to {{.DestName}} on host {{.DestHost.Name}}",
|
||||
},
|
||||
{
|
||||
Key: "VmClonedEvent",
|
||||
Description: "VM cloned",
|
||||
Category: "info",
|
||||
FullFormat: "Clone of {{.SourceVm.Name}} completed",
|
||||
},
|
||||
{
|
||||
Key: "VmBeingDeployedEvent",
|
||||
Description: "Deploying VM",
|
||||
Category: "info",
|
||||
FullFormat: "Deploying {{.Vm.Name}} on host {{.Host.Name}} in {{.Datacenter.Name}} from template {{.SrcTemplate.Name}}",
|
||||
},
|
||||
{
|
||||
Key: "VmDeployedEvent",
|
||||
Description: "VM deployed",
|
||||
Category: "info",
|
||||
FullFormat: "Template {{.SrcTemplate.Name}} deployed on host {{.Host.Name}}",
|
||||
},
|
||||
{
|
||||
Key: "VmInstanceUuidAssignedEvent",
|
||||
Description: "Assign a new instance UUID",
|
||||
Category: "info",
|
||||
FullFormat: "Assign a new instance UUID ({{.InstanceUuid}}) to {{.Vm.Name}}",
|
||||
},
|
||||
{
|
||||
Key: "VmPoweredOnEvent",
|
||||
Description: "VM powered on",
|
||||
Category: "info",
|
||||
FullFormat: "{{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}} is powered on",
|
||||
},
|
||||
{
|
||||
Key: "VmStartingEvent",
|
||||
Description: "VM starting",
|
||||
Category: "info",
|
||||
FullFormat: "{{.Vm.Name}} on host {{.Host.Name}} in {{.Datacenter.Name}} is starting",
|
||||
},
|
||||
{
|
||||
Key: "VmSuspendingEvent",
|
||||
Description: "VM being suspended",
|
||||
Category: "info",
|
||||
FullFormat: "{{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}} is being suspended",
|
||||
},
|
||||
{
|
||||
Key: "VmResumingEvent",
|
||||
Description: "VM resuming",
|
||||
Category: "info",
|
||||
FullFormat: "{{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}} is resumed",
|
||||
},
|
||||
{
|
||||
Key: "VmBeingCreatedEvent",
|
||||
Description: "Creating VM",
|
||||
Category: "info",
|
||||
FullFormat: "Creating {{.Vm.Name}} on host {{.Host.Name}} in {{.Datacenter.Name}}",
|
||||
},
|
||||
{
|
||||
Key: "VmCreatedEvent",
|
||||
Description: "VM created",
|
||||
Category: "info",
|
||||
FullFormat: "Created virtual machine {{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}}",
|
||||
},
|
||||
{
|
||||
Key: "VmRemovedEvent",
|
||||
Description: "VM removed",
|
||||
Category: "info",
|
||||
FullFormat: "Removed {{.Vm.Name}} on {{.Host.Name}} from {{.Datacenter.Name}}",
|
||||
},
|
||||
{
|
||||
Key: "VmResettingEvent",
|
||||
Description: "VM resetting",
|
||||
Category: "info",
|
||||
FullFormat: "{{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}} is reset",
|
||||
},
|
||||
{
|
||||
Key: "VmGuestShutdownEvent",
|
||||
Description: "Guest OS shut down",
|
||||
Category: "info",
|
||||
FullFormat: "Guest OS shut down for {{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}}",
|
||||
},
|
||||
{
|
||||
Key: "VmUuidAssignedEvent",
|
||||
Description: "VM UUID assigned",
|
||||
Category: "info",
|
||||
FullFormat: "Assigned new BIOS UUID ({{.Uuid}}) to {{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}}",
|
||||
},
|
||||
{
|
||||
Key: "VmPoweredOffEvent",
|
||||
Description: "VM powered off",
|
||||
Category: "info",
|
||||
FullFormat: "{{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}} is powered off",
|
||||
},
|
||||
{
|
||||
Key: "VmRelocatedEvent",
|
||||
Description: "VM relocated",
|
||||
Category: "info",
|
||||
FullFormat: "Completed the relocation of the virtual machine",
|
||||
},
|
||||
{
|
||||
Key: "DrsVmMigratedEvent",
|
||||
Description: "DRS VM migrated",
|
||||
Category: "info",
|
||||
FullFormat: "DRS migrated {{.Vm.Name}} from {{.SourceHost.Name}} to {{.Host.Name}} in cluster {{.ComputeResource.Name}} in {{.Datacenter.Name}}",
|
||||
},
|
||||
{
|
||||
Key: "DrsVmPoweredOnEvent",
|
||||
Description: "DRS VM powered on",
|
||||
Category: "info",
|
||||
FullFormat: "DRS powered On {{.Vm.Name}} on {{.Host.Name}} in {{.Datacenter.Name}}",
|
||||
},
|
||||
}
|
||||
1091
vendor/github.com/vmware/govmomi/simulator/esx/host_config_info.go
generated
vendored
Normal file
1091
vendor/github.com/vmware/govmomi/simulator/esx/host_config_info.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1425
vendor/github.com/vmware/govmomi/simulator/esx/host_firewall_system.go
generated
vendored
Normal file
1425
vendor/github.com/vmware/govmomi/simulator/esx/host_firewall_system.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
864
vendor/github.com/vmware/govmomi/simulator/esx/host_hardware_info.go
generated
vendored
Normal file
864
vendor/github.com/vmware/govmomi/simulator/esx/host_hardware_info.go
generated
vendored
Normal file
@@ -0,0 +1,864 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package esx
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
// HostHardwareInfo is the default template for the HostSystem hardware property.
|
||||
// Capture method:
|
||||
// govc object.collect -s -dump HostSystem:ha-host hardware
|
||||
var HostHardwareInfo = &types.HostHardwareInfo{
|
||||
SystemInfo: types.HostSystemInfo{
|
||||
Vendor: "VMware, Inc.",
|
||||
Model: "VMware Virtual Platform",
|
||||
Uuid: "e88d4d56-9f1e-3ea1-71fa-13a8e1a7fd70",
|
||||
OtherIdentifyingInfo: []types.HostSystemIdentificationInfo{
|
||||
{
|
||||
IdentifierValue: " No Asset Tag",
|
||||
IdentifierType: &types.ElementDescription{
|
||||
Description: types.Description{
|
||||
Label: "Asset Tag",
|
||||
Summary: "Asset tag of the system",
|
||||
},
|
||||
Key: "AssetTag",
|
||||
},
|
||||
},
|
||||
{
|
||||
IdentifierValue: "[MS_VM_CERT/SHA1/27d66596a61c48dd3dc7216fd715126e33f59ae7]",
|
||||
IdentifierType: &types.ElementDescription{
|
||||
Description: types.Description{
|
||||
Label: "OEM specific string",
|
||||
Summary: "OEM specific string",
|
||||
},
|
||||
Key: "OemSpecificString",
|
||||
},
|
||||
},
|
||||
{
|
||||
IdentifierValue: "Welcome to the Virtual Machine",
|
||||
IdentifierType: &types.ElementDescription{
|
||||
Description: types.Description{
|
||||
Label: "OEM specific string",
|
||||
Summary: "OEM specific string",
|
||||
},
|
||||
Key: "OemSpecificString",
|
||||
},
|
||||
},
|
||||
{
|
||||
IdentifierValue: "VMware-56 4d 8d e8 1e 9f a1 3e-71 fa 13 a8 e1 a7 fd 70",
|
||||
IdentifierType: &types.ElementDescription{
|
||||
Description: types.Description{
|
||||
Label: "Service tag",
|
||||
Summary: "Service tag of the system",
|
||||
},
|
||||
Key: "ServiceTag",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
CpuPowerManagementInfo: &types.HostCpuPowerManagementInfo{
|
||||
CurrentPolicy: "Balanced",
|
||||
HardwareSupport: "",
|
||||
},
|
||||
CpuInfo: types.HostCpuInfo{
|
||||
NumCpuPackages: 2,
|
||||
NumCpuCores: 2,
|
||||
NumCpuThreads: 2,
|
||||
Hz: 3591345000,
|
||||
},
|
||||
CpuPkg: []types.HostCpuPackage{
|
||||
{
|
||||
Index: 0,
|
||||
Vendor: "intel",
|
||||
Hz: 3591345000,
|
||||
BusHz: 115849838,
|
||||
Description: "Intel(R) Xeon(R) CPU E5-1620 0 @ 3.60GHz",
|
||||
ThreadId: []int16{0},
|
||||
CpuFeature: []types.HostCpuIdInfo{
|
||||
{
|
||||
Level: 0,
|
||||
Vendor: "",
|
||||
Eax: "0000:0000:0000:0000:0000:0000:0000:1101",
|
||||
Ebx: "0111:0101:0110:1110:0110:0101:0100:0111",
|
||||
Ecx: "0110:1100:0110:0101:0111:0100:0110:1110",
|
||||
Edx: "0100:1001:0110:0101:0110:1110:0110:1001",
|
||||
},
|
||||
{
|
||||
Level: 1,
|
||||
Vendor: "",
|
||||
Eax: "0000:0000:0000:0010:0000:0110:1101:0111",
|
||||
Ebx: "0000:0000:0000:0001:0000:1000:0000:0000",
|
||||
Ecx: "1001:0111:1011:1010:0010:0010:0010:1011",
|
||||
Edx: "0000:1111:1010:1011:1111:1011:1111:1111",
|
||||
},
|
||||
{
|
||||
Level: -2147483648,
|
||||
Vendor: "",
|
||||
Eax: "1000:0000:0000:0000:0000:0000:0000:1000",
|
||||
Ebx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
Ecx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
Edx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
},
|
||||
{
|
||||
Level: -2147483647,
|
||||
Vendor: "",
|
||||
Eax: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
Ebx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
Ecx: "0000:0000:0000:0000:0000:0000:0000:0001",
|
||||
Edx: "0010:1000:0001:0000:0000:1000:0000:0000",
|
||||
},
|
||||
{
|
||||
Level: -2147483640,
|
||||
Vendor: "",
|
||||
Eax: "0000:0000:0000:0000:0011:0000:0010:1010",
|
||||
Ebx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
Ecx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
Edx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Index: 1,
|
||||
Vendor: "intel",
|
||||
Hz: 3591345000,
|
||||
BusHz: 115849838,
|
||||
Description: "Intel(R) Xeon(R) CPU E5-1620 0 @ 3.60GHz",
|
||||
ThreadId: []int16{1},
|
||||
CpuFeature: []types.HostCpuIdInfo{
|
||||
{
|
||||
Level: 0,
|
||||
Vendor: "",
|
||||
Eax: "0000:0000:0000:0000:0000:0000:0000:1101",
|
||||
Ebx: "0111:0101:0110:1110:0110:0101:0100:0111",
|
||||
Ecx: "0110:1100:0110:0101:0111:0100:0110:1110",
|
||||
Edx: "0100:1001:0110:0101:0110:1110:0110:1001",
|
||||
},
|
||||
{
|
||||
Level: 1,
|
||||
Vendor: "",
|
||||
Eax: "0000:0000:0000:0010:0000:0110:1101:0111",
|
||||
Ebx: "0000:0010:0000:0001:0000:1000:0000:0000",
|
||||
Ecx: "1001:0111:1011:1010:0010:0010:0010:1011",
|
||||
Edx: "0000:1111:1010:1011:1111:1011:1111:1111",
|
||||
},
|
||||
{
|
||||
Level: -2147483648,
|
||||
Vendor: "",
|
||||
Eax: "1000:0000:0000:0000:0000:0000:0000:1000",
|
||||
Ebx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
Ecx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
Edx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
},
|
||||
{
|
||||
Level: -2147483647,
|
||||
Vendor: "",
|
||||
Eax: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
Ebx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
Ecx: "0000:0000:0000:0000:0000:0000:0000:0001",
|
||||
Edx: "0010:1000:0001:0000:0000:1000:0000:0000",
|
||||
},
|
||||
{
|
||||
Level: -2147483640,
|
||||
Vendor: "",
|
||||
Eax: "0000:0000:0000:0000:0011:0000:0010:1010",
|
||||
Ebx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
Ecx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
Edx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MemorySize: 4294430720,
|
||||
NumaInfo: &types.HostNumaInfo{
|
||||
Type: "NUMA",
|
||||
NumNodes: 1,
|
||||
NumaNode: []types.HostNumaNode{
|
||||
{
|
||||
TypeId: 0x0,
|
||||
CpuID: []int16{1, 0},
|
||||
MemoryRangeBegin: 4294967296,
|
||||
MemoryRangeLength: 1073741824,
|
||||
},
|
||||
},
|
||||
},
|
||||
SmcPresent: types.NewBool(false),
|
||||
PciDevice: []types.HostPciDevice{
|
||||
{
|
||||
Id: "0000:00:00.0",
|
||||
ClassId: 1536,
|
||||
Bus: 0x0,
|
||||
Slot: 0x0,
|
||||
Function: 0x0,
|
||||
VendorId: -32634,
|
||||
SubVendorId: 5549,
|
||||
VendorName: "Intel Corporation",
|
||||
DeviceId: 29072,
|
||||
SubDeviceId: 6518,
|
||||
ParentBridge: "",
|
||||
DeviceName: "Virtual Machine Chipset",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:01.0",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x1,
|
||||
Function: 0x0,
|
||||
VendorId: -32634,
|
||||
SubVendorId: 0,
|
||||
VendorName: "Intel Corporation",
|
||||
DeviceId: 29073,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "440BX/ZX/DX - 82443BX/ZX/DX AGP bridge",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:07.0",
|
||||
ClassId: 1537,
|
||||
Bus: 0x0,
|
||||
Slot: 0x7,
|
||||
Function: 0x0,
|
||||
VendorId: -32634,
|
||||
SubVendorId: 5549,
|
||||
VendorName: "Intel Corporation",
|
||||
DeviceId: 28944,
|
||||
SubDeviceId: 6518,
|
||||
ParentBridge: "",
|
||||
DeviceName: "Virtual Machine Chipset",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:07.1",
|
||||
ClassId: 257,
|
||||
Bus: 0x0,
|
||||
Slot: 0x7,
|
||||
Function: 0x1,
|
||||
VendorId: -32634,
|
||||
SubVendorId: 5549,
|
||||
VendorName: "Intel Corporation",
|
||||
DeviceId: 28945,
|
||||
SubDeviceId: 6518,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PIIX4 for 430TX/440BX/MX IDE Controller",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:07.3",
|
||||
ClassId: 1664,
|
||||
Bus: 0x0,
|
||||
Slot: 0x7,
|
||||
Function: 0x3,
|
||||
VendorId: -32634,
|
||||
SubVendorId: 5549,
|
||||
VendorName: "Intel Corporation",
|
||||
DeviceId: 28947,
|
||||
SubDeviceId: 6518,
|
||||
ParentBridge: "",
|
||||
DeviceName: "Virtual Machine Chipset",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:07.7",
|
||||
ClassId: 2176,
|
||||
Bus: 0x0,
|
||||
Slot: 0x7,
|
||||
Function: 0x7,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 5549,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1856,
|
||||
SubDeviceId: 1856,
|
||||
ParentBridge: "",
|
||||
DeviceName: "Virtual Machine Communication Interface",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:0f.0",
|
||||
ClassId: 768,
|
||||
Bus: 0x0,
|
||||
Slot: 0xf,
|
||||
Function: 0x0,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 5549,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1029,
|
||||
SubDeviceId: 1029,
|
||||
ParentBridge: "",
|
||||
DeviceName: "SVGA II Adapter",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:11.0",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x11,
|
||||
Function: 0x0,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1936,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI bridge",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:15.0",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x15,
|
||||
Function: 0x0,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:15.1",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x15,
|
||||
Function: 0x1,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:15.2",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x15,
|
||||
Function: 0x2,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:15.3",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x15,
|
||||
Function: 0x3,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:15.4",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x15,
|
||||
Function: 0x4,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:15.5",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x15,
|
||||
Function: 0x5,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:15.6",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x15,
|
||||
Function: 0x6,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:15.7",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x15,
|
||||
Function: 0x7,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:16.0",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x16,
|
||||
Function: 0x0,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:16.1",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x16,
|
||||
Function: 0x1,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:16.2",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x16,
|
||||
Function: 0x2,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:16.3",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x16,
|
||||
Function: 0x3,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:16.4",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x16,
|
||||
Function: 0x4,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:16.5",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x16,
|
||||
Function: 0x5,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:16.6",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x16,
|
||||
Function: 0x6,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:16.7",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x16,
|
||||
Function: 0x7,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:17.0",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x17,
|
||||
Function: 0x0,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:17.1",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x17,
|
||||
Function: 0x1,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:17.2",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x17,
|
||||
Function: 0x2,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:17.3",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x17,
|
||||
Function: 0x3,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:17.4",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x17,
|
||||
Function: 0x4,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:17.5",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x17,
|
||||
Function: 0x5,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:17.6",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x17,
|
||||
Function: 0x6,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:17.7",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x17,
|
||||
Function: 0x7,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:18.0",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x18,
|
||||
Function: 0x0,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:18.1",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x18,
|
||||
Function: 0x1,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:18.2",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x18,
|
||||
Function: 0x2,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:18.3",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x18,
|
||||
Function: 0x3,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:18.4",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x18,
|
||||
Function: 0x4,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:18.5",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x18,
|
||||
Function: 0x5,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:18.6",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x18,
|
||||
Function: 0x6,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:00:18.7",
|
||||
ClassId: 1540,
|
||||
Bus: 0x0,
|
||||
Slot: 0x18,
|
||||
Function: 0x7,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 0,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1952,
|
||||
SubDeviceId: 0,
|
||||
ParentBridge: "",
|
||||
DeviceName: "PCI Express Root Port",
|
||||
},
|
||||
{
|
||||
Id: "0000:03:00.0",
|
||||
ClassId: 263,
|
||||
Bus: 0x3,
|
||||
Slot: 0x0,
|
||||
Function: 0x0,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 5549,
|
||||
VendorName: "VMware",
|
||||
DeviceId: 1984,
|
||||
SubDeviceId: 1984,
|
||||
ParentBridge: "0000:00:15.0",
|
||||
DeviceName: "PVSCSI SCSI Controller",
|
||||
},
|
||||
{
|
||||
Id: "0000:0b:00.0",
|
||||
ClassId: 512,
|
||||
Bus: 0xb,
|
||||
Slot: 0x0,
|
||||
Function: 0x0,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 5549,
|
||||
VendorName: "VMware Inc.",
|
||||
DeviceId: 1968,
|
||||
SubDeviceId: 1968,
|
||||
ParentBridge: "0000:00:16.0",
|
||||
DeviceName: "vmxnet3 Virtual Ethernet Controller",
|
||||
},
|
||||
{
|
||||
Id: "0000:13:00.0",
|
||||
ClassId: 512,
|
||||
Bus: 0x13,
|
||||
Slot: 0x0,
|
||||
Function: 0x0,
|
||||
VendorId: 5549,
|
||||
SubVendorId: 5549,
|
||||
VendorName: "VMware Inc.",
|
||||
DeviceId: 1968,
|
||||
SubDeviceId: 1968,
|
||||
ParentBridge: "0000:00:17.0",
|
||||
DeviceName: "vmxnet3 Virtual Ethernet Controller",
|
||||
},
|
||||
},
|
||||
CpuFeature: []types.HostCpuIdInfo{
|
||||
{
|
||||
Level: 0,
|
||||
Vendor: "",
|
||||
Eax: "0000:0000:0000:0000:0000:0000:0000:1101",
|
||||
Ebx: "0111:0101:0110:1110:0110:0101:0100:0111",
|
||||
Ecx: "0110:1100:0110:0101:0111:0100:0110:1110",
|
||||
Edx: "0100:1001:0110:0101:0110:1110:0110:1001",
|
||||
},
|
||||
{
|
||||
Level: 1,
|
||||
Vendor: "",
|
||||
Eax: "0000:0000:0000:0010:0000:0110:1101:0111",
|
||||
Ebx: "0000:0000:0000:0001:0000:1000:0000:0000",
|
||||
Ecx: "1001:0111:1011:1010:0010:0010:0010:1011",
|
||||
Edx: "0000:1111:1010:1011:1111:1011:1111:1111",
|
||||
},
|
||||
{
|
||||
Level: -2147483648,
|
||||
Vendor: "",
|
||||
Eax: "1000:0000:0000:0000:0000:0000:0000:1000",
|
||||
Ebx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
Ecx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
Edx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
},
|
||||
{
|
||||
Level: -2147483647,
|
||||
Vendor: "",
|
||||
Eax: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
Ebx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
Ecx: "0000:0000:0000:0000:0000:0000:0000:0001",
|
||||
Edx: "0010:1000:0001:0000:0000:1000:0000:0000",
|
||||
},
|
||||
{
|
||||
Level: -2147483640,
|
||||
Vendor: "",
|
||||
Eax: "0000:0000:0000:0000:0011:0000:0010:1010",
|
||||
Ebx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
Ecx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
Edx: "0000:0000:0000:0000:0000:0000:0000:0000",
|
||||
},
|
||||
},
|
||||
BiosInfo: &types.HostBIOSInfo{
|
||||
BiosVersion: "6.00",
|
||||
ReleaseDate: nil,
|
||||
Vendor: "",
|
||||
MajorRelease: 0,
|
||||
MinorRelease: 0,
|
||||
FirmwareMajorRelease: 0,
|
||||
FirmwareMinorRelease: 0,
|
||||
},
|
||||
ReliableMemoryInfo: &types.HostReliableMemoryInfo{},
|
||||
}
|
||||
|
||||
func init() {
|
||||
date, _ := time.Parse("2006-01-02", "2015-07-02")
|
||||
|
||||
HostHardwareInfo.BiosInfo.ReleaseDate = &date
|
||||
}
|
||||
346
vendor/github.com/vmware/govmomi/simulator/esx/host_storage_device_info.go
generated
vendored
Normal file
346
vendor/github.com/vmware/govmomi/simulator/esx/host_storage_device_info.go
generated
vendored
Normal file
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package esx
|
||||
|
||||
import "github.com/vmware/govmomi/vim25/types"
|
||||
|
||||
// HostStorageDeviceInfo is the default template for the HostSystem config.storageDevice property.
|
||||
// Capture method:
|
||||
// govc object.collect -s -dump HostSystem:ha-host config.storageDevice
|
||||
var HostStorageDeviceInfo = types.HostStorageDeviceInfo{
|
||||
HostBusAdapter: []types.BaseHostHostBusAdapter{
|
||||
&types.HostParallelScsiHba{
|
||||
HostHostBusAdapter: types.HostHostBusAdapter{
|
||||
Key: "key-vim.host.ParallelScsiHba-vmhba0",
|
||||
Device: "vmhba0",
|
||||
Bus: 3,
|
||||
Status: "unknown",
|
||||
Model: "PVSCSI SCSI Controller",
|
||||
Driver: "pvscsi",
|
||||
Pci: "0000:03:00.0",
|
||||
},
|
||||
},
|
||||
&types.HostBlockHba{
|
||||
HostHostBusAdapter: types.HostHostBusAdapter{
|
||||
Key: "key-vim.host.BlockHba-vmhba1",
|
||||
Device: "vmhba1",
|
||||
Bus: 0,
|
||||
Status: "unknown",
|
||||
Model: "PIIX4 for 430TX/440BX/MX IDE Controller",
|
||||
Driver: "vmkata",
|
||||
Pci: "0000:00:07.1",
|
||||
},
|
||||
},
|
||||
&types.HostBlockHba{
|
||||
HostHostBusAdapter: types.HostHostBusAdapter{
|
||||
Key: "key-vim.host.BlockHba-vmhba64",
|
||||
Device: "vmhba64",
|
||||
Bus: 0,
|
||||
Status: "unknown",
|
||||
Model: "PIIX4 for 430TX/440BX/MX IDE Controller",
|
||||
Driver: "vmkata",
|
||||
Pci: "0000:00:07.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
ScsiLun: []types.BaseScsiLun{
|
||||
&types.ScsiLun{
|
||||
HostDevice: types.HostDevice{
|
||||
DeviceName: "/vmfs/devices/cdrom/mpx.vmhba1:C0:T0:L0",
|
||||
DeviceType: "cdrom",
|
||||
},
|
||||
Key: "key-vim.host.ScsiLun-0005000000766d686261313a303a30",
|
||||
Uuid: "0005000000766d686261313a303a30",
|
||||
Descriptor: []types.ScsiLunDescriptor{
|
||||
{
|
||||
Quality: "lowQuality",
|
||||
Id: "mpx.vmhba1:C0:T0:L0",
|
||||
},
|
||||
{
|
||||
Quality: "lowQuality",
|
||||
Id: "vml.0005000000766d686261313a303a30",
|
||||
},
|
||||
{
|
||||
Quality: "lowQuality",
|
||||
Id: "0005000000766d686261313a303a30",
|
||||
},
|
||||
},
|
||||
CanonicalName: "mpx.vmhba1:C0:T0:L0",
|
||||
DisplayName: "Local NECVMWar CD-ROM (mpx.vmhba1:C0:T0:L0)",
|
||||
LunType: "cdrom",
|
||||
Vendor: "NECVMWar",
|
||||
Model: "VMware IDE CDR00",
|
||||
Revision: "1.00",
|
||||
ScsiLevel: 5,
|
||||
SerialNumber: "unavailable",
|
||||
DurableName: (*types.ScsiLunDurableName)(nil),
|
||||
AlternateName: []types.ScsiLunDurableName{
|
||||
{
|
||||
Namespace: "GENERIC_VPD",
|
||||
NamespaceId: 0x5,
|
||||
Data: []uint8{0x2d, 0x37, 0x39},
|
||||
},
|
||||
{
|
||||
Namespace: "GENERIC_VPD",
|
||||
NamespaceId: 0x5,
|
||||
Data: []uint8{0x30},
|
||||
},
|
||||
},
|
||||
StandardInquiry: []uint8{0x30},
|
||||
QueueDepth: 0,
|
||||
OperationalState: []string{"ok"},
|
||||
Capabilities: &types.ScsiLunCapabilities{},
|
||||
VStorageSupport: "vStorageUnsupported",
|
||||
ProtocolEndpoint: types.NewBool(false),
|
||||
},
|
||||
&types.HostScsiDisk{
|
||||
ScsiLun: types.ScsiLun{
|
||||
HostDevice: types.HostDevice{
|
||||
DeviceName: "/vmfs/devices/disks/mpx.vmhba0:C0:T0:L0",
|
||||
DeviceType: "disk",
|
||||
},
|
||||
Key: "key-vim.host.ScsiDisk-0000000000766d686261303a303a30",
|
||||
Uuid: "0000000000766d686261303a303a30",
|
||||
Descriptor: []types.ScsiLunDescriptor{
|
||||
{
|
||||
Quality: "lowQuality",
|
||||
Id: "mpx.vmhba0:C0:T0:L0",
|
||||
},
|
||||
{
|
||||
Quality: "lowQuality",
|
||||
Id: "vml.0000000000766d686261303a303a30",
|
||||
},
|
||||
{
|
||||
Quality: "lowQuality",
|
||||
Id: "0000000000766d686261303a303a30",
|
||||
},
|
||||
},
|
||||
CanonicalName: "mpx.vmhba0:C0:T0:L0",
|
||||
DisplayName: "Local VMware, Disk (mpx.vmhba0:C0:T0:L0)",
|
||||
LunType: "disk",
|
||||
Vendor: "VMware, ",
|
||||
Model: "VMware Virtual S",
|
||||
Revision: "1.0 ",
|
||||
ScsiLevel: 2,
|
||||
SerialNumber: "unavailable",
|
||||
DurableName: (*types.ScsiLunDurableName)(nil),
|
||||
AlternateName: []types.ScsiLunDurableName{
|
||||
{
|
||||
Namespace: "GENERIC_VPD",
|
||||
NamespaceId: 0x5,
|
||||
Data: []uint8{0x2d, 0x37, 0x39},
|
||||
},
|
||||
{
|
||||
Namespace: "GENERIC_VPD",
|
||||
NamespaceId: 0x5,
|
||||
Data: []uint8{0x30},
|
||||
},
|
||||
},
|
||||
StandardInquiry: []uint8{0x30},
|
||||
QueueDepth: 1024,
|
||||
OperationalState: []string{"ok"},
|
||||
Capabilities: &types.ScsiLunCapabilities{},
|
||||
VStorageSupport: "vStorageUnsupported",
|
||||
ProtocolEndpoint: types.NewBool(false),
|
||||
},
|
||||
Capacity: types.HostDiskDimensionsLba{
|
||||
BlockSize: 512,
|
||||
Block: 67108864,
|
||||
},
|
||||
DevicePath: "/vmfs/devices/disks/mpx.vmhba0:C0:T0:L0",
|
||||
Ssd: types.NewBool(true),
|
||||
LocalDisk: types.NewBool(true),
|
||||
PhysicalLocation: nil,
|
||||
EmulatedDIXDIFEnabled: types.NewBool(false),
|
||||
VsanDiskInfo: (*types.VsanHostVsanDiskInfo)(nil),
|
||||
ScsiDiskType: "native512",
|
||||
},
|
||||
},
|
||||
ScsiTopology: &types.HostScsiTopology{
|
||||
Adapter: []types.HostScsiTopologyInterface{
|
||||
{
|
||||
Key: "key-vim.host.ScsiTopology.Interface-vmhba0",
|
||||
Adapter: "key-vim.host.ParallelScsiHba-vmhba0",
|
||||
Target: []types.HostScsiTopologyTarget{
|
||||
{
|
||||
Key: "key-vim.host.ScsiTopology.Target-vmhba0:0:0",
|
||||
Target: 0,
|
||||
Lun: []types.HostScsiTopologyLun{
|
||||
{
|
||||
Key: "key-vim.host.ScsiTopology.Lun-0000000000766d686261303a303a30",
|
||||
Lun: 0,
|
||||
ScsiLun: "key-vim.host.ScsiDisk-0000000000766d686261303a303a30",
|
||||
},
|
||||
},
|
||||
Transport: &types.HostParallelScsiTargetTransport{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "key-vim.host.ScsiTopology.Interface-vmhba1",
|
||||
Adapter: "key-vim.host.BlockHba-vmhba1",
|
||||
Target: []types.HostScsiTopologyTarget{
|
||||
{
|
||||
Key: "key-vim.host.ScsiTopology.Target-vmhba1:0:0",
|
||||
Target: 0,
|
||||
Lun: []types.HostScsiTopologyLun{
|
||||
{
|
||||
Key: "key-vim.host.ScsiTopology.Lun-0005000000766d686261313a303a30",
|
||||
Lun: 0,
|
||||
ScsiLun: "key-vim.host.ScsiLun-0005000000766d686261313a303a30",
|
||||
},
|
||||
},
|
||||
Transport: &types.HostBlockAdapterTargetTransport{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "key-vim.host.ScsiTopology.Interface-vmhba64",
|
||||
Adapter: "key-vim.host.BlockHba-vmhba64",
|
||||
Target: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
MultipathInfo: &types.HostMultipathInfo{
|
||||
Lun: []types.HostMultipathInfoLogicalUnit{
|
||||
{
|
||||
Key: "key-vim.host.MultipathInfo.LogicalUnit-0005000000766d686261313a303a30",
|
||||
Id: "0005000000766d686261313a303a30",
|
||||
Lun: "key-vim.host.ScsiLun-0005000000766d686261313a303a30",
|
||||
Path: []types.HostMultipathInfoPath{
|
||||
{
|
||||
Key: "key-vim.host.MultipathInfo.Path-vmhba1:C0:T0:L0",
|
||||
Name: "vmhba1:C0:T0:L0",
|
||||
PathState: "active",
|
||||
State: "active",
|
||||
IsWorkingPath: types.NewBool(true),
|
||||
Adapter: "key-vim.host.BlockHba-vmhba1",
|
||||
Lun: "key-vim.host.MultipathInfo.LogicalUnit-0005000000766d686261313a303a30",
|
||||
Transport: &types.HostBlockAdapterTargetTransport{},
|
||||
},
|
||||
},
|
||||
Policy: &types.HostMultipathInfoFixedLogicalUnitPolicy{
|
||||
HostMultipathInfoLogicalUnitPolicy: types.HostMultipathInfoLogicalUnitPolicy{
|
||||
Policy: "VMW_PSP_FIXED",
|
||||
},
|
||||
Prefer: "vmhba1:C0:T0:L0",
|
||||
},
|
||||
StorageArrayTypePolicy: &types.HostMultipathInfoLogicalUnitStorageArrayTypePolicy{
|
||||
Policy: "VMW_SATP_LOCAL",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "key-vim.host.MultipathInfo.LogicalUnit-0000000000766d686261303a303a30",
|
||||
Id: "0000000000766d686261303a303a30",
|
||||
Lun: "key-vim.host.ScsiDisk-0000000000766d686261303a303a30",
|
||||
Path: []types.HostMultipathInfoPath{
|
||||
{
|
||||
Key: "key-vim.host.MultipathInfo.Path-vmhba0:C0:T0:L0",
|
||||
Name: "vmhba0:C0:T0:L0",
|
||||
PathState: "active",
|
||||
State: "active",
|
||||
IsWorkingPath: types.NewBool(true),
|
||||
Adapter: "key-vim.host.ParallelScsiHba-vmhba0",
|
||||
Lun: "key-vim.host.MultipathInfo.LogicalUnit-0000000000766d686261303a303a30",
|
||||
Transport: &types.HostParallelScsiTargetTransport{},
|
||||
},
|
||||
},
|
||||
Policy: &types.HostMultipathInfoFixedLogicalUnitPolicy{
|
||||
HostMultipathInfoLogicalUnitPolicy: types.HostMultipathInfoLogicalUnitPolicy{
|
||||
Policy: "VMW_PSP_FIXED",
|
||||
},
|
||||
Prefer: "vmhba0:C0:T0:L0",
|
||||
},
|
||||
StorageArrayTypePolicy: &types.HostMultipathInfoLogicalUnitStorageArrayTypePolicy{
|
||||
Policy: "VMW_SATP_LOCAL",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
PlugStoreTopology: &types.HostPlugStoreTopology{
|
||||
Adapter: []types.HostPlugStoreTopologyAdapter{
|
||||
{
|
||||
Key: "key-vim.host.PlugStoreTopology.Adapter-vmhba0",
|
||||
Adapter: "key-vim.host.ParallelScsiHba-vmhba0",
|
||||
Path: []string{"key-vim.host.PlugStoreTopology.Path-vmhba0:C0:T0:L0"},
|
||||
},
|
||||
{
|
||||
Key: "key-vim.host.PlugStoreTopology.Adapter-vmhba1",
|
||||
Adapter: "key-vim.host.BlockHba-vmhba1",
|
||||
Path: []string{"key-vim.host.PlugStoreTopology.Path-vmhba1:C0:T0:L0"},
|
||||
},
|
||||
{
|
||||
Key: "key-vim.host.PlugStoreTopology.Adapter-vmhba64",
|
||||
Adapter: "key-vim.host.BlockHba-vmhba64",
|
||||
Path: nil,
|
||||
},
|
||||
},
|
||||
Path: []types.HostPlugStoreTopologyPath{
|
||||
{
|
||||
Key: "key-vim.host.PlugStoreTopology.Path-vmhba0:C0:T0:L0",
|
||||
Name: "vmhba0:C0:T0:L0",
|
||||
ChannelNumber: 0,
|
||||
TargetNumber: 0,
|
||||
LunNumber: 0,
|
||||
Adapter: "key-vim.host.PlugStoreTopology.Adapter-vmhba0",
|
||||
Target: "key-vim.host.PlugStoreTopology.Target-pscsi.0:0",
|
||||
Device: "key-vim.host.PlugStoreTopology.Device-0000000000766d686261303a303a30",
|
||||
},
|
||||
{
|
||||
Key: "key-vim.host.PlugStoreTopology.Path-vmhba1:C0:T0:L0",
|
||||
Name: "vmhba1:C0:T0:L0",
|
||||
ChannelNumber: 0,
|
||||
TargetNumber: 0,
|
||||
LunNumber: 0,
|
||||
Adapter: "key-vim.host.PlugStoreTopology.Adapter-vmhba1",
|
||||
Target: "key-vim.host.PlugStoreTopology.Target-ide.0:0",
|
||||
Device: "key-vim.host.PlugStoreTopology.Device-0005000000766d686261313a303a30",
|
||||
},
|
||||
},
|
||||
Target: []types.HostPlugStoreTopologyTarget{
|
||||
{
|
||||
Key: "key-vim.host.PlugStoreTopology.Target-pscsi.0:0",
|
||||
Transport: &types.HostParallelScsiTargetTransport{},
|
||||
},
|
||||
{
|
||||
Key: "key-vim.host.PlugStoreTopology.Target-ide.0:0",
|
||||
Transport: &types.HostBlockAdapterTargetTransport{},
|
||||
},
|
||||
},
|
||||
Device: []types.HostPlugStoreTopologyDevice{
|
||||
{
|
||||
Key: "key-vim.host.PlugStoreTopology.Device-0005000000766d686261313a303a30",
|
||||
Lun: "key-vim.host.ScsiLun-0005000000766d686261313a303a30",
|
||||
Path: []string{"key-vim.host.PlugStoreTopology.Path-vmhba1:C0:T0:L0"},
|
||||
},
|
||||
{
|
||||
Key: "key-vim.host.PlugStoreTopology.Device-0000000000766d686261303a303a30",
|
||||
Lun: "key-vim.host.ScsiDisk-0000000000766d686261303a303a30",
|
||||
Path: []string{"key-vim.host.PlugStoreTopology.Path-vmhba0:C0:T0:L0"},
|
||||
},
|
||||
},
|
||||
Plugin: []types.HostPlugStoreTopologyPlugin{
|
||||
{
|
||||
Key: "key-vim.host.PlugStoreTopology.Plugin-NMP",
|
||||
Name: "NMP",
|
||||
Device: []string{"key-vim.host.PlugStoreTopology.Device-0005000000766d686261313a303a30", "key-vim.host.PlugStoreTopology.Device-0000000000766d686261303a303a30"},
|
||||
ClaimedPath: []string{"key-vim.host.PlugStoreTopology.Path-vmhba0:C0:T0:L0", "key-vim.host.PlugStoreTopology.Path-vmhba1:C0:T0:L0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
SoftwareInternetScsiEnabled: false,
|
||||
}
|
||||
1791
vendor/github.com/vmware/govmomi/simulator/esx/host_system.go
generated
vendored
Normal file
1791
vendor/github.com/vmware/govmomi/simulator/esx/host_system.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9885
vendor/github.com/vmware/govmomi/simulator/esx/performance_manager.go
generated
vendored
Normal file
9885
vendor/github.com/vmware/govmomi/simulator/esx/performance_manager.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
165
vendor/github.com/vmware/govmomi/simulator/esx/resource_pool.go
generated
vendored
Normal file
165
vendor/github.com/vmware/govmomi/simulator/esx/resource_pool.go
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package esx
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
// ResourcePool is the default template for ResourcePool properties.
|
||||
// Capture method:
|
||||
// govc pool.info "*" -dump
|
||||
var ResourcePool = mo.ResourcePool{
|
||||
ManagedEntity: mo.ManagedEntity{
|
||||
ExtensibleManagedObject: mo.ExtensibleManagedObject{
|
||||
Self: types.ManagedObjectReference{Type: "ResourcePool", Value: "ha-root-pool"},
|
||||
Value: nil,
|
||||
AvailableField: nil,
|
||||
},
|
||||
Parent: &types.ManagedObjectReference{Type: "ComputeResource", Value: "ha-compute-res"},
|
||||
CustomValue: nil,
|
||||
OverallStatus: "green",
|
||||
ConfigStatus: "green",
|
||||
ConfigIssue: nil,
|
||||
EffectiveRole: []int32{-1},
|
||||
Permission: nil,
|
||||
Name: "Resources",
|
||||
DisabledMethod: []string{"CreateVApp", "CreateChildVM_Task"},
|
||||
RecentTask: nil,
|
||||
DeclaredAlarmState: nil,
|
||||
TriggeredAlarmState: nil,
|
||||
AlarmActionsEnabled: (*bool)(nil),
|
||||
Tag: nil,
|
||||
},
|
||||
Summary: &types.ResourcePoolSummary{
|
||||
DynamicData: types.DynamicData{},
|
||||
Name: "Resources",
|
||||
Config: types.ResourceConfigSpec{
|
||||
DynamicData: types.DynamicData{},
|
||||
Entity: &types.ManagedObjectReference{Type: "ResourcePool", Value: "ha-root-pool"},
|
||||
ChangeVersion: "",
|
||||
LastModified: (*time.Time)(nil),
|
||||
CpuAllocation: types.ResourceAllocationInfo{
|
||||
DynamicData: types.DynamicData{},
|
||||
Reservation: types.NewInt64(4121),
|
||||
ExpandableReservation: types.NewBool(false),
|
||||
Limit: types.NewInt64(4121),
|
||||
Shares: &types.SharesInfo{
|
||||
DynamicData: types.DynamicData{},
|
||||
Shares: 9000,
|
||||
Level: "custom",
|
||||
},
|
||||
OverheadLimit: nil,
|
||||
},
|
||||
MemoryAllocation: types.ResourceAllocationInfo{
|
||||
DynamicData: types.DynamicData{},
|
||||
Reservation: types.NewInt64(961),
|
||||
ExpandableReservation: types.NewBool(false),
|
||||
Limit: types.NewInt64(961),
|
||||
Shares: &types.SharesInfo{
|
||||
DynamicData: types.DynamicData{},
|
||||
Shares: 9000,
|
||||
Level: "custom",
|
||||
},
|
||||
OverheadLimit: nil,
|
||||
},
|
||||
},
|
||||
Runtime: types.ResourcePoolRuntimeInfo{
|
||||
DynamicData: types.DynamicData{},
|
||||
Memory: types.ResourcePoolResourceUsage{
|
||||
DynamicData: types.DynamicData{},
|
||||
ReservationUsed: 0,
|
||||
ReservationUsedForVm: 0,
|
||||
UnreservedForPool: 1007681536,
|
||||
UnreservedForVm: 1007681536,
|
||||
OverallUsage: 0,
|
||||
MaxUsage: 1007681536,
|
||||
},
|
||||
Cpu: types.ResourcePoolResourceUsage{
|
||||
DynamicData: types.DynamicData{},
|
||||
ReservationUsed: 0,
|
||||
ReservationUsedForVm: 0,
|
||||
UnreservedForPool: 4121,
|
||||
UnreservedForVm: 4121,
|
||||
OverallUsage: 0,
|
||||
MaxUsage: 4121,
|
||||
},
|
||||
OverallStatus: "green",
|
||||
},
|
||||
QuickStats: (*types.ResourcePoolQuickStats)(nil),
|
||||
ConfiguredMemoryMB: 0,
|
||||
},
|
||||
Runtime: types.ResourcePoolRuntimeInfo{
|
||||
DynamicData: types.DynamicData{},
|
||||
Memory: types.ResourcePoolResourceUsage{
|
||||
DynamicData: types.DynamicData{},
|
||||
ReservationUsed: 0,
|
||||
ReservationUsedForVm: 0,
|
||||
UnreservedForPool: 1007681536,
|
||||
UnreservedForVm: 1007681536,
|
||||
OverallUsage: 0,
|
||||
MaxUsage: 1007681536,
|
||||
},
|
||||
Cpu: types.ResourcePoolResourceUsage{
|
||||
DynamicData: types.DynamicData{},
|
||||
ReservationUsed: 0,
|
||||
ReservationUsedForVm: 0,
|
||||
UnreservedForPool: 4121,
|
||||
UnreservedForVm: 4121,
|
||||
OverallUsage: 0,
|
||||
MaxUsage: 4121,
|
||||
},
|
||||
OverallStatus: "green",
|
||||
},
|
||||
Owner: types.ManagedObjectReference{Type: "ComputeResource", Value: "ha-compute-res"},
|
||||
ResourcePool: nil,
|
||||
Vm: nil,
|
||||
Config: types.ResourceConfigSpec{
|
||||
DynamicData: types.DynamicData{},
|
||||
Entity: &types.ManagedObjectReference{Type: "ResourcePool", Value: "ha-root-pool"},
|
||||
ChangeVersion: "",
|
||||
LastModified: (*time.Time)(nil),
|
||||
CpuAllocation: types.ResourceAllocationInfo{
|
||||
DynamicData: types.DynamicData{},
|
||||
Reservation: types.NewInt64(4121),
|
||||
ExpandableReservation: types.NewBool(false),
|
||||
Limit: types.NewInt64(4121),
|
||||
Shares: &types.SharesInfo{
|
||||
DynamicData: types.DynamicData{},
|
||||
Shares: 9000,
|
||||
Level: "custom",
|
||||
},
|
||||
OverheadLimit: nil,
|
||||
},
|
||||
MemoryAllocation: types.ResourceAllocationInfo{
|
||||
DynamicData: types.DynamicData{},
|
||||
Reservation: types.NewInt64(961),
|
||||
ExpandableReservation: types.NewBool(false),
|
||||
Limit: types.NewInt64(961),
|
||||
Shares: &types.SharesInfo{
|
||||
DynamicData: types.DynamicData{},
|
||||
Shares: 9000,
|
||||
Level: "custom",
|
||||
},
|
||||
OverheadLimit: nil,
|
||||
},
|
||||
},
|
||||
ChildConfiguration: nil,
|
||||
}
|
||||
76
vendor/github.com/vmware/govmomi/simulator/esx/root_folder.go
generated
vendored
Normal file
76
vendor/github.com/vmware/govmomi/simulator/esx/root_folder.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package esx
|
||||
|
||||
import (
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
// RootFolder is the default template for the ServiceContent rootFolder property.
|
||||
// Capture method:
|
||||
// govc folder.info -dump /
|
||||
var RootFolder = mo.Folder{
|
||||
ManagedEntity: mo.ManagedEntity{
|
||||
ExtensibleManagedObject: mo.ExtensibleManagedObject{
|
||||
Self: types.ManagedObjectReference{Type: "Folder", Value: "ha-folder-root"},
|
||||
Value: nil,
|
||||
AvailableField: nil,
|
||||
},
|
||||
Parent: (*types.ManagedObjectReference)(nil),
|
||||
CustomValue: nil,
|
||||
OverallStatus: "green",
|
||||
ConfigStatus: "green",
|
||||
ConfigIssue: nil,
|
||||
EffectiveRole: []int32{-1},
|
||||
Permission: []types.Permission{
|
||||
{
|
||||
DynamicData: types.DynamicData{},
|
||||
Entity: &types.ManagedObjectReference{Type: "Folder", Value: "ha-folder-root"},
|
||||
Principal: "vpxuser",
|
||||
Group: false,
|
||||
RoleId: -1,
|
||||
Propagate: true,
|
||||
},
|
||||
{
|
||||
DynamicData: types.DynamicData{},
|
||||
Entity: &types.ManagedObjectReference{Type: "Folder", Value: "ha-folder-root"},
|
||||
Principal: "dcui",
|
||||
Group: false,
|
||||
RoleId: -1,
|
||||
Propagate: true,
|
||||
},
|
||||
{
|
||||
DynamicData: types.DynamicData{},
|
||||
Entity: &types.ManagedObjectReference{Type: "Folder", Value: "ha-folder-root"},
|
||||
Principal: "root",
|
||||
Group: false,
|
||||
RoleId: -1,
|
||||
Propagate: true,
|
||||
},
|
||||
},
|
||||
Name: "ha-folder-root",
|
||||
DisabledMethod: nil,
|
||||
RecentTask: nil,
|
||||
DeclaredAlarmState: nil,
|
||||
TriggeredAlarmState: nil,
|
||||
AlarmActionsEnabled: (*bool)(nil),
|
||||
Tag: nil,
|
||||
},
|
||||
ChildType: []string{"Datacenter"},
|
||||
ChildEntity: nil,
|
||||
}
|
||||
86
vendor/github.com/vmware/govmomi/simulator/esx/service_content.go
generated
vendored
Normal file
86
vendor/github.com/vmware/govmomi/simulator/esx/service_content.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package esx
|
||||
|
||||
import "github.com/vmware/govmomi/vim25/types"
|
||||
|
||||
// ServiceContent is the default template for the ServiceInstance content property.
|
||||
// Capture method:
|
||||
// govc object.collect -s -dump - content
|
||||
var ServiceContent = types.ServiceContent{
|
||||
RootFolder: types.ManagedObjectReference{Type: "Folder", Value: "ha-folder-root"},
|
||||
PropertyCollector: types.ManagedObjectReference{Type: "PropertyCollector", Value: "ha-property-collector"},
|
||||
ViewManager: &types.ManagedObjectReference{Type: "ViewManager", Value: "ViewManager"},
|
||||
About: types.AboutInfo{
|
||||
Name: "VMware ESXi",
|
||||
FullName: "VMware ESXi 6.5.0 build-5969303",
|
||||
Vendor: "VMware, Inc.",
|
||||
Version: "6.5.0",
|
||||
Build: "5969303",
|
||||
LocaleVersion: "INTL",
|
||||
LocaleBuild: "000",
|
||||
OsType: "vmnix-x86",
|
||||
ProductLineId: "embeddedEsx",
|
||||
ApiType: "HostAgent",
|
||||
ApiVersion: "6.5",
|
||||
InstanceUuid: "",
|
||||
LicenseProductName: "VMware ESX Server",
|
||||
LicenseProductVersion: "6.0",
|
||||
},
|
||||
Setting: &types.ManagedObjectReference{Type: "OptionManager", Value: "HostAgentSettings"},
|
||||
UserDirectory: &types.ManagedObjectReference{Type: "UserDirectory", Value: "ha-user-directory"},
|
||||
SessionManager: &types.ManagedObjectReference{Type: "SessionManager", Value: "ha-sessionmgr"},
|
||||
AuthorizationManager: &types.ManagedObjectReference{Type: "AuthorizationManager", Value: "ha-authmgr"},
|
||||
ServiceManager: &types.ManagedObjectReference{Type: "ServiceManager", Value: "ha-servicemanager"},
|
||||
PerfManager: &types.ManagedObjectReference{Type: "PerformanceManager", Value: "ha-perfmgr"},
|
||||
ScheduledTaskManager: (*types.ManagedObjectReference)(nil),
|
||||
AlarmManager: (*types.ManagedObjectReference)(nil),
|
||||
EventManager: &types.ManagedObjectReference{Type: "EventManager", Value: "ha-eventmgr"},
|
||||
TaskManager: &types.ManagedObjectReference{Type: "TaskManager", Value: "ha-taskmgr"},
|
||||
ExtensionManager: (*types.ManagedObjectReference)(nil),
|
||||
CustomizationSpecManager: (*types.ManagedObjectReference)(nil),
|
||||
CustomFieldsManager: (*types.ManagedObjectReference)(nil),
|
||||
AccountManager: &types.ManagedObjectReference{Type: "HostLocalAccountManager", Value: "ha-localacctmgr"},
|
||||
DiagnosticManager: &types.ManagedObjectReference{Type: "DiagnosticManager", Value: "ha-diagnosticmgr"},
|
||||
LicenseManager: &types.ManagedObjectReference{Type: "LicenseManager", Value: "ha-license-manager"},
|
||||
SearchIndex: &types.ManagedObjectReference{Type: "SearchIndex", Value: "ha-searchindex"},
|
||||
FileManager: &types.ManagedObjectReference{Type: "FileManager", Value: "ha-nfc-file-manager"},
|
||||
DatastoreNamespaceManager: &types.ManagedObjectReference{Type: "DatastoreNamespaceManager", Value: "ha-datastore-namespace-manager"},
|
||||
VirtualDiskManager: &types.ManagedObjectReference{Type: "VirtualDiskManager", Value: "ha-vdiskmanager"},
|
||||
VirtualizationManager: (*types.ManagedObjectReference)(nil),
|
||||
SnmpSystem: (*types.ManagedObjectReference)(nil),
|
||||
VmProvisioningChecker: (*types.ManagedObjectReference)(nil),
|
||||
VmCompatibilityChecker: (*types.ManagedObjectReference)(nil),
|
||||
OvfManager: &types.ManagedObjectReference{Type: "OvfManager", Value: "ha-ovf-manager"},
|
||||
IpPoolManager: (*types.ManagedObjectReference)(nil),
|
||||
DvSwitchManager: &types.ManagedObjectReference{Type: "DistributedVirtualSwitchManager", Value: "ha-dvsmanager"},
|
||||
HostProfileManager: (*types.ManagedObjectReference)(nil),
|
||||
ClusterProfileManager: (*types.ManagedObjectReference)(nil),
|
||||
ComplianceManager: (*types.ManagedObjectReference)(nil),
|
||||
LocalizationManager: &types.ManagedObjectReference{Type: "LocalizationManager", Value: "ha-l10n-manager"},
|
||||
StorageResourceManager: &types.ManagedObjectReference{Type: "StorageResourceManager", Value: "ha-storage-resource-manager"},
|
||||
GuestOperationsManager: &types.ManagedObjectReference{Type: "GuestOperationsManager", Value: "ha-guest-operations-manager"},
|
||||
OverheadMemoryManager: (*types.ManagedObjectReference)(nil),
|
||||
CertificateManager: (*types.ManagedObjectReference)(nil),
|
||||
IoFilterManager: (*types.ManagedObjectReference)(nil),
|
||||
VStorageObjectManager: &types.ManagedObjectReference{Type: "HostVStorageObjectManager", Value: "ha-vstorage-object-manager"},
|
||||
HostSpecManager: (*types.ManagedObjectReference)(nil),
|
||||
CryptoManager: &types.ManagedObjectReference{Type: "CryptoManager", Value: "ha-crypto-manager"},
|
||||
HealthUpdateManager: (*types.ManagedObjectReference)(nil),
|
||||
FailoverClusterConfigurator: (*types.ManagedObjectReference)(nil),
|
||||
FailoverClusterManager: (*types.ManagedObjectReference)(nil),
|
||||
}
|
||||
30
vendor/github.com/vmware/govmomi/simulator/esx/setting.go
generated
vendored
Normal file
30
vendor/github.com/vmware/govmomi/simulator/esx/setting.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package esx
|
||||
|
||||
import "github.com/vmware/govmomi/vim25/types"
|
||||
|
||||
// Setting is captured from ESX's HostSystem.configManager.advancedOption
|
||||
// Capture method:
|
||||
// govc object.collect -s -dump $(govc object.collect -s HostSystem:ha-host configManager.advancedOption) setting
|
||||
var Setting = []types.BaseOptionValue{
|
||||
// This list is currently pruned to include a single option for testing
|
||||
&types.OptionValue{
|
||||
Key: "Config.HostAgent.log.level",
|
||||
Value: "info",
|
||||
},
|
||||
}
|
||||
242
vendor/github.com/vmware/govmomi/simulator/esx/virtual_device.go
generated
vendored
Normal file
242
vendor/github.com/vmware/govmomi/simulator/esx/virtual_device.go
generated
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package esx
|
||||
|
||||
import "github.com/vmware/govmomi/vim25/types"
|
||||
|
||||
// VirtualDevice is the default set of VirtualDevice types created for a VirtualMachine
|
||||
// Capture method:
|
||||
// govc vm.create foo
|
||||
// govc object.collect -s -dump vm/foo config.hardware.device
|
||||
var VirtualDevice = []types.BaseVirtualDevice{
|
||||
&types.VirtualIDEController{
|
||||
VirtualController: types.VirtualController{
|
||||
VirtualDevice: types.VirtualDevice{
|
||||
DynamicData: types.DynamicData{},
|
||||
Key: 200,
|
||||
DeviceInfo: &types.Description{
|
||||
DynamicData: types.DynamicData{},
|
||||
Label: "IDE 0",
|
||||
Summary: "IDE 0",
|
||||
},
|
||||
Backing: nil,
|
||||
Connectable: (*types.VirtualDeviceConnectInfo)(nil),
|
||||
SlotInfo: nil,
|
||||
ControllerKey: 0,
|
||||
UnitNumber: (*int32)(nil),
|
||||
},
|
||||
BusNumber: 0,
|
||||
Device: nil,
|
||||
},
|
||||
},
|
||||
&types.VirtualIDEController{
|
||||
VirtualController: types.VirtualController{
|
||||
VirtualDevice: types.VirtualDevice{
|
||||
DynamicData: types.DynamicData{},
|
||||
Key: 201,
|
||||
DeviceInfo: &types.Description{
|
||||
DynamicData: types.DynamicData{},
|
||||
Label: "IDE 1",
|
||||
Summary: "IDE 1",
|
||||
},
|
||||
Backing: nil,
|
||||
Connectable: (*types.VirtualDeviceConnectInfo)(nil),
|
||||
SlotInfo: nil,
|
||||
ControllerKey: 0,
|
||||
UnitNumber: (*int32)(nil),
|
||||
},
|
||||
BusNumber: 1,
|
||||
Device: nil,
|
||||
},
|
||||
},
|
||||
&types.VirtualPS2Controller{
|
||||
VirtualController: types.VirtualController{
|
||||
VirtualDevice: types.VirtualDevice{
|
||||
DynamicData: types.DynamicData{},
|
||||
Key: 300,
|
||||
DeviceInfo: &types.Description{
|
||||
DynamicData: types.DynamicData{},
|
||||
Label: "PS2 controller 0",
|
||||
Summary: "PS2 controller 0",
|
||||
},
|
||||
Backing: nil,
|
||||
Connectable: (*types.VirtualDeviceConnectInfo)(nil),
|
||||
SlotInfo: nil,
|
||||
ControllerKey: 0,
|
||||
UnitNumber: (*int32)(nil),
|
||||
},
|
||||
BusNumber: 0,
|
||||
Device: []int32{600, 700},
|
||||
},
|
||||
},
|
||||
&types.VirtualPCIController{
|
||||
VirtualController: types.VirtualController{
|
||||
VirtualDevice: types.VirtualDevice{
|
||||
DynamicData: types.DynamicData{},
|
||||
Key: 100,
|
||||
DeviceInfo: &types.Description{
|
||||
DynamicData: types.DynamicData{},
|
||||
Label: "PCI controller 0",
|
||||
Summary: "PCI controller 0",
|
||||
},
|
||||
Backing: nil,
|
||||
Connectable: (*types.VirtualDeviceConnectInfo)(nil),
|
||||
SlotInfo: nil,
|
||||
ControllerKey: 0,
|
||||
UnitNumber: (*int32)(nil),
|
||||
},
|
||||
BusNumber: 0,
|
||||
Device: []int32{500, 12000},
|
||||
},
|
||||
},
|
||||
&types.VirtualSIOController{
|
||||
VirtualController: types.VirtualController{
|
||||
VirtualDevice: types.VirtualDevice{
|
||||
DynamicData: types.DynamicData{},
|
||||
Key: 400,
|
||||
DeviceInfo: &types.Description{
|
||||
DynamicData: types.DynamicData{},
|
||||
Label: "SIO controller 0",
|
||||
Summary: "SIO controller 0",
|
||||
},
|
||||
Backing: nil,
|
||||
Connectable: (*types.VirtualDeviceConnectInfo)(nil),
|
||||
SlotInfo: nil,
|
||||
ControllerKey: 0,
|
||||
UnitNumber: (*int32)(nil),
|
||||
},
|
||||
BusNumber: 0,
|
||||
Device: nil,
|
||||
},
|
||||
},
|
||||
&types.VirtualKeyboard{
|
||||
VirtualDevice: types.VirtualDevice{
|
||||
DynamicData: types.DynamicData{},
|
||||
Key: 600,
|
||||
DeviceInfo: &types.Description{
|
||||
DynamicData: types.DynamicData{},
|
||||
Label: "Keyboard ",
|
||||
Summary: "Keyboard",
|
||||
},
|
||||
Backing: nil,
|
||||
Connectable: (*types.VirtualDeviceConnectInfo)(nil),
|
||||
SlotInfo: nil,
|
||||
ControllerKey: 300,
|
||||
UnitNumber: types.NewInt32(0),
|
||||
},
|
||||
},
|
||||
&types.VirtualPointingDevice{
|
||||
VirtualDevice: types.VirtualDevice{
|
||||
DynamicData: types.DynamicData{},
|
||||
Key: 700,
|
||||
DeviceInfo: &types.Description{
|
||||
DynamicData: types.DynamicData{},
|
||||
Label: "Pointing device",
|
||||
Summary: "Pointing device; Device",
|
||||
},
|
||||
Backing: &types.VirtualPointingDeviceDeviceBackingInfo{
|
||||
VirtualDeviceDeviceBackingInfo: types.VirtualDeviceDeviceBackingInfo{
|
||||
VirtualDeviceBackingInfo: types.VirtualDeviceBackingInfo{},
|
||||
DeviceName: "",
|
||||
UseAutoDetect: types.NewBool(false),
|
||||
},
|
||||
HostPointingDevice: "autodetect",
|
||||
},
|
||||
Connectable: (*types.VirtualDeviceConnectInfo)(nil),
|
||||
SlotInfo: nil,
|
||||
ControllerKey: 300,
|
||||
UnitNumber: types.NewInt32(1),
|
||||
},
|
||||
},
|
||||
&types.VirtualMachineVideoCard{
|
||||
VirtualDevice: types.VirtualDevice{
|
||||
DynamicData: types.DynamicData{},
|
||||
Key: 500,
|
||||
DeviceInfo: &types.Description{
|
||||
DynamicData: types.DynamicData{},
|
||||
Label: "Video card ",
|
||||
Summary: "Video card",
|
||||
},
|
||||
Backing: nil,
|
||||
Connectable: (*types.VirtualDeviceConnectInfo)(nil),
|
||||
SlotInfo: nil,
|
||||
ControllerKey: 100,
|
||||
UnitNumber: types.NewInt32(0),
|
||||
},
|
||||
VideoRamSizeInKB: 4096,
|
||||
NumDisplays: 1,
|
||||
UseAutoDetect: types.NewBool(false),
|
||||
Enable3DSupport: types.NewBool(false),
|
||||
Use3dRenderer: "automatic",
|
||||
GraphicsMemorySizeInKB: 262144,
|
||||
},
|
||||
&types.VirtualMachineVMCIDevice{
|
||||
VirtualDevice: types.VirtualDevice{
|
||||
DynamicData: types.DynamicData{},
|
||||
Key: 12000,
|
||||
DeviceInfo: &types.Description{
|
||||
DynamicData: types.DynamicData{},
|
||||
Label: "VMCI device",
|
||||
Summary: "Device on the virtual machine PCI bus that provides support for the virtual machine communication interface",
|
||||
},
|
||||
Backing: nil,
|
||||
Connectable: (*types.VirtualDeviceConnectInfo)(nil),
|
||||
SlotInfo: nil,
|
||||
ControllerKey: 100,
|
||||
UnitNumber: types.NewInt32(17),
|
||||
},
|
||||
Id: -1,
|
||||
AllowUnrestrictedCommunication: types.NewBool(false),
|
||||
FilterEnable: types.NewBool(true),
|
||||
FilterInfo: (*types.VirtualMachineVMCIDeviceFilterInfo)(nil),
|
||||
},
|
||||
}
|
||||
|
||||
// EthernetCard template for types.VirtualEthernetCard
|
||||
var EthernetCard = types.VirtualE1000{
|
||||
VirtualEthernetCard: types.VirtualEthernetCard{
|
||||
VirtualDevice: types.VirtualDevice{
|
||||
DynamicData: types.DynamicData{},
|
||||
Key: 4000,
|
||||
Backing: &types.VirtualEthernetCardNetworkBackingInfo{
|
||||
VirtualDeviceDeviceBackingInfo: types.VirtualDeviceDeviceBackingInfo{
|
||||
VirtualDeviceBackingInfo: types.VirtualDeviceBackingInfo{},
|
||||
DeviceName: "VM Network",
|
||||
UseAutoDetect: types.NewBool(false),
|
||||
},
|
||||
Network: (*types.ManagedObjectReference)(nil),
|
||||
InPassthroughMode: types.NewBool(false),
|
||||
},
|
||||
Connectable: &types.VirtualDeviceConnectInfo{
|
||||
DynamicData: types.DynamicData{},
|
||||
StartConnected: true,
|
||||
AllowGuestControl: true,
|
||||
Connected: false,
|
||||
Status: "untried",
|
||||
},
|
||||
SlotInfo: &types.VirtualDevicePciBusSlotInfo{
|
||||
VirtualDeviceBusSlotInfo: types.VirtualDeviceBusSlotInfo{},
|
||||
PciSlotNumber: 32,
|
||||
},
|
||||
ControllerKey: 100,
|
||||
UnitNumber: types.NewInt32(7),
|
||||
},
|
||||
AddressType: "generated",
|
||||
MacAddress: "",
|
||||
WakeOnLanEnabled: types.NewBool(true),
|
||||
},
|
||||
}
|
||||
423
vendor/github.com/vmware/govmomi/simulator/event_manager.go
generated
vendored
Normal file
423
vendor/github.com/vmware/govmomi/simulator/event_manager.go
generated
vendored
Normal file
@@ -0,0 +1,423 @@
|
||||
/*
|
||||
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"container/ring"
|
||||
"log"
|
||||
"reflect"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
var (
|
||||
maxPageSize = 1000
|
||||
logEvents = false
|
||||
)
|
||||
|
||||
type EventManager struct {
|
||||
mo.EventManager
|
||||
|
||||
root types.ManagedObjectReference
|
||||
page *ring.Ring
|
||||
key int32
|
||||
collectors map[types.ManagedObjectReference]*EventHistoryCollector
|
||||
templates map[string]*template.Template
|
||||
}
|
||||
|
||||
func NewEventManager(ref types.ManagedObjectReference) object.Reference {
|
||||
return &EventManager{
|
||||
EventManager: mo.EventManager{
|
||||
Self: ref,
|
||||
Description: types.EventDescription{
|
||||
EventInfo: esx.EventInfo,
|
||||
},
|
||||
MaxCollector: 1000,
|
||||
},
|
||||
root: Map.content().RootFolder,
|
||||
page: ring.New(maxPageSize),
|
||||
collectors: make(map[types.ManagedObjectReference]*EventHistoryCollector),
|
||||
templates: make(map[string]*template.Template),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *EventManager) createCollector(ctx *Context, req *types.CreateCollectorForEvents) (*EventHistoryCollector, *soap.Fault) {
|
||||
size, err := validatePageSize(req.Filter.MaxCount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(m.collectors) >= int(m.MaxCollector) {
|
||||
return nil, Fault("Too many event collectors to create", new(types.InvalidState))
|
||||
}
|
||||
|
||||
collector := &EventHistoryCollector{
|
||||
m: m,
|
||||
page: ring.New(size),
|
||||
}
|
||||
collector.Filter = req.Filter
|
||||
collector.fillPage(size)
|
||||
|
||||
return collector, nil
|
||||
}
|
||||
|
||||
func (m *EventManager) CreateCollectorForEvents(ctx *Context, req *types.CreateCollectorForEvents) soap.HasFault {
|
||||
body := new(methods.CreateCollectorForEventsBody)
|
||||
collector, err := m.createCollector(ctx, req)
|
||||
if err != nil {
|
||||
body.Fault_ = err
|
||||
return body
|
||||
}
|
||||
|
||||
ref := ctx.Session.Put(collector).Reference()
|
||||
m.collectors[ref] = collector
|
||||
|
||||
body.Res = &types.CreateCollectorForEventsResponse{
|
||||
Returnval: ref,
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (m *EventManager) QueryEvents(ctx *Context, req *types.QueryEvents) soap.HasFault {
|
||||
if Map.IsESX() {
|
||||
return &methods.QueryEventsBody{
|
||||
Fault_: Fault("", new(types.NotImplemented)),
|
||||
}
|
||||
}
|
||||
|
||||
body := new(methods.QueryEventsBody)
|
||||
collector, err := m.createCollector(ctx, &types.CreateCollectorForEvents{Filter: req.Filter})
|
||||
if err != nil {
|
||||
body.Fault_ = err
|
||||
return body
|
||||
}
|
||||
|
||||
body.Res = &types.QueryEventsResponse{
|
||||
Returnval: collector.GetLatestPage(),
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
// formatMessage applies the EventDescriptionEventDetail.FullFormat template to the given event's FullFormattedMessage field.
|
||||
func (m *EventManager) formatMessage(event types.BaseEvent) {
|
||||
id := reflect.ValueOf(event).Elem().Type().Name()
|
||||
e := event.GetEvent()
|
||||
|
||||
t, ok := m.templates[id]
|
||||
if !ok {
|
||||
for _, info := range m.Description.EventInfo {
|
||||
if info.Key == id {
|
||||
t = template.Must(template.New(id).Parse(info.FullFormat))
|
||||
m.templates[id] = t
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := t.Execute(&buf, event); err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
e.FullFormattedMessage = buf.String()
|
||||
|
||||
if logEvents {
|
||||
log.Printf("[%s] %s", id, e.FullFormattedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *EventManager) PostEvent(ctx *Context, req *types.PostEvent) soap.HasFault {
|
||||
m.key++
|
||||
event := req.EventToPost.GetEvent()
|
||||
event.Key = m.key
|
||||
event.ChainId = event.Key
|
||||
event.CreatedTime = time.Now()
|
||||
event.UserName = ctx.Session.UserName
|
||||
|
||||
m.page = m.page.Next()
|
||||
m.page.Value = req.EventToPost
|
||||
m.formatMessage(req.EventToPost)
|
||||
|
||||
for _, c := range m.collectors {
|
||||
if c.eventMatches(req.EventToPost) {
|
||||
c.page = c.page.Next()
|
||||
c.page.Value = event
|
||||
}
|
||||
}
|
||||
|
||||
return &methods.PostEventBody{
|
||||
Res: new(types.PostEventResponse),
|
||||
}
|
||||
}
|
||||
|
||||
type EventHistoryCollector struct {
|
||||
mo.EventHistoryCollector
|
||||
|
||||
m *EventManager
|
||||
page *ring.Ring
|
||||
}
|
||||
|
||||
// doEntityEventArgument calls f for each entity argument in the event.
|
||||
// If f returns true, the iteration stops.
|
||||
func doEntityEventArgument(event types.BaseEvent, f func(types.ManagedObjectReference, *types.EntityEventArgument) bool) bool {
|
||||
e := event.GetEvent()
|
||||
|
||||
if arg := e.Vm; arg != nil {
|
||||
if f(arg.Vm, &arg.EntityEventArgument) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if arg := e.Host; arg != nil {
|
||||
if f(arg.Host, &arg.EntityEventArgument) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if arg := e.ComputeResource; arg != nil {
|
||||
if f(arg.ComputeResource, &arg.EntityEventArgument) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if arg := e.Ds; arg != nil {
|
||||
if f(arg.Datastore, &arg.EntityEventArgument) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if arg := e.Net; arg != nil {
|
||||
if f(arg.Network, &arg.EntityEventArgument) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if arg := e.Dvs; arg != nil {
|
||||
if f(arg.Dvs, &arg.EntityEventArgument) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if arg := e.Datacenter; arg != nil {
|
||||
if f(arg.Datacenter, &arg.EntityEventArgument) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// eventFilterSelf returns true if self is one of the entity arguments in the event.
|
||||
func eventFilterSelf(event types.BaseEvent, self types.ManagedObjectReference) bool {
|
||||
return doEntityEventArgument(event, func(ref types.ManagedObjectReference, _ *types.EntityEventArgument) bool {
|
||||
return self == ref
|
||||
})
|
||||
}
|
||||
|
||||
// eventFilterChildren returns true if a child of self is one of the entity arguments in the event.
|
||||
func eventFilterChildren(event types.BaseEvent, self types.ManagedObjectReference) bool {
|
||||
return doEntityEventArgument(event, func(ref types.ManagedObjectReference, _ *types.EntityEventArgument) bool {
|
||||
seen := false
|
||||
|
||||
var match func(types.ManagedObjectReference)
|
||||
|
||||
match = func(child types.ManagedObjectReference) {
|
||||
if child == self {
|
||||
seen = true
|
||||
return
|
||||
}
|
||||
|
||||
walk(child, match)
|
||||
}
|
||||
|
||||
walk(ref, match)
|
||||
|
||||
return seen
|
||||
})
|
||||
}
|
||||
|
||||
// entityMatches returns true if the spec Entity filter matches the event.
|
||||
func (c *EventHistoryCollector) entityMatches(event types.BaseEvent, spec *types.EventFilterSpec) bool {
|
||||
e := spec.Entity
|
||||
if e == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
isRootFolder := c.m.root == e.Entity
|
||||
|
||||
switch e.Recursion {
|
||||
case types.EventFilterSpecRecursionOptionSelf:
|
||||
return isRootFolder || eventFilterSelf(event, e.Entity)
|
||||
case types.EventFilterSpecRecursionOptionChildren:
|
||||
return eventFilterChildren(event, e.Entity)
|
||||
case types.EventFilterSpecRecursionOptionAll:
|
||||
if isRootFolder || eventFilterSelf(event, e.Entity) {
|
||||
return true
|
||||
}
|
||||
return eventFilterChildren(event, e.Entity)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// typeMatches returns true if one of the spec EventTypeId types matches the event.
|
||||
func (c *EventHistoryCollector) typeMatches(event types.BaseEvent, spec *types.EventFilterSpec) bool {
|
||||
if len(spec.EventTypeId) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
matches := func(name string) bool {
|
||||
for _, id := range spec.EventTypeId {
|
||||
if id == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
kind := reflect.ValueOf(event).Elem().Type()
|
||||
|
||||
if matches(kind.Name()) {
|
||||
return true // concrete type
|
||||
}
|
||||
|
||||
field, ok := kind.FieldByNameFunc(matches)
|
||||
if ok {
|
||||
return field.Anonymous // base type (embedded field)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// eventMatches returns true one of the filters matches the event.
|
||||
func (c *EventHistoryCollector) eventMatches(event types.BaseEvent) bool {
|
||||
spec := c.Filter.(types.EventFilterSpec)
|
||||
|
||||
if !c.typeMatches(event, &spec) {
|
||||
return false
|
||||
}
|
||||
|
||||
// TODO: spec.Time, spec.UserName, etc
|
||||
|
||||
return c.entityMatches(event, &spec)
|
||||
}
|
||||
|
||||
// filePage copies the manager's latest events into the collector's page with Filter applied.
|
||||
func (c *EventHistoryCollector) fillPage(size int) {
|
||||
l := c.page.Len()
|
||||
delta := size - l
|
||||
|
||||
if delta < 0 {
|
||||
// Shrink ring size
|
||||
c.page = c.page.Unlink(-delta)
|
||||
return
|
||||
}
|
||||
|
||||
matches := 0
|
||||
mpage := c.m.page
|
||||
page := c.page
|
||||
|
||||
if delta != 0 {
|
||||
// Grow ring size
|
||||
c.page = c.page.Link(ring.New(delta))
|
||||
}
|
||||
|
||||
for i := 0; i < maxPageSize; i++ {
|
||||
event, ok := mpage.Value.(types.BaseEvent)
|
||||
mpage = mpage.Prev()
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if c.eventMatches(event) {
|
||||
page.Value = event
|
||||
page = page.Prev()
|
||||
matches++
|
||||
if matches == size {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func validatePageSize(count int32) (int, *soap.Fault) {
|
||||
size := int(count)
|
||||
|
||||
if size == 0 {
|
||||
size = 10 // defaultPageSize
|
||||
} else if size < 0 || size > maxPageSize {
|
||||
return -1, Fault("", &types.InvalidArgument{InvalidProperty: "maxCount"})
|
||||
}
|
||||
|
||||
return size, nil
|
||||
}
|
||||
|
||||
func (c *EventHistoryCollector) SetCollectorPageSize(ctx *Context, req *types.SetCollectorPageSize) soap.HasFault {
|
||||
body := new(methods.SetCollectorPageSizeBody)
|
||||
size, err := validatePageSize(req.MaxCount)
|
||||
if err != nil {
|
||||
body.Fault_ = err
|
||||
return body
|
||||
}
|
||||
|
||||
ctx.WithLock(c.m, func() {
|
||||
c.fillPage(size)
|
||||
})
|
||||
|
||||
body.Res = new(types.SetCollectorPageSizeResponse)
|
||||
return body
|
||||
}
|
||||
|
||||
func (c *EventHistoryCollector) DestroyCollector(ctx *Context, req *types.DestroyCollector) soap.HasFault {
|
||||
ctx.Session.Remove(req.This)
|
||||
|
||||
ctx.WithLock(c.m, func() {
|
||||
delete(c.m.collectors, req.This)
|
||||
})
|
||||
|
||||
return &methods.DestroyCollectorBody{
|
||||
Res: new(types.DestroyCollectorResponse),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *EventHistoryCollector) GetLatestPage() []types.BaseEvent {
|
||||
var latestPage []types.BaseEvent
|
||||
|
||||
c.page.Do(func(val interface{}) {
|
||||
if val == nil {
|
||||
return
|
||||
}
|
||||
latestPage = append(latestPage, val.(types.BaseEvent))
|
||||
})
|
||||
|
||||
return latestPage
|
||||
}
|
||||
|
||||
func (c *EventHistoryCollector) Get() mo.Reference {
|
||||
clone := *c
|
||||
|
||||
clone.LatestPage = clone.GetLatestPage()
|
||||
|
||||
return &clone
|
||||
}
|
||||
117
vendor/github.com/vmware/govmomi/simulator/event_manager_test.go
generated
vendored
Normal file
117
vendor/github.com/vmware/govmomi/simulator/event_manager_test.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/event"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestEventManagerVPX(t *testing.T) {
|
||||
logEvents = testing.Verbose()
|
||||
ctx := context.Background()
|
||||
|
||||
m := VPX()
|
||||
m.Datacenter = 2
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
e := event.NewManager(c.Client)
|
||||
count := m.Count()
|
||||
|
||||
root := c.ServiceContent.RootFolder
|
||||
vm := Map.Any("VirtualMachine").(*VirtualMachine)
|
||||
host := Map.Get(vm.Runtime.Host.Reference()).(*HostSystem)
|
||||
|
||||
vmEvents := 6 // BeingCreated + InstanceUuid + Uuid + Created + Starting + PoweredOn
|
||||
tests := []struct {
|
||||
obj types.ManagedObjectReference
|
||||
expect int
|
||||
ids []string
|
||||
}{
|
||||
{root, -1 * count.Machine, nil},
|
||||
{root, 1, []string{"SessionEvent"}}, // UserLoginSessionEvent
|
||||
{vm.Reference(), 0, []string{"SessionEvent"}},
|
||||
{root, count.Machine, []string{"VmCreatedEvent"}}, // concrete type
|
||||
{root, count.Machine * vmEvents, []string{"VmEvent"}}, // base type
|
||||
{vm.Reference(), 1, []string{"VmCreatedEvent"}},
|
||||
{vm.Reference(), vmEvents, nil},
|
||||
{host.Reference(), len(host.Vm), []string{"VmCreatedEvent"}},
|
||||
{host.Reference(), len(host.Vm) * vmEvents, nil},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
n := 0
|
||||
filter := types.EventFilterSpec{
|
||||
Entity: &types.EventFilterSpecByEntity{
|
||||
Entity: test.obj,
|
||||
Recursion: types.EventFilterSpecRecursionOptionAll,
|
||||
},
|
||||
EventTypeId: test.ids,
|
||||
MaxCount: 100,
|
||||
}
|
||||
|
||||
f := func(obj types.ManagedObjectReference, events []types.BaseEvent) error {
|
||||
n += len(events)
|
||||
|
||||
qevents, qerr := e.QueryEvents(ctx, filter)
|
||||
if qerr != nil {
|
||||
t.Fatal(qerr)
|
||||
}
|
||||
|
||||
if n != len(qevents) {
|
||||
t.Errorf("%d vs %d", n, len(qevents))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
err = e.Events(ctx, []types.ManagedObjectReference{test.obj}, filter.MaxCount, false, false, f, test.ids...)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: %s", i, err)
|
||||
}
|
||||
|
||||
if test.expect < 0 {
|
||||
expect := test.expect * -1
|
||||
if n < expect {
|
||||
t.Errorf("%d: expected at least %d events, got: %d", i, expect, n)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if test.expect != n {
|
||||
t.Errorf("%d: expected %d events, got: %d", i, test.expect, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
112
vendor/github.com/vmware/govmomi/simulator/example_extend_test.go
generated
vendored
Normal file
112
vendor/github.com/vmware/govmomi/simulator/example_extend_test.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/simulator"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
// BusyVM changes the behavior of simulator.VirtualMachine
|
||||
type BusyVM struct {
|
||||
*simulator.VirtualMachine
|
||||
}
|
||||
|
||||
// Override simulator.VirtualMachine.PowerOffVMTask to inject faults
|
||||
func (vm *BusyVM) PowerOffVMTask(req *types.PowerOffVM_Task) soap.HasFault {
|
||||
task := simulator.CreateTask(req.This, "powerOff", func(*simulator.Task) (types.AnyType, types.BaseMethodFault) {
|
||||
return nil, &types.TaskInProgress{}
|
||||
})
|
||||
|
||||
return &methods.PowerOffVM_TaskBody{
|
||||
Res: &types.PowerOffVM_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Add AcquireTicket method, not implemented by simulator.VirtualMachine
|
||||
func (vm *BusyVM) AcquireTicket(req *types.AcquireTicket) soap.HasFault {
|
||||
body := &methods.AcquireTicketBody{}
|
||||
|
||||
if req.TicketType != "mks" {
|
||||
body.Fault_ = simulator.Fault("", &types.InvalidArgument{})
|
||||
}
|
||||
|
||||
body.Res = &types.AcquireTicketResponse{
|
||||
Returnval: types.VirtualMachineTicket{
|
||||
Ticket: "welcome 2 the machine",
|
||||
},
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
// Example of extending the simulator to inject faults.
|
||||
func Example() {
|
||||
ctx := context.Background()
|
||||
model := simulator.VPX()
|
||||
|
||||
defer model.Remove()
|
||||
_ = model.Create()
|
||||
|
||||
s := model.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
// NewClient connects to s.URL over https and invokes 2 SOAP methods (RetrieveServiceContent + Login)
|
||||
c, _ := govmomi.NewClient(ctx, s.URL, true)
|
||||
|
||||
// Shortcut to choose any VM, rather than using the more verbose Finder or ContainerView.
|
||||
obj := simulator.Map.Any("VirtualMachine").(*simulator.VirtualMachine)
|
||||
// Validate VM is powered on
|
||||
if obj.Runtime.PowerState != "poweredOn" {
|
||||
log.Fatal(obj.Runtime.PowerState)
|
||||
}
|
||||
|
||||
// Wrap the existing vm object, using the same vm.Self (ManagedObjectReference) value as the Map key.
|
||||
simulator.Map.Put(&BusyVM{obj})
|
||||
|
||||
vm := object.NewVirtualMachine(c.Client, obj.Reference())
|
||||
|
||||
// Start a PowerOff task using the SOAP client.
|
||||
task, _ := vm.PowerOff(ctx)
|
||||
|
||||
// Wait for task completion, expecting failure.
|
||||
err := task.Wait(ctx)
|
||||
if err == nil {
|
||||
log.Fatal("expected error")
|
||||
}
|
||||
|
||||
// Invalid ticket type, expecting failure.
|
||||
_, err = vm.AcquireTicket(ctx, "pks")
|
||||
if err == nil {
|
||||
log.Fatal("expected error")
|
||||
}
|
||||
|
||||
mks, _ := vm.AcquireTicket(ctx, "mks")
|
||||
|
||||
fmt.Println(mks.Ticket, obj.Runtime.PowerState)
|
||||
// Output: welcome 2 the machine poweredOn
|
||||
}
|
||||
92
vendor/github.com/vmware/govmomi/simulator/example_test.go
generated
vendored
Normal file
92
vendor/github.com/vmware/govmomi/simulator/example_test.go
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/simulator"
|
||||
)
|
||||
|
||||
// Example boilerplate for starting a simulator initialized with an ESX model.
|
||||
func ExampleESX() {
|
||||
ctx := context.Background()
|
||||
|
||||
// ESXi model + initial set of objects (VMs, network, datastore)
|
||||
model := simulator.ESX()
|
||||
|
||||
defer model.Remove()
|
||||
err := model.Create()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
s := model.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, _ := govmomi.NewClient(ctx, s.URL, true)
|
||||
|
||||
fmt.Printf("%s with %d host", c.Client.ServiceContent.About.ApiType, model.Count().Host)
|
||||
// Output: HostAgent with 1 host
|
||||
}
|
||||
|
||||
// Example for starting a simulator with empty inventory, similar to a fresh install of vCenter.
|
||||
func ExampleModel() {
|
||||
ctx := context.Background()
|
||||
|
||||
model := simulator.VPX()
|
||||
model.Datacenter = 0 // No DC == no inventory
|
||||
|
||||
defer model.Remove()
|
||||
err := model.Create()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
s := model.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, _ := govmomi.NewClient(ctx, s.URL, true)
|
||||
|
||||
fmt.Printf("%s with %d hosts", c.Client.ServiceContent.About.ApiType, model.Count().Host)
|
||||
// Output: VirtualCenter with 0 hosts
|
||||
}
|
||||
|
||||
// Example boilerplate for starting a simulator initialized with a vCenter model.
|
||||
func ExampleVPX() {
|
||||
ctx := context.Background()
|
||||
|
||||
// vCenter model + initial set of objects (cluster, hosts, VMs, network, datastore, etc)
|
||||
model := simulator.VPX()
|
||||
|
||||
defer model.Remove()
|
||||
err := model.Create()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
s := model.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, _ := govmomi.NewClient(ctx, s.URL, true)
|
||||
|
||||
fmt.Printf("%s with %d hosts", c.Client.ServiceContent.About.ApiType, model.Count().Host)
|
||||
// Output: VirtualCenter with 4 hosts
|
||||
}
|
||||
252
vendor/github.com/vmware/govmomi/simulator/file_manager.go
generated
vendored
Normal file
252
vendor/github.com/vmware/govmomi/simulator/file_manager.go
generated
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type FileManager struct {
|
||||
mo.FileManager
|
||||
}
|
||||
|
||||
func NewFileManager(ref types.ManagedObjectReference) object.Reference {
|
||||
m := &FileManager{}
|
||||
m.Self = ref
|
||||
return m
|
||||
}
|
||||
|
||||
func (f *FileManager) findDatastore(ref mo.Reference, name string) (*Datastore, types.BaseMethodFault) {
|
||||
var refs []types.ManagedObjectReference
|
||||
|
||||
switch obj := ref.(type) {
|
||||
case *Folder:
|
||||
refs = obj.ChildEntity
|
||||
case *StoragePod:
|
||||
refs = obj.ChildEntity
|
||||
}
|
||||
|
||||
for _, ref := range refs {
|
||||
switch obj := Map.Get(ref).(type) {
|
||||
case *Datastore:
|
||||
if obj.Name == name {
|
||||
return obj, nil
|
||||
}
|
||||
case *Folder, *StoragePod:
|
||||
ds, _ := f.findDatastore(obj, name)
|
||||
if ds != nil {
|
||||
return ds, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, &types.InvalidDatastore{Name: name}
|
||||
}
|
||||
|
||||
func (f *FileManager) resolve(dc *types.ManagedObjectReference, name string) (string, types.BaseMethodFault) {
|
||||
p, fault := parseDatastorePath(name)
|
||||
if fault != nil {
|
||||
return "", fault
|
||||
}
|
||||
|
||||
if dc == nil {
|
||||
if Map.IsESX() {
|
||||
dc = &esx.Datacenter.Self
|
||||
} else {
|
||||
return "", &types.InvalidArgument{InvalidProperty: "dc"}
|
||||
}
|
||||
}
|
||||
|
||||
folder := Map.Get(*dc).(*Datacenter).DatastoreFolder
|
||||
|
||||
ds, fault := f.findDatastore(Map.Get(folder), p.Datastore)
|
||||
if fault != nil {
|
||||
return "", fault
|
||||
}
|
||||
|
||||
dir := ds.Info.GetDatastoreInfo().Url
|
||||
|
||||
return path.Join(dir, p.Path), nil
|
||||
}
|
||||
|
||||
func (f *FileManager) fault(name string, err error, fault types.BaseFileFault) types.BaseMethodFault {
|
||||
switch {
|
||||
case os.IsNotExist(err):
|
||||
fault = new(types.FileNotFound)
|
||||
case os.IsExist(err):
|
||||
fault = new(types.FileAlreadyExists)
|
||||
}
|
||||
|
||||
fault.GetFileFault().File = name
|
||||
|
||||
return fault.(types.BaseMethodFault)
|
||||
}
|
||||
|
||||
func (f *FileManager) deleteDatastoreFile(req *types.DeleteDatastoreFile_Task) types.BaseMethodFault {
|
||||
file, fault := f.resolve(req.Datacenter, req.Name)
|
||||
if fault != nil {
|
||||
return fault
|
||||
}
|
||||
|
||||
_, err := os.Stat(file)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return f.fault(file, err, new(types.CannotDeleteFile))
|
||||
}
|
||||
}
|
||||
|
||||
err = os.RemoveAll(file)
|
||||
if err != nil {
|
||||
return f.fault(file, err, new(types.CannotDeleteFile))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FileManager) DeleteDatastoreFileTask(req *types.DeleteDatastoreFile_Task) soap.HasFault {
|
||||
task := CreateTask(f, "deleteDatastoreFile", func(*Task) (types.AnyType, types.BaseMethodFault) {
|
||||
return nil, f.deleteDatastoreFile(req)
|
||||
})
|
||||
|
||||
return &methods.DeleteDatastoreFile_TaskBody{
|
||||
Res: &types.DeleteDatastoreFile_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FileManager) MakeDirectory(req *types.MakeDirectory) soap.HasFault {
|
||||
body := &methods.MakeDirectoryBody{}
|
||||
|
||||
name, fault := f.resolve(req.Datacenter, req.Name)
|
||||
if fault != nil {
|
||||
body.Fault_ = Fault("", fault)
|
||||
return body
|
||||
}
|
||||
|
||||
mkdir := os.Mkdir
|
||||
|
||||
if isTrue(req.CreateParentDirectories) {
|
||||
mkdir = os.MkdirAll
|
||||
}
|
||||
|
||||
err := mkdir(name, 0700)
|
||||
if err != nil {
|
||||
fault = f.fault(req.Name, err, new(types.CannotCreateFile))
|
||||
body.Fault_ = Fault(err.Error(), fault)
|
||||
return body
|
||||
}
|
||||
|
||||
body.Res = new(types.MakeDirectoryResponse)
|
||||
return body
|
||||
}
|
||||
|
||||
func (f *FileManager) moveDatastoreFile(req *types.MoveDatastoreFile_Task) types.BaseMethodFault {
|
||||
src, fault := f.resolve(req.SourceDatacenter, req.SourceName)
|
||||
if fault != nil {
|
||||
return fault
|
||||
}
|
||||
|
||||
dst, fault := f.resolve(req.DestinationDatacenter, req.DestinationName)
|
||||
if fault != nil {
|
||||
return fault
|
||||
}
|
||||
|
||||
if !isTrue(req.Force) {
|
||||
_, err := os.Stat(dst)
|
||||
if err == nil {
|
||||
return f.fault(dst, nil, new(types.FileAlreadyExistsFault))
|
||||
}
|
||||
}
|
||||
|
||||
err := os.Rename(src, dst)
|
||||
if err != nil {
|
||||
return f.fault(src, err, new(types.CannotAccessFile))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FileManager) MoveDatastoreFileTask(req *types.MoveDatastoreFile_Task) soap.HasFault {
|
||||
task := CreateTask(f, "moveDatastoreFile", func(*Task) (types.AnyType, types.BaseMethodFault) {
|
||||
return nil, f.moveDatastoreFile(req)
|
||||
})
|
||||
|
||||
return &methods.MoveDatastoreFile_TaskBody{
|
||||
Res: &types.MoveDatastoreFile_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FileManager) copyDatastoreFile(req *types.CopyDatastoreFile_Task) types.BaseMethodFault {
|
||||
src, fault := f.resolve(req.SourceDatacenter, req.SourceName)
|
||||
if fault != nil {
|
||||
return fault
|
||||
}
|
||||
|
||||
dst, fault := f.resolve(req.DestinationDatacenter, req.DestinationName)
|
||||
if fault != nil {
|
||||
return fault
|
||||
}
|
||||
|
||||
if !isTrue(req.Force) {
|
||||
_, err := os.Stat(dst)
|
||||
if err == nil {
|
||||
return f.fault(dst, nil, new(types.FileAlreadyExistsFault))
|
||||
}
|
||||
}
|
||||
|
||||
r, err := os.Open(src)
|
||||
if err != nil {
|
||||
return f.fault(dst, err, new(types.CannotAccessFile))
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
w, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return f.fault(dst, err, new(types.CannotCreateFile))
|
||||
}
|
||||
defer w.Close()
|
||||
|
||||
if _, err = io.Copy(w, r); err != nil {
|
||||
return f.fault(dst, err, new(types.CannotCreateFile))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FileManager) CopyDatastoreFileTask(req *types.CopyDatastoreFile_Task) soap.HasFault {
|
||||
task := CreateTask(f, "copyDatastoreFile", func(*Task) (types.AnyType, types.BaseMethodFault) {
|
||||
return nil, f.copyDatastoreFile(req)
|
||||
})
|
||||
|
||||
return &methods.CopyDatastoreFile_TaskBody{
|
||||
Res: &types.CopyDatastoreFile_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
220
vendor/github.com/vmware/govmomi/simulator/finder_test.go
generated
vendored
Normal file
220
vendor/github.com/vmware/govmomi/simulator/finder_test.go
generated
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/find"
|
||||
"github.com/vmware/govmomi/object"
|
||||
)
|
||||
|
||||
func TestFinderVPX(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
m := VPX()
|
||||
m.Datacenter = 3
|
||||
m.Folder = 2
|
||||
m.Pool = 1
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
client, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder := find.NewFinder(client.Client, false)
|
||||
dc, _ := finder.Datacenter(ctx, "/F0/DC1")
|
||||
finder.SetDatacenter(dc)
|
||||
|
||||
tests := []struct {
|
||||
kind string
|
||||
path string
|
||||
expect int
|
||||
}{
|
||||
{"ManagedObjectList", "./*", 4}, // /F0/DC1/{vm,host,network,datastore}
|
||||
{"ManagedObjectListChildren", ".", 4}, // ""
|
||||
{"ManagedObjectList", "/", 1},
|
||||
{"ManagedObjectList", "/*", m.Datacenter - m.Folder + m.Folder},
|
||||
{"ManagedObjectList", "/DC0", 1},
|
||||
{"ManagedObjectList", "/F[01]", 2},
|
||||
{"ManagedObjectListChildren", "/*", m.Datacenter + 3},
|
||||
{"ManagedObjectListChildren", "/*/*", 19},
|
||||
{"ManagedObjectListChildren", "/*/*/*", 25},
|
||||
{"FolderList", "/*", m.Folder},
|
||||
{"DatacenterList", "/F0/*", 1},
|
||||
{"DatacenterList", "/DC0", 1},
|
||||
{"VirtualMachineList", "/DC0/vm/*", (m.Host + m.Cluster) * m.Machine},
|
||||
{"VirtualMachineList", "F0/DC1_C0_RP0_VM0", 1},
|
||||
{"VirtualMachineList", "./DC1_C0_RP0_VM0", 0},
|
||||
{"VirtualMachineList", "DC1_C0_RP0_VM0", 1}, // find . -type VirtualMachine -name DC1_C0_RP0_VM0
|
||||
{"VirtualAppList", "/DC0/vm/*", 0},
|
||||
{"DatastoreList", "/DC0/datastore/*", m.Datastore},
|
||||
{"DatastoreList", "./*", 0},
|
||||
{"DatastoreList", "./F0/*", m.Datastore},
|
||||
{"DatastoreList", "/F*/*/datastore/F*/*", m.Datastore * m.Folder},
|
||||
{"DatastoreList", "/F0/DC1/datastore/F0/LocalDS_0", m.Datastore},
|
||||
{"DatastoreList", "/F0/DC1/datastore/F0/*", m.Datastore},
|
||||
{"DatastoreList", "/F1/DC2/datastore/F1/*", m.Datastore},
|
||||
{"DatastoreList", "./LocalDS_0", 0},
|
||||
{"DatastoreList", "LocalDS_0", 1}, // find . -type Datastore -name LocalDS_0
|
||||
{"DatastoreClusterList", "/DC0/datastore/*", 0},
|
||||
{"ComputeResourceList", "/DC0/host/*", m.Host + m.Cluster},
|
||||
{"ClusterComputeResourceList", "/DC0/host/*", m.Cluster},
|
||||
{"HostSystemList", "/DC0/host/*", m.Host + m.ClusterHost},
|
||||
{"HostSystemList", "/F0/DC1/host/F0/*", m.Host + m.ClusterHost},
|
||||
{"HostSystemList", "DC1_H0", 1}, // find . -type HostSystem -name DC1_H0
|
||||
{"ComputeResourceList", "DC1_H0", 1}, // find . -type ComputeResource -name DC1_H0
|
||||
{"ClusterComputeResourceList", "DC1_C0", 1}, // find . -type ClusterComputeResource -name DC1_H0
|
||||
{"NetworkList", "/DC0/network/*", 3 + m.Portgroup}, // VM Network + DSwitch + DSwitch-Uplinks + m.Portgroup
|
||||
{"NetworkList", "./*", 1},
|
||||
{"NetworkList", "/F0/DC1/network/VM Network", 1},
|
||||
{"NetworkList", "/F0/DC1/network/F0/*", 2 + m.Portgroup},
|
||||
{"NetworkList", "./F0/DC1_DVPG0", 1},
|
||||
{"NetworkList", "./F0/DC1_DVPG0", 1},
|
||||
{"NetworkList", "DC1_DVPG0", 1}, // find . -type Network -name DC1_DVPG0
|
||||
{"ResourcePoolList", "/F0/DC1/host/F0/*", m.Host + m.Cluster},
|
||||
{"ResourcePoolList", "/F0/DC1/host/F0/*/*", m.Host + m.Cluster},
|
||||
{"ResourcePoolList", "/DC0/host/*", m.Host + m.Cluster},
|
||||
{"ResourcePoolList", "/DC0/host/*/*", m.Host + m.Cluster},
|
||||
{"ResourcePoolList", "/DC0/host/DC0_H0/Resources", 1},
|
||||
{"ResourcePoolList", "/F1/DC2/host/F1/DC2_C0/Resources", 1},
|
||||
{"ResourcePoolList", "Resources", m.Host + m.Cluster}, // find . -type ResourcePool -name Resources
|
||||
{"ResourcePoolList", "/F1/DC2/...", m.Pool + m.Host + 1}, // find $path -type ResourcePool
|
||||
{"ResourcePoolList", "/F1/DC2/host/...", m.Pool + m.Host + 1}, // find $path -type ResourcePool
|
||||
{"ResourcePoolList", "/F1/DC2/host/F1/...", m.Pool + m.Host + 1}, // find $path -type ResourcePool
|
||||
{"ResourcePoolList", "/F1/DC2/host/F1/DC2_C0/...", m.Pool + 1}, // find $path -type ResourcePool
|
||||
{"ResourcePoolList", "/F1/DC2/host/F1/DC2_C0/Resources/...", m.Pool}, // find $path -type ResourcePool
|
||||
{"ResourcePoolList", "F0/DC1_C0", 1},
|
||||
{"ResourcePoolList", "DC1_C0_RP1", 1}, // find . -type ResourcePool -name DC1_C0_RP1
|
||||
{"", "", 0}, // unset Datacenter
|
||||
{"DatacenterList", "*", m.Datacenter}, // find . -type Datacenter
|
||||
{"DatacenterList", "./...", m.Datacenter}, // find . -type Datacenter
|
||||
{"DatacenterList", "DC2", 1}, // find . -type Datacenter -name DC2
|
||||
{"DatacenterList", "/*", m.Datacenter - m.Folder},
|
||||
{"DatacenterList", "/*/*", m.Folder},
|
||||
{"DatastoreList", "/F1/DC2/datastore/F1/LocalDS_0", 1},
|
||||
{"VirtualMachineList", "DC1_C0_RP0_VM0", 0}, // TODO: recurse all Datacenters?
|
||||
}
|
||||
|
||||
f := reflect.ValueOf(finder)
|
||||
c := reflect.ValueOf(ctx)
|
||||
|
||||
for i, test := range tests {
|
||||
if test.kind == "" {
|
||||
finder.SetDatacenter(nil)
|
||||
continue
|
||||
}
|
||||
|
||||
err = nil
|
||||
|
||||
arg := []reflect.Value{c, reflect.ValueOf(test.path)}
|
||||
res := f.MethodByName(test.kind).Call(arg)
|
||||
|
||||
rval := res[0]
|
||||
rerr := res[1]
|
||||
|
||||
if rval.Len() != test.expect {
|
||||
msg := fmt.Sprintf("expected %d, got %d", test.expect, rval.Len())
|
||||
if !rerr.IsNil() {
|
||||
msg += fmt.Sprintf(" (%s)", rerr.Interface())
|
||||
}
|
||||
err = errors.New(msg)
|
||||
|
||||
if !rval.IsNil() {
|
||||
for j := 0; j < rval.Len(); j++ {
|
||||
t.Logf("%s\n", rval.Index(j).Interface())
|
||||
}
|
||||
}
|
||||
} else if !rerr.IsNil() {
|
||||
if test.expect != 0 {
|
||||
err = rerr.Interface().(error)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("%d) %s(%s): %s", i, test.kind, test.path, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFinderESX(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
m := ESX()
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
client, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder := find.NewFinder(client.Client, false)
|
||||
|
||||
dc, err := finder.DefaultDatacenter(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder.SetDatacenter(dc)
|
||||
|
||||
f := reflect.ValueOf(finder)
|
||||
c := reflect.ValueOf(ctx)
|
||||
|
||||
tests := []string{"Folder", "Datastore", "ComputeResource", "HostSystem", "Datastore", "Network"}
|
||||
|
||||
for _, test := range tests {
|
||||
res := f.MethodByName("Default" + test).Call([]reflect.Value{c})
|
||||
if !res[1].IsNil() {
|
||||
t.Fatalf("%s: %s", test, res[1].Interface())
|
||||
}
|
||||
|
||||
// test find by moref
|
||||
ref := res[0].Interface().(object.Reference).Reference()
|
||||
o, err := finder.Element(ctx, ref)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if o.Object.Reference() != ref {
|
||||
t.Errorf("%s", ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
583
vendor/github.com/vmware/govmomi/simulator/folder.go
generated
vendored
Normal file
583
vendor/github.com/vmware/govmomi/simulator/folder.go
generated
vendored
Normal file
@@ -0,0 +1,583 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type Folder struct {
|
||||
mo.Folder
|
||||
}
|
||||
|
||||
func (f *Folder) eventArgument() types.FolderEventArgument {
|
||||
return types.FolderEventArgument{
|
||||
Folder: f.Self,
|
||||
EntityEventArgument: types.EntityEventArgument{Name: f.Name},
|
||||
}
|
||||
}
|
||||
|
||||
// update references when objects are added/removed from a Folder
|
||||
func (f *Folder) update(o mo.Reference, u func(mo.Reference, *[]types.ManagedObjectReference, types.ManagedObjectReference)) {
|
||||
ref := o.Reference()
|
||||
|
||||
if f.Parent == nil {
|
||||
return // this is the root folder
|
||||
}
|
||||
|
||||
switch ref.Type {
|
||||
case "Datacenter", "Folder":
|
||||
return // nothing to update
|
||||
}
|
||||
|
||||
dc := Map.getEntityDatacenter(f)
|
||||
|
||||
switch ref.Type {
|
||||
case "Network", "DistributedVirtualSwitch", "DistributedVirtualPortgroup":
|
||||
u(dc, &dc.Network, ref)
|
||||
case "Datastore":
|
||||
u(dc, &dc.Datastore, ref)
|
||||
}
|
||||
}
|
||||
|
||||
func networkSummary(n *mo.Network) *types.NetworkSummary {
|
||||
return &types.NetworkSummary{
|
||||
Network: &n.Self,
|
||||
Name: n.Name,
|
||||
Accessible: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Folder) putChild(o mo.Entity) {
|
||||
Map.PutEntity(f, o)
|
||||
|
||||
f.ChildEntity = append(f.ChildEntity, o.Reference())
|
||||
|
||||
f.update(o, Map.AddReference)
|
||||
|
||||
switch e := o.(type) {
|
||||
case *mo.Network:
|
||||
e.Summary = networkSummary(e)
|
||||
case *mo.OpaqueNetwork:
|
||||
e.Summary = networkSummary(&e.Network)
|
||||
case *DistributedVirtualPortgroup:
|
||||
e.Summary = networkSummary(&e.Network)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Folder) removeChild(o mo.Reference) {
|
||||
Map.Remove(o.Reference())
|
||||
|
||||
RemoveReference(&f.ChildEntity, o.Reference())
|
||||
|
||||
f.update(o, Map.RemoveReference)
|
||||
}
|
||||
|
||||
func (f *Folder) hasChildType(kind string) bool {
|
||||
for _, t := range f.ChildType {
|
||||
if t == kind {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *Folder) typeNotSupported() *soap.Fault {
|
||||
return Fault(fmt.Sprintf("%s supports types: %#v", f.Self, f.ChildType), &types.NotSupported{})
|
||||
}
|
||||
|
||||
type addStandaloneHost struct {
|
||||
*Folder
|
||||
|
||||
req *types.AddStandaloneHost_Task
|
||||
}
|
||||
|
||||
func (add *addStandaloneHost) Run(task *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
host, err := CreateStandaloneHost(add.Folder, add.req.Spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if add.req.AddConnected {
|
||||
host.Runtime.ConnectionState = types.HostSystemConnectionStateConnected
|
||||
}
|
||||
|
||||
return host.Reference(), nil
|
||||
}
|
||||
|
||||
func (f *Folder) AddStandaloneHostTask(a *types.AddStandaloneHost_Task) soap.HasFault {
|
||||
r := &methods.AddStandaloneHost_TaskBody{}
|
||||
|
||||
if f.hasChildType("ComputeResource") && f.hasChildType("Folder") {
|
||||
r.Res = &types.AddStandaloneHost_TaskResponse{
|
||||
Returnval: NewTask(&addStandaloneHost{f, a}).Run(),
|
||||
}
|
||||
} else {
|
||||
r.Fault_ = f.typeNotSupported()
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (f *Folder) CreateFolder(c *types.CreateFolder) soap.HasFault {
|
||||
r := &methods.CreateFolderBody{}
|
||||
|
||||
if f.hasChildType("Folder") {
|
||||
folder := &Folder{}
|
||||
|
||||
folder.Name = c.Name
|
||||
folder.ChildType = f.ChildType
|
||||
|
||||
f.putChild(folder)
|
||||
|
||||
r.Res = &types.CreateFolderResponse{
|
||||
Returnval: folder.Self,
|
||||
}
|
||||
} else {
|
||||
r.Fault_ = f.typeNotSupported()
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// StoragePod aka "Datastore Cluster"
|
||||
type StoragePod struct {
|
||||
mo.StoragePod
|
||||
}
|
||||
|
||||
func (f *Folder) CreateStoragePod(c *types.CreateStoragePod) soap.HasFault {
|
||||
r := &methods.CreateStoragePodBody{}
|
||||
|
||||
if f.hasChildType("StoragePod") {
|
||||
pod := &StoragePod{}
|
||||
|
||||
pod.Name = c.Name
|
||||
pod.ChildType = []string{"Datastore"}
|
||||
|
||||
f.putChild(pod)
|
||||
|
||||
r.Res = &types.CreateStoragePodResponse{
|
||||
Returnval: pod.Self,
|
||||
}
|
||||
} else {
|
||||
r.Fault_ = f.typeNotSupported()
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (p *StoragePod) MoveIntoFolderTask(c *types.MoveIntoFolder_Task) soap.HasFault {
|
||||
return (&Folder{Folder: p.Folder}).MoveIntoFolderTask(c)
|
||||
}
|
||||
|
||||
func (f *Folder) CreateDatacenter(ctx *Context, c *types.CreateDatacenter) soap.HasFault {
|
||||
r := &methods.CreateDatacenterBody{}
|
||||
|
||||
if f.hasChildType("Datacenter") && f.hasChildType("Folder") {
|
||||
dc := NewDatacenter(f)
|
||||
|
||||
dc.Name = c.Name
|
||||
|
||||
r.Res = &types.CreateDatacenterResponse{
|
||||
Returnval: dc.Self,
|
||||
}
|
||||
|
||||
ctx.postEvent(&types.DatacenterCreatedEvent{
|
||||
DatacenterEvent: types.DatacenterEvent{
|
||||
Event: types.Event{
|
||||
Datacenter: datacenterEventArgument(dc),
|
||||
},
|
||||
},
|
||||
Parent: f.eventArgument(),
|
||||
})
|
||||
} else {
|
||||
r.Fault_ = f.typeNotSupported()
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (f *Folder) CreateClusterEx(c *types.CreateClusterEx) soap.HasFault {
|
||||
r := &methods.CreateClusterExBody{}
|
||||
|
||||
if f.hasChildType("ComputeResource") && f.hasChildType("Folder") {
|
||||
cluster, err := CreateClusterComputeResource(f, c.Name, c.Spec)
|
||||
if err != nil {
|
||||
r.Fault_ = Fault("", err)
|
||||
return r
|
||||
}
|
||||
|
||||
r.Res = &types.CreateClusterExResponse{
|
||||
Returnval: cluster.Self,
|
||||
}
|
||||
} else {
|
||||
r.Fault_ = f.typeNotSupported()
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
type createVM struct {
|
||||
*Folder
|
||||
|
||||
ctx *Context
|
||||
req *types.CreateVM_Task
|
||||
|
||||
register bool
|
||||
}
|
||||
|
||||
func (c *createVM) Run(task *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
vm, err := NewVirtualMachine(c.Folder.Self, &c.req.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vm.ResourcePool = &c.req.Pool
|
||||
|
||||
if c.req.Host == nil {
|
||||
var hosts []types.ManagedObjectReference
|
||||
|
||||
pool := Map.Get(c.req.Pool).(mo.Entity)
|
||||
|
||||
switch cr := Map.getEntityComputeResource(pool).(type) {
|
||||
case *mo.ComputeResource:
|
||||
hosts = cr.Host
|
||||
case *ClusterComputeResource:
|
||||
hosts = cr.Host
|
||||
}
|
||||
|
||||
// Assuming for now that all hosts have access to the datastore
|
||||
host := hosts[rand.Intn(len(hosts))]
|
||||
vm.Runtime.Host = &host
|
||||
} else {
|
||||
vm.Runtime.Host = c.req.Host
|
||||
}
|
||||
|
||||
vm.Guest = &types.GuestInfo{
|
||||
ToolsStatus: types.VirtualMachineToolsStatusToolsNotInstalled,
|
||||
ToolsVersion: "0",
|
||||
}
|
||||
|
||||
vm.Summary.Guest = &types.VirtualMachineGuestSummary{
|
||||
ToolsStatus: vm.Guest.ToolsStatus,
|
||||
}
|
||||
vm.Summary.Config.VmPathName = vm.Config.Files.VmPathName
|
||||
vm.Summary.Runtime.Host = vm.Runtime.Host
|
||||
|
||||
err = vm.create(&c.req.Config, c.register)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.Folder.putChild(vm)
|
||||
|
||||
host := Map.Get(*vm.Runtime.Host).(*HostSystem)
|
||||
Map.AppendReference(host, &host.Vm, vm.Self)
|
||||
|
||||
for i := range vm.Datastore {
|
||||
ds := Map.Get(vm.Datastore[i]).(*Datastore)
|
||||
Map.AppendReference(ds, &ds.Vm, vm.Self)
|
||||
}
|
||||
|
||||
pool := Map.Get(*vm.ResourcePool)
|
||||
// This can be an internal call from VirtualApp.CreateChildVMTask, where pool is already locked.
|
||||
c.ctx.WithLock(pool, func() {
|
||||
switch rp := pool.(type) {
|
||||
case *ResourcePool:
|
||||
rp.Vm = append(rp.Vm, vm.Self)
|
||||
case *VirtualApp:
|
||||
rp.Vm = append(rp.Vm, vm.Self)
|
||||
}
|
||||
})
|
||||
|
||||
event := vm.event()
|
||||
c.ctx.postEvent(
|
||||
&types.VmBeingCreatedEvent{
|
||||
VmEvent: event,
|
||||
ConfigSpec: &c.req.Config,
|
||||
},
|
||||
&types.VmInstanceUuidAssignedEvent{
|
||||
VmEvent: event,
|
||||
InstanceUuid: vm.Config.InstanceUuid,
|
||||
},
|
||||
&types.VmUuidAssignedEvent{
|
||||
VmEvent: event,
|
||||
Uuid: vm.Config.Uuid,
|
||||
},
|
||||
&types.VmCreatedEvent{
|
||||
VmEvent: event,
|
||||
},
|
||||
)
|
||||
|
||||
return vm.Reference(), nil
|
||||
}
|
||||
|
||||
func (f *Folder) CreateVMTask(ctx *Context, c *types.CreateVM_Task) soap.HasFault {
|
||||
return &methods.CreateVM_TaskBody{
|
||||
Res: &types.CreateVM_TaskResponse{
|
||||
Returnval: NewTask(&createVM{f, ctx, c, false}).Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type registerVM struct {
|
||||
*Folder
|
||||
|
||||
ctx *Context
|
||||
req *types.RegisterVM_Task
|
||||
}
|
||||
|
||||
func (c *registerVM) Run(task *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
host := c.req.Host
|
||||
pool := c.req.Pool
|
||||
|
||||
if c.req.AsTemplate {
|
||||
if host == nil {
|
||||
return nil, &types.InvalidArgument{InvalidProperty: "host"}
|
||||
} else if pool != nil {
|
||||
return nil, &types.InvalidArgument{InvalidProperty: "pool"}
|
||||
}
|
||||
|
||||
pool = hostParent(&Map.Get(*host).(*HostSystem).HostSystem).ResourcePool
|
||||
} else {
|
||||
if pool == nil {
|
||||
return nil, &types.InvalidArgument{InvalidProperty: "pool"}
|
||||
}
|
||||
}
|
||||
|
||||
if c.req.Path == "" {
|
||||
return nil, &types.InvalidArgument{InvalidProperty: "path"}
|
||||
}
|
||||
|
||||
s := Map.SearchIndex()
|
||||
r := s.FindByDatastorePath(&types.FindByDatastorePath{
|
||||
This: s.Reference(),
|
||||
Path: c.req.Path,
|
||||
Datacenter: Map.getEntityDatacenter(c.Folder).Reference(),
|
||||
})
|
||||
|
||||
if ref := r.(*methods.FindByDatastorePathBody).Res.Returnval; ref != nil {
|
||||
return nil, &types.AlreadyExists{Name: ref.Value}
|
||||
}
|
||||
|
||||
if c.req.Name == "" {
|
||||
p, err := parseDatastorePath(c.req.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.req.Name = path.Dir(p.Path)
|
||||
}
|
||||
|
||||
create := NewTask(&createVM{
|
||||
Folder: c.Folder,
|
||||
register: true,
|
||||
ctx: c.ctx,
|
||||
req: &types.CreateVM_Task{
|
||||
This: c.Folder.Reference(),
|
||||
Config: types.VirtualMachineConfigSpec{
|
||||
Name: c.req.Name,
|
||||
Files: &types.VirtualMachineFileInfo{
|
||||
VmPathName: c.req.Path,
|
||||
},
|
||||
},
|
||||
Pool: *pool,
|
||||
Host: host,
|
||||
},
|
||||
})
|
||||
|
||||
create.Run()
|
||||
|
||||
if create.Info.Error != nil {
|
||||
return nil, create.Info.Error.Fault
|
||||
}
|
||||
|
||||
return create.Info.Result, nil
|
||||
}
|
||||
|
||||
func (f *Folder) RegisterVMTask(ctx *Context, c *types.RegisterVM_Task) soap.HasFault {
|
||||
ctx.Caller = &f.Self
|
||||
|
||||
return &methods.RegisterVM_TaskBody{
|
||||
Res: &types.RegisterVM_TaskResponse{
|
||||
Returnval: NewTask(®isterVM{f, ctx, c}).Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Folder) MoveIntoFolderTask(c *types.MoveIntoFolder_Task) soap.HasFault {
|
||||
task := CreateTask(f, "moveIntoFolder", func(t *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
for _, ref := range c.List {
|
||||
obj := Map.Get(ref).(mo.Entity)
|
||||
|
||||
parent, ok := Map.Get(*(obj.Entity()).Parent).(*Folder)
|
||||
|
||||
if !ok || !f.hasChildType(ref.Type) {
|
||||
return nil, &types.NotSupported{}
|
||||
}
|
||||
|
||||
parent.removeChild(ref)
|
||||
f.putChild(obj)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.MoveIntoFolder_TaskBody{
|
||||
Res: &types.MoveIntoFolder_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Folder) CreateDVSTask(req *types.CreateDVS_Task) soap.HasFault {
|
||||
task := CreateTask(f, "createDVS", func(t *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
spec := req.Spec.ConfigSpec.GetDVSConfigSpec()
|
||||
dvs := &DistributedVirtualSwitch{}
|
||||
dvs.Name = spec.Name
|
||||
dvs.Entity().Name = dvs.Name
|
||||
|
||||
if Map.FindByName(dvs.Name, f.ChildEntity) != nil {
|
||||
return nil, &types.InvalidArgument{InvalidProperty: "name"}
|
||||
}
|
||||
|
||||
dvs.Uuid = uuid.New().String()
|
||||
|
||||
f.putChild(dvs)
|
||||
|
||||
dvs.Summary = types.DVSSummary{
|
||||
Name: dvs.Name,
|
||||
Uuid: dvs.Uuid,
|
||||
NumPorts: spec.NumStandalonePorts,
|
||||
ProductInfo: req.Spec.ProductInfo,
|
||||
Description: spec.Description,
|
||||
}
|
||||
|
||||
configInfo := &types.VMwareDVSConfigInfo{
|
||||
DVSConfigInfo: types.DVSConfigInfo{
|
||||
Uuid: dvs.Uuid,
|
||||
Name: spec.Name,
|
||||
ConfigVersion: spec.ConfigVersion,
|
||||
NumStandalonePorts: spec.NumStandalonePorts,
|
||||
MaxPorts: spec.MaxPorts,
|
||||
UplinkPortPolicy: spec.UplinkPortPolicy,
|
||||
UplinkPortgroup: spec.UplinkPortgroup,
|
||||
DefaultPortConfig: spec.DefaultPortConfig,
|
||||
ExtensionKey: spec.ExtensionKey,
|
||||
Description: spec.Description,
|
||||
Policy: spec.Policy,
|
||||
VendorSpecificConfig: spec.VendorSpecificConfig,
|
||||
SwitchIpAddress: spec.SwitchIpAddress,
|
||||
DefaultProxySwitchMaxNumPorts: spec.DefaultProxySwitchMaxNumPorts,
|
||||
InfrastructureTrafficResourceConfig: spec.InfrastructureTrafficResourceConfig,
|
||||
NetworkResourceControlVersion: spec.NetworkResourceControlVersion,
|
||||
},
|
||||
}
|
||||
|
||||
if spec.Contact != nil {
|
||||
configInfo.Contact = *spec.Contact
|
||||
}
|
||||
|
||||
dvs.Config = configInfo
|
||||
|
||||
if dvs.Summary.ProductInfo == nil {
|
||||
product := Map.content().About
|
||||
dvs.Summary.ProductInfo = &types.DistributedVirtualSwitchProductSpec{
|
||||
Name: "DVS",
|
||||
Vendor: product.Vendor,
|
||||
Version: product.Version,
|
||||
Build: product.Build,
|
||||
ForwardingClass: "etherswitch",
|
||||
}
|
||||
}
|
||||
|
||||
dvs.AddDVPortgroupTask(&types.AddDVPortgroup_Task{
|
||||
Spec: []types.DVPortgroupConfigSpec{{
|
||||
Name: dvs.Name + "-DVUplinks" + strings.TrimPrefix(dvs.Self.Value, "dvs"),
|
||||
DefaultPortConfig: &types.VMwareDVSPortSetting{
|
||||
Vlan: &types.VmwareDistributedVirtualSwitchTrunkVlanSpec{
|
||||
VlanId: []types.NumericRange{{Start: 0, End: 4094}},
|
||||
},
|
||||
},
|
||||
}},
|
||||
})
|
||||
|
||||
return dvs.Reference(), nil
|
||||
})
|
||||
|
||||
return &methods.CreateDVS_TaskBody{
|
||||
Res: &types.CreateDVS_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Folder) RenameTask(r *types.Rename_Task) soap.HasFault {
|
||||
return RenameTask(f, r)
|
||||
}
|
||||
|
||||
func (f *Folder) DestroyTask(req *types.Destroy_Task) soap.HasFault {
|
||||
type destroyer interface {
|
||||
mo.Reference
|
||||
DestroyTask(*types.Destroy_Task) soap.HasFault
|
||||
}
|
||||
|
||||
task := CreateTask(f, "destroy", func(*Task) (types.AnyType, types.BaseMethodFault) {
|
||||
// Attempt to destroy all children
|
||||
for _, c := range f.ChildEntity {
|
||||
obj, ok := Map.Get(c).(destroyer)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
var fault types.BaseMethodFault
|
||||
Map.WithLock(obj, func() {
|
||||
id := obj.DestroyTask(&types.Destroy_Task{
|
||||
This: c,
|
||||
}).(*methods.Destroy_TaskBody).Res.Returnval
|
||||
|
||||
t := Map.Get(id).(*Task)
|
||||
if t.Info.Error != nil {
|
||||
fault = t.Info.Error.Fault // For example, can't destroy a powered on VM
|
||||
}
|
||||
})
|
||||
if fault != nil {
|
||||
return nil, fault
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the folder itself
|
||||
Map.Get(*f.Parent).(*Folder).removeChild(f.Self)
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.Destroy_TaskBody{
|
||||
Res: &types.Destroy_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
562
vendor/github.com/vmware/govmomi/simulator/folder_test.go
generated
vendored
Normal file
562
vendor/github.com/vmware/govmomi/simulator/folder_test.go
generated
vendored
Normal file
@@ -0,0 +1,562 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/find"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/simulator/vpx"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func addStandaloneHostTask(folder *object.Folder, spec types.HostConnectSpec) (*object.Task, error) {
|
||||
// TODO: add govmomi wrapper
|
||||
req := types.AddStandaloneHost_Task{
|
||||
This: folder.Reference(),
|
||||
Spec: spec,
|
||||
AddConnected: true,
|
||||
}
|
||||
|
||||
res, err := methods.AddStandaloneHost_Task(context.TODO(), folder.Client(), &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
task := object.NewTask(folder.Client(), res.Returnval)
|
||||
return task, nil
|
||||
}
|
||||
|
||||
func TestFolderESX(t *testing.T) {
|
||||
content := esx.ServiceContent
|
||||
s := New(NewServiceInstance(content, esx.RootFolder))
|
||||
|
||||
ts := s.NewServer()
|
||||
defer ts.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
c, err := govmomi.NewClient(ctx, ts.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
f := object.NewRootFolder(c.Client)
|
||||
|
||||
_, err = f.CreateFolder(ctx, "foo")
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
_, err = f.CreateDatacenter(ctx, "foo")
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
finder := find.NewFinder(c.Client, false)
|
||||
dc, err := finder.DatacenterOrDefault(ctx, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
folders, err := dc.Folders(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
spec := types.HostConnectSpec{}
|
||||
_, err = addStandaloneHostTask(folders.HostFolder, spec)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
|
||||
_, err = folders.DatastoreFolder.CreateStoragePod(ctx, "pod")
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFolderVC(t *testing.T) {
|
||||
content := vpx.ServiceContent
|
||||
s := New(NewServiceInstance(content, vpx.RootFolder))
|
||||
|
||||
ts := s.NewServer()
|
||||
defer ts.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
c, err := govmomi.NewClient(ctx, ts.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
f := object.NewRootFolder(c.Client)
|
||||
|
||||
ff, err := f.CreateFolder(ctx, "foo")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
dc, err := f.CreateDatacenter(ctx, "bar")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
for _, ref := range []object.Reference{ff, dc} {
|
||||
o := Map.Get(ref.Reference())
|
||||
if o == nil {
|
||||
t.Fatalf("failed to find %#v", ref)
|
||||
}
|
||||
|
||||
e := o.(mo.Entity).Entity()
|
||||
if *e.Parent != f.Reference() {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
dc, err = ff.CreateDatacenter(ctx, "biz")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
folders, err := dc.Folders(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = folders.VmFolder.CreateStoragePod(ctx, "pod")
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
_, err = folders.DatastoreFolder.CreateStoragePod(ctx, "pod")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
state types.TaskInfoState
|
||||
}{
|
||||
{"", types.TaskInfoStateError},
|
||||
{"foo.local", types.TaskInfoStateSuccess},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
spec := types.HostConnectSpec{
|
||||
HostName: test.name,
|
||||
}
|
||||
|
||||
task, err := addStandaloneHostTask(folders.HostFolder, spec)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
res, err := task.WaitForResult(ctx, nil)
|
||||
if test.state == types.TaskInfoStateError {
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
if res.Result != nil {
|
||||
t.Error("expected nil")
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ref, ok := res.Result.(types.ManagedObjectReference)
|
||||
if !ok {
|
||||
t.Errorf("expected moref, got type=%T", res.Result)
|
||||
}
|
||||
host := Map.Get(ref).(*HostSystem)
|
||||
if host.Name != test.name {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if ref == esx.HostSystem.Self {
|
||||
t.Error("expected new host Self reference")
|
||||
}
|
||||
if *host.Summary.Host == esx.HostSystem.Self {
|
||||
t.Error("expected new host summary Self reference")
|
||||
}
|
||||
|
||||
pool := Map.Get(*host.Parent).(*mo.ComputeResource).ResourcePool
|
||||
if *pool == esx.ResourcePool.Self {
|
||||
t.Error("expected new pool Self reference")
|
||||
}
|
||||
}
|
||||
|
||||
if res.State != test.state {
|
||||
t.Fatalf("%s", res.State)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFolderFaults(t *testing.T) {
|
||||
f := Folder{}
|
||||
f.ChildType = []string{"VirtualMachine"}
|
||||
|
||||
if f.CreateFolder(nil).Fault() == nil {
|
||||
t.Error("expected fault")
|
||||
}
|
||||
|
||||
if f.CreateDatacenter(nil, nil).Fault() == nil {
|
||||
t.Error("expected fault")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterVm(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
for i, model := range []*Model{ESX(), VPX()} {
|
||||
match := "*"
|
||||
if i == 1 {
|
||||
model.App = 1
|
||||
match = "*APP*"
|
||||
}
|
||||
defer model.Remove()
|
||||
err := model.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := model.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder := find.NewFinder(c.Client, false)
|
||||
dc, err := finder.DefaultDatacenter(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder.SetDatacenter(dc)
|
||||
|
||||
folders, err := dc.Folders(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vmFolder := folders.VmFolder
|
||||
|
||||
vms, err := finder.VirtualMachineList(ctx, match)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vm := Map.Get(vms[0].Reference()).(*VirtualMachine)
|
||||
|
||||
req := types.RegisterVM_Task{
|
||||
This: vmFolder.Reference(),
|
||||
AsTemplate: true,
|
||||
}
|
||||
|
||||
steps := []struct {
|
||||
e interface{}
|
||||
f func()
|
||||
}{
|
||||
{
|
||||
new(types.InvalidArgument), func() { req.AsTemplate = false },
|
||||
},
|
||||
{
|
||||
new(types.InvalidArgument), func() { req.Pool = vm.ResourcePool },
|
||||
},
|
||||
{
|
||||
new(types.InvalidArgument), func() { req.Path = "enoent" },
|
||||
},
|
||||
{
|
||||
new(types.InvalidDatastorePath), func() { req.Path = vm.Config.Files.VmPathName + "-enoent" },
|
||||
},
|
||||
{
|
||||
new(types.NotFound), func() { req.Path = vm.Config.Files.VmPathName },
|
||||
},
|
||||
{
|
||||
new(types.AlreadyExists), func() { Map.Remove(vm.Reference()) },
|
||||
},
|
||||
{
|
||||
nil, func() {},
|
||||
},
|
||||
}
|
||||
|
||||
for _, step := range steps {
|
||||
res, err := methods.RegisterVM_Task(ctx, c.Client, &req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
rt := Map.Get(res.Returnval).(*Task)
|
||||
|
||||
if step.e != nil {
|
||||
fault := rt.Info.Error.Fault
|
||||
if reflect.TypeOf(fault) != reflect.TypeOf(step.e) {
|
||||
t.Errorf("%T != %T", fault, step.e)
|
||||
}
|
||||
} else {
|
||||
if rt.Info.Error != nil {
|
||||
t.Errorf("unexpected error: %#v", rt.Info.Error)
|
||||
}
|
||||
}
|
||||
|
||||
step.f()
|
||||
}
|
||||
|
||||
nvm, err := finder.VirtualMachine(ctx, vm.Name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if nvm.Reference() == vm.Reference() {
|
||||
t.Error("expected new moref")
|
||||
}
|
||||
|
||||
_, _ = nvm.PowerOn(ctx)
|
||||
|
||||
steps = []struct {
|
||||
e interface{}
|
||||
f func()
|
||||
}{
|
||||
{
|
||||
types.InvalidPowerState{}, func() { _, _ = nvm.PowerOff(ctx) },
|
||||
},
|
||||
{
|
||||
nil, func() {},
|
||||
},
|
||||
{
|
||||
types.ManagedObjectNotFound{}, func() {},
|
||||
},
|
||||
}
|
||||
|
||||
for _, step := range steps {
|
||||
err = nvm.Unregister(ctx)
|
||||
|
||||
if step.e != nil {
|
||||
fault := soap.ToSoapFault(err).VimFault()
|
||||
if reflect.TypeOf(fault) != reflect.TypeOf(step.e) {
|
||||
t.Errorf("%T != %T", fault, step.e)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %#v", err)
|
||||
}
|
||||
}
|
||||
|
||||
step.f()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFolderMoveInto(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
model := VPX()
|
||||
defer model.Remove()
|
||||
err := model.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := model.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder := find.NewFinder(c.Client, false)
|
||||
|
||||
dc, err := finder.DefaultDatacenter(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder.SetDatacenter(dc)
|
||||
|
||||
folders, err := dc.Folders(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ds, err := finder.DefaultDatastore(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Move Datastore into a vm folder should fail
|
||||
task, err := folders.VmFolder.MoveInto(ctx, []types.ManagedObjectReference{ds.Reference()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err == nil {
|
||||
t.Errorf("expected error")
|
||||
}
|
||||
|
||||
// Move Datacenter into a sub folder should pass
|
||||
f, err := object.NewRootFolder(c.Client).CreateFolder(ctx, "foo")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
task, _ = f.MoveInto(ctx, []types.ManagedObjectReference{dc.Reference()})
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
pod, err := folders.DatastoreFolder.CreateStoragePod(ctx, "pod")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// Moving any type other than Datastore into a StoragePod should fail
|
||||
task, _ = pod.MoveInto(ctx, []types.ManagedObjectReference{dc.Reference()})
|
||||
err = task.Wait(ctx)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
// Move DS into a StoragePod
|
||||
task, _ = pod.MoveInto(ctx, []types.ManagedObjectReference{ds.Reference()})
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFolderCreateDVS(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
model := VPX()
|
||||
defer model.Remove()
|
||||
err := model.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := model.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder := find.NewFinder(c.Client, false)
|
||||
|
||||
dc, err := finder.DefaultDatacenter(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder.SetDatacenter(dc)
|
||||
|
||||
folders, err := dc.Folders(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var spec types.DVSCreateSpec
|
||||
spec.ConfigSpec = &types.VMwareDVSConfigSpec{}
|
||||
spec.ConfigSpec.GetDVSConfigSpec().Name = "foo"
|
||||
|
||||
task, err := folders.NetworkFolder.CreateDVS(ctx, spec)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
net, err := finder.Network(ctx, "foo")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
dvs, ok := net.(*object.DistributedVirtualSwitch)
|
||||
if !ok {
|
||||
t.Fatalf("%T is not of type %T", net, dvs)
|
||||
}
|
||||
|
||||
task, err = folders.NetworkFolder.CreateDVS(ctx, spec)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
pspec := types.DVPortgroupConfigSpec{Name: "xnet"}
|
||||
task, err = dvs.AddPortgroup(ctx, []types.DVPortgroupConfigSpec{pspec})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
net, err = finder.Network(ctx, "xnet")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
pg, ok := net.(*object.DistributedVirtualPortgroup)
|
||||
if !ok {
|
||||
t.Fatalf("%T is not of type %T", net, pg)
|
||||
}
|
||||
|
||||
backing, err := net.EthernetCardBackingInfo(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
info, ok := backing.(*types.VirtualEthernetCardDistributedVirtualPortBackingInfo)
|
||||
if ok {
|
||||
if info.Port.SwitchUuid == "" || info.Port.PortgroupKey == "" {
|
||||
t.Errorf("invalid port: %#v", info.Port)
|
||||
}
|
||||
} else {
|
||||
t.Fatalf("%T is not of type %T", net, info)
|
||||
}
|
||||
|
||||
task, err = dvs.AddPortgroup(ctx, []types.DVPortgroupConfigSpec{pspec})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
}
|
||||
171
vendor/github.com/vmware/govmomi/simulator/guest_id.go
generated
vendored
Normal file
171
vendor/github.com/vmware/govmomi/simulator/guest_id.go
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import "github.com/vmware/govmomi/vim25/types"
|
||||
|
||||
// GuestID is the list of valid types.VirtualMachineGuestOsIdentifier
|
||||
var GuestID = []types.VirtualMachineGuestOsIdentifier{
|
||||
types.VirtualMachineGuestOsIdentifierDosGuest,
|
||||
types.VirtualMachineGuestOsIdentifierWin31Guest,
|
||||
types.VirtualMachineGuestOsIdentifierWin95Guest,
|
||||
types.VirtualMachineGuestOsIdentifierWin98Guest,
|
||||
types.VirtualMachineGuestOsIdentifierWinMeGuest,
|
||||
types.VirtualMachineGuestOsIdentifierWinNTGuest,
|
||||
types.VirtualMachineGuestOsIdentifierWin2000ProGuest,
|
||||
types.VirtualMachineGuestOsIdentifierWin2000ServGuest,
|
||||
types.VirtualMachineGuestOsIdentifierWin2000AdvServGuest,
|
||||
types.VirtualMachineGuestOsIdentifierWinXPHomeGuest,
|
||||
types.VirtualMachineGuestOsIdentifierWinXPProGuest,
|
||||
types.VirtualMachineGuestOsIdentifierWinXPPro64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierWinNetWebGuest,
|
||||
types.VirtualMachineGuestOsIdentifierWinNetStandardGuest,
|
||||
types.VirtualMachineGuestOsIdentifierWinNetEnterpriseGuest,
|
||||
types.VirtualMachineGuestOsIdentifierWinNetDatacenterGuest,
|
||||
types.VirtualMachineGuestOsIdentifierWinNetBusinessGuest,
|
||||
types.VirtualMachineGuestOsIdentifierWinNetStandard64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierWinNetEnterprise64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierWinLonghornGuest,
|
||||
types.VirtualMachineGuestOsIdentifierWinLonghorn64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierWinNetDatacenter64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierWinVistaGuest,
|
||||
types.VirtualMachineGuestOsIdentifierWinVista64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierWindows7Guest,
|
||||
types.VirtualMachineGuestOsIdentifierWindows7_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierWindows7Server64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierWindows8Guest,
|
||||
types.VirtualMachineGuestOsIdentifierWindows8_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierWindows8Server64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierWindows9Guest,
|
||||
types.VirtualMachineGuestOsIdentifierWindows9_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierWindows9Server64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierWindowsHyperVGuest,
|
||||
types.VirtualMachineGuestOsIdentifierFreebsdGuest,
|
||||
types.VirtualMachineGuestOsIdentifierFreebsd64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierRedhatGuest,
|
||||
types.VirtualMachineGuestOsIdentifierRhel2Guest,
|
||||
types.VirtualMachineGuestOsIdentifierRhel3Guest,
|
||||
types.VirtualMachineGuestOsIdentifierRhel3_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierRhel4Guest,
|
||||
types.VirtualMachineGuestOsIdentifierRhel4_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierRhel5Guest,
|
||||
types.VirtualMachineGuestOsIdentifierRhel5_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierRhel6Guest,
|
||||
types.VirtualMachineGuestOsIdentifierRhel6_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierRhel7Guest,
|
||||
types.VirtualMachineGuestOsIdentifierRhel7_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierCentosGuest,
|
||||
types.VirtualMachineGuestOsIdentifierCentos64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierCentos6Guest,
|
||||
types.VirtualMachineGuestOsIdentifierCentos6_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierCentos7Guest,
|
||||
types.VirtualMachineGuestOsIdentifierCentos7_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierOracleLinuxGuest,
|
||||
types.VirtualMachineGuestOsIdentifierOracleLinux64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierOracleLinux6Guest,
|
||||
types.VirtualMachineGuestOsIdentifierOracleLinux6_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierOracleLinux7Guest,
|
||||
types.VirtualMachineGuestOsIdentifierOracleLinux7_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierSuseGuest,
|
||||
types.VirtualMachineGuestOsIdentifierSuse64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierSlesGuest,
|
||||
types.VirtualMachineGuestOsIdentifierSles64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierSles10Guest,
|
||||
types.VirtualMachineGuestOsIdentifierSles10_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierSles11Guest,
|
||||
types.VirtualMachineGuestOsIdentifierSles11_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierSles12Guest,
|
||||
types.VirtualMachineGuestOsIdentifierSles12_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierNld9Guest,
|
||||
types.VirtualMachineGuestOsIdentifierOesGuest,
|
||||
types.VirtualMachineGuestOsIdentifierSjdsGuest,
|
||||
types.VirtualMachineGuestOsIdentifierMandrakeGuest,
|
||||
types.VirtualMachineGuestOsIdentifierMandrivaGuest,
|
||||
types.VirtualMachineGuestOsIdentifierMandriva64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierTurboLinuxGuest,
|
||||
types.VirtualMachineGuestOsIdentifierTurboLinux64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierUbuntuGuest,
|
||||
types.VirtualMachineGuestOsIdentifierUbuntu64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDebian4Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDebian4_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDebian5Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDebian5_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDebian6Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDebian6_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDebian7Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDebian7_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDebian8Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDebian8_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDebian9Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDebian9_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDebian10Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDebian10_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierAsianux3Guest,
|
||||
types.VirtualMachineGuestOsIdentifierAsianux3_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierAsianux4Guest,
|
||||
types.VirtualMachineGuestOsIdentifierAsianux4_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierAsianux5_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierAsianux7_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierOpensuseGuest,
|
||||
types.VirtualMachineGuestOsIdentifierOpensuse64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierFedoraGuest,
|
||||
types.VirtualMachineGuestOsIdentifierFedora64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierCoreos64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierVmwarePhoton64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierOther24xLinuxGuest,
|
||||
types.VirtualMachineGuestOsIdentifierOther26xLinuxGuest,
|
||||
types.VirtualMachineGuestOsIdentifierOtherLinuxGuest,
|
||||
types.VirtualMachineGuestOsIdentifierOther3xLinuxGuest,
|
||||
types.VirtualMachineGuestOsIdentifierGenericLinuxGuest,
|
||||
types.VirtualMachineGuestOsIdentifierOther24xLinux64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierOther26xLinux64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierOther3xLinux64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierOtherLinux64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierSolaris6Guest,
|
||||
types.VirtualMachineGuestOsIdentifierSolaris7Guest,
|
||||
types.VirtualMachineGuestOsIdentifierSolaris8Guest,
|
||||
types.VirtualMachineGuestOsIdentifierSolaris9Guest,
|
||||
types.VirtualMachineGuestOsIdentifierSolaris10Guest,
|
||||
types.VirtualMachineGuestOsIdentifierSolaris10_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierSolaris11_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierOs2Guest,
|
||||
types.VirtualMachineGuestOsIdentifierEComStationGuest,
|
||||
types.VirtualMachineGuestOsIdentifierEComStation2Guest,
|
||||
types.VirtualMachineGuestOsIdentifierNetware4Guest,
|
||||
types.VirtualMachineGuestOsIdentifierNetware5Guest,
|
||||
types.VirtualMachineGuestOsIdentifierNetware6Guest,
|
||||
types.VirtualMachineGuestOsIdentifierOpenServer5Guest,
|
||||
types.VirtualMachineGuestOsIdentifierOpenServer6Guest,
|
||||
types.VirtualMachineGuestOsIdentifierUnixWare7Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDarwinGuest,
|
||||
types.VirtualMachineGuestOsIdentifierDarwin64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDarwin10Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDarwin10_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDarwin11Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDarwin11_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDarwin12_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDarwin13_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDarwin14_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDarwin15_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierDarwin16_64Guest,
|
||||
types.VirtualMachineGuestOsIdentifierVmkernelGuest,
|
||||
types.VirtualMachineGuestOsIdentifierVmkernel5Guest,
|
||||
types.VirtualMachineGuestOsIdentifierVmkernel6Guest,
|
||||
types.VirtualMachineGuestOsIdentifierVmkernel65Guest,
|
||||
types.VirtualMachineGuestOsIdentifierOtherGuest,
|
||||
types.VirtualMachineGuestOsIdentifierOtherGuest64,
|
||||
}
|
||||
35
vendor/github.com/vmware/govmomi/simulator/guest_id.sh
generated
vendored
Executable file
35
vendor/github.com/vmware/govmomi/simulator/guest_id.sh
generated
vendored
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
pushd "$(dirname "$0")" >/dev/null
|
||||
|
||||
{
|
||||
cat <<EOF
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
// GuestID is the list of valid types.VirtualMachineGuestOsIdentifier
|
||||
var GuestID = []types.VirtualMachineGuestOsIdentifier{
|
||||
EOF
|
||||
|
||||
ids=($(grep 'VirtualMachineGuestOsIdentifier(' ../vim25/types/enum.go | grep = | awk '{print $1}'))
|
||||
printf "types.%s,\n" "${ids[@]}"
|
||||
|
||||
echo "}"
|
||||
} > guest_id.go
|
||||
|
||||
goimports -w guest_id.go
|
||||
254
vendor/github.com/vmware/govmomi/simulator/host_datastore_browser.go
generated
vendored
Normal file
254
vendor/github.com/vmware/govmomi/simulator/host_datastore_browser.go
generated
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type HostDatastoreBrowser struct {
|
||||
mo.HostDatastoreBrowser
|
||||
}
|
||||
|
||||
type searchDatastore struct {
|
||||
*HostDatastoreBrowser
|
||||
|
||||
DatastorePath string
|
||||
SearchSpec *types.HostDatastoreBrowserSearchSpec
|
||||
|
||||
res []types.HostDatastoreBrowserSearchResults
|
||||
|
||||
recurse bool
|
||||
}
|
||||
|
||||
func (s *searchDatastore) addFile(file os.FileInfo, res *types.HostDatastoreBrowserSearchResults) {
|
||||
details := s.SearchSpec.Details
|
||||
if details == nil {
|
||||
details = new(types.FileQueryFlags)
|
||||
}
|
||||
|
||||
name := file.Name()
|
||||
|
||||
info := types.FileInfo{
|
||||
Path: name,
|
||||
}
|
||||
|
||||
var finfo types.BaseFileInfo = &info
|
||||
|
||||
if details.FileSize {
|
||||
info.FileSize = file.Size()
|
||||
}
|
||||
|
||||
if details.Modification {
|
||||
mtime := file.ModTime()
|
||||
info.Modification = &mtime
|
||||
}
|
||||
|
||||
if isTrue(details.FileOwner) {
|
||||
// Assume for now this process created all files in the datastore
|
||||
user := os.Getenv("USER")
|
||||
|
||||
info.Owner = user
|
||||
}
|
||||
|
||||
if file.IsDir() {
|
||||
finfo = &types.FolderFileInfo{FileInfo: info}
|
||||
} else if details.FileType {
|
||||
switch path.Ext(name) {
|
||||
case ".img":
|
||||
finfo = &types.FloppyImageFileInfo{FileInfo: info}
|
||||
case ".iso":
|
||||
finfo = &types.IsoImageFileInfo{FileInfo: info}
|
||||
case ".log":
|
||||
finfo = &types.VmLogFileInfo{FileInfo: info}
|
||||
case ".nvram":
|
||||
finfo = &types.VmNvramFileInfo{FileInfo: info}
|
||||
case ".vmdk":
|
||||
// TODO: lookup device to set other fields
|
||||
finfo = &types.VmDiskFileInfo{FileInfo: info}
|
||||
case ".vmx":
|
||||
finfo = &types.VmConfigFileInfo{FileInfo: info}
|
||||
}
|
||||
}
|
||||
|
||||
res.File = append(res.File, finfo)
|
||||
}
|
||||
|
||||
func (s *searchDatastore) queryMatch(file os.FileInfo) bool {
|
||||
if len(s.SearchSpec.Query) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
name := file.Name()
|
||||
ext := path.Ext(name)
|
||||
|
||||
for _, q := range s.SearchSpec.Query {
|
||||
switch q.(type) {
|
||||
case *types.FileQuery:
|
||||
return true
|
||||
case *types.FolderFileQuery:
|
||||
if file.IsDir() {
|
||||
return true
|
||||
}
|
||||
case *types.FloppyImageFileQuery:
|
||||
if ext == ".img" {
|
||||
return true
|
||||
}
|
||||
case *types.IsoImageFileQuery:
|
||||
if ext == ".iso" {
|
||||
return true
|
||||
}
|
||||
case *types.VmConfigFileQuery:
|
||||
if ext == ".vmx" {
|
||||
// TODO: check Filter and Details fields
|
||||
return true
|
||||
}
|
||||
case *types.VmDiskFileQuery:
|
||||
if ext == ".vmdk" {
|
||||
if strings.HasSuffix(name, "-flat.vmdk") {
|
||||
// only matches the descriptor, not the backing file(s)
|
||||
return false
|
||||
}
|
||||
// TODO: check Filter and Details fields
|
||||
return true
|
||||
}
|
||||
case *types.VmLogFileQuery:
|
||||
if ext == ".log" {
|
||||
return strings.HasPrefix(name, "vmware")
|
||||
}
|
||||
case *types.VmNvramFileQuery:
|
||||
if ext == ".nvram" {
|
||||
return true
|
||||
}
|
||||
case *types.VmSnapshotFileQuery:
|
||||
if ext == ".vmsn" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *searchDatastore) search(ds *types.ManagedObjectReference, folder string, dir string) error {
|
||||
files, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
log.Printf("search %s: %s", dir, err)
|
||||
return err
|
||||
}
|
||||
|
||||
res := types.HostDatastoreBrowserSearchResults{
|
||||
Datastore: ds,
|
||||
FolderPath: folder,
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
name := file.Name()
|
||||
|
||||
if s.queryMatch(file) {
|
||||
for _, m := range s.SearchSpec.MatchPattern {
|
||||
if ok, _ := path.Match(m, name); ok {
|
||||
s.addFile(file, &res)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if s.recurse && file.IsDir() {
|
||||
_ = s.search(ds, path.Join(folder, name), path.Join(dir, name))
|
||||
}
|
||||
}
|
||||
|
||||
s.res = append(s.res, res)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *searchDatastore) Run(Task *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
p, fault := parseDatastorePath(s.DatastorePath)
|
||||
if fault != nil {
|
||||
return nil, fault
|
||||
}
|
||||
|
||||
ref := Map.FindByName(p.Datastore, s.Datastore)
|
||||
if ref == nil {
|
||||
return nil, &types.InvalidDatastore{Name: p.Datastore}
|
||||
}
|
||||
|
||||
ds := ref.(*Datastore)
|
||||
|
||||
dir := path.Join(ds.Info.GetDatastoreInfo().Url, p.Path)
|
||||
|
||||
err := s.search(&ds.Self, s.DatastorePath, dir)
|
||||
if err != nil {
|
||||
ff := types.FileFault{
|
||||
File: p.Path,
|
||||
}
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
return nil, &types.FileNotFound{FileFault: ff}
|
||||
}
|
||||
|
||||
return nil, &types.InvalidArgument{InvalidProperty: p.Path}
|
||||
}
|
||||
|
||||
if s.recurse {
|
||||
return types.ArrayOfHostDatastoreBrowserSearchResults{
|
||||
HostDatastoreBrowserSearchResults: s.res,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return s.res[0], nil
|
||||
}
|
||||
|
||||
func (b *HostDatastoreBrowser) SearchDatastoreTask(s *types.SearchDatastore_Task) soap.HasFault {
|
||||
task := NewTask(&searchDatastore{
|
||||
HostDatastoreBrowser: b,
|
||||
DatastorePath: s.DatastorePath,
|
||||
SearchSpec: s.SearchSpec,
|
||||
})
|
||||
|
||||
return &methods.SearchDatastore_TaskBody{
|
||||
Res: &types.SearchDatastore_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (b *HostDatastoreBrowser) SearchDatastoreSubFoldersTask(s *types.SearchDatastoreSubFolders_Task) soap.HasFault {
|
||||
task := NewTask(&searchDatastore{
|
||||
HostDatastoreBrowser: b,
|
||||
DatastorePath: s.DatastorePath,
|
||||
SearchSpec: s.SearchSpec,
|
||||
recurse: true,
|
||||
})
|
||||
|
||||
return &methods.SearchDatastoreSubFolders_TaskBody{
|
||||
Res: &types.SearchDatastoreSubFolders_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
161
vendor/github.com/vmware/govmomi/simulator/host_datastore_system.go
generated
vendored
Normal file
161
vendor/github.com/vmware/govmomi/simulator/host_datastore_system.go
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type HostDatastoreSystem struct {
|
||||
mo.HostDatastoreSystem
|
||||
|
||||
Host *mo.HostSystem
|
||||
}
|
||||
|
||||
func (dss *HostDatastoreSystem) add(ds *Datastore) *soap.Fault {
|
||||
info := ds.Info.GetDatastoreInfo()
|
||||
|
||||
info.Name = ds.Name
|
||||
|
||||
if e := Map.FindByName(ds.Name, dss.Datastore); e != nil {
|
||||
return Fault(e.Reference().Value, &types.DuplicateName{
|
||||
Name: ds.Name,
|
||||
Object: e.Reference(),
|
||||
})
|
||||
}
|
||||
|
||||
fi, err := os.Stat(info.Url)
|
||||
if err == nil && !fi.IsDir() {
|
||||
err = os.ErrInvalid
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
switch {
|
||||
case os.IsNotExist(err):
|
||||
return Fault(err.Error(), &types.NotFound{})
|
||||
default:
|
||||
return Fault(err.Error(), &types.HostConfigFault{})
|
||||
}
|
||||
}
|
||||
|
||||
folder := Map.getEntityFolder(dss.Host, "datastore")
|
||||
ds.Self.Type = typeName(ds)
|
||||
// Datastore is the only type where create methods do not include the parent (Folder in this case),
|
||||
// but we need the moref to be unique per DC/datastoreFolder, but not per-HostSystem.
|
||||
ds.Self.Value += "@" + folder.Self.Value
|
||||
// TODO: name should be made unique in the case of Local ds type
|
||||
|
||||
ds.Summary.Datastore = &ds.Self
|
||||
ds.Summary.Name = ds.Name
|
||||
ds.Summary.Url = info.Url
|
||||
|
||||
dss.Datastore = append(dss.Datastore, ds.Self)
|
||||
dss.Host.Datastore = dss.Datastore
|
||||
parent := hostParent(dss.Host)
|
||||
Map.AddReference(parent, &parent.Datastore, ds.Self)
|
||||
|
||||
browser := &HostDatastoreBrowser{}
|
||||
browser.Datastore = dss.Datastore
|
||||
ds.Browser = Map.Put(browser).Reference()
|
||||
|
||||
folder.putChild(ds)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dss *HostDatastoreSystem) CreateLocalDatastore(c *types.CreateLocalDatastore) soap.HasFault {
|
||||
r := &methods.CreateLocalDatastoreBody{}
|
||||
|
||||
ds := &Datastore{}
|
||||
ds.Name = c.Name
|
||||
ds.Self.Value = c.Path
|
||||
|
||||
ds.Info = &types.LocalDatastoreInfo{
|
||||
DatastoreInfo: types.DatastoreInfo{
|
||||
Name: c.Name,
|
||||
Url: c.Path,
|
||||
},
|
||||
Path: c.Path,
|
||||
}
|
||||
|
||||
ds.Summary.Type = "local"
|
||||
|
||||
if err := dss.add(ds); err != nil {
|
||||
r.Fault_ = err
|
||||
return r
|
||||
}
|
||||
|
||||
ds.Host = append(ds.Host, types.DatastoreHostMount{
|
||||
Key: dss.Host.Reference(),
|
||||
MountInfo: types.HostMountInfo{
|
||||
AccessMode: string(types.HostMountModeReadWrite),
|
||||
Mounted: types.NewBool(true),
|
||||
Accessible: types.NewBool(true),
|
||||
},
|
||||
})
|
||||
|
||||
_ = ds.RefreshDatastore(&types.RefreshDatastore{This: ds.Self})
|
||||
|
||||
r.Res = &types.CreateLocalDatastoreResponse{
|
||||
Returnval: ds.Self,
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (dss *HostDatastoreSystem) CreateNasDatastore(c *types.CreateNasDatastore) soap.HasFault {
|
||||
r := &methods.CreateNasDatastoreBody{}
|
||||
|
||||
ds := &Datastore{}
|
||||
ds.Name = path.Base(c.Spec.LocalPath)
|
||||
ds.Self.Value = c.Spec.RemoteHost + ":" + c.Spec.RemotePath
|
||||
|
||||
ds.Info = &types.NasDatastoreInfo{
|
||||
DatastoreInfo: types.DatastoreInfo{
|
||||
Url: c.Spec.LocalPath,
|
||||
},
|
||||
Nas: &types.HostNasVolume{
|
||||
HostFileSystemVolume: types.HostFileSystemVolume{
|
||||
Name: c.Spec.LocalPath,
|
||||
Type: c.Spec.Type,
|
||||
},
|
||||
RemoteHost: c.Spec.RemoteHost,
|
||||
RemotePath: c.Spec.RemotePath,
|
||||
},
|
||||
}
|
||||
|
||||
ds.Summary.Type = c.Spec.Type
|
||||
|
||||
if err := dss.add(ds); err != nil {
|
||||
r.Fault_ = err
|
||||
return r
|
||||
}
|
||||
|
||||
_ = ds.RefreshDatastore(&types.RefreshDatastore{This: ds.Self})
|
||||
|
||||
r.Res = &types.CreateNasDatastoreResponse{
|
||||
Returnval: ds.Self,
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
100
vendor/github.com/vmware/govmomi/simulator/host_datastore_system_test.go
generated
vendored
Normal file
100
vendor/github.com/vmware/govmomi/simulator/host_datastore_system_test.go
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestHostDatastoreSystem(t *testing.T) {
|
||||
s := New(NewServiceInstance(esx.ServiceContent, esx.RootFolder))
|
||||
|
||||
ts := s.NewServer()
|
||||
defer ts.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, ts.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
host := object.NewHostSystem(c.Client, esx.HostSystem.Reference())
|
||||
|
||||
dss, err := host.ConfigManager().DatastoreSystem(ctx)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
pwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
spec := types.HostNasVolumeSpec{
|
||||
Type: string(types.HostFileSystemVolumeFileSystemTypeNFS),
|
||||
RemoteHost: "localhost",
|
||||
}
|
||||
|
||||
tests := []func(string) (*object.Datastore, error){
|
||||
func(dir string) (*object.Datastore, error) {
|
||||
spec.LocalPath = dir
|
||||
spec.RemotePath = dir
|
||||
return dss.CreateNasDatastore(ctx, spec)
|
||||
},
|
||||
func(dir string) (*object.Datastore, error) {
|
||||
return dss.CreateLocalDatastore(ctx, filepath.Base(dir), dir)
|
||||
},
|
||||
}
|
||||
|
||||
for _, create := range tests {
|
||||
for _, fail := range []bool{false, true} {
|
||||
if fail {
|
||||
_, err = create(pwd)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
// TODO: hds.Remove(ds)
|
||||
pwd = filepath.Join(pwd, "esx")
|
||||
} else {
|
||||
_, err = create(pwd)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, create := range tests {
|
||||
for _, dir := range []string{"./enoent", "host_datastore_system.go"} {
|
||||
_, err = create(dir)
|
||||
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
87
vendor/github.com/vmware/govmomi/simulator/host_firewall_system.go
generated
vendored
Normal file
87
vendor/github.com/vmware/govmomi/simulator/host_firewall_system.go
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type HostFirewallSystem struct {
|
||||
mo.HostFirewallSystem
|
||||
}
|
||||
|
||||
func NewHostFirewallSystem(_ *mo.HostSystem) *HostFirewallSystem {
|
||||
info := esx.HostFirewallInfo
|
||||
|
||||
return &HostFirewallSystem{
|
||||
HostFirewallSystem: mo.HostFirewallSystem{
|
||||
FirewallInfo: &info,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func DisableRuleset(info *types.HostFirewallInfo, id string) bool {
|
||||
for i := range info.Ruleset {
|
||||
if info.Ruleset[i].Key == id {
|
||||
info.Ruleset[i].Enabled = false
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *HostFirewallSystem) DisableRuleset(req *types.DisableRuleset) soap.HasFault {
|
||||
body := &methods.DisableRulesetBody{}
|
||||
|
||||
if DisableRuleset(s.HostFirewallSystem.FirewallInfo, req.Id) {
|
||||
body.Res = new(types.DisableRulesetResponse)
|
||||
return body
|
||||
}
|
||||
|
||||
body.Fault_ = Fault("", &types.NotFound{})
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func EnableRuleset(info *types.HostFirewallInfo, id string) bool {
|
||||
for i := range info.Ruleset {
|
||||
if info.Ruleset[i].Key == id {
|
||||
info.Ruleset[i].Enabled = true
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *HostFirewallSystem) EnableRuleset(req *types.EnableRuleset) soap.HasFault {
|
||||
body := &methods.EnableRulesetBody{}
|
||||
|
||||
if EnableRuleset(s.HostFirewallSystem.FirewallInfo, req.Id) {
|
||||
body.Res = new(types.EnableRulesetResponse)
|
||||
return body
|
||||
}
|
||||
|
||||
body.Fault_ = Fault("", &types.NotFound{})
|
||||
|
||||
return body
|
||||
}
|
||||
69
vendor/github.com/vmware/govmomi/simulator/host_firewall_system_test.go
generated
vendored
Normal file
69
vendor/github.com/vmware/govmomi/simulator/host_firewall_system_test.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
)
|
||||
|
||||
func TestHostFirewallSystem(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
m := ESX()
|
||||
m.Datastore = 0
|
||||
m.Machine = 0
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c := m.Service.client
|
||||
|
||||
host := object.NewHostSystem(c, esx.HostSystem.Reference())
|
||||
|
||||
hfs, _ := host.ConfigManager().FirewallSystem(ctx)
|
||||
|
||||
err = hfs.DisableRuleset(ctx, "enoent")
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
err = hfs.EnableRuleset(ctx, "enoent")
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
err = hfs.DisableRuleset(ctx, "sshServer")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
err = hfs.EnableRuleset(ctx, "sshServer")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = hfs.Info(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
80
vendor/github.com/vmware/govmomi/simulator/host_local_account_manager.go
generated
vendored
Normal file
80
vendor/github.com/vmware/govmomi/simulator/host_local_account_manager.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
// As of vSphere API 5.1, local groups operations are deprecated, so it's not supported here.
|
||||
|
||||
type HostLocalAccountManager struct {
|
||||
mo.HostLocalAccountManager
|
||||
}
|
||||
|
||||
func NewHostLocalAccountManager(ref types.ManagedObjectReference) object.Reference {
|
||||
m := &HostLocalAccountManager{}
|
||||
m.Self = ref
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func (h *HostLocalAccountManager) CreateUser(req *types.CreateUser) soap.HasFault {
|
||||
spec := req.User.GetHostAccountSpec()
|
||||
userDirectory := Map.UserDirectory()
|
||||
|
||||
found := userDirectory.search(true, false, compareFunc(spec.Id, true))
|
||||
if len(found) > 0 {
|
||||
return &methods.CreateUserBody{
|
||||
Fault_: Fault("", &types.AlreadyExists{}),
|
||||
}
|
||||
}
|
||||
|
||||
userDirectory.addUser(spec.Id)
|
||||
|
||||
return &methods.CreateUserBody{
|
||||
Res: &types.CreateUserResponse{},
|
||||
}
|
||||
}
|
||||
|
||||
func (h *HostLocalAccountManager) RemoveUser(req *types.RemoveUser) soap.HasFault {
|
||||
userDirectory := Map.UserDirectory()
|
||||
|
||||
found := userDirectory.search(true, false, compareFunc(req.UserName, true))
|
||||
|
||||
if len(found) == 0 {
|
||||
return &methods.RemoveUserBody{
|
||||
Fault_: Fault("", &types.UserNotFound{}),
|
||||
}
|
||||
}
|
||||
|
||||
userDirectory.removeUser(req.UserName)
|
||||
|
||||
return &methods.RemoveUserBody{
|
||||
Res: &types.RemoveUserResponse{},
|
||||
}
|
||||
}
|
||||
|
||||
func (h *HostLocalAccountManager) UpdateUser(req *types.UpdateUser) soap.HasFault {
|
||||
return &methods.CreateUserBody{
|
||||
Res: &types.CreateUserResponse{},
|
||||
}
|
||||
}
|
||||
92
vendor/github.com/vmware/govmomi/simulator/host_local_account_manager_test.go
generated
vendored
Normal file
92
vendor/github.com/vmware/govmomi/simulator/host_local_account_manager_test.go
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestHostLocalAccountManager(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
m := ESX()
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ts := m.Service.NewServer()
|
||||
defer ts.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, ts.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ref := types.ManagedObjectReference{Type: "HostLocalAccountManager", Value: "ha-localacctmgr"}
|
||||
|
||||
createUserReq := &types.CreateUser{
|
||||
This: ref,
|
||||
User: &types.HostAccountSpec{
|
||||
Id: "userid",
|
||||
},
|
||||
}
|
||||
|
||||
_, err = methods.CreateUser(ctx, c.Client, createUserReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = methods.CreateUser(ctx, c.Client, createUserReq)
|
||||
if err == nil {
|
||||
t.Fatal("expect err; got nil")
|
||||
}
|
||||
|
||||
updateUserReq := &types.UpdateUser{
|
||||
This: ref,
|
||||
User: &types.HostAccountSpec{
|
||||
Id: "userid",
|
||||
},
|
||||
}
|
||||
|
||||
_, err = methods.UpdateUser(ctx, c.Client, updateUserReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
removeUserReq := &types.RemoveUser{
|
||||
This: ref,
|
||||
UserName: "userid",
|
||||
}
|
||||
|
||||
_, err = methods.RemoveUser(ctx, c.Client, removeUserReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = methods.RemoveUser(ctx, c.Client, removeUserReq)
|
||||
if err == nil {
|
||||
t.Fatal("expect err; got nil")
|
||||
}
|
||||
}
|
||||
171
vendor/github.com/vmware/govmomi/simulator/host_network_system.go
generated
vendored
Normal file
171
vendor/github.com/vmware/govmomi/simulator/host_network_system.go
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type HostNetworkSystem struct {
|
||||
mo.HostNetworkSystem
|
||||
|
||||
Host *mo.HostSystem
|
||||
}
|
||||
|
||||
func NewHostNetworkSystem(host *mo.HostSystem) *HostNetworkSystem {
|
||||
return &HostNetworkSystem{
|
||||
Host: host,
|
||||
HostNetworkSystem: mo.HostNetworkSystem{
|
||||
NetworkInfo: &types.HostNetworkInfo{
|
||||
Vswitch: []types.HostVirtualSwitch{
|
||||
{
|
||||
Name: "vSwitch0",
|
||||
Portgroup: []string{"VM Network"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *HostNetworkSystem) folder() *Folder {
|
||||
f := Map.getEntityDatacenter(s.Host).NetworkFolder
|
||||
return Map.Get(f).(*Folder)
|
||||
}
|
||||
|
||||
func (s *HostNetworkSystem) AddVirtualSwitch(c *types.AddVirtualSwitch) soap.HasFault {
|
||||
r := &methods.AddVirtualSwitchBody{}
|
||||
|
||||
for _, vswitch := range s.NetworkInfo.Vswitch {
|
||||
if vswitch.Name == c.VswitchName {
|
||||
r.Fault_ = Fault("", &types.AlreadyExists{Name: c.VswitchName})
|
||||
return r
|
||||
}
|
||||
}
|
||||
|
||||
s.NetworkInfo.Vswitch = append(s.NetworkInfo.Vswitch, types.HostVirtualSwitch{
|
||||
Name: c.VswitchName,
|
||||
})
|
||||
|
||||
r.Res = &types.AddVirtualSwitchResponse{}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (s *HostNetworkSystem) RemoveVirtualSwitch(c *types.RemoveVirtualSwitch) soap.HasFault {
|
||||
r := &methods.RemoveVirtualSwitchBody{}
|
||||
|
||||
vs := s.NetworkInfo.Vswitch
|
||||
|
||||
for i, v := range vs {
|
||||
if v.Name == c.VswitchName {
|
||||
s.NetworkInfo.Vswitch = append(vs[:i], vs[i+1:]...)
|
||||
r.Res = &types.RemoveVirtualSwitchResponse{}
|
||||
return r
|
||||
}
|
||||
}
|
||||
|
||||
r.Fault_ = Fault("", &types.NotFound{})
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (s *HostNetworkSystem) AddPortGroup(c *types.AddPortGroup) soap.HasFault {
|
||||
var vswitch *types.HostVirtualSwitch
|
||||
|
||||
r := &methods.AddPortGroupBody{}
|
||||
|
||||
if c.Portgrp.Name == "" {
|
||||
r.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "name"})
|
||||
return r
|
||||
}
|
||||
|
||||
for i := range s.NetworkInfo.Vswitch {
|
||||
if s.NetworkInfo.Vswitch[i].Name == c.Portgrp.VswitchName {
|
||||
vswitch = &s.NetworkInfo.Vswitch[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if vswitch == nil {
|
||||
r.Fault_ = Fault("", &types.NotFound{})
|
||||
return r
|
||||
}
|
||||
|
||||
network := &mo.Network{}
|
||||
network.Name = c.Portgrp.Name
|
||||
network.Entity().Name = network.Name
|
||||
|
||||
folder := s.folder()
|
||||
|
||||
if obj := Map.FindByName(c.Portgrp.Name, folder.ChildEntity); obj != nil {
|
||||
r.Fault_ = Fault("", &types.DuplicateName{
|
||||
Name: c.Portgrp.Name,
|
||||
Object: obj.Reference(),
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
folder.putChild(network)
|
||||
|
||||
vswitch.Portgroup = append(vswitch.Portgroup, c.Portgrp.Name)
|
||||
r.Res = &types.AddPortGroupResponse{}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (s *HostNetworkSystem) RemovePortGroup(c *types.RemovePortGroup) soap.HasFault {
|
||||
var vswitch *types.HostVirtualSwitch
|
||||
|
||||
r := &methods.RemovePortGroupBody{}
|
||||
|
||||
for i, v := range s.NetworkInfo.Vswitch {
|
||||
for j, pg := range v.Portgroup {
|
||||
if pg == c.PgName {
|
||||
vswitch = &s.NetworkInfo.Vswitch[i]
|
||||
vswitch.Portgroup = append(vswitch.Portgroup[:j], vswitch.Portgroup[j+1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if vswitch == nil {
|
||||
r.Fault_ = Fault("", &types.NotFound{})
|
||||
return r
|
||||
}
|
||||
|
||||
folder := s.folder()
|
||||
e := Map.FindByName(c.PgName, folder.ChildEntity)
|
||||
folder.removeChild(e.Reference())
|
||||
|
||||
r.Res = &types.RemovePortGroupResponse{}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (s *HostNetworkSystem) UpdateNetworkConfig(req *types.UpdateNetworkConfig) soap.HasFault {
|
||||
s.NetworkConfig = &req.Config
|
||||
|
||||
return &methods.UpdateNetworkConfigBody{
|
||||
Res: &types.UpdateNetworkConfigResponse{
|
||||
Returnval: types.HostNetworkConfigResult{},
|
||||
},
|
||||
}
|
||||
}
|
||||
118
vendor/github.com/vmware/govmomi/simulator/host_network_system_test.go
generated
vendored
Normal file
118
vendor/github.com/vmware/govmomi/simulator/host_network_system_test.go
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi/find"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestHostNetworkSystem(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
s := New(NewServiceInstance(esx.ServiceContent, esx.RootFolder))
|
||||
|
||||
host := object.NewHostSystem(s.client, esx.HostSystem.Reference())
|
||||
|
||||
ns, err := host.ConfigManager().NetworkSystem(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder := find.NewFinder(s.client, false)
|
||||
finder.SetDatacenter(object.NewDatacenter(s.client, esx.Datacenter.Reference()))
|
||||
|
||||
// created by default
|
||||
_, err = finder.Network(ctx, "VM Network")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// not created yet
|
||||
_, err = finder.Network(ctx, "bridge")
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
|
||||
err = ns.AddVirtualSwitch(ctx, "vSwitch0", nil)
|
||||
if err == nil {
|
||||
t.Fatal("expected error") // DuplicateName
|
||||
}
|
||||
|
||||
err = ns.AddVirtualSwitch(ctx, "vSwitch1", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
spec := types.HostPortGroupSpec{}
|
||||
err = ns.AddPortGroup(ctx, spec)
|
||||
if err == nil {
|
||||
t.Fatal("expected error") // InvalidArgument "name"
|
||||
}
|
||||
|
||||
spec.Name = "bridge"
|
||||
err = ns.AddPortGroup(ctx, spec)
|
||||
if err == nil {
|
||||
t.Fatal("expected error") // NotFound
|
||||
}
|
||||
|
||||
spec.VswitchName = "vSwitch1"
|
||||
err = ns.AddPortGroup(ctx, spec)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = finder.Network(ctx, "bridge")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ns.AddPortGroup(ctx, spec)
|
||||
if err == nil {
|
||||
t.Error("expected error") // DuplicateName
|
||||
}
|
||||
|
||||
err = ns.RemovePortGroup(ctx, "bridge")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = finder.Network(ctx, "bridge")
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
|
||||
err = ns.RemovePortGroup(ctx, "bridge")
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
err = ns.RemoveVirtualSwitch(ctx, "vSwitch1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ns.RemoveVirtualSwitch(ctx, "vSwitch1")
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
}
|
||||
219
vendor/github.com/vmware/govmomi/simulator/host_system.go
generated
vendored
Normal file
219
vendor/github.com/vmware/govmomi/simulator/host_system.go
generated
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type HostSystem struct {
|
||||
mo.HostSystem
|
||||
}
|
||||
|
||||
func NewHostSystem(host mo.HostSystem) *HostSystem {
|
||||
now := time.Now()
|
||||
|
||||
hs := &HostSystem{
|
||||
HostSystem: host,
|
||||
}
|
||||
|
||||
hs.Name = hs.Summary.Config.Name
|
||||
hs.Summary.Runtime = &hs.Runtime
|
||||
hs.Summary.Runtime.BootTime = &now
|
||||
|
||||
id := uuid.New().String()
|
||||
|
||||
hardware := *host.Summary.Hardware
|
||||
hs.Summary.Hardware = &hardware
|
||||
hs.Summary.Hardware.Uuid = id
|
||||
|
||||
info := *esx.HostHardwareInfo
|
||||
info.SystemInfo.Uuid = id
|
||||
hs.Hardware = &info
|
||||
|
||||
config := []struct {
|
||||
ref **types.ManagedObjectReference
|
||||
obj mo.Reference
|
||||
}{
|
||||
{&hs.ConfigManager.DatastoreSystem, &HostDatastoreSystem{Host: &hs.HostSystem}},
|
||||
{&hs.ConfigManager.NetworkSystem, NewHostNetworkSystem(&hs.HostSystem)},
|
||||
{&hs.ConfigManager.AdvancedOption, NewOptionManager(nil, esx.Setting)},
|
||||
{&hs.ConfigManager.FirewallSystem, NewHostFirewallSystem(&hs.HostSystem)},
|
||||
}
|
||||
|
||||
for _, c := range config {
|
||||
ref := Map.Put(c.obj).Reference()
|
||||
|
||||
*c.ref = &ref
|
||||
}
|
||||
|
||||
return hs
|
||||
}
|
||||
|
||||
func (h *HostSystem) eventArgument() *types.HostEventArgument {
|
||||
return &types.HostEventArgument{
|
||||
Host: h.Self,
|
||||
EntityEventArgument: types.EntityEventArgument{Name: h.Name},
|
||||
}
|
||||
}
|
||||
|
||||
func (h *HostSystem) eventArgumentParent() *types.ComputeResourceEventArgument {
|
||||
parent := hostParent(&h.HostSystem)
|
||||
|
||||
return &types.ComputeResourceEventArgument{
|
||||
ComputeResource: parent.Self,
|
||||
EntityEventArgument: types.EntityEventArgument{Name: parent.Name},
|
||||
}
|
||||
}
|
||||
|
||||
func hostParent(host *mo.HostSystem) *mo.ComputeResource {
|
||||
switch parent := Map.Get(*host.Parent).(type) {
|
||||
case *mo.ComputeResource:
|
||||
return parent
|
||||
case *ClusterComputeResource:
|
||||
return &parent.ComputeResource
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func addComputeResource(s *types.ComputeResourceSummary, h *HostSystem) {
|
||||
s.TotalCpu += h.Summary.Hardware.CpuMhz
|
||||
s.TotalMemory += h.Summary.Hardware.MemorySize
|
||||
s.NumCpuCores += h.Summary.Hardware.NumCpuCores
|
||||
s.NumCpuThreads += h.Summary.Hardware.NumCpuThreads
|
||||
s.EffectiveCpu += h.Summary.Hardware.CpuMhz
|
||||
s.EffectiveMemory += h.Summary.Hardware.MemorySize
|
||||
s.NumHosts++
|
||||
s.NumEffectiveHosts++
|
||||
s.OverallStatus = types.ManagedEntityStatusGreen
|
||||
}
|
||||
|
||||
// CreateDefaultESX creates a standalone ESX
|
||||
// Adds objects of type: Datacenter, Network, ComputeResource, ResourcePool and HostSystem
|
||||
func CreateDefaultESX(f *Folder) {
|
||||
dc := NewDatacenter(f)
|
||||
|
||||
host := NewHostSystem(esx.HostSystem)
|
||||
|
||||
summary := new(types.ComputeResourceSummary)
|
||||
addComputeResource(summary, host)
|
||||
|
||||
cr := &mo.ComputeResource{Summary: summary}
|
||||
cr.Self = *host.Parent
|
||||
cr.Name = host.Name
|
||||
cr.Host = append(cr.Host, host.Reference())
|
||||
Map.PutEntity(cr, host)
|
||||
|
||||
pool := NewResourcePool()
|
||||
cr.ResourcePool = &pool.Self
|
||||
Map.PutEntity(cr, pool)
|
||||
pool.Owner = cr.Self
|
||||
|
||||
Map.Get(dc.HostFolder).(*Folder).putChild(cr)
|
||||
}
|
||||
|
||||
// CreateStandaloneHost uses esx.HostSystem as a template, applying the given spec
|
||||
// and creating the ComputeResource parent and ResourcePool sibling.
|
||||
func CreateStandaloneHost(f *Folder, spec types.HostConnectSpec) (*HostSystem, types.BaseMethodFault) {
|
||||
if spec.HostName == "" {
|
||||
return nil, &types.NoHost{}
|
||||
}
|
||||
|
||||
pool := NewResourcePool()
|
||||
host := NewHostSystem(esx.HostSystem)
|
||||
|
||||
host.Summary.Config.Name = spec.HostName
|
||||
host.Name = host.Summary.Config.Name
|
||||
host.Runtime.ConnectionState = types.HostSystemConnectionStateDisconnected
|
||||
|
||||
summary := new(types.ComputeResourceSummary)
|
||||
addComputeResource(summary, host)
|
||||
|
||||
cr := &mo.ComputeResource{
|
||||
ConfigurationEx: &types.ComputeResourceConfigInfo{
|
||||
VmSwapPlacement: string(types.VirtualMachineConfigInfoSwapPlacementTypeVmDirectory),
|
||||
},
|
||||
Summary: summary,
|
||||
}
|
||||
|
||||
Map.PutEntity(cr, Map.NewEntity(host))
|
||||
host.Summary.Host = &host.Self
|
||||
|
||||
Map.PutEntity(cr, Map.NewEntity(pool))
|
||||
|
||||
cr.Name = host.Name
|
||||
cr.Host = append(cr.Host, host.Reference())
|
||||
cr.ResourcePool = &pool.Self
|
||||
|
||||
f.putChild(cr)
|
||||
pool.Owner = cr.Self
|
||||
|
||||
return host, nil
|
||||
}
|
||||
|
||||
func (h *HostSystem) DestroyTask(req *types.Destroy_Task) soap.HasFault {
|
||||
task := CreateTask(h, "destroy", func(t *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
if len(h.Vm) > 0 {
|
||||
return nil, &types.ResourceInUse{}
|
||||
}
|
||||
|
||||
f := Map.getEntityParent(h, "Folder").(*Folder)
|
||||
f.removeChild(h.Reference())
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.Destroy_TaskBody{
|
||||
Res: &types.Destroy_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (h *HostSystem) EnterMaintenanceModeTask(spec *types.EnterMaintenanceMode_Task) soap.HasFault {
|
||||
task := CreateTask(h, "enterMaintenanceMode", func(t *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
h.Runtime.InMaintenanceMode = true
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.EnterMaintenanceMode_TaskBody{
|
||||
Res: &types.EnterMaintenanceMode_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (h *HostSystem) ExitMaintenanceModeTask(spec *types.ExitMaintenanceMode_Task) soap.HasFault {
|
||||
task := CreateTask(h, "exitMaintenanceMode", func(t *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
h.Runtime.InMaintenanceMode = false
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.ExitMaintenanceMode_TaskBody{
|
||||
Res: &types.ExitMaintenanceMode_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
208
vendor/github.com/vmware/govmomi/simulator/host_system_test.go
generated
vendored
Normal file
208
vendor/github.com/vmware/govmomi/simulator/host_system_test.go
generated
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/find"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
)
|
||||
|
||||
func TestDefaultESX(t *testing.T) {
|
||||
s := New(NewServiceInstance(esx.ServiceContent, esx.RootFolder))
|
||||
|
||||
ts := s.NewServer()
|
||||
defer ts.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
client, err := govmomi.NewClient(ctx, ts.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder := find.NewFinder(client.Client, false)
|
||||
|
||||
dc, err := finder.DatacenterOrDefault(ctx, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder.SetDatacenter(dc)
|
||||
|
||||
host, err := finder.HostSystemOrDefault(ctx, "*")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if host.Name() != esx.HostSystem.Summary.Config.Name {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
pool, err := finder.ResourcePoolOrDefault(ctx, "*")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if pool.Name() != "Resources" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaintenanceMode(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
m := ESX()
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c := m.Service.client
|
||||
|
||||
hs := Map.Get(esx.HostSystem.Reference()).(*HostSystem)
|
||||
host := object.NewHostSystem(c, hs.Self)
|
||||
|
||||
task, err := host.EnterMaintenanceMode(ctx, 1, false, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if hs.Runtime.InMaintenanceMode != true {
|
||||
t.Fatal("expect InMaintenanceMode is true; got false")
|
||||
}
|
||||
|
||||
task, err = host.ExitMaintenanceMode(ctx, 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if hs.Runtime.InMaintenanceMode != false {
|
||||
t.Fatal("expect InMaintenanceMode is false; got true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewHostSystem(t *testing.T) {
|
||||
m := ESX()
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hs := NewHostSystem(esx.HostSystem)
|
||||
if hs.Summary.Runtime != &hs.Runtime {
|
||||
t.Fatal("expected hs.Summary.Runtime == &hs.Runtime; got !=")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDestroyHostSystem(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
m := VPX()
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c := m.Service.client
|
||||
|
||||
vm := Map.Any("VirtualMachine").(*VirtualMachine)
|
||||
hs := Map.Get(*vm.Runtime.Host).(*HostSystem)
|
||||
host := object.NewHostSystem(c, hs.Self)
|
||||
|
||||
vms := []*VirtualMachine{}
|
||||
for _, vmref := range hs.Vm {
|
||||
vms = append(vms, Map.Get(vmref).(*VirtualMachine))
|
||||
}
|
||||
|
||||
task, err := host.Destroy(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err == nil {
|
||||
t.Fatal("expect err because host with vms cannot be destroyed")
|
||||
}
|
||||
|
||||
for _, vmref := range hs.Vm {
|
||||
vm := Map.Get(vmref).(*VirtualMachine)
|
||||
vmo := object.NewVirtualMachine(c, vm.Self)
|
||||
|
||||
task, err := vmo.PowerOff(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
task, err = vmo.Destroy(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
task, err = host.Destroy(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hs2 := Map.Get(esx.HostSystem.Reference())
|
||||
if hs2 != nil {
|
||||
t.Fatal("host should have been destroyed")
|
||||
}
|
||||
}
|
||||
392
vendor/github.com/vmware/govmomi/simulator/ip_pool_manager.go
generated
vendored
Normal file
392
vendor/github.com/vmware/govmomi/simulator/ip_pool_manager.go
generated
vendored
Normal file
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
var ipPool = MustNewIpPool(&types.IpPool{
|
||||
Id: 1,
|
||||
Name: "ip-pool",
|
||||
AvailableIpv4Addresses: 250,
|
||||
AvailableIpv6Addresses: 250,
|
||||
AllocatedIpv6Addresses: 0,
|
||||
AllocatedIpv4Addresses: 0,
|
||||
Ipv4Config: &types.IpPoolIpPoolConfigInfo{
|
||||
Netmask: "10.10.10.255",
|
||||
Gateway: "10.10.10.1",
|
||||
SubnetAddress: "10.10.10.0",
|
||||
Range: "10.10.10.2#250",
|
||||
},
|
||||
Ipv6Config: &types.IpPoolIpPoolConfigInfo{
|
||||
Netmask: "2001:4860:0:2001::ff",
|
||||
Gateway: "2001:4860:0:2001::1",
|
||||
SubnetAddress: "2001:4860:0:2001::0",
|
||||
Range: "2001:4860:0:2001::2#250",
|
||||
},
|
||||
})
|
||||
|
||||
// IpPoolManager implements a simple IP Pool manager in which all pools are shared
|
||||
// across different datacenters.
|
||||
type IpPoolManager struct {
|
||||
mo.IpPoolManager
|
||||
|
||||
pools map[int32]*IpPool
|
||||
nextPoolId int32
|
||||
}
|
||||
|
||||
func NewIpPoolManager(ref types.ManagedObjectReference) *IpPoolManager {
|
||||
m := &IpPoolManager{}
|
||||
m.Self = ref
|
||||
|
||||
m.pools = map[int32]*IpPool{
|
||||
1: ipPool,
|
||||
}
|
||||
m.nextPoolId = 2
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *IpPoolManager) CreateIpPool(req *types.CreateIpPool) soap.HasFault {
|
||||
body := &methods.CreateIpPoolBody{}
|
||||
id := m.nextPoolId
|
||||
|
||||
var err error
|
||||
m.pools[id], err = NewIpPool(&req.Pool)
|
||||
if err != nil {
|
||||
body.Fault_ = Fault("", &types.RuntimeFault{})
|
||||
return body
|
||||
}
|
||||
|
||||
m.nextPoolId++
|
||||
|
||||
body.Res = &types.CreateIpPoolResponse{
|
||||
Returnval: id,
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (m *IpPoolManager) DestroyIpPool(req *types.DestroyIpPool) soap.HasFault {
|
||||
delete(m.pools, req.Id)
|
||||
|
||||
return &methods.DestroyIpPoolBody{
|
||||
Res: &types.DestroyIpPoolResponse{},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *IpPoolManager) QueryIpPools(req *types.QueryIpPools) soap.HasFault {
|
||||
pools := []types.IpPool{}
|
||||
|
||||
for i := int32(1); i < m.nextPoolId; i++ {
|
||||
if p, ok := m.pools[i]; ok {
|
||||
pools = append(pools, *p.config)
|
||||
}
|
||||
}
|
||||
|
||||
return &methods.QueryIpPoolsBody{
|
||||
Res: &types.QueryIpPoolsResponse{
|
||||
Returnval: pools,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *IpPoolManager) UpdateIpPool(req *types.UpdateIpPool) soap.HasFault {
|
||||
body := &methods.UpdateIpPoolBody{}
|
||||
|
||||
var pool *IpPool
|
||||
var err error
|
||||
var ok bool
|
||||
|
||||
if pool, ok = m.pools[req.Pool.Id]; !ok {
|
||||
body.Fault_ = Fault("", &types.NotFoundFault{})
|
||||
return body
|
||||
}
|
||||
|
||||
if pool.config.AllocatedIpv4Addresses+pool.config.AllocatedIpv6Addresses != 0 {
|
||||
body.Fault_ = Fault("update a pool has been used is not supported", &types.RuntimeFault{})
|
||||
return body
|
||||
}
|
||||
|
||||
m.pools[req.Pool.Id], err = NewIpPool(&req.Pool)
|
||||
if err != nil {
|
||||
body.Fault_ = Fault(err.Error(), &types.RuntimeFault{})
|
||||
return body
|
||||
}
|
||||
|
||||
body.Res = &types.UpdateIpPoolResponse{}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (m *IpPoolManager) AllocateIpv4Address(req *types.AllocateIpv4Address) soap.HasFault {
|
||||
body := &methods.AllocateIpv4AddressBody{}
|
||||
|
||||
pool, ok := m.pools[req.PoolId]
|
||||
if !ok {
|
||||
body.Fault_ = Fault("", &types.InvalidArgument{})
|
||||
return body
|
||||
}
|
||||
|
||||
ip, err := pool.AllocateIPv4(req.AllocationId)
|
||||
if err != nil {
|
||||
body.Fault_ = Fault(err.Error(), &types.RuntimeFault{})
|
||||
return body
|
||||
}
|
||||
|
||||
body.Res = &types.AllocateIpv4AddressResponse{
|
||||
Returnval: ip,
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (m *IpPoolManager) AllocateIpv6Address(req *types.AllocateIpv6Address) soap.HasFault {
|
||||
body := &methods.AllocateIpv6AddressBody{}
|
||||
|
||||
pool, ok := m.pools[req.PoolId]
|
||||
if !ok {
|
||||
body.Fault_ = Fault("", &types.InvalidArgument{})
|
||||
return body
|
||||
}
|
||||
|
||||
ip, err := pool.AllocateIpv6(req.AllocationId)
|
||||
if err != nil {
|
||||
body.Fault_ = Fault(err.Error(), &types.RuntimeFault{})
|
||||
return body
|
||||
}
|
||||
|
||||
body.Res = &types.AllocateIpv6AddressResponse{
|
||||
Returnval: ip,
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (m *IpPoolManager) ReleaseIpAllocation(req *types.ReleaseIpAllocation) soap.HasFault {
|
||||
body := &methods.ReleaseIpAllocationBody{}
|
||||
|
||||
pool, ok := m.pools[req.PoolId]
|
||||
if !ok {
|
||||
body.Fault_ = Fault("", &types.InvalidArgument{})
|
||||
return body
|
||||
}
|
||||
|
||||
pool.ReleaseIpv4(req.AllocationId)
|
||||
pool.ReleaseIpv6(req.AllocationId)
|
||||
|
||||
body.Res = &types.ReleaseIpAllocationResponse{}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (m *IpPoolManager) QueryIPAllocations(req *types.QueryIPAllocations) soap.HasFault {
|
||||
body := &methods.QueryIPAllocationsBody{}
|
||||
|
||||
pool, ok := m.pools[req.PoolId]
|
||||
if !ok {
|
||||
body.Fault_ = Fault("", &types.InvalidArgument{})
|
||||
return body
|
||||
}
|
||||
|
||||
body.Res = &types.QueryIPAllocationsResponse{}
|
||||
|
||||
ipv4, ok := pool.ipv4Allocation[req.ExtensionKey]
|
||||
if ok {
|
||||
body.Res.Returnval = append(body.Res.Returnval, types.IpPoolManagerIpAllocation{
|
||||
IpAddress: ipv4,
|
||||
AllocationId: req.ExtensionKey,
|
||||
})
|
||||
}
|
||||
|
||||
ipv6, ok := pool.ipv6Allocation[req.ExtensionKey]
|
||||
if ok {
|
||||
body.Res.Returnval = append(body.Res.Returnval, types.IpPoolManagerIpAllocation{
|
||||
IpAddress: ipv6,
|
||||
AllocationId: req.ExtensionKey,
|
||||
})
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
var (
|
||||
errNoIpAvailable = errors.New("no ip address available")
|
||||
errInvalidAllocation = errors.New("allocation id not recognized")
|
||||
)
|
||||
|
||||
type IpPool struct {
|
||||
config *types.IpPool
|
||||
ipv4Allocation map[string]string
|
||||
ipv6Allocation map[string]string
|
||||
ipv4Pool []string
|
||||
ipv6Pool []string
|
||||
}
|
||||
|
||||
func MustNewIpPool(config *types.IpPool) *IpPool {
|
||||
pool, err := NewIpPool(config)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return pool
|
||||
}
|
||||
|
||||
func NewIpPool(config *types.IpPool) (*IpPool, error) {
|
||||
pool := &IpPool{
|
||||
config: config,
|
||||
ipv4Allocation: make(map[string]string),
|
||||
ipv6Allocation: make(map[string]string),
|
||||
}
|
||||
|
||||
return pool, pool.init()
|
||||
}
|
||||
|
||||
func (p *IpPool) init() error {
|
||||
// IPv4 range
|
||||
if p.config.Ipv4Config != nil {
|
||||
ranges := strings.Split(p.config.Ipv4Config.Range, ",")
|
||||
for _, r := range ranges {
|
||||
sp := strings.Split(r, "#")
|
||||
if len(sp) != 2 {
|
||||
return fmt.Errorf("format of range should be ip#number; got %q", r)
|
||||
}
|
||||
|
||||
ip := net.ParseIP(strings.TrimSpace(sp[0])).To4()
|
||||
if ip == nil {
|
||||
return fmt.Errorf("bad ip format: %q", sp[0])
|
||||
}
|
||||
|
||||
length, err := strconv.Atoi(sp[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < length; i++ {
|
||||
p.ipv4Pool = append(p.ipv4Pool, net.IPv4(ip[0], ip[1], ip[2], ip[3]+byte(i)).String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IPv6 range
|
||||
if p.config.Ipv6Config != nil {
|
||||
ranges := strings.Split(p.config.Ipv6Config.Range, ",")
|
||||
for _, r := range ranges {
|
||||
sp := strings.Split(r, "#")
|
||||
if len(sp) != 2 {
|
||||
return fmt.Errorf("format of range should be ip#number; got %q", r)
|
||||
}
|
||||
|
||||
ip := net.ParseIP(strings.TrimSpace(sp[0])).To16()
|
||||
if ip == nil {
|
||||
return fmt.Errorf("bad ip format: %q", sp[0])
|
||||
}
|
||||
|
||||
length, err := strconv.Atoi(sp[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < length; i++ {
|
||||
var ipv6 [16]byte
|
||||
copy(ipv6[:], ip)
|
||||
ipv6[15] += byte(i)
|
||||
p.ipv6Pool = append(p.ipv6Pool, net.IP(ipv6[:]).String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *IpPool) AllocateIPv4(allocation string) (string, error) {
|
||||
if ip, ok := p.ipv4Allocation[allocation]; ok {
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
l := len(p.ipv4Pool)
|
||||
if l == 0 {
|
||||
return "", errNoIpAvailable
|
||||
}
|
||||
|
||||
ip := p.ipv4Pool[l-1]
|
||||
|
||||
p.config.AvailableIpv4Addresses--
|
||||
p.config.AllocatedIpv4Addresses++
|
||||
p.ipv4Pool = p.ipv4Pool[:l-1]
|
||||
p.ipv4Allocation[allocation] = ip
|
||||
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
func (p *IpPool) ReleaseIpv4(allocation string) error {
|
||||
ip, ok := p.ipv4Allocation[allocation]
|
||||
if !ok {
|
||||
return errInvalidAllocation
|
||||
}
|
||||
|
||||
delete(p.ipv4Allocation, allocation)
|
||||
p.config.AvailableIpv4Addresses++
|
||||
p.config.AllocatedIpv4Addresses--
|
||||
p.ipv4Pool = append(p.ipv4Pool, ip)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *IpPool) AllocateIpv6(allocation string) (string, error) {
|
||||
if ip, ok := p.ipv6Allocation[allocation]; ok {
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
l := len(p.ipv6Pool)
|
||||
if l == 0 {
|
||||
return "", errNoIpAvailable
|
||||
}
|
||||
|
||||
ip := p.ipv6Pool[l-1]
|
||||
|
||||
p.config.AvailableIpv6Addresses--
|
||||
p.config.AllocatedIpv6Addresses++
|
||||
p.ipv6Pool = p.ipv6Pool[:l-1]
|
||||
p.ipv6Allocation[allocation] = ip
|
||||
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
func (p *IpPool) ReleaseIpv6(allocation string) error {
|
||||
ip, ok := p.ipv6Allocation[allocation]
|
||||
if !ok {
|
||||
return errInvalidAllocation
|
||||
}
|
||||
|
||||
delete(p.ipv6Allocation, allocation)
|
||||
p.config.AvailableIpv6Addresses++
|
||||
p.config.AllocatedIpv6Addresses--
|
||||
p.ipv6Pool = append(p.ipv6Pool, ip)
|
||||
|
||||
return nil
|
||||
}
|
||||
362
vendor/github.com/vmware/govmomi/simulator/ip_pool_manager_test.go
generated
vendored
Normal file
362
vendor/github.com/vmware/govmomi/simulator/ip_pool_manager_test.go
generated
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestIpPoolv4(t *testing.T) {
|
||||
tests := []struct {
|
||||
ipRange string
|
||||
length int32
|
||||
}{
|
||||
{"10.10.10.2#250", 250},
|
||||
{"10.10.10.2#10, 10.10.10.20#20", 30},
|
||||
{"10.10.10.2#10, 10.10.10.20#20, 10.10.10.50#20", 50},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
var ipPool = MustNewIpPool(&types.IpPool{
|
||||
Id: 1,
|
||||
Name: "ip-pool",
|
||||
AvailableIpv4Addresses: test.length,
|
||||
AvailableIpv6Addresses: 0,
|
||||
AllocatedIpv6Addresses: 0,
|
||||
AllocatedIpv4Addresses: 0,
|
||||
Ipv4Config: &types.IpPoolIpPoolConfigInfo{
|
||||
Netmask: "10.10.10.255",
|
||||
Gateway: "10.10.10.1",
|
||||
SubnetAddress: "10.10.10.0",
|
||||
Range: test.ipRange,
|
||||
},
|
||||
})
|
||||
|
||||
if len(ipPool.ipv4Pool) != int(test.length) {
|
||||
t.Fatalf("expect length to be %d; got %d", test.length, len(ipPool.ipv4Pool))
|
||||
}
|
||||
|
||||
ip, err := ipPool.AllocateIPv4("alloc")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ip2, err := ipPool.AllocateIPv4("alloc")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ip != ip2 {
|
||||
t.Fatalf("same allocation key should allocate the same ip; got %s, %s", ip, ip2)
|
||||
}
|
||||
|
||||
err = ipPool.ReleaseIpv4("bad-alloc")
|
||||
if err == nil {
|
||||
t.Fatal("expect error to release a bad allocation")
|
||||
}
|
||||
|
||||
if len(ipPool.ipv4Pool) != int(test.length)-1 {
|
||||
t.Fatalf("expect length to be %d; got %d", test.length-1, len(ipPool.ipv4Pool))
|
||||
}
|
||||
|
||||
err = ipPool.ReleaseIpv4("alloc")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(ipPool.ipv4Pool) != int(test.length) {
|
||||
t.Fatalf("expect length to be %d; got %d", test.length, len(ipPool.ipv4Pool))
|
||||
}
|
||||
|
||||
allocated := map[string]bool{}
|
||||
for i := 0; i < int(test.length); i++ {
|
||||
ip, err := ipPool.AllocateIPv4(fmt.Sprintf("alloc-%d", i))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, ok := allocated[ip]; ok {
|
||||
t.Fatalf("duplicated allocation of ip %q", ip)
|
||||
}
|
||||
allocated[ip] = true
|
||||
}
|
||||
|
||||
_, err = ipPool.AllocateIPv4("last-allocation")
|
||||
if err != errNoIpAvailable {
|
||||
t.Fatalf("expect errNoIpAvailable; got %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIpPoolv6(t *testing.T) {
|
||||
tests := []struct {
|
||||
ipRange string
|
||||
length int32
|
||||
}{
|
||||
{"2001:4860:0:2001::2#250", 250},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
var ipPool = MustNewIpPool(&types.IpPool{
|
||||
Id: 1,
|
||||
Name: "ip-pool",
|
||||
AvailableIpv4Addresses: 0,
|
||||
AvailableIpv6Addresses: test.length,
|
||||
AllocatedIpv6Addresses: 0,
|
||||
AllocatedIpv4Addresses: 0,
|
||||
Ipv6Config: &types.IpPoolIpPoolConfigInfo{
|
||||
Netmask: "2001:4860:0:2001::ff",
|
||||
Gateway: "2001:4860:0:2001::1",
|
||||
SubnetAddress: "2001:4860:0:2001::0",
|
||||
Range: test.ipRange,
|
||||
},
|
||||
})
|
||||
|
||||
if len(ipPool.ipv6Pool) != int(test.length) {
|
||||
t.Fatalf("expect length to be %d; got %d", test.length, len(ipPool.ipv4Pool))
|
||||
}
|
||||
|
||||
ip, err := ipPool.AllocateIpv6("alloc")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ip2, err := ipPool.AllocateIpv6("alloc")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ip != ip2 {
|
||||
t.Fatalf("same allocation key should allocate the same ip; got %s, %s", ip, ip2)
|
||||
}
|
||||
|
||||
err = ipPool.ReleaseIpv6("bad-alloc")
|
||||
if err == nil {
|
||||
t.Fatal("expect error to release a bad allocation")
|
||||
}
|
||||
|
||||
if len(ipPool.ipv6Pool) != int(test.length)-1 {
|
||||
t.Fatalf("expect length to be %d; got %d", test.length-1, len(ipPool.ipv4Pool))
|
||||
}
|
||||
|
||||
err = ipPool.ReleaseIpv6("alloc")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(ipPool.ipv6Pool) != int(test.length) {
|
||||
t.Fatalf("expect length to be %d; got %d", test.length, len(ipPool.ipv4Pool))
|
||||
}
|
||||
|
||||
allocated := map[string]bool{}
|
||||
for i := 0; i < int(test.length); i++ {
|
||||
ip, err := ipPool.AllocateIpv6(fmt.Sprintf("alloc-%d", i))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, ok := allocated[ip]; ok {
|
||||
t.Fatalf("duplicated allocation of ip %q", ip)
|
||||
}
|
||||
allocated[ip] = true
|
||||
}
|
||||
|
||||
_, err = ipPool.AllocateIpv6("last-allocation")
|
||||
if err != errNoIpAvailable {
|
||||
t.Fatalf("expect errNoIpAvailable; got %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIpPoolManagerLifecycle(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
m := VPX()
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ref := types.ManagedObjectReference{Type: "IpPoolManager", Value: "IpPoolManager"}
|
||||
|
||||
var ipPool = &types.IpPool{
|
||||
Name: "ip-pool",
|
||||
AvailableIpv4Addresses: 250,
|
||||
AvailableIpv6Addresses: 250,
|
||||
AllocatedIpv4Addresses: 0,
|
||||
AllocatedIpv6Addresses: 0,
|
||||
Ipv4Config: &types.IpPoolIpPoolConfigInfo{
|
||||
Netmask: "10.10.10.255",
|
||||
Gateway: "10.10.10.1",
|
||||
SubnetAddress: "10.10.10.0",
|
||||
Range: "10.10.10.2#250",
|
||||
},
|
||||
Ipv6Config: &types.IpPoolIpPoolConfigInfo{
|
||||
Netmask: "2001:4860:0:2001::ff",
|
||||
Gateway: "2001:4860:0:2001::1",
|
||||
SubnetAddress: "2001:4860:0:2001::0",
|
||||
Range: "2001:4860:0:2001::2#250",
|
||||
},
|
||||
}
|
||||
|
||||
createReq := &types.CreateIpPool{
|
||||
This: ref,
|
||||
Pool: *ipPool,
|
||||
}
|
||||
|
||||
createResp, err := methods.CreateIpPool(ctx, c.Client, createReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if createResp.Returnval != 2 {
|
||||
t.Fatalf("expect pool id to be 2; got %d", createResp.Returnval)
|
||||
}
|
||||
|
||||
ipPool.Id = 2
|
||||
ipPool.Ipv4Config = &types.IpPoolIpPoolConfigInfo{
|
||||
Netmask: "10.20.10.255",
|
||||
Gateway: "10.20.10.1",
|
||||
SubnetAddress: "10.20.10.0",
|
||||
Range: "10.20.10.2#250",
|
||||
}
|
||||
|
||||
updateReq := &types.UpdateIpPool{
|
||||
This: ref,
|
||||
Pool: *ipPool,
|
||||
}
|
||||
|
||||
_, err = methods.UpdateIpPool(ctx, c.Client, updateReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
queryReq := &types.QueryIpPools{
|
||||
This: ref,
|
||||
}
|
||||
|
||||
queryResp, err := methods.QueryIpPools(ctx, c.Client, queryReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(queryResp.Returnval) != 2 {
|
||||
t.Fatalf("expect length of ip pools is 2; got %d", len(queryResp.Returnval))
|
||||
}
|
||||
if !reflect.DeepEqual(queryResp.Returnval[1].Ipv4Config, ipPool.Ipv4Config) {
|
||||
t.Fatalf("expect query result equal to %+v; got %+v",
|
||||
ipPool.Ipv4Config, queryResp.Returnval[1].Ipv4Config)
|
||||
}
|
||||
|
||||
destroyReq := &types.DestroyIpPool{
|
||||
This: ref,
|
||||
Id: 2,
|
||||
}
|
||||
|
||||
_, err = methods.DestroyIpPool(ctx, c.Client, destroyReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
queryResp, err = methods.QueryIpPools(ctx, c.Client, queryReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(queryResp.Returnval) != 1 {
|
||||
t.Fatalf("expect length of ip pools is 1 (1 deleted); got %d", len(queryResp.Returnval))
|
||||
}
|
||||
}
|
||||
|
||||
func TestIpPoolManagerAllocate(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
m := VPX()
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ref := types.ManagedObjectReference{Type: "IpPoolManager", Value: "IpPoolManager"}
|
||||
|
||||
// Allocate IPv4
|
||||
allocateReq := &types.AllocateIpv4Address{
|
||||
This: ref,
|
||||
PoolId: 1,
|
||||
AllocationId: "alloc",
|
||||
}
|
||||
|
||||
allocateResp, err := methods.AllocateIpv4Address(ctx, c.Client, allocateReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if net.ParseIP(allocateResp.Returnval) == nil {
|
||||
t.Fatalf("%q is not IP address", allocateResp.Returnval)
|
||||
}
|
||||
|
||||
releaseReq := &types.ReleaseIpAllocation{
|
||||
This: ref,
|
||||
PoolId: 1,
|
||||
AllocationId: "alloc",
|
||||
}
|
||||
|
||||
queryReq := &types.QueryIPAllocations{
|
||||
This: ref,
|
||||
PoolId: 1,
|
||||
ExtensionKey: "alloc",
|
||||
}
|
||||
|
||||
queryResp, err := methods.QueryIPAllocations(ctx, c.Client, queryReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(queryResp.Returnval) != 1 {
|
||||
t.Fatalf("expect length of result 1; got %s", queryResp.Returnval)
|
||||
}
|
||||
if queryResp.Returnval[0].IpAddress != allocateResp.Returnval {
|
||||
t.Fatalf("expect same IP address; got %s, %s", queryResp.Returnval[0].IpAddress, allocateResp.Returnval)
|
||||
}
|
||||
|
||||
_, err = methods.ReleaseIpAllocation(ctx, c.Client, releaseReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
156
vendor/github.com/vmware/govmomi/simulator/license_manager.go
generated
vendored
Normal file
156
vendor/github.com/vmware/govmomi/simulator/license_manager.go
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
// Copyright 2017 VMware, Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
// EvalLicense is the default license
|
||||
var EvalLicense = types.LicenseManagerLicenseInfo{
|
||||
LicenseKey: "00000-00000-00000-00000-00000",
|
||||
EditionKey: "eval",
|
||||
Name: "Evaluation Mode",
|
||||
Properties: []types.KeyAnyValue{
|
||||
{
|
||||
Key: "feature",
|
||||
Value: types.KeyValue{
|
||||
Key: "serialuri:2",
|
||||
Value: "Remote virtual Serial Port Concentrator",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "feature",
|
||||
Value: types.KeyValue{
|
||||
Key: "dvs",
|
||||
Value: "vSphere Distributed Switch",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type LicenseManager struct {
|
||||
mo.LicenseManager
|
||||
}
|
||||
|
||||
func NewLicenseManager(ref types.ManagedObjectReference) object.Reference {
|
||||
m := &LicenseManager{}
|
||||
m.Self = ref
|
||||
m.Licenses = []types.LicenseManagerLicenseInfo{EvalLicense}
|
||||
|
||||
if Map.IsVPX() {
|
||||
am := Map.Put(&LicenseAssignmentManager{}).Reference()
|
||||
m.LicenseAssignmentManager = &am
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *LicenseManager) AddLicense(req *types.AddLicense) soap.HasFault {
|
||||
body := &methods.AddLicenseBody{
|
||||
Res: &types.AddLicenseResponse{},
|
||||
}
|
||||
|
||||
for _, license := range m.Licenses {
|
||||
if license.LicenseKey == req.LicenseKey {
|
||||
body.Res.Returnval = licenseInfo(license.LicenseKey, license.Labels)
|
||||
return body
|
||||
}
|
||||
}
|
||||
|
||||
m.Licenses = append(m.Licenses, types.LicenseManagerLicenseInfo{
|
||||
LicenseKey: req.LicenseKey,
|
||||
Labels: req.Labels,
|
||||
})
|
||||
|
||||
body.Res.Returnval = licenseInfo(req.LicenseKey, req.Labels)
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (m *LicenseManager) RemoveLicense(req *types.RemoveLicense) soap.HasFault {
|
||||
body := &methods.RemoveLicenseBody{
|
||||
Res: &types.RemoveLicenseResponse{},
|
||||
}
|
||||
|
||||
for i, license := range m.Licenses {
|
||||
if req.LicenseKey == license.LicenseKey {
|
||||
m.Licenses = append(m.Licenses[:i], m.Licenses[i+1:]...)
|
||||
return body
|
||||
}
|
||||
}
|
||||
return body
|
||||
}
|
||||
|
||||
type LicenseAssignmentManager struct {
|
||||
mo.LicenseAssignmentManager
|
||||
}
|
||||
|
||||
func (m *LicenseAssignmentManager) QueryAssignedLicenses(req *types.QueryAssignedLicenses) soap.HasFault {
|
||||
body := &methods.QueryAssignedLicensesBody{
|
||||
Res: &types.QueryAssignedLicensesResponse{},
|
||||
}
|
||||
|
||||
// EntityId can be a HostSystem or the vCenter InstanceUuid
|
||||
if req.EntityId != "" {
|
||||
if req.EntityId != Map.content().About.InstanceUuid {
|
||||
id := types.ManagedObjectReference{
|
||||
Type: "HostSystem",
|
||||
Value: req.EntityId,
|
||||
}
|
||||
|
||||
if Map.Get(id) == nil {
|
||||
return body
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body.Res.Returnval = []types.LicenseAssignmentManagerLicenseAssignment{
|
||||
{
|
||||
EntityId: req.EntityId,
|
||||
AssignedLicense: EvalLicense,
|
||||
},
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func licenseInfo(key string, labels []types.KeyValue) types.LicenseManagerLicenseInfo {
|
||||
info := EvalLicense
|
||||
|
||||
info.LicenseKey = key
|
||||
info.Labels = labels
|
||||
|
||||
return info
|
||||
}
|
||||
206
vendor/github.com/vmware/govmomi/simulator/license_manager_test.go
generated
vendored
Normal file
206
vendor/github.com/vmware/govmomi/simulator/license_manager_test.go
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/find"
|
||||
"github.com/vmware/govmomi/license"
|
||||
)
|
||||
|
||||
func TestLicenseManagerVPX(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
m := VPX()
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
lm := license.NewManager(c.Client)
|
||||
am, err := lm.AssignmentManager(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
la, err := am.QueryAssigned(ctx, "enoent")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(la) != 0 {
|
||||
t.Errorf("unexpected license")
|
||||
}
|
||||
|
||||
finder := find.NewFinder(c.Client, false)
|
||||
hosts, err := finder.HostSystemList(ctx, "/...")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
host := hosts[0].Reference().Value
|
||||
vcid := c.Client.ServiceContent.About.InstanceUuid
|
||||
|
||||
for _, name := range []string{"", host, vcid} {
|
||||
la, err = am.QueryAssigned(ctx, name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(la) != 1 {
|
||||
t.Fatal("no licenses")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(la[0].AssignedLicense, EvalLicense) {
|
||||
t.Fatal("invalid license")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLicenseManagerESX(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
m := ESX()
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
lm := license.NewManager(c.Client)
|
||||
_, err = lm.AssignmentManager(ctx)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
|
||||
la, err := lm.List(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(la) != 1 {
|
||||
t.Fatal("no licenses")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(la[0], EvalLicense) {
|
||||
t.Fatal("invalid license")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddRemoveLicense(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
m := ESX()
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
lm := license.NewManager(c.Client)
|
||||
key := "00000-00000-00000-00000-11111"
|
||||
labels := map[string]string{"key": "value"}
|
||||
|
||||
info, err := lm.Add(ctx, key, labels)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if info.LicenseKey != key {
|
||||
t.Fatalf("expect info.LicenseKey equal to %q; got %q", key, info.LicenseKey)
|
||||
}
|
||||
|
||||
if len(info.Labels) != len(labels) {
|
||||
t.Fatalf("expect len(info.Labels) eqaul to %d; got %d",
|
||||
len(labels), len(info.Labels))
|
||||
}
|
||||
|
||||
if info.Labels[0].Key != "key" || info.Labels[0].Value != "value" {
|
||||
t.Fatalf("expect label to be {key:value}; got {%s:%s}",
|
||||
info.Labels[0].Key, info.Labels[0].Value)
|
||||
}
|
||||
|
||||
la, err := lm.List(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(la) != 2 {
|
||||
t.Fatal("no licenses")
|
||||
}
|
||||
|
||||
if la[1].LicenseKey != key {
|
||||
t.Fatalf("expect info.LicenseKey equal to %q; got %q",
|
||||
key, la[1].LicenseKey)
|
||||
}
|
||||
|
||||
if len(la[1].Labels) != len(labels) {
|
||||
t.Fatalf("expect len(info.Labels) eqaul to %d; got %d",
|
||||
len(labels), len(la[1].Labels))
|
||||
}
|
||||
|
||||
if la[1].Labels[0].Key != "key" || la[1].Labels[0].Value != "value" {
|
||||
t.Fatalf("expect label to be {key:value}; got {%s:%s}",
|
||||
la[1].Labels[0].Key, la[1].Labels[0].Value)
|
||||
}
|
||||
|
||||
err = lm.Remove(ctx, key)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
la, err = lm.List(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(la) != 1 {
|
||||
t.Fatal("no licenses")
|
||||
}
|
||||
}
|
||||
489
vendor/github.com/vmware/govmomi/simulator/model.go
generated
vendored
Normal file
489
vendor/github.com/vmware/govmomi/simulator/model.go
generated
vendored
Normal file
@@ -0,0 +1,489 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/simulator/vpx"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
// Model is used to populate a Model with an initial set of managed entities.
|
||||
// This is a simple helper for tests running against a simulator, to populate an inventory
|
||||
// with commonly used models.
|
||||
type Model struct {
|
||||
Service *Service `json:"-"`
|
||||
|
||||
ServiceContent types.ServiceContent `json:"-"`
|
||||
RootFolder mo.Folder `json:"-"`
|
||||
|
||||
// Autostart will power on Model created VMs when true
|
||||
Autostart bool `json:"-"`
|
||||
|
||||
// Datacenter specifies the number of Datacenter entities to create
|
||||
Datacenter int
|
||||
|
||||
// Portgroup specifies the number of DistributedVirtualPortgroup entities to create per Datacenter
|
||||
Portgroup int
|
||||
|
||||
// Host specifies the number of standalone HostSystems entities to create per Datacenter
|
||||
Host int `json:",omitempty"`
|
||||
|
||||
// Cluster specifies the number of ClusterComputeResource entities to create per Datacenter
|
||||
Cluster int
|
||||
|
||||
// ClusterHost specifies the number of HostSystems entities to create within a Cluster
|
||||
ClusterHost int `json:",omitempty"`
|
||||
|
||||
// Pool specifies the number of ResourcePool entities to create per Cluster
|
||||
Pool int
|
||||
|
||||
// Datastore specifies the number of Datastore entities to create
|
||||
// Each Datastore will have temporary local file storage and will be mounted
|
||||
// on every HostSystem created by the ModelConfig
|
||||
Datastore int
|
||||
|
||||
// Machine specifies the number of VirtualMachine entities to create per ResourcePool
|
||||
Machine int
|
||||
|
||||
// Folder specifies the number of Datacenter to place within a Folder.
|
||||
// This includes a folder for the Datacenter itself and its host, vm, network and datastore folders.
|
||||
// All resources for the Datacenter are placed within these folders, rather than the top-level folders.
|
||||
Folder int
|
||||
|
||||
// App specifies the number of VirtualApp to create per Cluster
|
||||
App int
|
||||
|
||||
// Pod specifies the number of StoragePod to create per Cluster
|
||||
Pod int
|
||||
|
||||
// total number of inventory objects, set by Count()
|
||||
total int
|
||||
|
||||
dirs []string
|
||||
}
|
||||
|
||||
// ESX is the default Model for a standalone ESX instance
|
||||
func ESX() *Model {
|
||||
return &Model{
|
||||
ServiceContent: esx.ServiceContent,
|
||||
RootFolder: esx.RootFolder,
|
||||
Autostart: true,
|
||||
Datastore: 1,
|
||||
Machine: 2,
|
||||
}
|
||||
}
|
||||
|
||||
// VPX is the default Model for a vCenter instance
|
||||
func VPX() *Model {
|
||||
return &Model{
|
||||
ServiceContent: vpx.ServiceContent,
|
||||
RootFolder: vpx.RootFolder,
|
||||
Autostart: true,
|
||||
Datacenter: 1,
|
||||
Portgroup: 1,
|
||||
Host: 1,
|
||||
Cluster: 1,
|
||||
ClusterHost: 3,
|
||||
Datastore: 1,
|
||||
Machine: 2,
|
||||
}
|
||||
}
|
||||
|
||||
// Count returns a Model with total number of each existing type
|
||||
func (m *Model) Count() Model {
|
||||
count := Model{}
|
||||
|
||||
for ref, obj := range Map.objects {
|
||||
if _, ok := obj.(mo.Entity); !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
count.total++
|
||||
|
||||
switch ref.Type {
|
||||
case "Datacenter":
|
||||
count.Datacenter++
|
||||
case "DistributedVirtualPortgroup":
|
||||
count.Portgroup++
|
||||
case "ClusterComputeResource":
|
||||
count.Cluster++
|
||||
case "Datastore":
|
||||
count.Datastore++
|
||||
case "HostSystem":
|
||||
count.Host++
|
||||
case "VirtualMachine":
|
||||
count.Machine++
|
||||
case "ResourcePool":
|
||||
count.Pool++
|
||||
case "VirtualApp":
|
||||
count.App++
|
||||
case "Folder":
|
||||
count.Folder++
|
||||
case "StoragePod":
|
||||
count.Pod++
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
func (*Model) fmtName(prefix string, num int) string {
|
||||
return fmt.Sprintf("%s%d", prefix, num)
|
||||
}
|
||||
|
||||
// Create populates the Model with the given ModelConfig
|
||||
func (m *Model) Create() error {
|
||||
m.Service = New(NewServiceInstance(m.ServiceContent, m.RootFolder))
|
||||
|
||||
ctx := context.Background()
|
||||
client := m.Service.client
|
||||
root := object.NewRootFolder(client)
|
||||
|
||||
// After all hosts are created, this var is used to mount the host datastores.
|
||||
var hosts []*object.HostSystem
|
||||
hostMap := make(map[string][]*object.HostSystem)
|
||||
|
||||
// We need to defer VM creation until after the datastores are created.
|
||||
var vms []func() error
|
||||
// 1 DVS per DC, added to all hosts
|
||||
var dvs *object.DistributedVirtualSwitch
|
||||
// 1 NIC per VM, backed by a DVPG if Model.Portgroup > 0
|
||||
vmnet := esx.EthernetCard.Backing
|
||||
|
||||
// addHost adds a cluster host or a stanalone host.
|
||||
addHost := func(name string, f func(types.HostConnectSpec) (*object.Task, error)) (*object.HostSystem, error) {
|
||||
spec := types.HostConnectSpec{
|
||||
HostName: name,
|
||||
}
|
||||
|
||||
task, err := f(spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info, err := task.WaitForResult(context.Background(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
host := object.NewHostSystem(client, info.Result.(types.ManagedObjectReference))
|
||||
hosts = append(hosts, host)
|
||||
|
||||
if dvs != nil {
|
||||
config := &types.DVSConfigSpec{
|
||||
Host: []types.DistributedVirtualSwitchHostMemberConfigSpec{{
|
||||
Operation: string(types.ConfigSpecOperationAdd),
|
||||
Host: host.Reference(),
|
||||
}},
|
||||
}
|
||||
|
||||
_, _ = dvs.Reconfigure(ctx, config)
|
||||
}
|
||||
|
||||
return host, nil
|
||||
}
|
||||
|
||||
// addMachine returns a func to create a VM.
|
||||
addMachine := func(prefix string, host *object.HostSystem, pool *object.ResourcePool, folders *object.DatacenterFolders) {
|
||||
nic := esx.EthernetCard
|
||||
nic.Backing = vmnet
|
||||
ds := types.ManagedObjectReference{}
|
||||
|
||||
f := func() error {
|
||||
for i := 0; i < m.Machine; i++ {
|
||||
name := m.fmtName(prefix+"_VM", i)
|
||||
|
||||
config := types.VirtualMachineConfigSpec{
|
||||
Name: name,
|
||||
GuestId: string(types.VirtualMachineGuestOsIdentifierOtherGuest),
|
||||
Files: &types.VirtualMachineFileInfo{
|
||||
VmPathName: "[LocalDS_0]",
|
||||
},
|
||||
}
|
||||
|
||||
if pool == nil {
|
||||
pool, _ = host.ResourcePool(ctx)
|
||||
}
|
||||
|
||||
var devices object.VirtualDeviceList
|
||||
|
||||
scsi, _ := devices.CreateSCSIController("pvscsi")
|
||||
ide, _ := devices.CreateIDEController()
|
||||
cdrom, _ := devices.CreateCdrom(ide.(*types.VirtualIDEController))
|
||||
disk := devices.CreateDisk(scsi.(types.BaseVirtualController), ds,
|
||||
config.Files.VmPathName+" "+path.Join(name, "disk1.vmdk"))
|
||||
disk.CapacityInKB = 1024
|
||||
|
||||
devices = append(devices, scsi, cdrom, disk, &nic)
|
||||
|
||||
config.DeviceChange, _ = devices.ConfigSpec(types.VirtualDeviceConfigSpecOperationAdd)
|
||||
|
||||
task, err := folders.VmFolder.CreateVM(ctx, config, pool, host)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info, err := task.WaitForResult(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vm := object.NewVirtualMachine(client, info.Result.(types.ManagedObjectReference))
|
||||
|
||||
if m.Autostart {
|
||||
_, _ = vm.PowerOn(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
vms = append(vms, f)
|
||||
}
|
||||
|
||||
nfolder := 0
|
||||
|
||||
for ndc := 0; ndc < m.Datacenter; ndc++ {
|
||||
dcName := m.fmtName("DC", ndc)
|
||||
folder := root
|
||||
fName := m.fmtName("F", nfolder)
|
||||
|
||||
// If Datacenter > Folder, don't create folders for the first N DCs.
|
||||
if nfolder < m.Folder && ndc >= (m.Datacenter-m.Folder) {
|
||||
f, err := folder.CreateFolder(ctx, fName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
folder = f
|
||||
}
|
||||
|
||||
dc, err := folder.CreateDatacenter(ctx, dcName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
folders, err := dc.Folders(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if m.Pod > 0 {
|
||||
for pod := 0; pod < m.Pod; pod++ {
|
||||
_, _ = folders.DatastoreFolder.CreateStoragePod(ctx, m.fmtName(dcName+"_POD", pod))
|
||||
}
|
||||
}
|
||||
|
||||
if folder != root {
|
||||
// Create sub-folders and use them to create any resources that follow
|
||||
subs := []**object.Folder{&folders.DatastoreFolder, &folders.HostFolder, &folders.NetworkFolder, &folders.VmFolder}
|
||||
|
||||
for _, sub := range subs {
|
||||
f, err := (*sub).CreateFolder(ctx, fName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*sub = f
|
||||
}
|
||||
|
||||
nfolder++
|
||||
}
|
||||
|
||||
if m.Portgroup > 0 {
|
||||
var spec types.DVSCreateSpec
|
||||
spec.ConfigSpec = &types.VMwareDVSConfigSpec{}
|
||||
spec.ConfigSpec.GetDVSConfigSpec().Name = m.fmtName("DVS", 0)
|
||||
|
||||
task, err := folders.NetworkFolder.CreateDVS(ctx, spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info, err := task.WaitForResult(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dvs = object.NewDistributedVirtualSwitch(client, info.Result.(types.ManagedObjectReference))
|
||||
|
||||
for npg := 0; npg < m.Portgroup; npg++ {
|
||||
name := m.fmtName(dcName+"_DVPG", npg)
|
||||
|
||||
task, err = dvs.AddPortgroup(ctx, []types.DVPortgroupConfigSpec{{Name: name}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Use the 1st DVPG for the VMs eth0 backing
|
||||
if npg == 0 {
|
||||
// AddPortgroup_Task does not return the moid, so we look it up by name
|
||||
net := Map.Get(folders.NetworkFolder.Reference()).(*Folder)
|
||||
pg := Map.FindByName(name, net.ChildEntity)
|
||||
|
||||
vmnet, _ = object.NewDistributedVirtualPortgroup(client, pg.Reference()).EthernetCardBackingInfo(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for nhost := 0; nhost < m.Host; nhost++ {
|
||||
name := m.fmtName(dcName+"_H", nhost)
|
||||
|
||||
host, err := addHost(name, func(spec types.HostConnectSpec) (*object.Task, error) {
|
||||
return folders.HostFolder.AddStandaloneHost(ctx, spec, true, nil, nil)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addMachine(name, host, nil, folders)
|
||||
}
|
||||
|
||||
for ncluster := 0; ncluster < m.Cluster; ncluster++ {
|
||||
clusterName := m.fmtName(dcName+"_C", ncluster)
|
||||
|
||||
cluster, err := folders.HostFolder.CreateCluster(ctx, clusterName, types.ClusterConfigSpecEx{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for nhost := 0; nhost < m.ClusterHost; nhost++ {
|
||||
name := m.fmtName(clusterName+"_H", nhost)
|
||||
|
||||
_, err = addHost(name, func(spec types.HostConnectSpec) (*object.Task, error) {
|
||||
return cluster.AddHost(ctx, spec, true, nil, nil)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
pool, err := cluster.ResourcePool(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
prefix := clusterName + "_RP"
|
||||
|
||||
addMachine(prefix+"0", nil, pool, folders)
|
||||
|
||||
for npool := 1; npool <= m.Pool; npool++ {
|
||||
spec := types.DefaultResourceConfigSpec()
|
||||
|
||||
_, err = pool.Create(ctx, m.fmtName(prefix, npool), spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
prefix = clusterName + "_APP"
|
||||
|
||||
for napp := 0; napp < m.App; napp++ {
|
||||
rspec := types.DefaultResourceConfigSpec()
|
||||
vspec := NewVAppConfigSpec()
|
||||
name := m.fmtName(prefix, napp)
|
||||
|
||||
vapp, err := pool.CreateVApp(ctx, name, rspec, vspec, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addMachine(name, nil, vapp.ResourcePool, folders)
|
||||
}
|
||||
}
|
||||
|
||||
hostMap[dcName] = hosts
|
||||
hosts = nil
|
||||
}
|
||||
|
||||
if m.ServiceContent.RootFolder == esx.RootFolder.Reference() {
|
||||
// ESX model
|
||||
host := object.NewHostSystem(client, esx.HostSystem.Reference())
|
||||
|
||||
dc := object.NewDatacenter(client, esx.Datacenter.Reference())
|
||||
folders, err := dc.Folders(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hostMap[dc.Reference().Value] = append(hosts, host)
|
||||
|
||||
addMachine(host.Reference().Value, host, nil, folders)
|
||||
}
|
||||
|
||||
for dc, dchosts := range hostMap {
|
||||
for i := 0; i < m.Datastore; i++ {
|
||||
err := m.createLocalDatastore(dc, m.fmtName("LocalDS_", i), dchosts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, createVM := range vms {
|
||||
err := createVM()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Model) createLocalDatastore(dc string, name string, hosts []*object.HostSystem) error {
|
||||
ctx := context.Background()
|
||||
dir, err := ioutil.TempDir("", fmt.Sprintf("govcsim-%s-%s-", dc, name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.dirs = append(m.dirs, dir)
|
||||
|
||||
for _, host := range hosts {
|
||||
dss, err := host.ConfigManager().DatastoreSystem(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = dss.CreateLocalDatastore(ctx, name, dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove cleans up items created by the Model, such as local datastore directories
|
||||
func (m *Model) Remove() {
|
||||
for _, dir := range m.dirs {
|
||||
_ = os.RemoveAll(dir)
|
||||
}
|
||||
}
|
||||
146
vendor/github.com/vmware/govmomi/simulator/model_test.go
generated
vendored
Normal file
146
vendor/github.com/vmware/govmomi/simulator/model_test.go
generated
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi/simulator/vpx"
|
||||
)
|
||||
|
||||
func compareModel(t *testing.T, m *Model) {
|
||||
count := m.Count()
|
||||
|
||||
hosts := (m.Host + (m.ClusterHost * m.Cluster)) * m.Datacenter
|
||||
vms := ((m.Host + m.Cluster) * m.Datacenter) * m.Machine
|
||||
// child pools + root pools
|
||||
pools := (m.Pool * m.Cluster * m.Datacenter) + (m.Host+m.Cluster)*m.Datacenter
|
||||
// root folder + Datacenter folders {host,vm,datastore,network} + top-level folders
|
||||
folders := 1 + (4 * m.Datacenter) + (5 * m.Folder)
|
||||
pgs := m.Portgroup
|
||||
if pgs > 0 {
|
||||
pgs++ // uplinks
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
expect int
|
||||
actual int
|
||||
kind string
|
||||
}{
|
||||
{m.Datacenter, count.Datacenter, "Datacenter"},
|
||||
{m.Cluster * m.Datacenter, count.Cluster, "Cluster"},
|
||||
{pgs * m.Datacenter, count.Portgroup, "Portgroup"},
|
||||
{m.Datastore * m.Datacenter, count.Datastore, "Datastore"},
|
||||
{hosts, count.Host, "Host"},
|
||||
{vms, count.Machine, "VirtualMachine"},
|
||||
{pools, count.Pool, "ResourcePool"},
|
||||
{folders, count.Folder, "Folder"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
if test.expect != test.actual {
|
||||
t.Errorf("expected %d %s, actual: %d", test.expect, test.kind, test.actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestModelESX(t *testing.T) {
|
||||
m := ESX()
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Set these for the compareModel math, and for m.Create to fail below
|
||||
m.Datacenter = 1
|
||||
m.Host = 1
|
||||
|
||||
compareModel(t, m)
|
||||
|
||||
err = m.Create()
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestModelVPX(t *testing.T) {
|
||||
m := VPX()
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
compareModel(t, m)
|
||||
}
|
||||
|
||||
func TestModelNoSwitchVPX(t *testing.T) {
|
||||
m := VPX()
|
||||
m.Portgroup = 0 // disabled DVS creation
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
compareModel(t, m)
|
||||
}
|
||||
|
||||
func TestModelCustomVPX(t *testing.T) {
|
||||
m := &Model{
|
||||
ServiceContent: vpx.ServiceContent,
|
||||
RootFolder: vpx.RootFolder,
|
||||
Datacenter: 2,
|
||||
Cluster: 2,
|
||||
Host: 2,
|
||||
ClusterHost: 3,
|
||||
Datastore: 1,
|
||||
Machine: 3,
|
||||
Pool: 2,
|
||||
Portgroup: 2,
|
||||
}
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
compareModel(t, m)
|
||||
}
|
||||
|
||||
func TestModelWithFolders(t *testing.T) {
|
||||
m := VPX()
|
||||
m.Datacenter = 3
|
||||
m.Folder = 2
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
compareModel(t, m)
|
||||
}
|
||||
98
vendor/github.com/vmware/govmomi/simulator/option_manager.go
generated
vendored
Normal file
98
vendor/github.com/vmware/govmomi/simulator/option_manager.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type OptionManager struct {
|
||||
mo.OptionManager
|
||||
}
|
||||
|
||||
func NewOptionManager(ref *types.ManagedObjectReference, setting []types.BaseOptionValue) object.Reference {
|
||||
s := &OptionManager{}
|
||||
if ref != nil {
|
||||
s.Self = *ref
|
||||
}
|
||||
s.Setting = setting
|
||||
return s
|
||||
}
|
||||
|
||||
func (m *OptionManager) QueryOptions(req *types.QueryOptions) soap.HasFault {
|
||||
body := &methods.QueryOptionsBody{}
|
||||
res := &types.QueryOptionsResponse{}
|
||||
|
||||
for _, opt := range m.Setting {
|
||||
if strings.HasPrefix(opt.GetOptionValue().Key, req.Name) {
|
||||
res.Returnval = append(res.Returnval, opt)
|
||||
}
|
||||
}
|
||||
|
||||
if len(res.Returnval) == 0 {
|
||||
body.Fault_ = Fault("", &types.InvalidName{Name: req.Name})
|
||||
} else {
|
||||
body.Res = res
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (m *OptionManager) find(key string) *types.OptionValue {
|
||||
for _, opt := range m.Setting {
|
||||
setting := opt.GetOptionValue()
|
||||
if setting.Key == key {
|
||||
return setting
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *OptionManager) UpdateOptions(req *types.UpdateOptions) soap.HasFault {
|
||||
body := new(methods.UpdateOptionsBody)
|
||||
|
||||
for _, change := range req.ChangedValue {
|
||||
setting := change.GetOptionValue()
|
||||
|
||||
// We don't currently include the entire list of default settings for ESX and vCenter,
|
||||
// this prefix is currently used to test the failure path.
|
||||
// Real vCenter seems to only allow new options if Key has a "config." prefix.
|
||||
// TODO: consider behaving the same, which would require including 2 long lists of options in vpx.Setting and esx.Setting
|
||||
if strings.HasPrefix(setting.Key, "ENOENT.") {
|
||||
body.Fault_ = Fault("", &types.InvalidName{Name: setting.Key})
|
||||
return body
|
||||
}
|
||||
|
||||
opt := m.find(setting.Key)
|
||||
if opt != nil {
|
||||
// This is an existing option.
|
||||
opt.Value = setting.Value
|
||||
continue
|
||||
}
|
||||
|
||||
m.Setting = append(m.Setting, change)
|
||||
}
|
||||
|
||||
body.Res = new(types.UpdateOptionsResponse)
|
||||
return body
|
||||
}
|
||||
146
vendor/github.com/vmware/govmomi/simulator/option_manager_test.go
generated
vendored
Normal file
146
vendor/github.com/vmware/govmomi/simulator/option_manager_test.go
generated
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestOptionManagerESX(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
model := ESX()
|
||||
model.Datastore = 0
|
||||
model.Machine = 0
|
||||
|
||||
err := model.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c := model.Service.client
|
||||
|
||||
m := object.NewOptionManager(c, *c.ServiceContent.Setting)
|
||||
_, err = m.Query(ctx, "config.vpxd.")
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
host := object.NewHostSystem(c, esx.HostSystem.Reference())
|
||||
m, err = host.ConfigManager().OptionManager(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
res, err := m.Query(ctx, "Config.HostAgent.")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if len(res) == 0 {
|
||||
t.Error("no results")
|
||||
}
|
||||
|
||||
err = m.Update(ctx, []types.BaseOptionValue{&types.OptionValue{
|
||||
Key: "Config.HostAgent.log.level",
|
||||
Value: "verbose",
|
||||
}})
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOptionManagerVPX(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
model := VPX()
|
||||
model.Datastore = 0
|
||||
model.Machine = 0
|
||||
|
||||
err := model.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c := model.Service.client
|
||||
|
||||
m := object.NewOptionManager(c, *c.ServiceContent.Setting)
|
||||
_, err = m.Query(ctx, "enoent")
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
res, err := m.Query(ctx, "event.")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if len(res) == 0 {
|
||||
t.Error("no results")
|
||||
}
|
||||
|
||||
val := &types.OptionValue{
|
||||
Key: "event.maxAge",
|
||||
}
|
||||
|
||||
// Get the existing maxAge value
|
||||
for _, r := range res {
|
||||
opt := r.GetOptionValue()
|
||||
if opt.Key == val.Key {
|
||||
val.Value = opt.Value
|
||||
}
|
||||
}
|
||||
|
||||
// Increase maxAge * 2
|
||||
val.Value = val.Value.(int32) * 2
|
||||
err = m.Update(ctx, []types.BaseOptionValue{val})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// Verify maxAge was updated
|
||||
res, err = m.Query(ctx, val.Key)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if res[0].GetOptionValue().Value != val.Value {
|
||||
t.Errorf("%s was not updated", val.Key)
|
||||
}
|
||||
|
||||
// Expected to throw InvalidName fault
|
||||
err = m.Update(ctx, []types.BaseOptionValue{&types.OptionValue{
|
||||
Key: "ENOENT.anything",
|
||||
}})
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
// Add a new option
|
||||
err = m.Update(ctx, []types.BaseOptionValue{&types.OptionValue{
|
||||
Key: "config.anything",
|
||||
Value: "OK",
|
||||
}})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
40
vendor/github.com/vmware/govmomi/simulator/os_unix.go
generated
vendored
Normal file
40
vendor/github.com/vmware/govmomi/simulator/os_unix.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
//+build !windows
|
||||
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import "syscall"
|
||||
|
||||
func (ds *Datastore) stat() error {
|
||||
info := ds.Info.GetDatastoreInfo()
|
||||
var stat syscall.Statfs_t
|
||||
|
||||
err := syscall.Statfs(info.Url, &stat)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bsize := uint64(stat.Bsize) / 512
|
||||
|
||||
info.FreeSpace = int64(stat.Bfree*bsize) >> 1
|
||||
|
||||
ds.Summary.FreeSpace = info.FreeSpace
|
||||
ds.Summary.Capacity = int64(stat.Blocks*bsize) >> 1
|
||||
|
||||
return nil
|
||||
}
|
||||
26
vendor/github.com/vmware/govmomi/simulator/os_windows.go
generated
vendored
Normal file
26
vendor/github.com/vmware/govmomi/simulator/os_windows.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import "os"
|
||||
|
||||
func (ds *Datastore) stat() error {
|
||||
info := ds.Info.GetDatastoreInfo()
|
||||
|
||||
_, err := os.Stat(info.Url)
|
||||
return err
|
||||
}
|
||||
35
vendor/github.com/vmware/govmomi/simulator/performance_manager.go
generated
vendored
Normal file
35
vendor/github.com/vmware/govmomi/simulator/performance_manager.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type PerformanceManager struct {
|
||||
mo.PerformanceManager
|
||||
}
|
||||
|
||||
func NewPerformanceManager(ref types.ManagedObjectReference) object.Reference {
|
||||
m := &PerformanceManager{}
|
||||
m.Self = ref
|
||||
m.PerfCounter = esx.PerfCounter
|
||||
return m
|
||||
}
|
||||
71
vendor/github.com/vmware/govmomi/simulator/portgroup.go
generated
vendored
Normal file
71
vendor/github.com/vmware/govmomi/simulator/portgroup.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type DistributedVirtualPortgroup struct {
|
||||
mo.DistributedVirtualPortgroup
|
||||
}
|
||||
|
||||
func (s *DistributedVirtualPortgroup) ReconfigureDVPortgroupTask(req *types.ReconfigureDVPortgroup_Task) soap.HasFault {
|
||||
task := CreateTask(s, "reconfigureDvPortgroup", func(t *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
s.Config.DefaultPortConfig = req.Spec.DefaultPortConfig
|
||||
s.Config.NumPorts = req.Spec.NumPorts
|
||||
s.Config.AutoExpand = req.Spec.AutoExpand
|
||||
s.Config.Type = req.Spec.Type
|
||||
s.Config.Description = req.Spec.Description
|
||||
s.Config.DynamicData = req.Spec.DynamicData
|
||||
s.Config.Name = req.Spec.Name
|
||||
s.Config.Policy = req.Spec.Policy
|
||||
s.Config.PortNameFormat = req.Spec.PortNameFormat
|
||||
s.Config.VmVnicNetworkResourcePoolKey = req.Spec.VmVnicNetworkResourcePoolKey
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.ReconfigureDVPortgroup_TaskBody{
|
||||
Res: &types.ReconfigureDVPortgroup_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DistributedVirtualPortgroup) DestroyTask(req *types.Destroy_Task) soap.HasFault {
|
||||
task := CreateTask(s, "destroy", func(t *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
vswitch := Map.Get(*s.Config.DistributedVirtualSwitch).(*DistributedVirtualSwitch)
|
||||
Map.RemoveReference(vswitch, &vswitch.Portgroup, s.Reference())
|
||||
Map.removeString(vswitch, &vswitch.Summary.PortgroupName, s.Name)
|
||||
|
||||
f := Map.getEntityParent(vswitch, "Folder").(*Folder)
|
||||
f.removeChild(s.Reference())
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.Destroy_TaskBody{
|
||||
Res: &types.Destroy_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
93
vendor/github.com/vmware/govmomi/simulator/portgroup_test.go
generated
vendored
Normal file
93
vendor/github.com/vmware/govmomi/simulator/portgroup_test.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestReconfigurePortgroup(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
m := VPX()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
c := m.Service.client
|
||||
|
||||
dvs := object.NewDistributedVirtualSwitch(c,
|
||||
Map.Any("DistributedVirtualSwitch").Reference())
|
||||
|
||||
spec := []types.DVPortgroupConfigSpec{
|
||||
types.DVPortgroupConfigSpec{
|
||||
Name: "pg1",
|
||||
NumPorts: 10,
|
||||
},
|
||||
}
|
||||
|
||||
task, err := dvs.AddPortgroup(ctx, spec)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pg := object.NewDistributedVirtualPortgroup(c,
|
||||
Map.Any("DistributedVirtualPortgroup").Reference())
|
||||
pgspec := types.DVPortgroupConfigSpec{
|
||||
NumPorts: 5,
|
||||
Name: "pg1",
|
||||
}
|
||||
|
||||
task, err = pg.Reconfigure(ctx, pgspec)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pge := Map.Get(pg.Reference()).(*DistributedVirtualPortgroup)
|
||||
if pge.Config.Name != "pg1" || pge.Config.NumPorts != 5 {
|
||||
t.Fatalf("expect pg.Name==pg1 && pg.Config.NumPort==5; got %s,%d",
|
||||
pge.Config.Name, pge.Config.NumPorts)
|
||||
}
|
||||
|
||||
task, err = pg.Destroy(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
580
vendor/github.com/vmware/govmomi/simulator/property_collector.go
generated
vendored
Normal file
580
vendor/github.com/vmware/govmomi/simulator/property_collector.go
generated
vendored
Normal file
@@ -0,0 +1,580 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"path"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type PropertyCollector struct {
|
||||
mo.PropertyCollector
|
||||
}
|
||||
|
||||
func NewPropertyCollector(ref types.ManagedObjectReference) object.Reference {
|
||||
s := &PropertyCollector{}
|
||||
s.Self = ref
|
||||
return s
|
||||
}
|
||||
|
||||
var errMissingField = errors.New("missing field")
|
||||
var errEmptyField = errors.New("empty field")
|
||||
|
||||
func getObject(ctx *Context, ref types.ManagedObjectReference) (reflect.Value, bool) {
|
||||
var obj mo.Reference
|
||||
if ctx.Session == nil {
|
||||
// Even without permissions to access an object or specific fields, RetrieveProperties
|
||||
// returns an ObjectContent response as long as the object exists. See retrieveResult.add()
|
||||
obj = Map.Get(ref)
|
||||
} else {
|
||||
obj = ctx.Session.Get(ref)
|
||||
}
|
||||
|
||||
if obj == nil {
|
||||
return reflect.Value{}, false
|
||||
}
|
||||
|
||||
if ctx.Session == nil && ref.Type == "SessionManager" {
|
||||
// RetrieveProperties on SessionManager without a session always returns empty,
|
||||
// rather than MissingSet + Fault.NotAuthenticated for each field.
|
||||
obj = &mo.SessionManager{Self: ref}
|
||||
}
|
||||
|
||||
// For objects that use internal types that differ from that of the vim25/mo field types.
|
||||
// See EventHistoryCollector for example.
|
||||
type get interface {
|
||||
Get() mo.Reference
|
||||
}
|
||||
if o, ok := obj.(get); ok {
|
||||
obj = o.Get()
|
||||
}
|
||||
|
||||
rval := reflect.ValueOf(obj).Elem()
|
||||
rtype := rval.Type()
|
||||
|
||||
// PropertyCollector is for Managed Object types only (package mo).
|
||||
// If the registry object is not in the mo package, assume it is a wrapper
|
||||
// type where the first field is an embedded mo type.
|
||||
// We need to dig out the mo type for PropSet.All to work properly and
|
||||
// for the case where the type has a field of the same name, for example:
|
||||
// mo.ResourcePool.ResourcePool
|
||||
for {
|
||||
if path.Base(rtype.PkgPath()) != "mo" {
|
||||
if rtype.Kind() != reflect.Struct || rtype.NumField() == 0 {
|
||||
log.Printf("%#v does not have an embedded mo type", ref)
|
||||
return reflect.Value{}, false
|
||||
}
|
||||
rval = rval.Field(0)
|
||||
rtype = rval.Type()
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return rval, true
|
||||
}
|
||||
|
||||
func fieldValueInterface(f reflect.StructField, rval reflect.Value) interface{} {
|
||||
if rval.Kind() == reflect.Ptr {
|
||||
rval = rval.Elem()
|
||||
}
|
||||
|
||||
pval := rval.Interface()
|
||||
|
||||
if rval.Kind() == reflect.Slice {
|
||||
// Convert slice to types.ArrayOf*
|
||||
switch v := pval.(type) {
|
||||
case []string:
|
||||
pval = &types.ArrayOfString{
|
||||
String: v,
|
||||
}
|
||||
case []int32:
|
||||
pval = &types.ArrayOfInt{
|
||||
Int: v,
|
||||
}
|
||||
default:
|
||||
kind := f.Type.Elem().Name()
|
||||
// Remove govmomi interface prefix name
|
||||
if strings.HasPrefix(kind, "Base") {
|
||||
kind = kind[4:]
|
||||
}
|
||||
akind, _ := typeFunc("ArrayOf" + kind)
|
||||
a := reflect.New(akind)
|
||||
a.Elem().FieldByName(kind).Set(rval)
|
||||
pval = a.Interface()
|
||||
}
|
||||
}
|
||||
|
||||
return pval
|
||||
}
|
||||
|
||||
func fieldValue(rval reflect.Value, p string) (interface{}, error) {
|
||||
var value interface{}
|
||||
fields := strings.Split(p, ".")
|
||||
|
||||
for i, name := range fields {
|
||||
kind := rval.Type().Kind()
|
||||
|
||||
if kind == reflect.Interface {
|
||||
if rval.IsNil() {
|
||||
continue
|
||||
}
|
||||
rval = rval.Elem()
|
||||
kind = rval.Type().Kind()
|
||||
}
|
||||
|
||||
if kind == reflect.Ptr {
|
||||
if rval.IsNil() {
|
||||
continue
|
||||
}
|
||||
rval = rval.Elem()
|
||||
}
|
||||
|
||||
x := ucFirst(name)
|
||||
val := rval.FieldByName(x)
|
||||
if !val.IsValid() {
|
||||
return nil, errMissingField
|
||||
}
|
||||
|
||||
if isEmpty(val) {
|
||||
return nil, errEmptyField
|
||||
}
|
||||
|
||||
if i == len(fields)-1 {
|
||||
ftype, _ := rval.Type().FieldByName(x)
|
||||
value = fieldValueInterface(ftype, val)
|
||||
break
|
||||
}
|
||||
|
||||
rval = val
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func fieldRefs(f interface{}) []types.ManagedObjectReference {
|
||||
switch fv := f.(type) {
|
||||
case types.ManagedObjectReference:
|
||||
return []types.ManagedObjectReference{fv}
|
||||
case *types.ArrayOfManagedObjectReference:
|
||||
return fv.ManagedObjectReference
|
||||
case nil:
|
||||
// empty field
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isEmpty(rval reflect.Value) bool {
|
||||
switch rval.Kind() {
|
||||
case reflect.Ptr:
|
||||
return rval.IsNil()
|
||||
case reflect.String:
|
||||
return rval.Len() == 0
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func isTrue(v *bool) bool {
|
||||
return v != nil && *v
|
||||
}
|
||||
|
||||
func isFalse(v *bool) bool {
|
||||
return v == nil || *v == false
|
||||
}
|
||||
|
||||
func lcFirst(s string) string {
|
||||
return strings.ToLower(s[:1]) + s[1:]
|
||||
}
|
||||
|
||||
func ucFirst(s string) string {
|
||||
return strings.ToUpper(s[:1]) + s[1:]
|
||||
}
|
||||
|
||||
type retrieveResult struct {
|
||||
*types.RetrieveResult
|
||||
req *types.RetrievePropertiesEx
|
||||
collected map[types.ManagedObjectReference]bool
|
||||
specs map[string]*types.TraversalSpec
|
||||
}
|
||||
|
||||
func (rr *retrieveResult) add(ctx *Context, name string, val types.AnyType, content *types.ObjectContent) {
|
||||
if ctx.Session != nil {
|
||||
content.PropSet = append(content.PropSet, types.DynamicProperty{
|
||||
Name: name,
|
||||
Val: val,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
content.MissingSet = append(content.MissingSet, types.MissingProperty{
|
||||
Path: name,
|
||||
Fault: types.LocalizedMethodFault{Fault: &types.NotAuthenticated{
|
||||
NoPermission: types.NoPermission{
|
||||
Object: content.Obj,
|
||||
PrivilegeId: "System.Read",
|
||||
}},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (rr *retrieveResult) collectAll(ctx *Context, rval reflect.Value, rtype reflect.Type, content *types.ObjectContent) {
|
||||
for i := 0; i < rval.NumField(); i++ {
|
||||
val := rval.Field(i)
|
||||
|
||||
f := rtype.Field(i)
|
||||
|
||||
if isEmpty(val) || f.Name == "Self" {
|
||||
continue
|
||||
}
|
||||
|
||||
if f.Anonymous {
|
||||
// recurse into embedded field
|
||||
rr.collectAll(ctx, val, f.Type, content)
|
||||
continue
|
||||
}
|
||||
|
||||
rr.add(ctx, lcFirst(f.Name), fieldValueInterface(f, val), content)
|
||||
}
|
||||
}
|
||||
|
||||
func (rr *retrieveResult) collectFields(ctx *Context, rval reflect.Value, fields []string, content *types.ObjectContent) {
|
||||
seen := make(map[string]bool)
|
||||
|
||||
for i := range content.PropSet {
|
||||
seen[content.PropSet[i].Name] = true // mark any already collected via embedded field
|
||||
}
|
||||
|
||||
for _, name := range fields {
|
||||
if seen[name] {
|
||||
// rvc 'ls' includes the "name" property twice, then fails with no error message or stack trace
|
||||
// in RbVmomi::VIM::ObjectContent.to_hash_uncached when it sees the 2nd "name" property.
|
||||
continue
|
||||
}
|
||||
seen[name] = true
|
||||
|
||||
val, err := fieldValue(rval, name)
|
||||
if err == nil {
|
||||
rr.add(ctx, name, val, content)
|
||||
continue
|
||||
}
|
||||
|
||||
switch err {
|
||||
case errEmptyField:
|
||||
// ok
|
||||
case errMissingField:
|
||||
content.MissingSet = append(content.MissingSet, types.MissingProperty{
|
||||
Path: name,
|
||||
Fault: types.LocalizedMethodFault{Fault: &types.InvalidProperty{
|
||||
Name: name,
|
||||
}},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (rr *retrieveResult) collect(ctx *Context, ref types.ManagedObjectReference) {
|
||||
if rr.collected[ref] {
|
||||
return
|
||||
}
|
||||
|
||||
content := types.ObjectContent{
|
||||
Obj: ref,
|
||||
}
|
||||
|
||||
rval, ok := getObject(ctx, ref)
|
||||
if !ok {
|
||||
// Possible if a test uses Map.Remove instead of Destroy_Task
|
||||
log.Printf("object %s no longer exists", ref)
|
||||
return
|
||||
}
|
||||
|
||||
rtype := rval.Type()
|
||||
|
||||
for _, spec := range rr.req.SpecSet {
|
||||
for _, p := range spec.PropSet {
|
||||
if p.Type != ref.Type {
|
||||
// e.g. ManagedEntity, ComputeResource
|
||||
field, ok := rtype.FieldByName(p.Type)
|
||||
|
||||
if !(ok && field.Anonymous) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if isTrue(p.All) {
|
||||
rr.collectAll(ctx, rval, rtype, &content)
|
||||
continue
|
||||
}
|
||||
|
||||
rr.collectFields(ctx, rval, p.PathSet, &content)
|
||||
}
|
||||
}
|
||||
|
||||
if len(content.PropSet) != 0 || len(content.MissingSet) != 0 {
|
||||
rr.Objects = append(rr.Objects, content)
|
||||
}
|
||||
|
||||
rr.collected[ref] = true
|
||||
}
|
||||
|
||||
func (rr *retrieveResult) selectSet(ctx *Context, obj reflect.Value, s []types.BaseSelectionSpec, refs *[]types.ManagedObjectReference) types.BaseMethodFault {
|
||||
for _, ss := range s {
|
||||
ts, ok := ss.(*types.TraversalSpec)
|
||||
if ok {
|
||||
if ts.Name != "" {
|
||||
rr.specs[ts.Name] = ts
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, ss := range s {
|
||||
ts, ok := ss.(*types.TraversalSpec)
|
||||
if !ok {
|
||||
ts = rr.specs[ss.GetSelectionSpec().Name]
|
||||
if ts == nil {
|
||||
return &types.InvalidArgument{InvalidProperty: "undefined TraversalSpec name"}
|
||||
}
|
||||
}
|
||||
|
||||
f, _ := fieldValue(obj, ts.Path)
|
||||
|
||||
for _, ref := range fieldRefs(f) {
|
||||
if isFalse(ts.Skip) {
|
||||
*refs = append(*refs, ref)
|
||||
}
|
||||
|
||||
rval, ok := getObject(ctx, ref)
|
||||
if ok {
|
||||
if err := rr.selectSet(ctx, rval, ts.SelectSet, refs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pc *PropertyCollector) collect(ctx *Context, r *types.RetrievePropertiesEx) (*types.RetrieveResult, types.BaseMethodFault) {
|
||||
var refs []types.ManagedObjectReference
|
||||
|
||||
rr := &retrieveResult{
|
||||
RetrieveResult: &types.RetrieveResult{},
|
||||
req: r,
|
||||
collected: make(map[types.ManagedObjectReference]bool),
|
||||
specs: make(map[string]*types.TraversalSpec),
|
||||
}
|
||||
|
||||
// Select object references
|
||||
for _, spec := range r.SpecSet {
|
||||
for _, o := range spec.ObjectSet {
|
||||
rval, ok := getObject(ctx, o.Obj)
|
||||
if !ok {
|
||||
if isFalse(spec.ReportMissingObjectsInResults) {
|
||||
return nil, &types.ManagedObjectNotFound{Obj: o.Obj}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if o.SelectSet == nil || isFalse(o.Skip) {
|
||||
refs = append(refs, o.Obj)
|
||||
}
|
||||
|
||||
if err := rr.selectSet(ctx, rval, o.SelectSet, &refs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, ref := range refs {
|
||||
rr.collect(ctx, ref)
|
||||
}
|
||||
|
||||
return rr.RetrieveResult, nil
|
||||
}
|
||||
|
||||
func (pc *PropertyCollector) CreateFilter(ctx *Context, c *types.CreateFilter) soap.HasFault {
|
||||
body := &methods.CreateFilterBody{}
|
||||
|
||||
filter := &PropertyFilter{pc: pc}
|
||||
filter.PartialUpdates = c.PartialUpdates
|
||||
filter.Spec = c.Spec
|
||||
|
||||
pc.Filter = append(pc.Filter, ctx.Session.Put(filter).Reference())
|
||||
|
||||
body.Res = &types.CreateFilterResponse{
|
||||
Returnval: filter.Self,
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (pc *PropertyCollector) CreatePropertyCollector(ctx *Context, c *types.CreatePropertyCollector) soap.HasFault {
|
||||
body := &methods.CreatePropertyCollectorBody{}
|
||||
|
||||
cpc := &PropertyCollector{}
|
||||
|
||||
body.Res = &types.CreatePropertyCollectorResponse{
|
||||
Returnval: ctx.Session.Put(cpc).Reference(),
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (pc *PropertyCollector) DestroyPropertyCollector(ctx *Context, c *types.DestroyPropertyCollector) soap.HasFault {
|
||||
body := &methods.DestroyPropertyCollectorBody{}
|
||||
|
||||
for _, ref := range pc.Filter {
|
||||
filter := ctx.Session.Get(ref).(*PropertyFilter)
|
||||
filter.DestroyPropertyFilter(&types.DestroyPropertyFilter{This: ref})
|
||||
}
|
||||
|
||||
ctx.Session.Remove(c.This)
|
||||
|
||||
body.Res = &types.DestroyPropertyCollectorResponse{}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (pc *PropertyCollector) RetrievePropertiesEx(ctx *Context, r *types.RetrievePropertiesEx) soap.HasFault {
|
||||
body := &methods.RetrievePropertiesExBody{}
|
||||
|
||||
res, fault := pc.collect(ctx, r)
|
||||
|
||||
if fault != nil {
|
||||
body.Fault_ = Fault("", fault)
|
||||
} else {
|
||||
body.Res = &types.RetrievePropertiesExResponse{
|
||||
Returnval: res,
|
||||
}
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
// RetrieveProperties is deprecated, but govmomi is still using it at the moment.
|
||||
func (pc *PropertyCollector) RetrieveProperties(ctx *Context, r *types.RetrieveProperties) soap.HasFault {
|
||||
body := &methods.RetrievePropertiesBody{}
|
||||
|
||||
res := pc.RetrievePropertiesEx(ctx, &types.RetrievePropertiesEx{
|
||||
This: r.This,
|
||||
SpecSet: r.SpecSet,
|
||||
})
|
||||
|
||||
if res.Fault() != nil {
|
||||
body.Fault_ = res.Fault()
|
||||
} else {
|
||||
body.Res = &types.RetrievePropertiesResponse{
|
||||
Returnval: res.(*methods.RetrievePropertiesExBody).Res.Returnval.Objects,
|
||||
}
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (pc *PropertyCollector) CancelWaitForUpdates(r *types.CancelWaitForUpdates) soap.HasFault {
|
||||
return &methods.CancelWaitForUpdatesBody{Res: new(types.CancelWaitForUpdatesResponse)}
|
||||
}
|
||||
|
||||
func (pc *PropertyCollector) WaitForUpdatesEx(ctx *Context, r *types.WaitForUpdatesEx) soap.HasFault {
|
||||
body := &methods.WaitForUpdatesExBody{}
|
||||
|
||||
// At the moment we need to support Task completion. Handlers can simply set the Task
|
||||
// state before returning and the non-incremental update is enough for the client.
|
||||
// We can wait for incremental updates to simulate timeouts, etc.
|
||||
if r.Version != "" {
|
||||
body.Fault_ = Fault("incremental updates not supported yet", &types.NotSupported{})
|
||||
return body
|
||||
}
|
||||
|
||||
update := &types.UpdateSet{
|
||||
Version: "-",
|
||||
}
|
||||
|
||||
for _, ref := range pc.Filter {
|
||||
filter := ctx.Session.Get(ref).(*PropertyFilter)
|
||||
|
||||
r := &types.RetrievePropertiesEx{}
|
||||
r.SpecSet = append(r.SpecSet, filter.Spec)
|
||||
|
||||
res, fault := pc.collect(ctx, r)
|
||||
if fault != nil {
|
||||
body.Fault_ = Fault("", fault)
|
||||
return body
|
||||
}
|
||||
|
||||
fu := types.PropertyFilterUpdate{
|
||||
Filter: ref,
|
||||
}
|
||||
|
||||
for _, o := range res.Objects {
|
||||
ou := types.ObjectUpdate{
|
||||
Obj: o.Obj,
|
||||
Kind: types.ObjectUpdateKindEnter,
|
||||
}
|
||||
|
||||
for _, p := range o.PropSet {
|
||||
ou.ChangeSet = append(ou.ChangeSet, types.PropertyChange{
|
||||
Op: types.PropertyChangeOpAssign,
|
||||
Name: p.Name,
|
||||
Val: p.Val,
|
||||
})
|
||||
}
|
||||
|
||||
fu.ObjectSet = append(fu.ObjectSet, ou)
|
||||
}
|
||||
|
||||
update.FilterSet = append(update.FilterSet, fu)
|
||||
}
|
||||
|
||||
body.Res = &types.WaitForUpdatesExResponse{
|
||||
Returnval: update,
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
// WaitForUpdates is deprecated, but pyvmomi is still using it at the moment.
|
||||
func (pc *PropertyCollector) WaitForUpdates(ctx *Context, r *types.WaitForUpdates) soap.HasFault {
|
||||
body := &methods.WaitForUpdatesBody{}
|
||||
|
||||
res := pc.WaitForUpdatesEx(ctx, &types.WaitForUpdatesEx{
|
||||
This: r.This,
|
||||
Version: r.Version,
|
||||
})
|
||||
|
||||
if res.Fault() != nil {
|
||||
body.Fault_ = res.Fault()
|
||||
} else {
|
||||
body.Res = &types.WaitForUpdatesResponse{
|
||||
Returnval: *res.(*methods.WaitForUpdatesExBody).Res.Returnval,
|
||||
}
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
1111
vendor/github.com/vmware/govmomi/simulator/property_collector_test.go
generated
vendored
Normal file
1111
vendor/github.com/vmware/govmomi/simulator/property_collector_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
42
vendor/github.com/vmware/govmomi/simulator/property_filter.go
generated
vendored
Normal file
42
vendor/github.com/vmware/govmomi/simulator/property_filter.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type PropertyFilter struct {
|
||||
mo.PropertyFilter
|
||||
|
||||
pc *PropertyCollector
|
||||
}
|
||||
|
||||
func (f *PropertyFilter) DestroyPropertyFilter(c *types.DestroyPropertyFilter) soap.HasFault {
|
||||
body := &methods.DestroyPropertyFilterBody{}
|
||||
|
||||
RemoveReference(&f.pc.Filter, c.This)
|
||||
|
||||
Map.Remove(c.This)
|
||||
|
||||
body.Res = &types.DestroyPropertyFilterResponse{}
|
||||
|
||||
return body
|
||||
}
|
||||
130
vendor/github.com/vmware/govmomi/simulator/race_test.go
generated
vendored
Normal file
130
vendor/github.com/vmware/govmomi/simulator/race_test.go
generated
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/find"
|
||||
"github.com/vmware/govmomi/property"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestRace(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
m := VPX()
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
spec := types.VirtualMachineConfigSpec{
|
||||
Name: fmt.Sprintf("race-test-%d", i),
|
||||
GuestId: string(types.VirtualMachineGuestOsIdentifierOtherGuest),
|
||||
Files: &types.VirtualMachineFileInfo{
|
||||
VmPathName: "[LocalDS_0]",
|
||||
},
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder := find.NewFinder(c.Client, false)
|
||||
pc := property.DefaultCollector(c.Client)
|
||||
dc, err := finder.DefaultDatacenter(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder.SetDatacenter(dc)
|
||||
|
||||
f, err := dc.Folders(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pool, err := finder.ResourcePool(ctx, "DC0_C0/Resources")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(time.Millisecond * 100)
|
||||
defer ticker.Stop()
|
||||
|
||||
for j := 0; j < 2; j++ {
|
||||
cspec := spec // copy spec and give it a unique name
|
||||
cspec.Name += fmt.Sprintf("-%d", j)
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
task, _ := f.VmFolder.CreateVM(ctx, cspec, pool, nil)
|
||||
info, terr := task.WaitForResult(ctx, nil)
|
||||
if terr != nil {
|
||||
t.Error(terr)
|
||||
}
|
||||
go func() {
|
||||
for _ = range ticker.C {
|
||||
var content []types.ObjectContent
|
||||
rerr := pc.RetrieveOne(ctx, info.Result.(types.ManagedObjectReference), nil, &content)
|
||||
if rerr != nil {
|
||||
t.Error(rerr)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}()
|
||||
}
|
||||
|
||||
vms, err := finder.VirtualMachineList(ctx, "*")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := range vms {
|
||||
vm := vms[i]
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
task, _ := vm.PowerOff(ctx)
|
||||
_ = task.Wait(ctx)
|
||||
}()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
426
vendor/github.com/vmware/govmomi/simulator/registry.go
generated
vendored
Normal file
426
vendor/github.com/vmware/govmomi/simulator/registry.go
generated
vendored
Normal file
@@ -0,0 +1,426 @@
|
||||
/*
|
||||
Copyright (c) 2017-2018 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
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 (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
// This is a map from a reference type name to a reference value name prefix.
|
||||
// It's a convention that VirtualCenter follows. The map is not complete, but
|
||||
// it should cover the most popular objects.
|
||||
var refValueMap = map[string]string{
|
||||
"DistributedVirtualPortgroup": "dvportgroup",
|
||||
"EnvironmentBrowser": "envbrowser",
|
||||
"HostSystem": "host",
|
||||
"ResourcePool": "resgroup",
|
||||
"VirtualMachine": "vm",
|
||||
"VirtualMachineSnapshot": "snapshot",
|
||||
"VmwareDistributedVirtualSwitch": "dvs",
|
||||
"DistributedVirtualSwitch": "dvs",
|
||||
}
|
||||
|
||||
// Map is the default Registry instance.
|
||||
var Map = NewRegistry()
|
||||
|
||||
// RegisterObject interface supports callbacks when objects are added and removed from the Registry
|
||||
type RegisterObject interface {
|
||||
mo.Reference
|
||||
PutObject(mo.Reference)
|
||||
RemoveObject(types.ManagedObjectReference)
|
||||
}
|
||||
|
||||
// Registry manages a map of mo.Reference objects
|
||||
type Registry struct {
|
||||
m sync.Mutex
|
||||
objects map[types.ManagedObjectReference]mo.Reference
|
||||
handlers map[types.ManagedObjectReference]RegisterObject
|
||||
locks map[types.ManagedObjectReference]sync.Locker
|
||||
counter int
|
||||
}
|
||||
|
||||
// NewRegistry creates a new instances of Registry
|
||||
func NewRegistry() *Registry {
|
||||
r := &Registry{
|
||||
objects: make(map[types.ManagedObjectReference]mo.Reference),
|
||||
handlers: make(map[types.ManagedObjectReference]RegisterObject),
|
||||
locks: make(map[types.ManagedObjectReference]sync.Locker),
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// typeName returns the type of the given object.
|
||||
func typeName(item mo.Reference) string {
|
||||
return reflect.TypeOf(item).Elem().Name()
|
||||
}
|
||||
|
||||
// valuePrefix returns the value name prefix of a given object
|
||||
func valuePrefix(typeName string) string {
|
||||
if v, ok := refValueMap[typeName]; ok {
|
||||
return v
|
||||
}
|
||||
|
||||
return strings.ToLower(typeName)
|
||||
}
|
||||
|
||||
// newReference returns a new MOR, where Type defaults to type of the given item
|
||||
// and Value defaults to a unique id for the given type.
|
||||
func (r *Registry) newReference(item mo.Reference) types.ManagedObjectReference {
|
||||
ref := item.Reference()
|
||||
|
||||
if ref.Type == "" {
|
||||
ref.Type = typeName(item)
|
||||
}
|
||||
|
||||
if ref.Value == "" {
|
||||
r.counter++
|
||||
ref.Value = fmt.Sprintf("%s-%d", valuePrefix(ref.Type), r.counter)
|
||||
}
|
||||
|
||||
return ref
|
||||
}
|
||||
|
||||
func (r *Registry) setReference(item mo.Reference, ref types.ManagedObjectReference) {
|
||||
// mo.Reference() returns a value, not a pointer so use reflect to set the Self field
|
||||
reflect.ValueOf(item).Elem().FieldByName("Self").Set(reflect.ValueOf(ref))
|
||||
}
|
||||
|
||||
// AddHandler adds a RegisterObject handler to the Registry.
|
||||
func (r *Registry) AddHandler(h RegisterObject) {
|
||||
r.handlers[h.Reference()] = h
|
||||
}
|
||||
|
||||
// NewEntity sets Entity().Self with a new, unique Value.
|
||||
// Useful for creating object instances from templates.
|
||||
func (r *Registry) NewEntity(item mo.Entity) mo.Entity {
|
||||
e := item.Entity()
|
||||
e.Self.Value = ""
|
||||
e.Self = r.newReference(item)
|
||||
return item
|
||||
}
|
||||
|
||||
// PutEntity sets item.Parent to that of parent.Self before adding item to the Registry.
|
||||
func (r *Registry) PutEntity(parent mo.Entity, item mo.Entity) mo.Entity {
|
||||
e := item.Entity()
|
||||
|
||||
if parent != nil {
|
||||
e.Parent = &parent.Entity().Self
|
||||
}
|
||||
|
||||
r.Put(item)
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
// Get returns the object for the given reference.
|
||||
func (r *Registry) Get(ref types.ManagedObjectReference) mo.Reference {
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
|
||||
return r.objects[ref]
|
||||
}
|
||||
|
||||
// Any returns the first instance of entity type specified by kind.
|
||||
func (r *Registry) Any(kind string) mo.Entity {
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
|
||||
for ref, val := range r.objects {
|
||||
if ref.Type == kind {
|
||||
return val.(mo.Entity)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Put adds a new object to Registry, generating a ManagedObjectReference if not already set.
|
||||
func (r *Registry) Put(item mo.Reference) mo.Reference {
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
|
||||
ref := item.Reference()
|
||||
if ref.Type == "" || ref.Value == "" {
|
||||
ref = r.newReference(item)
|
||||
r.setReference(item, ref)
|
||||
}
|
||||
|
||||
if me, ok := item.(mo.Entity); ok {
|
||||
me.Entity().ConfigStatus = types.ManagedEntityStatusGreen
|
||||
me.Entity().OverallStatus = types.ManagedEntityStatusGreen
|
||||
me.Entity().EffectiveRole = []int32{-1} // Admin
|
||||
}
|
||||
|
||||
r.objects[ref] = item
|
||||
|
||||
for _, h := range r.handlers {
|
||||
h.PutObject(item)
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
// Remove removes an object from the Registry.
|
||||
func (r *Registry) Remove(item types.ManagedObjectReference) {
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
|
||||
for _, h := range r.handlers {
|
||||
h.RemoveObject(item)
|
||||
}
|
||||
|
||||
delete(r.objects, item)
|
||||
delete(r.handlers, item)
|
||||
delete(r.locks, item)
|
||||
}
|
||||
|
||||
// getEntityParent traverses up the inventory and returns the first object of type kind.
|
||||
// If no object of type kind is found, the method will panic when it reaches the
|
||||
// inventory root Folder where the Parent field is nil.
|
||||
func (r *Registry) getEntityParent(item mo.Entity, kind string) mo.Entity {
|
||||
for {
|
||||
parent := item.Entity().Parent
|
||||
|
||||
item = r.Get(*parent).(mo.Entity)
|
||||
|
||||
if item.Reference().Type == kind {
|
||||
return item
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getEntityDatacenter returns the Datacenter containing the given item
|
||||
func (r *Registry) getEntityDatacenter(item mo.Entity) *Datacenter {
|
||||
return r.getEntityParent(item, "Datacenter").(*Datacenter)
|
||||
}
|
||||
|
||||
func (r *Registry) getEntityFolder(item mo.Entity, kind string) *Folder {
|
||||
dc := Map.getEntityDatacenter(item)
|
||||
|
||||
var ref types.ManagedObjectReference
|
||||
|
||||
switch kind {
|
||||
case "datastore":
|
||||
ref = dc.DatastoreFolder
|
||||
}
|
||||
|
||||
folder := r.Get(ref).(*Folder)
|
||||
|
||||
// If Model was created with Folder option, use that Folder; else use top-level folder
|
||||
for _, child := range folder.ChildEntity {
|
||||
if child.Type == "Folder" {
|
||||
folder = Map.Get(child).(*Folder)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return folder
|
||||
}
|
||||
|
||||
// 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 (r *Registry) getEntityComputeResource(item mo.Entity) mo.Entity {
|
||||
for {
|
||||
parent := item.Entity().Parent
|
||||
|
||||
item = r.Get(*parent).(mo.Entity)
|
||||
|
||||
switch item.Reference().Type {
|
||||
case "ComputeResource":
|
||||
return item
|
||||
case "ClusterComputeResource":
|
||||
return item
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FindByName returns the first mo.Entity of the given refs whose Name field is equal to the given name.
|
||||
// If there is no match, nil is returned.
|
||||
// This method is useful for cases where objects are required to have a unique name, such as Datastore with
|
||||
// a HostStorageSystem or HostSystem within a ClusterComputeResource.
|
||||
func (r *Registry) FindByName(name string, refs []types.ManagedObjectReference) mo.Entity {
|
||||
for _, ref := range refs {
|
||||
if e, ok := r.Get(ref).(mo.Entity); ok {
|
||||
if name == e.Entity().Name {
|
||||
return e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindReference returns the 1st match found in refs, or nil if not found.
|
||||
func FindReference(refs []types.ManagedObjectReference, match ...types.ManagedObjectReference) *types.ManagedObjectReference {
|
||||
for _, ref := range refs {
|
||||
for _, m := range match {
|
||||
if ref == m {
|
||||
return &ref
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AppendReference appends the given refs to field.
|
||||
func (r *Registry) AppendReference(obj mo.Reference, field *[]types.ManagedObjectReference, ref ...types.ManagedObjectReference) {
|
||||
r.WithLock(obj, func() {
|
||||
*field = append(*field, ref...)
|
||||
})
|
||||
}
|
||||
|
||||
// AddReference appends ref to field if not already in the given field.
|
||||
func (r *Registry) AddReference(obj mo.Reference, field *[]types.ManagedObjectReference, ref types.ManagedObjectReference) {
|
||||
r.WithLock(obj, func() {
|
||||
if FindReference(*field, ref) == nil {
|
||||
*field = append(*field, ref)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// RemoveReference removes ref from the given field.
|
||||
func RemoveReference(field *[]types.ManagedObjectReference, ref types.ManagedObjectReference) {
|
||||
for i, r := range *field {
|
||||
if r == ref {
|
||||
*field = append((*field)[:i], (*field)[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveReference removes ref from the given field.
|
||||
func (r *Registry) RemoveReference(obj mo.Reference, field *[]types.ManagedObjectReference, ref types.ManagedObjectReference) {
|
||||
r.WithLock(obj, func() {
|
||||
RemoveReference(field, ref)
|
||||
})
|
||||
}
|
||||
|
||||
func (r *Registry) removeString(obj mo.Reference, field *[]string, val string) {
|
||||
r.WithLock(obj, func() {
|
||||
for i, name := range *field {
|
||||
if name == val {
|
||||
*field = append((*field)[:i], (*field)[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (r *Registry) content() types.ServiceContent {
|
||||
return r.Get(methods.ServiceInstance).(*ServiceInstance).Content
|
||||
}
|
||||
|
||||
// IsESX returns true if this Registry maps an ESX model
|
||||
func (r *Registry) IsESX() bool {
|
||||
return r.content().About.ApiType == "HostAgent"
|
||||
}
|
||||
|
||||
// IsVPX returns true if this Registry maps a VPX model
|
||||
func (r *Registry) IsVPX() bool {
|
||||
return !r.IsESX()
|
||||
}
|
||||
|
||||
// SearchIndex returns the SearchIndex singleton
|
||||
func (r *Registry) SearchIndex() *SearchIndex {
|
||||
return r.Get(r.content().SearchIndex.Reference()).(*SearchIndex)
|
||||
}
|
||||
|
||||
// EventManager returns the EventManager singleton
|
||||
func (r *Registry) EventManager() *EventManager {
|
||||
return r.Get(r.content().EventManager.Reference()).(*EventManager)
|
||||
}
|
||||
|
||||
// FileManager returns the FileManager singleton
|
||||
func (r *Registry) FileManager() *FileManager {
|
||||
return r.Get(r.content().FileManager.Reference()).(*FileManager)
|
||||
}
|
||||
|
||||
// VirtualDiskManager returns the VirtualDiskManager singleton
|
||||
func (r *Registry) VirtualDiskManager() *VirtualDiskManager {
|
||||
return r.Get(r.content().VirtualDiskManager.Reference()).(*VirtualDiskManager)
|
||||
}
|
||||
|
||||
// ViewManager returns the ViewManager singleton
|
||||
func (r *Registry) ViewManager() *ViewManager {
|
||||
return r.Get(r.content().ViewManager.Reference()).(*ViewManager)
|
||||
}
|
||||
|
||||
// UserDirectory returns the UserDirectory singleton
|
||||
func (r *Registry) UserDirectory() *UserDirectory {
|
||||
return r.Get(r.content().UserDirectory.Reference()).(*UserDirectory)
|
||||
}
|
||||
|
||||
// SessionManager returns the SessionManager singleton
|
||||
func (r *Registry) SessionManager() *SessionManager {
|
||||
return r.Get(r.content().SessionManager.Reference()).(*SessionManager)
|
||||
}
|
||||
|
||||
func (r *Registry) MarshalJSON() ([]byte, error) {
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
|
||||
vars := struct {
|
||||
Objects int
|
||||
Locks int
|
||||
}{
|
||||
len(r.objects),
|
||||
len(r.locks),
|
||||
}
|
||||
|
||||
return json.Marshal(vars)
|
||||
}
|
||||
|
||||
func (r *Registry) locker(obj mo.Reference) sync.Locker {
|
||||
if mu, ok := obj.(sync.Locker); ok {
|
||||
return mu
|
||||
}
|
||||
|
||||
ref := obj.Reference()
|
||||
r.m.Lock()
|
||||
mu, ok := r.locks[ref]
|
||||
if !ok {
|
||||
mu = new(sync.Mutex)
|
||||
r.locks[ref] = mu
|
||||
}
|
||||
r.m.Unlock()
|
||||
|
||||
return mu
|
||||
}
|
||||
|
||||
var enableLocker = os.Getenv("VCSIM_LOCKER") != "false"
|
||||
|
||||
// WithLock holds a lock for the given object while then given function is run.
|
||||
func (r *Registry) WithLock(obj mo.Reference, f func()) {
|
||||
if enableLocker {
|
||||
mu := r.locker(obj)
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
}
|
||||
f()
|
||||
}
|
||||
69
vendor/github.com/vmware/govmomi/simulator/registry_test.go
generated
vendored
Normal file
69
vendor/github.com/vmware/govmomi/simulator/registry_test.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestRegistry(t *testing.T) {
|
||||
r := NewRegistry()
|
||||
|
||||
ref := types.ManagedObjectReference{Type: "Test", Value: "Test"}
|
||||
f := &mo.Folder{}
|
||||
f.Self = ref
|
||||
r.PutEntity(nil, f)
|
||||
|
||||
e := r.Get(ref)
|
||||
|
||||
if e.Reference() != ref {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
r.Remove(ref)
|
||||
|
||||
if r.Get(ref) != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
r.Put(e)
|
||||
e = r.Get(ref)
|
||||
|
||||
if e.Reference() != ref {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveReference(t *testing.T) {
|
||||
var refs []types.ManagedObjectReference
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
refs = append(refs, types.ManagedObjectReference{Type: "any", Value: fmt.Sprintf("%d", i)})
|
||||
}
|
||||
|
||||
n := len(refs)
|
||||
|
||||
RemoveReference(&refs, refs[2])
|
||||
|
||||
if len(refs) != n-1 {
|
||||
t.Errorf("%d", len(refs))
|
||||
}
|
||||
}
|
||||
314
vendor/github.com/vmware/govmomi/simulator/resource_pool.go
generated
vendored
Normal file
314
vendor/github.com/vmware/govmomi/simulator/resource_pool.go
generated
vendored
Normal file
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type ResourcePool struct {
|
||||
mo.ResourcePool
|
||||
}
|
||||
|
||||
func NewResourcePool() *ResourcePool {
|
||||
pool := &ResourcePool{
|
||||
ResourcePool: esx.ResourcePool,
|
||||
}
|
||||
|
||||
if Map.IsVPX() {
|
||||
pool.DisabledMethod = nil // Enable VApp methods for VC
|
||||
}
|
||||
|
||||
return pool
|
||||
}
|
||||
|
||||
func allResourceFieldsSet(info *types.ResourceAllocationInfo) bool {
|
||||
return info.Reservation != nil &&
|
||||
info.Limit != nil &&
|
||||
info.ExpandableReservation != nil &&
|
||||
info.Shares != nil
|
||||
}
|
||||
|
||||
func allResourceFieldsValid(info *types.ResourceAllocationInfo) bool {
|
||||
if info.Reservation != nil {
|
||||
if *info.Reservation < 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if info.Limit != nil {
|
||||
if *info.Limit < -1 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if info.Shares != nil {
|
||||
if info.Shares.Level == types.SharesLevelCustom {
|
||||
if info.Shares.Shares < 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if info.OverheadLimit != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *ResourcePool) createChild(name string, spec types.ResourceConfigSpec) (*ResourcePool, *soap.Fault) {
|
||||
if e := Map.FindByName(name, p.ResourcePool.ResourcePool); e != nil {
|
||||
return nil, Fault("", &types.DuplicateName{
|
||||
Name: e.Entity().Name,
|
||||
Object: e.Reference(),
|
||||
})
|
||||
}
|
||||
|
||||
if !(allResourceFieldsSet(&spec.CpuAllocation) && allResourceFieldsValid(&spec.CpuAllocation)) {
|
||||
return nil, Fault("", &types.InvalidArgument{
|
||||
InvalidProperty: "spec.cpuAllocation",
|
||||
})
|
||||
}
|
||||
|
||||
if !(allResourceFieldsSet(&spec.MemoryAllocation) && allResourceFieldsValid(&spec.MemoryAllocation)) {
|
||||
return nil, Fault("", &types.InvalidArgument{
|
||||
InvalidProperty: "spec.memoryAllocation",
|
||||
})
|
||||
}
|
||||
|
||||
child := NewResourcePool()
|
||||
|
||||
child.Name = name
|
||||
child.Owner = p.Owner
|
||||
child.Summary.GetResourcePoolSummary().Name = name
|
||||
child.Config.CpuAllocation = spec.CpuAllocation
|
||||
child.Config.MemoryAllocation = spec.MemoryAllocation
|
||||
child.Config.Entity = spec.Entity
|
||||
|
||||
return child, nil
|
||||
}
|
||||
|
||||
func (p *ResourcePool) CreateResourcePool(c *types.CreateResourcePool) soap.HasFault {
|
||||
body := &methods.CreateResourcePoolBody{}
|
||||
|
||||
child, err := p.createChild(c.Name, c.Spec)
|
||||
if err != nil {
|
||||
body.Fault_ = err
|
||||
return body
|
||||
}
|
||||
|
||||
Map.PutEntity(p, Map.NewEntity(child))
|
||||
|
||||
p.ResourcePool.ResourcePool = append(p.ResourcePool.ResourcePool, child.Reference())
|
||||
|
||||
body.Res = &types.CreateResourcePoolResponse{
|
||||
Returnval: child.Reference(),
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func updateResourceAllocation(kind string, src, dst *types.ResourceAllocationInfo) types.BaseMethodFault {
|
||||
if !allResourceFieldsValid(src) {
|
||||
return &types.InvalidArgument{
|
||||
InvalidProperty: fmt.Sprintf("spec.%sAllocation", kind),
|
||||
}
|
||||
}
|
||||
|
||||
if src.Reservation != nil {
|
||||
dst.Reservation = src.Reservation
|
||||
}
|
||||
|
||||
if src.Limit != nil {
|
||||
dst.Limit = src.Limit
|
||||
}
|
||||
|
||||
if src.Shares != nil {
|
||||
dst.Shares = src.Shares
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ResourcePool) UpdateConfig(c *types.UpdateConfig) soap.HasFault {
|
||||
body := &methods.UpdateConfigBody{}
|
||||
|
||||
if c.Name != "" {
|
||||
if e := Map.FindByName(c.Name, p.ResourcePool.ResourcePool); e != nil {
|
||||
body.Fault_ = Fault("", &types.DuplicateName{
|
||||
Name: e.Entity().Name,
|
||||
Object: e.Reference(),
|
||||
})
|
||||
return body
|
||||
}
|
||||
|
||||
p.Name = c.Name
|
||||
}
|
||||
|
||||
spec := c.Config
|
||||
|
||||
if spec != nil {
|
||||
if err := updateResourceAllocation("memory", &spec.MemoryAllocation, &p.Config.MemoryAllocation); err != nil {
|
||||
body.Fault_ = Fault("", err)
|
||||
return body
|
||||
}
|
||||
|
||||
if err := updateResourceAllocation("cpu", &spec.CpuAllocation, &p.Config.CpuAllocation); err != nil {
|
||||
body.Fault_ = Fault("", err)
|
||||
return body
|
||||
}
|
||||
}
|
||||
|
||||
body.Res = &types.UpdateConfigResponse{}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
type VirtualApp struct {
|
||||
mo.VirtualApp
|
||||
}
|
||||
|
||||
func NewVAppConfigSpec() types.VAppConfigSpec {
|
||||
spec := types.VAppConfigSpec{
|
||||
Annotation: "vcsim",
|
||||
VmConfigSpec: types.VmConfigSpec{
|
||||
Product: []types.VAppProductSpec{
|
||||
{
|
||||
Info: &types.VAppProductInfo{
|
||||
Name: "vcsim",
|
||||
Vendor: "VMware",
|
||||
VendorUrl: "http://www.vmware.com/",
|
||||
Version: "0.1",
|
||||
},
|
||||
ArrayUpdateSpec: types.ArrayUpdateSpec{
|
||||
Operation: types.ArrayUpdateOperationAdd,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return spec
|
||||
}
|
||||
|
||||
func (p *ResourcePool) CreateVApp(req *types.CreateVApp) soap.HasFault {
|
||||
body := &methods.CreateVAppBody{}
|
||||
|
||||
pool, err := p.createChild(req.Name, req.ResSpec)
|
||||
if err != nil {
|
||||
body.Fault_ = err
|
||||
return body
|
||||
}
|
||||
|
||||
child := &VirtualApp{}
|
||||
child.ResourcePool = pool.ResourcePool
|
||||
child.Self.Type = "VirtualApp"
|
||||
child.ParentFolder = req.VmFolder
|
||||
|
||||
if child.ParentFolder == nil {
|
||||
folder := Map.getEntityDatacenter(p).VmFolder
|
||||
child.ParentFolder = &folder
|
||||
}
|
||||
|
||||
child.VAppConfig = &types.VAppConfigInfo{
|
||||
VmConfigInfo: types.VmConfigInfo{},
|
||||
Annotation: req.ConfigSpec.Annotation,
|
||||
}
|
||||
|
||||
for _, product := range req.ConfigSpec.Product {
|
||||
child.VAppConfig.Product = append(child.VAppConfig.Product, *product.Info)
|
||||
}
|
||||
|
||||
Map.PutEntity(p, Map.NewEntity(child))
|
||||
|
||||
p.ResourcePool.ResourcePool = append(p.ResourcePool.ResourcePool, child.Reference())
|
||||
|
||||
body.Res = &types.CreateVAppResponse{
|
||||
Returnval: child.Reference(),
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (a *VirtualApp) CreateChildVMTask(ctx *Context, req *types.CreateChildVM_Task) soap.HasFault {
|
||||
ctx.Caller = &a.Self
|
||||
body := &methods.CreateChildVM_TaskBody{}
|
||||
|
||||
folder := Map.Get(*a.ParentFolder).(*Folder)
|
||||
|
||||
res := folder.CreateVMTask(ctx, &types.CreateVM_Task{
|
||||
This: folder.Self,
|
||||
Config: req.Config,
|
||||
Host: req.Host,
|
||||
Pool: req.This,
|
||||
})
|
||||
|
||||
body.Res = &types.CreateChildVM_TaskResponse{
|
||||
Returnval: res.(*methods.CreateVM_TaskBody).Res.Returnval,
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (a *VirtualApp) DestroyTask(req *types.Destroy_Task) soap.HasFault {
|
||||
return (&ResourcePool{ResourcePool: a.ResourcePool}).DestroyTask(req)
|
||||
}
|
||||
|
||||
func (p *ResourcePool) DestroyTask(req *types.Destroy_Task) soap.HasFault {
|
||||
task := CreateTask(p, "destroy", func(t *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
if strings.HasSuffix(p.Parent.Type, "ComputeResource") {
|
||||
// Can't destroy the root pool
|
||||
return nil, &types.InvalidArgument{}
|
||||
}
|
||||
|
||||
pp := Map.Get(*p.Parent).(*ResourcePool)
|
||||
|
||||
parent := &pp.ResourcePool
|
||||
// Remove child reference from rp
|
||||
Map.RemoveReference(parent, &parent.ResourcePool, req.This)
|
||||
|
||||
// The grandchildren become children of the parent (rp)
|
||||
Map.AppendReference(parent, &parent.ResourcePool, p.ResourcePool.ResourcePool...)
|
||||
|
||||
// And VMs move to the parent
|
||||
vms := p.ResourcePool.Vm
|
||||
for _, ref := range vms {
|
||||
vm := Map.Get(ref).(*VirtualMachine)
|
||||
Map.WithLock(vm, func() { vm.ResourcePool = &parent.Self })
|
||||
}
|
||||
|
||||
Map.AppendReference(parent, &parent.Vm, vms...)
|
||||
|
||||
Map.Remove(req.This)
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.Destroy_TaskBody{
|
||||
Res: &types.Destroy_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
323
vendor/github.com/vmware/govmomi/simulator/resource_pool_test.go
generated
vendored
Normal file
323
vendor/github.com/vmware/govmomi/simulator/resource_pool_test.go
generated
vendored
Normal file
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/vmware/govmomi/find"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestResourcePool(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
m := &Model{
|
||||
ServiceContent: esx.ServiceContent,
|
||||
RootFolder: esx.RootFolder,
|
||||
}
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c := m.Service.client
|
||||
|
||||
finder := find.NewFinder(c, false)
|
||||
finder.SetDatacenter(object.NewDatacenter(c, esx.Datacenter.Reference()))
|
||||
|
||||
spec := types.DefaultResourceConfigSpec()
|
||||
|
||||
parent := object.NewResourcePool(c, esx.ResourcePool.Self)
|
||||
|
||||
spec.CpuAllocation.Reservation = nil
|
||||
// missing required field (Reservation) for create
|
||||
_, err = parent.Create(ctx, "fail", spec)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
spec = types.DefaultResourceConfigSpec()
|
||||
|
||||
// can't destroy a root pool
|
||||
task, err := parent.Destroy(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = task.Wait(ctx); err == nil {
|
||||
t.Fatal("expected error destroying a root pool")
|
||||
}
|
||||
|
||||
// create a child pool
|
||||
childName := uuid.New().String()
|
||||
|
||||
child, err := parent.Create(ctx, childName, spec)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if child.Reference() == esx.ResourcePool.Self {
|
||||
t.Error("expected new pool Self reference")
|
||||
}
|
||||
|
||||
*spec.CpuAllocation.Reservation = -1
|
||||
// invalid field value (Reservation) for update
|
||||
err = child.UpdateConfig(ctx, "", &spec)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
// valid config update
|
||||
*spec.CpuAllocation.Reservation = 10
|
||||
err = child.UpdateConfig(ctx, "", &spec)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var p mo.ResourcePool
|
||||
err = child.Properties(ctx, child.Reference(), []string{"config.cpuAllocation"}, &p)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if *p.Config.CpuAllocation.Reservation != 10 {
|
||||
t.Error("config not updated")
|
||||
}
|
||||
|
||||
// duplicate name
|
||||
_, err = parent.Create(ctx, childName, spec)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
// create a grandchild pool
|
||||
grandChildName := uuid.New().String()
|
||||
_, err = child.Create(ctx, grandChildName, spec)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// create sibling (of the grand child) pool
|
||||
siblingName := uuid.New().String()
|
||||
_, err = child.Create(ctx, siblingName, spec)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// finder should return the 2 grand children
|
||||
pools, err := finder.ResourcePoolList(ctx, "*/Resources/"+childName+"/*")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(pools) != 2 {
|
||||
t.Fatalf("len(pools) == %d", len(pools))
|
||||
}
|
||||
|
||||
// destroy the child
|
||||
task, err = child.Destroy(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// finder should error not found after destroying the child
|
||||
_, err = finder.ResourcePoolList(ctx, "*/Resources/"+childName+"/*")
|
||||
if err == nil {
|
||||
t.Fatal("expected not found error")
|
||||
}
|
||||
|
||||
// since the child was destroyed, grand child pools should now be children of the root pool
|
||||
pools, err = finder.ResourcePoolList(ctx, "*/Resources/*")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(pools) != 2 {
|
||||
t.Fatalf("len(pools) == %d", len(pools))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateVAppESX(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
m := ESX()
|
||||
m.Datastore = 0
|
||||
m.Machine = 0
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c := m.Service.client
|
||||
|
||||
parent := object.NewResourcePool(c, esx.ResourcePool.Self)
|
||||
|
||||
rspec := types.DefaultResourceConfigSpec()
|
||||
vspec := NewVAppConfigSpec()
|
||||
|
||||
_, err = parent.CreateVApp(ctx, "myapp", rspec, vspec, nil)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
|
||||
fault := soap.ToSoapFault(err).Detail.Fault
|
||||
|
||||
if reflect.TypeOf(fault) != reflect.TypeOf(&types.MethodDisabled{}) {
|
||||
t.Errorf("fault=%#v", fault)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateVAppVPX(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
m := VPX()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
c := m.Service.client
|
||||
|
||||
parent := object.NewResourcePool(c, Map.Any("ResourcePool").Reference())
|
||||
|
||||
rspec := types.DefaultResourceConfigSpec()
|
||||
vspec := NewVAppConfigSpec()
|
||||
|
||||
vapp, err := parent.CreateVApp(ctx, "myapp", rspec, vspec, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = parent.CreateVApp(ctx, "myapp", rspec, vspec, nil)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
spec := types.VirtualMachineConfigSpec{
|
||||
GuestId: string(types.VirtualMachineGuestOsIdentifierOtherGuest),
|
||||
Files: &types.VirtualMachineFileInfo{
|
||||
VmPathName: "[LocalDS_0]",
|
||||
},
|
||||
}
|
||||
|
||||
for _, fail := range []bool{true, false} {
|
||||
task, cerr := vapp.CreateChildVM(ctx, spec, nil)
|
||||
if cerr != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cerr = task.Wait(ctx)
|
||||
if fail {
|
||||
if cerr == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
} else {
|
||||
if cerr != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
spec.Name = "test"
|
||||
}
|
||||
|
||||
si := object.NewSearchIndex(c)
|
||||
vm, err := si.FindChild(ctx, vapp, spec.Name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if vm == nil {
|
||||
t.Errorf("FindChild(%s)==nil", spec.Name)
|
||||
}
|
||||
|
||||
task, err := vapp.Destroy(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResourcePoolValidation(t *testing.T) {
|
||||
tests := []func() bool{
|
||||
func() bool {
|
||||
return allResourceFieldsSet(&types.ResourceAllocationInfo{})
|
||||
},
|
||||
func() bool {
|
||||
spec := types.DefaultResourceConfigSpec()
|
||||
spec.CpuAllocation.Limit = nil
|
||||
return allResourceFieldsSet(&spec.CpuAllocation)
|
||||
},
|
||||
func() bool {
|
||||
spec := types.DefaultResourceConfigSpec()
|
||||
spec.CpuAllocation.Reservation = nil
|
||||
return allResourceFieldsSet(&spec.CpuAllocation)
|
||||
},
|
||||
func() bool {
|
||||
spec := types.DefaultResourceConfigSpec()
|
||||
spec.CpuAllocation.ExpandableReservation = nil
|
||||
return allResourceFieldsSet(&spec.CpuAllocation)
|
||||
},
|
||||
func() bool {
|
||||
spec := types.DefaultResourceConfigSpec()
|
||||
spec.CpuAllocation.Shares = nil
|
||||
return allResourceFieldsSet(&spec.CpuAllocation)
|
||||
},
|
||||
func() bool {
|
||||
spec := types.DefaultResourceConfigSpec()
|
||||
spec.CpuAllocation.Reservation = types.NewInt64(-1)
|
||||
return allResourceFieldsValid(&spec.CpuAllocation)
|
||||
},
|
||||
func() bool {
|
||||
spec := types.DefaultResourceConfigSpec()
|
||||
spec.CpuAllocation.Limit = types.NewInt64(-100)
|
||||
return allResourceFieldsValid(&spec.CpuAllocation)
|
||||
},
|
||||
func() bool {
|
||||
spec := types.DefaultResourceConfigSpec()
|
||||
shares := spec.CpuAllocation.Shares
|
||||
shares.Level = types.SharesLevelCustom
|
||||
shares.Shares = -1
|
||||
return allResourceFieldsValid(&spec.CpuAllocation)
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
ok := test()
|
||||
if ok {
|
||||
t.Errorf("%d: expected false", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
155
vendor/github.com/vmware/govmomi/simulator/search_index.go
generated
vendored
Normal file
155
vendor/github.com/vmware/govmomi/simulator/search_index.go
generated
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type SearchIndex struct {
|
||||
mo.SearchIndex
|
||||
}
|
||||
|
||||
func NewSearchIndex(ref types.ManagedObjectReference) object.Reference {
|
||||
m := &SearchIndex{}
|
||||
m.Self = ref
|
||||
return m
|
||||
}
|
||||
|
||||
func (s *SearchIndex) FindByDatastorePath(r *types.FindByDatastorePath) soap.HasFault {
|
||||
res := &methods.FindByDatastorePathBody{Res: new(types.FindByDatastorePathResponse)}
|
||||
|
||||
for ref, obj := range Map.objects {
|
||||
vm, ok := obj.(*VirtualMachine)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if vm.Config.Files.VmPathName == r.Path {
|
||||
res.Res.Returnval = &ref
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (s *SearchIndex) FindByInventoryPath(req *types.FindByInventoryPath) soap.HasFault {
|
||||
body := &methods.FindByInventoryPathBody{Res: new(types.FindByInventoryPathResponse)}
|
||||
|
||||
path := strings.Split(req.InventoryPath, "/")
|
||||
if len(path) <= 1 {
|
||||
return body
|
||||
}
|
||||
|
||||
root := Map.content().RootFolder
|
||||
o := &root
|
||||
|
||||
for _, name := range path[1:] {
|
||||
f := s.FindChild(&types.FindChild{Entity: *o, Name: name})
|
||||
|
||||
o = f.(*methods.FindChildBody).Res.Returnval
|
||||
if o == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
body.Res.Returnval = o
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (s *SearchIndex) FindChild(req *types.FindChild) soap.HasFault {
|
||||
body := &methods.FindChildBody{}
|
||||
|
||||
obj := Map.Get(req.Entity)
|
||||
|
||||
if obj == nil {
|
||||
body.Fault_ = Fault("", &types.ManagedObjectNotFound{Obj: req.Entity})
|
||||
return body
|
||||
}
|
||||
|
||||
body.Res = new(types.FindChildResponse)
|
||||
|
||||
var children []types.ManagedObjectReference
|
||||
|
||||
switch e := obj.(type) {
|
||||
case *Datacenter:
|
||||
children = []types.ManagedObjectReference{e.VmFolder, e.HostFolder, e.DatastoreFolder, e.NetworkFolder}
|
||||
case *Folder:
|
||||
children = e.ChildEntity
|
||||
case *mo.ComputeResource:
|
||||
children = e.Host
|
||||
children = append(children, *e.ResourcePool)
|
||||
case *ClusterComputeResource:
|
||||
children = e.Host
|
||||
children = append(children, *e.ResourcePool)
|
||||
case *ResourcePool:
|
||||
children = e.ResourcePool.ResourcePool
|
||||
children = append(children, e.Vm...)
|
||||
case *VirtualApp:
|
||||
children = e.ResourcePool.ResourcePool
|
||||
children = append(children, e.Vm...)
|
||||
}
|
||||
|
||||
match := Map.FindByName(req.Name, children)
|
||||
|
||||
if match != nil {
|
||||
ref := match.Reference()
|
||||
body.Res.Returnval = &ref
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (s *SearchIndex) FindByUuid(req *types.FindByUuid) soap.HasFault {
|
||||
body := &methods.FindByUuidBody{Res: new(types.FindByUuidResponse)}
|
||||
|
||||
if req.VmSearch {
|
||||
// Find Virtual Machine using UUID
|
||||
for ref, obj := range Map.objects {
|
||||
vm, ok := obj.(*VirtualMachine)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if vm.Config.Uuid == req.Uuid {
|
||||
body.Res.Returnval = &ref
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Find Host System using UUID
|
||||
for ref, obj := range Map.objects {
|
||||
host, ok := obj.(*HostSystem)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if host.Summary.Hardware.Uuid == req.Uuid {
|
||||
body.Res.Returnval = &ref
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
210
vendor/github.com/vmware/govmomi/simulator/search_index_test.go
generated
vendored
Normal file
210
vendor/github.com/vmware/govmomi/simulator/search_index_test.go
generated
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/find"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestSearchIndex(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
for _, model := range []*Model{ESX(), VPX()} {
|
||||
defer model.Remove()
|
||||
err := model.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := model.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder := find.NewFinder(c.Client, false)
|
||||
dc, err := finder.DefaultDatacenter(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder.SetDatacenter(dc)
|
||||
|
||||
vms, err := finder.VirtualMachineList(ctx, "*")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vm := Map.Get(vms[0].Reference()).(*VirtualMachine)
|
||||
|
||||
si := object.NewSearchIndex(c.Client)
|
||||
|
||||
ref, err := si.FindByDatastorePath(ctx, dc, vm.Config.Files.VmPathName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ref.Reference() != vm.Reference() {
|
||||
t.Errorf("moref mismatch %s != %s", ref, vm.Reference())
|
||||
}
|
||||
|
||||
ref, err = si.FindByDatastorePath(ctx, dc, vm.Config.Files.VmPathName+"enoent")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ref != nil {
|
||||
t.Errorf("ref=%s", ref)
|
||||
}
|
||||
|
||||
ref, err = si.FindByUuid(ctx, dc, vm.Config.Uuid, true, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ref.Reference() != vm.Reference() {
|
||||
t.Errorf("moref mismatch %s != %s", ref, vm.Reference())
|
||||
}
|
||||
|
||||
ref, err = si.FindByUuid(ctx, dc, vm.Config.Uuid, false, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ref != nil {
|
||||
t.Error("expected nil")
|
||||
}
|
||||
|
||||
host := Map.Any("HostSystem").(*HostSystem)
|
||||
|
||||
ref, err = si.FindByUuid(ctx, dc, host.Summary.Hardware.Uuid, false, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ref.Reference() != host.Reference() {
|
||||
t.Errorf("moref mismatch %s != %s", ref, host.Reference())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchIndexFindChild(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
model := VPX()
|
||||
model.Pool = 3
|
||||
|
||||
defer model.Remove()
|
||||
err := model.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := model.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
si := object.NewSearchIndex(c.Client)
|
||||
|
||||
tests := [][]string{
|
||||
// Datacenter -> host Folder -> Cluster -> HostSystem
|
||||
{"DC0", "host", "DC0_C0", "DC0_C0_H0"},
|
||||
// Datacenter -> host Folder -> ComputeResource -> HostSystem
|
||||
{"DC0", "host", "DC0_H0", "DC0_H0"},
|
||||
// Datacenter -> host Folder -> Cluster -> ResourcePool -> ResourcePool
|
||||
{"DC0", "host", "DC0_C0", "Resources", "DC0_C0_RP1"},
|
||||
// Datacenter -> host Folder -> Cluster -> ResourcePool -> VirtualMachine
|
||||
{"DC0", "host", "DC0_C0", "Resources", "DC0_C0_RP0_VM0"},
|
||||
// Datacenter -> vm Folder -> VirtualMachine
|
||||
{"DC0", "vm", "DC0_C0_RP0_VM0"},
|
||||
}
|
||||
|
||||
root := c.ServiceContent.RootFolder
|
||||
|
||||
for _, path := range tests {
|
||||
parent := root
|
||||
ipath := []string{""}
|
||||
|
||||
for _, name := range path {
|
||||
ref, err := si.FindChild(ctx, parent, name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ref == nil {
|
||||
t.Fatalf("failed to match %s using %s", name, parent)
|
||||
}
|
||||
|
||||
parent = ref.Reference()
|
||||
|
||||
ipath = append(ipath, name)
|
||||
|
||||
iref, err := si.FindByInventoryPath(ctx, strings.Join(ipath, "/"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if iref.Reference() != ref.Reference() {
|
||||
t.Errorf("%s != %s", iref, ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ref, err := si.FindChild(ctx, root, "enoent")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ref != nil {
|
||||
t.Error("unexpected match")
|
||||
}
|
||||
|
||||
root.Value = "enoent"
|
||||
_, err = si.FindChild(ctx, root, "enoent")
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
if _, ok := soap.ToSoapFault(err).VimFault().(types.ManagedObjectNotFound); !ok {
|
||||
t.Error("expected ManagedObjectNotFound fault")
|
||||
}
|
||||
|
||||
for _, path := range []string{"", "/", "/enoent"} {
|
||||
ref, err := si.FindByInventoryPath(ctx, path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ref != nil {
|
||||
t.Error("unexpected match")
|
||||
}
|
||||
}
|
||||
}
|
||||
104
vendor/github.com/vmware/govmomi/simulator/service_instance.go
generated
vendored
Normal file
104
vendor/github.com/vmware/govmomi/simulator/service_instance.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/simulator/vpx"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type ServiceInstance struct {
|
||||
mo.ServiceInstance
|
||||
}
|
||||
|
||||
func NewServiceInstance(content types.ServiceContent, folder mo.Folder) *ServiceInstance {
|
||||
Map = NewRegistry()
|
||||
|
||||
s := &ServiceInstance{}
|
||||
|
||||
s.Self = methods.ServiceInstance
|
||||
s.Content = content
|
||||
|
||||
Map.Put(s)
|
||||
|
||||
f := &Folder{Folder: folder}
|
||||
Map.Put(f)
|
||||
|
||||
var setting []types.BaseOptionValue
|
||||
|
||||
if content.About.ApiType == "HostAgent" {
|
||||
CreateDefaultESX(f)
|
||||
} else {
|
||||
setting = vpx.Setting
|
||||
}
|
||||
|
||||
objects := []object.Reference{
|
||||
NewSessionManager(*s.Content.SessionManager),
|
||||
NewAuthorizationManager(*s.Content.AuthorizationManager),
|
||||
NewPerformanceManager(*s.Content.PerfManager),
|
||||
NewPropertyCollector(s.Content.PropertyCollector),
|
||||
NewFileManager(*s.Content.FileManager),
|
||||
NewVirtualDiskManager(*s.Content.VirtualDiskManager),
|
||||
NewLicenseManager(*s.Content.LicenseManager),
|
||||
NewSearchIndex(*s.Content.SearchIndex),
|
||||
NewViewManager(*s.Content.ViewManager),
|
||||
NewEventManager(*s.Content.EventManager),
|
||||
NewTaskManager(*s.Content.TaskManager),
|
||||
NewUserDirectory(*s.Content.UserDirectory),
|
||||
NewOptionManager(s.Content.Setting, setting),
|
||||
}
|
||||
|
||||
if s.Content.CustomFieldsManager != nil {
|
||||
objects = append(objects, NewCustomFieldsManager(*s.Content.CustomFieldsManager))
|
||||
}
|
||||
|
||||
if s.Content.IpPoolManager != nil {
|
||||
objects = append(objects, NewIpPoolManager(*s.Content.IpPoolManager))
|
||||
}
|
||||
|
||||
if s.Content.AccountManager != nil {
|
||||
objects = append(objects, NewHostLocalAccountManager(*s.Content.AccountManager))
|
||||
}
|
||||
|
||||
for _, o := range objects {
|
||||
Map.Put(o)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *ServiceInstance) RetrieveServiceContent(*types.RetrieveServiceContent) soap.HasFault {
|
||||
return &methods.RetrieveServiceContentBody{
|
||||
Res: &types.RetrieveServiceContentResponse{
|
||||
Returnval: s.Content,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (*ServiceInstance) CurrentTime(*types.CurrentTime) soap.HasFault {
|
||||
return &methods.CurrentTimeBody{
|
||||
Res: &types.CurrentTimeResponse{
|
||||
Returnval: time.Now(),
|
||||
},
|
||||
}
|
||||
}
|
||||
277
vendor/github.com/vmware/govmomi/simulator/session_manager.go
generated
vendored
Normal file
277
vendor/github.com/vmware/govmomi/simulator/session_manager.go
generated
vendored
Normal file
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
Copyright (c) 2017-2018 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
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 (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/session"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type SessionManager struct {
|
||||
mo.SessionManager
|
||||
|
||||
ServiceHostName string
|
||||
|
||||
sessions map[string]Session
|
||||
}
|
||||
|
||||
func NewSessionManager(ref types.ManagedObjectReference) object.Reference {
|
||||
s := &SessionManager{
|
||||
sessions: make(map[string]Session),
|
||||
}
|
||||
s.Self = ref
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *SessionManager) Login(ctx *Context, login *types.Login) soap.HasFault {
|
||||
body := &methods.LoginBody{}
|
||||
|
||||
if login.Locale == "" {
|
||||
login.Locale = session.Locale
|
||||
}
|
||||
|
||||
if login.UserName == "" || login.Password == "" || ctx.Session != nil {
|
||||
body.Fault_ = invalidLogin
|
||||
} else {
|
||||
session := Session{
|
||||
UserSession: types.UserSession{
|
||||
Key: uuid.New().String(),
|
||||
UserName: login.UserName,
|
||||
FullName: login.UserName,
|
||||
LoginTime: time.Now(),
|
||||
LastActiveTime: time.Now(),
|
||||
Locale: login.Locale,
|
||||
MessageLocale: login.Locale,
|
||||
},
|
||||
Registry: NewRegistry(),
|
||||
}
|
||||
|
||||
ctx.SetSession(session, true)
|
||||
|
||||
body.Res = &types.LoginResponse{
|
||||
Returnval: session.UserSession,
|
||||
}
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (s *SessionManager) Logout(ctx *Context, _ *types.Logout) soap.HasFault {
|
||||
session := ctx.Session
|
||||
delete(s.sessions, session.Key)
|
||||
|
||||
ctx.postEvent(&types.UserLogoutSessionEvent{
|
||||
IpAddress: session.IpAddress,
|
||||
UserAgent: session.UserAgent,
|
||||
SessionId: session.Key,
|
||||
LoginTime: &session.LoginTime,
|
||||
})
|
||||
|
||||
return &methods.LogoutBody{Res: new(types.LogoutResponse)}
|
||||
}
|
||||
|
||||
func (s *SessionManager) TerminateSession(ctx *Context, req *types.TerminateSession) soap.HasFault {
|
||||
body := new(methods.TerminateSessionBody)
|
||||
|
||||
for _, id := range req.SessionId {
|
||||
if id == ctx.Session.Key {
|
||||
body.Fault_ = Fault("", new(types.InvalidArgument))
|
||||
return body
|
||||
}
|
||||
delete(s.sessions, id)
|
||||
}
|
||||
|
||||
body.Res = new(types.TerminateSessionResponse)
|
||||
return body
|
||||
}
|
||||
|
||||
func (s *SessionManager) AcquireCloneTicket(ctx *Context, _ *types.AcquireCloneTicket) soap.HasFault {
|
||||
session := *ctx.Session
|
||||
session.Key = uuid.New().String()
|
||||
s.sessions[session.Key] = session
|
||||
|
||||
return &methods.AcquireCloneTicketBody{
|
||||
Res: &types.AcquireCloneTicketResponse{
|
||||
Returnval: session.Key,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SessionManager) CloneSession(ctx *Context, ticket *types.CloneSession) soap.HasFault {
|
||||
body := new(methods.CloneSessionBody)
|
||||
|
||||
session, exists := s.sessions[ticket.CloneTicket]
|
||||
|
||||
if exists {
|
||||
delete(s.sessions, ticket.CloneTicket) // A clone ticket can only be used once
|
||||
session.Key = uuid.New().String()
|
||||
ctx.SetSession(session, true)
|
||||
|
||||
body.Res = &types.CloneSessionResponse{
|
||||
Returnval: session.UserSession,
|
||||
}
|
||||
} else {
|
||||
body.Fault_ = invalidLogin
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (s *SessionManager) AcquireGenericServiceTicket(ticket *types.AcquireGenericServiceTicket) soap.HasFault {
|
||||
return &methods.AcquireGenericServiceTicketBody{
|
||||
Res: &types.AcquireGenericServiceTicketResponse{
|
||||
Returnval: types.SessionManagerGenericServiceTicket{
|
||||
Id: uuid.New().String(),
|
||||
HostName: s.ServiceHostName,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// internalContext is the session for use by the in-memory client (Service.RoundTrip)
|
||||
var internalContext = &Context{
|
||||
Context: context.Background(),
|
||||
Session: &Session{
|
||||
UserSession: types.UserSession{
|
||||
Key: uuid.New().String(),
|
||||
},
|
||||
Registry: NewRegistry(),
|
||||
},
|
||||
}
|
||||
|
||||
var invalidLogin = Fault("Login failure", new(types.InvalidLogin))
|
||||
|
||||
// Context provides per-request Session management.
|
||||
type Context struct {
|
||||
req *http.Request
|
||||
res http.ResponseWriter
|
||||
m *SessionManager
|
||||
|
||||
context.Context
|
||||
Session *Session
|
||||
Caller *types.ManagedObjectReference
|
||||
}
|
||||
|
||||
// mapSession maps an HTTP cookie to a Session.
|
||||
func (c *Context) mapSession() {
|
||||
if cookie, err := c.req.Cookie(soap.SessionCookieName); err == nil {
|
||||
if val, ok := c.m.sessions[cookie.Value]; ok {
|
||||
c.SetSession(val, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetSession should be called after successful authentication.
|
||||
func (c *Context) SetSession(session Session, login bool) {
|
||||
session.UserAgent = c.req.UserAgent()
|
||||
session.IpAddress = strings.Split(c.req.RemoteAddr, ":")[0]
|
||||
session.LastActiveTime = time.Now()
|
||||
|
||||
c.m.sessions[session.Key] = session
|
||||
c.Session = &session
|
||||
|
||||
if login {
|
||||
http.SetCookie(c.res, &http.Cookie{
|
||||
Name: soap.SessionCookieName,
|
||||
Value: session.Key,
|
||||
})
|
||||
|
||||
c.postEvent(&types.UserLoginSessionEvent{
|
||||
SessionId: session.Key,
|
||||
IpAddress: session.IpAddress,
|
||||
UserAgent: session.UserAgent,
|
||||
Locale: session.Locale,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WithLock holds a lock for the given object while then given function is run.
|
||||
func (c *Context) WithLock(obj mo.Reference, f func()) {
|
||||
if c.Caller != nil && *c.Caller == obj.Reference() {
|
||||
// Internal method invocation, obj is already locked
|
||||
f()
|
||||
return
|
||||
}
|
||||
Map.WithLock(obj, f)
|
||||
}
|
||||
|
||||
// postEvent wraps EventManager.PostEvent for internal use, with a lock on the EventManager.
|
||||
func (c *Context) postEvent(events ...types.BaseEvent) {
|
||||
m := Map.EventManager()
|
||||
c.WithLock(m, func() {
|
||||
for _, event := range events {
|
||||
m.PostEvent(c, &types.PostEvent{EventToPost: event})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Session combines a UserSession and a Registry for per-session managed objects.
|
||||
type Session struct {
|
||||
types.UserSession
|
||||
*Registry
|
||||
}
|
||||
|
||||
// Put wraps Registry.Put, setting the moref value to include the session key.
|
||||
func (s *Session) Put(item mo.Reference) mo.Reference {
|
||||
ref := item.Reference()
|
||||
if ref.Value == "" {
|
||||
ref.Value = fmt.Sprintf("session[%s]%s", s.Key, uuid.New())
|
||||
}
|
||||
s.Registry.setReference(item, ref)
|
||||
return s.Registry.Put(item)
|
||||
}
|
||||
|
||||
// Get wraps Registry.Get, session-izing singleton objects such as SessionManager and the root PropertyCollector.
|
||||
func (s *Session) Get(ref types.ManagedObjectReference) mo.Reference {
|
||||
obj := s.Registry.Get(ref)
|
||||
if obj != nil {
|
||||
return obj
|
||||
}
|
||||
|
||||
// Return a session "view" of certain singleton objects
|
||||
switch ref.Type {
|
||||
case "SessionManager":
|
||||
// Clone SessionManager so the PropertyCollector can properly report CurrentSession
|
||||
m := *Map.SessionManager()
|
||||
m.CurrentSession = &s.UserSession
|
||||
|
||||
// TODO: we could maintain SessionList as part of the SessionManager singleton
|
||||
for _, session := range m.sessions {
|
||||
m.SessionList = append(m.SessionList, session.UserSession)
|
||||
}
|
||||
|
||||
return &m
|
||||
case "PropertyCollector":
|
||||
if ref == Map.content().PropertyCollector {
|
||||
return s.Put(NewPropertyCollector(ref))
|
||||
}
|
||||
}
|
||||
|
||||
return Map.Get(ref)
|
||||
}
|
||||
186
vendor/github.com/vmware/govmomi/simulator/session_manager_test.go
generated
vendored
Normal file
186
vendor/github.com/vmware/govmomi/simulator/session_manager_test.go
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
Copyright (c) 2017-2018 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
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 (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/property"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func isNotAuthenticated(err error) bool {
|
||||
if soap.IsSoapFault(err) {
|
||||
switch soap.ToSoapFault(err).VimFault().(type) {
|
||||
case types.NotAuthenticated:
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func TestSessionManagerAuth(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
m := VPX()
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
u := s.URL.User
|
||||
s.URL.User = nil // skip Login()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
session, err := c.SessionManager.UserSession(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if session != nil {
|
||||
t.Error("expected nil session")
|
||||
}
|
||||
|
||||
opts := object.NewOptionManager(c.Client, *c.ServiceContent.Setting)
|
||||
var content []types.ObjectContent
|
||||
err = opts.Properties(ctx, opts.Reference(), []string{"setting"}, &content)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(content) != 1 {
|
||||
t.Error("expected content len=1")
|
||||
}
|
||||
|
||||
if len(content[0].PropSet) != 0 {
|
||||
t.Error("non-empty PropSet")
|
||||
}
|
||||
|
||||
if len(content[0].MissingSet) != 1 {
|
||||
t.Error("expected MissingSet len=1")
|
||||
}
|
||||
|
||||
if _, ok := content[0].MissingSet[0].Fault.Fault.(*types.NotAuthenticated); !ok {
|
||||
t.Error("expected NotAuthenticated")
|
||||
}
|
||||
|
||||
_, err = methods.GetCurrentTime(ctx, c)
|
||||
if !isNotAuthenticated(err) {
|
||||
t.Error("expected NotAuthenticated")
|
||||
}
|
||||
|
||||
err = c.SessionManager.Login(ctx, u)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c.UserAgent = "vcsim/x.x"
|
||||
|
||||
session, err = c.SessionManager.UserSession(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if session == nil {
|
||||
t.Error("expected session")
|
||||
}
|
||||
|
||||
if session.UserAgent != c.UserAgent {
|
||||
t.Errorf("UserAgent=%s", session.UserAgent)
|
||||
}
|
||||
|
||||
content = nil
|
||||
err = opts.Properties(ctx, opts.Reference(), []string{"setting"}, &content)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(content) != 1 {
|
||||
t.Error("expected content len=1")
|
||||
}
|
||||
|
||||
if len(content[0].PropSet) != 1 {
|
||||
t.Error("PropSet len=1")
|
||||
}
|
||||
|
||||
if len(content[0].MissingSet) != 0 {
|
||||
t.Error("expected MissingSet len=0")
|
||||
}
|
||||
|
||||
last := session.LastActiveTime
|
||||
|
||||
_, err = methods.GetCurrentTime(ctx, c)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
pc, err := property.DefaultCollector(c.Client).Create(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
session, _ = c.SessionManager.UserSession(ctx)
|
||||
|
||||
if session.LastActiveTime.Equal(last) {
|
||||
t.Error("LastActiveTime was not updated")
|
||||
}
|
||||
|
||||
if !strings.Contains(pc.Reference().Value, session.Key) {
|
||||
t.Errorf("invalid ref=%s", pc.Reference())
|
||||
}
|
||||
|
||||
ticket, err := c.SessionManager.AcquireCloneTicket(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c, err = govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = c.SessionManager.CloneSession(ctx, ticket)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = c.SessionManager.CloneSession(ctx, ticket)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
_, err = methods.GetCurrentTime(ctx, c)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
610
vendor/github.com/vmware/govmomi/simulator/simulator.go
generated
vendored
Normal file
610
vendor/github.com/vmware/govmomi/simulator/simulator.go
generated
vendored
Normal file
@@ -0,0 +1,610 @@
|
||||
/*
|
||||
Copyright (c) 2017-2018 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/govmomi/find"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"github.com/vmware/govmomi/vim25/xml"
|
||||
)
|
||||
|
||||
// Trace when set to true, writes SOAP traffic to stderr
|
||||
var Trace = false
|
||||
|
||||
// Method encapsulates a decoded SOAP client request
|
||||
type Method struct {
|
||||
Name string
|
||||
This types.ManagedObjectReference
|
||||
Body types.AnyType
|
||||
}
|
||||
|
||||
// Service decodes incoming requests and dispatches to a Handler
|
||||
type Service struct {
|
||||
client *vim25.Client
|
||||
sm *SessionManager
|
||||
|
||||
readAll func(io.Reader) ([]byte, error)
|
||||
|
||||
TLS *tls.Config
|
||||
ServeMux *http.ServeMux
|
||||
}
|
||||
|
||||
// Server provides a simulator Service over HTTP
|
||||
type Server struct {
|
||||
*httptest.Server
|
||||
URL *url.URL
|
||||
|
||||
caFile string
|
||||
}
|
||||
|
||||
// New returns an initialized simulator Service instance
|
||||
func New(instance *ServiceInstance) *Service {
|
||||
s := &Service{
|
||||
readAll: ioutil.ReadAll,
|
||||
sm: Map.SessionManager(),
|
||||
}
|
||||
|
||||
s.client, _ = vim25.NewClient(context.Background(), s)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
type serverFaultBody struct {
|
||||
Reason *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
|
||||
}
|
||||
|
||||
func (b *serverFaultBody) Fault() *soap.Fault { return b.Reason }
|
||||
|
||||
func serverFault(msg string) soap.HasFault {
|
||||
return &serverFaultBody{Reason: Fault(msg, &types.InvalidRequest{})}
|
||||
}
|
||||
|
||||
// Fault wraps the given message and fault in a soap.Fault
|
||||
func Fault(msg string, fault types.BaseMethodFault) *soap.Fault {
|
||||
f := &soap.Fault{
|
||||
Code: "ServerFaultCode",
|
||||
String: msg,
|
||||
}
|
||||
|
||||
f.Detail.Fault = fault
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (s *Service) call(ctx *Context, method *Method) soap.HasFault {
|
||||
handler := Map.Get(method.This)
|
||||
session := ctx.Session
|
||||
|
||||
if session == nil {
|
||||
switch method.Name {
|
||||
case "RetrieveServiceContent", "Login", "RetrieveProperties", "RetrievePropertiesEx", "CloneSession":
|
||||
// ok for now, TODO: authz
|
||||
default:
|
||||
fault := &types.NotAuthenticated{
|
||||
NoPermission: types.NoPermission{
|
||||
Object: method.This,
|
||||
PrivilegeId: "System.View",
|
||||
},
|
||||
}
|
||||
return &serverFaultBody{Reason: Fault("", fault)}
|
||||
}
|
||||
} else {
|
||||
// Prefer the Session.Registry, ServiceContent.PropertyCollector filter field for example is per-session
|
||||
if h := session.Get(method.This); h != nil {
|
||||
handler = h
|
||||
}
|
||||
}
|
||||
|
||||
if handler == nil {
|
||||
msg := fmt.Sprintf("managed object not found: %s", method.This)
|
||||
log.Print(msg)
|
||||
fault := &types.ManagedObjectNotFound{Obj: method.This}
|
||||
return &serverFaultBody{Reason: Fault(msg, fault)}
|
||||
}
|
||||
|
||||
name := method.Name
|
||||
|
||||
if strings.HasSuffix(name, vTaskSuffix) {
|
||||
// Make golint happy renaming "Foo_Task" -> "FooTask"
|
||||
name = name[:len(name)-len(vTaskSuffix)] + sTaskSuffix
|
||||
}
|
||||
|
||||
m := reflect.ValueOf(handler).MethodByName(name)
|
||||
if !m.IsValid() {
|
||||
msg := fmt.Sprintf("%s does not implement: %s", method.This, method.Name)
|
||||
log.Print(msg)
|
||||
fault := &types.MethodNotFound{Receiver: method.This, Method: method.Name}
|
||||
return &serverFaultBody{Reason: Fault(msg, fault)}
|
||||
}
|
||||
|
||||
if e, ok := handler.(mo.Entity); ok {
|
||||
for _, dm := range e.Entity().DisabledMethod {
|
||||
if name == dm {
|
||||
msg := fmt.Sprintf("%s method is disabled: %s", method.This, method.Name)
|
||||
fault := &types.MethodDisabled{}
|
||||
return &serverFaultBody{Reason: Fault(msg, fault)}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var args, res []reflect.Value
|
||||
if m.Type().NumIn() == 2 {
|
||||
args = append(args, reflect.ValueOf(ctx))
|
||||
}
|
||||
args = append(args, reflect.ValueOf(method.Body))
|
||||
Map.WithLock(handler, func() {
|
||||
res = m.Call(args)
|
||||
})
|
||||
|
||||
return res[0].Interface().(soap.HasFault)
|
||||
}
|
||||
|
||||
// RoundTrip implements the soap.RoundTripper interface in process.
|
||||
// Rather than encode/decode SOAP over HTTP, this implementation uses reflection.
|
||||
func (s *Service) RoundTrip(ctx context.Context, request, response soap.HasFault) error {
|
||||
field := func(r soap.HasFault, name string) reflect.Value {
|
||||
return reflect.ValueOf(r).Elem().FieldByName(name)
|
||||
}
|
||||
|
||||
// Every struct passed to soap.RoundTrip has "Req" and "Res" fields
|
||||
req := field(request, "Req")
|
||||
|
||||
// Every request has a "This" field.
|
||||
this := req.Elem().FieldByName("This")
|
||||
|
||||
method := &Method{
|
||||
Name: req.Elem().Type().Name(),
|
||||
This: this.Interface().(types.ManagedObjectReference),
|
||||
Body: req.Interface(),
|
||||
}
|
||||
|
||||
res := s.call(&Context{
|
||||
Context: ctx,
|
||||
Session: internalContext.Session,
|
||||
}, method)
|
||||
|
||||
if err := res.Fault(); err != nil {
|
||||
return soap.WrapSoapFault(err)
|
||||
}
|
||||
|
||||
field(response, "Res").Set(field(res, "Res"))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// soapEnvelope is a copy of soap.Envelope, with namespace changed to "soapenv",
|
||||
// and additional namespace attributes required by some client libraries.
|
||||
// Go still has issues decoding with such a namespace, but encoding is ok.
|
||||
type soapEnvelope struct {
|
||||
XMLName xml.Name `xml:"soapenv:Envelope"`
|
||||
Enc string `xml:"xmlns:soapenc,attr"`
|
||||
Env string `xml:"xmlns:soapenv,attr"`
|
||||
XSD string `xml:"xmlns:xsd,attr"`
|
||||
XSI string `xml:"xmlns:xsi,attr"`
|
||||
Body interface{} `xml:"soapenv:Body"`
|
||||
}
|
||||
|
||||
// soapFault is a copy of soap.Fault, with the same changes as soapEnvelope
|
||||
type soapFault struct {
|
||||
XMLName xml.Name `xml:"soapenv:Fault"`
|
||||
Code string `xml:"faultcode"`
|
||||
String string `xml:"faultstring"`
|
||||
Detail struct {
|
||||
Fault types.AnyType `xml:",any,typeattr"`
|
||||
} `xml:"detail"`
|
||||
}
|
||||
|
||||
// About generates some info about the simulator.
|
||||
func (s *Service) About(w http.ResponseWriter, r *http.Request) {
|
||||
var about struct {
|
||||
Methods []string
|
||||
Types []string
|
||||
}
|
||||
|
||||
seen := make(map[string]bool)
|
||||
|
||||
f := reflect.TypeOf((*soap.HasFault)(nil)).Elem()
|
||||
|
||||
for _, obj := range Map.objects {
|
||||
kind := obj.Reference().Type
|
||||
if seen[kind] {
|
||||
continue
|
||||
}
|
||||
seen[kind] = true
|
||||
|
||||
about.Types = append(about.Types, kind)
|
||||
|
||||
t := reflect.TypeOf(obj)
|
||||
for i := 0; i < t.NumMethod(); i++ {
|
||||
m := t.Method(i)
|
||||
if seen[m.Name] {
|
||||
continue
|
||||
}
|
||||
seen[m.Name] = true
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(about.Methods)
|
||||
sort.Strings(about.Types)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetIndent("", " ")
|
||||
_ = enc.Encode(&about)
|
||||
}
|
||||
|
||||
// ServeSDK implements the http.Handler interface
|
||||
func (s *Service) ServeSDK(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
body, err := s.readAll(r.Body)
|
||||
_ = r.Body.Close()
|
||||
if err != nil {
|
||||
log.Printf("error reading body: %s", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if Trace {
|
||||
fmt.Fprintf(os.Stderr, "Request: %s\n", string(body))
|
||||
}
|
||||
|
||||
ctx := &Context{
|
||||
req: r,
|
||||
res: w,
|
||||
m: s.sm,
|
||||
|
||||
Context: context.Background(),
|
||||
}
|
||||
Map.WithLock(s.sm, ctx.mapSession)
|
||||
|
||||
var res soap.HasFault
|
||||
var soapBody interface{}
|
||||
|
||||
method, err := UnmarshalBody(body)
|
||||
if err != nil {
|
||||
res = serverFault(err.Error())
|
||||
} else {
|
||||
res = s.call(ctx, method)
|
||||
}
|
||||
|
||||
if f := res.Fault(); f != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
// the generated method/*Body structs use the '*soap.Fault' type,
|
||||
// so we need our own Body type to use the modified '*soapFault' type.
|
||||
soapBody = struct {
|
||||
Fault *soapFault
|
||||
}{
|
||||
&soapFault{
|
||||
Code: f.Code,
|
||||
String: f.String,
|
||||
Detail: f.Detail,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
soapBody = res
|
||||
}
|
||||
|
||||
var out bytes.Buffer
|
||||
|
||||
fmt.Fprint(&out, xml.Header)
|
||||
e := xml.NewEncoder(&out)
|
||||
err = e.Encode(&soapEnvelope{
|
||||
Enc: "http://schemas.xmlsoap.org/soap/encoding/",
|
||||
Env: "http://schemas.xmlsoap.org/soap/envelope/",
|
||||
XSD: "http://www.w3.org/2001/XMLSchema",
|
||||
XSI: "http://www.w3.org/2001/XMLSchema-instance",
|
||||
Body: soapBody,
|
||||
})
|
||||
if err == nil {
|
||||
err = e.Flush()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Printf("error encoding %s response: %s", method.Name, err)
|
||||
return
|
||||
}
|
||||
|
||||
if Trace {
|
||||
fmt.Fprintf(os.Stderr, "Response: %s\n", out.String())
|
||||
}
|
||||
|
||||
_, _ = w.Write(out.Bytes())
|
||||
}
|
||||
|
||||
func (s *Service) findDatastore(query url.Values) (*Datastore, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
finder := find.NewFinder(s.client, false)
|
||||
dc, err := finder.DatacenterOrDefault(ctx, query.Get("dcName"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
finder.SetDatacenter(dc)
|
||||
|
||||
ds, err := finder.DatastoreOrDefault(ctx, query.Get("dsName"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return Map.Get(ds.Reference()).(*Datastore), nil
|
||||
}
|
||||
|
||||
const folderPrefix = "/folder/"
|
||||
|
||||
// ServeDatastore handler for Datastore access via /folder path.
|
||||
func (s *Service) ServeDatastore(w http.ResponseWriter, r *http.Request) {
|
||||
ds, ferr := s.findDatastore(r.URL.Query())
|
||||
if ferr != nil {
|
||||
log.Printf("failed to locate datastore with query params: %s", r.URL.RawQuery)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
r.URL.Path = strings.TrimPrefix(r.URL.Path, folderPrefix)
|
||||
p := path.Join(ds.Info.GetDatastoreInfo().Url, r.URL.Path)
|
||||
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
_, err := os.Stat(p)
|
||||
if err == nil {
|
||||
// File exists
|
||||
w.WriteHeader(http.StatusConflict)
|
||||
return
|
||||
}
|
||||
|
||||
// File does not exist, fallthrough to create via PUT logic
|
||||
fallthrough
|
||||
case "PUT":
|
||||
f, err := os.Create(p)
|
||||
if err != nil {
|
||||
log.Printf("failed to %s '%s': %s", r.Method, p, err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, _ = io.Copy(f, r.Body)
|
||||
default:
|
||||
fs := http.FileServer(http.Dir(ds.Info.GetDatastoreInfo().Url))
|
||||
|
||||
fs.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// ServiceVersions handler for the /sdk/vimServiceVersions.xml path.
|
||||
func (*Service) ServiceVersions(w http.ResponseWriter, r *http.Request) {
|
||||
// pyvmomi depends on this
|
||||
|
||||
const versions = xml.Header + `<namespaces version="1.0">
|
||||
<namespace>
|
||||
<name>urn:vim25</name>
|
||||
<version>6.5</version>
|
||||
<priorVersions>
|
||||
<version>6.0</version>
|
||||
<version>5.5</version>
|
||||
</priorVersions>
|
||||
</namespace>
|
||||
</namespaces>
|
||||
`
|
||||
fmt.Fprint(w, versions)
|
||||
}
|
||||
|
||||
// NewServer returns an http Server instance for the given service
|
||||
func (s *Service) NewServer() *Server {
|
||||
mux := s.ServeMux
|
||||
if mux == nil {
|
||||
mux = http.NewServeMux()
|
||||
}
|
||||
|
||||
path := "/sdk"
|
||||
|
||||
mux.HandleFunc(path, s.ServeSDK)
|
||||
mux.HandleFunc(path+"/vimServiceVersions.xml", s.ServiceVersions)
|
||||
mux.HandleFunc(folderPrefix, s.ServeDatastore)
|
||||
mux.HandleFunc("/about", s.About)
|
||||
|
||||
// Using NewUnstartedServer() instead of NewServer(),
|
||||
// for use in main.go, where Start() blocks, we can still set ServiceHostName
|
||||
ts := httptest.NewUnstartedServer(mux)
|
||||
|
||||
u := &url.URL{
|
||||
Scheme: "http",
|
||||
Host: ts.Listener.Addr().String(),
|
||||
Path: path,
|
||||
User: url.UserPassword("user", "pass"),
|
||||
}
|
||||
|
||||
// Redirect clients to this http server, rather than HostSystem.Name
|
||||
Map.SessionManager().ServiceHostName = u.Host
|
||||
|
||||
if f := flag.Lookup("httptest.serve"); f != nil {
|
||||
// Avoid the blocking behaviour of httptest.Server.Start() when this flag is set
|
||||
_ = f.Value.Set("")
|
||||
}
|
||||
|
||||
if s.TLS == nil {
|
||||
ts.Start()
|
||||
} else {
|
||||
ts.TLS = s.TLS
|
||||
ts.StartTLS()
|
||||
u.Scheme += "s"
|
||||
}
|
||||
|
||||
return &Server{
|
||||
Server: ts,
|
||||
URL: u,
|
||||
}
|
||||
}
|
||||
|
||||
// Certificate returns the TLS certificate for the Server if started with TLS enabled.
|
||||
// This method will panic if TLS is not enabled for the server.
|
||||
func (s *Server) Certificate() *x509.Certificate {
|
||||
// By default httptest.StartTLS uses http/internal.LocalhostCert, which we can access here:
|
||||
cert, _ := x509.ParseCertificate(s.TLS.Certificates[0].Certificate[0])
|
||||
return cert
|
||||
}
|
||||
|
||||
// CertificateInfo returns Server.Certificate() as object.HostCertificateInfo
|
||||
func (s *Server) CertificateInfo() *object.HostCertificateInfo {
|
||||
info := new(object.HostCertificateInfo)
|
||||
info.FromCertificate(s.Certificate())
|
||||
return info
|
||||
}
|
||||
|
||||
// CertificateFile returns a file name, where the file contains the PEM encoded Server.Certificate.
|
||||
// The temporary file is removed when Server.Close() is called.
|
||||
func (s *Server) CertificateFile() (string, error) {
|
||||
if s.caFile != "" {
|
||||
return s.caFile, nil
|
||||
}
|
||||
|
||||
f, err := ioutil.TempFile("", "vcsim-")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
s.caFile = f.Name()
|
||||
cert := s.Certificate()
|
||||
return s.caFile, pem.Encode(f, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
|
||||
}
|
||||
|
||||
// Close shuts down the server and blocks until all outstanding
|
||||
// requests on this server have completed.
|
||||
func (s *Server) Close() {
|
||||
s.Server.Close()
|
||||
if s.caFile != "" {
|
||||
_ = os.Remove(s.caFile)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
vim25MapType = types.TypeFunc()
|
||||
typeFunc = defaultMapType
|
||||
)
|
||||
|
||||
func defaultMapType(name string) (reflect.Type, bool) {
|
||||
typ, ok := vim25MapType(name)
|
||||
if !ok {
|
||||
// See TestIssue945, in which case Go does not resolve the namespace and name == "ns1:TraversalSpec"
|
||||
// Without this hack, the SelectSet would be all nil's
|
||||
kind := strings.SplitN(name, ":", 2)
|
||||
if len(kind) == 2 {
|
||||
typ, ok = vim25MapType(kind[1])
|
||||
}
|
||||
}
|
||||
return typ, ok
|
||||
}
|
||||
|
||||
// UnmarshalBody extracts the Body from a soap.Envelope and unmarshals to the corresponding govmomi type
|
||||
func UnmarshalBody(data []byte) (*Method, error) {
|
||||
body := struct {
|
||||
Content string `xml:",innerxml"`
|
||||
}{}
|
||||
|
||||
req := soap.Envelope{
|
||||
Body: &body,
|
||||
}
|
||||
|
||||
err := xml.Unmarshal(data, &req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("xml.Unmarshal: %s", err)
|
||||
}
|
||||
|
||||
decoder := xml.NewDecoder(bytes.NewReader([]byte(body.Content)))
|
||||
decoder.TypeFunc = typeFunc // required to decode interface types
|
||||
|
||||
var start *xml.StartElement
|
||||
|
||||
for {
|
||||
tok, derr := decoder.Token()
|
||||
if derr != nil {
|
||||
return nil, fmt.Errorf("decoding body: %s", err)
|
||||
}
|
||||
if t, ok := tok.(xml.StartElement); ok {
|
||||
start = &t
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
kind := start.Name.Local
|
||||
|
||||
rtype, ok := typeFunc(kind)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no vmomi type defined for '%s'", kind)
|
||||
}
|
||||
|
||||
var val interface{}
|
||||
if rtype != nil {
|
||||
val = reflect.New(rtype).Interface()
|
||||
}
|
||||
|
||||
err = decoder.DecodeElement(val, start)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decoding %s: %s", kind, err)
|
||||
}
|
||||
|
||||
method := &Method{Name: kind, Body: val}
|
||||
|
||||
field := reflect.ValueOf(val).Elem().FieldByName("This")
|
||||
|
||||
method.This = field.Interface().(types.ManagedObjectReference)
|
||||
|
||||
return method, nil
|
||||
}
|
||||
496
vendor/github.com/vmware/govmomi/simulator/simulator_test.go
generated
vendored
Normal file
496
vendor/github.com/vmware/govmomi/simulator/simulator_test.go
generated
vendored
Normal file
@@ -0,0 +1,496 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/simulator/vpx"
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestUnmarshal(t *testing.T) {
|
||||
requests := []struct {
|
||||
body interface{}
|
||||
data string
|
||||
}{
|
||||
{
|
||||
&types.RetrieveServiceContent{
|
||||
This: types.ManagedObjectReference{
|
||||
Type: "ServiceInstance", Value: "ServiceInstance",
|
||||
},
|
||||
},
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<Body>
|
||||
<RetrieveServiceContent xmlns="urn:vim25">
|
||||
<_this type="ServiceInstance">ServiceInstance</_this>
|
||||
</RetrieveServiceContent>
|
||||
</Body>
|
||||
</Envelope>`,
|
||||
},
|
||||
{
|
||||
&types.Login{
|
||||
This: types.ManagedObjectReference{
|
||||
Type: "SessionManager",
|
||||
Value: "SessionManager",
|
||||
},
|
||||
UserName: "root",
|
||||
Password: "secret",
|
||||
},
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<Body>
|
||||
<Login xmlns="urn:vim25">
|
||||
<_this type="SessionManager">SessionManager</_this>
|
||||
<userName>root</userName>
|
||||
<password>secret</password>
|
||||
</Login>
|
||||
</Body>
|
||||
</Envelope>`,
|
||||
},
|
||||
{
|
||||
&types.RetrieveProperties{
|
||||
This: types.ManagedObjectReference{Type: "PropertyCollector", Value: "ha-property-collector"},
|
||||
SpecSet: []types.PropertyFilterSpec{
|
||||
{
|
||||
DynamicData: types.DynamicData{},
|
||||
PropSet: []types.PropertySpec{
|
||||
{
|
||||
DynamicData: types.DynamicData{},
|
||||
Type: "ManagedEntity",
|
||||
All: (*bool)(nil),
|
||||
PathSet: []string{"name", "parent"},
|
||||
},
|
||||
},
|
||||
ObjectSet: []types.ObjectSpec{
|
||||
{
|
||||
DynamicData: types.DynamicData{},
|
||||
Obj: types.ManagedObjectReference{Type: "Folder", Value: "ha-folder-root"},
|
||||
Skip: types.NewBool(false),
|
||||
SelectSet: []types.BaseSelectionSpec{ // test decode of interface
|
||||
&types.TraversalSpec{
|
||||
SelectionSpec: types.SelectionSpec{
|
||||
DynamicData: types.DynamicData{},
|
||||
Name: "traverseParent",
|
||||
},
|
||||
Type: "ManagedEntity",
|
||||
Path: "parent",
|
||||
Skip: types.NewBool(false),
|
||||
SelectSet: []types.BaseSelectionSpec{
|
||||
&types.SelectionSpec{
|
||||
DynamicData: types.DynamicData{},
|
||||
Name: "traverseParent",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ReportMissingObjectsInResults: (*bool)(nil),
|
||||
},
|
||||
}},
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<Body>
|
||||
<RetrieveProperties xmlns="urn:vim25">
|
||||
<_this type="PropertyCollector">ha-property-collector</_this>
|
||||
<specSet>
|
||||
<propSet>
|
||||
<type>ManagedEntity</type>
|
||||
<pathSet>name</pathSet>
|
||||
<pathSet>parent</pathSet>
|
||||
</propSet>
|
||||
<objectSet>
|
||||
<obj type="Folder">ha-folder-root</obj>
|
||||
<skip>false</skip>
|
||||
<selectSet xmlns:XMLSchema-instance="http://www.w3.org/2001/XMLSchema-instance" XMLSchema-instance:type="TraversalSpec">
|
||||
<name>traverseParent</name>
|
||||
<type>ManagedEntity</type>
|
||||
<path>parent</path>
|
||||
<skip>false</skip>
|
||||
<selectSet XMLSchema-instance:type="SelectionSpec">
|
||||
<name>traverseParent</name>
|
||||
</selectSet>
|
||||
</selectSet>
|
||||
</objectSet>
|
||||
</specSet>
|
||||
</RetrieveProperties>
|
||||
</Body>
|
||||
</Envelope>`,
|
||||
},
|
||||
}
|
||||
|
||||
for i, req := range requests {
|
||||
method, err := UnmarshalBody([]byte(req.data))
|
||||
if err != nil {
|
||||
t.Errorf("failed to decode %d (%s): %s", i, req, err)
|
||||
}
|
||||
if !reflect.DeepEqual(method.Body, req.body) {
|
||||
t.Errorf("malformed body %d (%#v):", i, method.Body)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalError(t *testing.T) {
|
||||
requests := []string{
|
||||
"", // io.EOF
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<Body>
|
||||
</MissingEndTag
|
||||
</Envelope>`,
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<Body>
|
||||
<UnknownType xmlns="urn:vim25">
|
||||
<_this type="ServiceInstance">ServiceInstance</_this>
|
||||
</UnknownType>
|
||||
</Body>
|
||||
</Envelope>`,
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<Body>
|
||||
<!-- no start tag -->
|
||||
</Body>
|
||||
</Envelope>`,
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<Body>
|
||||
<RetrieveServiceContent xmlns="urn:vim25">
|
||||
<_this type="ServiceInstance">ServiceInstance</_this>
|
||||
</RetrieveServiceContent>
|
||||
</Body>
|
||||
</Envelope>`,
|
||||
}
|
||||
|
||||
defer func() {
|
||||
typeFunc = defaultMapType // reset
|
||||
}()
|
||||
|
||||
ttypes := map[string]reflect.Type{
|
||||
// triggers xml.Decoder.DecodeElement error
|
||||
"RetrieveServiceContent": reflect.TypeOf(nil),
|
||||
}
|
||||
typeFunc = func(name string) (reflect.Type, bool) {
|
||||
typ, ok := ttypes[name]
|
||||
return typ, ok
|
||||
}
|
||||
|
||||
for i, data := range requests {
|
||||
_, err := UnmarshalBody([]byte(data))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
t.Errorf("expected %d (%s) to return an error", i, data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeHTTP(t *testing.T) {
|
||||
configs := []struct {
|
||||
content types.ServiceContent
|
||||
folder mo.Folder
|
||||
}{
|
||||
{esx.ServiceContent, esx.RootFolder},
|
||||
{vpx.ServiceContent, vpx.RootFolder},
|
||||
}
|
||||
|
||||
for _, config := range configs {
|
||||
s := New(NewServiceInstance(config.content, config.folder))
|
||||
ts := s.NewServer()
|
||||
defer ts.Close()
|
||||
|
||||
u := ts.URL.User
|
||||
ts.URL.User = nil
|
||||
|
||||
ctx := context.Background()
|
||||
client, err := govmomi.NewClient(ctx, ts.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = client.Login(ctx, nil)
|
||||
if err == nil {
|
||||
t.Fatal("expected invalid login error")
|
||||
}
|
||||
|
||||
err = client.Login(ctx, u)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Testing http client + reflect client
|
||||
clients := []soap.RoundTripper{client, s.client}
|
||||
for _, c := range clients {
|
||||
now, err := methods.GetCurrentTime(ctx, c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if now.After(time.Now()) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
// test the fail/Fault path
|
||||
_, err = methods.QueryVMotionCompatibility(ctx, c, &types.QueryVMotionCompatibility{})
|
||||
if err == nil {
|
||||
t.Errorf("expected error")
|
||||
}
|
||||
}
|
||||
|
||||
err = client.Logout(ctx)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeAbout(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
m := VPX()
|
||||
m.App = 1
|
||||
m.Pod = 1
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
u := *s.URL
|
||||
u.Path += "/vimServiceVersions.xml"
|
||||
r, err := c.Get(u.String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_ = r.Body.Close()
|
||||
|
||||
u.Path = "/about"
|
||||
r, err = c.Get(u.String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_ = r.Body.Close()
|
||||
}
|
||||
|
||||
func TestServeHTTPS(t *testing.T) {
|
||||
s := New(NewServiceInstance(esx.ServiceContent, esx.RootFolder))
|
||||
s.TLS = new(tls.Config)
|
||||
ts := s.NewServer()
|
||||
defer ts.Close()
|
||||
|
||||
ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0) // silence benign "TLS handshake error" log messages
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// insecure=true OK
|
||||
_, err := govmomi.NewClient(ctx, ts.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// insecure=false should FAIL
|
||||
_, err = govmomi.NewClient(ctx, ts.URL, false)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
|
||||
uerr, ok := err.(*url.Error)
|
||||
if !ok {
|
||||
t.Fatalf("err type=%T", err)
|
||||
}
|
||||
|
||||
_, ok = uerr.Err.(x509.UnknownAuthorityError)
|
||||
if !ok {
|
||||
t.Fatalf("err type=%T", uerr.Err)
|
||||
}
|
||||
|
||||
sinfo := ts.CertificateInfo()
|
||||
|
||||
// Test thumbprint validation
|
||||
sc := soap.NewClient(ts.URL, false)
|
||||
// Add host with thumbprint mismatch should fail
|
||||
sc.SetThumbprint(ts.URL.Host, "nope")
|
||||
_, err = vim25.NewClient(ctx, sc)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
// Add host with thumbprint match should pass
|
||||
sc.SetThumbprint(ts.URL.Host, sinfo.ThumbprintSHA1)
|
||||
_, err = vim25.NewClient(ctx, sc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var pinfo object.HostCertificateInfo
|
||||
err = pinfo.FromURL(ts.URL, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pinfo.ThumbprintSHA1 != sinfo.ThumbprintSHA1 {
|
||||
t.Error("thumbprint mismatch")
|
||||
}
|
||||
|
||||
// Test custom RootCAs list
|
||||
sc = soap.NewClient(ts.URL, false)
|
||||
caFile, err := ts.CertificateFile()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = sc.SetRootCAs(caFile); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = vim25.NewClient(ctx, sc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
type errorMarshal struct {
|
||||
mo.ServiceInstance
|
||||
}
|
||||
|
||||
func (*errorMarshal) Fault() *soap.Fault {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*errorMarshal) MarshalText() ([]byte, error) {
|
||||
return nil, errors.New("time has stopped")
|
||||
}
|
||||
|
||||
func (h *errorMarshal) CurrentTime(types.AnyType) soap.HasFault {
|
||||
return h
|
||||
}
|
||||
|
||||
type errorNoSuchMethod struct {
|
||||
mo.ServiceInstance
|
||||
}
|
||||
|
||||
func TestServeHTTPErrors(t *testing.T) {
|
||||
s := New(NewServiceInstance(esx.ServiceContent, esx.RootFolder))
|
||||
|
||||
ts := s.NewServer()
|
||||
defer ts.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
client, err := govmomi.NewClient(ctx, ts.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// test response to unimplemented method
|
||||
req := &types.QueryMemoryOverhead{This: esx.HostSystem.Reference()}
|
||||
_, err = methods.QueryMemoryOverhead(ctx, client.Client, req)
|
||||
if _, ok := soap.ToSoapFault(err).VimFault().(types.MethodNotFound); !ok {
|
||||
t.Error("expected MethodNotFound fault")
|
||||
}
|
||||
|
||||
// unregister type, covering the ServeHTTP UnmarshalBody error path
|
||||
typeFunc = func(name string) (reflect.Type, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
_, err = methods.GetCurrentTime(ctx, client)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
typeFunc = types.TypeFunc() // reset
|
||||
|
||||
// cover the does not implement method error path
|
||||
Map.objects[methods.ServiceInstance] = &errorNoSuchMethod{}
|
||||
_, err = methods.GetCurrentTime(ctx, client)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
// cover the xml encode error path
|
||||
Map.objects[methods.ServiceInstance] = &errorMarshal{}
|
||||
_, err = methods.GetCurrentTime(ctx, client)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
// cover the no such object path
|
||||
Map.Remove(methods.ServiceInstance)
|
||||
_, err = methods.GetCurrentTime(ctx, client)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
// verify we properly marshal the fault
|
||||
fault := soap.ToSoapFault(err).VimFault()
|
||||
f, ok := fault.(types.ManagedObjectNotFound)
|
||||
if !ok {
|
||||
t.Fatalf("fault=%#v", fault)
|
||||
}
|
||||
if f.Obj != methods.ServiceInstance {
|
||||
t.Errorf("obj=%#v", f.Obj)
|
||||
}
|
||||
|
||||
// cover the method not supported path
|
||||
res, err := http.Get(ts.URL.String())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if res.StatusCode != http.StatusMethodNotAllowed {
|
||||
t.Errorf("expected status %d, got %s", http.StatusMethodNotAllowed, res.Status)
|
||||
}
|
||||
|
||||
// cover the ioutil.ReadAll error path
|
||||
s.readAll = func(io.Reader) ([]byte, error) {
|
||||
return nil, io.ErrShortBuffer
|
||||
}
|
||||
res, err = http.Post(ts.URL.String(), "none", nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if res.StatusCode != http.StatusBadRequest {
|
||||
t.Errorf("expected status %d, got %s", http.StatusBadRequest, res.Status)
|
||||
}
|
||||
}
|
||||
68
vendor/github.com/vmware/govmomi/simulator/snapshot.go
generated
vendored
Normal file
68
vendor/github.com/vmware/govmomi/simulator/snapshot.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type VirtualMachineSnapshot struct {
|
||||
mo.VirtualMachineSnapshot
|
||||
}
|
||||
|
||||
func (v *VirtualMachineSnapshot) RemoveSnapshotTask(req *types.RemoveSnapshot_Task) soap.HasFault {
|
||||
task := CreateTask(v, "removeSnapshot", func(t *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
Map.Remove(req.This)
|
||||
|
||||
vm := Map.Get(v.Vm).(*VirtualMachine)
|
||||
Map.WithLock(vm, func() {
|
||||
if vm.Snapshot.CurrentSnapshot != nil && *vm.Snapshot.CurrentSnapshot == req.This {
|
||||
parent := findParentSnapshotInTree(vm.Snapshot.RootSnapshotList, req.This)
|
||||
vm.Snapshot.CurrentSnapshot = parent
|
||||
}
|
||||
|
||||
vm.Snapshot.RootSnapshotList = removeSnapshotInTree(vm.Snapshot.RootSnapshotList, req.This, req.RemoveChildren)
|
||||
})
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.RemoveSnapshot_TaskBody{
|
||||
Res: &types.RemoveSnapshot_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (v *VirtualMachineSnapshot) RevertToSnapshotTask(req *types.RevertToSnapshot_Task) soap.HasFault {
|
||||
task := CreateTask(v, "revertToSnapshot", func(t *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
vm := Map.Get(v.Vm).(*VirtualMachine)
|
||||
|
||||
Map.WithLock(vm, func() { vm.Snapshot.CurrentSnapshot = &v.Self })
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.RevertToSnapshot_TaskBody{
|
||||
Res: &types.RevertToSnapshot_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
102
vendor/github.com/vmware/govmomi/simulator/task.go
generated
vendored
Normal file
102
vendor/github.com/vmware/govmomi/simulator/task.go
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
const vTaskSuffix = "_Task" // vmomi suffix
|
||||
const sTaskSuffix = "Task" // simulator suffix (avoiding golint warning)
|
||||
|
||||
type Task struct {
|
||||
mo.Task
|
||||
|
||||
Execute func(*Task) (types.AnyType, types.BaseMethodFault)
|
||||
}
|
||||
|
||||
func NewTask(runner TaskRunner) *Task {
|
||||
ref := runner.Reference()
|
||||
name := reflect.TypeOf(runner).Elem().Name()
|
||||
name = strings.Replace(name, "VM", "Vm", 1) // "VM" for the type to make go-lint happy, but "Vm" for the vmodl ID
|
||||
return CreateTask(ref, name, runner.Run)
|
||||
}
|
||||
|
||||
func CreateTask(e mo.Reference, name string, run func(*Task) (types.AnyType, types.BaseMethodFault)) *Task {
|
||||
ref := e.Reference()
|
||||
id := name
|
||||
|
||||
if strings.HasSuffix(id, sTaskSuffix) {
|
||||
id = id[:len(id)-len(sTaskSuffix)]
|
||||
name = id + vTaskSuffix
|
||||
}
|
||||
|
||||
task := &Task{
|
||||
Execute: run,
|
||||
}
|
||||
|
||||
Map.Put(task)
|
||||
|
||||
task.Info.Key = task.Self.Value
|
||||
task.Info.Task = task.Self
|
||||
task.Info.Name = ucFirst(name)
|
||||
task.Info.DescriptionId = fmt.Sprintf("%s.%s", ref.Type, id)
|
||||
task.Info.Entity = &ref
|
||||
task.Info.EntityName = ref.Value
|
||||
|
||||
task.Info.QueueTime = time.Now()
|
||||
task.Info.State = types.TaskInfoStateQueued
|
||||
|
||||
return task
|
||||
}
|
||||
|
||||
type TaskRunner interface {
|
||||
mo.Reference
|
||||
|
||||
Run(*Task) (types.AnyType, types.BaseMethodFault)
|
||||
}
|
||||
|
||||
func (t *Task) Run() types.ManagedObjectReference {
|
||||
now := time.Now()
|
||||
t.Info.StartTime = &now
|
||||
|
||||
t.Info.State = types.TaskInfoStateRunning
|
||||
|
||||
res, err := t.Execute(t)
|
||||
|
||||
now = time.Now()
|
||||
t.Info.CompleteTime = &now
|
||||
|
||||
if err != nil {
|
||||
t.Info.State = types.TaskInfoStateError
|
||||
t.Info.Error = &types.LocalizedMethodFault{
|
||||
Fault: err,
|
||||
LocalizedMessage: fmt.Sprintf("%T", err),
|
||||
}
|
||||
} else {
|
||||
t.Info.Result = res
|
||||
t.Info.State = types.TaskInfoStateSuccess
|
||||
}
|
||||
|
||||
return t.Self
|
||||
}
|
||||
52
vendor/github.com/vmware/govmomi/simulator/task_manager.go
generated
vendored
Normal file
52
vendor/github.com/vmware/govmomi/simulator/task_manager.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
var recentTaskMax = 200 // the VC limit
|
||||
|
||||
type TaskManager struct {
|
||||
mo.TaskManager
|
||||
}
|
||||
|
||||
func NewTaskManager(ref types.ManagedObjectReference) object.Reference {
|
||||
s := &TaskManager{}
|
||||
s.Self = ref
|
||||
Map.AddHandler(s)
|
||||
return s
|
||||
}
|
||||
|
||||
func (m *TaskManager) PutObject(obj mo.Reference) {
|
||||
ref := obj.Reference()
|
||||
if ref.Type != "Task" {
|
||||
return
|
||||
}
|
||||
|
||||
m.RecentTask = append(m.RecentTask, ref)
|
||||
|
||||
if len(m.RecentTask) > recentTaskMax {
|
||||
m.RecentTask = m.RecentTask[1:]
|
||||
}
|
||||
}
|
||||
|
||||
func (m *TaskManager) RemoveObject(_ types.ManagedObjectReference) {
|
||||
}
|
||||
47
vendor/github.com/vmware/govmomi/simulator/task_manager_test.go
generated
vendored
Normal file
47
vendor/github.com/vmware/govmomi/simulator/task_manager_test.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
)
|
||||
|
||||
func TestTaskManagerRecent(t *testing.T) {
|
||||
m := ESX()
|
||||
m.Datastore = 0
|
||||
m.Machine = 0
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
recentTaskMax = 5
|
||||
|
||||
tm := Map.Get(*esx.ServiceContent.TaskManager).(*TaskManager)
|
||||
tm.RecentTask = nil
|
||||
|
||||
for i := 0; i < recentTaskMax+2; i++ {
|
||||
CreateTask(esx.RootFolder, "noop", nil)
|
||||
|
||||
if len(tm.RecentTask) > recentTaskMax {
|
||||
t.Errorf("too many tasks %d > %d", len(tm.RecentTask), recentTaskMax)
|
||||
}
|
||||
}
|
||||
}
|
||||
65
vendor/github.com/vmware/govmomi/simulator/task_test.go
generated
vendored
Normal file
65
vendor/github.com/vmware/govmomi/simulator/task_test.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type addWaterTask struct {
|
||||
*mo.Folder
|
||||
|
||||
fault types.BaseMethodFault
|
||||
}
|
||||
|
||||
func (a *addWaterTask) Run(task *Task) (types.AnyType, types.BaseMethodFault) {
|
||||
return nil, a.fault
|
||||
}
|
||||
|
||||
func TestNewTask(t *testing.T) {
|
||||
f := &mo.Folder{}
|
||||
Map.NewEntity(f)
|
||||
|
||||
add := &addWaterTask{f, nil}
|
||||
task := NewTask(add)
|
||||
info := &task.Info
|
||||
|
||||
if info.Name != "AddWater_Task" {
|
||||
t.Errorf("name=%s", info.Name)
|
||||
}
|
||||
|
||||
if info.DescriptionId != "Folder.addWater" {
|
||||
t.Errorf("descriptionId=%s", info.DescriptionId)
|
||||
}
|
||||
|
||||
task.Run()
|
||||
|
||||
if info.State != types.TaskInfoStateSuccess {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
add.fault = &types.ManagedObjectNotFound{}
|
||||
|
||||
task.Run()
|
||||
|
||||
if info.State != types.TaskInfoStateError {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
110
vendor/github.com/vmware/govmomi/simulator/user_directory.go
generated
vendored
Normal file
110
vendor/github.com/vmware/govmomi/simulator/user_directory.go
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
var DefaultUserGroup = []*types.UserSearchResult{
|
||||
{FullName: "root", Group: true, Principal: "root"},
|
||||
{FullName: "root", Group: false, Principal: "root"},
|
||||
{FullName: "administrator", Group: false, Principal: "admin"},
|
||||
}
|
||||
|
||||
type UserDirectory struct {
|
||||
mo.UserDirectory
|
||||
|
||||
userGroup []*types.UserSearchResult
|
||||
}
|
||||
|
||||
func NewUserDirectory(ref types.ManagedObjectReference) object.Reference {
|
||||
u := &UserDirectory{}
|
||||
|
||||
u.Self = ref
|
||||
u.userGroup = DefaultUserGroup
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
func (u *UserDirectory) RetrieveUserGroups(req *types.RetrieveUserGroups) soap.HasFault {
|
||||
compare := compareFunc(req.SearchStr, req.ExactMatch)
|
||||
|
||||
res := u.search(req.FindUsers, req.FindGroups, compare)
|
||||
|
||||
body := &methods.RetrieveUserGroupsBody{
|
||||
Res: &types.RetrieveUserGroupsResponse{
|
||||
Returnval: res,
|
||||
},
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func (u *UserDirectory) search(findUsers, findGroups bool, compare func(string) bool) (res []types.BaseUserSearchResult) {
|
||||
for _, ug := range u.userGroup {
|
||||
if findUsers && !ug.Group || findGroups && ug.Group {
|
||||
if compare(ug.Principal) {
|
||||
res = append(res, ug)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (u *UserDirectory) addUser(id string) {
|
||||
u.add(id, false)
|
||||
}
|
||||
|
||||
func (u *UserDirectory) removeUser(id string) {
|
||||
u.remove(id, false)
|
||||
}
|
||||
|
||||
func (u *UserDirectory) add(id string, group bool) {
|
||||
user := &types.UserSearchResult{
|
||||
FullName: id,
|
||||
Group: group,
|
||||
Principal: id,
|
||||
}
|
||||
|
||||
u.userGroup = append(u.userGroup, user)
|
||||
}
|
||||
|
||||
func (u *UserDirectory) remove(id string, group bool) {
|
||||
for i, ug := range u.userGroup {
|
||||
if ug.Group == group && ug.Principal == id {
|
||||
u.userGroup = append(u.userGroup[:i], u.userGroup[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func compareFunc(compared string, exactly bool) func(string) bool {
|
||||
return func(s string) bool {
|
||||
if exactly {
|
||||
return s == compared
|
||||
}
|
||||
return strings.Contains(strings.ToLower(s), strings.ToLower(compared))
|
||||
}
|
||||
}
|
||||
140
vendor/github.com/vmware/govmomi/simulator/user_directory_test.go
generated
vendored
Normal file
140
vendor/github.com/vmware/govmomi/simulator/user_directory_test.go
generated
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestUserDirectory(t *testing.T) {
|
||||
s := New(NewServiceInstance(esx.ServiceContent, esx.RootFolder))
|
||||
|
||||
ts := s.NewServer()
|
||||
defer ts.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, ts.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
findUsers bool
|
||||
findGroups bool
|
||||
}{
|
||||
{true, true},
|
||||
{true, false},
|
||||
{false, true},
|
||||
{false, false},
|
||||
}
|
||||
|
||||
ref := *c.ServiceContent.UserDirectory
|
||||
|
||||
for _, test := range tests {
|
||||
req := types.RetrieveUserGroups{
|
||||
This: ref,
|
||||
SearchStr: "root",
|
||||
ExactMatch: true,
|
||||
FindUsers: test.findUsers,
|
||||
FindGroups: test.findGroups,
|
||||
}
|
||||
|
||||
result, err := methods.RetrieveUserGroups(ctx, c.Client, &req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedSize := 0
|
||||
if test.findGroups {
|
||||
expectedSize++
|
||||
}
|
||||
if test.findUsers {
|
||||
expectedSize++
|
||||
}
|
||||
|
||||
if len(result.Returnval) != expectedSize {
|
||||
t.Fatalf("expect search result for root is %d; got %d", expectedSize, len(result.Returnval))
|
||||
}
|
||||
|
||||
for _, u := range result.Returnval {
|
||||
if u.GetUserSearchResult().Principal != "root" {
|
||||
t.Fatalf("expect principal to be root; got %s", u.GetUserSearchResult().Principal)
|
||||
}
|
||||
if !test.findGroups && u.GetUserSearchResult().Group {
|
||||
t.Fatal("expect search result is non-group; got group")
|
||||
}
|
||||
if !test.findUsers && !u.GetUserSearchResult().Group {
|
||||
t.Fatal("expect search result is non-user; got user")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserDirectoryExactlyMatch(t *testing.T) {
|
||||
s := New(NewServiceInstance(esx.ServiceContent, esx.RootFolder))
|
||||
|
||||
ts := s.NewServer()
|
||||
defer ts.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, ts.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
exactly bool
|
||||
search string
|
||||
expectedSize int
|
||||
}{
|
||||
{true, "root", 2},
|
||||
{false, "ROO", 2},
|
||||
}
|
||||
|
||||
ref := *c.ServiceContent.UserDirectory
|
||||
|
||||
for _, test := range tests {
|
||||
req := types.RetrieveUserGroups{
|
||||
This: ref,
|
||||
SearchStr: test.search,
|
||||
ExactMatch: test.exactly,
|
||||
FindUsers: true,
|
||||
FindGroups: true,
|
||||
}
|
||||
|
||||
result, err := methods.RetrieveUserGroups(ctx, c.Client, &req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(result.Returnval) != test.expectedSize {
|
||||
t.Fatalf("expect result contains %d results; got %d", test.expectedSize, len(result.Returnval))
|
||||
}
|
||||
}
|
||||
}
|
||||
194
vendor/github.com/vmware/govmomi/simulator/view_manager.go
generated
vendored
Normal file
194
vendor/github.com/vmware/govmomi/simulator/view_manager.go
generated
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type ViewManager struct {
|
||||
mo.ViewManager
|
||||
|
||||
entities map[string]bool
|
||||
}
|
||||
|
||||
var entities = []struct {
|
||||
Type reflect.Type
|
||||
Container bool
|
||||
}{
|
||||
{reflect.TypeOf((*mo.ManagedEntity)(nil)).Elem(), true},
|
||||
{reflect.TypeOf((*mo.Folder)(nil)).Elem(), true},
|
||||
{reflect.TypeOf((*mo.StoragePod)(nil)).Elem(), true},
|
||||
{reflect.TypeOf((*mo.Datacenter)(nil)).Elem(), true},
|
||||
{reflect.TypeOf((*mo.ComputeResource)(nil)).Elem(), true},
|
||||
{reflect.TypeOf((*mo.ClusterComputeResource)(nil)).Elem(), true},
|
||||
{reflect.TypeOf((*mo.HostSystem)(nil)).Elem(), true},
|
||||
{reflect.TypeOf((*mo.ResourcePool)(nil)).Elem(), true},
|
||||
{reflect.TypeOf((*mo.VirtualApp)(nil)).Elem(), true},
|
||||
{reflect.TypeOf((*mo.VirtualMachine)(nil)).Elem(), false},
|
||||
{reflect.TypeOf((*mo.Datastore)(nil)).Elem(), false},
|
||||
{reflect.TypeOf((*mo.Network)(nil)).Elem(), false},
|
||||
{reflect.TypeOf((*mo.OpaqueNetwork)(nil)).Elem(), false},
|
||||
{reflect.TypeOf((*mo.DistributedVirtualPortgroup)(nil)).Elem(), false},
|
||||
{reflect.TypeOf((*mo.DistributedVirtualSwitch)(nil)).Elem(), false},
|
||||
{reflect.TypeOf((*mo.VmwareDistributedVirtualSwitch)(nil)).Elem(), false},
|
||||
}
|
||||
|
||||
func NewViewManager(ref types.ManagedObjectReference) object.Reference {
|
||||
s := &ViewManager{
|
||||
entities: make(map[string]bool),
|
||||
}
|
||||
|
||||
s.Self = ref
|
||||
|
||||
for _, e := range entities {
|
||||
s.entities[e.Type.Name()] = e.Container
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func destroyView(ref types.ManagedObjectReference) soap.HasFault {
|
||||
m := Map.ViewManager()
|
||||
|
||||
RemoveReference(&m.ViewList, ref)
|
||||
|
||||
return &methods.DestroyViewBody{
|
||||
Res: &types.DestroyViewResponse{},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *ViewManager) CreateContainerView(ctx *Context, req *types.CreateContainerView) soap.HasFault {
|
||||
body := &methods.CreateContainerViewBody{}
|
||||
|
||||
root := Map.Get(req.Container)
|
||||
if root == nil {
|
||||
body.Fault_ = Fault("", &types.ManagedObjectNotFound{Obj: req.Container})
|
||||
return body
|
||||
}
|
||||
|
||||
if m.entities[root.Reference().Type] != true {
|
||||
body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "container"})
|
||||
return body
|
||||
}
|
||||
|
||||
container := &ContainerView{
|
||||
mo.ContainerView{
|
||||
Container: root.Reference(),
|
||||
Recursive: req.Recursive,
|
||||
Type: req.Type,
|
||||
},
|
||||
make(map[string]bool),
|
||||
}
|
||||
|
||||
for _, ctype := range container.Type {
|
||||
if _, ok := m.entities[ctype]; !ok {
|
||||
body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "type"})
|
||||
return body
|
||||
}
|
||||
|
||||
container.types[ctype] = true
|
||||
|
||||
for _, e := range entities {
|
||||
// Check for embedded types
|
||||
if f, ok := e.Type.FieldByName(ctype); ok && f.Anonymous {
|
||||
container.types[e.Type.Name()] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Session.Put(container)
|
||||
|
||||
m.ViewList = append(m.ViewList, container.Reference())
|
||||
|
||||
body.Res = &types.CreateContainerViewResponse{
|
||||
Returnval: container.Self,
|
||||
}
|
||||
|
||||
seen := make(map[types.ManagedObjectReference]bool)
|
||||
container.add(root, seen)
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
type ContainerView struct {
|
||||
mo.ContainerView
|
||||
|
||||
types map[string]bool
|
||||
}
|
||||
|
||||
func (v *ContainerView) DestroyView(c *types.DestroyView) soap.HasFault {
|
||||
return destroyView(c.This)
|
||||
}
|
||||
|
||||
func (v *ContainerView) include(o types.ManagedObjectReference) bool {
|
||||
if len(v.types) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
return v.types[o.Type]
|
||||
}
|
||||
|
||||
func walk(root mo.Reference, f func(child types.ManagedObjectReference)) {
|
||||
var children []types.ManagedObjectReference
|
||||
|
||||
switch e := root.(type) {
|
||||
case *Datacenter:
|
||||
children = []types.ManagedObjectReference{e.VmFolder, e.HostFolder, e.DatastoreFolder, e.NetworkFolder}
|
||||
case *Folder:
|
||||
children = e.ChildEntity
|
||||
case *mo.ComputeResource:
|
||||
children = e.Host
|
||||
children = append(children, *e.ResourcePool)
|
||||
case *ClusterComputeResource:
|
||||
children = e.Host
|
||||
children = append(children, *e.ResourcePool)
|
||||
case *ResourcePool:
|
||||
children = e.ResourcePool.ResourcePool
|
||||
children = append(children, e.Vm...)
|
||||
case *VirtualApp:
|
||||
children = e.ResourcePool.ResourcePool
|
||||
children = append(children, e.Vm...)
|
||||
case *HostSystem:
|
||||
children = e.Vm
|
||||
}
|
||||
|
||||
for _, child := range children {
|
||||
f(child)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *ContainerView) add(root mo.Reference, seen map[types.ManagedObjectReference]bool) {
|
||||
walk(root, func(child types.ManagedObjectReference) {
|
||||
if v.include(child) {
|
||||
if seen[child] == false {
|
||||
seen[child] = true
|
||||
v.View = append(v.View, child)
|
||||
}
|
||||
}
|
||||
|
||||
if v.Recursive {
|
||||
v.add(Map.Get(child), seen)
|
||||
}
|
||||
})
|
||||
}
|
||||
144
vendor/github.com/vmware/govmomi/simulator/view_manager_test.go
generated
vendored
Normal file
144
vendor/github.com/vmware/govmomi/simulator/view_manager_test.go
generated
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/property"
|
||||
"github.com/vmware/govmomi/view"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestContainerViewVPX(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
m := VPX()
|
||||
m.Datacenter = 3
|
||||
m.Folder = 2
|
||||
m.Pool = 1
|
||||
m.App = 1
|
||||
m.Pod = 1
|
||||
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
v := view.NewManager(c.Client)
|
||||
root := c.Client.ServiceContent.RootFolder
|
||||
|
||||
// test container type validation
|
||||
_, err = v.CreateContainerView(ctx, v.Reference(), nil, false)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
|
||||
// test container value validation
|
||||
_, err = v.CreateContainerView(ctx, types.ManagedObjectReference{Value: "enoent"}, nil, false)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
|
||||
// test types validation
|
||||
_, err = v.CreateContainerView(ctx, root, []string{"enoent"}, false)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
|
||||
vapp := object.NewVirtualApp(c.Client, Map.Any("VirtualApp").Reference())
|
||||
|
||||
count := m.Count()
|
||||
|
||||
tests := []struct {
|
||||
root types.ManagedObjectReference
|
||||
recurse bool
|
||||
kinds []string
|
||||
expect int
|
||||
}{
|
||||
{root, false, nil, m.Datacenter - m.Folder + m.Folder},
|
||||
{root, true, nil, count.total - 1}, // not including the root Folder
|
||||
{root, true, []string{"ManagedEntity"}, count.total - 1}, // not including the root Folder
|
||||
{root, true, []string{"Folder"}, count.Folder + count.Pod - 1}, // not including the root Folder
|
||||
{root, false, []string{"HostSystem"}, 0},
|
||||
{root, true, []string{"HostSystem"}, count.Host},
|
||||
{root, false, []string{"Datacenter"}, m.Datacenter - m.Folder},
|
||||
{root, true, []string{"Datacenter"}, count.Datacenter},
|
||||
{root, true, []string{"Datastore"}, count.Datastore},
|
||||
{root, true, []string{"VirtualMachine"}, count.Machine},
|
||||
{root, true, []string{"ResourcePool"}, count.Pool + count.App},
|
||||
{root, true, []string{"VirtualApp"}, count.App},
|
||||
{vapp.Reference(), true, []string{"VirtualMachine"}, m.Machine},
|
||||
{root, true, []string{"ClusterComputeResource"}, count.Cluster},
|
||||
{root, true, []string{"ComputeResource"}, (m.Cluster + m.Host) * m.Datacenter},
|
||||
{root, true, []string{"DistributedVirtualSwitch"}, count.Datacenter},
|
||||
{root, true, []string{"DistributedVirtualPortgroup"}, count.Portgroup},
|
||||
{root, true, []string{"Network"}, count.Portgroup + m.Datacenter},
|
||||
{root, true, []string{"OpaqueNetwork"}, 0},
|
||||
{root, true, []string{"StoragePod"}, m.Pod * m.Datacenter},
|
||||
}
|
||||
|
||||
pc := property.DefaultCollector(c.Client)
|
||||
|
||||
mvm := Map.ViewManager()
|
||||
|
||||
for i, test := range tests {
|
||||
cv, err := v.CreateContainerView(ctx, test.root, test.kinds, test.recurse)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(mvm.ViewList) != 1 {
|
||||
t.Errorf("ViewList=%s", mvm.ViewList)
|
||||
}
|
||||
|
||||
var mcv mo.ContainerView
|
||||
err = pc.RetrieveOne(ctx, cv.Reference(), nil, &mcv)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
n := len(mcv.View)
|
||||
|
||||
if n != test.expect {
|
||||
t.Errorf("%d: %d != %d", i, n, test.expect)
|
||||
}
|
||||
|
||||
err = cv.Destroy(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(mvm.ViewList) != 0 {
|
||||
t.Errorf("ViewList=%s", mvm.ViewList)
|
||||
}
|
||||
}
|
||||
}
|
||||
212
vendor/github.com/vmware/govmomi/simulator/virtual_disk_manager.go
generated
vendored
Normal file
212
vendor/github.com/vmware/govmomi/simulator/virtual_disk_manager.go
generated
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type VirtualDiskManager struct {
|
||||
mo.VirtualDiskManager
|
||||
}
|
||||
|
||||
func NewVirtualDiskManager(ref types.ManagedObjectReference) object.Reference {
|
||||
m := &VirtualDiskManager{}
|
||||
m.Self = ref
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *VirtualDiskManager) names(name string) []string {
|
||||
return []string{
|
||||
strings.Replace(name, ".vmdk", "-flat.vmdk", 1),
|
||||
name,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *VirtualDiskManager) createVirtualDisk(op types.VirtualDeviceConfigSpecFileOperation, req *types.CreateVirtualDisk_Task) types.BaseMethodFault {
|
||||
fm := Map.FileManager()
|
||||
|
||||
file, fault := fm.resolve(req.Datacenter, req.Name)
|
||||
if fault != nil {
|
||||
return fault
|
||||
}
|
||||
|
||||
shouldReplace := op == types.VirtualDeviceConfigSpecFileOperationReplace
|
||||
shouldExist := op == ""
|
||||
for _, name := range m.names(file) {
|
||||
_, err := os.Stat(name)
|
||||
if err == nil {
|
||||
if shouldExist {
|
||||
return nil
|
||||
}
|
||||
if shouldReplace {
|
||||
if err = os.Truncate(file, 0); err != nil {
|
||||
return fm.fault(name, err, new(types.CannotCreateFile))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fm.fault(name, nil, new(types.FileAlreadyExists))
|
||||
} else if shouldExist {
|
||||
return fm.fault(name, nil, new(types.FileNotFound))
|
||||
}
|
||||
|
||||
f, err := os.Create(name)
|
||||
if err != nil {
|
||||
return fm.fault(name, err, new(types.CannotCreateFile))
|
||||
}
|
||||
|
||||
_ = f.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *VirtualDiskManager) CreateVirtualDiskTask(req *types.CreateVirtualDisk_Task) soap.HasFault {
|
||||
task := CreateTask(m, "createVirtualDisk", func(*Task) (types.AnyType, types.BaseMethodFault) {
|
||||
return nil, m.createVirtualDisk(types.VirtualDeviceConfigSpecFileOperationCreate, req)
|
||||
})
|
||||
|
||||
return &methods.CreateVirtualDisk_TaskBody{
|
||||
Res: &types.CreateVirtualDisk_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *VirtualDiskManager) DeleteVirtualDiskTask(req *types.DeleteVirtualDisk_Task) soap.HasFault {
|
||||
task := CreateTask(m, "deleteVirtualDisk", func(*Task) (types.AnyType, types.BaseMethodFault) {
|
||||
fm := Map.FileManager()
|
||||
|
||||
for _, name := range m.names(req.Name) {
|
||||
err := fm.deleteDatastoreFile(&types.DeleteDatastoreFile_Task{
|
||||
Name: name,
|
||||
Datacenter: req.Datacenter,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.DeleteVirtualDisk_TaskBody{
|
||||
Res: &types.DeleteVirtualDisk_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *VirtualDiskManager) MoveVirtualDiskTask(req *types.MoveVirtualDisk_Task) soap.HasFault {
|
||||
task := CreateTask(m, "moveVirtualDisk", func(*Task) (types.AnyType, types.BaseMethodFault) {
|
||||
fm := Map.FileManager()
|
||||
|
||||
dest := m.names(req.DestName)
|
||||
|
||||
for i, name := range m.names(req.SourceName) {
|
||||
err := fm.moveDatastoreFile(&types.MoveDatastoreFile_Task{
|
||||
SourceName: name,
|
||||
SourceDatacenter: req.SourceDatacenter,
|
||||
DestinationName: dest[i],
|
||||
DestinationDatacenter: req.DestDatacenter,
|
||||
Force: req.Force,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.MoveVirtualDisk_TaskBody{
|
||||
Res: &types.MoveVirtualDisk_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *VirtualDiskManager) CopyVirtualDiskTask(req *types.CopyVirtualDisk_Task) soap.HasFault {
|
||||
task := CreateTask(m, "copyVirtualDisk", func(*Task) (types.AnyType, types.BaseMethodFault) {
|
||||
if req.DestSpec != nil {
|
||||
if Map.IsVPX() {
|
||||
return nil, new(types.NotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
fm := Map.FileManager()
|
||||
|
||||
dest := m.names(req.DestName)
|
||||
|
||||
for i, name := range m.names(req.SourceName) {
|
||||
err := fm.copyDatastoreFile(&types.CopyDatastoreFile_Task{
|
||||
SourceName: name,
|
||||
SourceDatacenter: req.SourceDatacenter,
|
||||
DestinationName: dest[i],
|
||||
DestinationDatacenter: req.DestDatacenter,
|
||||
Force: req.Force,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return &methods.CopyVirtualDisk_TaskBody{
|
||||
Res: &types.CopyVirtualDisk_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *VirtualDiskManager) QueryVirtualDiskUuid(req *types.QueryVirtualDiskUuid) soap.HasFault {
|
||||
body := new(methods.QueryVirtualDiskUuidBody)
|
||||
|
||||
fm := Map.FileManager()
|
||||
|
||||
file, fault := fm.resolve(req.Datacenter, req.Name)
|
||||
if fault != nil {
|
||||
body.Fault_ = Fault("", fault)
|
||||
return body
|
||||
}
|
||||
|
||||
_, err := os.Stat(file)
|
||||
if err != nil {
|
||||
fault = fm.fault(file, err, new(types.CannotAccessFile))
|
||||
body.Fault_ = Fault("", fault)
|
||||
return body
|
||||
}
|
||||
|
||||
body.Res = &types.QueryVirtualDiskUuidResponse{
|
||||
Returnval: uuid.NewSHA1(uuid.NameSpaceOID, []byte(file)).String(),
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
163
vendor/github.com/vmware/govmomi/simulator/virtual_disk_manager_test.go
generated
vendored
Normal file
163
vendor/github.com/vmware/govmomi/simulator/virtual_disk_manager_test.go
generated
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestVirtualDiskManager(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
m := ESX()
|
||||
defer m.Remove()
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dm := object.NewVirtualDiskManager(c.Client)
|
||||
fm := object.NewFileManager(c.Client)
|
||||
|
||||
spec := &types.FileBackedVirtualDiskSpec{
|
||||
VirtualDiskSpec: types.VirtualDiskSpec{
|
||||
AdapterType: string(types.VirtualDiskAdapterTypeLsiLogic),
|
||||
DiskType: string(types.VirtualDiskTypeThin),
|
||||
},
|
||||
CapacityKb: 1024 * 1024,
|
||||
}
|
||||
|
||||
name := "[LocalDS_0] disks/disk1.vmdk"
|
||||
|
||||
for i, fail := range []bool{true, false, true} {
|
||||
task, err := dm.CreateVirtualDisk(ctx, name, nil, spec)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if fail {
|
||||
if err == nil {
|
||||
t.Error("expected error") // disk1 already exists
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
err = fm.MakeDirectory(ctx, path.Dir(name), nil, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qname := name
|
||||
for _, fail := range []bool{false, true} {
|
||||
id, err := dm.QueryVirtualDiskUuid(ctx, qname, nil)
|
||||
if fail {
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = uuid.Parse(id)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
qname += "-enoent"
|
||||
}
|
||||
|
||||
old := name
|
||||
name = strings.Replace(old, "disk1", "disk2", 1)
|
||||
|
||||
for _, fail := range []bool{false, true} {
|
||||
task, err := dm.MoveVirtualDisk(ctx, old, nil, name, nil, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if fail {
|
||||
if err == nil {
|
||||
t.Error("expected error") // disk1 no longer exists
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, fail := range []bool{false, true} {
|
||||
task, err := dm.CopyVirtualDisk(ctx, name, nil, old, nil, &types.VirtualDiskSpec{}, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if fail {
|
||||
if err == nil {
|
||||
t.Error("expected error") // disk1 exists again
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, fail := range []bool{false, true} {
|
||||
task, err := dm.DeleteVirtualDisk(ctx, name, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if fail {
|
||||
if err == nil {
|
||||
t.Error("expected error") // disk2 no longer exists
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1132
vendor/github.com/vmware/govmomi/simulator/virtual_machine.go
generated
vendored
Normal file
1132
vendor/github.com/vmware/govmomi/simulator/virtual_machine.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
806
vendor/github.com/vmware/govmomi/simulator/virtual_machine_test.go
generated
vendored
Normal file
806
vendor/github.com/vmware/govmomi/simulator/virtual_machine_test.go
generated
vendored
Normal file
@@ -0,0 +1,806 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/find"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/property"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/task"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestCreateVm(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
for _, model := range []*Model{ESX(), VPX()} {
|
||||
defer model.Remove()
|
||||
err := model.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := model.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
p := property.DefaultCollector(c.Client)
|
||||
|
||||
finder := find.NewFinder(c.Client, false)
|
||||
|
||||
dc, err := finder.DefaultDatacenter(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder.SetDatacenter(dc)
|
||||
|
||||
folders, err := dc.Folders(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ds, err := finder.DefaultDatastore(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hosts, err := finder.HostSystemList(ctx, "*/*")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nhosts := len(hosts)
|
||||
host := hosts[rand.Intn(nhosts)]
|
||||
pool, err := host.ResourcePool(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if nhosts == 1 {
|
||||
// test the default path against the ESX model
|
||||
host = nil
|
||||
}
|
||||
|
||||
vmFolder := folders.VmFolder
|
||||
|
||||
var vmx string
|
||||
|
||||
spec := types.VirtualMachineConfigSpec{
|
||||
// Note: real ESX allows the VM to be created without a GuestId,
|
||||
// but will power on will fail.
|
||||
GuestId: string(types.VirtualMachineGuestOsIdentifierOtherGuest),
|
||||
}
|
||||
|
||||
steps := []func(){
|
||||
func() {
|
||||
spec.Name = "test"
|
||||
vmx = fmt.Sprintf("%s/%s.vmx", spec.Name, spec.Name)
|
||||
},
|
||||
func() {
|
||||
spec.Files = &types.VirtualMachineFileInfo{
|
||||
VmPathName: fmt.Sprintf("[%s] %s", ds.Name(), vmx),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// expecting CreateVM to fail until all steps are taken
|
||||
for _, step := range steps {
|
||||
task, cerr := vmFolder.CreateVM(ctx, spec, pool, host)
|
||||
if cerr != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cerr = task.Wait(ctx)
|
||||
if cerr == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
step()
|
||||
}
|
||||
|
||||
task, err := vmFolder.CreateVM(ctx, spec, pool, host)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
info, err := task.WaitForResult(ctx, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Test that datastore files were created
|
||||
_, err = ds.Stat(ctx, vmx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vm := object.NewVirtualMachine(c.Client, info.Result.(types.ManagedObjectReference))
|
||||
|
||||
name, err := vm.ObjectName(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if name != spec.Name {
|
||||
t.Errorf("name=%s", name)
|
||||
}
|
||||
|
||||
_, err = vm.Device(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
recreate := func(context.Context) (*object.Task, error) {
|
||||
return vmFolder.CreateVM(ctx, spec, pool, nil)
|
||||
}
|
||||
|
||||
ops := []struct {
|
||||
method func(context.Context) (*object.Task, error)
|
||||
state types.VirtualMachinePowerState
|
||||
fail bool
|
||||
}{
|
||||
// Powered off by default
|
||||
{nil, types.VirtualMachinePowerStatePoweredOff, false},
|
||||
// Create with same .vmx path should fail
|
||||
{recreate, "", true},
|
||||
// Off -> On == ok
|
||||
{vm.PowerOn, types.VirtualMachinePowerStatePoweredOn, false},
|
||||
// On -> On == fail
|
||||
{vm.PowerOn, types.VirtualMachinePowerStatePoweredOn, true},
|
||||
// On -> Off == ok
|
||||
{vm.PowerOff, types.VirtualMachinePowerStatePoweredOff, false},
|
||||
// Off -> Off == fail
|
||||
{vm.PowerOff, types.VirtualMachinePowerStatePoweredOff, true},
|
||||
// Off -> On == ok
|
||||
{vm.PowerOn, types.VirtualMachinePowerStatePoweredOn, false},
|
||||
// Destroy == fail (power is On)
|
||||
{vm.Destroy, types.VirtualMachinePowerStatePoweredOn, true},
|
||||
// On -> Off == ok
|
||||
{vm.PowerOff, types.VirtualMachinePowerStatePoweredOff, false},
|
||||
// Destroy == ok (power is Off)
|
||||
{vm.Destroy, "", false},
|
||||
}
|
||||
|
||||
for i, op := range ops {
|
||||
if op.method != nil {
|
||||
task, err = op.method(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if op.fail {
|
||||
if err == nil {
|
||||
t.Errorf("%d: expected error", i)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("%d: %s", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(op.state) != 0 {
|
||||
state, err := vm.PowerState(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if state != op.state {
|
||||
t.Errorf("state=%s", state)
|
||||
}
|
||||
|
||||
err = property.Wait(ctx, p, vm.Reference(), []string{object.PropRuntimePowerState}, func(pc []types.PropertyChange) bool {
|
||||
for _, c := range pc {
|
||||
switch v := c.Val.(type) {
|
||||
case types.VirtualMachinePowerState:
|
||||
if v != op.state {
|
||||
t.Errorf("state=%s", v)
|
||||
}
|
||||
default:
|
||||
t.Errorf("unexpected type %T", v)
|
||||
}
|
||||
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Test that datastore files were removed
|
||||
_, err = ds.Stat(ctx, vmx)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReconfigVmDevice(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
m := ESX()
|
||||
defer m.Remove()
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finder := find.NewFinder(c.Client, false)
|
||||
finder.SetDatacenter(object.NewDatacenter(c.Client, esx.Datacenter.Reference()))
|
||||
|
||||
vms, err := finder.VirtualMachineList(ctx, "*")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vm := vms[0]
|
||||
device, err := vm.Device(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// verify default device list
|
||||
_, err = device.FindIDEController("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// default list of devices + 1 NIC + 1 SCSI controller + 1 CDROM + 1 disk created by the Model
|
||||
mdevices := len(esx.VirtualDevice) + 4
|
||||
|
||||
if len(device) != mdevices {
|
||||
t.Errorf("expected %d devices, got %d", mdevices, len(device))
|
||||
}
|
||||
|
||||
d := device.FindByKey(esx.EthernetCard.Key)
|
||||
|
||||
err = vm.AddDevice(ctx, d)
|
||||
if _, ok := err.(task.Error).Fault().(*types.InvalidDeviceSpec); !ok {
|
||||
t.Fatalf("err=%v", err)
|
||||
}
|
||||
|
||||
err = vm.RemoveDevice(ctx, false, d)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
device, err = vm.Device(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(device) != mdevices-1 {
|
||||
t.Error("device list mismatch")
|
||||
}
|
||||
|
||||
// cover the path where the simulator assigns a UnitNumber
|
||||
d.GetVirtualDevice().UnitNumber = nil
|
||||
// cover the path where the simulator assigns a Key
|
||||
d.GetVirtualDevice().Key = -1
|
||||
|
||||
err = vm.AddDevice(ctx, d)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
device, err = vm.Device(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(device) != mdevices {
|
||||
t.Error("device list mismatch")
|
||||
}
|
||||
|
||||
disks := device.SelectByType((*types.VirtualDisk)(nil))
|
||||
|
||||
for _, d := range disks {
|
||||
disk := d.(*types.VirtualDisk)
|
||||
info := disk.Backing.(*types.VirtualDiskFlatVer2BackingInfo)
|
||||
|
||||
if info.Datastore.Type == "" || info.Datastore.Value == "" {
|
||||
t.Errorf("invalid datastore for %s", device.Name(d))
|
||||
}
|
||||
|
||||
// RemoveDevice and keep the file backing
|
||||
if err = vm.RemoveDevice(ctx, true, d); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err = vm.AddDevice(ctx, d); err == nil {
|
||||
t.Error("expected FileExists error")
|
||||
}
|
||||
|
||||
// Need FileOperation=="" to add an existing disk, see object.VirtualMachine.configureDevice
|
||||
disk.CapacityInKB = 0
|
||||
if err = vm.AddDevice(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)
|
||||
}
|
||||
|
||||
if err = vm.AddDevice(ctx, d); err == nil {
|
||||
t.Error("expected FileNotFound error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReconfigVm(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
m := ESX()
|
||||
defer m.Remove()
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vmm := Map.Any("VirtualMachine").(*VirtualMachine)
|
||||
vm := object.NewVirtualMachine(c.Client, vmm.Reference())
|
||||
|
||||
tests := []struct {
|
||||
fail bool
|
||||
spec types.VirtualMachineConfigSpec
|
||||
}{
|
||||
{
|
||||
true, types.VirtualMachineConfigSpec{
|
||||
CpuAllocation: &types.ResourceAllocationInfo{Reservation: types.NewInt64(-1)},
|
||||
},
|
||||
},
|
||||
{
|
||||
false, types.VirtualMachineConfigSpec{
|
||||
CpuAllocation: &types.ResourceAllocationInfo{Reservation: types.NewInt64(100)},
|
||||
},
|
||||
},
|
||||
{
|
||||
true, types.VirtualMachineConfigSpec{
|
||||
GuestId: "enoent",
|
||||
},
|
||||
},
|
||||
{
|
||||
false, types.VirtualMachineConfigSpec{
|
||||
GuestId: string(GuestID[0]),
|
||||
},
|
||||
},
|
||||
{
|
||||
false, types.VirtualMachineConfigSpec{
|
||||
NestedHVEnabled: types.NewBool(true),
|
||||
},
|
||||
},
|
||||
{
|
||||
false, types.VirtualMachineConfigSpec{
|
||||
CpuHotAddEnabled: types.NewBool(true),
|
||||
},
|
||||
},
|
||||
{
|
||||
false, types.VirtualMachineConfigSpec{
|
||||
CpuHotRemoveEnabled: types.NewBool(true),
|
||||
},
|
||||
},
|
||||
{
|
||||
false, types.VirtualMachineConfigSpec{
|
||||
GuestAutoLockEnabled: types.NewBool(true),
|
||||
},
|
||||
},
|
||||
{
|
||||
false, types.VirtualMachineConfigSpec{
|
||||
MemoryHotAddEnabled: types.NewBool(true),
|
||||
},
|
||||
},
|
||||
{
|
||||
false, types.VirtualMachineConfigSpec{
|
||||
MemoryReservationLockedToMax: types.NewBool(true),
|
||||
},
|
||||
},
|
||||
{
|
||||
false, types.VirtualMachineConfigSpec{
|
||||
MessageBusTunnelEnabled: types.NewBool(true),
|
||||
},
|
||||
},
|
||||
{
|
||||
false, types.VirtualMachineConfigSpec{
|
||||
NpivTemporaryDisabled: types.NewBool(true),
|
||||
},
|
||||
},
|
||||
{
|
||||
false, types.VirtualMachineConfigSpec{
|
||||
NpivOnNonRdmDisks: types.NewBool(true),
|
||||
},
|
||||
},
|
||||
{
|
||||
false, types.VirtualMachineConfigSpec{
|
||||
ConsolePreferences: &types.VirtualMachineConsolePreferences{
|
||||
PowerOnWhenOpened: types.NewBool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
false, types.VirtualMachineConfigSpec{
|
||||
CpuAffinity: &types.VirtualMachineAffinityInfo{
|
||||
AffinitySet: []int32{1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
false, types.VirtualMachineConfigSpec{
|
||||
CpuAllocation: &types.ResourceAllocationInfo{
|
||||
Reservation: types.NewInt64(100),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
false, types.VirtualMachineConfigSpec{
|
||||
MemoryAffinity: &types.VirtualMachineAffinityInfo{
|
||||
AffinitySet: []int32{1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
false, types.VirtualMachineConfigSpec{
|
||||
MemoryAllocation: &types.ResourceAllocationInfo{
|
||||
Reservation: types.NewInt64(100),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
false, types.VirtualMachineConfigSpec{
|
||||
LatencySensitivity: &types.LatencySensitivity{
|
||||
Sensitivity: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
rtask, _ := vm.Reconfigure(ctx, test.spec)
|
||||
|
||||
err := rtask.Wait(ctx)
|
||||
if test.fail {
|
||||
if err == nil {
|
||||
t.Errorf("%d: expected failure", i)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("unexpected failure: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify ReConfig actually works
|
||||
if *vmm.Config.NestedHVEnabled != true {
|
||||
t.Errorf("vm.Config.NestedHVEnabled expected true; got false")
|
||||
}
|
||||
if *vmm.Config.CpuHotAddEnabled != true {
|
||||
t.Errorf("vm.Config.CpuHotAddEnabled expected true; got false")
|
||||
}
|
||||
if *vmm.Config.CpuHotRemoveEnabled != true {
|
||||
t.Errorf("vm.Config.CpuHotRemoveEnabled expected true; got false")
|
||||
}
|
||||
if *vmm.Config.GuestAutoLockEnabled != true {
|
||||
t.Errorf("vm.Config.GuestAutoLockEnabled expected true; got false")
|
||||
}
|
||||
if *vmm.Config.MemoryHotAddEnabled != true {
|
||||
t.Errorf("vm.Config.MemoryHotAddEnabled expected true; got false")
|
||||
}
|
||||
if *vmm.Config.MemoryReservationLockedToMax != true {
|
||||
t.Errorf("vm.Config.MemoryReservationLockedToMax expected true; got false")
|
||||
}
|
||||
if *vmm.Config.MessageBusTunnelEnabled != true {
|
||||
t.Errorf("vm.Config.MessageBusTunnelEnabled expected true; got false")
|
||||
}
|
||||
if *vmm.Config.NpivTemporaryDisabled != true {
|
||||
t.Errorf("vm.Config.NpivTemporaryDisabled expected true; got false")
|
||||
}
|
||||
if *vmm.Config.NpivOnNonRdmDisks != true {
|
||||
t.Errorf("vm.Config.NpivOnNonRdmDisks expected true; got false")
|
||||
}
|
||||
if *vmm.Config.ConsolePreferences.PowerOnWhenOpened != true {
|
||||
t.Errorf("vm.Config.ConsolePreferences.PowerOnWhenOpened expected true; got false")
|
||||
}
|
||||
if vmm.Config.CpuAffinity.AffinitySet[0] != int32(1) {
|
||||
t.Errorf("vm.Config.CpuAffinity.AffinitySet[0] expected %d; got %d",
|
||||
1, vmm.Config.CpuAffinity.AffinitySet[0])
|
||||
}
|
||||
if vmm.Config.MemoryAffinity.AffinitySet[0] != int32(1) {
|
||||
t.Errorf("vm.Config.CpuAffinity.AffinitySet[0] expected %d; got %d",
|
||||
1, vmm.Config.CpuAffinity.AffinitySet[0])
|
||||
}
|
||||
if *vmm.Config.CpuAllocation.Reservation != 100 {
|
||||
t.Errorf("vm.Config.CpuAllocation.Reservation expected %d; got %d",
|
||||
100, *vmm.Config.CpuAllocation.Reservation)
|
||||
}
|
||||
if *vmm.Config.MemoryAllocation.Reservation != 100 {
|
||||
t.Errorf("vm.Config.MemoryAllocation.Reservation expected %d; got %d",
|
||||
100, *vmm.Config.MemoryAllocation.Reservation)
|
||||
}
|
||||
if vmm.Config.LatencySensitivity.Sensitivity != int32(1) {
|
||||
t.Errorf("vmm.Config.LatencySensitivity.Sensitivity expected %d; got %d",
|
||||
1, vmm.Config.LatencySensitivity.Sensitivity)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateVmWithDevices(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
m := ESX()
|
||||
defer m.Remove()
|
||||
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c := m.Service.client
|
||||
|
||||
folder := object.NewFolder(c, esx.Datacenter.VmFolder)
|
||||
pool := object.NewResourcePool(c, esx.ResourcePool.Self)
|
||||
|
||||
// different set of devices from Model.Create's
|
||||
var devices object.VirtualDeviceList
|
||||
ide, _ := devices.CreateIDEController()
|
||||
cdrom, _ := devices.CreateCdrom(ide.(*types.VirtualIDEController))
|
||||
scsi, _ := devices.CreateSCSIController("scsi")
|
||||
disk := &types.VirtualDisk{
|
||||
CapacityInKB: 1024,
|
||||
VirtualDevice: types.VirtualDevice{
|
||||
Backing: new(types.VirtualDiskFlatVer2BackingInfo), // Leave fields empty to test defaults
|
||||
},
|
||||
}
|
||||
devices.AssignController(disk, scsi.(*types.VirtualLsiLogicController))
|
||||
devices = append(devices, ide, cdrom, scsi, disk)
|
||||
create, _ := devices.ConfigSpec(types.VirtualDeviceConfigSpecOperationAdd)
|
||||
|
||||
spec := types.VirtualMachineConfigSpec{
|
||||
Name: "foo",
|
||||
GuestId: string(types.VirtualMachineGuestOsIdentifierOtherGuest),
|
||||
DeviceChange: create,
|
||||
Files: &types.VirtualMachineFileInfo{
|
||||
VmPathName: "[LocalDS_0] foo/foo.vmx",
|
||||
},
|
||||
}
|
||||
|
||||
ctask, _ := folder.CreateVM(ctx, spec, pool, nil)
|
||||
info, err := ctask.WaitForResult(ctx, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vm := Map.Get(info.Result.(types.ManagedObjectReference)).(*VirtualMachine)
|
||||
|
||||
expect := len(esx.VirtualDevice) + len(devices)
|
||||
ndevice := len(vm.Config.Hardware.Device)
|
||||
|
||||
if expect != ndevice {
|
||||
t.Errorf("expected %d, got %d", expect, ndevice)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShutdownGuest(t *testing.T) {
|
||||
// use the default vm for testing
|
||||
ctx := context.Background()
|
||||
|
||||
for _, model := range []*Model{ESX(), VPX()} {
|
||||
defer model.Remove()
|
||||
err := model.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := model.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vm := object.NewVirtualMachine(c.Client, Map.Any("VirtualMachine").Reference())
|
||||
// shutdown the vm
|
||||
err = vm.ShutdownGuest(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// state should be poweroff
|
||||
state, err := vm.PowerState(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if state != types.VirtualMachinePowerStatePoweredOff {
|
||||
t.Errorf("state=%s", state)
|
||||
}
|
||||
|
||||
// shutdown a poweroff vm should fail
|
||||
err = vm.ShutdownGuest(ctx)
|
||||
if err == nil {
|
||||
t.Error("expected error: InvalidPowerState")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVmSnapshot(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
m := ESX()
|
||||
defer m.Remove()
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vm := object.NewVirtualMachine(c.Client, Map.Any("VirtualMachine").Reference())
|
||||
|
||||
task, err := vm.CreateSnapshot(ctx, "root", "description", true, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
task, err = vm.CreateSnapshot(ctx, "child", "description", true, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = vm.FindSnapshot(ctx, "child")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
task, err = vm.RevertToCurrentSnapshot(ctx, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
task, err = vm.RevertToSnapshot(ctx, "root", true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
task, err = vm.RemoveSnapshot(ctx, "child", false, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = vm.FindSnapshot(ctx, "child")
|
||||
if err == nil {
|
||||
t.Fatal("child should be removed")
|
||||
}
|
||||
|
||||
task, err = vm.RemoveAllSnapshot(ctx, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = task.Wait(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = vm.FindSnapshot(ctx, "root")
|
||||
if err == nil {
|
||||
t.Fatal("all snapshots should be removed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVmMarkAsTemplate(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
m := VPX()
|
||||
defer m.Remove()
|
||||
err := m.Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := m.Service.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
c, err := govmomi.NewClient(ctx, s.URL, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vm := object.NewVirtualMachine(c.Client, Map.Any("VirtualMachine").Reference())
|
||||
|
||||
err = vm.MarkAsTemplate(ctx)
|
||||
if err == nil {
|
||||
t.Fatal("cannot create template for a powered on vm")
|
||||
}
|
||||
|
||||
task, err := vm.PowerOff(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
task.Wait(ctx)
|
||||
|
||||
err = vm.MarkAsTemplate(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = vm.PowerOn(ctx)
|
||||
if err == nil {
|
||||
t.Fatal("cannot PowerOn a template")
|
||||
}
|
||||
}
|
||||
20
vendor/github.com/vmware/govmomi/simulator/vpx/doc.go
generated
vendored
Normal file
20
vendor/github.com/vmware/govmomi/simulator/vpx/doc.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Package vpx contains SOAP responses from a vCenter server, captured using `govc ... -dump`.
|
||||
*/
|
||||
package vpx
|
||||
64
vendor/github.com/vmware/govmomi/simulator/vpx/root_folder.go
generated
vendored
Normal file
64
vendor/github.com/vmware/govmomi/simulator/vpx/root_folder.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package vpx
|
||||
|
||||
import (
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
var RootFolder = mo.Folder{
|
||||
ManagedEntity: mo.ManagedEntity{
|
||||
ExtensibleManagedObject: mo.ExtensibleManagedObject{
|
||||
Self: types.ManagedObjectReference{Type: "Folder", Value: "group-d1"},
|
||||
Value: nil,
|
||||
AvailableField: nil,
|
||||
},
|
||||
Parent: (*types.ManagedObjectReference)(nil),
|
||||
CustomValue: nil,
|
||||
OverallStatus: "green",
|
||||
ConfigStatus: "green",
|
||||
ConfigIssue: nil,
|
||||
EffectiveRole: []int32{-1},
|
||||
Permission: []types.Permission{
|
||||
{
|
||||
DynamicData: types.DynamicData{},
|
||||
Entity: &types.ManagedObjectReference{Type: "Folder", Value: "group-d1"},
|
||||
Principal: "VSPHERE.LOCAL\\Administrator",
|
||||
Group: false,
|
||||
RoleId: -1,
|
||||
Propagate: true,
|
||||
},
|
||||
{
|
||||
DynamicData: types.DynamicData{},
|
||||
Entity: &types.ManagedObjectReference{Type: "Folder", Value: "group-d1"},
|
||||
Principal: "VSPHERE.LOCAL\\Administrators",
|
||||
Group: true,
|
||||
RoleId: -1,
|
||||
Propagate: true,
|
||||
},
|
||||
},
|
||||
Name: "Datacenters",
|
||||
DisabledMethod: nil,
|
||||
RecentTask: nil,
|
||||
DeclaredAlarmState: nil,
|
||||
AlarmActionsEnabled: (*bool)(nil),
|
||||
Tag: nil,
|
||||
},
|
||||
ChildType: []string{"Folder", "Datacenter"},
|
||||
ChildEntity: nil,
|
||||
}
|
||||
86
vendor/github.com/vmware/govmomi/simulator/vpx/service_content.go
generated
vendored
Normal file
86
vendor/github.com/vmware/govmomi/simulator/vpx/service_content.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package vpx
|
||||
|
||||
import "github.com/vmware/govmomi/vim25/types"
|
||||
|
||||
// ServiceContent is the default template for the ServiceInstance content property.
|
||||
// Capture method:
|
||||
// govc object.collect -s -dump - content
|
||||
var ServiceContent = types.ServiceContent{
|
||||
RootFolder: types.ManagedObjectReference{Type: "Folder", Value: "group-d1"},
|
||||
PropertyCollector: types.ManagedObjectReference{Type: "PropertyCollector", Value: "propertyCollector"},
|
||||
ViewManager: &types.ManagedObjectReference{Type: "ViewManager", Value: "ViewManager"},
|
||||
About: types.AboutInfo{
|
||||
Name: "VMware vCenter Server",
|
||||
FullName: "VMware vCenter Server 6.5.0 build-5973321",
|
||||
Vendor: "VMware, Inc.",
|
||||
Version: "6.5.0",
|
||||
Build: "5973321",
|
||||
LocaleVersion: "INTL",
|
||||
LocaleBuild: "000",
|
||||
OsType: "linux-x64",
|
||||
ProductLineId: "vpx",
|
||||
ApiType: "VirtualCenter",
|
||||
ApiVersion: "6.5",
|
||||
InstanceUuid: "dbed6e0c-bd88-4ef6-b594-21283e1c677f",
|
||||
LicenseProductName: "VMware VirtualCenter Server",
|
||||
LicenseProductVersion: "6.0",
|
||||
},
|
||||
Setting: &types.ManagedObjectReference{Type: "OptionManager", Value: "VpxSettings"},
|
||||
UserDirectory: &types.ManagedObjectReference{Type: "UserDirectory", Value: "UserDirectory"},
|
||||
SessionManager: &types.ManagedObjectReference{Type: "SessionManager", Value: "SessionManager"},
|
||||
AuthorizationManager: &types.ManagedObjectReference{Type: "AuthorizationManager", Value: "AuthorizationManager"},
|
||||
ServiceManager: &types.ManagedObjectReference{Type: "ServiceManager", Value: "ServiceMgr"},
|
||||
PerfManager: &types.ManagedObjectReference{Type: "PerformanceManager", Value: "PerfMgr"},
|
||||
ScheduledTaskManager: &types.ManagedObjectReference{Type: "ScheduledTaskManager", Value: "ScheduledTaskManager"},
|
||||
AlarmManager: &types.ManagedObjectReference{Type: "AlarmManager", Value: "AlarmManager"},
|
||||
EventManager: &types.ManagedObjectReference{Type: "EventManager", Value: "EventManager"},
|
||||
TaskManager: &types.ManagedObjectReference{Type: "TaskManager", Value: "TaskManager"},
|
||||
ExtensionManager: &types.ManagedObjectReference{Type: "ExtensionManager", Value: "ExtensionManager"},
|
||||
CustomizationSpecManager: &types.ManagedObjectReference{Type: "CustomizationSpecManager", Value: "CustomizationSpecManager"},
|
||||
CustomFieldsManager: &types.ManagedObjectReference{Type: "CustomFieldsManager", Value: "CustomFieldsManager"},
|
||||
AccountManager: (*types.ManagedObjectReference)(nil),
|
||||
DiagnosticManager: &types.ManagedObjectReference{Type: "DiagnosticManager", Value: "DiagMgr"},
|
||||
LicenseManager: &types.ManagedObjectReference{Type: "LicenseManager", Value: "LicenseManager"},
|
||||
SearchIndex: &types.ManagedObjectReference{Type: "SearchIndex", Value: "SearchIndex"},
|
||||
FileManager: &types.ManagedObjectReference{Type: "FileManager", Value: "FileManager"},
|
||||
DatastoreNamespaceManager: &types.ManagedObjectReference{Type: "DatastoreNamespaceManager", Value: "DatastoreNamespaceManager"},
|
||||
VirtualDiskManager: &types.ManagedObjectReference{Type: "VirtualDiskManager", Value: "virtualDiskManager"},
|
||||
VirtualizationManager: (*types.ManagedObjectReference)(nil),
|
||||
SnmpSystem: &types.ManagedObjectReference{Type: "HostSnmpSystem", Value: "SnmpSystem"},
|
||||
VmProvisioningChecker: &types.ManagedObjectReference{Type: "VirtualMachineProvisioningChecker", Value: "ProvChecker"},
|
||||
VmCompatibilityChecker: &types.ManagedObjectReference{Type: "VirtualMachineCompatibilityChecker", Value: "CompatChecker"},
|
||||
OvfManager: &types.ManagedObjectReference{Type: "OvfManager", Value: "OvfManager"},
|
||||
IpPoolManager: &types.ManagedObjectReference{Type: "IpPoolManager", Value: "IpPoolManager"},
|
||||
DvSwitchManager: &types.ManagedObjectReference{Type: "DistributedVirtualSwitchManager", Value: "DVSManager"},
|
||||
HostProfileManager: &types.ManagedObjectReference{Type: "HostProfileManager", Value: "HostProfileManager"},
|
||||
ClusterProfileManager: &types.ManagedObjectReference{Type: "ClusterProfileManager", Value: "ClusterProfileManager"},
|
||||
ComplianceManager: &types.ManagedObjectReference{Type: "ProfileComplianceManager", Value: "MoComplianceManager"},
|
||||
LocalizationManager: &types.ManagedObjectReference{Type: "LocalizationManager", Value: "LocalizationManager"},
|
||||
StorageResourceManager: &types.ManagedObjectReference{Type: "StorageResourceManager", Value: "StorageResourceManager"},
|
||||
GuestOperationsManager: &types.ManagedObjectReference{Type: "GuestOperationsManager", Value: "guestOperationsManager"},
|
||||
OverheadMemoryManager: &types.ManagedObjectReference{Type: "OverheadMemoryManager", Value: "OverheadMemoryManager"},
|
||||
CertificateManager: &types.ManagedObjectReference{Type: "CertificateManager", Value: "certificateManager"},
|
||||
IoFilterManager: &types.ManagedObjectReference{Type: "IoFilterManager", Value: "IoFilterManager"},
|
||||
VStorageObjectManager: &types.ManagedObjectReference{Type: "VcenterVStorageObjectManager", Value: "VStorageObjectManager"},
|
||||
HostSpecManager: &types.ManagedObjectReference{Type: "HostSpecificationManager", Value: "HostSpecificationManager"},
|
||||
CryptoManager: &types.ManagedObjectReference{Type: "CryptoManagerKmip", Value: "CryptoManager"},
|
||||
HealthUpdateManager: &types.ManagedObjectReference{Type: "HealthUpdateManager", Value: "HealthUpdateManager"},
|
||||
FailoverClusterConfigurator: &types.ManagedObjectReference{Type: "FailoverClusterConfigurator", Value: "FailoverClusterConfigurator"},
|
||||
FailoverClusterManager: &types.ManagedObjectReference{Type: "FailoverClusterManager", Value: "FailoverClusterManager"},
|
||||
}
|
||||
72
vendor/github.com/vmware/govmomi/simulator/vpx/setting.go
generated
vendored
Normal file
72
vendor/github.com/vmware/govmomi/simulator/vpx/setting.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package vpx
|
||||
|
||||
import "github.com/vmware/govmomi/vim25/types"
|
||||
|
||||
// Setting is captured from VC's ServiceContent.OptionManager.setting
|
||||
var Setting = []types.BaseOptionValue{
|
||||
// This list is currently pruned to include sso options only with sso.enabled set to false
|
||||
&types.OptionValue{
|
||||
Key: "config.vpxd.sso.sts.uri",
|
||||
Value: "https://127.0.0.1/sts/STSService/vsphere.local",
|
||||
},
|
||||
&types.OptionValue{
|
||||
Key: "config.vpxd.sso.solutionUser.privateKey",
|
||||
Value: "/etc/vmware-vpx/ssl/vcsoluser.key",
|
||||
},
|
||||
&types.OptionValue{
|
||||
Key: "config.vpxd.sso.solutionUser.name",
|
||||
Value: "vpxd-b643d01c-928f-469b-96a5-d571d762a78e@vsphere.local",
|
||||
},
|
||||
&types.OptionValue{
|
||||
Key: "config.vpxd.sso.solutionUser.certificate",
|
||||
Value: "/etc/vmware-vpx/ssl/vcsoluser.crt",
|
||||
},
|
||||
&types.OptionValue{
|
||||
Key: "config.vpxd.sso.groupcheck.uri",
|
||||
Value: "https://127.0.0.1/sso-adminserver/sdk/vsphere.local",
|
||||
},
|
||||
&types.OptionValue{
|
||||
Key: "config.vpxd.sso.enabled",
|
||||
Value: "false",
|
||||
},
|
||||
&types.OptionValue{
|
||||
Key: "config.vpxd.sso.default.isGroup",
|
||||
Value: "false",
|
||||
},
|
||||
&types.OptionValue{
|
||||
Key: "config.vpxd.sso.default.admin",
|
||||
Value: "Administrator@vsphere.local",
|
||||
},
|
||||
&types.OptionValue{
|
||||
Key: "config.vpxd.sso.admin.uri",
|
||||
Value: "https://127.0.0.1/sso-adminserver/sdk/vsphere.local",
|
||||
},
|
||||
&types.OptionValue{
|
||||
Key: "event.batchsize",
|
||||
Value: int32(2000),
|
||||
},
|
||||
&types.OptionValue{
|
||||
Key: "event.maxAge",
|
||||
Value: int32(30),
|
||||
},
|
||||
&types.OptionValue{
|
||||
Key: "event.maxAgeEnabled",
|
||||
Value: bool(true),
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user