vmware, ui: update portgroup on network update (#5470)

Enhanced update network form in the UI.
On network offering change for an isolated network,

- VMware portgroup should be updated accordingly.
- VMs on the network should be placed on the correct VMware portgroup based on the network rate, https://docs.cloudstack.apache.org/en/latest/adminguide/service_offerings.html#network-throttling.

Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
Abhishek Kumar 2021-10-03 14:41:42 +05:30 committed by GitHub
parent 965a47fdfd
commit 4a42e7ef9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 403 additions and 112 deletions

View File

@ -221,7 +221,7 @@ public interface VirtualMachineManager extends Manager {
*/ */
VirtualMachineTO toVmTO(VirtualMachineProfile profile); VirtualMachineTO toVmTO(VirtualMachineProfile profile);
boolean replugNic(Network network, NicTO nic, VirtualMachineTO vm, ReservationContext context, DeployDestination dest) throws ConcurrentOperationException, boolean replugNic(Network network, NicTO nic, VirtualMachineTO vm, Host dest) throws ConcurrentOperationException,
ResourceUnavailableException, InsufficientCapacityException; ResourceUnavailableException, InsufficientCapacityException;
VirtualMachine reConfigureVm(String vmUuid, ServiceOffering oldServiceOffering, ServiceOffering newServiceOffering, Map<String, String> customParameters, boolean sameHost) throws ResourceUnavailableException, ConcurrentOperationException, VirtualMachine reConfigureVm(String vmUuid, ServiceOffering oldServiceOffering, ServiceOffering newServiceOffering, Map<String, String> customParameters, boolean sameHost) throws ResourceUnavailableException, ConcurrentOperationException,

View File

@ -43,7 +43,6 @@ import java.util.concurrent.TimeUnit;
import javax.inject.Inject; import javax.inject.Inject;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import com.cloud.api.ApiDBUtils;
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
import org.apache.cloudstack.annotation.AnnotationService; import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.annotation.dao.AnnotationDao; import org.apache.cloudstack.annotation.dao.AnnotationDao;
@ -129,6 +128,7 @@ import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.agent.manager.Commands; import com.cloud.agent.manager.Commands;
import com.cloud.agent.manager.allocator.HostAllocator; import com.cloud.agent.manager.allocator.HostAllocator;
import com.cloud.alert.AlertManager; import com.cloud.alert.AlertManager;
import com.cloud.api.ApiDBUtils;
import com.cloud.api.query.dao.DomainRouterJoinDao; import com.cloud.api.query.dao.DomainRouterJoinDao;
import com.cloud.api.query.dao.UserVmJoinDao; import com.cloud.api.query.dao.UserVmJoinDao;
import com.cloud.api.query.vo.DomainRouterJoinVO; import com.cloud.api.query.vo.DomainRouterJoinVO;
@ -4047,16 +4047,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
//3) Convert nicProfile to NicTO //3) Convert nicProfile to NicTO
final NicTO nicTO = toNicTO(nic, vmProfile.getVirtualMachine().getHypervisorType()); final NicTO nicTO = toNicTO(nic, vmProfile.getVirtualMachine().getHypervisorType());
if (network != null) {
final Map<NetworkOffering.Detail, String> details = networkOfferingDetailsDao.getNtwkOffDetails(network.getNetworkOfferingId());
if (details != null) {
details.putIfAbsent(NetworkOffering.Detail.PromiscuousMode, NetworkOrchestrationService.PromiscuousMode.value().toString());
details.putIfAbsent(NetworkOffering.Detail.MacAddressChanges, NetworkOrchestrationService.MacAddressChanges.value().toString());
details.putIfAbsent(NetworkOffering.Detail.ForgedTransmits, NetworkOrchestrationService.ForgedTransmits.value().toString());
}
nicTO.setDetails(details);
}
//4) plug the nic to the vm //4) plug the nic to the vm
s_logger.debug("Plugging nic for vm " + vm + " in network " + network); s_logger.debug("Plugging nic for vm " + vm + " in network " + network);
@ -4566,7 +4556,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
} }
@Override @Override
public boolean replugNic(final Network network, final NicTO nic, final VirtualMachineTO vm, final ReservationContext context, final DeployDestination dest) throws ConcurrentOperationException, public boolean replugNic(final Network network, final NicTO nic, final VirtualMachineTO vm, final Host host) throws ConcurrentOperationException,
ResourceUnavailableException, InsufficientCapacityException { ResourceUnavailableException, InsufficientCapacityException {
boolean result = true; boolean result = true;
@ -4576,14 +4566,14 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
final ReplugNicCommand replugNicCmd = new ReplugNicCommand(nic, vm.getName(), vm.getType(), vm.getDetails()); final ReplugNicCommand replugNicCmd = new ReplugNicCommand(nic, vm.getName(), vm.getType(), vm.getDetails());
final Commands cmds = new Commands(Command.OnError.Stop); final Commands cmds = new Commands(Command.OnError.Stop);
cmds.addCommand("replugnic", replugNicCmd); cmds.addCommand("replugnic", replugNicCmd);
_agentMgr.send(dest.getHost().getId(), cmds); _agentMgr.send(host.getId(), cmds);
final ReplugNicAnswer replugNicAnswer = cmds.getAnswer(ReplugNicAnswer.class); final ReplugNicAnswer replugNicAnswer = cmds.getAnswer(ReplugNicAnswer.class);
if (replugNicAnswer == null || !replugNicAnswer.getResult()) { if (replugNicAnswer == null || !replugNicAnswer.getResult()) {
s_logger.warn("Unable to replug nic for vm " + vm.getName()); s_logger.warn("Unable to replug nic for vm " + vm.getName());
result = false; result = false;
} }
} catch (final OperationTimedoutException e) { } catch (final OperationTimedoutException e) {
throw new AgentUnavailableException("Unable to plug nic for router " + vm.getName() + " in network " + network, dest.getHost().getId(), e); throw new AgentUnavailableException("Unable to plug nic for router " + vm.getName() + " in network " + network, host.getId(), e);
} }
} else { } else {
s_logger.warn("Unable to apply ReplugNic, vm " + router + " is not in the right state " + router.getState()); s_logger.warn("Unable to apply ReplugNic, vm " + router + " is not in the right state " + router.getState());

View File

@ -25,8 +25,11 @@ import javax.inject.Inject;
import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.backup.Backup; import org.apache.cloudstack.backup.Backup;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils; import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import com.cloud.agent.api.Command; import com.cloud.agent.api.Command;
@ -36,6 +39,7 @@ import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.gpu.GPU; import com.cloud.gpu.GPU;
import com.cloud.host.HostVO; import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostDao;
import com.cloud.network.Network;
import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.BroadcastDomainType;
import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkDetailVO; import com.cloud.network.dao.NetworkDetailVO;
@ -61,9 +65,6 @@ import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.NicSecondaryIpDao; import com.cloud.vm.dao.NicSecondaryIpDao;
import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.UserVmDetailsDao;
import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.dao.VMInstanceDao;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.commons.lang3.StringUtils;
public abstract class HypervisorGuruBase extends AdapterBase implements HypervisorGuru, Configurable { public abstract class HypervisorGuruBase extends AdapterBase implements HypervisorGuru, Configurable {
public static final Logger s_logger = Logger.getLogger(HypervisorGuruBase.class); public static final Logger s_logger = Logger.getLogger(HypervisorGuruBase.class);
@ -97,6 +98,24 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
public static ConfigKey<Boolean> VmMinCpuSpeedEqualsCpuSpeedDividedByCpuOverprovisioningFactor = new ConfigKey<Boolean>("Advanced", Boolean.class, "vm.min.cpu.speed.equals.cpu.speed.divided.by.cpu.overprovisioning.factor", "true", public static ConfigKey<Boolean> VmMinCpuSpeedEqualsCpuSpeedDividedByCpuOverprovisioningFactor = new ConfigKey<Boolean>("Advanced", Boolean.class, "vm.min.cpu.speed.equals.cpu.speed.divided.by.cpu.overprovisioning.factor", "true",
"If we set this to 'true', a minimum CPU speed (cpu speed/ cpu.overprovisioning.factor) will be set on the VM, independent of using a scalable service offering or not.", true, ConfigKey.Scope.Cluster); "If we set this to 'true', a minimum CPU speed (cpu speed/ cpu.overprovisioning.factor) will be set on the VM, independent of using a scalable service offering or not.", true, ConfigKey.Scope.Cluster);
private Map<NetworkOffering.Detail, String> getNicDetails(Network network) {
if (network == null) {
s_logger.debug("Unable to get NIC details as the network is null");
return null;
}
Map<NetworkOffering.Detail, String> details = networkOfferingDetailsDao.getNtwkOffDetails(network.getNetworkOfferingId());
if (details != null) {
details.putIfAbsent(NetworkOffering.Detail.PromiscuousMode, NetworkOrchestrationService.PromiscuousMode.value().toString());
details.putIfAbsent(NetworkOffering.Detail.MacAddressChanges, NetworkOrchestrationService.MacAddressChanges.value().toString());
details.putIfAbsent(NetworkOffering.Detail.ForgedTransmits, NetworkOrchestrationService.ForgedTransmits.value().toString());
}
NetworkDetailVO pvlantypeDetail = networkDetailsDao.findDetail(network.getId(), ApiConstants.ISOLATED_PVLAN_TYPE);
if (pvlantypeDetail != null) {
details.putIfAbsent(NetworkOffering.Detail.pvlanType, pvlantypeDetail.getValue());
}
return details;
}
@Override @Override
public NicTO toNicTO(NicProfile profile) { public NicTO toNicTO(NicProfile profile) {
NicTO to = new NicTO(); NicTO to = new NicTO();
@ -140,6 +159,7 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
//FixMe: uuid and secondary IPs can be made part of nic profile //FixMe: uuid and secondary IPs can be made part of nic profile
to.setUuid(UUID.randomUUID().toString()); to.setUuid(UUID.randomUUID().toString());
} }
to.setDetails(getNicDetails(network));
//check whether the this nic has secondary ip addresses set //check whether the this nic has secondary ip addresses set
//set nic secondary ip address in NicTO which are used for security group //set nic secondary ip address in NicTO which are used for security group
@ -217,20 +237,6 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
nicProfile.setBroadcastType(BroadcastDomainType.Native); nicProfile.setBroadcastType(BroadcastDomainType.Native);
} }
NicTO nicTo = toNicTO(nicProfile); NicTO nicTo = toNicTO(nicProfile);
final NetworkVO network = _networkDao.findByUuid(nicTo.getNetworkUuid());
if (network != null) {
final Map<NetworkOffering.Detail, String> details = networkOfferingDetailsDao.getNtwkOffDetails(network.getNetworkOfferingId());
if (details != null) {
details.putIfAbsent(NetworkOffering.Detail.PromiscuousMode, NetworkOrchestrationService.PromiscuousMode.value().toString());
details.putIfAbsent(NetworkOffering.Detail.MacAddressChanges, NetworkOrchestrationService.MacAddressChanges.value().toString());
details.putIfAbsent(NetworkOffering.Detail.ForgedTransmits, NetworkOrchestrationService.ForgedTransmits.value().toString());
}
NetworkDetailVO pvlantypeDetail = networkDetailsDao.findDetail(network.getId(), ApiConstants.ISOLATED_PVLAN_TYPE);
if (pvlantypeDetail != null) {
details.putIfAbsent(NetworkOffering.Detail.pvlanType, pvlantypeDetail.getValue());
}
nicTo.setDetails(details);
}
nics[i++] = nicTo; nics[i++] = nicTo;
} }

