package org.ovirt.engine.core.bll.hostdeploy; import java.io.File; import java.io.IOException; import java.util.Collections; import java.util.Map; import java.util.regex.Matcher; import org.apache.commons.lang.StringUtils; import org.ovirt.engine.core.bll.LockMessagesMatchUtil; import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute; 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.common.AuditLogType; import org.ovirt.engine.core.common.action.LockProperties; import org.ovirt.engine.core.common.action.LockProperties.Scope; import org.ovirt.engine.core.common.action.hostdeploy.InstallVdsParameters; import org.ovirt.engine.core.common.businessentities.VDSStatus; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.common.locks.LockingGroup; import org.ovirt.engine.core.common.utils.Pair; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.RpmVersion; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @NonTransactiveCommandAttribute public class UpgradeOvirtNodeInternalCommand<T extends InstallVdsParameters> extends VdsCommand<T> { private static Logger log = LoggerFactory.getLogger(UpgradeOvirtNodeInternalCommand.class); protected File _iso = null; private VDSStatus vdsInitialStatus; private File resolveISO(String iso) { File ret = null; // do not allow exiting the designated paths if (iso != null && iso.indexOf(File.pathSeparatorChar) == -1) { for (OVirtNodeInfo.Entry info : OVirtNodeInfo.getInstance().get()) { File path = new File(info.path, iso); if (path.exists()) { ret = path; break; } } } return ret; } @Override protected LockProperties applyLockProperties(LockProperties lockProperties) { return lockProperties.withScope(Scope.Execution); } @Override protected void setActionMessageParameters() { addValidationMessage(EngineMessage.VAR__ACTION__INSTALL); addValidationMessage(EngineMessage.VAR__TYPE__HOST); } private boolean isISOCompatible( File iso, RpmVersion ovirtHostOsVersion ) { boolean ret = false; log.debug("Check if ISO compatible: '{}'", iso); for (OVirtNodeInfo.Entry info : OVirtNodeInfo.getInstance().get()) { if (info.path.equals(iso.getParentFile())) { try { Matcher matcher = info.isoPattern.matcher( iso.getCanonicalFile().getName() ); if (matcher.find()) { String rpmLike = matcher.group(1).replaceAll("-", "."); log.debug("ISO version: '{}' '{}' '{}'", iso, rpmLike, ovirtHostOsVersion); RpmVersion isoVersion = new RpmVersion(rpmLike, "", true); if (VdsHandler.isIsoVersionCompatibleForUpgrade(ovirtHostOsVersion, isoVersion)) { log.debug("ISO compatible '{}'", iso); ret = true; break; } } } catch (IOException e) { log.error( "Cannot get canonical path to '{}': {}", iso.getName(), e.getMessage() ); log.debug("Exception", e); } } } return ret; } public UpgradeOvirtNodeInternalCommand(T parameters, CommandContext cmdContext) { super(parameters, cmdContext); } @Override protected boolean validate() { if (getVdsId() == null || getVdsId().equals(Guid.Empty)) { return failValidation(EngineMessage.VDS_INVALID_SERVER_ID); } if (getVds() == null) { return failValidation(EngineMessage.ACTION_TYPE_FAILED_HOST_NOT_EXIST); } if (isOvirtReInstallOrUpgrade()) { // Block re-install on non-operational Host if (getVds().getStatus() == VDSStatus.NonOperational) { return failValidation(EngineMessage.VDS_CANNOT_INSTALL_STATUS_ILLEGAL); } File iso = resolveISO(getParameters().getoVirtIsoFile()); if (iso == null) { return failValidation(EngineMessage.VDS_CANNOT_INSTALL_MISSING_IMAGE_FILE); } RpmVersion ovirtHostOsVersion = VdsHandler.getOvirtHostOsVersion(getVds()); if (!isISOCompatible(iso, ovirtHostOsVersion)) { addValidationMessage(EngineMessage.VDS_CANNOT_UPGRADE_BETWEEN_MAJOR_VERSION); addValidationMessageVariable("IsoVersion", ovirtHostOsVersion.getMajor()); return false; } _iso = iso; } else { return failValidation(EngineMessage.VDS_CANNOT_INSTALL_STATUS_ILLEGAL); } return true; } @Override public AuditLogType getAuditLogTypeValue() { AuditLogType result = null; if (getSucceeded()) { result = AuditLogType.VDS_INSTALL; } else { // In case of failure - add to audit log the error as achieved from // the host addCustomValue("FailedInstallMessage", getErrorMessage(_failureMessage)); result = AuditLogType.VDS_INSTALL_FAILED; } return result; } @Override protected void executeCommand() { if (getVds() == null) { return; } vdsInitialStatus = getVds().getStatus(); if (isOvirtReInstallOrUpgrade()) { upgradeNode(); } } private void upgradeNode() { try ( final OVirtNodeUpgrade upgrade = new OVirtNodeUpgrade( getVds(), _iso ) ) { upgrade.setCorrelationId(getCorrelationId()); log.info( "Execute upgrade host '{}', '{}'", getVds().getId(), getVds().getName() ); setVdsStatus(VDSStatus.Installing); upgrade.execute(); switch (upgrade.getDeployStatus()) { case Failed: throw new VdsInstallException(VDSStatus.InstallFailed, StringUtils.EMPTY); case Reboot: setVdsStatus(VDSStatus.Reboot); runSleepOnReboot(getStatusOnReboot()); break; } log.info( "After upgrade host '{}', '{}': success", getVds().getId(), getVds().getName() ); setSucceeded(true); } catch (VdsInstallException e) { handleError(e, e.getStatus()); } catch (Exception e) { handleError(e, VDSStatus.InstallFailed); } } private boolean isOvirtReInstallOrUpgrade() { return getParameters().getIsReinstallOrUpgrade() && getVds().isOvirtVintageNode(); } @Override protected Map<String, Pair<String, String>> getExclusiveLocks() { return Collections.singletonMap( getParameters().getVdsId().toString(), LockMessagesMatchUtil.makeLockingPair( LockingGroup.VDS, EngineMessage.ACTION_TYPE_FAILED_OBJECT_LOCKED ) ); } private VDSStatus getStatusOnReboot() { if (getParameters().getActivateHost()) { return VDSStatus.NonResponsive; } return VDSStatus.Maintenance.equals(vdsInitialStatus) ? VDSStatus.Maintenance : VDSStatus.NonResponsive; } }