From 5a73309e754cc3fd1f9c19d9fde07e777fef5e64 Mon Sep 17 00:00:00 2001 From: prachi Date: Wed, 13 Apr 2011 13:46:42 -0700 Subject: [PATCH] Bug 9387: Recreate system vms if template id changed.... Changes: While starting a System VM: - We check, incase the ROOT volume is READY, if the templateID of the volume matches the SystemVM's template. - If it does not match, we update the volumes' templateId and ask deployment planner to reassign a pool to this volume even if it is READY. In general: - If a root volume is READY, we remove its entry from the deploydestination before calling storagemanager :: prepare() - StorageManager creates a volume if a pool is assigned to it in deploydestination passed to it. - If a volume has no pool assigned to it in deploydestination, it means the volume is ready and has a pool already allocated to it. --- api/src/com/cloud/vm/VirtualMachine.java | 11 +- .../src/com/cloud/deploy/FirstFitPlanner.java | 7 +- .../com/cloud/storage/StorageManagerImpl.java | 64 ++++++----- .../cloud/vm/VirtualMachineManagerImpl.java | 100 ++++++++---------- 4 files changed, 91 insertions(+), 91 deletions(-) diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java index cbf64da9483..fee9806e11d 100755 --- a/api/src/com/cloud/vm/VirtualMachine.java +++ b/api/src/com/cloud/vm/VirtualMachine.java @@ -151,7 +151,16 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, StateObject * UserBareMetal is only used for selecting VirtualMachineGuru, there is no * VM with this type. UserBareMetal should treat exactly as User. */ - UserBareMetal, + UserBareMetal; + + public static boolean isSystemVM(VirtualMachine.Type vmtype) { + if(DomainRouter.equals(vmtype) + || ConsoleProxy.equals(vmtype) + || SecondaryStorageVm.equals(vmtype)){ + return true; + } + return false; + } } public String getInstanceName(); diff --git a/server/src/com/cloud/deploy/FirstFitPlanner.java b/server/src/com/cloud/deploy/FirstFitPlanner.java index 4f1cbdb0348..c62706fdfae 100644 --- a/server/src/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/com/cloud/deploy/FirstFitPlanner.java @@ -515,14 +515,17 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { //skip the volume if its already in READY state and has pool allocated if(plan.getPoolId() != null){ - if (toBeCreated.getPoolId() != null && toBeCreated.getPoolId().longValue() == plan.getPoolId().longValue()) { - s_logger.debug("Volume is in READY state and has pool already allocated."); + if (toBeCreated.getVolumeType() == Volume.Type.ROOT && toBeCreated.getPoolId() != null && toBeCreated.getPoolId().longValue() == plan.getPoolId().longValue()) { + s_logger.debug("ROOT Volume is in READY state and has pool already allocated."); List suitablePools = new ArrayList(); StoragePoolVO pool = _storagePoolDao.findById(toBeCreated.getPoolId()); if(!avoid.shouldAvoid(pool)){ + s_logger.debug("Planner need not allocate a pool for this volume since its READY"); suitablePools.add(pool); suitableVolumeStoragePools.put(toBeCreated, suitablePools); continue; + }else{ + s_logger.debug("Pool of the ROOT volume is in avoid set, need to allocate a pool for this volume"); } } } diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index e5f48954868..25e5e0435f3 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -2463,12 +2463,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag if (s_logger.isDebugEnabled()) { s_logger.debug("DeployDestination cannot be null, cannot prepare Volumes for the vm: "+ vm); } - throw new CloudRuntimeException("Unable to prepare Volume for vm because DeployDestination is null"); - }else if(dest.getStorageForDisks() == null){ - if (s_logger.isDebugEnabled()) { - s_logger.debug("DeployDestination has no storage pools specified, cannot prepare Volumes for the vm: "+ vm); - } - throw new CloudRuntimeException("Unable to prepare Volume for vm because DeployDestination DeployDestination has no storage pools specified"); + throw new CloudRuntimeException("Unable to prepare Volume for vm because DeployDestination is null, vm:"+vm); } List vols = _volsDao.findUsableVolumesForInstance(vm.getId()); if (s_logger.isDebugEnabled()) { @@ -2478,34 +2473,35 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag List recreateVols = new ArrayList(vols.size()); for (VolumeVO vol : vols) { - if(vol.getPoolId() == null){ - recreateVols.add(vol); - }else{ - StoragePool assignedPool = dest.getStorageForDisks().get(vol); - if(assignedPool == null){ - throw new StorageUnavailableException("No storage pool assigned in DeployDestination, Unable to create " + vol, -1L); - } - if(vol.getPoolId() != assignedPool.getId()){ - if (vol.isRecreatable()) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Volume " + vol + " has to be recreated since a different storage pool " + assignedPool + " is assigned by deploymentPlanner"); - } - recreateVols.add(vol); - } else { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Volume " + vol + " is not recreatable! Cannot create storagepool..."); - } - throw new StorageUnavailableException("Unable to create " + vol, assignedPool.getId()); - //copy volume usecase - not yet developed. - } - }else{ - if (s_logger.isDebugEnabled()) { - s_logger.debug("Volume " + vol + " already has the poolId set to the assigned pool: " + assignedPool); - } - StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId()); - vm.addDisk(new VolumeTO(vol, pool)); - } - } + StoragePool assignedPool = null; + if(dest.getStorageForDisks() != null){ + assignedPool = dest.getStorageForDisks().get(vol); + } + if(assignedPool != null){ + Volume.State state = vol.getState(); + if(state == Volume.State.Allocated){ + recreateVols.add(vol); + }else{ + if (vol.isRecreatable()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Volume " + vol + " will be recreated on storage pool " + assignedPool + " assigned by deploymentPlanner"); + } + recreateVols.add(vol); + }else{ + if (s_logger.isDebugEnabled()) { + s_logger.debug("Volume " + vol + " is not recreatable! Cannot recreate on storagepool: "+assignedPool); + } + throw new StorageUnavailableException("Volume is not recreatable, Unable to create " + vol, Volume.class, vol.getId()); + //copy volume usecase - not yet developed. + } + } + }else{ + if(vol.getPoolId() == null){ + throw new StorageUnavailableException("Volume has no pool associate and also no storage pool assigned in DeployDestination, Unable to create " + vol, Volume.class, vol.getId()); + } + StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId()); + vm.addDisk(new VolumeTO(vol, pool)); + } } for (VolumeVO vol : recreateVols) { diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index f6b2b1af800..5304b5b5ee1 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -555,21 +555,6 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene T startedVm = null; ServiceOfferingVO offering = _offeringDao.findById(vm.getServiceOfferingId()); VMTemplateVO template = _templateDao.findById(vm.getTemplateId()); - //if System VM template has been changed, update vm templateId if this is a System VM - if(VirtualMachine.Type.DomainRouter.equals(vm.getType()) - || VirtualMachine.Type.ConsoleProxy.equals(vm.getType()) - || VirtualMachine.Type.SecondaryStorageVm.equals(vm.getType())){ - VMTemplateVO systemVMTemplate = _templateDao.findSystemVMTemplate(vm.getDataCenterId(), vm.getHypervisorType()); - if(template != null && systemVMTemplate != null){ - if(template.getId() != systemVMTemplate.getId()){ - if (s_logger.isDebugEnabled()) { - s_logger.debug("System VM's templateId does not match the current System VM Template, updating templateId of the VM: "+ vm); - } - vm.setTemplateId(systemVMTemplate.getId()); - _vmDao.update(vm.getId(), vm); - } - } - } Long clusterSpecified = null; if(hostIdSpecified != null){ @@ -581,50 +566,48 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene try { Journal journal = start.second().getJournal(); + + //edit plan if this vm's ROOT volume is in READY state already + VolumeVO readyRootVolume = null; + List vols = _volsDao.findReadyRootVolumesByInstance(vm.getId()); + + for (VolumeVO vol : vols) { + Volume.State state = vol.getState(); + if (state == Volume.State.Ready) { + //make sure if this is a System VM, templateId is unchanged. If it is changed, let planner + //reassign pool for the volume + if(VirtualMachine.Type.isSystemVM(vm.getType())){ + Long volTemplateId = vol.getTemplateId(); + if(volTemplateId != null && template != null){ + if(volTemplateId.longValue() != template.getId()){ + if (s_logger.isDebugEnabled()) { + s_logger.debug("Root Volume " + vol + " of "+vm.getType().toString() +" System VM is ready, but volume's templateId does not match the System VM Template, updating templateId and reassigning a new pool"); + } + vol.setTemplateId(template.getId()); + _volsDao.update(vol.getId(), vol); + continue; + } + } + + } + StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId()); + if (!pool.isInMaintenance()) { + long rootVolDcId = pool.getDataCenterId(); + Long rootVolPodId = pool.getPodId(); + Long rootVolClusterId = pool.getClusterId(); + plan = new DataCenterDeployment(rootVolDcId, rootVolPodId, rootVolClusterId, null, vol.getPoolId()); + readyRootVolume = vol; + if (s_logger.isDebugEnabled()) { + s_logger.debug("Root Volume " + vol + " is ready, changing deployment plan to use this pool's datacenterId: "+rootVolDcId +" , podId: "+rootVolPodId +" , and clusterId: "+rootVolClusterId); + } + } + } + } ExcludeList avoids = new ExcludeList(); int retry = _retry; while (retry-- != 0) { // It's != so that it can match -1. - //edit plan if this vm's ROOT volume is in READY state already - List vols = _volsDao.findReadyRootVolumesByInstance(vm.getId()); - - for (VolumeVO vol : vols) { - Volume.State state = vol.getState(); - if (state == Volume.State.Ready) { - //make sure if this is a System VM, templateId is unchanged. If it is changed, let planner - //reassign pool for the volume - if(VirtualMachine.Type.DomainRouter.equals(vm.getType()) - || VirtualMachine.Type.ConsoleProxy.equals(vm.getType()) - || VirtualMachine.Type.SecondaryStorageVm.equals(vm.getType())){ - - Long volTemplateId = vol.getTemplateId(); - VMTemplateVO systemVMTemplate = _templateDao.findSystemVMTemplate(vm.getDataCenterId(), vm.getHypervisorType()); - if(volTemplateId != null && systemVMTemplate != null){ - if(volTemplateId.longValue() != systemVMTemplate.getId()){ - if (s_logger.isDebugEnabled()) { - s_logger.debug("Root Volume " + vol + " of "+vm.getType().toString() +" System VM is ready, but volume's templateId does not match the System VM Template, updating templateId and reassigning a new pool"); - } - vol.setTemplateId(systemVMTemplate.getId()); - _volsDao.update(vol.getId(), vol); - continue; - } - } - - } - StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId()); - if (!pool.isInMaintenance()) { - long rootVolDcId = pool.getDataCenterId(); - Long rootVolPodId = pool.getPodId(); - Long rootVolClusterId = pool.getClusterId(); - plan = new DataCenterDeployment(rootVolDcId, rootVolPodId, rootVolClusterId, null, vol.getPoolId()); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Root Volume " + vol + " is ready, changing deployment plan to use this pool's datacenterId: "+rootVolDcId +" , podId: "+rootVolPodId +" , and clusterId: "+rootVolClusterId); - } - } - } - } - VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vm, template, offering, account, params); DeployDestination dest = null; for (DeploymentPlanner planner : _planners) { @@ -652,6 +635,15 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene try { if (vm.getHypervisorType() != HypervisorType.BareMetal) { + if(readyRootVolume != null){ + //remove the vol<->pool from destination, since we don't have to prepare this volume. + if(dest.getStorageForDisks() != null){ + if (s_logger.isDebugEnabled()) { + s_logger.debug("No need to prepare the READY Root Volume " + readyRootVolume + ", removing it from deploydestination"); + } + dest.getStorageForDisks().remove(readyRootVolume); + } + } _storageMgr.prepare(vmProfile, dest); } _networkMgr.prepare(vmProfile, dest, ctx);