github.com/vmware/govmomi@v0.43.0/simulator/datacenter.go (about)

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