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

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