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;