View File

@ -556,7 +556,7 @@ public class NetworkMigrationManagerImpl implements NetworkMigrationManager {
try { try {
nicProfile = _networkMgr.prepareNic(vmProfile, dest, context, nicProfile.getId(), networkInNewPhysicalNet); nicProfile = _networkMgr.prepareNic(vmProfile, dest, context, nicProfile.getId(), networkInNewPhysicalNet);
_itMgr.replugNic(networkInNewPhysicalNet, _itMgr.toNicTO(nicProfile, host.getHypervisorType()), _itMgr.toVmTO(vmProfile), context, dest); _itMgr.replugNic(networkInNewPhysicalNet, _itMgr.toNicTO(nicProfile, host.getHypervisorType()), _itMgr.toVmTO(vmProfile), dest.getHost());
} catch (ResourceUnavailableException | InsufficientCapacityException e) { } catch (ResourceUnavailableException | InsufficientCapacityException e) {
throw new CloudRuntimeException("Migration of Nic failed", e); throw new CloudRuntimeException("Migration of Nic failed", e);
} }

View File

@ -34,17 +34,15 @@ import java.util.TreeSet;
import javax.inject.Inject; import javax.inject.Inject;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import com.cloud.utils.StringUtils;
import org.apache.cloudstack.context.CallContext;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import com.cloud.api.ApiDBUtils; import com.cloud.api.ApiDBUtils;
import com.cloud.configuration.Config; import com.cloud.configuration.Config;
@ -116,6 +114,7 @@ import com.cloud.user.AccountVO;
import com.cloud.user.DomainManager; import com.cloud.user.DomainManager;
import com.cloud.user.User; import com.cloud.user.User;
import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.AccountDao;
import com.cloud.utils.StringUtils;
import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.component.ManagerBase; import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.db.DB; import com.cloud.utils.db.DB;
@ -1014,23 +1013,33 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
// or on NULL from network.throttling.rate // or on NULL from network.throttling.rate
// For others: Use network rate from their network offering, // For others: Use network rate from their network offering,
// or on NULL from network.throttling.rate setting at zone > global level // or on NULL from network.throttling.rate setting at zone > global level
// http://docs.cloudstack.apache.org/projects/cloudstack-administration/en/latest/service_offerings.html#network-throttling // http://docs.cloudstack.apache.org/en/latest/adminguide/service_offerings.html#network-throttling
if (vm != null) { if (vm != null) {
if (vm.getType() == Type.User) { switch (vm.getType()) {
case User:
final Nic nic = _nicDao.findByNtwkIdAndInstanceId(networkId, vmId); final Nic nic = _nicDao.findByNtwkIdAndInstanceId(networkId, vmId);
if (nic != null && nic.isDefaultNic()) { if (nic != null && nic.isDefaultNic()) {
return _configMgr.getServiceOfferingNetworkRate(vm.getServiceOfferingId(), network.getDataCenterId()); return _configMgr.getServiceOfferingNetworkRate(vm.getServiceOfferingId(), network.getDataCenterId());
} }
break;
case DomainRouter:
if (TrafficType.Guest.equals(network.getTrafficType())) {
final Nic routerNic = _nicDao.findByNtwkIdAndInstanceId(networkId, vmId);
if (routerNic != null) {
return _configMgr.getNetworkOfferingNetworkRate(network.getNetworkOfferingId(), network.getDataCenterId());
} }
if (vm.getType() == Type.DomainRouter && (network.getTrafficType() == TrafficType.Public || network.getTrafficType() == TrafficType.Guest)) { } else if (TrafficType.Public.equals(network.getTrafficType())) {
for (final Nic nic: _nicDao.listByVmId(vmId)) { List<NicVO> routerNics = _nicDao.listByVmId(vmId);
final NetworkVO nw = _networksDao.findById(nic.getNetworkId()); for (final Nic routerNic : routerNics) {
if (nw.getTrafficType() == TrafficType.Guest) { final NetworkVO nw = _networksDao.findById(routerNic.getNetworkId());
if (TrafficType.Guest.equals(nw.getTrafficType())) {
return _configMgr.getNetworkOfferingNetworkRate(nw.getNetworkOfferingId(), network.getDataCenterId()); return _configMgr.getNetworkOfferingNetworkRate(nw.getNetworkOfferingId(), network.getDataCenterId());
} }
} }
} }
if (vm.getType() == Type.ConsoleProxy || vm.getType() == Type.SecondaryStorageVm) { break;
case ConsoleProxy:
case SecondaryStorageVm:
return -1; return -1;
} }
} }

View File

@ -16,6 +16,9 @@
// under the License. // under the License.
package com.cloud.network; package com.cloud.network;
import static org.apache.commons.lang.StringUtils.isBlank;
import static org.apache.commons.lang.StringUtils.isNotBlank;
import java.net.Inet6Address; import java.net.Inet6Address;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.URI; import java.net.URI;
@ -38,7 +41,6 @@ import java.util.UUID;
import javax.inject.Inject; import javax.inject.Inject;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import com.cloud.network.Network.PVlanType;
import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiConstants;
@ -92,11 +94,14 @@ import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.UnsupportedServiceException; import com.cloud.exception.UnsupportedServiceException;
import com.cloud.host.Host;
import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.network.IpAddress.State; import com.cloud.network.IpAddress.State;
import com.cloud.network.Network.Capability; import com.cloud.network.Network.Capability;
import com.cloud.network.Network.GuestType; import com.cloud.network.Network.GuestType;
import com.cloud.network.Network.IpAddresses; import com.cloud.network.Network.IpAddresses;
import com.cloud.network.Network.PVlanType;
import com.cloud.network.Network.Provider; import com.cloud.network.Network.Provider;
import com.cloud.network.Network.Service; import com.cloud.network.Network.Service;
import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.BroadcastDomainType;
@ -187,6 +192,7 @@ import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.exception.ExceptionUtil; import com.cloud.utils.exception.ExceptionUtil;
import com.cloud.utils.net.NetUtils; import com.cloud.utils.net.NetUtils;
import com.cloud.vm.Nic; import com.cloud.vm.Nic;
import com.cloud.vm.NicProfile;
import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.NicSecondaryIp;
import com.cloud.vm.NicVO; import com.cloud.vm.NicVO;
import com.cloud.vm.ReservationContext; import com.cloud.vm.ReservationContext;
@ -195,15 +201,15 @@ import com.cloud.vm.SecondaryStorageVmVO;
import com.cloud.vm.UserVmVO; import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineManager;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.VirtualMachineProfileImpl;
import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.NicSecondaryIpDao; import com.cloud.vm.dao.NicSecondaryIpDao;
import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.NicSecondaryIpVO;
import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.dao.VMInstanceDao;
import static org.apache.commons.lang.StringUtils.isBlank;
import static org.apache.commons.lang.StringUtils.isNotBlank;
/** /**
* NetworkServiceImpl implements NetworkService. * NetworkServiceImpl implements NetworkService.
*/ */
@ -327,6 +333,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
AccountService _accountService; AccountService _accountService;
@Inject @Inject
NetworkAccountDao _networkAccountDao; NetworkAccountDao _networkAccountDao;
@Inject
VirtualMachineManager vmManager;
int _cidrLimit; int _cidrLimit;
boolean _allowSubdomainNetworkAccess; boolean _allowSubdomainNetworkAccess;
@ -2144,6 +2152,38 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
return vms.isEmpty(); return vms.isEmpty();
} }
private void replugNicsForUpdatedNetwork(NetworkVO network) throws ResourceUnavailableException, InsufficientCapacityException {
List<NicVO> nics = _nicDao.listByNetworkId(network.getId());
Network updatedNetwork = getNetwork(network.getId());
for (NicVO nic : nics) {
long vmId = nic.getInstanceId();
VMInstanceVO vm = _vmDao.findById(vmId);
if (vm == null) {
s_logger.error(String.format("Cannot replug NIC: %s as VM for it is not found with ID: %d", nic, vmId));
continue;
}
if (!Hypervisor.HypervisorType.VMware.equals(vm.getHypervisorType())) {
s_logger.debug(String.format("Cannot replug NIC: %s for VM: %s as it is not on VMware", nic, vm));
continue;
}
if (!VirtualMachine.Type.User.equals(vm.getType())) {
s_logger.debug(String.format("Cannot replug NIC: %s for VM: %s as it is not a user VM", nic, vm));
continue;
}
if (!VirtualMachine.State.Running.equals(vm.getState())) {
s_logger.debug(String.format("Cannot replug NIC: %s for VM: %s as it is not in running state", nic, vm));
continue;
}
Host host = _hostDao.findById(vm.getHostId());
VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl(vm, null, null, null, null);
NicProfile nicProfile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(),
_networkModel.getNetworkRate(network.getId(), vm.getId()),
_networkModel.isSecurityGroupSupportedInNetwork(updatedNetwork),
_networkModel.getNetworkTag(vmProfile.getVirtualMachine().getHypervisorType(), network));
vmManager.replugNic(updatedNetwork, vmManager.toNicTO(nicProfile, vm.getHypervisorType()), vmManager.toVmTO(vmProfile), host);
}
}
@Override @Override
@DB @DB
@ActionEvent(eventType = EventTypes.EVENT_NETWORK_UPDATE, eventDescription = "updating network", async = true) @ActionEvent(eventType = EventTypes.EVENT_NETWORK_UPDATE, eventDescription = "updating network", async = true)
@ -2545,6 +2585,9 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
throw e; throw e;
} }
} }
if (networkOfferingChanged) {
replugNicsForUpdatedNetwork(network);
}
} }
// 4) if network has been upgraded from a non persistent ntwk offering to a persistent ntwk offering, // 4) if network has been upgraded from a non persistent ntwk offering to a persistent ntwk offering,

