package org.ovirt.engine.core.vdsbroker.irsbroker; import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpMethodBase; import org.codehaus.jackson.map.ObjectMapper; import org.ovirt.engine.core.common.asynctasks.AsyncTaskCreationInfo; import org.ovirt.engine.core.common.asynctasks.AsyncTaskType; import org.ovirt.engine.core.common.businessentities.VdsStatic; import org.ovirt.engine.core.common.config.Config; import org.ovirt.engine.core.common.config.ConfigValues; import org.ovirt.engine.core.common.errors.EngineError; import org.ovirt.engine.core.common.errors.VDSError; import org.ovirt.engine.core.common.utils.Pair; import org.ovirt.engine.core.common.vdscommands.ImageHttpAccessVDSCommandParameters; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.utils.threadpool.ThreadPoolUtil; import org.ovirt.engine.core.vdsbroker.HttpUtils; import org.ovirt.engine.core.vdsbroker.VdsManager; import org.ovirt.engine.core.vdsbroker.vdsbroker.StatusOnlyReturn; import org.ovirt.engine.core.vdsbroker.vdsbroker.VDSErrorException; import org.ovirt.engine.core.vdsbroker.vdsbroker.VdsBrokerCommand; public abstract class HttpImageTaskVDSCommand<T extends HttpMethodBase, P extends ImageHttpAccessVDSCommandParameters> extends VdsBrokerCommand<P> { private T method; public HttpImageTaskVDSCommand(P parameters) { super(parameters); } @Override protected void executeVdsBrokerCommand() { logExecution(); prepareMethod(); addHeaders(); try { executeHttpMethod(getMethod()); } finally { try { getMethod().releaseConnection(); } catch (RuntimeException releaseException) { log.error("failed when attempting to release connection", releaseException); } } } private void addHeaders() { getMethod().setRequestHeader("connection", "close"); getMethod().setRequestHeader("Storage-Pool-Id", getParameters().getStoragePoolId().toString()); getMethod().setRequestHeader("Storage-Domain-Id", getParameters().getStorageDomainId().toString()); getMethod().setRequestHeader("Image-Id", getParameters().getImageGroupId().toString()); getMethod().setRequestHeader("Volume-Id", getParameters().getImageId().toString()); } protected void executeHttpMethod(final T method) { int responseCode = -1; VdsManager manager = resourceManager.getVdsManager(getParameters().getVdsId()); final HttpClient httpclient = manager.getVdsProxy().getHttpClient(); try { FutureTask<Integer> futureTask = new FutureTask(() -> httpclient.executeMethod(method)); Future<Integer> f = ThreadPoolUtil.execute(futureTask); if (f.get(Config.<Integer>getValue(getConfigValueTimeLimitForOperation()), TimeUnit.MINUTES) == null) { responseCode = futureTask.get(); } } catch (InterruptedException e) { throw new RuntimeException(e); } catch (Exception e) { log.debug("Exception", e); throw createNetworkException(e); } if (responseCode == getSuccessCode()) { Guid createdTask = Guid.createGuidFromString(processResponseHeaderValue(getMethod(), "Task-Id", null)); getVDSReturnValue().setCreationInfo( new AsyncTaskCreationInfo(createdTask, getCreatedTaskType(), getParameters() .getStoragePoolId())); handleOkResponse(); getVDSReturnValue().setSucceeded(true); return; } processResponseHeaderValue(getMethod(), "Content-type", "application/json"); String response; try { response = getMethod().getResponseBodyAsString(); } catch (Exception e) { throw createNetworkException(e); } Map<String, Object> resultMap = null; try { resultMap = new ObjectMapper().readValue(response, HashMap.class); status = new StatusOnlyReturn(resultMap); } catch (Exception e) { throwVdsErrorException("failed to parse response " + response, EngineError.GeneralException); } proceedProxyReturnValue(); } protected void handleOkResponse() {} protected String processResponseHeaderValue(HttpMethodBase method, String headerName, String expectedValue) { Header header = method.getResponseHeader(headerName); if (header == null) { throwVdsErrorException("response was missing the following header: " + headerName, EngineError.GeneralException); } if (expectedValue != null && !expectedValue.equals(header.getValue())) { throwVdsErrorException("response header value unexpected for header: " + headerName, EngineError.GeneralException); } return header.getValue(); } protected T getMethod() { if (method == null) { VdsStatic vdsStatic = getAndSetVdsStatic(); Pair<String, URL> urlInfo = HttpUtils.getConnectionUrl(vdsStatic.getHostName(), vdsStatic.getPort(), "", Config.getValue(ConfigValues.EncryptHostCommunication)); method = concreteCreateMethod(urlInfo.getFirst()); } return method; } private void logExecution() { log.info("-- executeVdsBrokerCommand, parameters:"); log.info("++ spUUID={}", getParameters().getStoragePoolId()); log.info("++ sdUUID={}", getParameters().getStorageDomainId()); log.info("++ imageGUID={}", getParameters().getImageGroupId()); log.info("++ volUUID={}", getParameters().getImageId()); log.info("++ size={}", getParameters().getSize()); } protected void throwVdsErrorException(String message, EngineError error) { VDSErrorException outEx = new VDSErrorException(message); VDSError vdsError = new VDSError(); vdsError.setCode(error); vdsError.setMessage(message); outEx.setVdsError(vdsError); throw outEx; } protected void prepareMethod() {} protected abstract ConfigValues getConfigValueTimeLimitForOperation(); protected abstract AsyncTaskType getCreatedTaskType(); protected abstract T concreteCreateMethod(String url); protected abstract int getSuccessCode(); }