github.com/vmware/govmomi@v0.37.2/simulator/view_manager.go (about)

     1  /*
     2  Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package simulator
    18  
    19  import (
    20  	"reflect"
    21  
    22  	"github.com/vmware/govmomi/vim25/methods"
    23  	"github.com/vmware/govmomi/vim25/mo"
    24  	"github.com/vmware/govmomi/vim25/soap"
    25  	"github.com/vmware/govmomi/vim25/types"
    26  )
    27  
    28  type ViewManager struct {
    29  	mo.ViewManager
    30  
    31  	entities map[string]bool
    32  }
    33  
    34  var entities = []struct {
    35  	Type      reflect.Type
    36  	Container bool
    37  }{
    38  	{reflect.TypeOf((*mo.ManagedEntity)(nil)).Elem(), true},
    39  	{reflect.TypeOf((*mo.Folder)(nil)).Elem(), true},
    40  	{reflect.TypeOf((*mo.StoragePod)(nil)).Elem(), true},
    41  	{reflect.TypeOf((*mo.Datacenter)(nil)).Elem(), true},
    42  	{reflect.TypeOf((*mo.ComputeResource)(nil)).Elem(), true},
    43  	{reflect.TypeOf((*mo.ClusterComputeResource)(nil)).Elem(), true},
    44  	{reflect.TypeOf((*mo.HostSystem)(nil)).Elem(), true},
    45  	{reflect.TypeOf((*mo.ResourcePool)(nil)).Elem(), true},
    46  	{reflect.TypeOf((*mo.VirtualApp)(nil)).Elem(), true},
    47  	{reflect.TypeOf((*mo.VirtualMachine)(nil)).Elem(), false},
    48  	{reflect.TypeOf((*mo.Datastore)(nil)).Elem(), false},
    49  	{reflect.TypeOf((*mo.Network)(nil)).Elem(), false},
    50  	{reflect.TypeOf((*mo.OpaqueNetwork)(nil)).Elem(), false},
    51  	{reflect.TypeOf((*mo.DistributedVirtualPortgroup)(nil)).Elem(), false},
    52  	{reflect.TypeOf((*mo.DistributedVirtualSwitch)(nil)).Elem(), false},
    53  	{reflect.TypeOf((*mo.VmwareDistributedVirtualSwitch)(nil)).Elem(), false},
    54  }
    55  
    56  func (m *ViewManager) init(*Registry) {
    57  	m.entities = make(map[string]bool, len(entities))
    58  	for _, e := range entities {
    59  		m.entities[e.Type.Name()] = e.Container
    60  	}
    61  }
    62  
    63  func destroyView(ref types.ManagedObjectReference) soap.HasFault {
    64  	return &methods.DestroyViewBody{
    65  		Res: &types.DestroyViewResponse{},
    66  	}
    67  }
    68  
    69  func (m *ViewManager) CreateContainerView(ctx *Context, req *types.CreateContainerView) soap.HasFault {
    70  	body := &methods.CreateContainerViewBody{}
    71  
    72  	root := ctx.Map.Get(req.Container)
    73  	if root == nil {
    74  		body.Fault_ = Fault("", &types.ManagedObjectNotFound{Obj: req.Container})
    75  		return body
    76  	}
    77  
    78  	if !m.entities[root.Reference().Type] {
    79  		body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "container"})
    80  		return body
    81  	}
    82  
    83  	container := &ContainerView{
    84  		mo.ContainerView{
    85  			Container: root.Reference(),
    86  			Recursive: req.Recursive,
    87  			Type:      req.Type,
    88  		},
    89  		root,
    90  		make(map[string]bool),
    91  	}
    92  
    93  	for _, ctype := range container.Type {
    94  		if _, ok := m.entities[ctype]; !ok {
    95  			body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "type"})
    96  			return body
    97  		}
    98  
    99  		container.types[ctype] = true
   100  
   101  		for _, e := range entities {
   102  			// Check for embedded types
   103  			if f, ok := e.Type.FieldByName(ctype); ok && f.Anonymous {
   104  				container.types[e.Type.Name()] = true
   105  			}
   106  		}
   107  	}
   108  
   109  	ctx.Session.setReference(container)
   110  
   111  	body.Res = &types.CreateContainerViewResponse{
   112  		Returnval: container.Self,
   113  	}
   114  
   115  	seen := make(map[types.ManagedObjectReference]bool)
   116  	container.add(root, seen)
   117  
   118  	ctx.Session.Registry.Put(container)
   119  	ctx.Map.AddHandler(container)
   120  
   121  	return body
   122  }
   123  
   124  type ContainerView struct {
   125  	mo.ContainerView
   126  
   127  	root  mo.Reference
   128  	types map[string]bool
   129  }
   130  
   131  func (v *ContainerView) DestroyView(ctx *Context, c *types.DestroyView) soap.HasFault {
   132  	ctx.Map.RemoveHandler(v)
   133  	ctx.Session.Remove(ctx, c.This)
   134  	return destroyView(c.This)
   135  }
   136  
   137  func (v *ContainerView) include(o types.ManagedObjectReference) bool {
   138  	if len(v.types) == 0 {
   139  		return true
   140  	}
   141  
   142  	return v.types[o.Type]
   143  }
   144  
   145  func walk(root mo.Reference, f func(child types.ManagedObjectReference)) {
   146  	if _, ok := root.(types.ManagedObjectReference); ok || root == nil {
   147  		return
   148  	}
   149  
   150  	var children []types.ManagedObjectReference
   151  
   152  	switch e := getManagedObject(root).Addr().Interface().(type) {
   153  	case *mo.Datacenter:
   154  		children = []types.ManagedObjectReference{e.VmFolder, e.HostFolder, e.DatastoreFolder, e.NetworkFolder}
   155  	case *mo.Folder:
   156  		children = e.ChildEntity
   157  	case *mo.StoragePod:
   158  		children = e.ChildEntity
   159  	case *mo.ComputeResource:
   160  		children = e.Host
   161  		children = append(children, *e.ResourcePool)
   162  	case *mo.ClusterComputeResource:
   163  		children = e.Host
   164  		children = append(children, *e.ResourcePool)
   165  	case *mo.ResourcePool:
   166  		children = e.ResourcePool
   167  		children = append(children, e.Vm...)
   168  	case *mo.VirtualApp:
   169  		children = e.ResourcePool.ResourcePool
   170  		children = append(children, e.Vm...)
   171  	case *mo.HostSystem:
   172  		children = e.Vm
   173  	}
   174  
   175  	for _, child := range children {
   176  		f(child)
   177  	}
   178  }
   179  
   180  func (v *ContainerView) add(root mo.Reference, seen map[types.ManagedObjectReference]bool) {
   181  	walk(root, func(child types.ManagedObjectReference) {
   182  		if v.include(child) {
   183  			if !seen[child] {
   184  				seen[child] = true
   185  				v.View = append(v.View, child)
   186  			}
   187  		}
   188  
   189  		if v.Recursive {
   190  			v.add(Map.Get(child), seen)
   191  		}
   192  	})
   193  }
   194  
   195  func (v *ContainerView) find(root mo.Reference, ref types.ManagedObjectReference, found *bool) bool {
   196  	walk(root, func(child types.ManagedObjectReference) {
   197  		if *found {
   198  			return
   199  		}
   200  		if child == ref {
   201  			*found = true
   202  			return
   203  		}
   204  		if v.Recursive {
   205  			*found = v.find(Map.Get(child), ref, found)
   206  		}
   207  	})
   208  
   209  	return *found
   210  }
   211  
   212  func (v *ContainerView) PutObject(obj mo.Reference) {
   213  	ref := obj.Reference()
   214  
   215  	if v.include(ref) && v.find(v.root, ref, types.NewBool(false)) {
   216  		Map.Update(v, []types.PropertyChange{{Name: "view", Val: append(v.View, ref)}})
   217  	}
   218  }
   219  
   220  func (v *ContainerView) RemoveObject(ctx *Context, obj types.ManagedObjectReference) {
   221  	ctx.Map.RemoveReference(ctx, v, &v.View, obj)
   222  }
   223  
   224  func (*ContainerView) UpdateObject(mo.Reference, []types.PropertyChange) {}
   225  
   226  func (m *ViewManager) CreateListView(ctx *Context, req *types.CreateListView) soap.HasFault {
   227  	body := new(methods.CreateListViewBody)
   228  	list := new(ListView)
   229  
   230  	if refs := list.add(ctx, req.Obj); len(refs) != 0 {
   231  		body.Fault_ = Fault("", &types.ManagedObjectNotFound{Obj: refs[0]})
   232  		return body
   233  	}
   234  
   235  	ctx.Session.Put(list)
   236  
   237  	body.Res = &types.CreateListViewResponse{
   238  		Returnval: list.Self,
   239  	}
   240  
   241  	return body
   242  }
   243  
   244  type ListView struct {
   245  	mo.ListView
   246  }
   247  
   248  func (v *ListView) update(ctx *Context) {
   249  	ctx.Map.Update(v, []types.PropertyChange{{Name: "view", Val: v.View}})
   250  }
   251  
   252  func (v *ListView) add(ctx *Context, refs []types.ManagedObjectReference) []types.ManagedObjectReference {
   253  	var unresolved []types.ManagedObjectReference
   254  	for _, ref := range refs {
   255  		obj := ctx.Session.Get(ref)
   256  		if obj == nil {
   257  			unresolved = append(unresolved, ref)
   258  		}
   259  		v.View = append(v.View, ref)
   260  	}
   261  	return unresolved
   262  }
   263  
   264  func (v *ListView) DestroyView(ctx *Context, c *types.DestroyView) soap.HasFault {
   265  	ctx.Session.Remove(ctx, c.This)
   266  	return destroyView(c.This)
   267  }
   268  
   269  func (v *ListView) ModifyListView(ctx *Context, req *types.ModifyListView) soap.HasFault {
   270  	body := &methods.ModifyListViewBody{
   271  		Res: new(types.ModifyListViewResponse),
   272  	}
   273  
   274  	body.Res.Returnval = v.add(ctx, req.Add)
   275  
   276  	for _, ref := range req.Remove {
   277  		RemoveReference(&v.View, ref)
   278  		if ctx.Map.Get(ref) == nil {
   279  			body.Res.Returnval = append(body.Res.Returnval, ref)
   280  		}
   281  	}
   282  
   283  	if len(req.Remove) != 0 || len(req.Add) != 0 {
   284  		v.update(ctx)
   285  	}
   286  
   287  	return body
   288  }
   289  
   290  func (v *ListView) ResetListView(ctx *Context, req *types.ResetListView) soap.HasFault {
   291  	body := &methods.ResetListViewBody{
   292  		Res: new(types.ResetListViewResponse),
   293  	}
   294  
   295  	v.View = nil
   296  
   297  	body.Res.Returnval = v.add(ctx, req.Obj)
   298  
   299  	v.update(ctx)
   300  
   301  	return body
   302  }