Refactor and fix upload certificate error message even though operation is successful

This commit is contained in:
nvazquez 2018-02-08 11:26:35 -03:00 committed by Daan Hoogland
parent d39664a382
commit 1c71a9b867
3 changed files with 142 additions and 117 deletions

View File

@ -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();
}
}

View File

@ -27,5 +27,5 @@ public interface DirectDownloadService {
/**
* Upload client certificate to each running host
*/
boolean uploadCertificateToHosts(String certificateCer, String certificateName);
}
boolean uploadCertificateToHosts(String certificateCer, String certificateName, String hypervisor);
}

View File

@ -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.<br/>
* 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<HostVO> hostsQuery = hostDao.listAllHostsByType(Host.Type.Routing);
List<HostVO> 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<HostVO> getRunningHostsToUploadCertificate(HypervisorType hypervisorType) {
List<HostVO> 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<HostVO> 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;