diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 27c032832a3..6fd10ca8b28 100644 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -1434,7 +1434,21 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir throw new InvalidParameterValueException("There is no vm with the nic"); } - if (!_networkModel.listNetworkOfferingServices(nicVO.getNetworkId()).isEmpty() && vm.getState() != State.Stopped) { + Network network = _networkDao.findById(nicVO.getNetworkId()); + if (network == null) { + throw new InvalidParameterValueException("There is no network with the nic"); + } + // Don't allow to update vm nic ip if network is not in Implemented/Setup/Allocated state + if (!(network.getState() == Network.State.Allocated || network.getState() == Network.State.Implemented || network.getState() == Network.State.Setup)) { + throw new InvalidParameterValueException("Network is not in the right state to update vm nic ip. Correct states are: " + Network.State.Allocated + ", " + Network.State.Implemented + ", " + + Network.State.Setup); + } + + NetworkOfferingVO offering = _networkOfferingDao.findByIdIncludingRemoved(network.getNetworkOfferingId()); + if (offering == null) { + throw new InvalidParameterValueException("There is no network offering with the network"); + } + if (!_networkModel.listNetworkOfferingServices(offering.getId()).isEmpty() && vm.getState() != State.Stopped) { InvalidParameterValueException ex = new InvalidParameterValueException( "VM is not Stopped, unable to update the vm nic having the specified id"); ex.addProxyObject(vm.getUuid(), "vmId"); @@ -1447,8 +1461,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir // verify ip address s_logger.debug("Calling the ip allocation ..."); - Network network = _networkDao.findById(nicVO.getNetworkId()); DataCenter dc = _dcDao.findById(network.getDataCenterId()); + if (dc == null) { + throw new InvalidParameterValueException("There is no dc with the nic"); + } if (dc.getNetworkType() == NetworkType.Advanced && network.getGuestType() == Network.GuestType.Isolated) { try { ipaddr = _ipAddrMgr.allocateGuestIP(network, ipaddr); @@ -1458,6 +1474,39 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir if (ipaddr == null) { throw new InvalidParameterValueException("Allocating ip to guest nic " + nicVO.getUuid() + " failed, please choose another ip"); } + + if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.StaticNat)) { + IPAddressVO oldIP = _ipAddressDao.findByAssociatedVmId(vm.getId()); + if (oldIP != null) { + oldIP.setVmIp(ipaddr); + _ipAddressDao.persist(oldIP); + } + } + // implementing the network elements and resources as a part of vm nic ip update if network has services and it is in Implemented state + if (!_networkModel.listNetworkOfferingServices(offering.getId()).isEmpty() && network.getState() == Network.State.Implemented) { + User callerUser = _accountMgr.getActiveUser(CallContext.current().getCallingUserId()); + ReservationContext context = new ReservationContextImpl(null, null, callerUser, caller); + DeployDestination dest = new DeployDestination(_dcDao.findById(network.getDataCenterId()), null, null, null); + + s_logger.debug("Implementing the network " + network + " elements and resources as a part of vm nic ip update"); + try { + // implement the network elements and rules again + _networkMgr.implementNetworkElementsAndResources(dest, context, network, offering); + } catch (Exception ex) { + s_logger.warn("Failed to implement network " + network + " elements and resources as a part of vm nic ip update due to ", ex); + CloudRuntimeException e = new CloudRuntimeException("Failed to implement network (with specified id) elements and resources as a part of vm nic ip update"); + e.addProxyObject(network.getUuid(), "networkId"); + // restore to old ip address + if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.StaticNat)) { + IPAddressVO oldIP = _ipAddressDao.findByAssociatedVmId(vm.getId()); + if (oldIP != null) { + oldIP.setVmIp(nicVO.getIPv4Address()); + _ipAddressDao.persist(oldIP); + } + } + throw e; + } + } } else if (dc.getNetworkType() == NetworkType.Basic || network.getGuestType() == Network.GuestType.Shared) { //handle the basic networks here //for basic zone, need to provide the podId to ensure proper ip alloation diff --git a/server/test/com/cloud/vm/UserVmManagerTest.java b/server/test/com/cloud/vm/UserVmManagerTest.java index a94b7651e0d..cffb506285f 100644 --- a/server/test/com/cloud/vm/UserVmManagerTest.java +++ b/server/test/com/cloud/vm/UserVmManagerTest.java @@ -55,6 +55,7 @@ import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd; import org.apache.cloudstack.api.command.user.vm.UpdateVmNicIpCmd; import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; @@ -66,6 +67,7 @@ import com.cloud.configuration.ConfigurationManager; import com.cloud.dc.DataCenterVO; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.dao.DataCenterDao; +import com.cloud.deploy.DeployDestination; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InvalidParameterValueException; @@ -75,6 +77,7 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.hypervisor.Hypervisor; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.IpAddressManager; +import com.cloud.network.Network; import com.cloud.network.Network.GuestType; import com.cloud.network.Network.Service; import com.cloud.network.NetworkModel; @@ -82,6 +85,8 @@ import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; import com.cloud.offering.ServiceOffering; +import com.cloud.offerings.NetworkOfferingVO; +import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.Storage.ImageFormat; @@ -196,6 +201,12 @@ public class UserVmManagerTest { IpAddressManager _ipAddrMgr; @Mock IPAddressDao _ipAddressDao; + @Mock + NetworkOfferingDao _networkOfferingDao; + @Mock + NetworkOfferingVO _networkOfferingMock; + @Mock + NetworkOrchestrationService _networkMgr; @Before public void setup() { @@ -227,6 +238,8 @@ public class UserVmManagerTest { _userVmMgr._dcDao = _dcDao; _userVmMgr._ipAddrMgr = _ipAddrMgr; _userVmMgr._ipAddressDao = _ipAddressDao; + _userVmMgr._networkOfferingDao = _networkOfferingDao; + _userVmMgr._networkMgr = _networkMgr; doReturn(3L).when(_account).getId(); doReturn(8L).when(_vmMock).getAccountId(); @@ -705,6 +718,10 @@ public class UserVmManagerTest { NicVO nic = new NicVO("nic", 1L, 2L, VirtualMachine.Type.User); when(_nicDao.findById(anyLong())).thenReturn(nic); when(_vmDao.findById(anyLong())).thenReturn(_vmMock); + when(_networkDao.findById(anyLong())).thenReturn(_networkMock); + doReturn(9L).when(_networkMock).getNetworkOfferingId(); + when(_networkOfferingDao.findByIdIncludingRemoved(anyLong())).thenReturn(_networkOfferingMock); + doReturn(10L).when(_networkOfferingMock).getId(); List services = new ArrayList(); services.add(Service.Dhcp); @@ -713,13 +730,14 @@ public class UserVmManagerTest { doNothing().when(_accountMgr).checkAccess(_account, null, true, _vmMock); when(_accountDao.findByIdIncludingRemoved(anyLong())).thenReturn(_accountMock); - when(_networkDao.findById(anyLong())).thenReturn(_networkMock); + when(_networkMock.getState()).thenReturn(Network.State.Implemented); when(_networkMock.getDataCenterId()).thenReturn(3L); when(_networkMock.getGuestType()).thenReturn(GuestType.Isolated); when(_dcDao.findById(anyLong())).thenReturn(_dcMock); when(_dcMock.getNetworkType()).thenReturn(NetworkType.Advanced); when(_ipAddrMgr.allocateGuestIP(Mockito.eq(_networkMock), anyString())).thenReturn("10.10.10.10"); + doNothing().when(_networkMgr).implementNetworkElementsAndResources(Mockito.any(DeployDestination.class), Mockito.any(ReservationContext.class), Mockito.eq(_networkMock), Mockito.eq(_networkOfferingMock)); when(_nicDao.persist(any(NicVO.class))).thenReturn(nic); Account caller = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString()); @@ -748,6 +766,10 @@ public class UserVmManagerTest { NicVO nic = new NicVO("nic", 1L, 2L, VirtualMachine.Type.User); when(_nicDao.findById(anyLong())).thenReturn(nic); when(_vmDao.findById(anyLong())).thenReturn(_vmMock); + when(_networkDao.findById(anyLong())).thenReturn(_networkMock); + doReturn(9L).when(_networkMock).getNetworkOfferingId(); + when(_networkOfferingDao.findByIdIncludingRemoved(anyLong())).thenReturn(_networkOfferingMock); + doReturn(10L).when(_networkOfferingMock).getId(); List services = new ArrayList(); when(_networkModel.listNetworkOfferingServices(anyLong())).thenReturn(services); @@ -755,7 +777,7 @@ public class UserVmManagerTest { doNothing().when(_accountMgr).checkAccess(_account, null, true, _vmMock); when(_accountDao.findByIdIncludingRemoved(anyLong())).thenReturn(_accountMock); - when(_networkDao.findById(anyLong())).thenReturn(_networkMock); + when(_networkMock.getState()).thenReturn(Network.State.Implemented); when(_networkMock.getDataCenterId()).thenReturn(3L); when(_networkMock.getGuestType()).thenReturn(GuestType.Shared); when(_dcDao.findById(anyLong())).thenReturn(_dcMock); @@ -792,6 +814,11 @@ public class UserVmManagerTest { NicVO nic = new NicVO("nic", 1L, 2L, VirtualMachine.Type.User); when(_nicDao.findById(anyLong())).thenReturn(nic); when(_vmDao.findById(anyLong())).thenReturn(_vmMock); + when(_networkDao.findById(anyLong())).thenReturn(_networkMock); + when(_networkMock.getState()).thenReturn(Network.State.Implemented); + doReturn(9L).when(_networkMock).getNetworkOfferingId(); + when(_networkOfferingDao.findByIdIncludingRemoved(anyLong())).thenReturn(_networkOfferingMock); + doReturn(10L).when(_networkOfferingMock).getId(); List services = new ArrayList(); services.add(Service.Dhcp); @@ -825,6 +852,10 @@ public class UserVmManagerTest { NicVO nic = new NicVO("nic", 1L, 2L, VirtualMachine.Type.User); when(_nicDao.findById(anyLong())).thenReturn(nic); when(_vmDao.findById(anyLong())).thenReturn(_vmMock); + when(_networkDao.findById(anyLong())).thenReturn(_networkMock); + doReturn(9L).when(_networkMock).getNetworkOfferingId(); + when(_networkOfferingDao.findByIdIncludingRemoved(anyLong())).thenReturn(_networkOfferingMock); + doReturn(10L).when(_networkOfferingMock).getId(); List services = new ArrayList(); services.add(Service.Dhcp); @@ -833,7 +864,7 @@ public class UserVmManagerTest { doNothing().when(_accountMgr).checkAccess(_account, null, true, _vmMock); when(_accountDao.findByIdIncludingRemoved(anyLong())).thenReturn(_accountMock); - when(_networkDao.findById(anyLong())).thenReturn(_networkMock); + when(_networkMock.getState()).thenReturn(Network.State.Implemented); when(_networkMock.getDataCenterId()).thenReturn(3L); when(_networkMock.getGuestType()).thenReturn(GuestType.Isolated); when(_dcDao.findById(anyLong())).thenReturn(_dcMock); @@ -868,6 +899,10 @@ public class UserVmManagerTest { NicVO nic = new NicVO("nic", 1L, 2L, VirtualMachine.Type.User); when(_nicDao.findById(anyLong())).thenReturn(nic); when(_vmDao.findById(anyLong())).thenReturn(_vmMock); + when(_networkDao.findById(anyLong())).thenReturn(_networkMock); + doReturn(9L).when(_networkMock).getNetworkOfferingId(); + when(_networkOfferingDao.findByIdIncludingRemoved(anyLong())).thenReturn(_networkOfferingMock); + doReturn(10L).when(_networkOfferingMock).getId(); List services = new ArrayList(); services.add(Service.Dhcp); @@ -876,7 +911,7 @@ public class UserVmManagerTest { doNothing().when(_accountMgr).checkAccess(_account, null, true, _vmMock); when(_accountDao.findByIdIncludingRemoved(anyLong())).thenReturn(_accountMock); - when(_networkDao.findById(anyLong())).thenReturn(_networkMock); + when(_networkMock.getState()).thenReturn(Network.State.Implemented); when(_networkMock.getDataCenterId()).thenReturn(3L); when(_networkMock.getGuestType()).thenReturn(GuestType.Shared); when(_dcDao.findById(anyLong())).thenReturn(_dcMock);