github.com/vmware/govmomi@v0.51.0/eam/simulator/agent.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 "fmt" 9 "log" 10 "time" 11 12 "github.com/google/uuid" 13 14 "github.com/vmware/govmomi/simulator" 15 "github.com/vmware/govmomi/vim25" 16 vimmethods "github.com/vmware/govmomi/vim25/methods" 17 "github.com/vmware/govmomi/vim25/soap" 18 vim "github.com/vmware/govmomi/vim25/types" 19 20 "github.com/vmware/govmomi/eam/internal" 21 "github.com/vmware/govmomi/eam/methods" 22 "github.com/vmware/govmomi/eam/mo" 23 "github.com/vmware/govmomi/eam/types" 24 ) 25 26 // Agenct is the vSphere ESX Agent Manager managed object responsible 27 // fordeploying an Agency on a single host. The Agent maintains the state 28 // of the current deployment in its runtime information 29 type Agent struct { 30 EamObject 31 mo.Agent 32 } 33 34 type AgentVMPlacementOptions struct { 35 computeResource vim.ManagedObjectReference 36 datacenter vim.ManagedObjectReference 37 datastore vim.ManagedObjectReference 38 folder vim.ManagedObjectReference 39 host vim.ManagedObjectReference 40 network vim.ManagedObjectReference 41 pool vim.ManagedObjectReference 42 } 43 44 // NewAgent returns a new Agent as if CreateAgency were called on the 45 // EsxAgentManager object. 46 func NewAgent( 47 ctx *simulator.Context, 48 agency vim.ManagedObjectReference, 49 config types.AgentConfigInfo, 50 vmName string, 51 vmPlacement AgentVMPlacementOptions) (*Agent, vim.BaseMethodFault) { 52 vimCtx := ctx.For(vim25.Path) 53 vimMap := vimCtx.Map 54 55 agent := &Agent{ 56 EamObject: EamObject{ 57 Self: vim.ManagedObjectReference{ 58 Type: internal.Agent, 59 Value: uuid.New().String(), 60 }, 61 }, 62 Agent: mo.Agent{ 63 Config: config, 64 Runtime: types.AgentRuntimeInfo{ 65 Agency: &agency, 66 VmName: vmName, 67 Host: &vmPlacement.host, 68 EsxAgentFolder: &vmPlacement.folder, 69 EsxAgentResourcePool: &vmPlacement.pool, 70 }, 71 }, 72 } 73 74 // Register the agent with the registry in order for the agent to start 75 // receiving API calls from clients. 76 ctx.Map.Put(agent) 77 78 createVm := func() (vim.ManagedObjectReference, *vim.LocalizedMethodFault) { 79 var vmRef vim.ManagedObjectReference 80 81 // vmExtraConfig is used when creating the VM for this agent. 82 vmExtraConfig := []vim.BaseOptionValue{} 83 84 // If config.OvfPackageUrl is non-empty and does not appear to point to 85 // a local file or an HTTP URI, then assume it is a container. 86 if url := config.OvfPackageUrl; url != "" && !fsOrHTTPRx.MatchString(url) { 87 vmExtraConfig = append( 88 vmExtraConfig, 89 &vim.OptionValue{ 90 Key: "RUN.container", 91 Value: url, 92 }) 93 } 94 95 // Copy the OVF environment properties into the VM's ExtraConfig property. 96 if ovfEnv := config.OvfEnvironment; ovfEnv != nil { 97 for _, ovfProp := range ovfEnv.OvfProperty { 98 vmExtraConfig = append( 99 vmExtraConfig, 100 &vim.OptionValue{ 101 Key: ovfProp.Key, 102 Value: ovfProp.Value, 103 }) 104 } 105 } 106 107 datastore := vimMap.Get(vmPlacement.datastore).(*simulator.Datastore) 108 vmPathName := fmt.Sprintf("[%[1]s] %[2]s/%[2]s.vmx", datastore.Name, vmName) 109 vmConfigSpec := vim.VirtualMachineConfigSpec{ 110 Name: vmName, 111 ExtraConfig: vmExtraConfig, 112 Files: &vim.VirtualMachineFileInfo{ 113 VmPathName: vmPathName, 114 }, 115 } 116 117 // Create the VM for this agent. 118 vmFolder := vimMap.Get(vmPlacement.folder).(*simulator.Folder) 119 createVmTaskRef := vmFolder.CreateVMTask(vimCtx, &vim.CreateVM_Task{ 120 This: vmFolder.Self, 121 Config: vmConfigSpec, 122 Pool: vmPlacement.pool, 123 Host: &vmPlacement.host, 124 }).(*vimmethods.CreateVM_TaskBody).Res.Returnval 125 createVmTask := vimMap.Get(createVmTaskRef).(*simulator.Task) 126 127 // Wait for the task to complete and see if there is an error. 128 createVmTask.Wait() 129 if createVmTask.Info.Error != nil { 130 return vmRef, createVmTask.Info.Error 131 } 132 133 vmRef = createVmTask.Info.Result.(vim.ManagedObjectReference) 134 vm := vimMap.Get(vmRef).(*simulator.VirtualMachine) 135 log.Printf("created agent vm: MoRef=%v, Name=%s", vm.Self, vm.Name) 136 137 // Link the agent to this VM. 138 agent.Runtime.Vm = &vm.Self 139 140 return vm.Self, nil 141 } 142 143 vmRef, err := createVm() 144 if err != nil { 145 return nil, &vim.RuntimeFault{ 146 MethodFault: vim.MethodFault{ 147 FaultCause: err, 148 }, 149 } 150 } 151 152 // Start watching this VM and updating the agent's information about the VM. 153 go func(ctx *simulator.Context, eamReg, vimReg *simulator.Registry) { 154 var ( 155 ticker = time.NewTicker(1 * time.Second) 156 vmName string 157 ) 158 for range ticker.C { 159 eamReg.WithLock(ctx, agent.Self, func() { 160 agentObj := eamReg.Get(agent.Self) 161 if agentObj == nil { 162 log.Printf("not found: %v", agent.Self) 163 // If the agent no longer exists then stop watching it. 164 ticker.Stop() 165 return 166 } 167 168 updateAgent := func(vm *simulator.VirtualMachine) { 169 if vmName == "" { 170 vmName = vm.Config.Name 171 } 172 173 // Update the agent's properties from the VM. 174 agent := agentObj.(*Agent) 175 agent.Runtime.VmPowerState = vm.Runtime.PowerState 176 if guest := vm.Summary.Guest; guest == nil { 177 agent.Runtime.VmIp = "" 178 } else { 179 agent.Runtime.VmIp = guest.IpAddress 180 } 181 } 182 183 vimReg.WithLock(ctx, vmRef, func() { 184 if vmObj := vimReg.Get(vmRef); vmObj != nil { 185 updateAgent(vmObj.(*simulator.VirtualMachine)) 186 } else { 187 // If the VM no longer exists then create a new agent VM. 188 log.Printf( 189 "creating new agent vm: %v, %v, vmName=%s", 190 agent.Self, vmRef, vmName) 191 192 newVmRef, err := createVm() 193 if err != nil { 194 log.Printf( 195 "failed to create new agent vm: %v, %v, vmName=%s, err=%v", 196 agent.Self, vmRef, vmName, *err) 197 ticker.Stop() 198 return 199 } 200 201 // Make sure the vmRef variable is assigned to the new 202 // VM's reference for the next time through this loop. 203 vmRef = newVmRef 204 205 // Get a lock for the *new* VM. 206 vimReg.WithLock(ctx, vmRef, func() { 207 vmObj = vimReg.Get(vmRef) 208 if vmObj == nil { 209 log.Printf("not found: %v", vmRef) 210 ticker.Stop() 211 return 212 } 213 updateAgent(vmObj.(*simulator.VirtualMachine)) 214 }) 215 } 216 217 }) 218 }) 219 } 220 }(vimCtx, ctx.Map, vimMap) 221 222 return agent, nil 223 } 224 225 func (m *Agent) AgentQueryConfig( 226 ctx *simulator.Context, 227 req *types.AgentQueryConfig) soap.HasFault { 228 229 return &methods.AgentQueryConfigBody{ 230 Res: &types.AgentQueryConfigResponse{ 231 Returnval: m.Config, 232 }, 233 } 234 } 235 236 func (m *Agent) AgentQueryRuntime( 237 ctx *simulator.Context, 238 req *types.AgentQueryRuntime) soap.HasFault { 239 240 return &methods.AgentQueryRuntimeBody{ 241 Res: &types.AgentQueryRuntimeResponse{ 242 Returnval: m.Runtime, 243 }, 244 } 245 } 246 247 func (m *Agent) MarkAsAvailable( 248 ctx *simulator.Context, 249 req *types.MarkAsAvailable) soap.HasFault { 250 251 return &methods.MarkAsAvailableBody{ 252 Res: &types.MarkAsAvailableResponse{}, 253 } 254 }