@Override public void doPolling(Guid cmdId, List<Guid> childCmdIds) { RemoveVmPoolCommand<? extends VmPoolParametersBase> command = getCommand(cmdId); boolean anyFailed = false; for (Guid childCmdId : childCmdIds) { CommandEntity entity = CommandCoordinatorUtil.getCommandEntity(childCmdId); switch (entity.getCommandStatus()) { case ENDED_WITH_FAILURE: case FAILED: case EXECUTION_FAILED: case UNKNOWN: anyFailed = true; break; default: break; } } if (anyFailed) { command.setCommandStatus(CommandStatus.FAILED); } else { VmPool pool = DbFacade.getInstance().getVmPoolDao().get(command.getVmPoolId()); if (pool == null || pool.getRunningVmsCount() == 0) { command.setCommandStatus(CommandStatus.SUCCEEDED); } } }
@Override public CommandEntity mapRow(ResultSet resultSet, int rowNum) throws SQLException { CommandEntity result = new CommandEntity(); result.setUserId(Guid.createGuidFromString(resultSet.getString("user_id"))); result.setId(Guid.createGuidFromString(resultSet.getString("command_id"))); result.setJobId(Guid.createGuidFromString(resultSet.getString("job_id"))); result.setStepId(Guid.createGuidFromString(resultSet.getString("step_id"))); result.setCreatedAt(DbFacadeUtils.fromDate(resultSet.getTimestamp("created_at"))); result.setCommandType(VdcActionType.forValue(resultSet.getInt("command_type"))); result.setParentCommandId( Guid.createGuidFromString(resultSet.getString("parent_command_id"))); result.setRootCommandId( Guid.createGuidFromString(resultSet.getString("root_command_id"))); result.setCommandParameters( deserializeParameters( resultSet.getString("command_parameters"), resultSet.getString("command_params_class"))); result.setReturnValue( deserializeReturnValue( resultSet.getString("return_value"), resultSet.getString("return_value_class"))); result.setCommandStatus(getCommandStatus(resultSet.getString("status"))); result.setExecuted(resultSet.getBoolean("executed")); result.setCallbackEnabled(resultSet.getBoolean("callback_enabled")); result.setCallbackNotified(resultSet.getBoolean("callback_notified")); return result; }
@Override protected MapSqlParameterSource createFullParametersMapper(CommandEntity entity) { return getCustomMapSqlParameterSource() .addValue( "user_id", Guid.isNullOrEmpty(entity.getUserId()) ? Guid.Empty : entity.getUserId()) .addValue("command_id", Guid.isNullOrEmpty(entity.getId()) ? Guid.Empty : entity.getId()) .addValue("command_type", entity.getCommandType().getValue()) .addValue("parent_command_id", entity.getParentCommandId()) .addValue( "root_command_id", Guid.isNullOrEmpty(entity.getRootCommandId()) ? Guid.Empty : entity.getRootCommandId()) .addValue("job_id", Guid.isNullOrEmpty(entity.getJobId()) ? Guid.Empty : entity.getJobId()) .addValue( "step_id", Guid.isNullOrEmpty(entity.getStepId()) ? Guid.Empty : entity.getStepId()) .addValue("command_parameters", serializeParameters(entity.getCommandParameters())) .addValue( "command_params_class", entity.getCommandParameters() == null ? null : entity.getCommandParameters().getClass().getName()) .addValue("created_at", entity.getCreatedAt()) .addValue("status", entity.getCommandStatus().toString()) .addValue("executed", entity.isExecuted()) .addValue("callback_enabled", entity.isCallbackEnabled()) .addValue("return_value", serializeReturnValue(entity.getReturnValue())) .addValue( "return_value_class", entity.getReturnValue() == null ? null : entity.getReturnValue().getClass().getName()); }
public void proceedCommandExecution() { // Steps are executed such that: // a) all logic before the command runs is idempotent // b) the command is the last action in the step // This allows for recovery after a crash at any point during command execution. log.debug("Proceeding with execution of RemoveSnapshotSingleDiskLiveCommand"); if (getParameters().getCommandStep() == null) { getParameters().setCommandStep(getInitialMergeStepForImage(getParameters().getImageId())); getParameters().setChildCommands(new HashMap<RemoveSnapshotSingleDiskLiveStep, Guid>()); } // Upon recovery or after invoking a new child command, our map may be missing an entry syncChildCommandList(); Guid currentChildId = getCurrentChildId(); VdcReturnValueBase vdcReturnValue = null; if (currentChildId != null) { switch (CommandCoordinatorUtil.getCommandStatus(currentChildId)) { case ACTIVE: case NOT_STARTED: log.info( "Waiting on Live Merge command step '{}' to complete", getParameters().getCommandStep()); return; case SUCCEEDED: CommandEntity cmdEntity = CommandCoordinatorUtil.getCommandEntity(currentChildId); if (cmdEntity.isCallbackEnabled() && !cmdEntity.isCallbackNotified()) { log.info( "Waiting on Live Merge command step '{}' to finalize", getParameters().getCommandStep()); return; } vdcReturnValue = CommandCoordinatorUtil.getCommandReturnValue(currentChildId); if (vdcReturnValue != null && vdcReturnValue.getSucceeded()) { log.debug("Child command '{}' succeeded", getParameters().getCommandStep()); getParameters().setCommandStep(getParameters().getNextCommandStep()); break; } else { log.error( "Child command '{}' failed: {}", getParameters().getCommandStep(), (vdcReturnValue != null ? vdcReturnValue.getExecuteFailedMessages() : "null return value")); setCommandStatus(CommandStatus.FAILED); return; } case FAILED: case FAILED_RESTARTED: log.error("Failed child command status for step '{}'", getParameters().getCommandStep()); setCommandStatus(CommandStatus.FAILED); return; case UNKNOWN: log.error("Unknown child command status for step '{}'", getParameters().getCommandStep()); setCommandStatus(CommandStatus.FAILED); return; } } log.info("Executing Live Merge command step '{}'", getParameters().getCommandStep()); Pair<VdcActionType, ? extends VdcActionParametersBase> nextCommand = null; switch (getParameters().getCommandStep()) { case EXTEND: nextCommand = new Pair<>(VdcActionType.MergeExtend, buildMergeParameters()); getParameters().setNextCommandStep(RemoveSnapshotSingleDiskLiveStep.MERGE); break; case MERGE: nextCommand = new Pair<>(VdcActionType.Merge, buildMergeParameters()); getParameters().setNextCommandStep(RemoveSnapshotSingleDiskLiveStep.MERGE_STATUS); break; case MERGE_STATUS: getParameters().setMergeCommandComplete(true); nextCommand = new Pair<>(VdcActionType.MergeStatus, buildMergeParameters()); getParameters().setNextCommandStep(RemoveSnapshotSingleDiskLiveStep.DESTROY_IMAGE); break; case DESTROY_IMAGE: if (vdcReturnValue != null) { getParameters() .setMergeStatusReturnValue( (MergeStatusReturnValue) vdcReturnValue.getActionReturnValue()); } else if (getParameters().getMergeStatusReturnValue() == null) { // If the images were already merged, just add the orphaned image getParameters().setMergeStatusReturnValue(synthesizeMergeStatusReturnValue()); } nextCommand = new Pair<>(VdcActionType.DestroyImage, buildDestroyImageParameters()); getParameters().setNextCommandStep(RemoveSnapshotSingleDiskLiveStep.COMPLETE); break; case COMPLETE: getParameters().setDestroyImageCommandComplete(true); setCommandStatus(CommandStatus.SUCCEEDED); break; } persistCommand(getParameters().getParentCommand(), true); if (nextCommand != null) { CommandCoordinatorUtil.executeAsyncCommand( nextCommand.getFirst(), nextCommand.getSecond(), cloneContextAndDetachFromParent()); // Add the child, but wait, it's a race! child will start, task may spawn, get polled, and we // won't have the child id } }