diff --git a/api/src/com/cloud/agent/api/storage/DownloadCommand.java b/api/src/com/cloud/agent/api/storage/DownloadCommand.java index 126ee46cdd5..67b31589e20 100644 --- a/api/src/com/cloud/agent/api/storage/DownloadCommand.java +++ b/api/src/com/cloud/agent/api/storage/DownloadCommand.java @@ -117,6 +117,7 @@ public class DownloadCommand extends AbstractDownloadCommand { this.auth = that.getAuth(); this.setSecUrl(that.getSecUrl()); this.maxDownloadSizeInBytes = that.getMaxDownloadSizeInBytes(); + this.resourceType = that.resourceType; } public DownloadCommand(String secUrl, VirtualMachineTemplate template, Long maxDownloadSizeInBytes) { diff --git a/api/src/com/cloud/agent/api/storage/ListVolumeCommand.java b/api/src/com/cloud/agent/api/storage/ListVolumeCommand.java new file mode 100755 index 00000000000..d7ecb09d742 --- /dev/null +++ b/api/src/com/cloud/agent/api/storage/ListVolumeCommand.java @@ -0,0 +1,27 @@ +package com.cloud.agent.api.storage; + +import com.cloud.agent.api.LogLevel; +import com.cloud.agent.api.LogLevel.Log4jLevel; +import com.cloud.agent.api.to.SwiftTO; + +public class ListVolumeCommand extends StorageCommand { + + private String secUrl; + + public ListVolumeCommand() { + } + + public ListVolumeCommand(String secUrl) { + this.secUrl = secUrl; + } + + @Override + public boolean executeInSequence() { + return true; + } + + public String getSecUrl() { + return secUrl; + } + +} diff --git a/api/src/com/cloud/storage/Volume.java b/api/src/com/cloud/storage/Volume.java index 959336b5821..73e69d53026 100755 --- a/api/src/com/cloud/storage/Volume.java +++ b/api/src/com/cloud/storage/Volume.java @@ -31,7 +31,10 @@ public interface Volume extends ControlledEntity, BasedOn, StateObject templateInfos = _dlMgr.gatherTemplateInfo(root); + return new ListTemplateAnswer(cmd.getSecUrl(), templateInfos); + + } + private Answer execute(SecStorageVMSetupCommand cmd) { if (!_inSystemVM){ return new Answer(cmd, true, null); diff --git a/core/src/com/cloud/storage/template/DownloadManager.java b/core/src/com/cloud/storage/template/DownloadManager.java index 94e8094b793..306836e87da 100644 --- a/core/src/com/cloud/storage/template/DownloadManager.java +++ b/core/src/com/cloud/storage/template/DownloadManager.java @@ -92,5 +92,11 @@ public interface DownloadManager extends Manager { * @return list of template info for installed templates */ public Map gatherTemplateInfo(String templateDir); + + /** + /** + * @return list of volume info for installed volumes + */ + public Map gatherVolumeInfo(String volumeDir); } \ No newline at end of file diff --git a/core/src/com/cloud/storage/template/DownloadManagerImpl.java b/core/src/com/cloud/storage/template/DownloadManagerImpl.java index bf77ac80d17..5867ac63eda 100755 --- a/core/src/com/cloud/storage/template/DownloadManagerImpl.java +++ b/core/src/com/cloud/storage/template/DownloadManagerImpl.java @@ -222,6 +222,7 @@ public class DownloadManagerImpl implements DownloadManager { private final Map jobs = new ConcurrentHashMap(); private String listTmpltScr; + private String listVolScr; private int installTimeoutPerGig = 180 * 60 * 1000; private boolean _sslCopy; @@ -317,23 +318,28 @@ public class DownloadManagerImpl implements DownloadManager { private String postDownload(String jobId) { DownloadJob dnld = jobs.get(jobId); TemplateDownloader td = dnld.getTemplateDownloader(); - String templatePath = null; - templatePath = dnld.getInstallPathPrefix() + dnld.getAccountId() + File.separator + dnld.getId() + File.separator;// dnld.getTmpltName(); + String resourcePath = null; ResourceType resourceType = dnld.getResourceType(); - - _storage.mkdirs(templatePath); - + // once template path is set, remove the parent dir so that the template is installed with a relative path - String finalTemplatePath = resourceType == ResourceType.TEMPLATE ? _templateDir : _volumeDir - + File.separator + dnld.getAccountId() + File.separator + dnld.getId() + File.separator; - dnld.setTmpltPath(finalTemplatePath); + String finalResourcePath = ""; + if (resourceType == ResourceType.TEMPLATE){ + finalResourcePath += _templateDir + File.separator + dnld.getAccountId() + File.separator + dnld.getId() + File.separator; + resourcePath = dnld.getInstallPathPrefix() + dnld.getAccountId() + File.separator + dnld.getId() + File.separator;// dnld.getTmpltName(); + }else { + finalResourcePath += _volumeDir + File.separator + dnld.getId() + File.separator; + resourcePath = dnld.getInstallPathPrefix() + dnld.getId() + File.separator;// dnld.getTmpltName(); + } + + _storage.mkdirs(resourcePath); + dnld.setTmpltPath(finalResourcePath); int imgSizeGigs = (int) Math.ceil(_storage.getSize(td.getDownloadLocalPath()) * 1.0d / (1024 * 1024 * 1024)); imgSizeGigs++; // add one just in case long timeout = imgSizeGigs * installTimeoutPerGig; Script scr = null; String script = resourceType == ResourceType.TEMPLATE ? createTmpltScr : createVolScr; - scr = new Script(createTmpltScr, timeout, s_logger); + scr = new Script(script, timeout, s_logger); scr.add("-s", Integer.toString(imgSizeGigs)); scr.add("-S", Long.toString(td.getMaxTemplateSizeInBytes())); if (dnld.getDescription() != null && dnld.getDescription().length() > 1) { @@ -353,10 +359,10 @@ public class DownloadManagerImpl implements DownloadManager { } String templateFilename = templateName + "." + extension; - dnld.setTmpltPath(finalTemplatePath + "/" + templateFilename); + dnld.setTmpltPath(finalResourcePath + "/" + templateFilename); scr.add("-n", templateFilename); - scr.add("-t", templatePath); + scr.add("-t", resourcePath); scr.add("-f", td.getDownloadLocalPath()); if (dnld.getChecksum() != null && dnld.getChecksum().length() > 1) { scr.add("-c", dnld.getChecksum()); @@ -370,18 +376,24 @@ public class DownloadManagerImpl implements DownloadManager { } // Set permissions for the downloaded template - File downloadedTemplate = new File(templatePath + "/" + templateFilename); + File downloadedTemplate = new File(resourcePath + "/" + templateFilename); _storage.setWorldReadableAndWriteable(downloadedTemplate); - // Set permissions for template.properties - File templateProperties = new File(templatePath + "/template.properties"); + // Set permissions for template/volume.properties + String propertiesFile = resourcePath; + if (resourceType == ResourceType.TEMPLATE){ + propertiesFile += "/template.properties"; + }else{ + propertiesFile += "/volume.properties"; + } + File templateProperties = new File(propertiesFile); _storage.setWorldReadableAndWriteable(templateProperties); - TemplateLocation loc = new TemplateLocation(_storage, templatePath); + TemplateLocation loc = new TemplateLocation(_storage, resourcePath); try { loc.create(dnld.getId(), true, dnld.getTmpltName()); } catch (IOException e) { - s_logger.warn("Something is wrong with template location " + templatePath, e); + s_logger.warn("Something is wrong with template location " + resourcePath, e); loc.purge(); return "Unable to download due to " + e.getMessage(); } @@ -392,7 +404,7 @@ public class DownloadManagerImpl implements DownloadManager { FormatInfo info = null; try { - info = processor.process(templatePath, null, templateName); + info = processor.process(resourcePath, null, templateName); } catch (InternalErrorException e) { s_logger.error("Template process exception ", e); return e.toString(); @@ -432,7 +444,12 @@ public class DownloadManagerImpl implements DownloadManager { public String downloadPublicTemplate(long id, String url, String name, ImageFormat format, boolean hvm, Long accountId, String descr, String cksum, String installPathPrefix, String user, String password, long maxTemplateSizeInBytes, Proxy proxy, ResourceType resourceType) { UUID uuid = UUID.randomUUID(); String jobId = uuid.toString(); - String tmpDir = installPathPrefix + File.separator + accountId + File.separator + id; + String tmpDir = ""; + if(resourceType == ResourceType.TEMPLATE){ + tmpDir = installPathPrefix + File.separator + accountId + File.separator + id; + }else { + tmpDir = installPathPrefix + File.separator + id; + } try { @@ -672,6 +689,19 @@ public class DownloadManagerImpl implements DownloadManager { } + + private List listVolumes(String rootdir) { + List result = new ArrayList(); + + Script script = new Script(listVolScr, s_logger); + script.add("-r", rootdir); + ZfsPathParser zpp = new ZfsPathParser(rootdir); + script.execute(zpp); + result.addAll(zpp.getPaths()); + s_logger.info("found " + zpp.getPaths().size() + " volumes" + zpp.getPaths()); + return result; + } + private List listTemplates(String rootdir) { List result = new ArrayList(); @@ -849,6 +879,12 @@ public class DownloadManagerImpl implements DownloadManager { } s_logger.info("createtmplt.sh found in " + createTmpltScr); + /*listVolScr = Script.findScript(scriptsDir, "listvolume.sh"); + if (listVolScr == null) { + throw new ConfigurationException("Unable to find the listvolume.sh"); + } + s_logger.info("listvolume.sh found in " + listVolScr);*/ + createVolScr = Script.findScript(scriptsDir, "createvolume.sh"); if (createVolScr == null) { throw new ConfigurationException("Unable to find createvolume.sh"); @@ -884,7 +920,7 @@ public class DownloadManagerImpl implements DownloadManager { _templateDir = TemplateConstants.DEFAULT_TMPLT_ROOT_DIR; } _templateDir += File.separator + TemplateConstants.DEFAULT_TMPLT_FIRST_LEVEL_DIR; - _volumeDir = TemplateConstants.DEFAULT_VOLUME_ROOT_DIR; + _volumeDir = TemplateConstants.DEFAULT_VOLUME_ROOT_DIR + File.separator; // Add more processors here. threadPool = Executors.newFixedThreadPool(numInstallThreads); return true; @@ -959,4 +995,10 @@ public class DownloadManagerImpl implements DownloadManager { return; } } + + @Override + public Map gatherVolumeInfo(String volumeDir) { + // TODO Auto-generated method stub + return null; + } } diff --git a/core/src/com/cloud/storage/template/TemplateConstants.java b/core/src/com/cloud/storage/template/TemplateConstants.java index ec2aa4cf90c..105fe8728a1 100644 --- a/core/src/com/cloud/storage/template/TemplateConstants.java +++ b/core/src/com/cloud/storage/template/TemplateConstants.java @@ -18,7 +18,7 @@ package com.cloud.storage.template; */ public final class TemplateConstants { public static final String DEFAULT_TMPLT_ROOT_DIR = "template"; - public static final String DEFAULT_VOLUME_ROOT_DIR = "volume"; + public static final String DEFAULT_VOLUME_ROOT_DIR = "volumes"; public static final String DEFAULT_TMPLT_FIRST_LEVEL_DIR = "tmpl/"; public static final String DEFAULT_SYSTEM_VM_TEMPLATE_PATH = "template/tmpl/1/"; diff --git a/core/src/com/cloud/storage/template/TemplateLocation.java b/core/src/com/cloud/storage/template/TemplateLocation.java index 0756165397e..42d591342ab 100644 --- a/core/src/com/cloud/storage/template/TemplateLocation.java +++ b/core/src/com/cloud/storage/template/TemplateLocation.java @@ -48,7 +48,12 @@ public class TemplateLocation { } _formats = new ArrayList(5); _props = new Properties(); - _file = _storage.getFile(_templatePath + Filename); + //TO DO remove this hack + if (_templatePath.matches(".*"+"volumes"+".*")){ + _file = _storage.getFile(_templatePath + "volume.properties"); + }else { + _file = _storage.getFile(_templatePath + Filename); + } _isCorrupted = false; } diff --git a/server/src/com/cloud/storage/StorageManager.java b/server/src/com/cloud/storage/StorageManager.java index 2fa5c350b23..e51d49e5c5a 100755 --- a/server/src/com/cloud/storage/StorageManager.java +++ b/server/src/com/cloud/storage/StorageManager.java @@ -220,4 +220,10 @@ public interface StorageManager extends StorageService, Manager { List getUpHostsInPool(long poolId); void cleanupSecondaryStorage(boolean recurring); -} + + VolumeVO copyVolumeFromSecToPrimary(VolumeVO volume, VMInstanceVO vm, + VMTemplateVO template, DataCenterVO dc, HostPodVO pod, + Long clusterId, ServiceOfferingVO offering, + DiskOfferingVO diskOffering, List avoids, long size, + HypervisorType hyperType) throws NoTransitionException; +} diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 8c1694b8ee9..7c6f9eaa4a0 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -131,6 +131,7 @@ import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.Volume.Event; import com.cloud.storage.Volume.Type; import com.cloud.storage.allocator.StoragePoolAllocator; import com.cloud.storage.dao.DiskOfferingDao; @@ -144,6 +145,7 @@ import com.cloud.storage.dao.VMTemplateHostDao; import com.cloud.storage.dao.VMTemplatePoolDao; import com.cloud.storage.dao.VMTemplateSwiftDao; import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeHostDao; import com.cloud.storage.download.DownloadMonitor; import com.cloud.storage.listener.StoragePoolMonitor; import com.cloud.storage.secondary.SecondaryStorageVmManager; @@ -255,6 +257,8 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag @Inject protected UserVmDao _userVmDao; @Inject + VolumeHostDao _volumeHostDao; + @Inject protected VMInstanceDao _vmInstanceDao; @Inject protected StoragePoolDao _storagePoolDao = null; @@ -706,6 +710,53 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag return new Pair(vdiUUID, basicErrMsg); } + + @Override + @DB + public VolumeVO copyVolumeFromSecToPrimary(VolumeVO volume, VMInstanceVO vm, VMTemplateVO template, DataCenterVO dc, HostPodVO pod, Long clusterId, ServiceOfferingVO offering, DiskOfferingVO diskOffering, + List avoids, long size, HypervisorType hyperType) throws NoTransitionException { + + final HashSet avoidPools = new HashSet(avoids); + DiskProfile dskCh = createDiskCharacteristics(volume, template, dc, diskOffering); + dskCh.setHyperType(vm.getHypervisorType()); + // Find a suitable storage to create volume on + StoragePoolVO destPool = findStoragePool(dskCh, dc, pod, clusterId, vm, avoidPools); + + // Copy the volume from secondary storage to the destination storage pool + stateTransitTo(volume, Event.CopyRequested); + VolumeHostVO volumeHostVO = _volumeHostDao.findByVolumeId(volume.getId()); + HostVO secStorage = _hostDao.findById(volumeHostVO.getHostId()); + String secondaryStorageURL = secStorage.getStorageUrl(); + String[] volumePath = volumeHostVO.getInstallPath().split("/"); + String volumeUUID = volumePath[volumePath.length - 1].split("\\.")[0]; + + CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(), volumeUUID, destPool, secondaryStorageURL, false, _copyvolumewait); + CopyVolumeAnswer cvAnswer; + try { + cvAnswer = (CopyVolumeAnswer) sendToPool(destPool, cvCmd); + } catch (StorageUnavailableException e1) { + stateTransitTo(volume, Event.CopyFailed); + throw new CloudRuntimeException("Failed to copy the volume from secondary storage to the destination primary storage pool."); + } + + if (cvAnswer == null || !cvAnswer.getResult()) { + stateTransitTo(volume, Event.CopyFailed); + throw new CloudRuntimeException("Failed to copy the volume from secondary storage to the destination primary storage pool."); + } + Transaction txn = Transaction.currentTxn(); + txn.start(); + volume.setPath(cvAnswer.getVolumePath()); + volume.setFolder(destPool.getPath()); + volume.setPodId(destPool.getPodId()); + volume.setPoolId(destPool.getId()); + volume.setPodId(destPool.getPodId()); + stateTransitTo(volume, Event.CopySucceeded); + _volumeHostDao.remove(volumeHostVO.getId()); + txn.commit(); + return volume; + + } + @Override @DB public VolumeVO createVolume(VolumeVO volume, VMInstanceVO vm, VMTemplateVO template, DataCenterVO dc, HostPodVO pod, Long clusterId, ServiceOfferingVO offering, DiskOfferingVO diskOffering, @@ -1748,7 +1799,7 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag volume.setAccountId(ownerId); volume.setDomainId(((caller == null) ? Domain.ROOT_DOMAIN : caller.getDomainId())); long diskOfferingId = _diskOfferingDao.findByUniqueName("Cloud.com-Custom").getId(); - volume.setDiskOfferingId(diskOfferingId); + volume.setDiskOfferingId(diskOfferingId); //volume.setSize(size); volume.setInstanceId(null); volume.setUpdated(new Date()); @@ -1757,7 +1808,12 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag volume = _volsDao.persist(volume); UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), diskOfferingId, null, 0l); _usageEventDao.persist(usageEvent); - + try { + stateTransitTo(volume, Event.UploadRequested); + } catch (NoTransitionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } UserContext.current().setEventDetails("Volume Id: " + volume.getId()); // Increment resource count during allocation; if actual creation fails, decrement it diff --git a/server/src/com/cloud/storage/dao/VolumeHostDao.java b/server/src/com/cloud/storage/dao/VolumeHostDao.java index 26e13ac43d5..33d46410897 100755 --- a/server/src/com/cloud/storage/dao/VolumeHostDao.java +++ b/server/src/com/cloud/storage/dao/VolumeHostDao.java @@ -7,4 +7,6 @@ public interface VolumeHostDao extends GenericDao { VolumeHostVO findByHostVolume(long id, long id2); + VolumeHostVO findByVolumeId(long volumeId); + } diff --git a/server/src/com/cloud/storage/dao/VolumeHostDaoImpl.java b/server/src/com/cloud/storage/dao/VolumeHostDaoImpl.java index d95d50196e4..8f4b5e20729 100755 --- a/server/src/com/cloud/storage/dao/VolumeHostDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VolumeHostDaoImpl.java @@ -1,8 +1,9 @@ package com.cloud.storage.dao; -import javax.ejb.Local; +import java.util.List; +import javax.ejb.Local; import com.cloud.storage.VolumeHostVO; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; @@ -11,6 +12,7 @@ import com.cloud.utils.db.SearchCriteria; public class VolumeHostDaoImpl extends GenericDaoBase implements VolumeHostDao { protected final SearchBuilder HostVolumeSearch; + protected final SearchBuilder VolumeSearch; VolumeHostDaoImpl(){ HostVolumeSearch = createSearchBuilder(); @@ -18,6 +20,11 @@ public class VolumeHostDaoImpl extends GenericDaoBase implem HostVolumeSearch.and("volume_id", HostVolumeSearch.entity().getVolumeId(), SearchCriteria.Op.EQ); HostVolumeSearch.and("destroyed", HostVolumeSearch.entity().getDestroyed(), SearchCriteria.Op.EQ); HostVolumeSearch.done(); + + VolumeSearch = createSearchBuilder(); + VolumeSearch.and("volume_id", VolumeSearch.entity().getVolumeId(), SearchCriteria.Op.EQ); + VolumeSearch.and("destroyed", VolumeSearch.entity().getDestroyed(), SearchCriteria.Op.EQ); + VolumeSearch.done(); } @@ -30,5 +37,13 @@ public class VolumeHostDaoImpl extends GenericDaoBase implem sc.setParameters("destroyed", false); return findOneIncludingRemovedBy(sc); } + + @Override + public VolumeHostVO findByVolumeId(long volumeId) { + SearchCriteria sc = VolumeSearch.create(); + sc.setParameters("volume_id", volumeId); + sc.setParameters("destroyed", false); + return findOneBy(sc); + } } diff --git a/server/src/com/cloud/storage/download/DownloadListener.java b/server/src/com/cloud/storage/download/DownloadListener.java index 654958498f4..62e3f3eeee4 100755 --- a/server/src/com/cloud/storage/download/DownloadListener.java +++ b/server/src/com/cloud/storage/download/DownloadListener.java @@ -33,16 +33,19 @@ import com.cloud.agent.api.StartupStorageCommand; import com.cloud.agent.api.storage.DownloadAnswer; import com.cloud.agent.api.storage.DownloadCommand; import com.cloud.agent.api.storage.DownloadProgressCommand; +import com.cloud.agent.api.storage.DownloadCommand.ResourceType; import com.cloud.agent.api.storage.DownloadProgressCommand.RequestType; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.ConnectionException; import com.cloud.host.HostVO; import com.cloud.storage.Storage; +import com.cloud.storage.StorageManager; import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VolumeHostVO; import com.cloud.storage.VolumeVO; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; +import com.cloud.storage.Volume.Event; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateHostDao; @@ -50,6 +53,7 @@ import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.dao.VolumeHostDao; import com.cloud.storage.download.DownloadState.DownloadEvent; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.fsm.NoTransitionException; /** * Monitor progress of template download to a single storage server @@ -108,7 +112,8 @@ public class DownloadListener implements Listener { private boolean downloadActive = true; private VolumeHostDao volumeHostDao; - private VolumeDao _volumeDao; + private VolumeDao _volumeDao; + private StorageManager _storageMgr; private VMTemplateHostDao vmTemplateHostDao; private VMTemplateDao _vmTemplateDao; @@ -146,7 +151,7 @@ public class DownloadListener implements Listener { updateDatabase(Status.NOT_DOWNLOADED, ""); } - public DownloadListener(HostVO ssAgent, HostVO host, VolumeVO volume, Timer _timer, VolumeHostDao dao, Long volHostId, DownloadMonitorImpl downloadMonitor, DownloadCommand cmd, VolumeDao volumeDao) { + public DownloadListener(HostVO ssAgent, HostVO host, VolumeVO volume, Timer _timer, VolumeHostDao dao, Long volHostId, DownloadMonitorImpl downloadMonitor, DownloadCommand cmd, VolumeDao volumeDao, StorageManager storageMgr) { this.ssAgent = ssAgent; this.sserver = host; this.volume = volume; @@ -160,6 +165,7 @@ public class DownloadListener implements Listener { this.timeoutTask = new TimeoutTask(this); this.timer.schedule(timeoutTask, 3*STATUS_POLL_INTERVAL); this._volumeDao = volumeDao; + this._storageMgr = storageMgr; updateDatabase(Status.NOT_DOWNLOADED, ""); } @@ -186,7 +192,11 @@ public class DownloadListener implements Listener { log("Sending progress command ", Level.TRACE); } try { - downloadMonitor.send(ssAgent.getId(), new DownloadProgressCommand(getCommand(), getJobId(), reqType), this); + DownloadProgressCommand dcmd = new DownloadProgressCommand(getCommand(), getJobId(), reqType); + if (template == null){ + dcmd.setResourceType(ResourceType.VOLUME); + } + downloadMonitor.send(ssAgent.getId(), dcmd, this); } catch (AgentUnavailableException e) { s_logger.debug("Send command failed", e); setDisconnected(); @@ -328,6 +338,12 @@ public class DownloadListener implements Listener { updateBuilder.setPhysicalSize(answer.getTemplatePhySicalSize()); volumeHostDao.update(getVolumeHostId(), updateBuilder); + try { + _storageMgr.stateTransitTo(volume, Event.UploadSucceeded); + } catch (NoTransitionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } /*if (answer.getCheckSum() != null) { VMTemplateVO templateDaoBuilder = _vmTemplateDao.createForUpdate(); diff --git a/server/src/com/cloud/storage/download/DownloadMonitorImpl.java b/server/src/com/cloud/storage/download/DownloadMonitorImpl.java index 1a76a2f0cf7..34139798ba1 100755 --- a/server/src/com/cloud/storage/download/DownloadMonitorImpl.java +++ b/server/src/com/cloud/storage/download/DownloadMonitorImpl.java @@ -34,6 +34,7 @@ import com.cloud.agent.api.Command; import com.cloud.agent.api.storage.DeleteTemplateCommand; import com.cloud.agent.api.storage.DownloadCommand; import com.cloud.agent.api.storage.DownloadCommand.Proxy; +import com.cloud.agent.api.storage.DownloadCommand.ResourceType; import com.cloud.agent.api.storage.DownloadProgressCommand; import com.cloud.agent.api.storage.DownloadProgressCommand.RequestType; import com.cloud.agent.api.storage.ListTemplateAnswer; @@ -57,12 +58,14 @@ import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ResourceManager; import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.StorageManager; import com.cloud.storage.SwiftVO; import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.VolumeHostVO; import com.cloud.storage.VolumeVO; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; +import com.cloud.storage.Volume.Event; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VMTemplateZoneVO; import com.cloud.storage.dao.StoragePoolHostDao; @@ -86,6 +89,7 @@ import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.fsm.NoTransitionException; import com.cloud.vm.SecondaryStorageVm; import com.cloud.vm.SecondaryStorageVmVO; import com.cloud.vm.UserVmManager; @@ -126,6 +130,8 @@ public class DownloadMonitorImpl implements DownloadMonitor { protected SwiftManager _swiftMgr; @Inject SecondaryStorageVmManager _ssvmMgr; + @Inject + StorageManager _storageMgr ; @Inject private final DataCenterDao _dcDao = null; @@ -423,12 +429,19 @@ public class DownloadMonitorImpl implements DownloadMonitor { volumeHost = _volumeHostDao.findByHostVolume(sserver.getId(), volume.getId()); if (volumeHost == null) { - volumeHost = new VolumeHostVO(sserver.getId(), volume.getId(), new Date(), 0, VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED, null, null, "jobid0000", null, url, checkSum); + volumeHost = new VolumeHostVO(sserver.getId(), volume.getId(), new Date(), 0, VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED, null, null, + "jobid0000", null, url, checkSum); _volumeHostDao.persist(volumeHost); } else if ((volumeHost.getJobId() != null) && (volumeHost.getJobId().length() > 2)) { downloadJobExists = true; } - + + try { + _storageMgr.stateTransitTo(volume, Event.UploadRequested); + } catch (NoTransitionException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } Long maxVolumeSizeInBytes = getMaxVolumeSizeInBytes(); String secUrl = sserver.getStorageUrl(); if(volumeHost != null) { @@ -437,6 +450,7 @@ public class DownloadMonitorImpl implements DownloadMonitor { dcmd.setProxy(getHttpProxy()); if (downloadJobExists) { dcmd = new DownloadProgressCommand(dcmd, volumeHost.getJobId(), RequestType.GET_OR_RESTART); + dcmd.setResourceType(ResourceType.VOLUME); } HostVO ssvm = _ssvmMgr.pickSsvmHost(sserver); @@ -444,7 +458,8 @@ public class DownloadMonitorImpl implements DownloadMonitor { s_logger.warn("There is no secondary storage VM for secondary storage host " + sserver.getName()); return; } - DownloadListener dl = new DownloadListener(ssvm, sserver, volume, _timer, _volumeHostDao, volumeHost.getId(), this, dcmd, _volumeDao); + DownloadListener dl = new DownloadListener(ssvm, sserver, volume, _timer, _volumeHostDao, volumeHost.getId(), + this, dcmd, _volumeDao, _storageMgr); if (downloadJobExists) { dl.setCurrState(volumeHost.getDownloadState()); diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 8c5c55e1435..6fd021fcba2 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -152,6 +152,7 @@ import com.cloud.storage.GuestOSVO; import com.cloud.storage.Snapshot; import com.cloud.storage.SnapshotVO; import com.cloud.storage.Storage; +import com.cloud.storage.VolumeHostVO; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Storage.TemplateType; @@ -175,6 +176,7 @@ import com.cloud.storage.dao.VMTemplateDetailsDao; import com.cloud.storage.dao.VMTemplateHostDao; import com.cloud.storage.dao.VMTemplateZoneDao; import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeHostDao; import com.cloud.storage.snapshot.SnapshotManager; import com.cloud.template.VirtualMachineTemplate; import com.cloud.template.VirtualMachineTemplate.BootloaderType; @@ -335,6 +337,8 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager SecurityGroupVMMapDao _securityGroupVMMapDao; @Inject protected ItWorkDao _workDao; + VolumeHostDao _volumeHostDao; + protected ScheduledExecutorService _executor = null; protected int _expungeInterval; @@ -548,14 +552,20 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager //permission check _accountMgr.checkAccess(caller, null, true, volume, vm); + //Check if volume is stored on secondary Storage. + boolean volumeOnSec = false; + VolumeHostVO volHostVO = _volumeHostDao.findByVolumeId(volume.getId()); + if (volHostVO != null){ + volumeOnSec = true; + } // Check that the volume is stored on shared storage - if (!(Volume.State.Allocated.equals(volume.getState())) && !_storageMgr.volumeOnSharedStoragePool(volume)) { + if (!(Volume.State.Allocated.equals(volume.getState()) || Volume.State.Uploaded.equals(volume.getState())) && !_storageMgr.volumeOnSharedStoragePool(volume)) { throw new InvalidParameterValueException("Please specify a volume that has been created on a shared storage pool."); } - if (!(Volume.State.Allocated.equals(volume.getState()) || Volume.State.Ready.equals(volume.getState()))) { - throw new InvalidParameterValueException("Volume state must be in Allocated or Ready state"); + if ( !(Volume.State.Allocated.equals(volume.getState()) || Volume.State.Ready.equals(volume.getState()) || Volume.State.Uploaded.equals(volume.getState())) ) { + throw new InvalidParameterValueException("Volume state must be in Allocated, Ready or Uploaded state"); } VolumeVO rootVolumeOfVm = null; @@ -566,8 +576,31 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager rootVolumeOfVm = rootVolumesOfVm.get(0); } - HypervisorType rootDiskHyperType = vm.getHypervisorType(); - + HypervisorType rootDiskHyperType = _volsDao.getHypervisorType(rootVolumeOfVm.getId()); + + if (volume.getState().equals(Volume.State.Allocated) || volume.getState().equals(Volume.State.Uploaded)) { + /* Need to create the volume */ + VMTemplateVO rootDiskTmplt = _templateDao.findById(vm.getTemplateId()); + DataCenterVO dcVO = _dcDao.findById(vm.getDataCenterIdToDeployIn()); + HostPodVO pod = _podDao.findById(vm.getPodIdToDeployIn()); + StoragePoolVO rootDiskPool = _storagePoolDao.findById(rootVolumeOfVm.getPoolId()); + ServiceOfferingVO svo = _serviceOfferingDao.findById(vm.getServiceOfferingId()); + DiskOfferingVO diskVO = _diskOfferingDao.findById(volume.getDiskOfferingId()); + if (!volumeOnSec){ + volume = _storageMgr.createVolume(volume, vm, rootDiskTmplt, dcVO, pod, rootDiskPool.getClusterId(), svo, diskVO, new ArrayList(), volume.getSize(), rootDiskHyperType); + }else { + try { + volume = _storageMgr.copyVolumeFromSecToPrimary(volume, vm, rootDiskTmplt, dcVO, pod, rootDiskPool.getClusterId(), svo, diskVO, new ArrayList(), volume.getSize(), rootDiskHyperType); + } catch (NoTransitionException e) { + e.printStackTrace(); + } + } + + if (volume == null) { + throw new CloudRuntimeException("Failed to create volume when attaching it to VM: " + vm.getHostName()); + } + } + HypervisorType dataDiskHyperType = _volsDao.getHypervisorType(volume.getId()); if (dataDiskHyperType != HypervisorType.None && rootDiskHyperType != dataDiskHyperType) { throw new InvalidParameterValueException("Can't attach a volume created by: " + dataDiskHyperType + " to a " + rootDiskHyperType + " vm");