|
41 | 41 | import org.apache.cloudstack.framework.jobs.AsyncJobConstants; |
42 | 42 | import org.apache.cloudstack.framework.jobs.AsyncJobManager; |
43 | 43 | import org.apache.cloudstack.framework.messagebus.MessageBus; |
| 44 | +import org.apache.cloudstack.framework.messagebus.MessageDispatcher; |
| 45 | +import org.apache.cloudstack.framework.messagebus.MessageHandler; |
44 | 46 | import org.apache.cloudstack.messagebus.TopicConstants; |
45 | 47 | import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; |
46 | 48 | import org.apache.cloudstack.vm.jobs.VmWorkJobDao; |
@@ -238,6 +240,9 @@ public void setHostAllocators(List<HostAllocator> hostAllocators) { |
238 | 240 | protected ClusterDetailsDao _clusterDetailsDao; |
239 | 241 | @Inject |
240 | 242 | protected UserVmDetailsDao _uservmDetailsDao; |
| 243 | + |
| 244 | + @Inject |
| 245 | + protected VMInstanceDao _instanceDao; |
241 | 246 |
|
242 | 247 | @Inject |
243 | 248 | protected ConfigurationDao _configDao; |
@@ -427,14 +432,17 @@ public void advanceExpunge(String vmUuid) throws ResourceUnavailableException, O |
427 | 432 |
|
428 | 433 | _vmDao.remove(vm.getId()); |
429 | 434 | } |
| 435 | + |
| 436 | + |
430 | 437 |
|
431 | 438 | @Override |
432 | 439 | public boolean start() { |
433 | 440 | _executor.scheduleAtFixedRate(new CleanupTask(), _cleanupInterval, _cleanupInterval, TimeUnit.SECONDS); |
434 | 441 | cancelWorkItems(_nodeId); |
| 442 | + |
435 | 443 | return true; |
436 | 444 | } |
437 | | - |
| 445 | + |
438 | 446 | @Override |
439 | 447 | public boolean stop() { |
440 | 448 | return true; |
@@ -469,6 +477,9 @@ public boolean configure(String name, Map<String, Object> xmlParams) throws Conf |
469 | 477 | .and(rvsEntity.getInstanceId(), SearchCriteria.Op.EQ, "instance") |
470 | 478 | .and(rvsEntity.getDeviceId(), SearchCriteria.Op.EQ).values(0) |
471 | 479 | .done(); |
| 480 | + |
| 481 | + |
| 482 | + _messageBus.subscribe(TopicConstants.VM_POWER_STATE, MessageDispatcher.getDispatcher(this)); |
472 | 483 |
|
473 | 484 | return true; |
474 | 485 | } |
@@ -1311,176 +1322,6 @@ public void orchestrateStop(String vmUuid, boolean forced) throws AgentUnavailab |
1311 | 1322 | } |
1312 | 1323 | } |
1313 | 1324 |
|
1314 | | - /* |
1315 | | - @Override |
1316 | | - public boolean advanceStop(String vmUuid, boolean forced, User user, Account account) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException { |
1317 | | - State state = vm.getState(); |
1318 | | - if (state == State.Stopped) { |
1319 | | - if (s_logger.isDebugEnabled()) { |
1320 | | - s_logger.debug("VM is already stopped: " + vm); |
1321 | | - } |
1322 | | - return true; |
1323 | | - } |
1324 | | -
|
1325 | | - if (state == State.Destroyed || state == State.Expunging || state == State.Error) { |
1326 | | - if (s_logger.isDebugEnabled()) { |
1327 | | - s_logger.debug("Stopped called on " + vm + " but the state is " + state); |
1328 | | - } |
1329 | | - return true; |
1330 | | - } |
1331 | | - // grab outstanding work item if any |
1332 | | - VmWorkJobVO work = _workDao.findByOutstandingWork(vm.getId(), vm.getState()); |
1333 | | - if (work != null) { |
1334 | | - if (s_logger.isDebugEnabled()) { |
1335 | | - s_logger.debug("Found an outstanding work item for this vm " + vm + " with state:" + vm.getState() + ", work id:" + work.getId()); |
1336 | | - } |
1337 | | - } |
1338 | | - Long hostId = vm.getHostId(); |
1339 | | - if (hostId == null) { |
1340 | | - if (!forced) { |
1341 | | - if (s_logger.isDebugEnabled()) { |
1342 | | - s_logger.debug("HostId is null but this is not a forced stop, cannot stop vm " + vm + " with state:" + vm.getState()); |
1343 | | - } |
1344 | | - return false; |
1345 | | - } |
1346 | | - try { |
1347 | | - stateTransitTo(vm, Event.AgentReportStopped, null, null); |
1348 | | - } catch (NoTransitionException e) { |
1349 | | - s_logger.warn(e.getMessage()); |
1350 | | - } |
1351 | | - // mark outstanding work item if any as done |
1352 | | - if (work != null) { |
1353 | | - if (s_logger.isDebugEnabled()) { |
1354 | | - s_logger.debug("Updating work item to Done, id:" + work.getId()); |
1355 | | - } |
1356 | | - work.setStep(Step.Done); |
1357 | | - _workDao.update(work.getId(), work); |
1358 | | - } |
1359 | | - return true; |
1360 | | - } |
1361 | | -
|
1362 | | - VirtualMachineGuru<T> vmGuru = getVmGuru(vm); |
1363 | | - VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); |
1364 | | -
|
1365 | | - try { |
1366 | | - if (!stateTransitTo(vm, Event.StopRequested, vm.getHostId())) { |
1367 | | - throw new ConcurrentOperationException("VM is being operated on."); |
1368 | | - } |
1369 | | - } catch (NoTransitionException e1) { |
1370 | | - if (!forced) { |
1371 | | - throw new CloudRuntimeException("We cannot stop " + vm + " when it is in state " + vm.getState()); |
1372 | | - } |
1373 | | - boolean doCleanup = false; |
1374 | | - if (s_logger.isDebugEnabled()) { |
1375 | | - s_logger.debug("Unable to transition the state but we're moving on because it's forced stop"); |
1376 | | - } |
1377 | | - if (state == State.Starting || state == State.Migrating) { |
1378 | | - if (work != null) { |
1379 | | - doCleanup = true; |
1380 | | - } else { |
1381 | | - if (s_logger.isDebugEnabled()) { |
1382 | | - s_logger.debug("Unable to cleanup VM: " + vm + " ,since outstanding work item is not found"); |
1383 | | - } |
1384 | | - throw new CloudRuntimeException("Work item not found, We cannot stop " + vm + " when it is in state " + vm.getState()); |
1385 | | - } |
1386 | | - } else if (state == State.Stopping) { |
1387 | | - doCleanup = true; |
1388 | | - } |
1389 | | -
|
1390 | | - if (doCleanup) { |
1391 | | - if (cleanup(vmGuru, new VirtualMachineProfileImpl(vm), work, Event.StopRequested, forced, user, account)) { |
1392 | | - try { |
1393 | | - if (s_logger.isDebugEnabled()) { |
1394 | | - s_logger.debug("Updating work item to Done, id:" + work.getId()); |
1395 | | - } |
1396 | | - return changeState(vm, Event.AgentReportStopped, null, work, Step.Done); |
1397 | | - } catch (NoTransitionException e) { |
1398 | | - s_logger.warn("Unable to cleanup " + vm); |
1399 | | - return false; |
1400 | | - } |
1401 | | - } else { |
1402 | | - if (s_logger.isDebugEnabled()) { |
1403 | | - s_logger.debug("Failed to cleanup VM: " + vm); |
1404 | | - } |
1405 | | - throw new CloudRuntimeException("Failed to cleanup " + vm + " , current state " + vm.getState()); |
1406 | | - } |
1407 | | - } |
1408 | | - } |
1409 | | -
|
1410 | | - if (vm.getState() != State.Stopping) { |
1411 | | - throw new CloudRuntimeException("We cannot proceed with stop VM " + vm + " since it is not in 'Stopping' state, current state: " + vm.getState()); |
1412 | | - } |
1413 | | -
|
1414 | | - vmGuru.prepareStop(profile); |
1415 | | - |
1416 | | - StopCommand stop = new StopCommand(vm); |
1417 | | - boolean stopped = false; |
1418 | | - StopAnswer answer = null; |
1419 | | - try { |
1420 | | - answer = (StopAnswer) _agentMgr.send(vm.getHostId(), stop); |
1421 | | - stopped = answer.getResult(); |
1422 | | - if (!stopped) { |
1423 | | - throw new CloudRuntimeException("Unable to stop the virtual machine due to " + answer.getDetails()); |
1424 | | - } |
1425 | | - vmGuru.finalizeStop(profile, answer); |
1426 | | -
|
1427 | | - } catch (AgentUnavailableException e) { |
1428 | | - s_logger.warn("Unable to stop vm, agent unavailable: " + e.toString()); |
1429 | | - } catch (OperationTimedoutException e) { |
1430 | | - s_logger.warn("Unable to stop vm, operation timed out: " + e.toString()); |
1431 | | - } finally { |
1432 | | - if (!stopped) { |
1433 | | - if (!forced) { |
1434 | | - s_logger.warn("Unable to stop vm " + vm); |
1435 | | - try { |
1436 | | - stateTransitTo(vm, Event.OperationFailed, vm.getHostId()); |
1437 | | - } catch (NoTransitionException e) { |
1438 | | - s_logger.warn("Unable to transition the state " + vm); |
1439 | | - } |
1440 | | - return false; |
1441 | | - } else { |
1442 | | - s_logger.warn("Unable to actually stop " + vm + " but continue with release because it's a force stop"); |
1443 | | - vmGuru.finalizeStop(profile, answer); |
1444 | | - } |
1445 | | - } |
1446 | | - } |
1447 | | -
|
1448 | | - if (s_logger.isDebugEnabled()) { |
1449 | | - s_logger.debug(vm + " is stopped on the host. Proceeding to release resource held."); |
1450 | | - } |
1451 | | -
|
1452 | | - try { |
1453 | | - _networkMgr.release(profile, forced); |
1454 | | - s_logger.debug("Successfully released network resources for the vm " + vm); |
1455 | | - } catch (Exception e) { |
1456 | | - s_logger.warn("Unable to release some network resources.", e); |
1457 | | - } |
1458 | | -
|
1459 | | - try { |
1460 | | - if (vm.getHypervisorType() != HypervisorType.BareMetal) { |
1461 | | - this.volumeMgr.release(profile); |
1462 | | - s_logger.debug("Successfully released storage resources for the vm " + vm); |
1463 | | - } |
1464 | | - } catch (Exception e) { |
1465 | | - s_logger.warn("Unable to release storage resources.", e); |
1466 | | - } |
1467 | | -
|
1468 | | - try { |
1469 | | - if (work != null) { |
1470 | | - if (s_logger.isDebugEnabled()) { |
1471 | | - s_logger.debug("Updating the outstanding work item to Done, id:" + work.getId()); |
1472 | | - } |
1473 | | - work.setStep(Step.Done); |
1474 | | - _workDao.update(work.getId(), work); |
1475 | | - } |
1476 | | -
|
1477 | | - return stateTransitTo(vm, Event.OperationSucceeded, null); |
1478 | | - } catch (NoTransitionException e) { |
1479 | | - s_logger.warn(e.getMessage()); |
1480 | | - return false; |
1481 | | - } |
1482 | | - } |
1483 | | - */ |
1484 | 1325 | private void setStateMachine() { |
1485 | 1326 | _stateMachine = VirtualMachine.State.getStateMachine(); |
1486 | 1327 | } |
@@ -3569,5 +3410,101 @@ public boolean reConfigureVm(VirtualMachine vm, ServiceOffering oldServiceOfferi |
3569 | 3410 | return false; |
3570 | 3411 |
|
3571 | 3412 | } |
| 3413 | + |
| 3414 | + @MessageHandler(topic=TopicConstants.VM_POWER_STATE) |
| 3415 | + private void HandlePownerStateReport(Object target, String subject, String senderAddress, Object args) { |
| 3416 | + assert(args != null); |
| 3417 | + Long vmId = (Long)args; |
| 3418 | + |
| 3419 | + List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs( |
| 3420 | + VirtualMachine.Type.Instance, vmId); |
| 3421 | + if(pendingWorkJobs.size() == 0) { |
| 3422 | + // there is no pending operation job |
| 3423 | + VMInstanceVO vm = _instanceDao.findById(vmId); |
| 3424 | + if(vm != null) { |
| 3425 | + switch(vm.getPowerState()) { |
| 3426 | + case PowerOn : |
| 3427 | + HandlePowerOnReportWithNoPendingJobsOnVM(vm); |
| 3428 | + break; |
| 3429 | + |
| 3430 | + case PowerOff : |
| 3431 | + HandlePowerOffReportWithNoPendingJobsOnVM(vm); |
| 3432 | + break; |
| 3433 | + |
| 3434 | + // PowerUnknown shouldn't be reported, it is a derived |
| 3435 | + // VM power state from host state (host un-reachable |
| 3436 | + case PowerUnknown : |
| 3437 | + default : |
| 3438 | + assert(false); |
| 3439 | + break; |
| 3440 | + } |
| 3441 | + } else { |
| 3442 | + s_logger.warn("VM " + vmId + " no longer exists when processing VM state report"); |
| 3443 | + } |
| 3444 | + } else { |
| 3445 | + // TODO, wake-up signalling |
| 3446 | + } |
| 3447 | + } |
| 3448 | + |
| 3449 | + private void HandlePowerOnReportWithNoPendingJobsOnVM(VMInstanceVO vm) { |
3572 | 3450 |
|
| 3451 | + // TODO : |
| 3452 | + // 1) handle left-over transitional VM states |
| 3453 | + // 2) handle out of band VM live migration |
| 3454 | + // 3) handle out of sync stationary states, marking VM from Stopped to Running with |
| 3455 | + // alert messages |
| 3456 | + |
| 3457 | + switch(vm.getState()) { |
| 3458 | + case Starting: |
| 3459 | + break; |
| 3460 | + |
| 3461 | + case Running : |
| 3462 | + break; |
| 3463 | + |
| 3464 | + case Stopping : |
| 3465 | + case Stopped : |
| 3466 | + break; |
| 3467 | + |
| 3468 | + case Destroyed : |
| 3469 | + case Expunging : |
| 3470 | + break; |
| 3471 | + |
| 3472 | + case Migrating : |
| 3473 | + break; |
| 3474 | + |
| 3475 | + case Error : |
| 3476 | + default : |
| 3477 | + break; |
| 3478 | + } |
| 3479 | + } |
| 3480 | + |
| 3481 | + private void HandlePowerOffReportWithNoPendingJobsOnVM(VMInstanceVO vm) { |
| 3482 | + |
| 3483 | + // TODO : |
| 3484 | + // 1) handle left-over transitional VM states |
| 3485 | + // 2) handle out of sync stationary states, schedule force-stop to release resources |
| 3486 | + // |
| 3487 | + switch(vm.getState()) { |
| 3488 | + case Starting: |
| 3489 | + break; |
| 3490 | + |
| 3491 | + case Running : |
| 3492 | + break; |
| 3493 | + |
| 3494 | + case Stopping : |
| 3495 | + case Stopped : |
| 3496 | + break; |
| 3497 | + |
| 3498 | + case Destroyed : |
| 3499 | + case Expunging : |
| 3500 | + break; |
| 3501 | + |
| 3502 | + case Migrating : |
| 3503 | + break; |
| 3504 | + |
| 3505 | + case Error : |
| 3506 | + default : |
| 3507 | + break; |
| 3508 | + } |
| 3509 | + } |
3573 | 3510 | } |
0 commit comments