github.com/vmware/govmomi@v0.51.0/simulator/datacenter.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  	"log"
     9  	"strings"
    10  
    11  	"github.com/vmware/govmomi/simulator/esx"
    12  	"github.com/vmware/govmomi/vim25/methods"
    13  	"github.com/vmware/govmomi/vim25/mo"
    14  	"github.com/vmware/govmomi/vim25/soap"
    15  	"github.com/vmware/govmomi/vim25/types"
    16  )
    17  
    18  type Datacenter struct {
    19  	mo.Datacenter
    20  
    21  	isESX bool
    22  }
    23  
    24  // NewDatacenter creates a Datacenter and its child folders.
    25  func NewDatacenter(ctx *Context, f *mo.Folder) *Datacenter {
    26  	dc := &Datacenter{
    27  		isESX: f.Self == esx.RootFolder.Self,
    28  	}
    29  
    30  	if dc.isESX {
    31  		dc.Datacenter = esx.Datacenter
    32  	}
    33  
    34  	folderPutChild(ctx, f, dc)
    35  
    36  	dc.createFolders(ctx)
    37  
    38  	return dc
    39  }
    40  
    41  func (dc *Datacenter) RenameTask(ctx *Context, r *types.Rename_Task) soap.HasFault {
    42  	return RenameTask(ctx, dc, r)
    43  }
    44  
    45  // Create Datacenter Folders.
    46  // Every Datacenter has 4 inventory Folders: Vm, Host, Datastore and Network.
    47  // The ESX folder child types are limited to 1 type.
    48  // The VC folders have additional child types, including nested folders.
    49  func (dc *Datacenter) createFolders(ctx *Context) {
    50  	folders := []struct {
    51  		ref   *types.ManagedObjectReference
    52  		name  string
    53  		types []string
    54  	}{
    55  		{&dc.VmFolder, "vm", []string{"VirtualMachine", "VirtualApp", "Folder"}},
    56  		{&dc.HostFolder, "host", []string{"ComputeResource", "Folder"}},
    57  		{&dc.DatastoreFolder, "datastore", []string{"Datastore", "StoragePod", "Folder"}},
    58  		{&dc.NetworkFolder, "network", []string{"Network", "DistributedVirtualSwitch", "Folder"}},
    59  	}
    60  
    61  	for _, f := range folders {
    62  		folder := &Folder{}
    63  		folder.Name = f.name
    64  
    65  		if dc.isESX {
    66  			folder.ChildType = f.types[:1]
    67  			folder.Self = *f.ref
    68  			ctx.Map.PutEntity(dc, folder)
    69  		} else {
    70  			folder.ChildType = f.types
    71  			e := ctx.Map.PutEntity(dc, folder)
    72  
    73  			// propagate the generated morefs to Datacenter
    74  			ref := e.Reference()
    75  			f.ref.Type = ref.Type
    76  			f.ref.Value = ref.Value
    77  		}
    78  	}
    79  
    80  	net := ctx.Map.Get(dc.NetworkFolder).(*Folder)
    81  
    82  	for _, ref := range esx.Datacenter.Network {
    83  		// Add VM Network by default to each Datacenter
    84  		network := &mo.Network{}
    85  		network.Self = ref
    86  		network.Name = strings.Split(ref.Value, "-")[1]
    87  		network.Entity().Name = network.Name
    88  		if !dc.isESX {
    89  			network.Self.Value = "" // we want a different moid per-DC
    90  		}
    91  
    92  		folderPutChild(ctx, &net.Folder, network)
    93  	}
    94  }
    95  
    96  func (dc *Datacenter) defaultNetwork() []types.ManagedObjectReference {
    97  	return dc.Network[:1] // VM Network
    98  }
    99  
   100  // folder returns the Datacenter folder that can contain the given object type
   101  func (dc *Datacenter) folder(ctx *Context, obj mo.Entity) *mo.Folder {
   102  	folders := []types.ManagedObjectReference{
   103  		dc.VmFolder,
   104  		dc.HostFolder,
   105  		dc.DatastoreFolder,
   106  		dc.NetworkFolder,
   107  	}
   108  	otype := getManagedObject(obj).Type()
   109  	rtype := obj.Reference().Type
   110  
   111  	for i := range folders {
   112  		folder, _ := asFolderMO(ctx.Map.Get(folders[i]))
   113  		for _, kind := range folder.ChildType {
   114  			if rtype == kind {
   115  				return folder
   116  			}
   117  			if f, ok := otype.FieldByName(kind); ok && f.Anonymous {
   118  				return folder
   119  			}
   120  		}
   121  	}
   122  
   123  	log.Panicf("failed to find folder for type=%s", rtype)
   124  	return nil
   125  }
   126  
   127  func datacenterEventArgument(ctx *Context, obj mo.Entity) *types.DatacenterEventArgument {
   128  	dc, ok := obj.(*Datacenter)
   129  	if !ok {
   130  		dc = ctx.Map.getEntityDatacenter(obj)
   131  	}
   132  	return &types.DatacenterEventArgument{
   133  		Datacenter:          dc.Self,
   134  		EntityEventArgument: types.EntityEventArgument{Name: dc.Name},
   135  	}
   136  }
   137  
   138  func (dc *Datacenter) PowerOnMultiVMTask(ctx *Context, req *types.PowerOnMultiVM_Task) soap.HasFault {
   139  	task := CreateTask(dc, "powerOnMultiVM", func(_ *Task) (types.AnyType, types.BaseMethodFault) {
   140  		if dc.isESX {
   141  			return nil, new(types.NotImplemented)
   142  		}
   143  
   144  		// Return per-VM tasks, structured as:
   145  		// thisTask.result - DC level task
   146  		//    +- []Attempted
   147  		//        +- subTask.result - VM level powerOn task result
   148  		//        +- ...
   149  		res := types.ClusterPowerOnVmResult{}
   150  		res.Attempted = []types.ClusterAttemptedVmInfo{}
   151  
   152  		for _, ref := range req.Vm {
   153  			vm, ok := ctx.Map.Get(ref).(*VirtualMachine)
   154  			if !ok {
   155  				continue
   156  			}
   157  			// This task creates multiple subtasks which violates the assumption
   158  			// of 1:1 Context:Task, which results in data races in objects
   159  			// like the Simulator.Event manager. This is the minimum context
   160  			// required for the PowerOnVMTask to complete.
   161  			taskCtx := &Context{
   162  				Context: ctx.Context,
   163  				Session: ctx.Session,
   164  				Map:     ctx.Map,
   165  			}
   166  
   167  			// NOTE: Simulator does not actually perform any specific host-level placement
   168  			// (equivalent to vSphere DRS).
   169  			taskCtx.WithLock(vm, func() {
   170  				vmTaskBody := vm.PowerOnVMTask(taskCtx, &types.PowerOnVM_Task{}).(*methods.PowerOnVM_TaskBody)
   171  				res.Attempted = append(res.Attempted, types.ClusterAttemptedVmInfo{Vm: ref, Task: &vmTaskBody.Res.Returnval})
   172  			})
   173  		}
   174  
   175  		return res, nil
   176  	})
   177  
   178  	return &methods.PowerOnMultiVM_TaskBody{
   179  		Res: &types.PowerOnMultiVM_TaskResponse{
   180  			Returnval: task.Run(ctx),
   181  		},
   182  	}
   183  }
   184  
   185  func (d *Datacenter) DestroyTask(ctx *Context, req *types.Destroy_Task) soap.HasFault {
   186  	task := CreateTask(d, "destroy", func(t *Task) (types.AnyType, types.BaseMethodFault) {
   187  		folders := []types.ManagedObjectReference{
   188  			d.VmFolder,
   189  			d.HostFolder,
   190  		}
   191  
   192  		for _, ref := range folders {
   193  			f, _ := asFolderMO(ctx.Map.Get(ref))
   194  			if len(f.ChildEntity) != 0 {
   195  				return nil, &types.ResourceInUse{}
   196  			}
   197  		}
   198  
   199  		p, _ := asFolderMO(ctx.Map.Get(*d.Parent))
   200  		folderRemoveChild(ctx, p, d.Self)
   201  
   202  		return nil, nil
   203  	})
   204  
   205  	return &methods.Destroy_TaskBody{
   206  		Res: &types.Destroy_TaskResponse{
   207  			Returnval: task.Run(ctx),
   208  		},
   209  	}
   210  }