Fix a bug in register template, cannot find template adapter. Project: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/commit/c0442e25 Tree: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/tree/c0442e25 Diff: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/diff/c0442e25
Branch: refs/heads/vim51_win8 Commit: c0442e2556a7b10cfb363a2d4d55b7fb9c381297 Parents: 6320cad Author: Min Chen <[email protected]> Authored: Tue Feb 12 16:56:02 2013 -0800 Committer: Min Chen <[email protected]> Committed: Tue Feb 12 16:56:02 2013 -0800 ---------------------------------------------------------------------- client/tomcatconf/componentContext.xml.in | 8 + client/tomcatconf/nonossComponentContext.xml.in | 8 + .../cloud/baremetal/BareMetalTemplateAdapter.java | 33 +- .../cloud/template/HyervisorTemplateAdapter.java | 303 --------------- .../cloud/template/HypervisorTemplateAdapter.java | 302 ++++++++++++++ 5 files changed, 334 insertions(+), 320 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c0442e25/client/tomcatconf/componentContext.xml.in ---------------------------------------------------------------------- diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 43d31fb..fc6c3e3 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -95,6 +95,14 @@ <property name="name" value="FirstFitRouting"/> </bean> + <bean id="hypervisorTemplateAdapter" class="com.cloud.template.HypervisorTemplateAdapter"> + <property name="name" value="HypervisorAdapter"/> + </bean> + + <bean id="bareMetalTemplateAdapter" class="com.cloud.baremetal.BareMetalTemplateAdapter"> + <property name="name" value="BareMetalAdapter"/> + </bean> + <!-- Storage pool allocators --> http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c0442e25/client/tomcatconf/nonossComponentContext.xml.in ---------------------------------------------------------------------- diff --git a/client/tomcatconf/nonossComponentContext.xml.in b/client/tomcatconf/nonossComponentContext.xml.in index 5532bec..57f7ad5 100644 --- a/client/tomcatconf/nonossComponentContext.xml.in +++ b/client/tomcatconf/nonossComponentContext.xml.in @@ -104,6 +104,14 @@ <property name="name" value="FirstFitRouting"/> </bean> + <bean id="hypervisorTemplateAdapter" class="com.cloud.template.HypervisorTemplateAdapter"> + <property name="name" value="HypervisorAdapter"/> + </bean> + + <bean id="bareMetalTemplateAdapter" class="com.cloud.baremetal.BareMetalTemplateAdapter"> + <property name="name" value="BareMetalAdapter"/> + </bean> + <!-- Storage pool allocators --> http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c0442e25/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java b/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java index 965c912..33ab468 100755 --- a/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java +++ b/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java @@ -48,17 +48,16 @@ import com.cloud.user.Account; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; -@Component @Local(value=TemplateAdapter.class) public class BareMetalTemplateAdapter extends TemplateAdapterBase implements TemplateAdapter { private final static Logger s_logger = Logger.getLogger(BareMetalTemplateAdapter.class); @Inject HostDao _hostDao; @Inject ResourceManager _resourceMgr; - + @Override public TemplateProfile prepare(RegisterTemplateCmd cmd) throws ResourceAllocationException { TemplateProfile profile = super.prepare(cmd); - + if (profile.getZoneId() == null || profile.getZoneId() == -1) { List<DataCenterVO> dcs = _dcDao.listAllIncludingRemoved(); for (DataCenterVO dc : dcs) { @@ -73,15 +72,15 @@ public class BareMetalTemplateAdapter extends TemplateAdapterBase implements Tem throw new CloudRuntimeException("Please add PXE server before adding baremetal template in zone " + profile.getZoneId()); } } - + return profile; } - + @Override public TemplateProfile prepare(RegisterIsoCmd cmd) throws ResourceAllocationException { throw new CloudRuntimeException("Baremetal doesn't support ISO template"); } - + private void templateCreateUsage(VMTemplateVO template, HostVO host) { if (template.getAccountId() != Account.ACCOUNT_ID_SYSTEM) { UsageEventUtils.publishUsageEvent(EventTypes.EVENT_TEMPLATE_CREATE, template.getAccountId(), host.getDataCenterId(), @@ -89,12 +88,12 @@ public class BareMetalTemplateAdapter extends TemplateAdapterBase implements Tem template.getClass().getName(), template.getUuid()); } } - + @Override public VMTemplateVO create(TemplateProfile profile) { VMTemplateVO template = persistTemplate(profile); Long zoneId = profile.getZoneId(); - + /* There is no secondary storage vm for baremetal, we use pxe server id. * Tempalte is not bound to pxeserver right now, and we assume the pxeserver * cannot be removed once it was added. so we use host id of first found pxe @@ -122,7 +121,7 @@ public class BareMetalTemplateAdapter extends TemplateAdapterBase implements Tem _tmpltHostDao.persist(vmTemplateHost); templateCreateUsage(template, pxe); } - + _resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template); return template; } @@ -130,7 +129,7 @@ public class BareMetalTemplateAdapter extends TemplateAdapterBase implements Tem public TemplateProfile prepareDelete(DeleteIsoCmd cmd) { throw new CloudRuntimeException("Baremetal doesn't support ISO, how the delete get here???"); } - + @Override @DB public boolean delete(TemplateProfile profile) { VMTemplateVO template = (VMTemplateVO)profile.getTemplate(); @@ -138,7 +137,7 @@ public class BareMetalTemplateAdapter extends TemplateAdapterBase implements Tem boolean success = true; String zoneName; boolean isAllZone; - + if (!template.isCrossZones() && profile.getZoneId() != null) { isAllZone = false; zoneName = profile.getZoneId().toString(); @@ -146,12 +145,12 @@ public class BareMetalTemplateAdapter extends TemplateAdapterBase implements Tem zoneName = "all zones"; isAllZone = true; } - + s_logger.debug("Attempting to mark template host refs for template: " + template.getName() + " as destroyed in zone: " + zoneName); Account account = _accountDao.findByIdIncludingRemoved(template.getAccountId()); String eventType = EventTypes.EVENT_TEMPLATE_DELETE; List<VMTemplateHostVO> templateHostVOs = _tmpltHostDao.listByTemplateId(templateId); - + for (VMTemplateHostVO vo : templateHostVOs) { VMTemplateHostVO lock = null; try { @@ -182,13 +181,13 @@ public class BareMetalTemplateAdapter extends TemplateAdapterBase implements Tem } } } - + s_logger.debug("Successfully marked template host refs for template: " + template.getName() + " as destroyed in zone: " + zoneName); - + // If there are no more non-destroyed template host entries for this template, delete it if (success && (_tmpltHostDao.listByTemplateId(templateId).size() == 0)) { long accountId = template.getAccountId(); - + VMTemplateVO lock = _tmpltDao.acquireInLockTable(templateId); try { @@ -207,7 +206,7 @@ public class BareMetalTemplateAdapter extends TemplateAdapterBase implements Tem } s_logger.debug("Removed template: " + template.getName() + " because all of its template host refs were marked as destroyed."); } - + return success; } } http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c0442e25/server/src/com/cloud/template/HyervisorTemplateAdapter.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/template/HyervisorTemplateAdapter.java b/server/src/com/cloud/template/HyervisorTemplateAdapter.java deleted file mode 100755 index 089f650..0000000 --- a/server/src/com/cloud/template/HyervisorTemplateAdapter.java +++ /dev/null @@ -1,303 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package com.cloud.template; - -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.UnknownHostException; -import java.util.List; - -import javax.ejb.Local; -import javax.inject.Inject; - -import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; -import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import com.cloud.agent.AgentManager; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.storage.DeleteTemplateCommand; -import com.cloud.configuration.Resource.ResourceType; -import com.cloud.dc.DataCenterVO; -import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventUtils; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.host.HostVO; -import com.cloud.storage.Storage.ImageFormat; -import com.cloud.storage.Storage.TemplateType; -import com.cloud.storage.VMTemplateHostVO; -import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.storage.TemplateProfile; -import com.cloud.storage.VMTemplateVO; -import com.cloud.storage.VMTemplateZoneVO; -import com.cloud.storage.download.DownloadMonitor; -import com.cloud.storage.secondary.SecondaryStorageVmManager; -import com.cloud.user.Account; -import com.cloud.utils.db.DB; -import com.cloud.utils.exception.CloudRuntimeException; -import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; -import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; -import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; -import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; -import org.apache.log4j.Logger; - -import javax.ejb.Local; -import java.net.*; -import java.util.List; - -@Component -@Local(value=TemplateAdapter.class) -public class HyervisorTemplateAdapter extends TemplateAdapterBase implements TemplateAdapter { - private final static Logger s_logger = Logger.getLogger(HyervisorTemplateAdapter.class); - @Inject DownloadMonitor _downloadMonitor; - @Inject SecondaryStorageVmManager _ssvmMgr; - @Inject AgentManager _agentMgr; - - private String validateUrl(String url) { - try { - URI uri = new URI(url); - if ((uri.getScheme() == null) || (!uri.getScheme().equalsIgnoreCase("http") - && !uri.getScheme().equalsIgnoreCase("https") && !uri.getScheme().equalsIgnoreCase("file"))) { - throw new IllegalArgumentException("Unsupported scheme for url: " + url); - } - - int port = uri.getPort(); - if (!(port == 80 || port == 443 || port == -1)) { - throw new IllegalArgumentException("Only ports 80 and 443 are allowed"); - } - String host = uri.getHost(); - try { - InetAddress hostAddr = InetAddress.getByName(host); - if (hostAddr.isAnyLocalAddress() || hostAddr.isLinkLocalAddress() || hostAddr.isLoopbackAddress() || hostAddr.isMulticastAddress()) { - throw new IllegalArgumentException("Illegal host specified in url"); - } - if (hostAddr instanceof Inet6Address) { - throw new IllegalArgumentException("IPV6 addresses not supported (" + hostAddr.getHostAddress() + ")"); - } - } catch (UnknownHostException uhe) { - throw new IllegalArgumentException("Unable to resolve " + host); - } - - return uri.toString(); - } catch (URISyntaxException e) { - throw new IllegalArgumentException("Invalid URL " + url); - } - } - - @Override - public TemplateProfile prepare(RegisterIsoCmd cmd) throws ResourceAllocationException { - TemplateProfile profile = super.prepare(cmd); - String url = profile.getUrl(); - - if((!url.toLowerCase().endsWith("iso"))&&(!url.toLowerCase().endsWith("iso.zip"))&&(!url.toLowerCase().endsWith("iso.bz2")) - &&(!url.toLowerCase().endsWith("iso.gz"))){ - throw new InvalidParameterValueException("Please specify a valid iso"); - } - - profile.setUrl(validateUrl(url)); - return profile; - } - - @Override - public TemplateProfile prepare(RegisterTemplateCmd cmd) throws ResourceAllocationException { - TemplateProfile profile = super.prepare(cmd); - String url = profile.getUrl(); - - if((!url.toLowerCase().endsWith("vhd"))&&(!url.toLowerCase().endsWith("vhd.zip")) - &&(!url.toLowerCase().endsWith("vhd.bz2"))&&(!url.toLowerCase().endsWith("vhd.gz")) - &&(!url.toLowerCase().endsWith("qcow2"))&&(!url.toLowerCase().endsWith("qcow2.zip")) - &&(!url.toLowerCase().endsWith("qcow2.bz2"))&&(!url.toLowerCase().endsWith("qcow2.gz")) - &&(!url.toLowerCase().endsWith("ova"))&&(!url.toLowerCase().endsWith("ova.zip")) - &&(!url.toLowerCase().endsWith("ova.bz2"))&&(!url.toLowerCase().endsWith("ova.gz")) - &&(!url.toLowerCase().endsWith("img"))&&(!url.toLowerCase().endsWith("raw"))){ - throw new InvalidParameterValueException("Please specify a valid "+ cmd.getFormat().toLowerCase()); - } - - if ((cmd.getFormat().equalsIgnoreCase("vhd") && (!url.toLowerCase().endsWith("vhd") && !url.toLowerCase().endsWith("vhd.zip") && !url.toLowerCase().endsWith("vhd.bz2") && !url.toLowerCase().endsWith("vhd.gz") )) - || (cmd.getFormat().equalsIgnoreCase("qcow2") && (!url.toLowerCase().endsWith("qcow2") && !url.toLowerCase().endsWith("qcow2.zip") && !url.toLowerCase().endsWith("qcow2.bz2") && !url.toLowerCase().endsWith("qcow2.gz") )) - || (cmd.getFormat().equalsIgnoreCase("ova") && (!url.toLowerCase().endsWith("ova") && !url.toLowerCase().endsWith("ova.zip") && !url.toLowerCase().endsWith("ova.bz2") && !url.toLowerCase().endsWith("ova.gz"))) - || (cmd.getFormat().equalsIgnoreCase("raw") && (!url.toLowerCase().endsWith("img") && !url.toLowerCase().endsWith("raw")))) { - throw new InvalidParameterValueException("Please specify a valid URL. URL:" + url + " is an invalid for the format " + cmd.getFormat().toLowerCase()); - } - - profile.setUrl(validateUrl(url)); - return profile; - } - - @Override - public VMTemplateVO create(TemplateProfile profile) { - VMTemplateVO template = persistTemplate(profile); - - if (template == null) { - throw new CloudRuntimeException("Unable to persist the template " + profile.getTemplate()); - } - - _downloadMonitor.downloadTemplateToStorage(template, profile.getZoneId()); - _resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template); - - return template; - } - - @Override @DB - public boolean delete(TemplateProfile profile) { - boolean success = true; - - VMTemplateVO template = (VMTemplateVO)profile.getTemplate(); - Long zoneId = profile.getZoneId(); - Long templateId = template.getId(); - - String zoneName; - List<HostVO> secondaryStorageHosts; - if (!template.isCrossZones() && zoneId != null) { - DataCenterVO zone = _dcDao.findById(zoneId); - zoneName = zone.getName(); - secondaryStorageHosts = _ssvmMgr.listSecondaryStorageHostsInOneZone(zoneId); - } else { - zoneName = "(all zones)"; - secondaryStorageHosts = _ssvmMgr.listSecondaryStorageHostsInAllZones(); - } - - s_logger.debug("Attempting to mark template host refs for template: " + template.getName() + " as destroyed in zone: " + zoneName); - - // Make sure the template is downloaded to all the necessary secondary storage hosts - for (HostVO secondaryStorageHost : secondaryStorageHosts) { - long hostId = secondaryStorageHost.getId(); - List<VMTemplateHostVO> templateHostVOs = _tmpltHostDao.listByHostTemplate(hostId, templateId); - for (VMTemplateHostVO templateHostVO : templateHostVOs) { - if (templateHostVO.getDownloadState() == Status.DOWNLOAD_IN_PROGRESS) { - String errorMsg = "Please specify a template that is not currently being downloaded."; - s_logger.debug("Template: " + template.getName() + " is currently being downloaded to secondary storage host: " + secondaryStorageHost.getName() + "; cant' delete it."); - throw new CloudRuntimeException(errorMsg); - } - } - } - - Account account = _accountDao.findByIdIncludingRemoved(template.getAccountId()); - String eventType = ""; - - if (template.getFormat().equals(ImageFormat.ISO)){ - eventType = EventTypes.EVENT_ISO_DELETE; - } else { - eventType = EventTypes.EVENT_TEMPLATE_DELETE; - } - - // Iterate through all necessary secondary storage hosts and mark the template on each host as destroyed - for (HostVO secondaryStorageHost : secondaryStorageHosts) { - long hostId = secondaryStorageHost.getId(); - long sZoneId = secondaryStorageHost.getDataCenterId(); - List<VMTemplateHostVO> templateHostVOs = _tmpltHostDao.listByHostTemplate(hostId, templateId); - for (VMTemplateHostVO templateHostVO : templateHostVOs) { - VMTemplateHostVO lock = _tmpltHostDao.acquireInLockTable(templateHostVO.getId()); - try { - if (lock == null) { - s_logger.debug("Failed to acquire lock when deleting templateHostVO with ID: " + templateHostVO.getId()); - success = false; - break; - } - UsageEventUtils.publishUsageEvent(eventType, account.getId(), sZoneId, templateId, null, null, null); - templateHostVO.setDestroyed(true); - _tmpltHostDao.update(templateHostVO.getId(), templateHostVO); - String installPath = templateHostVO.getInstallPath(); - if (installPath != null) { - Answer answer = _agentMgr.sendToSecStorage(secondaryStorageHost, new DeleteTemplateCommand(secondaryStorageHost.getStorageUrl(), installPath)); - - if (answer == null || !answer.getResult()) { - s_logger.debug("Failed to delete " + templateHostVO + " due to " + ((answer == null) ? "answer is null" : answer.getDetails())); - } else { - _tmpltHostDao.remove(templateHostVO.getId()); - s_logger.debug("Deleted template at: " + installPath); - } - } else { - _tmpltHostDao.remove(templateHostVO.getId()); - } - VMTemplateZoneVO templateZone = _tmpltZoneDao.findByZoneTemplate(sZoneId, templateId); - - if (templateZone != null) { - _tmpltZoneDao.remove(templateZone.getId()); - } - } finally { - if (lock != null) { - _tmpltHostDao.releaseFromLockTable(lock.getId()); - } - } - } - - if (!success) { - break; - } - } - - s_logger.debug("Successfully marked template host refs for template: " + template.getName() + " as destroyed in zone: " + zoneName); - - // If there are no more non-destroyed template host entries for this template, delete it - if (success && (_tmpltHostDao.listByTemplateId(templateId).size() == 0)) { - long accountId = template.getAccountId(); - - VMTemplateVO lock = _tmpltDao.acquireInLockTable(templateId); - - try { - if (lock == null) { - s_logger.debug("Failed to acquire lock when deleting template with ID: " + templateId); - success = false; - } else if (_tmpltDao.remove(templateId)) { - // Decrement the number of templates - _resourceLimitMgr.decrementResourceCount(accountId, ResourceType.template); - } - - } finally { - if (lock != null) { - _tmpltDao.releaseFromLockTable(lock.getId()); - } - } - - s_logger.debug("Removed template: " + template.getName() + " because all of its template host refs were marked as destroyed."); - } - - return success; - } - - public TemplateProfile prepareDelete(DeleteTemplateCmd cmd) { - TemplateProfile profile = super.prepareDelete(cmd); - VMTemplateVO template = (VMTemplateVO)profile.getTemplate(); - Long zoneId = profile.getZoneId(); - - if (template.getTemplateType() == TemplateType.SYSTEM) { - throw new InvalidParameterValueException("The DomR template cannot be deleted."); - } - - if (zoneId != null && (_ssvmMgr.findSecondaryStorageHost(zoneId) == null)) { - throw new InvalidParameterValueException("Failed to find a secondary storage host in the specified zone."); - } - - return profile; - } - - public TemplateProfile prepareDelete(DeleteIsoCmd cmd) { - TemplateProfile profile = super.prepareDelete(cmd); - Long zoneId = profile.getZoneId(); - - if (zoneId != null && (_ssvmMgr.findSecondaryStorageHost(zoneId) == null)) { - throw new InvalidParameterValueException("Failed to find a secondary storage host in the specified zone."); - } - - return profile; - } -} http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c0442e25/server/src/com/cloud/template/HypervisorTemplateAdapter.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/template/HypervisorTemplateAdapter.java b/server/src/com/cloud/template/HypervisorTemplateAdapter.java new file mode 100755 index 0000000..b93d7e5 --- /dev/null +++ b/server/src/com/cloud/template/HypervisorTemplateAdapter.java @@ -0,0 +1,302 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.template; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.util.List; + +import javax.ejb.Local; +import javax.inject.Inject; + +import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; +import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.storage.DeleteTemplateCommand; +import com.cloud.configuration.Resource.ResourceType; +import com.cloud.dc.DataCenterVO; +import com.cloud.event.EventTypes; +import com.cloud.event.UsageEventUtils; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.host.HostVO; +import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.Storage.TemplateType; +import com.cloud.storage.VMTemplateHostVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; +import com.cloud.storage.TemplateProfile; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VMTemplateZoneVO; +import com.cloud.storage.download.DownloadMonitor; +import com.cloud.storage.secondary.SecondaryStorageVmManager; +import com.cloud.user.Account; +import com.cloud.utils.db.DB; +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; +import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; +import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; +import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; +import org.apache.log4j.Logger; + +import javax.ejb.Local; +import java.net.*; +import java.util.List; + +@Local(value=TemplateAdapter.class) +public class HypervisorTemplateAdapter extends TemplateAdapterBase implements TemplateAdapter { + private final static Logger s_logger = Logger.getLogger(HypervisorTemplateAdapter.class); + @Inject DownloadMonitor _downloadMonitor; + @Inject SecondaryStorageVmManager _ssvmMgr; + @Inject AgentManager _agentMgr; + + private String validateUrl(String url) { + try { + URI uri = new URI(url); + if ((uri.getScheme() == null) || (!uri.getScheme().equalsIgnoreCase("http") + && !uri.getScheme().equalsIgnoreCase("https") && !uri.getScheme().equalsIgnoreCase("file"))) { + throw new IllegalArgumentException("Unsupported scheme for url: " + url); + } + + int port = uri.getPort(); + if (!(port == 80 || port == 443 || port == -1)) { + throw new IllegalArgumentException("Only ports 80 and 443 are allowed"); + } + String host = uri.getHost(); + try { + InetAddress hostAddr = InetAddress.getByName(host); + if (hostAddr.isAnyLocalAddress() || hostAddr.isLinkLocalAddress() || hostAddr.isLoopbackAddress() || hostAddr.isMulticastAddress()) { + throw new IllegalArgumentException("Illegal host specified in url"); + } + if (hostAddr instanceof Inet6Address) { + throw new IllegalArgumentException("IPV6 addresses not supported (" + hostAddr.getHostAddress() + ")"); + } + } catch (UnknownHostException uhe) { + throw new IllegalArgumentException("Unable to resolve " + host); + } + + return uri.toString(); + } catch (URISyntaxException e) { + throw new IllegalArgumentException("Invalid URL " + url); + } + } + + @Override + public TemplateProfile prepare(RegisterIsoCmd cmd) throws ResourceAllocationException { + TemplateProfile profile = super.prepare(cmd); + String url = profile.getUrl(); + + if((!url.toLowerCase().endsWith("iso"))&&(!url.toLowerCase().endsWith("iso.zip"))&&(!url.toLowerCase().endsWith("iso.bz2")) + &&(!url.toLowerCase().endsWith("iso.gz"))){ + throw new InvalidParameterValueException("Please specify a valid iso"); + } + + profile.setUrl(validateUrl(url)); + return profile; + } + + @Override + public TemplateProfile prepare(RegisterTemplateCmd cmd) throws ResourceAllocationException { + TemplateProfile profile = super.prepare(cmd); + String url = profile.getUrl(); + + if((!url.toLowerCase().endsWith("vhd"))&&(!url.toLowerCase().endsWith("vhd.zip")) + &&(!url.toLowerCase().endsWith("vhd.bz2"))&&(!url.toLowerCase().endsWith("vhd.gz")) + &&(!url.toLowerCase().endsWith("qcow2"))&&(!url.toLowerCase().endsWith("qcow2.zip")) + &&(!url.toLowerCase().endsWith("qcow2.bz2"))&&(!url.toLowerCase().endsWith("qcow2.gz")) + &&(!url.toLowerCase().endsWith("ova"))&&(!url.toLowerCase().endsWith("ova.zip")) + &&(!url.toLowerCase().endsWith("ova.bz2"))&&(!url.toLowerCase().endsWith("ova.gz")) + &&(!url.toLowerCase().endsWith("img"))&&(!url.toLowerCase().endsWith("raw"))){ + throw new InvalidParameterValueException("Please specify a valid "+ cmd.getFormat().toLowerCase()); + } + + if ((cmd.getFormat().equalsIgnoreCase("vhd") && (!url.toLowerCase().endsWith("vhd") && !url.toLowerCase().endsWith("vhd.zip") && !url.toLowerCase().endsWith("vhd.bz2") && !url.toLowerCase().endsWith("vhd.gz") )) + || (cmd.getFormat().equalsIgnoreCase("qcow2") && (!url.toLowerCase().endsWith("qcow2") && !url.toLowerCase().endsWith("qcow2.zip") && !url.toLowerCase().endsWith("qcow2.bz2") && !url.toLowerCase().endsWith("qcow2.gz") )) + || (cmd.getFormat().equalsIgnoreCase("ova") && (!url.toLowerCase().endsWith("ova") && !url.toLowerCase().endsWith("ova.zip") && !url.toLowerCase().endsWith("ova.bz2") && !url.toLowerCase().endsWith("ova.gz"))) + || (cmd.getFormat().equalsIgnoreCase("raw") && (!url.toLowerCase().endsWith("img") && !url.toLowerCase().endsWith("raw")))) { + throw new InvalidParameterValueException("Please specify a valid URL. URL:" + url + " is an invalid for the format " + cmd.getFormat().toLowerCase()); + } + + profile.setUrl(validateUrl(url)); + return profile; + } + + @Override + public VMTemplateVO create(TemplateProfile profile) { + VMTemplateVO template = persistTemplate(profile); + + if (template == null) { + throw new CloudRuntimeException("Unable to persist the template " + profile.getTemplate()); + } + + _downloadMonitor.downloadTemplateToStorage(template, profile.getZoneId()); + _resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template); + + return template; + } + + @Override @DB + public boolean delete(TemplateProfile profile) { + boolean success = true; + + VMTemplateVO template = (VMTemplateVO)profile.getTemplate(); + Long zoneId = profile.getZoneId(); + Long templateId = template.getId(); + + String zoneName; + List<HostVO> secondaryStorageHosts; + if (!template.isCrossZones() && zoneId != null) { + DataCenterVO zone = _dcDao.findById(zoneId); + zoneName = zone.getName(); + secondaryStorageHosts = _ssvmMgr.listSecondaryStorageHostsInOneZone(zoneId); + } else { + zoneName = "(all zones)"; + secondaryStorageHosts = _ssvmMgr.listSecondaryStorageHostsInAllZones(); + } + + s_logger.debug("Attempting to mark template host refs for template: " + template.getName() + " as destroyed in zone: " + zoneName); + + // Make sure the template is downloaded to all the necessary secondary storage hosts + for (HostVO secondaryStorageHost : secondaryStorageHosts) { + long hostId = secondaryStorageHost.getId(); + List<VMTemplateHostVO> templateHostVOs = _tmpltHostDao.listByHostTemplate(hostId, templateId); + for (VMTemplateHostVO templateHostVO : templateHostVOs) { + if (templateHostVO.getDownloadState() == Status.DOWNLOAD_IN_PROGRESS) { + String errorMsg = "Please specify a template that is not currently being downloaded."; + s_logger.debug("Template: " + template.getName() + " is currently being downloaded to secondary storage host: " + secondaryStorageHost.getName() + "; cant' delete it."); + throw new CloudRuntimeException(errorMsg); + } + } + } + + Account account = _accountDao.findByIdIncludingRemoved(template.getAccountId()); + String eventType = ""; + + if (template.getFormat().equals(ImageFormat.ISO)){ + eventType = EventTypes.EVENT_ISO_DELETE; + } else { + eventType = EventTypes.EVENT_TEMPLATE_DELETE; + } + + // Iterate through all necessary secondary storage hosts and mark the template on each host as destroyed + for (HostVO secondaryStorageHost : secondaryStorageHosts) { + long hostId = secondaryStorageHost.getId(); + long sZoneId = secondaryStorageHost.getDataCenterId(); + List<VMTemplateHostVO> templateHostVOs = _tmpltHostDao.listByHostTemplate(hostId, templateId); + for (VMTemplateHostVO templateHostVO : templateHostVOs) { + VMTemplateHostVO lock = _tmpltHostDao.acquireInLockTable(templateHostVO.getId()); + try { + if (lock == null) { + s_logger.debug("Failed to acquire lock when deleting templateHostVO with ID: " + templateHostVO.getId()); + success = false; + break; + } + UsageEventUtils.publishUsageEvent(eventType, account.getId(), sZoneId, templateId, null, null, null); + templateHostVO.setDestroyed(true); + _tmpltHostDao.update(templateHostVO.getId(), templateHostVO); + String installPath = templateHostVO.getInstallPath(); + if (installPath != null) { + Answer answer = _agentMgr.sendToSecStorage(secondaryStorageHost, new DeleteTemplateCommand(secondaryStorageHost.getStorageUrl(), installPath)); + + if (answer == null || !answer.getResult()) { + s_logger.debug("Failed to delete " + templateHostVO + " due to " + ((answer == null) ? "answer is null" : answer.getDetails())); + } else { + _tmpltHostDao.remove(templateHostVO.getId()); + s_logger.debug("Deleted template at: " + installPath); + } + } else { + _tmpltHostDao.remove(templateHostVO.getId()); + } + VMTemplateZoneVO templateZone = _tmpltZoneDao.findByZoneTemplate(sZoneId, templateId); + + if (templateZone != null) { + _tmpltZoneDao.remove(templateZone.getId()); + } + } finally { + if (lock != null) { + _tmpltHostDao.releaseFromLockTable(lock.getId()); + } + } + } + + if (!success) { + break; + } + } + + s_logger.debug("Successfully marked template host refs for template: " + template.getName() + " as destroyed in zone: " + zoneName); + + // If there are no more non-destroyed template host entries for this template, delete it + if (success && (_tmpltHostDao.listByTemplateId(templateId).size() == 0)) { + long accountId = template.getAccountId(); + + VMTemplateVO lock = _tmpltDao.acquireInLockTable(templateId); + + try { + if (lock == null) { + s_logger.debug("Failed to acquire lock when deleting template with ID: " + templateId); + success = false; + } else if (_tmpltDao.remove(templateId)) { + // Decrement the number of templates + _resourceLimitMgr.decrementResourceCount(accountId, ResourceType.template); + } + + } finally { + if (lock != null) { + _tmpltDao.releaseFromLockTable(lock.getId()); + } + } + + s_logger.debug("Removed template: " + template.getName() + " because all of its template host refs were marked as destroyed."); + } + + return success; + } + + public TemplateProfile prepareDelete(DeleteTemplateCmd cmd) { + TemplateProfile profile = super.prepareDelete(cmd); + VMTemplateVO template = (VMTemplateVO)profile.getTemplate(); + Long zoneId = profile.getZoneId(); + + if (template.getTemplateType() == TemplateType.SYSTEM) { + throw new InvalidParameterValueException("The DomR template cannot be deleted."); + } + + if (zoneId != null && (_ssvmMgr.findSecondaryStorageHost(zoneId) == null)) { + throw new InvalidParameterValueException("Failed to find a secondary storage host in the specified zone."); + } + + return profile; + } + + public TemplateProfile prepareDelete(DeleteIsoCmd cmd) { + TemplateProfile profile = super.prepareDelete(cmd); + Long zoneId = profile.getZoneId(); + + if (zoneId != null && (_ssvmMgr.findSecondaryStorageHost(zoneId) == null)) { + throw new InvalidParameterValueException("Failed to find a secondary storage host in the specified zone."); + } + + return profile; + } +}