View File

@ -820,6 +820,7 @@
"label.disksizeusedgb": "Used", "label.disksizeusedgb": "Used",
"label.display.text": "Display Text", "label.display.text": "Display Text",
"label.displayname": "Display Name", "label.displayname": "Display Name",
"label.displaynetwork": "Display Network",
"label.displaytext": "Description", "label.displaytext": "Description",
"label.distributedvpcrouter": "Distributed VPC Router", "label.distributedvpcrouter": "Distributed VPC Router",
"label.dns": "DNS", "label.dns": "DNS",
@ -2241,6 +2242,7 @@
"label.untagged": "Untagged", "label.untagged": "Untagged",
"label.update.instance.group": "Update Instance Group", "label.update.instance.group": "Update Instance Group",
"label.update.ip.range": "Update IP range", "label.update.ip.range": "Update IP range",
"label.update.network": "Update Network",
"label.update.physical.network": "Update Physical Network", "label.update.physical.network": "Update Physical Network",
"label.update.project.resources": "Update project resources", "label.update.project.resources": "Update project resources",
"label.update.project.role": "Update project role", "label.update.project.role": "Update project role",
@ -3080,6 +3082,10 @@
"message.network.error": "Network Error", "message.network.error": "Network Error",
"message.network.error.description": "Unable to reach the management server or a browser extension may be blocking the network request.", "message.network.error.description": "Unable to reach the management server or a browser extension may be blocking the network request.",
"message.network.hint": "Configure network components and public/guest/management traffic including IP addresses.", "message.network.hint": "Configure network components and public/guest/management traffic including IP addresses.",
"message.network.offering.change.warning": "WARNING: Changing the offering will cause connectivity downtime for the VMs with NICs in the network.",
"message.network.offering.forged.transmits": "Applicable for guest networks on VMware hypervisor only.\nReject - The switch drops any outbound frame from a virtual machine adapter with a source MAC address that is different from the one in the .vmx configuration file.\nAccept - The switch does not perform filtering, and permits all outbound frames.\nNone - Default to value from global setting.",
"message.network.offering.mac.address.changes": "Applicable for guest networks on VMware hypervisor only.\nReject - If the guest OS changes the effective MAC address of the virtual machine to a value that is different from the MAC address of the VM network adapter (set in the .vmx configuration file), the switch drops all inbound frames to the adapter.\nIf the guest OS changes the effective MAC address of the virtual machine back to the MAC address of the VM network adapter, the virtual machine receives frames again.\nAccept - If the guest OS changes the effective MAC address of the virtual machine to a value that is different from the MAC address of the VM network adapter, the switch allows frames to the new address to pass.\nNone - Default to value from global setting.",
"message.network.offering.promiscuous.mode": "Applicable for guest networks on VMware hypervisor only.\nReject - The switch drops any outbound frame from a virtual machine adapter with a source MAC address that is different from the one in the .vmx configuration file.\nAccept - The switch does not perform filtering, and permits all outbound frames.\nNone - Default to value from global setting.",
"message.network.remote.access.vpn.configuration": "Remote Access VPN configuration has been generated, but it failed to apply. Please check connectivity of the network element, then re-try.", "message.network.remote.access.vpn.configuration": "Remote Access VPN configuration has been generated, but it failed to apply. Please check connectivity of the network element, then re-try.",
"message.network.removenic": "Please confirm that want to remove this NIC, which will also remove the associated network from the VM.", "message.network.removenic": "Please confirm that want to remove this NIC, which will also remove the associated network from the VM.",
"message.network.secondaryip": "Please confirm that you would like to acquire a new secondary IP for this NIC. \n NOTE: You need to manually configure the newly-acquired secondary IP inside the virtual machine.", "message.network.secondaryip": "Please confirm that you would like to acquire a new secondary IP for this NIC. \n NOTE: You need to manually configure the newly-acquired secondary IP inside the virtual machine.",
@ -3291,6 +3297,7 @@
"message.success.update.ipaddress": "Successfully updated IP Address", "message.success.update.ipaddress": "Successfully updated IP Address",
"message.success.update.iprange": "Successfully updated IP range", "message.success.update.iprange": "Successfully updated IP range",
"message.success.update.kubeversion": "Successfully updated Kubernetes supported version", "message.success.update.kubeversion": "Successfully updated Kubernetes supported version",
"message.success.update.network": "Successfully updated Network",
"message.success.update.user": "Successfully updated user", "message.success.update.user": "Successfully updated user",
"message.success.upgrade.kubernetes": "Successfully upgraded Kubernetes cluster", "message.success.upgrade.kubernetes": "Successfully upgraded Kubernetes cluster",
"message.success.upload": "Upload Successfully", "message.success.upload": "Upload Successfully",

