From 59acbc51b15f4dceb0a13580124ac71791154135 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Wed, 9 Dec 2015 09:43:18 +0100 Subject: [PATCH 1/7] CLOUDSTACK-9114: Rolling restart for VRs on restartNetwork This introduces a rolling restart of VRs when networks are restarted with cleanup option. Signed-off-by: Rohit Yadav --- api/src/com/cloud/network/Network.java | 2 + api/src/com/cloud/network/NetworkProfile.java | 5 + api/src/com/cloud/network/NetworkService.java | 2 +- .../cloud/network/router/VirtualRouter.java | 2 + api/src/com/cloud/network/vpc/Vpc.java | 6 + .../apache/cloudstack/api/ApiConstants.java | 3 +- .../user/network/RestartNetworkCmd.java | 12 +- .../api/command/user/vpc/RestartVPCCmd.java | 2 +- .../api/response/NetworkResponse.java | 12 ++ .../service/NetworkOrchestrationService.java | 6 + .../orchestration/NetworkOrchestrator.java | 185 ++++++++++++------ .../com/cloud/network/dao/NetworkDaoImpl.java | 3 +- .../src/com/cloud/network/dao/NetworkVO.java | 25 ++- .../src/com/cloud/network/vpc/VpcVO.java | 13 ++ .../src/com/cloud/vm/DomainRouterVO.java | 1 + .../src/com/cloud/api/ApiResponseHelper.java | 1 + .../com/cloud/network/NetworkServiceImpl.java | 10 +- .../network/element/VirtualRouterElement.java | 2 +- .../com/cloud/network/vpc/VpcManagerImpl.java | 74 +++++-- .../RouterDeploymentDefinition.java | 8 +- .../VpcRouterDeploymentDefinition.java | 5 + .../com/cloud/vpc/MockNetworkManagerImpl.java | 12 +- systemvm/debian/opt/cloud/bin/cs/CsAddress.py | 4 +- systemvm/debian/opt/cloud/bin/setup/common.sh | 6 +- .../debian/opt/cloud/bin/setup/postinit.sh | 6 +- .../opt/cloud/templates/keepalived.conf.templ | 6 +- ui/scripts/network.js | 31 ++- 27 files changed, 337 insertions(+), 107 deletions(-) diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index e4990de6cdac..75196a469d3e 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -351,6 +351,8 @@ public void setIp6Address(String ip6Address) { boolean isRedundant(); + boolean isRollingRestart(); + long getRelated(); URI getBroadcastUri(); diff --git a/api/src/com/cloud/network/NetworkProfile.java b/api/src/com/cloud/network/NetworkProfile.java index 127750aa2efc..d8733ca6c501 100644 --- a/api/src/com/cloud/network/NetworkProfile.java +++ b/api/src/com/cloud/network/NetworkProfile.java @@ -155,6 +155,11 @@ public boolean isRedundant() { return this.isRedundant; } + @Override + public boolean isRollingRestart() { + return false; + } + @Override public String getName() { return name; diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index 2559cfa97fbf..d76d65972026 100644 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -70,7 +70,7 @@ IpAddress allocatePortableIP(Account ipOwner, int regionId, Long zoneId, Long ne boolean deleteNetwork(long networkId, boolean forced); - boolean restartNetwork(RestartNetworkCmd cmd, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException; + boolean restartNetwork(RestartNetworkCmd cmd, boolean cleanup, boolean makeRedundant) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException; int getActiveNicsInNetwork(long networkId); diff --git a/api/src/com/cloud/network/router/VirtualRouter.java b/api/src/com/cloud/network/router/VirtualRouter.java index 84c85ce66758..0849880e953c 100644 --- a/api/src/com/cloud/network/router/VirtualRouter.java +++ b/api/src/com/cloud/network/router/VirtualRouter.java @@ -40,6 +40,8 @@ public enum RedundantState { RedundantState getRedundantState(); + void setRedundantState(final RedundantState redundantState); + String getPublicIpAddress(); boolean isStopPending(); diff --git a/api/src/com/cloud/network/vpc/Vpc.java b/api/src/com/cloud/network/vpc/Vpc.java index dd607fe6caa9..2e4c77214626 100644 --- a/api/src/com/cloud/network/vpc/Vpc.java +++ b/api/src/com/cloud/network/vpc/Vpc.java @@ -76,6 +76,8 @@ public enum State { boolean isRedundant(); + void setRedundant(final boolean isRedundant); + /** * * @return true if VPC is configured to use distributed router to provides one-hop forwarding and hypervisor based ACL @@ -87,4 +89,8 @@ public enum State { * @return true if VPC spans multiple zones in the region */ boolean isRegionLevelVpc(); + + boolean isRollingRestart(); + + void setRollingRestart(boolean rollingRestart); } diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index dfe9b30f3068..03ee7fc1b20b 100644 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -56,7 +56,7 @@ public class ApiConstants { public static final String CIDR_LIST = "cidrlist"; public static final String DEST_CIDR_LIST = "destcidrlist"; public static final String CLEANUP = "cleanup"; - public static final String MAKEREDUNDANTE = "makeredundant"; + public static final String MAKEREDUNDANT = "makeredundant"; public static final String CLUSTER_ID = "clusterid"; public static final String CLUSTER_NAME = "clustername"; public static final String CLUSTER_TYPE = "clustertype"; @@ -681,6 +681,7 @@ public class ApiConstants { public static final String REMAININGCAPACITY = "remainingcapacity"; public static final String MAXCAPACITY = "maxcapacity"; public static final String DISTRIBUTED_VPC_ROUTER = "distributedvpcrouter"; + public static final String REDUNDANT_ROUTER = "redundantrouter"; public static final String REDUNDANT_VPC_ROUTER = "redundantvpcrouter"; public static final String READ_ONLY = "readonly"; public static final String SUPPORTS_REGION_LEVEL_VPC = "supportsregionLevelvpc"; diff --git a/api/src/org/apache/cloudstack/api/command/user/network/RestartNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/RestartNetworkCmd.java index 62566653bca7..24cb70aa70bc 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/RestartNetworkCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/RestartNetworkCmd.java @@ -57,6 +57,9 @@ public class RestartNetworkCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.CLEANUP, type = CommandType.BOOLEAN, required = false, description = "If cleanup old network elements") private Boolean cleanup; + @Parameter(name = ApiConstants.MAKEREDUNDANT, type = CommandType.BOOLEAN, required = false, description = "Turn the network into a network with redundant routers.", since = "4.11.1") + private Boolean makeRedundant; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -77,6 +80,13 @@ public Boolean getCleanup() { return true; } + public Boolean getMakeRedundant() { + if (makeRedundant != null) { + return makeRedundant; + } + return true; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -92,7 +102,7 @@ public static String getResultObjectName() { @Override public void execute() throws ResourceUnavailableException, ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException { - boolean result = _networkService.restartNetwork(this, getCleanup()); + boolean result = _networkService.restartNetwork(this, getCleanup(), getMakeRedundant()); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); setResponseObject(response); diff --git a/api/src/org/apache/cloudstack/api/command/user/vpc/RestartVPCCmd.java b/api/src/org/apache/cloudstack/api/command/user/vpc/RestartVPCCmd.java index ea34c6a95807..21619eb8a767 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vpc/RestartVPCCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vpc/RestartVPCCmd.java @@ -51,7 +51,7 @@ public class RestartVPCCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.CLEANUP, type = CommandType.BOOLEAN, required = false, description = "If cleanup old network elements") private Boolean cleanup; - @Parameter(name = ApiConstants.MAKEREDUNDANTE, type = CommandType.BOOLEAN, required = false, description = "Turn a single VPC into a redundant one.") + @Parameter(name = ApiConstants.MAKEREDUNDANT, type = CommandType.BOOLEAN, required = false, description = "Turn a single VPC into a redundant one.") private Boolean makeredundant; ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/response/NetworkResponse.java b/api/src/org/apache/cloudstack/api/response/NetworkResponse.java index f54b063ad41b..8d0f725500bb 100644 --- a/api/src/org/apache/cloudstack/api/response/NetworkResponse.java +++ b/api/src/org/apache/cloudstack/api/response/NetworkResponse.java @@ -229,6 +229,10 @@ public class NetworkResponse extends BaseResponse implements ControlledEntityRes @Param(description = "The external id of the network", since = "4.11") private String externalId; + @SerializedName(ApiConstants.REDUNDANT_ROUTER) + @Param(description = "If the network has redundant routers enabled", since = "4.11.1") + private Boolean redundantRouter; + public Boolean getDisplayNetwork() { return displayNetwork; } @@ -437,4 +441,12 @@ public void setNetworkSpannedZones(Set networkSpannedZones) { public void setExternalId(String externalId) { this.externalId = externalId; } + + public Boolean getRedundantRouter() { + return redundantRouter; + } + + public void setRedundantRouter(Boolean redundantRouter) { + this.redundantRouter = redundantRouter; + } } diff --git a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java index 67471d0d3e4c..753750085d97 100644 --- a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java +++ b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java @@ -43,6 +43,7 @@ import com.cloud.network.element.StaticNatServiceProvider; import com.cloud.network.element.UserDataServiceProvider; import com.cloud.network.guru.NetworkGuru; +import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.offering.NetworkOffering; import com.cloud.user.Account; @@ -282,4 +283,9 @@ void implementNetworkElementsAndResources(DeployDestination dest, ReservationCon void finalizeUpdateInSequence(Network network, boolean success); List getNetworkGurus(); + + void destroyExpendableRouters(final List routers, final ReservationContext context) throws ResourceUnavailableException; + + boolean validateNewRouters(final List routers); + } diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 1b707c3979d4..50579ab335f0 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -38,15 +38,11 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.utils.StringUtils; -import org.apache.log4j.Logger; - import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.cloud.entity.api.db.VMNetworkMapVO; import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMNetworkMapDao; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; -import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.ConfigKey.Scope; import org.apache.cloudstack.framework.config.Configurable; @@ -54,8 +50,7 @@ import org.apache.cloudstack.framework.messagebus.MessageBus; import org.apache.cloudstack.framework.messagebus.PublishScope; import org.apache.cloudstack.managed.context.ManagedContextRunnable; -import org.apache.cloudstack.region.PortableIpDao; - +import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; @@ -87,7 +82,6 @@ import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; import com.cloud.domain.Domain; -import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ConnectionException; import com.cloud.exception.InsufficientAddressCapacityException; @@ -119,6 +113,7 @@ import com.cloud.network.PhysicalNetwork; import com.cloud.network.PhysicalNetworkSetupInfo; import com.cloud.network.RemoteAccessVpn; +import com.cloud.network.VpcVirtualNetworkApplianceService; import com.cloud.network.addr.PublicIp; import com.cloud.network.dao.AccountGuestVlanMapDao; import com.cloud.network.dao.AccountGuestVlanMapVO; @@ -128,7 +123,6 @@ import com.cloud.network.dao.NetworkAccountDao; import com.cloud.network.dao.NetworkAccountVO; import com.cloud.network.dao.NetworkDao; -import com.cloud.network.dao.NetworkDetailsDao; import com.cloud.network.dao.NetworkDomainDao; import com.cloud.network.dao.NetworkDomainVO; import com.cloud.network.dao.NetworkServiceMapDao; @@ -141,7 +135,6 @@ import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.dao.RemoteAccessVpnDao; import com.cloud.network.dao.RemoteAccessVpnVO; -import com.cloud.network.dao.VpnUserDao; import com.cloud.network.element.AggregatedCommandExecutor; import com.cloud.network.element.DhcpServiceProvider; import com.cloud.network.element.DnsServiceProvider; @@ -183,6 +176,7 @@ import com.cloud.user.dao.AccountDao; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; +import com.cloud.utils.StringUtils; import com.cloud.utils.UuidUtils; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.ManagerBase; @@ -201,9 +195,9 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; import com.cloud.utils.fsm.StateMachine2; +import com.cloud.utils.net.Dhcp; import com.cloud.utils.net.NetUtils; import com.cloud.vm.DomainRouterVO; -import com.cloud.utils.net.Dhcp; import com.cloud.vm.Nic; import com.cloud.vm.Nic.ReservationStrategy; import com.cloud.vm.NicExtraDhcpOptionVO; @@ -287,11 +281,11 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra @Inject VMNetworkMapDao _vmNetworkMapDao; @Inject - DomainRouterDao _rotuerDao; + DomainRouterDao _routerDao; @Inject RemoteAccessVpnDao _remoteAccessVpnDao; @Inject - VpnUserDao _vpnUserDao; + VpcVirtualNetworkApplianceService _routerService; List networkGurus; @@ -369,17 +363,9 @@ public void setDhcpProviders(final List dhcpProviders) { @Inject NetworkACLManager _networkACLMgr; @Inject - UsageEventDao _usageEventDao; - @Inject NetworkModel _networkModel; @Inject NicSecondaryIpDao _nicSecondaryIpDao; - @Inject - PortableIpDao _portableIpDao; - @Inject - ConfigDepot _configDepot; - @Inject - NetworkDetailsDao _networkDetailsDao; protected StateMachine2 _stateMachine; ScheduledExecutorService _executor; @@ -1147,29 +1133,7 @@ public void implementNetworkElementsAndResources(final DeployDestination dest, f } // get providers to implement final List providersToImplement = getNetworkProviders(network.getId()); - for (final NetworkElement element : networkElements) { - if (providersToImplement.contains(element.getProvider())) { - if (!_networkModel.isProviderEnabledInPhysicalNetwork(_networkModel.getPhysicalNetworkId(network), element.getProvider().getName())) { - // The physicalNetworkId will not get translated into a uuid by the reponse serializer, - // because the serializer would look up the NetworkVO class's table and retrieve the - // network id instead of the physical network id. - // So just throw this exception as is. We may need to TBD by changing the serializer. - throw new CloudRuntimeException("Service provider " + element.getProvider().getName() + " either doesn't exist or is not enabled in physical network id: " - + network.getPhysicalNetworkId()); - } - - if (s_logger.isDebugEnabled()) { - s_logger.debug("Asking " + element.getName() + " to implement " + network); - } - - if (!element.implement(network, offering, dest, context)) { - final CloudRuntimeException ex = new CloudRuntimeException("Failed to implement provider " + element.getProvider().getName() + " for network with specified id"); - ex.addProxyObject(network.getUuid(), "networkId"); - throw ex; - } - } - } - + implementNetworkElements(dest, context, network, offering, providersToImplement); //Reset the extra DHCP option that may have been cleared per nic. List nicVOs = _nicDao.listByNetworkId(network.getId()); @@ -1217,6 +1181,32 @@ public void implementNetworkElementsAndResources(final DeployDestination dest, f } } + protected void implementNetworkElements(final DeployDestination dest, final ReservationContext context, final Network network, final NetworkOffering offering, final List providersToImplement) + throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { + for (NetworkElement element : networkElements) { + if (providersToImplement.contains(element.getProvider())) { + if (!_networkModel.isProviderEnabledInPhysicalNetwork(_networkModel.getPhysicalNetworkId(network), element.getProvider().getName())) { + // The physicalNetworkId will not get translated into a uuid by the reponse serializer, + // because the serializer would look up the NetworkVO class's table and retrieve the + // network id instead of the physical network id. + // So just throw this exception as is. We may need to TBD by changing the serializer. + throw new CloudRuntimeException("Service provider " + element.getProvider().getName() + " either doesn't exist or is not enabled in physical network id: " + + network.getPhysicalNetworkId()); + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Asking " + element.getName() + " to implemenet " + network); + } + + if (!element.implement(network, offering, dest, context)) { + CloudRuntimeException ex = new CloudRuntimeException("Failed to implement provider " + element.getProvider().getName() + " for network with specified id"); + ex.addProxyObject(network.getUuid(), "networkId"); + throw ex; + } + } + } + } + // This method re-programs the rules/ips for existing network protected boolean reprogramNetworkRules(final long networkId, final Account caller, final Network network) throws ResourceUnavailableException { boolean success = true; @@ -1235,7 +1225,6 @@ protected boolean reprogramNetworkRules(final long networkId, final Account call success = false; } - // associate all ip addresses if (!_ipAddrMgr.applyIpAssociations(network, false)) { s_logger.warn("Failed to apply ip addresses as a part of network id" + networkId + " restart"); @@ -1344,15 +1333,15 @@ public boolean canUpdateInSequence(Network network, boolean forced){ List providers = getNetworkProviders(network.getId()); //check if the there are no service provider other than virtualrouter. - for(Provider provider :providers){ - if(provider!=Provider.VirtualRouter) + for(Provider provider : providers) { + if (provider!=Provider.VirtualRouter) throw new UnsupportedOperationException("Cannot update the network resources in sequence when providers other than virtualrouter are used"); } //check if routers are in correct state before proceeding with the update - List routers=_rotuerDao.listByNetworkAndRole(network.getId(), VirtualRouter.Role.VIRTUAL_ROUTER); - for(DomainRouterVO router :routers){ - if(router.getRedundantState()== VirtualRouter.RedundantState.UNKNOWN){ - if(!forced){ + List routers = _routerDao.listByNetworkAndRole(network.getId(), VirtualRouter.Role.VIRTUAL_ROUTER); + for (DomainRouterVO router : routers){ + if (router.getRedundantState() == VirtualRouter.RedundantState.UNKNOWN) { + if (!forced) { throw new CloudRuntimeException("Domain router: "+router.getInstanceName()+" is in unknown state, Cannot update network. set parameter forced to true for forcing an update"); } } @@ -2839,26 +2828,18 @@ public boolean restartNetwork(final Long networkId, final Account callerAccount, s_logger.debug("Restarting network " + networkId + "..."); final ReservationContext context = new ReservationContextImpl(null, null, callerUser, callerAccount); + final NetworkOffering offering = _networkOfferingDao.findByIdIncludingRemoved(network.getNetworkOfferingId()); + final DeployDestination dest = new DeployDestination(_dcDao.findById(network.getDataCenterId()), null, null, null); if (cleanup) { - // shutdown the network - s_logger.debug("Shutting down the network id=" + networkId + " as a part of network restart"); - - if (!shutdownNetworkElementsAndResources(context, true, network)) { - s_logger.debug("Failed to shutdown the network elements and resources as a part of network restart: " + network.getState()); + if (!rollingRestartRouters(network, offering, dest, context)) { setRestartRequired(network, true); return false; } - } else { - s_logger.debug("Skip the shutting down of network id=" + networkId); + return true; } - // implement the network elements and rules again - final 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 network restart"); - final NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); - + s_logger.debug("Implementing the network " + network + " elements and resources as a part of network restart without cleanup"); try { implementNetworkElementsAndResources(dest, context, network, offering); setRestartRequired(network, true); @@ -2869,6 +2850,84 @@ public boolean restartNetwork(final Long networkId, final Account callerAccount, } } + @Override + public void destroyExpendableRouters(final List routers, final ReservationContext context) throws ResourceUnavailableException { + final List remainingRouters = new ArrayList<>(); + // Purge invalid routers + for (final VirtualRouter router : routers) { + if (router.getState() == VirtualMachine.State.Stopped || + router.getState() == VirtualMachine.State.Error || + router.getState() == VirtualMachine.State.Shutdowned || + router.getState() == VirtualMachine.State.Unknown) { + s_logger.debug("Destroying old router " + router); + _routerService.destroyRouter(router.getId(), context.getAccount(), context.getCaller().getId()); + } else { + remainingRouters.add(router); + } + } + + if (remainingRouters.size() < 2) { + return; + } + + // Purge any backup router + VirtualRouter backupRouter = null; + for (final VirtualRouter router : remainingRouters) { + if (router.getRedundantState() == VirtualRouter.RedundantState.BACKUP) { + backupRouter = router; + } + } + if (backupRouter == null) { + backupRouter = routers.get(routers.size() - 1); + } + if (backupRouter != null) { + _routerService.destroyRouter(backupRouter.getId(), context.getAccount(), context.getCaller().getId()); + } + } + + @Override + public boolean validateNewRouters(final List routers) { + for (final VirtualRouter router : routers) { + if (router.getState() != VirtualMachine.State.Running) { + s_logger.debug("Found new router " + router.getInstanceName() + " to be in non-Running state: " + router.getState() + ". Please try restarting network again."); + return false; + } + } + return true; + } + + private boolean rollingRestartRouters(final NetworkVO network, final NetworkOffering offering, final DeployDestination dest, final ReservationContext context) throws ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException { + s_logger.debug("Performing rolling restart of routers of network " + network); + destroyExpendableRouters(_routerDao.findByNetwork(network.getId()), context); + + final List providersToImplement = getNetworkProviders(network.getId()); + final List oldRouters = _routerDao.findByNetwork(network.getId()); + + // Deploy a new router + network.setRollingRestart(true); + implementNetworkElements(dest, context, network, offering, providersToImplement); + network.setRollingRestart(false); + + // For redundant network wait for 3*advert_int+skew_seconds for VRRP to kick in + if (network.isRedundant() || (oldRouters.size() == 1 && oldRouters.get(0).getIsRedundantRouter())) { + try { + Thread.sleep(10000L); + } catch (final InterruptedException ignored) {} + } + + // Destroy old routers + for (final DomainRouterVO oldRouter : oldRouters) { + _routerService.destroyRouter(oldRouter.getId(), context.getAccount(), context.getCaller().getId()); + } + + // Add a new backup router for redundant network + if (network.isRedundant()) { + implementNetworkElements(dest, context, network, offering, providersToImplement); + } + + return validateNewRouters(_routerDao.findByNetwork(network.getId())); + } + private void setRestartRequired(final NetworkVO network, final boolean restartRequired) { s_logger.debug("Marking network " + network + " with restartRequired=" + restartRequired); network.setRestartRequired(restartRequired); diff --git a/engine/schema/src/com/cloud/network/dao/NetworkDaoImpl.java b/engine/schema/src/com/cloud/network/dao/NetworkDaoImpl.java index 11444b0d008a..1e33b6ac535f 100644 --- a/engine/schema/src/com/cloud/network/dao/NetworkDaoImpl.java +++ b/engine/schema/src/com/cloud/network/dao/NetworkDaoImpl.java @@ -116,6 +116,7 @@ protected void init() { AllFieldsSearch.and("broadcastUri", AllFieldsSearch.entity().getBroadcastUri(), Op.EQ); AllFieldsSearch.and("vpcId", AllFieldsSearch.entity().getVpcId(), Op.EQ); AllFieldsSearch.and("aclId", AllFieldsSearch.entity().getNetworkACLId(), Op.EQ); + AllFieldsSearch.and("redundant", AllFieldsSearch.entity().isRedundant(), Op.EQ); final SearchBuilder join1 = _ntwkOffDao.createSearchBuilder(); join1.and("isSystem", join1.entity().isSystemOnly(), Op.EQ); join1.and("isRedundant", join1.entity().getRedundantRouter(), Op.EQ); @@ -656,7 +657,7 @@ public List listNetworksByAccount(final long accountId, final long zo @Override public List listRedundantNetworks() { final SearchCriteria sc = AllFieldsSearch.create(); - sc.setJoinParameters("offerings", "isRedundant", true); + sc.setParameters("redundant", true); return listBy(sc, null); } diff --git a/engine/schema/src/com/cloud/network/dao/NetworkVO.java b/engine/schema/src/com/cloud/network/dao/NetworkVO.java index 320256b90c0f..0c0bd4de6a12 100644 --- a/engine/schema/src/com/cloud/network/dao/NetworkVO.java +++ b/engine/schema/src/com/cloud/network/dao/NetworkVO.java @@ -178,13 +178,8 @@ public class NetworkVO implements Network { @Transient transient String vlanIdAsUUID; - public String getVlanIdAsUUID() { - return vlanIdAsUUID; - } - - public void setVlanIdAsUUID(String vlanIdAsUUID) { - this.vlanIdAsUUID = vlanIdAsUUID; - } + @Transient + boolean rollingRestart = false; public NetworkVO() { uuid = UUID.randomUUID().toString(); @@ -650,4 +645,20 @@ public String getExternalId() { public void setExternalId(String externalId) { this.externalId = externalId; } + + public String getVlanIdAsUUID() { + return vlanIdAsUUID; + } + + public void setVlanIdAsUUID(String vlanIdAsUUID) { + this.vlanIdAsUUID = vlanIdAsUUID; + } + + public boolean isRollingRestart() { + return rollingRestart; + } + + public void setRollingRestart(boolean rollingRestart) { + this.rollingRestart = rollingRestart; + } } diff --git a/engine/schema/src/com/cloud/network/vpc/VpcVO.java b/engine/schema/src/com/cloud/network/vpc/VpcVO.java index b78f22f9f55b..3061d305d05b 100644 --- a/engine/schema/src/com/cloud/network/vpc/VpcVO.java +++ b/engine/schema/src/com/cloud/network/vpc/VpcVO.java @@ -25,6 +25,7 @@ import javax.persistence.Enumerated; import javax.persistence.Id; import javax.persistence.Table; +import javax.persistence.Transient; import com.cloud.utils.db.GenericDao; @@ -88,6 +89,9 @@ public class VpcVO implements Vpc { @Column(name = "region_level_vpc") boolean regionLevelVpc = false; + @Transient + boolean rollingRestart = false; + public VpcVO() { uuid = UUID.randomUUID().toString(); } @@ -228,6 +232,15 @@ public void setRedundant(final boolean isRedundant) { redundant = isRedundant; } + @Override + public boolean isRollingRestart() { + return rollingRestart; + } + + public void setRollingRestart(boolean rollingRestart) { + this.rollingRestart = rollingRestart; + } + @Override public Class getEntityType() { return Vpc.class; diff --git a/engine/schema/src/com/cloud/vm/DomainRouterVO.java b/engine/schema/src/com/cloud/vm/DomainRouterVO.java index 2a7aa49b6ed4..6398a017b5a0 100644 --- a/engine/schema/src/com/cloud/vm/DomainRouterVO.java +++ b/engine/schema/src/com/cloud/vm/DomainRouterVO.java @@ -162,6 +162,7 @@ public RedundantState getRedundantState() { return redundantState; } + @Override public void setRedundantState(final RedundantState redundantState) { this.redundantState = redundantState; } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 88da6342b81c..e1e81ce8269f 100644 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -2241,6 +2241,7 @@ public NetworkResponse createNetworkResponse(ResponseView view, Network network) response.setNetworkSpannedZones(networkSpannedZones); } response.setExternalId(network.getExternalId()); + response.setRedundantRouter(network.isRedundant()); response.setObjectName("network"); return response; } diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 93f73d20a5f7..33a817872835 100644 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -1842,7 +1842,7 @@ public boolean deleteNetwork(long networkId, boolean forced) { @Override @ActionEvent(eventType = EventTypes.EVENT_NETWORK_RESTART, eventDescription = "restarting network", async = true) - public boolean restartNetwork(RestartNetworkCmd cmd, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { + public boolean restartNetwork(RestartNetworkCmd cmd, boolean cleanup, boolean makeRedundant) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { // This method restarts all network elements belonging to the network and re-applies all the rules Long networkId = cmd.getNetworkId(); @@ -1872,6 +1872,14 @@ public boolean restartNetwork(RestartNetworkCmd cmd, boolean cleanup) throws Con _accountMgr.checkAccess(callerAccount, null, true, network); + if (!network.isRedundant() && makeRedundant) { + network.setRedundant(true); + if (!_networksDao.update(network.getId(), network)) { + throw new CloudRuntimeException("Failed to update network into a redundant one, please try again"); + } + cleanup = true; + } + boolean success = _networkMgr.restartNetwork(networkId, callerAccount, callerUser, cleanup); if (success) { diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index 896a4892920c..8b628486620a 100644 --- a/server/src/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VirtualRouterElement.java @@ -227,7 +227,7 @@ public boolean implement(final Network network, final NetworkOffering offering, final List routers = routerDeploymentDefinition.deployVirtualRouter(); int routerCounts = 1; - if (offering.getRedundantRouter()) { + if (offering.getRedundantRouter() || network.isRollingRestart()) { routerCounts = 2; } if (routers == null || routers.size() < routerCounts) { diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index ab6441ac5b7e..e530dc8e78e5 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -33,13 +33,11 @@ import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; + import javax.annotation.PostConstruct; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.commons.collections.CollectionUtils; -import org.apache.log4j.Logger; - import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.api.command.user.vpc.ListPrivateGatewaysCmd; import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd; @@ -47,6 +45,9 @@ import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.commons.collections.CollectionUtils; +import org.apache.log4j.Logger; + import com.cloud.configuration.Config; import com.cloud.configuration.Resource.ResourceType; import com.cloud.dc.DataCenter; @@ -88,6 +89,7 @@ import com.cloud.network.element.NetworkElement; import com.cloud.network.element.StaticNatServiceProvider; import com.cloud.network.element.VpcProvider; +import com.cloud.network.router.VpcVirtualNetworkApplianceManager; import com.cloud.network.vpc.VpcOffering.State; import com.cloud.network.vpc.dao.NetworkACLDao; import com.cloud.network.vpc.dao.PrivateIpDao; @@ -132,8 +134,10 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.ExceptionUtil; import com.cloud.utils.net.NetUtils; +import com.cloud.vm.DomainRouterVO; import com.cloud.vm.ReservationContext; import com.cloud.vm.ReservationContextImpl; +import com.cloud.vm.dao.DomainRouterDao; public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvisioningService, VpcService { private static final Logger s_logger = Logger.getLogger(VpcManagerImpl.class); @@ -196,6 +200,10 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis NetworkACLManager _networkAclMgr; @Inject IpAddressManager _ipAddrMgr; + @Inject + VpcVirtualNetworkApplianceManager _routerService; + @Inject + DomainRouterDao _routerDao; @Inject private VpcPrivateGatewayTransactionCallable vpcTxCallable; @@ -1482,22 +1490,23 @@ public boolean cleanupVpcResources(final long vpcId, final Account caller, final public boolean restartVpc(final long vpcId, final boolean cleanUp, final boolean makeRedundant) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { - final Account caller = CallContext.current().getCallingAccount(); + final Account callerAccount = CallContext.current().getCallingAccount(); + final User callerUser = _accountMgr.getActiveUser(CallContext.current().getCallingUserId()); + final ReservationContext context = new ReservationContextImpl(null, null, callerUser, callerAccount); // Verify input parameters - final Vpc vpc = getActiveVpc(vpcId); + Vpc vpc = getActiveVpc(vpcId); if (vpc == null) { final InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find Enabled VPC by id specified"); ex.addProxyObject(String.valueOf(vpcId), "VPC"); throw ex; } - _accountMgr.checkAccess(caller, null, false, vpc); + _accountMgr.checkAccess(callerAccount, null, false, vpc); s_logger.debug("Restarting VPC " + vpc); boolean restartRequired = false; try { - boolean forceCleanup = cleanUp; if (!vpc.isRedundant() && makeRedundant) { final VpcOfferingVO redundantOffering = _vpcOffDao.findByUniqueName(VpcOffering.redundantVPCOfferingName); @@ -1508,7 +1517,9 @@ public boolean restartVpc(final long vpcId, final boolean cleanUp, final boolean // Change the VPC in order to get it updated after the end of // the restart procedure. - _vpcDao.update(vpc.getId(), entity); + if (_vpcDao.update(vpc.getId(), entity)) { + vpc = entity; + } // If the offering and redundant column are changing, force the // clean up. @@ -1516,17 +1527,15 @@ public boolean restartVpc(final long vpcId, final boolean cleanUp, final boolean } if (forceCleanup) { - s_logger.debug("Shutting down VPC " + vpc + " as a part of VPC restart process"); - if (!shutdownVpc(vpcId)) { - s_logger.warn("Failed to shutdown vpc as a part of VPC " + vpc + " restart process"); + if (!rollingRestartVpc(vpc, context)) { + s_logger.warn("Failed to execute a rolling restart as a part of VPC " + vpc + " restart process"); restartRequired = true; return false; } - } else { - s_logger.info("Will not shutdown vpc as a part of VPC " + vpc + " restart process."); + return true; } - s_logger.debug("Starting VPC " + vpc + " as a part of VPC restart process"); + s_logger.debug("Starting VPC " + vpc + " as a part of VPC restart process without cleanup"); if (!startVpc(vpcId, false)) { s_logger.warn("Failed to start vpc as a part of VPC " + vpc + " restart process"); restartRequired = true; @@ -2435,4 +2444,41 @@ public boolean isSrcNatIpRequired(long vpcOfferingId) { final Map> vpcOffSvcProvidersMap = getVpcOffSvcProvidersMap(vpcOfferingId); return vpcOffSvcProvidersMap.get(Network.Service.SourceNat).contains(Network.Provider.VPCVirtualRouter); } + + private boolean rollingRestartVpc(final Vpc vpc, final ReservationContext context) throws ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException { + s_logger.debug("Performing rolling restart of routers of VPC " + vpc); + _ntwkMgr.destroyExpendableRouters(_routerDao.listByVpcId(vpc.getId()), context); + + final DeployDestination dest = new DeployDestination(_dcDao.findById(vpc.getZoneId()), null, null, null); + final List oldRouters = _routerDao.listByVpcId(vpc.getId()); + + // Create a new router + vpc.setRollingRestart(true); + startVpc(vpc, dest, context); + vpc.setRollingRestart(false); + + // For redundant vpc wait for 3*advert_int+skew_seconds for VRRP to kick in + if (vpc.isRedundant() || (oldRouters.size() == 1 && oldRouters.get(0).getIsRedundantRouter())) { + try { + Thread.sleep(10000L); + } catch (final InterruptedException ignored) { + } + } + + // Destroy old routers + for (final DomainRouterVO oldRouter : oldRouters) { + _routerService.destroyRouter(oldRouter.getId(), context.getAccount(), context.getCaller().getId()); + } + + // Add a new backup router for redundant vpc or re-apply rules + if (vpc.isRedundant()) { + if (!startVpc(vpc, dest, context)) { + s_logger.debug("Failed to re-program VPC router or deploy a new backup router for VPC" + vpc); + return false; + } + } + + return _ntwkMgr.validateNewRouters(_routerDao.listByVpcId(vpc.getId())); + } + } diff --git a/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinition.java b/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinition.java index 9b22562a74e9..4ff5fa2dc28a 100644 --- a/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinition.java +++ b/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinition.java @@ -148,6 +148,10 @@ public boolean isRedundant() { return guestNetwork.isRedundant(); } + public boolean isRollingRestart() { + return guestNetwork.isRollingRestart(); + } + public DeploymentPlan getPlan() { return plan; } @@ -316,7 +320,7 @@ protected int getNumberOfRoutersToDeploy() { // If old network is redundant but new is single router, then // routers.size() = 2 but routerCount = 1 int routersExpected = 1; - if (isRedundant()) { + if (isRedundant() || isRollingRestart()) { routersExpected = 2; } return routersExpected < routers.size() ? 0 : routersExpected - routers.size(); @@ -416,7 +420,7 @@ protected void deployAllVirtualRouters() throws ConcurrentOperationException, In final DomainRouterVO router = nwHelper.deployRouter(this, false); //check if the network update is in progress. //if update is in progress add the update_pending flag to DomainRouterVO. - NetworkDetailVO detail =networkDetailsDao.findDetail(guestNetwork.getId(),Network.updatingInSequence); + NetworkDetailVO detail = networkDetailsDao.findDetail(guestNetwork.getId(),Network.updatingInSequence); if("true".equalsIgnoreCase(detail!=null ? detail.getValue() : null)) { router.setUpdateState(VirtualRouter.UpdateState.UPDATE_IN_PROGRESS); routerDao.persist(router); diff --git a/server/src/org/cloud/network/router/deployment/VpcRouterDeploymentDefinition.java b/server/src/org/cloud/network/router/deployment/VpcRouterDeploymentDefinition.java index 8ccecce619a7..f58491894239 100644 --- a/server/src/org/cloud/network/router/deployment/VpcRouterDeploymentDefinition.java +++ b/server/src/org/cloud/network/router/deployment/VpcRouterDeploymentDefinition.java @@ -194,4 +194,9 @@ public void generateDeploymentPlan() { public boolean isRedundant() { return vpc.isRedundant(); } + + @Override + public boolean isRollingRestart() { + return vpc.isRollingRestart(); + } } diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index d68b7c9e96df..472effa970d5 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -68,6 +68,7 @@ import com.cloud.network.element.StaticNatServiceProvider; import com.cloud.network.element.UserDataServiceProvider; import com.cloud.network.guru.NetworkGuru; +import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.vpc.Vpc; import com.cloud.offering.NetworkOffering; @@ -215,7 +216,7 @@ public boolean deleteNetwork(long networkId, boolean forced) { * @see com.cloud.network.NetworkService#restartNetwork(com.cloud.api.commands.RestartNetworkCmd, boolean) */ @Override - public boolean restartNetwork(RestartNetworkCmd cmd, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException, + public boolean restartNetwork(RestartNetworkCmd cmd, boolean cleanup, boolean makeRedundant) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { // TODO Auto-generated method stub return false; @@ -914,6 +915,15 @@ public int getResourceCount(Network network) { return null; } + @Override + public void destroyExpendableRouters(final List routers, final ReservationContext context) throws ResourceUnavailableException { + } + + @Override + public boolean validateNewRouters(final List routers) { + return false; + } + @Override public void finalizeUpdateInSequence(Network network, boolean success) { return; diff --git a/systemvm/debian/opt/cloud/bin/cs/CsAddress.py b/systemvm/debian/opt/cloud/bin/cs/CsAddress.py index 8df51622633e..727f2efd107f 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsAddress.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsAddress.py @@ -628,7 +628,9 @@ def hasIP(self, ip): def arpPing(self): cmd = "arping -c 1 -I %s -A -U -s %s %s" % ( self.dev, self.address['public_ip'], self.address['gateway']) - CsHelper.execute(cmd) + if not self.cl.is_redundant() and (not self.address['gateway'] or self.address['gateway'] == "None"): + cmd = "arping -c 1 -I %s -A -U %s" % (self.dev, self.address['public_ip']) + CsHelper.execute2(cmd, wait=False) # Delete any ips that are configured but not in the bag def compare(self, bag): diff --git a/systemvm/debian/opt/cloud/bin/setup/common.sh b/systemvm/debian/opt/cloud/bin/setup/common.sh index d2a26c988b0c..f26ff5b4c359 100755 --- a/systemvm/debian/opt/cloud/bin/setup/common.sh +++ b/systemvm/debian/opt/cloud/bin/setup/common.sh @@ -333,13 +333,13 @@ setup_common() { fi # Workaround to activate vSwitch under VMware - timeout 3 ping -n -c 3 $GW || true + timeout 3 ping -n -c 3 $GW & if [ -n "$MGMTNET" -a -n "$LOCAL_GW" ] then - timeout 3 ping -n -c 3 $LOCAL_GW || true + timeout 3 ping -n -c 3 $LOCAL_GW & #This code is added to address ARP issue by pinging MGMT_GW MGMT_GW=$(echo $MGMTNET | awk -F "." '{print $1"."$2"."$3".1"}') - timeout 3 ping -n -c 3 $MGMT_GW || true + timeout 3 ping -n -c 3 $MGMT_GW & fi if [ "$HYPERVISOR" == "vmware" ]; then diff --git a/systemvm/debian/opt/cloud/bin/setup/postinit.sh b/systemvm/debian/opt/cloud/bin/setup/postinit.sh index 9da5c7a75fa3..de7f259d826e 100755 --- a/systemvm/debian/opt/cloud/bin/setup/postinit.sh +++ b/systemvm/debian/opt/cloud/bin/setup/postinit.sh @@ -65,9 +65,6 @@ do systemctl disable --no-block --now $svc done -# Enable SSH by default -systemctl enable --no-block --now ssh - # Restore the persistent iptables nat, rules and filters for IPv4 and IPv6 if they exist ipv4="/etc/iptables/rules.v4" if [ -e $ipv4 ] @@ -81,5 +78,8 @@ then ip6tables-restore < $ipv6 fi +# Enable SSH by default +systemctl enable --no-block --now ssh + date > /var/cache/cloud/boot_up_done logger -t cloud "Boot up process done" diff --git a/systemvm/debian/opt/cloud/templates/keepalived.conf.templ b/systemvm/debian/opt/cloud/templates/keepalived.conf.templ index 0a5377766238..e5046366a6d7 100644 --- a/systemvm/debian/opt/cloud/templates/keepalived.conf.templ +++ b/systemvm/debian/opt/cloud/templates/keepalived.conf.templ @@ -31,9 +31,9 @@ vrrp_instance inside_network { nopreempt advert_int 1 - garp_master_delay 1 - garp_master_repeat 10 - garp_master_refresh 5 + #garp_master_delay 2 + #garp_master_repeat 10 + #garp_master_refresh 5 #use_vmac #vmac_xmit_base diff --git a/ui/scripts/network.js b/ui/scripts/network.js index 58fea81e2166..27579a7d73bb 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -1100,11 +1100,23 @@ }); args.$form.find('.form-item[rel=cleanup]').find('input').attr('checked', 'checked'); //checked args.$form.find('.form-item[rel=cleanup]').css('display', 'inline-block'); //shown + args.$form.find('.form-item[rel=makeredundant]').find('input').attr('checked', 'checked'); //checked + args.$form.find('.form-item[rel=makeredundant]').css('display', 'inline-block'); //shown + + if (Boolean(args.context.networks[0].redundantrouter)) { + args.$form.find('.form-item[rel=makeredundant]').hide(); + } else { + args.$form.find('.form-item[rel=makeredundant]').show(); + } }, fields: { cleanup: { label: 'label.clean.up', isBoolean: true + }, + makeredundant: { + label: 'label.make.redundant', + isBoolean: true } } }, @@ -1114,10 +1126,13 @@ } }, action: function(args) { - var array1 = []; - array1.push("&cleanup=" + (args.data.cleanup == "on")); $.ajax({ - url: createURL("restartNetwork&id=" + args.context.networks[0].id + array1.join("")), + url: createURL("restartNetwork"), + data: { + id: args.context.networks[0].id, + cleanup: (args.data.cleanup == "on"), + makeredundant: (args.data.makeredundant == "on") + }, dataType: "json", async: true, success: function(json) { @@ -1416,10 +1431,20 @@ label: 'label.reserved.ip.range' }, + redundantrouter: { + label: 'label.redundant.router', + converter: function(booleanValue) { + if (booleanValue == true) { + return "Yes"; + } + return "No"; + } + }, networkdomaintext: { label: 'label.network.domain.text' }, + networkdomain: { label: 'label.network.domain', isEditable: true From 85ed83eef5738dcdaa98cfd53edc884653c1f5e7 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Wed, 25 Apr 2018 18:32:21 +0200 Subject: [PATCH 2/7] server: fix NPE Signed-off-by: Rohit Yadav --- .../src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java index e3d1e30d3484..ec88033b1fc4 100644 --- a/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java @@ -76,7 +76,9 @@ public DomainRouterResponse newDomainRouterResponse(DomainRouterJoinVO router, A routerResponse.setCreated(router.getCreated()); routerResponse.setState(router.getState()); routerResponse.setIsRedundantRouter(router.isRedundantRouter()); - routerResponse.setRedundantState(router.getRedundantState().toString()); + if (router.getRedundantState() != null) { + routerResponse.setRedundantState(router.getRedundantState().toString()); + } if (router.getTemplateVersion() != null) { String routerVersion = Version.trimRouterVersion(router.getTemplateVersion()); routerResponse.setVersion(routerVersion); From 10ee97f4568ac7d5bf0d8dc9fccd29a960a2ac2b Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Mon, 30 Apr 2018 08:45:38 +0200 Subject: [PATCH 3/7] review fixes Signed-off-by: Rohit Yadav --- api/src/com/cloud/network/vpc/Vpc.java | 2 -- .../api/command/user/network/RestartNetworkCmd.java | 4 ++-- .../apache/cloudstack/api/command/user/vpc/RestartVPCCmd.java | 4 ++-- .../cloudstack/engine/orchestration/NetworkOrchestrator.java | 2 -- server/src/com/cloud/network/vpc/VpcManagerImpl.java | 4 ++-- 5 files changed, 6 insertions(+), 10 deletions(-) diff --git a/api/src/com/cloud/network/vpc/Vpc.java b/api/src/com/cloud/network/vpc/Vpc.java index 2e4c77214626..9f40562423d8 100644 --- a/api/src/com/cloud/network/vpc/Vpc.java +++ b/api/src/com/cloud/network/vpc/Vpc.java @@ -76,8 +76,6 @@ public enum State { boolean isRedundant(); - void setRedundant(final boolean isRedundant); - /** * * @return true if VPC is configured to use distributed router to provides one-hop forwarding and hypervisor based ACL diff --git a/api/src/org/apache/cloudstack/api/command/user/network/RestartNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/RestartNetworkCmd.java index 24cb70aa70bc..a0e9ad555d61 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/RestartNetworkCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/RestartNetworkCmd.java @@ -77,14 +77,14 @@ public Boolean getCleanup() { if (cleanup != null) { return cleanup; } - return true; + return false; } public Boolean getMakeRedundant() { if (makeRedundant != null) { return makeRedundant; } - return true; + return false; } ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/vpc/RestartVPCCmd.java b/api/src/org/apache/cloudstack/api/command/user/vpc/RestartVPCCmd.java index 21619eb8a767..f6b72eca5b8c 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vpc/RestartVPCCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vpc/RestartVPCCmd.java @@ -66,14 +66,14 @@ public Boolean getCleanup() { if (cleanup != null) { return cleanup; } - return true; + return false; } public Boolean getMakeredundant() { if (makeredundant != null) { return makeredundant; } - return true; + return false; } ///////////////////////////////////////////////////// diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 50579ab335f0..8a5d8be57f67 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -2853,7 +2853,6 @@ public boolean restartNetwork(final Long networkId, final Account callerAccount, @Override public void destroyExpendableRouters(final List routers, final ReservationContext context) throws ResourceUnavailableException { final List remainingRouters = new ArrayList<>(); - // Purge invalid routers for (final VirtualRouter router : routers) { if (router.getState() == VirtualMachine.State.Stopped || router.getState() == VirtualMachine.State.Error || @@ -2870,7 +2869,6 @@ public void destroyExpendableRouters(final List routers return; } - // Purge any backup router VirtualRouter backupRouter = null; for (final VirtualRouter router : remainingRouters) { if (router.getRedundantState() == VirtualRouter.RedundantState.BACKUP) { diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index e530dc8e78e5..53894be88ced 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -1183,7 +1183,7 @@ protected boolean startVpc(final Vpc vpc, final DeployDestination dest, final Re for (final VpcProvider element : getVpcElements()) { if (providersToImplement.contains(element.getProvider())) { if (element.implementVpc(vpc, dest, context)) { - s_logger.debug("Vpc " + vpc + " has started succesfully"); + s_logger.debug("Vpc " + vpc + " has started successfully"); } else { s_logger.warn("Vpc " + vpc + " failed to start"); success = false; @@ -1512,7 +1512,7 @@ public boolean restartVpc(final long vpcId, final boolean cleanUp, final boolean final VpcOfferingVO redundantOffering = _vpcOffDao.findByUniqueName(VpcOffering.redundantVPCOfferingName); final VpcVO entity = _vpcDao.findById(vpcId); - entity.setRedundant(makeRedundant); + entity.setRedundant(true); entity.setVpcOfferingId(redundantOffering.getId()); // Change the VPC in order to get it updated after the end of From 045a24aa14bbc510d5773435754b19a9f97bf885 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Mon, 30 Apr 2018 13:38:52 +0530 Subject: [PATCH 4/7] tests based fixes Signed-off-by: Rohit Yadav --- .../orchestration/NetworkOrchestrator.java | 13 ++++++++++--- .../com/cloud/network/vpc/VpcManagerImpl.java | 18 ++++++++++-------- systemvm/debian/opt/cloud/bin/cs/CsAddress.py | 2 +- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 8a5d8be57f67..b7cb426611f7 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -2902,9 +2902,13 @@ private boolean rollingRestartRouters(final NetworkVO network, final NetworkOffe final List oldRouters = _routerDao.findByNetwork(network.getId()); // Deploy a new router - network.setRollingRestart(true); + if (oldRouters.size() > 0) { + network.setRollingRestart(true); + } implementNetworkElements(dest, context, network, offering, providersToImplement); - network.setRollingRestart(false); + if (oldRouters.size() > 0) { + network.setRollingRestart(false); + } // For redundant network wait for 3*advert_int+skew_seconds for VRRP to kick in if (network.isRedundant() || (oldRouters.size() == 1 && oldRouters.get(0).getIsRedundantRouter())) { @@ -2918,9 +2922,12 @@ private boolean rollingRestartRouters(final NetworkVO network, final NetworkOffe _routerService.destroyRouter(oldRouter.getId(), context.getAccount(), context.getCaller().getId()); } - // Add a new backup router for redundant network if (network.isRedundant()) { + // Add a new backup router for redundant network implementNetworkElements(dest, context, network, offering, providersToImplement); + } else { + // Re-apply rules for non-redundant network + implementNetworkElementsAndResources(dest, context, network, offering); } return validateNewRouters(_routerDao.findByNetwork(network.getId())); diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 53894be88ced..2690e76d7102 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -2453,9 +2453,13 @@ private boolean rollingRestartVpc(final Vpc vpc, final ReservationContext contex final List oldRouters = _routerDao.listByVpcId(vpc.getId()); // Create a new router - vpc.setRollingRestart(true); + if (oldRouters.size() > 0) { + vpc.setRollingRestart(true); + } startVpc(vpc, dest, context); - vpc.setRollingRestart(false); + if (oldRouters.size() > 0) { + vpc.setRollingRestart(false); + } // For redundant vpc wait for 3*advert_int+skew_seconds for VRRP to kick in if (vpc.isRedundant() || (oldRouters.size() == 1 && oldRouters.get(0).getIsRedundantRouter())) { @@ -2470,12 +2474,10 @@ private boolean rollingRestartVpc(final Vpc vpc, final ReservationContext contex _routerService.destroyRouter(oldRouter.getId(), context.getAccount(), context.getCaller().getId()); } - // Add a new backup router for redundant vpc or re-apply rules - if (vpc.isRedundant()) { - if (!startVpc(vpc, dest, context)) { - s_logger.debug("Failed to re-program VPC router or deploy a new backup router for VPC" + vpc); - return false; - } + // Re-program VPC VR or add a new backup router for redundant VPC + if (!startVpc(vpc, dest, context)) { + s_logger.debug("Failed to re-program VPC router or deploy a new backup router for VPC" + vpc); + return false; } return _ntwkMgr.validateNewRouters(_routerDao.listByVpcId(vpc.getId())); diff --git a/systemvm/debian/opt/cloud/bin/cs/CsAddress.py b/systemvm/debian/opt/cloud/bin/cs/CsAddress.py index 727f2efd107f..3212dff71eee 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsAddress.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsAddress.py @@ -630,7 +630,7 @@ def arpPing(self): self.dev, self.address['public_ip'], self.address['gateway']) if not self.cl.is_redundant() and (not self.address['gateway'] or self.address['gateway'] == "None"): cmd = "arping -c 1 -I %s -A -U %s" % (self.dev, self.address['public_ip']) - CsHelper.execute2(cmd, wait=False) + CsHelper.execute2(cmd, False) # Delete any ips that are configured but not in the bag def compare(self, bag): From f8c5ee198f33b3cf8bce465819769b831409e9b3 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Mon, 30 Apr 2018 14:41:49 +0530 Subject: [PATCH 5/7] remove overrides Signed-off-by: Rohit Yadav --- api/src/com/cloud/network/router/VirtualRouter.java | 2 -- engine/schema/src/com/cloud/vm/DomainRouterVO.java | 1 - 2 files changed, 3 deletions(-) diff --git a/api/src/com/cloud/network/router/VirtualRouter.java b/api/src/com/cloud/network/router/VirtualRouter.java index 0849880e953c..84c85ce66758 100644 --- a/api/src/com/cloud/network/router/VirtualRouter.java +++ b/api/src/com/cloud/network/router/VirtualRouter.java @@ -40,8 +40,6 @@ public enum RedundantState { RedundantState getRedundantState(); - void setRedundantState(final RedundantState redundantState); - String getPublicIpAddress(); boolean isStopPending(); diff --git a/engine/schema/src/com/cloud/vm/DomainRouterVO.java b/engine/schema/src/com/cloud/vm/DomainRouterVO.java index 6398a017b5a0..2a7aa49b6ed4 100644 --- a/engine/schema/src/com/cloud/vm/DomainRouterVO.java +++ b/engine/schema/src/com/cloud/vm/DomainRouterVO.java @@ -162,7 +162,6 @@ public RedundantState getRedundantState() { return redundantState; } - @Override public void setRedundantState(final RedundantState redundantState) { this.redundantState = redundantState; } From eca8edff09cb5fd5db42ffcf059e8a11174b361e Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Fri, 4 May 2018 16:37:55 +0530 Subject: [PATCH 6/7] address review comments from Gabriel Signed-off-by: Rohit Yadav --- .../orchestration/service/NetworkOrchestrationService.java | 6 ++++++ .../engine/orchestration/NetworkOrchestrator.java | 4 ++-- server/src/com/cloud/network/vpc/VpcManagerImpl.java | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java index 753750085d97..c6ea93a04802 100644 --- a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java +++ b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java @@ -66,6 +66,12 @@ public interface NetworkOrchestrationService { String NetworkThrottlingRateCK = "network.throttling.rate"; String MinVRVersionCK = "minreq.sysvmtemplate.version"; + /** + * The redundant router handover time which is defined by VRRP2 spec as: + * (3 * advertisement interval + skew_seconds) or 10s with CloudStack default + */ + Long RVRHandoverTime = 10000L; + ConfigKey MinVRVersion = new ConfigKey(String.class, MinVRVersionCK, "Advanced", "4.10.0", "What version should the Virtual Routers report", true, ConfigKey.Scope.Zone, null); diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index b7cb426611f7..eb859cda76b1 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -1181,7 +1181,7 @@ public void implementNetworkElementsAndResources(final DeployDestination dest, f } } - protected void implementNetworkElements(final DeployDestination dest, final ReservationContext context, final Network network, final NetworkOffering offering, final List providersToImplement) + private void implementNetworkElements(final DeployDestination dest, final ReservationContext context, final Network network, final NetworkOffering offering, final List providersToImplement) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { for (NetworkElement element : networkElements) { if (providersToImplement.contains(element.getProvider())) { @@ -2913,7 +2913,7 @@ private boolean rollingRestartRouters(final NetworkVO network, final NetworkOffe // For redundant network wait for 3*advert_int+skew_seconds for VRRP to kick in if (network.isRedundant() || (oldRouters.size() == 1 && oldRouters.get(0).getIsRedundantRouter())) { try { - Thread.sleep(10000L); + Thread.sleep(NetworkOrchestrationService.RVRHandoverTime); } catch (final InterruptedException ignored) {} } diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 2690e76d7102..cd4a045c6b69 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -2464,7 +2464,7 @@ private boolean rollingRestartVpc(final Vpc vpc, final ReservationContext contex // For redundant vpc wait for 3*advert_int+skew_seconds for VRRP to kick in if (vpc.isRedundant() || (oldRouters.size() == 1 && oldRouters.get(0).getIsRedundantRouter())) { try { - Thread.sleep(10000L); + Thread.sleep(NetworkOrchestrationService.RVRHandoverTime); } catch (final InterruptedException ignored) { } } From 435eea2f3b9ab029f6ca86118d4168835b0a6de0 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Tue, 8 May 2018 18:03:57 +0530 Subject: [PATCH 7/7] address review comments from Rafael and Daan. Signed-off-by: Rohit Yadav --- .../user/network/RestartNetworkCmd.java | 14 ++++---------- .../api/command/user/vpc/RestartVPCCmd.java | 14 ++++---------- .../service/NetworkOrchestrationService.java | 14 +++++++++++++- .../orchestration/NetworkOrchestrator.java | 18 ++++++++++++++++-- .../network/element/VirtualRouterElement.java | 6 +++--- .../com/cloud/network/vpc/VpcManagerImpl.java | 14 +++++++++++++- .../com/cloud/vpc/MockNetworkManagerImpl.java | 2 +- .../opt/cloud/templates/keepalived.conf.templ | 3 --- 8 files changed, 54 insertions(+), 31 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/command/user/network/RestartNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/RestartNetworkCmd.java index a0e9ad555d61..645ae5aff8e3 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/RestartNetworkCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/RestartNetworkCmd.java @@ -55,10 +55,10 @@ public class RestartNetworkCmd extends BaseAsyncCmd { private Long id; @Parameter(name = ApiConstants.CLEANUP, type = CommandType.BOOLEAN, required = false, description = "If cleanup old network elements") - private Boolean cleanup; + private Boolean cleanup = false; @Parameter(name = ApiConstants.MAKEREDUNDANT, type = CommandType.BOOLEAN, required = false, description = "Turn the network into a network with redundant routers.", since = "4.11.1") - private Boolean makeRedundant; + private Boolean makeRedundant = false; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -74,17 +74,11 @@ public Long getNetworkId() { } public Boolean getCleanup() { - if (cleanup != null) { - return cleanup; - } - return false; + return cleanup; } public Boolean getMakeRedundant() { - if (makeRedundant != null) { - return makeRedundant; - } - return false; + return makeRedundant; } ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/vpc/RestartVPCCmd.java b/api/src/org/apache/cloudstack/api/command/user/vpc/RestartVPCCmd.java index f6b72eca5b8c..edfd93e785ec 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vpc/RestartVPCCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vpc/RestartVPCCmd.java @@ -49,10 +49,10 @@ public class RestartVPCCmd extends BaseAsyncCmd { private Long id; @Parameter(name = ApiConstants.CLEANUP, type = CommandType.BOOLEAN, required = false, description = "If cleanup old network elements") - private Boolean cleanup; + private Boolean cleanup = false; @Parameter(name = ApiConstants.MAKEREDUNDANT, type = CommandType.BOOLEAN, required = false, description = "Turn a single VPC into a redundant one.") - private Boolean makeredundant; + private Boolean makeredundant = false; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -63,17 +63,11 @@ public Long getId() { } public Boolean getCleanup() { - if (cleanup != null) { - return cleanup; - } - return false; + return cleanup; } public Boolean getMakeredundant() { - if (makeredundant != null) { - return makeredundant; - } - return false; + return makeredundant; } ///////////////////////////////////////////////////// diff --git a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java index c6ea93a04802..82d0566169a7 100644 --- a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java +++ b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java @@ -290,8 +290,20 @@ void implementNetworkElementsAndResources(DeployDestination dest, ReservationCon List getNetworkGurus(); + /** + * destroyExpendableRouters will find and destroy safely destroyable routers + * that are in bad states or are backup routers + * @param routers list of routers + * @param context reservation context + * @throws ResourceUnavailableException + */ void destroyExpendableRouters(final List routers, final ReservationContext context) throws ResourceUnavailableException; - boolean validateNewRouters(final List routers); + /** + * areRoutersRunning check if the given list of routers are running + * @param routers list of routers + * @return returns true is all routers are running + */ + boolean areRoutersRunning(final List routers); } diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index eb859cda76b1..c91ac6098d59 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -2884,7 +2884,7 @@ public void destroyExpendableRouters(final List routers } @Override - public boolean validateNewRouters(final List routers) { + public boolean areRoutersRunning(final List routers) { for (final VirtualRouter router : routers) { if (router.getState() != VirtualMachine.State.Running) { s_logger.debug("Found new router " + router.getInstanceName() + " to be in non-Running state: " + router.getState() + ". Please try restarting network again."); @@ -2894,6 +2894,20 @@ public boolean validateNewRouters(final List routers) { return true; } + /** + * rollingRestartRouters performs restart of routers of a network by first + * deploying a new VR and then destroying old VRs in rolling fashion. For + * non-redundant network, it will re-program the new router as final step + * otherwise deploys a backup router for the network. + * @param network network to be restarted + * @param offering network offering + * @param dest deployment destination + * @param context reservation context + * @return returns true when the rolling restart operation succeeds + * @throws ResourceUnavailableException + * @throws ConcurrentOperationException + * @throws InsufficientCapacityException + */ private boolean rollingRestartRouters(final NetworkVO network, final NetworkOffering offering, final DeployDestination dest, final ReservationContext context) throws ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException { s_logger.debug("Performing rolling restart of routers of network " + network); destroyExpendableRouters(_routerDao.findByNetwork(network.getId()), context); @@ -2930,7 +2944,7 @@ private boolean rollingRestartRouters(final NetworkVO network, final NetworkOffe implementNetworkElementsAndResources(dest, context, network, offering); } - return validateNewRouters(_routerDao.findByNetwork(network.getId())); + return areRoutersRunning(_routerDao.findByNetwork(network.getId())); } private void setRestartRequired(final NetworkVO network, final boolean restartRequired) { diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index 8b628486620a..7df1298e80ca 100644 --- a/server/src/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VirtualRouterElement.java @@ -226,11 +226,11 @@ public boolean implement(final Network network, final NetworkOffering offering, final List routers = routerDeploymentDefinition.deployVirtualRouter(); - int routerCounts = 1; + int expectedRouters = 1; if (offering.getRedundantRouter() || network.isRollingRestart()) { - routerCounts = 2; + expectedRouters = 2; } - if (routers == null || routers.size() < routerCounts) { + if (routers == null || routers.size() < expectedRouters) { //we might have a router which is already deployed and running. //so check the no of routers in network currently. List current_routers = _routerDao.listByNetworkAndRole(network.getId(), Role.VIRTUAL_ROUTER); diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index cd4a045c6b69..b32498b254d8 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -2445,6 +2445,18 @@ public boolean isSrcNatIpRequired(long vpcOfferingId) { return vpcOffSvcProvidersMap.get(Network.Service.SourceNat).contains(Network.Provider.VPCVirtualRouter); } + /** + * rollingRestartVpc performs restart of routers of a VPC by first + * deploying a new VR and then destroying old VRs in rolling fashion. For + * non-redundant VPC, it will re-program the new router as final step + * otherwise deploys a backup router for the VPC. + * @param vpc vpc to be restarted + * @param context reservation context + * @return returns true when the rolling restart succeeds + * @throws ResourceUnavailableException + * @throws ConcurrentOperationException + * @throws InsufficientCapacityException + */ private boolean rollingRestartVpc(final Vpc vpc, final ReservationContext context) throws ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException { s_logger.debug("Performing rolling restart of routers of VPC " + vpc); _ntwkMgr.destroyExpendableRouters(_routerDao.listByVpcId(vpc.getId()), context); @@ -2480,7 +2492,7 @@ private boolean rollingRestartVpc(final Vpc vpc, final ReservationContext contex return false; } - return _ntwkMgr.validateNewRouters(_routerDao.listByVpcId(vpc.getId())); + return _ntwkMgr.areRoutersRunning(_routerDao.listByVpcId(vpc.getId())); } } diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index 472effa970d5..8cbf30cdc883 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -920,7 +920,7 @@ public void destroyExpendableRouters(final List routers } @Override - public boolean validateNewRouters(final List routers) { + public boolean areRoutersRunning(final List routers) { return false; } diff --git a/systemvm/debian/opt/cloud/templates/keepalived.conf.templ b/systemvm/debian/opt/cloud/templates/keepalived.conf.templ index e5046366a6d7..ca9f231a541e 100644 --- a/systemvm/debian/opt/cloud/templates/keepalived.conf.templ +++ b/systemvm/debian/opt/cloud/templates/keepalived.conf.templ @@ -31,9 +31,6 @@ vrrp_instance inside_network { nopreempt advert_int 1 - #garp_master_delay 2 - #garp_master_repeat 10 - #garp_master_refresh 5 #use_vmac #vmac_xmit_base