diff --git a/api/src/org/apache/cloudstack/api/command/admin/direct/download/UploadTemplateDirectDownloadCertificate.java b/api/src/org/apache/cloudstack/api/command/admin/direct/download/UploadTemplateDirectDownloadCertificate.java
index eaac77f590a..227a7ca674c 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/direct/download/UploadTemplateDirectDownloadCertificate.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/direct/download/UploadTemplateDirectDownloadCertificate.java
@@ -1,88 +1,90 @@
-// 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 org.apache.cloudstack.api.command.admin.direct.download;
-
-import com.cloud.exception.ConcurrentOperationException;
-import com.cloud.exception.InsufficientCapacityException;
-import com.cloud.exception.ResourceAllocationException;
-import com.cloud.exception.ResourceUnavailableException;
-import com.cloud.exception.NetworkRuleConflictException;
-import org.apache.cloudstack.acl.RoleType;
-import org.apache.cloudstack.api.APICommand;
-import org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.api.BaseCmd;
-import org.apache.cloudstack.api.Parameter;
-import org.apache.cloudstack.api.ServerApiException;
-import org.apache.cloudstack.api.ApiErrorCode;
-import org.apache.cloudstack.api.response.SuccessResponse;
-import org.apache.cloudstack.context.CallContext;
-import org.apache.cloudstack.direct.download.DirectDownloadManager;
-import org.apache.log4j.Logger;
-
-import javax.inject.Inject;
-
-@APICommand(name = UploadTemplateDirectDownloadCertificate.APINAME,
- description = "Upload a certificate for HTTPS direct template download on KVM hosts",
- responseObject = SuccessResponse.class,
- requestHasSensitiveInfo = true,
- responseHasSensitiveInfo = true,
- since = "4.11.0",
- authorized = {RoleType.Admin})
-public class UploadTemplateDirectDownloadCertificate extends BaseCmd {
-
- @Inject
- DirectDownloadManager directDownloadManager;
-
- private static final Logger LOG = Logger.getLogger(UploadTemplateDirectDownloadCertificate.class);
- public static final String APINAME = "uploadTemplateDirectDownloadCertificate";
-
- @Parameter(name = ApiConstants.CERTIFICATE, type = BaseCmd.CommandType.STRING, required = true, length = 65535,
- description = "SSL certificate")
- private String certificate;
-
- @Parameter(name = ApiConstants.NAME , type = BaseCmd.CommandType.STRING, required = true,
- description = "Name for the uploaded certificate")
- private String name;
-
- @Parameter(name = ApiConstants.HYPERVISOR, type = BaseCmd.CommandType.STRING, required = true, description = "Hypervisor type")
- private String hypervisor;
-
- @Override
- public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
- if (!hypervisor.equalsIgnoreCase("kvm")) {
- throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Currently supporting KVM hosts only");
- }
-
- try {
- directDownloadManager.uploadCertificateToHosts(certificate, name);;
- setResponseObject(new SuccessResponse(getCommandName()));
- } catch (Exception e) {
- throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
- }
- }
-
- @Override
- public String getCommandName() {
- return UploadTemplateDirectDownloadCertificate.APINAME;
- }
-
- @Override
- public long getEntityOwnerId() {
- return CallContext.current().getCallingAccount().getId();
- }
-}
-
+// 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 org.apache.cloudstack.api.command.admin.direct.download;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.exception.NetworkRuleConflictException;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.direct.download.DirectDownloadManager;
+import org.apache.log4j.Logger;
+
+import javax.inject.Inject;
+
+@APICommand(name = UploadTemplateDirectDownloadCertificate.APINAME,
+ description = "Upload a certificate for HTTPS direct template download on KVM hosts",
+ responseObject = SuccessResponse.class,
+ requestHasSensitiveInfo = true,
+ responseHasSensitiveInfo = true,
+ since = "4.11.0",
+ authorized = {RoleType.Admin})
+public class UploadTemplateDirectDownloadCertificate extends BaseCmd {
+
+ @Inject
+ DirectDownloadManager directDownloadManager;
+
+ private static final Logger LOG = Logger.getLogger(UploadTemplateDirectDownloadCertificate.class);
+ public static final String APINAME = "uploadTemplateDirectDownloadCertificate";
+
+ @Parameter(name = ApiConstants.CERTIFICATE, type = BaseCmd.CommandType.STRING, required = true, length = 65535,
+ description = "SSL certificate")
+ private String certificate;
+
+ @Parameter(name = ApiConstants.NAME , type = BaseCmd.CommandType.STRING, required = true,
+ description = "Name for the uploaded certificate")
+ private String name;
+
+ @Parameter(name = ApiConstants.HYPERVISOR, type = BaseCmd.CommandType.STRING, required = true, description = "Hypervisor type")
+ private String hypervisor;
+
+ @Override
+ public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
+ if (!hypervisor.equalsIgnoreCase("kvm")) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Currently supporting KVM hosts only");
+ }
+
+ SuccessResponse response = new SuccessResponse(getCommandName());
+ try {
+ LOG.debug("Uploading certificate " + name + " to agents for Direct Download");
+ boolean result = directDownloadManager.uploadCertificateToHosts(certificate, name, hypervisor);
+ response.setSuccess(result);
+ setResponseObject(response);
+ } catch (Exception e) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
+ }
+ }
+
+ @Override
+ public String getCommandName() {
+ return UploadTemplateDirectDownloadCertificate.APINAME;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return CallContext.current().getCallingAccount().getId();
+ }
+}
diff --git a/framework/direct-download/src/org/apache/cloudstack/framework/agent/direct/download/DirectDownloadService.java b/framework/direct-download/src/org/apache/cloudstack/framework/agent/direct/download/DirectDownloadService.java
index 6e2af68692c..f3153e3470e 100644
--- a/framework/direct-download/src/org/apache/cloudstack/framework/agent/direct/download/DirectDownloadService.java
+++ b/framework/direct-download/src/org/apache/cloudstack/framework/agent/direct/download/DirectDownloadService.java
@@ -27,5 +27,5 @@ public interface DirectDownloadService {
/**
* Upload client certificate to each running host
*/
- boolean uploadCertificateToHosts(String certificateCer, String certificateName);
-}
\ No newline at end of file
+ boolean uploadCertificateToHosts(String certificateCer, String certificateName, String hypervisor);
+}
diff --git a/server/src/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java b/server/src/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java
index 40aba6f2bfe..a40cf2c1027 100644
--- a/server/src/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java
+++ b/server/src/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java
@@ -214,22 +214,7 @@ public class DirectDownloadManagerImpl extends ManagerBase implements DirectDown
DownloadProtocol protocol = getProtocolFromUrl(url);
DirectDownloadCommand cmd = getDirectDownloadCommandFromProtocol(protocol, url, templateId, to, checksum, headers);
- boolean downloaded = false;
- int retry = 3;
- Long[] hostsToRetry = getHostsToRetryOn(host.getClusterId(), host.getDataCenterId(), host.getHypervisorType(), hostId);
- int hostIndex = 0;
- Answer answer = null;
- Long hostToSendDownloadCmd = hostsToRetry[hostIndex];
- while (!downloaded && retry > 0) {
- s_logger.debug("Sending Direct download command to host " + hostToSendDownloadCmd);
- answer = agentManager.easySend(hostToSendDownloadCmd, cmd);
- downloaded = answer != null && answer.getResult();
- hostToSendDownloadCmd = hostsToRetry[(hostIndex + 1) % hostsToRetry.length];
- retry --;
- }
- if (!downloaded) {
- throw new CloudRuntimeException("Template " + templateId + " could not be downloaded on pool " + poolId + ", failing after trying on several hosts");
- }
+ Answer answer = sendDirectDownloadCommand(cmd, templateId, poolId, host);
VMTemplateStoragePoolVO sPoolRef = vmTemplatePoolDao.findByPoolTemplate(poolId, templateId);
if (sPoolRef == null) {
@@ -248,6 +233,35 @@ public class DirectDownloadManagerImpl extends ManagerBase implements DirectDown
}
}
+ /**
+ * Send direct download command for downloading template with ID templateId on storage pool with ID poolId.
+ * At first, cmd is sent to host, in case of failure it will retry on other hosts before failing
+ * @param cmd direct download command
+ * @param templateId template id
+ * @param poolId pool id
+ * @param host first host to which send the command
+ * @return download answer from any host which could handle cmd
+ */
+ private Answer sendDirectDownloadCommand(DirectDownloadCommand cmd, long templateId, long poolId, HostVO host) {
+ boolean downloaded = false;
+ int retry = 3;
+ Long[] hostsToRetry = getHostsToRetryOn(host.getClusterId(), host.getDataCenterId(), host.getHypervisorType(), host.getId());
+ int hostIndex = 0;
+ Answer answer = null;
+ Long hostToSendDownloadCmd = hostsToRetry[hostIndex];
+ while (!downloaded && retry > 0) {
+ s_logger.debug("Sending Direct download command to host " + hostToSendDownloadCmd);
+ answer = agentManager.easySend(hostToSendDownloadCmd, cmd);
+ downloaded = answer != null && answer.getResult();
+ hostToSendDownloadCmd = hostsToRetry[(hostIndex + 1) % hostsToRetry.length];
+ retry --;
+ }
+ if (!downloaded) {
+ throw new CloudRuntimeException("Template " + templateId + " could not be downloaded on pool " + poolId + ", failing after trying on several hosts");
+ }
+ return answer;
+ }
+
/**
* Return DirectDownloadCommand according to the protocol
* @param protocol
@@ -271,19 +285,28 @@ public class DirectDownloadManagerImpl extends ManagerBase implements DirectDown
}
}
- @Override
- public boolean uploadCertificateToHosts(String certificateCer, String certificateName) {
- List hostsQuery = hostDao.listAllHostsByType(Host.Type.Routing);
- List hosts = new ArrayList<>();
- for (HostVO host: hostsQuery) {
- if (host.getStatus().equals(Status.Up) &&
- host.getHypervisorType().equals(HypervisorType.KVM)) {
- hosts.add(host);
+ /**
+ * Return the list of running hosts to which upload certificates for Direct Download
+ */
+ private List getRunningHostsToUploadCertificate(HypervisorType hypervisorType) {
+ List resultingHosts = new ArrayList<>();
+ for (HostVO host : hostDao.listAllHostsByType(Host.Type.Routing)) {
+ if(host.getStatus().equals(Status.Up) && host.getHypervisorType().equals(hypervisorType)) {
+ resultingHosts.add(host);
}
}
- for (HostVO host : hosts) {
- if (!uploadCertificate(certificateCer, certificateName, host.getId())) {
- throw new CloudRuntimeException("Uploading certificate " + certificateName + " failed on host: " + host.getId());
+ return resultingHosts;
+ }
+
+ @Override
+ public boolean uploadCertificateToHosts(String certificateCer, String certificateName, String hypervisor) {
+ HypervisorType hypervisorType = HypervisorType.getType(hypervisor);
+ List hosts = getRunningHostsToUploadCertificate(hypervisorType);
+ if (CollectionUtils.isNotEmpty(hosts)) {
+ for (HostVO host : hosts) {
+ if (!uploadCertificate(certificateCer, certificateName, host.getId())) {
+ throw new CloudRuntimeException("Uploading certificate " + certificateName + " failed on host: " + host.getId());
+ }
}
}
return true;