package org.ovirt.engine.core.bll.hostdeploy; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.inject.Inject; import org.apache.commons.lang.StringUtils; import org.ovirt.engine.core.bll.Backend; import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute; import org.ovirt.engine.core.bll.RenamedEntityInfoProvider; import org.ovirt.engine.core.bll.VdsCommand; import org.ovirt.engine.core.bll.VdsHandler; import org.ovirt.engine.core.bll.context.CommandContext; import org.ovirt.engine.core.bll.hostedengine.HostedEngineHelper; import org.ovirt.engine.core.bll.network.cluster.NetworkClusterHelper; import org.ovirt.engine.core.bll.validator.UpdateHostValidator; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.VdcObjectType; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.action.VdcReturnValueBase; import org.ovirt.engine.core.common.action.hostdeploy.InstallVdsParameters; import org.ovirt.engine.core.common.action.hostdeploy.UpdateVdsActionParameters; import org.ovirt.engine.core.common.businessentities.KdumpStatus; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.VDSStatus; import org.ovirt.engine.core.common.businessentities.VdsDynamic; import org.ovirt.engine.core.common.businessentities.VdsStatic; import org.ovirt.engine.core.common.businessentities.network.Network; import org.ovirt.engine.core.common.businessentities.pm.FenceAgent; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.common.validation.group.PowerManagementCheck; import org.ovirt.engine.core.common.validation.group.UpdateEntity; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogable; import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogableBase; import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogableImpl; import org.ovirt.engine.core.dao.FenceAgentDao; import org.ovirt.engine.core.dao.VdsDao; import org.ovirt.engine.core.dao.VdsDynamicDao; import org.ovirt.engine.core.dao.VdsStaticDao; import org.ovirt.engine.core.dao.network.NetworkDao; import org.ovirt.engine.core.utils.transaction.TransactionMethod; import org.ovirt.engine.core.utils.transaction.TransactionSupport; import org.ovirt.engine.core.vdsbroker.ResourceManager; @NonTransactiveCommandAttribute(forceCompensation = true) public class UpdateVdsCommand<T extends UpdateVdsActionParameters> extends VdsCommand<T> implements RenamedEntityInfoProvider{ @Inject private ResourceManager resourceManager; @Inject private HostedEngineHelper hostedEngineHelper; @Inject private VdsHandler vdsHandler; @Inject private NetworkClusterHelper networkClusterHelper; private VDS oldHost; private static final List<String> UPDATE_FIELDS_VDS_BROKER = Arrays.asList( "host_name", "ip", "vds_unique_id", "port", "cluster_id", "protocol"); private VdcActionType actionType; @Inject private VdsDao vdsDao; @Inject private VdsStaticDao vdsStaticDao; @Inject private VdsDynamicDao vdsDynamicDao; @Inject private NetworkDao networkDao; @Inject private FenceAgentDao fenceAgentDao; public UpdateVdsCommand(T parameters, CommandContext cmdContext) { this(parameters, cmdContext, VdcActionType.InstallVdsInternal); } public UpdateVdsCommand(T parameters, CommandContext commandContext, VdcActionType actionType) { super(parameters, commandContext); this.actionType = actionType; } public UpdateVdsCommand(Guid commandId) { this(commandId, VdcActionType.InstallVdsInternal); } protected UpdateVdsCommand(Guid commandId, VdcActionType actionType) { super(commandId); this.actionType = actionType; } @Override protected boolean validate() { oldHost = vdsDao.get(getVdsId()); UpdateHostValidator validator = getUpdateHostValidator(oldHost, getParameters().getvds(), getParameters().isInstallHost()); return validate(validator.hostExists()) && validate(validator.hostStatusValid()) && validate(validator.nameNotEmpty()) && validate(validator.nameLengthIsLegal()) && validate(validator.updateHostAddressAllowed()) && validate(validator.nameNotUsed()) && validate(validator.hostNameNotUsed()) && validate(validator.statusSupportedForHostInstallation()) && validate(validator.passwordProvidedForHostInstallation(getParameters().getAuthMethod(), getParameters().getPassword())) && validate(validator.updatePortAllowed()) && validate(validator.clusterNotChanged()) && validate(validator.hostProviderExists()) && validate(validator.hostProviderTypeMatches()) && validateNetworkProviderConfiguration() && isPowerManagementLegal(getParameters().getVdsStaticData().isPmEnabled(), getParameters().getFenceAgents(), oldHost.getClusterCompatibilityVersion().toString()) && validate(validator.supportsDeployingHostedEngine( getParameters().getHostedEngineDeployConfiguration())); } UpdateHostValidator getUpdateHostValidator(VDS oldHost, VDS updatedHost, boolean installHost) { return UpdateHostValidator.createInstance( oldHost, updatedHost, installHost); } private boolean validateNetworkProviderConfiguration() { return !getParameters().isInstallHost() || getParameters().getVdsStaticData().getOpenstackNetworkProviderId() == null || validateNetworkProviderProperties(getParameters().getVdsStaticData().getOpenstackNetworkProviderId(), getParameters().getNetworkMappings()); } @Override protected void setActionMessageParameters() { addValidationMessage(EngineMessage.VAR__ACTION__UPDATE); addValidationMessage(EngineMessage.VAR__TYPE__HOST); } @Override protected void executeCommand() { updateVdsData(); if (needToUpdateVdsBroker()) { initializeVds(); } if (getParameters().isInstallHost()) { InstallVdsParameters tempVar = new InstallVdsParameters(getVdsId(), getParameters().getPassword()); tempVar.setIsReinstallOrUpgrade(getParameters().isReinstallOrUpgrade()); tempVar.setoVirtIsoFile(getParameters().getoVirtIsoFile()); if (vdsDynamicDao.get(getVdsId()).getStatus() == VDSStatus.InstallingOS) { // TODO: remove hack when reinstall api will provider override-firewall parameter. // https://bugzilla.redhat.com/show_bug.cgi?id=1177126 - for now we override firewall // configurations on each deploy for provisioned host to avoid wrong deployment. tempVar.setOverrideFirewall(true); } else { tempVar.setOverrideFirewall(getParameters().getOverrideFirewall()); } tempVar.setOverrideFirewall(getParameters().getOverrideFirewall()); tempVar.setActivateHost(getParameters().getActivateHost()); tempVar.setNetworkProviderId(getParameters().getVdsStaticData().getOpenstackNetworkProviderId()); tempVar.setNetworkMappings(getParameters().getNetworkMappings()); tempVar.setAuthMethod(getParameters().getAuthMethod()); if (getParameters().getHostedEngineDeployConfiguration() != null) { tempVar.setHostedEngineConfiguration( hostedEngineHelper.createVdsDeployParams(getVdsId(), getParameters().getHostedEngineDeployConfiguration().getDeployAction())); } ArrayList<VdcReturnValueBase> resultList = runInternalMultipleActions( actionType, new ArrayList<>(Arrays.asList(tempVar))); // Since Host status is set to "Installing", failure of InstallVdsCommand will hang the Host to in that // status, therefore needed to fail the command to revert the status. if (!resultList.isEmpty()) { VdcReturnValueBase vdcReturnValueBase = resultList.get(0); if (vdcReturnValueBase != null && !vdcReturnValueBase.isValid()) { ArrayList<String> validationMessages = vdcReturnValueBase.getValidationMessages(); if (!validationMessages.isEmpty()) { // add can do action messages to return value so error messages // are returned back to the client getReturnValue().getValidationMessages().addAll(validationMessages); log.error("Installation/upgrade of Host '{}', '{}' failed: {}", getVdsId(), getVdsName(), StringUtils.join(Backend.getInstance() .getErrorsTranslator() .translateErrorText(validationMessages), ",")); } // set can do action to false so can do action messages are // returned back to client getReturnValue().setValid(false); setSucceeded(false); // add old vds dynamic data to compensation context. This // way the status will revert back to what it was before // starting installation process getCompensationContext().snapshotEntityStatus(oldHost.getDynamicData()); getCompensationContext().stateChanged(); return; } } } // set clusters network to be operational (if needed) if (oldHost.getStatus() == VDSStatus.Up) { List<Network> networks = networkDao.getAllForCluster(oldHost.getClusterId()); networkClusterHelper.setStatus(oldHost.getClusterId(), networks); } alertIfPowerManagementNotConfigured(getParameters().getVdsStaticData()); testVdsPowerManagementStatus(getParameters().getVdsStaticData()); checkKdumpIntegrationStatus(); setSucceeded(true); } @Override public AuditLogType getAuditLogTypeValue() { return getSucceeded() ? AuditLogType.USER_UPDATE_VDS : AuditLogType.USER_FAILED_UPDATE_VDS; } private void updateVdsData() { TransactionSupport.executeInNewTransaction(new TransactionMethod<Void>() { @Override public Void runInTransaction() { getCompensationContext().snapshotEntity(getVds().getStaticData()); vdsStaticDao.update(getParameters().getVdsStaticData()); updateFenceAgents();// TODO: what compensation needed for fencing? getCompensationContext().stateChanged(); return null; } private void updateFenceAgents() { if (getParameters().getFenceAgents() != null) { // if == null, means no update. Empty list means // delete agents. fenceAgentDao.removeByVdsId(getVdsId()); for (FenceAgent agent : getParameters().getFenceAgents()) { agent.setHostId(getVdsId()); fenceAgentDao.save(agent); } } } }); } private boolean needToUpdateVdsBroker() { return vdsHandler.isFieldsUpdated(getParameters().getVdsStaticData(), oldHost.getStaticData(), UPDATE_FIELDS_VDS_BROKER); } @Override protected List<Class<?>> getValidationGroups() { addValidationGroup(UpdateEntity.class); if (getParameters().getVdsStaticData().isPmEnabled()) { addValidationGroup(PowerManagementCheck.class); } return super.getValidationGroups(); } @Override public String getEntityType() { return VdcObjectType.VDS.getVdcObjectTranslation(); } @Override public String getEntityOldName() { return oldHost.getName(); } @Override public String getEntityNewName() { return getParameters().getVdsStaticData().getName(); } @Override public void setEntityId(AuditLogableBase logable) { logable.setVdsId(oldHost.getId()); } private void checkKdumpIntegrationStatus() { VdsStatic vdsSt = getParameters().getVdsStaticData(); if (vdsSt.isPmEnabled() && vdsSt.isPmKdumpDetection()) { VdsDynamic vdsDyn = vdsDynamicDao.get(vdsSt.getId()); if (vdsDyn != null && vdsDyn.getKdumpStatus() != KdumpStatus.ENABLED) { AuditLogable logable = new AuditLogableImpl(); logable.setVdsId(vdsSt.getId()); logable.setVdsName(vdsSt.getName()); auditLogDirector.log(logable, AuditLogType.KDUMP_DETECTION_NOT_CONFIGURED_ON_VDS); } } } @Override protected boolean isPowerManagementLegal(boolean pmEnabled, List<FenceAgent> fenceAgents, String clusterCompatibilityVersion) { return super.isPowerManagementLegal(pmEnabled, fenceAgents, clusterCompatibilityVersion); } }