package org.ovirt.engine.core.bll.network.cluster;
import java.util.List;
import java.util.Objects;
import org.apache.commons.lang.StringUtils;
import org.ovirt.engine.core.bll.ValidationResult;
import org.ovirt.engine.core.common.businessentities.Cluster;
import org.ovirt.engine.core.common.businessentities.network.Network;
import org.ovirt.engine.core.common.businessentities.network.NetworkCluster;
import org.ovirt.engine.core.common.businessentities.network.VdsNetworkInterface;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.dao.VdsDao;
import org.ovirt.engine.core.dao.network.InterfaceDao;
import org.ovirt.engine.core.dao.network.NetworkDao;
import org.ovirt.engine.core.utils.NetworkUtils;
/**
* Validator class for {@link NetworkCluster} instances.
*/
public abstract class NetworkClusterValidatorBase {
protected static final String NETWORK_NAME_REPLACEMENT = "$NetworkName %s";
private static final String NIC_NAME_REPLACEMENT = "$nicName %s";
private static final String HOST_NAME_REPLACEMENT = "$hostName %s";
protected final NetworkCluster networkCluster;
private final InterfaceDao interfaceDao;
private final NetworkDao networkDao;
private final VdsDao vdsDao;
public NetworkClusterValidatorBase(InterfaceDao interfaceDao,
NetworkDao networkDao,
VdsDao vdsDao,
NetworkCluster networkCluster) {
this.interfaceDao = Objects.requireNonNull(interfaceDao, "interfaceDao cannot be null");
this.networkDao = Objects.requireNonNull(networkDao, "networkDao cannot be null");
this.vdsDao = Objects.requireNonNull(vdsDao, "vdsDao cannot be null");
this.networkCluster = networkCluster;
}
public ValidationResult roleNetworkHasIp() {
if (NetworkUtils.isRoleNetwork(networkCluster)) {
final Network network = networkDao.get(networkCluster.getNetworkId());
final String networkName = network.getName();
final ValidationResult roleNetworkHasIpOnAttachedNics = roleNetworkHasIpOnAttachedNics(networkName);
if (!roleNetworkHasIpOnAttachedNics.isValid()) {
return roleNetworkHasIpOnAttachedNics;
}
}
return ValidationResult.VALID;
}
ValidationResult roleNetworkHasIpOnAttachedNics(String networkName) {
final VdsNetworkInterface missingIpNic = findMissingIpNic(networkName);
if (missingIpNic != null) {
return createMissingIpValidationResult(missingIpNic, networkName);
}
return ValidationResult.VALID;
}
private ValidationResult createMissingIpValidationResult(
VdsNetworkInterface missingIpNic,
String networkName) {
return new ValidationResult(EngineMessage.NETWORK_ADDR_MANDATORY_FOR_ROLE_NETWORK,
String.format(NETWORK_NAME_REPLACEMENT, networkName),
String.format(NIC_NAME_REPLACEMENT, missingIpNic.getName()),
String.format(HOST_NAME_REPLACEMENT, missingIpNic.getVdsName()));
}
private VdsNetworkInterface findMissingIpNic(final String networkName) {
final List<VdsNetworkInterface> interfacesByClusterId =
interfaceDao.getAllInterfacesByClusterId(networkCluster.getClusterId());
final VdsNetworkInterface missingIpNic =
interfacesByClusterId.stream()
.filter(nic -> networkName.equals(nic.getNetworkName()))
.filter(this::isIpAddressMissingForRole)
.findFirst()
.orElse(null);
return missingIpNic;
}
private boolean isIpAddressMissingForRole(VdsNetworkInterface nic) {
if (networkCluster.isMigration()) {
return StringUtils.isEmpty(nic.getIpv4Address()) && StringUtils.isEmpty(nic.getIpv6Address());
}
return StringUtils.isEmpty(nic.getIpv4Address());
}
/**
* Make sure the given {@link Network} belongs to the same DC as the cluster.
*
* @param cluster
* the cluster to be checked against
* @param network
* network to be checked
*/
public ValidationResult networkBelongsToClusterDataCenter(Cluster cluster, Network network) {
return ValidationResult.failWith(EngineMessage.ACTION_TYPE_FAILED_NETWORK_FROM_DIFFERENT_DC,
String.format(NETWORK_NAME_REPLACEMENT, network.getName())).
unless(cluster.getStoragePoolId().equals(network.getDataCenterId()));
}
public ValidationResult managementNetworkNotExternal(Network network) {
return ValidationResult.failWith(EngineMessage.ACTION_TYPE_FAILED_MANAGEMENT_NETWORK_CANNOT_BE_EXTERNAL,
String.format(NETWORK_NAME_REPLACEMENT, network.getName())).when(
networkCluster.isManagement() &&
network.isExternal());
}
public ValidationResult defaultRouteNetworkCannotBeExternal(Network network) {
return ValidationResult.failWith(EngineMessage.ACTION_TYPE_FAILED_DEFAULT_ROUTE_NETWORK_CANNOT_BE_EXTERNAL,
String.format(NETWORK_NAME_REPLACEMENT, network.getName())).when(
networkCluster.isDefaultRoute() &&
network.isExternal());
}
public ValidationResult managementNetworkRequired(Network network) {
return ValidationResult.failWith(EngineMessage.ACTION_TYPE_FAILED_MANAGEMENT_NETWORK_REQUIRED,
String.format(NETWORK_NAME_REPLACEMENT, network.getName())).when(
networkCluster.isManagement() &&
!networkCluster.isRequired());
}
/**
* Make sure the management network change is valid - that is allowed in an empty cluster only
*
* @return Error if the management network change is not allowed.
*/
public ValidationResult managementNetworkChange() {
return ValidationResult.failWith(EngineMessage.ACTION_TYPE_FAILED_MANAGEMENT_NETWORK_CANNOT_BE_CHANGED).
when(isManagementNetworkChangeInvalid());
}
protected boolean isManagementNetworkChangeInvalid() {
return isManagementNetworkChanged() && isManagementNetworkChangeForbidden();
}
protected abstract boolean isManagementNetworkChanged();
protected boolean isManagementNetworkChangeForbidden() {
return !isClusterEmpty();
}
private boolean isClusterEmpty() {
return vdsDao.getAllForCluster(networkCluster.getClusterId()).isEmpty();
}
/**
* Make sure the external network attachment is valid: The network cannot be used as a display network.
*
* @param networkName
* The network's name.
* @return Error iff the external network attachment is not valid.
*/
public ValidationResult externalNetworkNotDisplay(String networkName) {
return networkCluster.isDisplay() ?
new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_EXTERNAL_NETWORK_CANNOT_BE_DISPLAY,
String.format(NETWORK_NAME_REPLACEMENT, networkName))
: ValidationResult.VALID;
}
/**
* Make sure the external network attachment is valid: The network cannot be required.
*
* @param networkName
* The network's name.
* @return Error iff the external network attachment is not valid.
*/
public ValidationResult externalNetworkNotRequired(String networkName) {
return networkCluster.isRequired() ?
new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_EXTERNAL_NETWORK_CANNOT_BE_REQUIRED,
String.format(NETWORK_NAME_REPLACEMENT, networkName))
: ValidationResult.VALID;
}
}