From fa623c04e25875e79183ff73b7bb66118ce696b9 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Tue, 19 Jul 2011 14:27:58 -0700 Subject: [PATCH] bug 10640: Redundant virtual router: Try to deploy the second virtual router to different pod/cluster/host/storagepool The old strategy is to deploy the second virtual router to diffent host only. status 10640: resolved fixed --- .../cloud/deploy/DataCenterDeployment.java | 13 ++++ api/src/com/cloud/deploy/DeploymentPlan.java | 14 ++++ .../VirtualNetworkApplianceManagerImpl.java | 73 +++++++++++++++++-- .../cloud/vm/VirtualMachineManagerImpl.java | 43 ++++------- 4 files changed, 107 insertions(+), 36 deletions(-) diff --git a/api/src/com/cloud/deploy/DataCenterDeployment.java b/api/src/com/cloud/deploy/DataCenterDeployment.java index cac3839999d..5be0247c2fc 100644 --- a/api/src/com/cloud/deploy/DataCenterDeployment.java +++ b/api/src/com/cloud/deploy/DataCenterDeployment.java @@ -17,12 +17,15 @@ */ package com.cloud.deploy; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; + public class DataCenterDeployment implements DeploymentPlan { long _dcId; Long _podId; Long _clusterId; Long _poolId; Long _hostId; + ExcludeList _avoids = null; boolean _recreateDisks; public DataCenterDeployment(long dataCenterId) { @@ -61,4 +64,14 @@ public class DataCenterDeployment implements DeploymentPlan { public Long getPoolId() { return _poolId; } + + @Override + public ExcludeList getAvoids() { + return _avoids; + } + + @Override + public void setAvoids(ExcludeList avoids) { + _avoids = avoids; + } } diff --git a/api/src/com/cloud/deploy/DeploymentPlan.java b/api/src/com/cloud/deploy/DeploymentPlan.java index 894bca77d25..0881f7bd50c 100644 --- a/api/src/com/cloud/deploy/DeploymentPlan.java +++ b/api/src/com/cloud/deploy/DeploymentPlan.java @@ -17,6 +17,8 @@ */ package com.cloud.deploy; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; + /** * Describes how a VM should be deployed. */ @@ -49,4 +51,16 @@ public interface DeploymentPlan { * @return pool the VM should be created in; null if no preference. */ public Long getPoolId(); + + /** + * @param avoids + * Set the ExcludeList to avoid for deployment + */ + public void setAvoids(ExcludeList avoids); + + /** + * @return + * the ExcludeList to avoid for deployment + */ + public ExcludeList getAvoids(); } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 2339e819536..5ebc7ac5f8d 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -77,6 +77,8 @@ import com.cloud.dc.dao.HostPodDao; import com.cloud.dc.dao.VlanDao; import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; +import com.cloud.deploy.DeploymentPlan; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; @@ -84,6 +86,7 @@ import com.cloud.event.dao.EventDao; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.OperationTimedoutException; import com.cloud.exception.PermissionDeniedException; @@ -131,6 +134,8 @@ import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.StorageManager; import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.Volume.Type; import com.cloud.storage.dao.GuestOSDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateHostDao; @@ -270,6 +275,8 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian VMInstanceDao _instanceDao; @Inject NicDao _nicDao; + @Inject + VolumeDao _volumeDao = null; int _routerRamSize; int _routerCpuMHz; @@ -891,6 +898,61 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian return routers; } + private DomainRouterVO startVirtualRouter(DomainRouterVO router, User user, Account caller, Map params) throws StorageUnavailableException, InsufficientCapacityException, + ConcurrentOperationException, ResourceUnavailableException { + if (router.getRole() == Role.DHCP_USERDATA || !router.getIsRedundantRouter()) { + return this.start(router, user, caller, params, null); + } + + DataCenterDeployment plan = new DataCenterDeployment(0, null, null, null, null); + DomainRouterVO result = null; + assert router.getIsRedundantRouter(); + List routerList = _routerDao.findBy(router.getAccountId(), router.getDataCenterIdToDeployIn()); + DomainRouterVO routerToBeAvoid = null; + for (DomainRouterVO rrouter : routerList) { + if (rrouter.getHostId() != null && rrouter.getIsRedundantRouter()) { + if (routerToBeAvoid != null) { + throw new ResourceUnavailableException("There are already two redundant routers with IP " + router.getPublicIpAddress(), this.getClass(), 0); + } + routerToBeAvoid = rrouter; + } + } + if (routerToBeAvoid == null) { + return this.start(router, user, caller, params, null); + } + // We would try best to deploy the router to another place + int retryIndex = 5; + ExcludeList[] avoids = new ExcludeList[5]; + avoids[0] = new ExcludeList(); + avoids[0].addPod(routerToBeAvoid.getPodIdToDeployIn()); + avoids[1] = new ExcludeList(); + avoids[1].addCluster(_hostDao.findById(routerToBeAvoid.getHostId()).getClusterId()); + avoids[2] = new ExcludeList(); + avoids[2].addHost(routerToBeAvoid.getHostId()); + avoids[3] = new ExcludeList(); + List volumes = _volumeDao.findByInstanceAndType(routerToBeAvoid.getId(), Type.ROOT); + if (volumes != null && volumes.size() != 0) { + avoids[3].addPool(volumes.get(0).getPoolId()); + } + avoids[4] = new ExcludeList(); + + for (int i = 0; i < retryIndex; i++) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("Try to deploy redundant virtual router:" + router.getHostName() + ", for " + i + " time"); + } + plan.setAvoids(avoids[i]); + try { + result = this.start(router, user, caller, params, plan); + } catch (InsufficientServerCapacityException ex) { + result = null; + } + if (result != null) { + break; + } + } + return result; + } + @Override public List deployVirtualRouter(Network guestNetwork, DeployDestination dest, Account owner, Map params, boolean isRedundant) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { @@ -912,11 +974,10 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian for (DomainRouterVO router : routers) { State state = router.getState(); if (state != State.Running) { - router = this.start(router, _accountService.getSystemUser(), _accountService.getSystemAccount(), params); + router = startVirtualRouter(router, _accountService.getSystemUser(), _accountService.getSystemAccount(), params); } runningRouters.add(router); } - return runningRouters; } @@ -1019,7 +1080,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian for (DomainRouterVO router : routers) { State state = router.getState(); if (state != State.Running) { - router = this.start(router, _accountService.getSystemUser(), _accountService.getSystemAccount(), params); + router = startVirtualRouter(router, _accountService.getSystemUser(), _accountService.getSystemAccount(), params); } runningRouters.add(router); } @@ -1316,10 +1377,10 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian public void finalizeExpunge(DomainRouterVO vm) { } - private DomainRouterVO start(DomainRouterVO router, User user, Account caller, Map params) throws StorageUnavailableException, InsufficientCapacityException, + private DomainRouterVO start(DomainRouterVO router, User user, Account caller, Map params, DeploymentPlan planToDeploy) throws StorageUnavailableException, InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { s_logger.debug("Starting router " + router); - if (_itMgr.start(router, params, user, caller) != null) { + if (_itMgr.start(router, params, user, caller, planToDeploy) != null) { return _routerDao.findById(router.getId()); } else { return null; @@ -1512,7 +1573,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian } else { params.put(Param.RestartNetwork, false); } - return this.start(router, user, account, params); + return startVirtualRouter(router, user, account, params); } private void createAssociateIPCommands(final DomainRouterVO router, final List ips, Commands cmds, long vmId) { diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index 939d7dbb6b1..faa2e0c796c 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -600,7 +600,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene VMTemplateVO template = _templateDao.findById(vm.getTemplateId()); DataCenterDeployment plan = new DataCenterDeployment(vm.getDataCenterIdToDeployIn(), vm.getPodIdToDeployIn(), null, null, null); - if(planToDeploy != null){ + if(planToDeploy != null && planToDeploy.getDataCenterId() != 0){ if (s_logger.isDebugEnabled()) { s_logger.debug("advanceStart: DeploymentPlan is provided, using that plan to deploy"); } @@ -612,15 +612,17 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene try { Journal journal = start.second().getJournal(); - ExcludeList avoids = new ExcludeList(); - if (vm.getType().equals(VirtualMachine.Type.DomainRouter)) { - List routers = _routerDao.findBy(vm.getAccountId(), vm.getDataCenterIdToDeployIn()); - for (DomainRouterVO router : routers) { - if (router.hostId != null) { - avoids.addHost(router.hostId); - s_logger.info("Router: try to avoid host " + router.hostId); - } - } + ExcludeList avoids = null; + if (planToDeploy != null) { + avoids = planToDeploy.getAvoids(); + } + if (avoids == null) { + avoids = new ExcludeList(); + } + if (s_logger.isDebugEnabled()) { + s_logger.debug("Deploy avoids pods: " + avoids.getPodsToAvoid() + + ", clusters: " + avoids.getClustersToAvoid() + + ", hosts: " + avoids.getHostsToAvoid()); } int retry = _retry; while (retry-- != 0) { // It's != so that it can match -1. @@ -647,7 +649,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene long rootVolDcId = pool.getDataCenterId(); Long rootVolPodId = pool.getPodId(); Long rootVolClusterId = pool.getClusterId(); - if(planToDeploy != null){ + if(planToDeploy != null && planToDeploy.getDataCenterId() != 0){ Long clusterIdSpecified = planToDeploy.getClusterId(); if(clusterIdSpecified != null && rootVolClusterId != null){ if(rootVolClusterId.longValue() != clusterIdSpecified.longValue()){ @@ -684,26 +686,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene } if (dest == null) { - //see if we can allocate the router without limitation - if (vm.getType().equals(VirtualMachine.Type.DomainRouter)) { - avoids = new ExcludeList(); - s_logger.info("Router: cancel avoids "); - for (DeploymentPlanner planner : _planners) { - if (planner.canHandle(vmProfile, plan, avoids)) { - dest = planner.plan(vmProfile, plan, avoids); - } else { - continue; - } - if (dest != null) { - avoids.addHost(dest.getHost().getId()); - journal.record("Deployment found ", vmProfile, dest); - break; - } - } - } - if (dest == null) { throw new InsufficientServerCapacityException("Unable to create a deployment for " + vmProfile, DataCenter.class, plan.getDataCenterId()); - } } long destHostId = dest.getHost().getId();