github.com/vmware/govmomi@v0.37.2/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 := ctx.Map.Get(ref).(*VirtualMachine)
   166  
   167  			// This task creates multiple subtasks which violates the assumption
   168  			// of 1:1 Context:Task, which results in data races in objects
   169  			// like the Simulator.Event manager. This is the minimum context
   170  			// required for the PowerOnVMTask to complete.
   171  			taskCtx := &Context{
   172  				Context: ctx.Context,
   173  				Session: ctx.Session,
   174  				Map:     ctx.Map,
   175  			}
   176  
   177  			// NOTE: Simulator does not actually perform any specific host-level placement
   178  			// (equivalent to vSphere DRS).
   179  			taskCtx.WithLock(vm, func() {
   180  				vmTaskBody := vm.PowerOnVMTask(taskCtx, &types.PowerOnVM_Task{}).(*methods.PowerOnVM_TaskBody)
   181  				res.Attempted = append(res.Attempted, types.ClusterAttemptedVmInfo{Vm: ref, Task: &vmTaskBody.Res.Returnval})
   182  			})
   183  		}
   184  
   185  		return res, nil
   186  	})
   187  
   188  	return &methods.PowerOnMultiVM_TaskBody{
   189  		Res: &types.PowerOnMultiVM_TaskResponse{
   190  			Returnval: task.Run(ctx),
   191  		},
   192  	}
   193  }
   194  
   195  func (d *Datacenter) DestroyTask(ctx *Context, req *types.Destroy_Task) soap.HasFault {
   196  	task := CreateTask(d, "destroy", func(t *Task) (types.AnyType, types.BaseMethodFault) {
   197  		folders := []types.ManagedObjectReference{
   198  			d.VmFolder,
   199  			d.HostFolder,
   200  		}
   201  
   202  		for _, ref := range folders {
   203  			f, _ := asFolderMO(ctx.Map.Get(ref))
   204  			if len(f.ChildEntity) != 0 {
   205  				return nil, &types.ResourceInUse{}
   206  			}
   207  		}
   208  
   209  		p, _ := asFolderMO(ctx.Map.Get(*d.Parent))
   210  		folderRemoveChild(ctx, p, d.Self)
   211  
   212  		return nil, nil
   213  	})
   214  
   215  	return &methods.Destroy_TaskBody{
   216  		Res: &types.Destroy_TaskResponse{
   217  			Returnval: task.Run(ctx),
   218  		},
   219  	}
   220  }