View File

@ -75,15 +75,10 @@ export default {
{ {
api: 'updateNetwork', api: 'updateNetwork',
icon: 'edit', icon: 'edit',
label: 'label.edit', label: 'label.update.network',
dataView: true, dataView: true,
args: (record) => { popup: true,
var fields = ['name', 'displaytext', 'guestvmcidr'] component: () => import('@/views/network/UpdateNetwork.vue')
if (record.type === 'Isolated') {
fields.push(...['networkofferingid', 'networkdomain'])
}
return fields
}
}, },
{ {
api: 'restartNetwork', api: 'restartNetwork',

View File

@ -1073,6 +1073,13 @@ export default {
params.isofilter = 'executable' params.isofilter = 'executable'
} else if (possibleApi === 'listHosts') { } else if (possibleApi === 'listHosts') {
params.type = 'routing' params.type = 'routing'
} else if (possibleApi === 'listNetworkOfferings' && this.resource) {
if (this.resource.type) {
params.guestiptype = this.resource.type
}
if (!this.resource.vpcid) {
params.forvpc = false
}
} }
if (showIcon) { if (showIcon) {
params.showicon = true params.showicon = true

View File

@ -0,0 +1,257 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
<template>
<div class="form-layout" v-ctrl-enter="handleSubmit">
<a-spin :spinning="loading">
<a-form
:form="form"
@submit="handleSubmit"
layout="vertical">
<a-form-item>
<tooltip-label slot="label" :title="$t('label.name')" :tooltip="apiParams.name.description"/>
<a-input
v-decorator="['name', {
rules: [{ required: true, message: `${$t('message.error.required.input')}` }]
}]"
:placeholder="apiParams.name.description"
autoFocus />
</a-form-item>
<a-form-item>
<tooltip-label slot="label" :title="$t('label.displaytext')" :tooltip="apiParams.displaytext.description"/>
<a-input
v-decorator="['displaytext', {
rules: [{ required: true, message: `${$t('message.error.required.input')}` }]
}]"
:placeholder="apiParams.displaytext.description"
autoFocus />
</a-form-item>
<a-form-item v-if="isUpdatingIsolatedNetwork">
<tooltip-label slot="label" :title="$t('label.networkofferingid')" :tooltip="apiParams.networkofferingid.description"/>
<span v-if="networkOffering.id && networkOffering.id != resource.networkofferingid">
<a-alert type="warning">
<span slot="message" v-html="$t('message.network.offering.change.warning')" />
</a-alert>
<br/>
</span>
<a-select
id="offering-selection"
v-decorator="['networkofferingid', {}]"
showSearch
optionFilterProp="children"
:filterOption="(input, option) => {
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
}"
:loading="networkOfferingLoading"
:placeholder="apiParams.networkofferingid.description"
@change="val => { networkOffering = networkOfferings[val] }">
<a-select-option v-for="(opt, optIndex) in networkOfferings" :key="optIndex">
{{ opt.displaytext || opt.name }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item>
<tooltip-label slot="label" :title="$t('label.guestvmcidr')" :tooltip="apiParams.guestvmcidr.description"/>
<a-input
v-decorator="['guestvmcidr', {}]"
:placeholder="apiParams.guestvmcidr.description"
@change="(e) => { cidrChanged = e.target.value !== resource.cidr }" />
</a-form-item>
<a-form-item v-if="cidrChanged">
<tooltip-label slot="label" :title="$t('label.changecidr')" :tooltip="apiParams.changecidr.description"/>
<a-switch v-decorator="['changecidr', {}]" />
</a-form-item>
<a-form-item v-if="isUpdatingIsolatedNetwork">
<tooltip-label slot="label" :title="$t('label.networkdomain')" :tooltip="apiParams.guestvmcidr.description"/>
<a-input
v-decorator="['networkdomain', {}]"
:placeholder="apiParams.networkdomain.description"
autoFocus />
</a-form-item>
<a-form-item v-if="resource.redundantrouter">
<tooltip-label slot="label" :title="$t('label.updateinsequence')" :tooltip="apiParams.updateinsequence.description"/>
<a-switch v-decorator="['maclearning', {initialValue: false}]" />
</a-form-item>
<a-form-item v-if="isAdmin()">
<tooltip-label slot="label" :title="$t('label.displaynetwork')" :tooltip="apiParams.displaynetwork.description"/>
<a-switch v-decorator="['displaynetwork', {}]" :defaultChecked="resource.displaynetwork" />
</a-form-item>
<a-form-item v-if="isAdmin()">
<tooltip-label slot="label" :title="$t('label.forced')" :tooltip="apiParams.forced.description"/>
<a-switch v-decorator="['forced', {}]" />
</a-form-item>
<div :span="24" class="action-button">
<a-button @click="closeAction">{{ $t('label.cancel') }}</a-button>
<a-button :loading="loading" ref="submit" type="primary" @click="handleSubmit">{{ this.$t('label.ok') }}</a-button>
</div>
</a-form>
</a-spin>
</div>
</template>
<script>
import { api } from '@/api'
import TooltipLabel from '@/components/widgets/TooltipLabel'
export default {
name: 'UpdateNetwork',
components: {
TooltipLabel
},
props: {
resource: {
type: Object,
required: true
}
},
data () {
return {
resourceValues: {},
networkOfferings: [],
networkOfferingLoading: false,
networkOffering: {},
cidrChanged: false,
loading: false
}
},
beforeCreate () {
this.form = this.$form.createForm(this)
this.apiParams = this.$getApiParams('updateNetwork')
},
created () {
this.resourceValues = {
name: this.resource.name,
displaytext: this.resource.displaytext,
guestvmcidr: this.resource.cidr
}
if (this.isUpdatingIsolatedNetwork) {
this.resourceValues.networkdomain = this.resource.networkdomain
}
for (var field in this.resourceValues) {
var fieldValue = this.resourceValues[field]
if (fieldValue) {
this.form.getFieldDecorator(field, { initialValue: fieldValue })
}
}
this.fetchData()
},
computed: {
isUpdatingIsolatedNetwork () {
return this.resource && this.resource.type === 'Isolated'
}
},
methods: {
isAdmin () {
return ['Admin'].includes(this.$store.getters.userInfo.roletype)
},
fetchData () {
this.fetchNetworkOfferingData()
},
arrayHasItems (array) {
return array !== null && array !== undefined && Array.isArray(array) && array.length > 0
},
fetchNetworkOfferingData () {
this.networkOfferings = []
if (!this.isUpdatingIsolatedNetwork) return
const params = {
zoneid: this.resource.zoneid,
state: 'Enabled',
guestiptype: this.resource.type,
forvpc: !!this.resource.vpcid
}
this.networkOfferingLoading = true
api('listNetworkOfferings', params).then(json => {
this.networkOfferings = json.listnetworkofferingsresponse.networkoffering
}).finally(() => {
this.networkOfferingLoading = false
if (this.arrayHasItems(this.networkOfferings)) {
for (var i = 0; i < this.networkOfferings.length; i++) {
if (this.networkOfferings[i].id === this.resource.networkofferingid) {
this.networkOffering = this.networkOfferings[i]
this.form.setFieldsValue({
networkofferingid: i
})
break
}
}
}
})
},
handleSubmit (e) {
e.preventDefault()
if (this.loading) return
this.form.validateFields((err, values) => {
if (err) {
return
}
this.loading = true
var manualFields = ['name', 'networkofferingid']
const params = {
id: this.resource.id,
name: values.name
}
for (var field in values) {
if (manualFields.includes(field)) continue
var fieldValue = values[field]
if (fieldValue !== undefined &&
fieldValue !== null &&
(!(field in this.resourceValues) || this.resourceValues[field] !== fieldValue)) {
params[field] = fieldValue
}
}
if (values.networkofferingid !== undefined &&
values.networkofferingid != null &&
this.networkOfferings &&
this.networkOfferings[values.networkofferingid].id !== this.resource.networkofferingid) {
params.networkofferingid = this.networkOfferings[values.networkofferingid].id
}
api('updateNetwork', params).then(json => {
const jobId = json.updatenetworkresponse.jobid
this.$pollJob({
jobId,
title: this.$t('label.update.network'),
description: this.resource.name,
loadingMessage: `${this.$t('label.update.network')} ${this.resource.name} ${this.$t('label.in.progress')}`,
catchMessage: this.$t('error.fetching.async.job.result'),
successMessage: `${this.$t('message.success.update.network')} ${this.resource.name}`
})
this.closeAction()
}).catch(error => {
this.$notifyError(error)
}).finally(() => {
this.loading = false
})
})
},
closeAction () {
this.$emit('close-action')
}
}
}
</script>
<style scoped lang="less">
.form-layout {
width: 60vw;
@media (min-width: 500px) {
width: 450px;
}
}
</style>

View File

@ -108,13 +108,13 @@
</a-radio-button> </a-radio-button>
</a-radio-group> </a-radio-group>
</a-form-item> </a-form-item>
<a-form-item :label="$t('label.promiscuousmode')"> <a-form-item>
<tooltip-label slot="label" :title="$t('label.promiscuousmode')" :tooltip="$t('message.network.offering.promiscuous.mode')"/>
<a-radio-group <a-radio-group
v-decorator="['promiscuousmode', { v-decorator="['promiscuousmode', {
initialValue: promiscuousMode initialValue: ''
}]" }]"
buttonStyle="solid" buttonStyle="solid">
@change="selected => { handlePromiscuousModeChange(selected.target.value) }">
<a-radio-button value=""> <a-radio-button value="">
{{ $t('label.none') }} {{ $t('label.none') }}
</a-radio-button> </a-radio-button>
@ -126,13 +126,13 @@
</a-radio-button> </a-radio-button>
</a-radio-group> </a-radio-group>
</a-form-item> </a-form-item>
<a-form-item :label="$t('label.macaddresschanges')"> <a-form-item>
<tooltip-label slot="label" :title="$t('label.macaddresschanges')" :tooltip="$t('message.network.offering.mac.address.changes')"/>
<a-radio-group <a-radio-group
v-decorator="['macaddresschanges', { v-decorator="['macaddresschanges', {
initialValue: macAddressChanges initialValue: ''
}]" }]"
buttonStyle="solid" buttonStyle="solid">
@change="selected => { handleMacAddressChangesChange(selected.target.value) }">
<a-radio-button value=""> <a-radio-button value="">
{{ $t('label.none') }} {{ $t('label.none') }}
</a-radio-button> </a-radio-button>
@ -144,13 +144,13 @@
</a-radio-button> </a-radio-button>
</a-radio-group> </a-radio-group>
</a-form-item> </a-form-item>
<a-form-item :label="$t('label.forgedtransmits')"> <a-form-item>
<tooltip-label slot="label" :title="$t('label.forgedtransmits')" :tooltip="$t('message.network.offering.forged.transmits')"/>
<a-radio-group <a-radio-group
v-decorator="['forgedtransmits', { v-decorator="['forgedtransmits', {
initialValue: forgedTransmits initialValue: ''
}]" }]"
buttonStyle="solid" buttonStyle="solid">
@change="selected => { handleForgedTransmitsChange(selected.target.value) }">
<a-radio-button value=""> <a-radio-button value="">
{{ $t('label.none') }} {{ $t('label.none') }}
</a-radio-button> </a-radio-button>
@ -418,9 +418,6 @@ export default {
hasAdvanceZone: false, hasAdvanceZone: false,
requiredNetworkOfferingExists: false, requiredNetworkOfferingExists: false,
guestType: 'isolated', guestType: 'isolated',
promiscuousMode: '',
macAddressChanges: '',
forgedTransmits: '',
selectedDomains: [], selectedDomains: [],
selectedZones: [], selectedZones: [],
forVpc: false, forVpc: false,
@ -502,15 +499,6 @@ export default {
handleGuestTypeChange (val) { handleGuestTypeChange (val) {
this.guestType = val this.guestType = val
}, },
handlePromiscuousModeChange (val) {
this.promiscuousMode = val
},
handleMacAddressChangesChange (val) {
this.macAddressChanges = val
},
handleForgedTransmitsChange (val) {
this.forgedTransmits = val
},
fetchSupportedServiceData () { fetchSupportedServiceData () {
const params = {} const params = {}
params.listAll = true params.listAll = true
@ -697,7 +685,8 @@ export default {
var self = this var self = this
var selectedServices = null var selectedServices = null
var keys = Object.keys(values) var keys = Object.keys(values)
var ignoredKeys = ['state', 'status', 'allocationstate', 'forvpc', 'specifyvlan', 'ispublic', 'domainid', 'zoneid', 'egressdefaultpolicy', 'promiscuousmode', 'macaddresschanges', 'forgedtransmits', 'isolation', 'supportspublicaccess'] const detailsKey = ['promiscuousmode', 'macaddresschanges', 'forgedtransmits']
const ignoredKeys = [...detailsKey, 'state', 'status', 'allocationstate', 'forvpc', 'specifyvlan', 'ispublic', 'domainid', 'zoneid', 'egressdefaultpolicy', 'isolation', 'supportspublicaccess']
keys.forEach(function (key, keyIndex) { keys.forEach(function (key, keyIndex) {
if (self.isSupportedServiceObject(values[key])) { if (self.isSupportedServiceObject(values[key])) {
if (selectedServices == null) { if (selectedServices == null) {
@ -840,14 +829,10 @@ export default {
if ('egressdefaultpolicy' in values && values.egressdefaultpolicy !== 'allow') { if ('egressdefaultpolicy' in values && values.egressdefaultpolicy !== 'allow') {
params.egressdefaultpolicy = false params.egressdefaultpolicy = false
} }
if (values.promiscuousmode) { for (const key of detailsKey) {
params['details[0].promiscuousMode'] = values.promiscuousmode if (values[key]) {
params['details[0].' + key] = values[key]
} }
if (values.macaddresschanges) {
params['details[0].macaddresschanges'] = values.macaddresschanges
}
if (values.forgedtransmits) {
params['details[0].forgedtransmits'] = values.forgedtransmits
} }
if (values.ispublic !== true) { if (values.ispublic !== true) {
var domainIndexes = values.domainid var domainIndexes = values.domainid

View File

@ -525,17 +525,9 @@ public class HypervisorHostHelper {
} }
/** /**
* @param ethPortProfileName * Prepares network (for non-standard virtual switch) for the VM NIC based on the parameters.
* @param namePrefix * Can create a new portgroup or update an existing.
* @param hostMo * @return Pair of network's ManagedObjectReference and name
* @param vlanId
* @param networkRateMbps
* @param networkRateMulticastMbps
* @param timeOutMs
* @param vSwitchType
* @param numPorts
* @param details
* @return
* @throws Exception * @throws Exception
*/ */
@ -1416,10 +1408,10 @@ public class HypervisorHostHelper {
return false; return false;
} }
if (secPolicyInSpec != null && securityPolicy != null if (secPolicyInSpec != null
&& ((securityPolicy.isAllowPromiscuous() != null && !securityPolicy.isAllowPromiscuous().equals(secPolicyInSpec.isAllowPromiscuous())) && ((securityPolicy.isAllowPromiscuous() != null && !securityPolicy.isAllowPromiscuous().equals(secPolicyInSpec.isAllowPromiscuous()))
|| (securityPolicy.isForgedTransmits() != null && !securityPolicy.isForgedTransmits().equals(secPolicyInSpec.isForgedTransmits())) || (securityPolicy.isForgedTransmits() != null && !securityPolicy.isForgedTransmits().equals(secPolicyInSpec.isForgedTransmits()))
|| (securityPolicy.isMacChanges() != null && securityPolicy.isMacChanges().equals(secPolicyInSpec.isMacChanges())))) { || (securityPolicy.isMacChanges() != null && !securityPolicy.isMacChanges().equals(secPolicyInSpec.isMacChanges())))) {
return false; return false;
} }