package org.ovirt.engine.core.vdsbroker.vdsbroker;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.ovirt.engine.core.common.action.CreateOrUpdateBond;
import org.ovirt.engine.core.common.businessentities.network.Ipv4BootProtocol;
import org.ovirt.engine.core.common.businessentities.network.Ipv6BootProtocol;
import org.ovirt.engine.core.common.network.SwitchType;
import org.ovirt.engine.core.common.validation.MaskValidator;
import org.ovirt.engine.core.common.vdscommands.HostNetwork;
import org.ovirt.engine.core.common.vdscommands.HostSetupNetworksVdsCommandParameters;
import org.ovirt.engine.core.utils.NetworkUtils;
public class HostSetupNetworksVDSCommand<T extends HostSetupNetworksVdsCommandParameters> extends FutureVDSCommand<T> {
protected static final String DHCP_BOOT_PROTOCOL = "dhcp";
protected static final String DHCPV6_BOOT_PROTOCOL = "dhcpv6";
protected static final String DHCPV6_AUTOCONF = "ipv6autoconf";
protected static final String BOOT_PROTOCOL = "bootproto";
protected static final String BONDING_OPTIONS = "options";
protected static final String SLAVES = "nics";
private static final String DEFAULT_ROUTE = "defaultRoute";
private static final Map<String, String> REMOVE_OBJ = Collections.singletonMap("remove", Boolean.TRUE.toString());
public HostSetupNetworksVDSCommand(T parameters) {
super(parameters);
}
@Override
protected void executeVdsBrokerCommand() {
httpTask = getBroker().setupNetworks(generateNetworks(), generateBonds(), generateOptions(), getParameters().isManagementNetworkChanged());
}
private Map<String, Object> generateNetworks() {
Map<String, Object> networks = new HashMap<>();
for (HostNetwork hostNetwork : getParameters().getNetworks()) {
Map<String, Object> attributes = new HashMap<>();
if (hostNetwork.isBonding()) {
attributes.put("bonding", hostNetwork.getNicName());
} else {
attributes.put("nic", hostNetwork.getNicName());
}
if (hostNetwork.isVlan()) {
attributes.put("vlan", hostNetwork.getVlan().toString());
}
if (hostNetwork.getMtu() == 0) {
attributes.put(VdsProperties.MTU, NetworkUtils.getDefaultMtu());
} else {
attributes.put(VdsProperties.MTU, hostNetwork.getMtu());
}
attributes.put("bridged", Boolean.toString(hostNetwork.isVmNetwork()));
if (hostNetwork.isVmNetwork()) {
attributes.put(VdsProperties.STP, hostNetwork.isStp() ? "yes" : "no");
}
if (hostNetwork.getIpv4BootProtocol() != null) {
addIpv4BootProtocol(attributes, hostNetwork);
}
if (hostNetwork.getIpv6BootProtocol() != null) {
addIpv6BootProtocol(attributes, hostNetwork);
}
if (hostNetwork.isDefaultRoute()) {
attributes.put(DEFAULT_ROUTE, Boolean.TRUE);
}
addSwitchTypeIfSpecified(attributes);
if (hostNetwork.hasProperties()) {
attributes.put(VdsProperties.NETWORK_CUSTOM_PROPERTIES, hostNetwork.getProperties());
}
if (hostNetwork.isQosConfiguredOnInterface()) {
HostNetworkQosMapper qosMapper = new HostNetworkQosMapper(attributes);
qosMapper.serialize(hostNetwork.getQos());
}
networks.put(hostNetwork.getNetworkName(), attributes);
}
for (String net : getParameters().getRemovedNetworks()) {
networks.put(net, REMOVE_OBJ);
}
return networks;
}
void addIpv4BootProtocol(Map<String, Object> opts, HostNetwork attachment) {
if (attachment.getIpv4BootProtocol() == Ipv4BootProtocol.DHCP) {
opts.put(BOOT_PROTOCOL, DHCP_BOOT_PROTOCOL);
} else if (attachment.getIpv4BootProtocol() == Ipv4BootProtocol.STATIC_IP) {
putIfNotEmpty(opts, "ipaddr", attachment.getIpv4Address());
putIpv4PrefixOrNetmaskIfNotEmpty(opts, attachment.getIpv4Netmask());
putIfNotEmpty(opts, "gateway", attachment.getIpv4Gateway());
}
}
private void addIpv6BootProtocol(Map<String, Object> opts, HostNetwork attachment) {
final Ipv6BootProtocol ipv6BootProtocol = attachment.getIpv6BootProtocol();
opts.put(DHCPV6_BOOT_PROTOCOL, Ipv6BootProtocol.DHCP == ipv6BootProtocol);
opts.put(DHCPV6_AUTOCONF, Ipv6BootProtocol.AUTOCONF == ipv6BootProtocol);
if (Ipv6BootProtocol.STATIC_IP == ipv6BootProtocol) {
putIfNotEmpty(opts, "ipv6addr", getIpv6Address(attachment));
putIfNotEmpty(opts, "ipv6gateway", attachment.getIpv6Gateway());
}
}
private String getIpv6Address(HostNetwork attachment) {
final String ipv6Address = attachment.getIpv6Address();
final Integer ipv6Prefix = attachment.getIpv6Prefix();
return ipv6Prefix == null ? ipv6Address : String.format("%s/%d", ipv6Address, ipv6Prefix);
}
private void putIpv4PrefixOrNetmaskIfNotEmpty(Map<String, Object> opts, String netmask) {
if (MaskValidator.getInstance().isPrefixValid(netmask)) {
putIfNotEmpty(opts, "prefix", netmask.replace("/", ""));
} else {
putIfNotEmpty(opts, "netmask", netmask);
}
}
private Map<String, Object> generateBonds() {
Map<String, Object> bonds = new HashMap<>();
for (CreateOrUpdateBond bond : getParameters().getCreateOrUpdateBonds()) {
bonds.put(bond.getName(), createBondAttributes(bond));
}
for (String bond : getParameters().getRemovedBonds()) {
bonds.put(bond, REMOVE_OBJ);
}
return bonds;
}
private Map<String, Object> createBondAttributes(CreateOrUpdateBond bond) {
Map<String, Object> attributes = new HashMap<>();
attributes.put(SLAVES, new ArrayList<>(bond.getSlaves()));
addSwitchTypeIfSpecified(attributes);
putIfNotEmpty(attributes, BONDING_OPTIONS, bond.getBondOptions());
return attributes;
}
private Map<String, Object> generateOptions() {
Map<String, Object> options = new HashMap<>();
options.put(VdsProperties.CONNECTIVITY_CHECK, Boolean.toString(getParameters().isRollbackOnFailure()));
// VDSM uses the connectivity timeout only if 'connectivityCheck' is set to true
if (getParameters().isRollbackOnFailure()) {
options.put(VdsProperties.CONNECTIVITY_TIMEOUT, getParameters().getConnectivityTimeout());
}
return options;
}
private static void putIfNotEmpty(Map<String, Object> map, String key, String value) {
if (StringUtils.isNotEmpty(value)) {
map.put(key, value);
}
}
/**
* switch type is optional, specifies switch type. Legacy will be used if switch option is not set/passed.
*/
private void addSwitchTypeIfSpecified(Map<String, Object> resultMap) {
SwitchType switchType = getParameters().getClusterSwitchType();
if (switchType != null) {
resultMap.put(VdsProperties.SWITCH_KEY, switchType.getOptionValue());
}
}
}