package org.ovirt.engine.core.bll.hostdeploy;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import javax.inject.Inject;
import org.apache.commons.lang.StringUtils;
import org.ovirt.engine.core.bll.QueriesCommandBase;
import org.ovirt.engine.core.bll.VdsHandler;
import org.ovirt.engine.core.common.businessentities.VDS;
import org.ovirt.engine.core.common.queries.IdQueryParameters;
import org.ovirt.engine.core.common.utils.RpmVersionUtils;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.RpmVersion;
import org.ovirt.engine.core.compat.Version;
import org.ovirt.engine.core.dao.VdsDao;
import org.ovirt.engine.core.dao.VdsDynamicDao;
/**
* The {@code GetoVirtISOsQuery} is responsible to detect all available oVirt images installed on engine server. It detects
* the available ISOs files by there associated version files, read the iSOs' version from within the version files,
* verifies image files exist, and returns list of ISOs sorted by their version.
*/
public class GetoVirtISOsQuery<P extends IdQueryParameters> extends QueriesCommandBase<P> {
private static final String OVIRT_ISO_VERSION_PREFIX = "version";
private static final String OVIRT_ISO_VDSM_COMPATIBILITY_PREFIX = "vdsm-compatibility";
@Inject
private VdsDynamicDao hostDynamicDao;
@Inject
private VdsDao hostDao;
public GetoVirtISOsQuery(P parameters) {
super(parameters);
}
@Override
protected void executeCommand() {
super.executeCommand();
}
@Override
protected void executeQueryCommand() {
List<RpmVersion> availableISOsList = new ArrayList<>();
VDS vds = getVdsByVdsId(getParameters().getId());
if (vds == null) {
getQueryReturnValue().setReturnValue(availableISOsList);
return;
}
RpmVersion vdsOsVersion = VdsHandler.getOvirtHostOsVersion(vds);
String nodeOS = vds.getHostOs();
if (nodeOS == null) {
getQueryReturnValue().setReturnValue(new ArrayList<RpmVersion>());
return;
}
for (OVirtNodeInfo.Entry info : OVirtNodeInfo.getInstance().get()) {
log.debug(
"nodeOS [{}] | osPattern [{}] | minimumVersion [{}]",
nodeOS,
info.osPattern,
info.minimumVersion
);
Matcher matcher = info.osPattern.matcher(nodeOS);
if (matcher.matches() && info.path.isDirectory()) {
log.debug("Looking for list of ISOs in [{}], regex [{}]", info.path, info.isoPattern);
File[] files = info.path.listFiles();
if (files != null) {
for (File file : files) {
matcher = info.isoPattern.matcher(file.getName());
if (matcher.matches()) {
log.debug("ISO Found [{}]", file);
String version = matcher.group(1);
log.debug("ISO Version [{}]", version);
File versionFile = new File(info.path, String.format("version-%s.txt", version));
log.debug("versionFile [{}]", versionFile);
// Setting IsoData Class to get further [version] and [vdsm compatibility version] data
IsoData isoData = new IsoData();
isoData.setVersion(readIsoVersion(versionFile));
String isoVersionText = isoData.getVersion();
isoData.setVdsmCompitibilityVersion(readVdsmCompatibiltyVersion(versionFile.getAbsolutePath().replace(OVIRT_ISO_VERSION_PREFIX,
OVIRT_ISO_VDSM_COMPATIBILITY_PREFIX)));
if (StringUtils.isEmpty(isoVersionText)) {
log.debug("Iso version file '{}' is empty.", versionFile.getAbsolutePath());
continue;
}
String[] versionParts = isoVersionText.split(",");
if (versionParts.length < 2) {
log.debug("Iso version file '{}' contains invalid content. Expected: <major-version>,<release> format.",
versionFile.getAbsolutePath());
continue;
}
RpmVersion isoVersion = new RpmVersion(file.getName());
if (isoData.getVdsmCompatibilityVersion() != null && isIsoCompatibleForUpgradeByClusterVersion(isoData) ||
vdsOsVersion != null && VdsHandler.isIsoVersionCompatibleForUpgrade(vdsOsVersion, isoVersion)
) {
availableISOsList.add(isoVersion);
}
}
}
}
}
}
Collections.sort(availableISOsList);
getQueryReturnValue().setReturnValue(availableISOsList);
updateUpdatesAvailableForHost(availableISOsList, vds);
}
public void updateUpdatesAvailableForHost(List<RpmVersion> availableIsos, VDS vds) {
boolean updateAvailable = RpmVersionUtils.isUpdateAvailable(availableIsos, vds.getHostOs());
if (updateAvailable != vds.isUpdateAvailable()) {
hostDynamicDao.updateUpdateAvailable(vds.getId(), updateAvailable);
}
}
private boolean isIsoCompatibleForUpgradeByClusterVersion(IsoData isoData) {
for (String v : isoData.getVdsmCompatibilityVersion()) {
Version isoClusterVersion = new Version(v);
if (isNewerVersion(isoClusterVersion)) {
return true;
}
}
return false;
}
private boolean isNewerVersion(Version isoClusterVersion) {
VDS vds = getVdsByVdsId(getParameters().getId());
Version vdsClusterVersion = vds.getClusterCompatibilityVersion();
log.debug(
"vdsClusterVersion '{}' isoClusterVersion '{}'",
vdsClusterVersion,
isoClusterVersion
);
return vdsClusterVersion.getMajor() == isoClusterVersion.getMajor() && vdsClusterVersion.getMinor() <= isoClusterVersion.getMinor();
}
private String[] readVdsmCompatibiltyVersion(String fileName) {
File file = new File(fileName);
String[] versions = null;
if (file.exists()) {
try (BufferedReader input = new BufferedReader(new FileReader(file))) {
String lineRead = input.readLine();
if (lineRead != null) {
versions = lineRead.split(",");
}
} catch (FileNotFoundException e) {
log.error("Failed to open version file '{}': {}",
file.getParent(),
e.getMessage());
log.debug("Exception", e);
} catch (IOException e) {
log.error("Failed to read version from '{}': {}",
file.getAbsolutePath(),
e.getMessage());
log.debug("Exception", e);
}
}
return versions;
}
private String readIsoVersion(File versionFile) {
String isoVersionText = null;
try (BufferedReader input = new BufferedReader(new FileReader(versionFile))){
isoVersionText = input.readLine();
} catch (FileNotFoundException e) {
log.error("Failed to open version file '{}': {}",
versionFile.getAbsolutePath(),
e.getMessage());
log.debug("Exception", e);
} catch (IOException e) {
log.error("Failed to read version from '{}': {}",
versionFile.getAbsolutePath(),
e.getMessage());
log.debug("Exception", e);
}
return isoVersionText;
}
public VDS getVdsByVdsId(Guid vdsId) {
VDS vds = null;
if (vdsId != null) {
vds = hostDao.get(vdsId);
}
return vds;
}
private class IsoData {
private String version;
private String[] vdsmCompatibilityVersion;
public void setVersion(String version) {
this.version = version;
}
public String getVersion() {
return version;
}
public void setVdsmCompitibilityVersion(String[] supportedClusterVersion) {
this.vdsmCompatibilityVersion = supportedClusterVersion;
}
public String[] getVdsmCompatibilityVersion() {
return vdsmCompatibilityVersion;
}
}
}