This is an automated email from the ASF dual-hosted git repository.
shwstppr pushed a commit to branch 4.18
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.18 by this push:
new ff3e9bd821f engine-storage: control download redirection
ff3e9bd821f is described below
commit ff3e9bd821f9d3e528b092fa31f338a73d2afc54
Author: Abhishek Kumar <[email protected]>
AuthorDate: Tue Mar 26 11:36:01 2024 +0530
engine-storage: control download redirection
Add a global setting to control whether redirection is allowed while
downloading templates and volumes
Signed-off-by: Abhishek Kumar <[email protected]>
---
.../storage/template/HttpTemplateDownloader.java | 18 +++++++-
.../template/MetalinkTemplateDownloader.java | 10 ++++-
.../storage/template/S3TemplateDownloader.java | 19 +++++++--
.../cloud/storage/template/TemplateDownloader.java | 2 +
.../storage/template/TemplateDownloaderBase.java | 6 +++
.../agent/directdownload/CheckUrlCommand.java | 11 ++++-
.../directdownload/DirectDownloadCommand.java | 15 ++++++-
.../directdownload/HttpDirectDownloadCommand.java | 6 ++-
.../directdownload/HttpsDirectDownloadCommand.java | 7 +++-
.../MetalinkDirectDownloadCommand.java | 5 ++-
.../directdownload/NfsDirectDownloadCommand.java | 5 ++-
.../direct/download/DirectDownloadHelper.java | 49 ++++++++++++----------
.../download/DirectTemplateDownloaderImpl.java | 13 +++++-
.../download/HttpDirectTemplateDownloader.java | 22 ++++++----
.../download/HttpsDirectTemplateDownloader.java | 28 +++++++++----
.../download/MetalinkDirectTemplateDownloader.java | 21 +++++-----
.../download/NfsDirectTemplateDownloader.java | 5 ++-
.../storage/command/DownloadCommand.java | 13 ++++++
.../storage/to/DownloadableObjectTO.java | 22 ++++------
.../cloudstack/storage/to/SnapshotObjectTO.java | 2 +-
.../cloudstack/storage/to/TemplateObjectTO.java | 3 +-
.../cloudstack/storage/to/VolumeObjectTO.java | 3 +-
.../download/BaseDirectTemplateDownloaderTest.java | 2 +-
.../MetalinkDirectTemplateDownloaderTest.java | 2 +-
.../api/storage/DownloadableDataInfo.java | 20 +++------
.../engine/subsystem/api/storage/TemplateInfo.java | 2 +-
.../engine/subsystem/api/storage/VolumeInfo.java | 2 +-
.../java/com/cloud/storage/StorageManager.java | 4 ++
.../storage/image/TemplateServiceImpl.java | 5 ++-
.../storage/image/store/TemplateObject.java | 8 ++++
.../cloudstack/storage/volume/VolumeObject.java | 8 ++++
.../cloudstack/framework/config/ConfigDepot.java | 1 +
.../framework/config/impl/ConfigDepotImpl.java | 7 ++++
.../framework/config/impl/ConfigDepotImplTest.java | 17 ++++++++
.../resource/wrapper/LibvirtCheckUrlCommand.java | 5 ++-
.../kvm/storage/KVMStorageProcessor.java | 2 +-
.../java/com/cloud/storage/StorageManagerImpl.java | 29 ++++++++++++-
.../com/cloud/storage/VolumeApiServiceImpl.java | 9 ++--
.../cloud/template/HypervisorTemplateAdapter.java | 23 +++++++---
.../direct/download/DirectDownloadManagerImpl.java | 17 +++++---
.../com/cloud/storage/StorageManagerImplTest.java | 41 ++++++++++++++++++
.../storage/template/DownloadManager.java | 18 ++++----
.../storage/template/DownloadManagerImpl.java | 25 +++++++----
utils/src/main/java/com/cloud/utils/UriUtils.java | 3 +-
.../java/com/cloud/utils/storage/QCOW2Utils.java | 21 ++++++----
45 files changed, 408 insertions(+), 148 deletions(-)
diff --git
a/core/src/main/java/com/cloud/storage/template/HttpTemplateDownloader.java
b/core/src/main/java/com/cloud/storage/template/HttpTemplateDownloader.java
index 2e331cab227..25f177eb5ff 100755
--- a/core/src/main/java/com/cloud/storage/template/HttpTemplateDownloader.java
+++ b/core/src/main/java/com/cloud/storage/template/HttpTemplateDownloader.java
@@ -26,6 +26,7 @@ import java.io.RandomAccessFile;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Date;
+import java.util.List;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
@@ -81,6 +82,7 @@ public class HttpTemplateDownloader extends
ManagedContextRunnable implements Te
private long maxTemplateSizeInBytes;
private ResourceType resourceType = ResourceType.TEMPLATE;
private final HttpMethodRetryHandler myretryhandler;
+ private boolean followRedirects = false;
public HttpTemplateDownloader(StorageLayer storageLayer, String
downloadUrl, String toDir, DownloadCompleteCallback callback, long
maxTemplateSizeInBytes,
String user, String password, Proxy proxy, ResourceType
resourceType) {
@@ -112,7 +114,7 @@ public class HttpTemplateDownloader extends
ManagedContextRunnable implements Te
private GetMethod createRequest(String downloadUrl) {
GetMethod request = new GetMethod(downloadUrl);
request.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
myretryhandler);
- request.setFollowRedirects(true);
+ request.setFollowRedirects(followRedirects);
return request;
}
@@ -336,6 +338,12 @@ public class HttpTemplateDownloader extends
ManagedContextRunnable implements Te
} else if ((responseCode = client.executeMethod(request)) !=
HttpStatus.SC_OK) {
status = Status.UNRECOVERABLE_ERROR;
errorString = " HTTP Server returned " + responseCode + "
(expected 200 OK) ";
+ if (List.of(HttpStatus.SC_MOVED_PERMANENTLY,
HttpStatus.SC_MOVED_TEMPORARILY).contains(responseCode)
+ && !followRedirects) {
+ errorString = String.format("Failed to download %s due to
redirection, response code: %d",
+ downloadUrl, responseCode);
+ s_logger.error(errorString);
+ }
return true; //FIXME: retry?
}
return false;
@@ -537,4 +545,12 @@ public class HttpTemplateDownloader extends
ManagedContextRunnable implements Te
return this;
}
}
+
+ @Override
+ public void setFollowRedirects(boolean followRedirects) {
+ this.followRedirects = followRedirects;
+ if (this.request != null) {
+ this.request.setFollowRedirects(followRedirects);
+ }
+ }
}
diff --git
a/core/src/main/java/com/cloud/storage/template/MetalinkTemplateDownloader.java
b/core/src/main/java/com/cloud/storage/template/MetalinkTemplateDownloader.java
index dd452f2e2d9..a118a9ac40f 100644
---
a/core/src/main/java/com/cloud/storage/template/MetalinkTemplateDownloader.java
+++
b/core/src/main/java/com/cloud/storage/template/MetalinkTemplateDownloader.java
@@ -60,7 +60,7 @@ public class MetalinkTemplateDownloader extends
TemplateDownloaderBase implement
protected GetMethod createRequest(String downloadUrl) {
GetMethod request = new GetMethod(downloadUrl);
request.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
myretryhandler);
- request.setFollowRedirects(true);
+ request.setFollowRedirects(followRedirects);
if (!toFileSet) {
String[] parts = downloadUrl.split("/");
String filename = parts[parts.length - 1];
@@ -173,4 +173,12 @@ public class MetalinkTemplateDownloader extends
TemplateDownloaderBase implement
public void setStatus(Status status) {
this.status = status;
}
+
+ @Override
+ public void setFollowRedirects(boolean followRedirects) {
+ super.setFollowRedirects(followRedirects);
+ if (this.request != null) {
+ this.request.setFollowRedirects(followRedirects);
+ }
+ }
}
diff --git
a/core/src/main/java/com/cloud/storage/template/S3TemplateDownloader.java
b/core/src/main/java/com/cloud/storage/template/S3TemplateDownloader.java
index 44565c4416c..a259e79fa42 100644
--- a/core/src/main/java/com/cloud/storage/template/S3TemplateDownloader.java
+++ b/core/src/main/java/com/cloud/storage/template/S3TemplateDownloader.java
@@ -34,6 +34,7 @@ import
org.apache.cloudstack.managed.context.ManagedContextRunnable;
import org.apache.cloudstack.storage.command.DownloadCommand.ResourceType;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
@@ -44,6 +45,7 @@ import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
+import java.util.List;
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
import static java.util.Arrays.asList;
@@ -72,8 +74,8 @@ public class S3TemplateDownloader extends
ManagedContextRunnable implements Temp
private long downloadTime;
private long totalBytes;
private long maxTemplateSizeInByte;
-
private boolean resume = false;
+ private boolean followRedirects = false;
public S3TemplateDownloader(S3TO s3TO, String downloadUrl, String
installPath, DownloadCompleteCallback downloadCompleteCallback,
long maxTemplateSizeInBytes, String username, String password,
Proxy proxy, ResourceType resourceType) {
@@ -91,7 +93,7 @@ public class S3TemplateDownloader extends
ManagedContextRunnable implements Temp
this.getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
HTTPUtils.getHttpMethodRetryHandler(5));
// Follow redirects
- this.getMethod.setFollowRedirects(true);
+ this.getMethod.setFollowRedirects(followRedirects);
// Set file extension.
this.fileExtension =
StringUtils.substringAfterLast(StringUtils.substringAfterLast(downloadUrl,
"/"), ".");
@@ -124,10 +126,11 @@ public class S3TemplateDownloader extends
ManagedContextRunnable implements Temp
return 0;
}
- if (!HTTPUtils.verifyResponseCode(responseCode)) {
+ boolean failedDueToRedirection =
List.of(HttpStatus.SC_MOVED_PERMANENTLY,
+ HttpStatus.SC_MOVED_TEMPORARILY).contains(responseCode) &&
!followRedirects;
+ if (!HTTPUtils.verifyResponseCode(responseCode) ||
failedDueToRedirection) {
errorString = "Response code for GetMethod of " + downloadUrl + "
is incorrect, responseCode: " + responseCode;
LOGGER.warn(errorString);
-
status = Status.UNRECOVERABLE_ERROR;
return 0;
}
@@ -373,4 +376,12 @@ public class S3TemplateDownloader extends
ManagedContextRunnable implements Temp
public String getFileExtension() {
return fileExtension;
}
+
+ @Override
+ public void setFollowRedirects(boolean followRedirects) {
+ this.followRedirects = followRedirects;
+ if (this.getMethod != null) {
+ this.getMethod.setFollowRedirects(followRedirects);
+ }
+ }
}
diff --git
a/core/src/main/java/com/cloud/storage/template/TemplateDownloader.java
b/core/src/main/java/com/cloud/storage/template/TemplateDownloader.java
index 5db3d2425a5..9fb1ca42442 100644
--- a/core/src/main/java/com/cloud/storage/template/TemplateDownloader.java
+++ b/core/src/main/java/com/cloud/storage/template/TemplateDownloader.java
@@ -92,4 +92,6 @@ public interface TemplateDownloader extends Runnable {
boolean isInited();
long getMaxTemplateSizeInBytes();
+
+ void setFollowRedirects(boolean followRedirects);
}
diff --git
a/core/src/main/java/com/cloud/storage/template/TemplateDownloaderBase.java
b/core/src/main/java/com/cloud/storage/template/TemplateDownloaderBase.java
index f56e4911ca7..66058bbf82e 100644
--- a/core/src/main/java/com/cloud/storage/template/TemplateDownloaderBase.java
+++ b/core/src/main/java/com/cloud/storage/template/TemplateDownloaderBase.java
@@ -43,6 +43,7 @@ public abstract class TemplateDownloaderBase extends
ManagedContextRunnable impl
protected long _start;
protected StorageLayer _storage;
protected boolean _inited = false;
+ protected boolean followRedirects = false;
private long maxTemplateSizeInBytes;
public TemplateDownloaderBase(StorageLayer storage, String downloadUrl,
String toDir, long maxTemplateSizeInBytes, DownloadCompleteCallback callback) {
@@ -149,4 +150,9 @@ public abstract class TemplateDownloaderBase extends
ManagedContextRunnable impl
public boolean isInited() {
return _inited;
}
+
+ @Override
+ public void setFollowRedirects(boolean followRedirects) {
+ this.followRedirects = followRedirects;
+ }
}
diff --git
a/core/src/main/java/org/apache/cloudstack/agent/directdownload/CheckUrlCommand.java
b/core/src/main/java/org/apache/cloudstack/agent/directdownload/CheckUrlCommand.java
index b1b76da8211..fe941b32ee3 100644
---
a/core/src/main/java/org/apache/cloudstack/agent/directdownload/CheckUrlCommand.java
+++
b/core/src/main/java/org/apache/cloudstack/agent/directdownload/CheckUrlCommand.java
@@ -28,6 +28,7 @@ public class CheckUrlCommand extends Command {
private Integer connectTimeout;
private Integer connectionRequestTimeout;
private Integer socketTimeout;
+ private boolean followRedirects;
public String getFormat() {
return format;
@@ -43,13 +44,19 @@ public class CheckUrlCommand extends Command {
public Integer getSocketTimeout() { return socketTimeout; }
- public CheckUrlCommand(final String format,final String url) {
+ public boolean isFollowRedirects() {
+ return followRedirects;
+ }
+
+ public CheckUrlCommand(final String format, final String url, final
boolean followRedirects) {
super();
this.format = format;
this.url = url;
+ this.followRedirects = followRedirects;
}
- public CheckUrlCommand(final String format,final String url, Integer
connectTimeout, Integer connectionRequestTimeout, Integer socketTimeout) {
+ public CheckUrlCommand(final String format,final String url, Integer
connectTimeout,
+ Integer connectionRequestTimeout, Integer socketTimeout, final
boolean followRedirects) {
super();
this.format = format;
this.url = url;
diff --git
a/core/src/main/java/org/apache/cloudstack/agent/directdownload/DirectDownloadCommand.java
b/core/src/main/java/org/apache/cloudstack/agent/directdownload/DirectDownloadCommand.java
index 7e1ff0b34c4..b6748dca434 100644
---
a/core/src/main/java/org/apache/cloudstack/agent/directdownload/DirectDownloadCommand.java
+++
b/core/src/main/java/org/apache/cloudstack/agent/directdownload/DirectDownloadCommand.java
@@ -45,7 +45,11 @@ public abstract class DirectDownloadCommand extends
StorageSubSystemCommand {
private Long templateSize;
private Storage.ImageFormat format;
- protected DirectDownloadCommand (final String url, final Long templateId,
final PrimaryDataStoreTO destPool, final String checksum, final Map<String,
String> headers, final Integer connectTimeout, final Integer soTimeout, final
Integer connectionRequestTimeout) {
+ private boolean followRedirects;
+
+ protected DirectDownloadCommand (final String url, final Long templateId,
final PrimaryDataStoreTO destPool,
+ final String checksum, final Map<String, String> headers, final
Integer connectTimeout,
+ final Integer soTimeout, final Integer connectionRequestTimeout,
final boolean followRedirects) {
this.url = url;
this.templateId = templateId;
this.destData = destData;
@@ -55,6 +59,7 @@ public abstract class DirectDownloadCommand extends
StorageSubSystemCommand {
this.connectTimeout = connectTimeout;
this.soTimeout = soTimeout;
this.connectionRequestTimeout = connectionRequestTimeout;
+ this.followRedirects = followRedirects;
}
public String getUrl() {
@@ -137,4 +142,12 @@ public abstract class DirectDownloadCommand extends
StorageSubSystemCommand {
public int getWaitInMillSeconds() {
return getWait() * 1000;
}
+
+ public boolean isFollowRedirects() {
+ return followRedirects;
+ }
+
+ public void setFollowRedirects(boolean followRedirects) {
+ this.followRedirects = followRedirects;
+ }
}
diff --git
a/core/src/main/java/org/apache/cloudstack/agent/directdownload/HttpDirectDownloadCommand.java
b/core/src/main/java/org/apache/cloudstack/agent/directdownload/HttpDirectDownloadCommand.java
index f131b3b0a7f..bdc00b3bc47 100644
---
a/core/src/main/java/org/apache/cloudstack/agent/directdownload/HttpDirectDownloadCommand.java
+++
b/core/src/main/java/org/apache/cloudstack/agent/directdownload/HttpDirectDownloadCommand.java
@@ -24,8 +24,10 @@ import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
public class HttpDirectDownloadCommand extends DirectDownloadCommand {
- public HttpDirectDownloadCommand(String url, Long templateId,
PrimaryDataStoreTO destPool, String checksum, Map<String, String> headers, int
connectTimeout, int soTimeout) {
- super(url, templateId, destPool, checksum, headers, connectTimeout,
soTimeout, null);
+ public HttpDirectDownloadCommand(String url, Long templateId,
PrimaryDataStoreTO destPool, String checksum,
+ Map<String, String> headers, int connectTimeout, int soTimeout,
boolean followRedirects) {
+ super(url, templateId, destPool, checksum, headers, connectTimeout,
soTimeout,
+ null, followRedirects);
}
}
diff --git
a/core/src/main/java/org/apache/cloudstack/agent/directdownload/HttpsDirectDownloadCommand.java
b/core/src/main/java/org/apache/cloudstack/agent/directdownload/HttpsDirectDownloadCommand.java
index dd88ad2a155..a7e16eac91a 100644
---
a/core/src/main/java/org/apache/cloudstack/agent/directdownload/HttpsDirectDownloadCommand.java
+++
b/core/src/main/java/org/apache/cloudstack/agent/directdownload/HttpsDirectDownloadCommand.java
@@ -25,7 +25,10 @@ import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
public class HttpsDirectDownloadCommand extends DirectDownloadCommand {
- public HttpsDirectDownloadCommand(String url, Long templateId,
PrimaryDataStoreTO destPool, String checksum, Map<String, String> headers, int
connectTimeout, int soTimeout, int connectionRequestTimeout) {
- super(url, templateId, destPool, checksum, headers, connectTimeout,
soTimeout, connectionRequestTimeout);
+ public HttpsDirectDownloadCommand(String url, Long templateId,
PrimaryDataStoreTO destPool, String checksum,
+ Map<String, String> headers, int connectTimeout, int soTimeout,
int connectionRequestTimeout,
+ boolean followRedirects) {
+ super(url, templateId, destPool, checksum, headers, connectTimeout,
soTimeout,
+ connectionRequestTimeout, followRedirects);
}
}
diff --git
a/core/src/main/java/org/apache/cloudstack/agent/directdownload/MetalinkDirectDownloadCommand.java
b/core/src/main/java/org/apache/cloudstack/agent/directdownload/MetalinkDirectDownloadCommand.java
index a3edcebe7de..7742994c76b 100644
---
a/core/src/main/java/org/apache/cloudstack/agent/directdownload/MetalinkDirectDownloadCommand.java
+++
b/core/src/main/java/org/apache/cloudstack/agent/directdownload/MetalinkDirectDownloadCommand.java
@@ -24,8 +24,9 @@ import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
public class MetalinkDirectDownloadCommand extends DirectDownloadCommand {
- public MetalinkDirectDownloadCommand(String url, Long templateId,
PrimaryDataStoreTO destPool, String checksum, Map<String, String> headers, int
connectTimeout, int soTimeout) {
- super(url, templateId, destPool, checksum, headers, connectTimeout,
soTimeout, null);
+ public MetalinkDirectDownloadCommand(String url, Long templateId,
PrimaryDataStoreTO destPool, String checksum,
+ Map<String, String> headers, int connectTimeout, int
soTimeout, boolean followRedirects) {
+ super(url, templateId, destPool, checksum, headers, connectTimeout,
soTimeout, null, followRedirects);
}
}
diff --git
a/core/src/main/java/org/apache/cloudstack/agent/directdownload/NfsDirectDownloadCommand.java
b/core/src/main/java/org/apache/cloudstack/agent/directdownload/NfsDirectDownloadCommand.java
index 0bf9c4d934b..0e51d786230 100644
---
a/core/src/main/java/org/apache/cloudstack/agent/directdownload/NfsDirectDownloadCommand.java
+++
b/core/src/main/java/org/apache/cloudstack/agent/directdownload/NfsDirectDownloadCommand.java
@@ -24,8 +24,9 @@ import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
public class NfsDirectDownloadCommand extends DirectDownloadCommand {
- public NfsDirectDownloadCommand(final String url, final Long templateId,
final PrimaryDataStoreTO destPool, final String checksum, final Map<String,
String> headers) {
- super(url, templateId, destPool, checksum, headers, null, null, null);
+ public NfsDirectDownloadCommand(final String url, final Long templateId,
final PrimaryDataStoreTO destPool,
+ final String checksum, final Map<String, String> headers) {
+ super(url, templateId, destPool, checksum, headers, null, null, null,
false);
}
}
diff --git
a/core/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadHelper.java
b/core/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadHelper.java
index 27e35b7074b..12fd5ad7162 100644
---
a/core/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadHelper.java
+++
b/core/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadHelper.java
@@ -34,27 +34,30 @@ public class DirectDownloadHelper {
* Get direct template downloader from direct download command and
destination pool
*/
public static DirectTemplateDownloader
getDirectTemplateDownloaderFromCommand(DirectDownloadCommand cmd,
-
String destPoolLocalPath,
-
String temporaryDownloadPath) {
+ String destPoolLocalPath, String temporaryDownloadPath) {
if (cmd instanceof HttpDirectDownloadCommand) {
- return new HttpDirectTemplateDownloader(cmd.getUrl(),
cmd.getTemplateId(), destPoolLocalPath, cmd.getChecksum(), cmd.getHeaders(),
- cmd.getConnectTimeout(), cmd.getSoTimeout(),
temporaryDownloadPath);
+ return new HttpDirectTemplateDownloader(cmd.getUrl(),
cmd.getTemplateId(), destPoolLocalPath,
+ cmd.getChecksum(), cmd.getHeaders(),
cmd.getConnectTimeout(), cmd.getSoTimeout(),
+ temporaryDownloadPath, cmd.isFollowRedirects());
} else if (cmd instanceof HttpsDirectDownloadCommand) {
- return new HttpsDirectTemplateDownloader(cmd.getUrl(),
cmd.getTemplateId(), destPoolLocalPath, cmd.getChecksum(), cmd.getHeaders(),
- cmd.getConnectTimeout(), cmd.getSoTimeout(),
cmd.getConnectionRequestTimeout(), temporaryDownloadPath);
+ return new HttpsDirectTemplateDownloader(cmd.getUrl(),
cmd.getTemplateId(), destPoolLocalPath,
+ cmd.getChecksum(), cmd.getHeaders(),
cmd.getConnectTimeout(), cmd.getSoTimeout(),
+ cmd.getConnectionRequestTimeout(), temporaryDownloadPath,
cmd.isFollowRedirects());
} else if (cmd instanceof NfsDirectDownloadCommand) {
- return new NfsDirectTemplateDownloader(cmd.getUrl(),
destPoolLocalPath, cmd.getTemplateId(), cmd.getChecksum(),
temporaryDownloadPath);
+ return new NfsDirectTemplateDownloader(cmd.getUrl(),
destPoolLocalPath, cmd.getTemplateId(),
+ cmd.getChecksum(), temporaryDownloadPath);
} else if (cmd instanceof MetalinkDirectDownloadCommand) {
- return new MetalinkDirectTemplateDownloader(cmd.getUrl(),
destPoolLocalPath, cmd.getTemplateId(), cmd.getChecksum(), cmd.getHeaders(),
- cmd.getConnectTimeout(), cmd.getSoTimeout(),
temporaryDownloadPath);
+ return new MetalinkDirectTemplateDownloader(cmd.getUrl(),
destPoolLocalPath, cmd.getTemplateId(),
+ cmd.getChecksum(), cmd.getHeaders(),
cmd.getConnectTimeout(), cmd.getSoTimeout(),
+ temporaryDownloadPath, cmd.isFollowRedirects());
} else {
throw new IllegalArgumentException("Unsupported protocol, please
provide HTTP(S), NFS or a metalink");
}
}
- public static boolean checkUrlExistence(String url) {
+ public static boolean checkUrlExistence(String url, boolean
followRedirects) {
try {
- DirectTemplateDownloader checker = getCheckerDownloader(url, null,
null, null);
+ DirectTemplateDownloader checker = getCheckerDownloader(url, null,
null, null, followRedirects);
return checker.checkUrl(url);
} catch (CloudRuntimeException e) {
LOGGER.error(String.format("Cannot check URL %s is reachable due
to: %s", url, e.getMessage()), e);
@@ -62,9 +65,11 @@ public class DirectDownloadHelper {
}
}
- public static boolean checkUrlExistence(String url, Integer
connectTimeout, Integer connectionRequestTimeout, Integer socketTimeout) {
+ public static boolean checkUrlExistence(String url, Integer
connectTimeout, Integer connectionRequestTimeout,
+ Integer socketTimeout, boolean followRedirects) {
try {
- DirectTemplateDownloader checker = getCheckerDownloader(url,
connectTimeout, connectionRequestTimeout, socketTimeout);
+ DirectTemplateDownloader checker = getCheckerDownloader(url,
connectTimeout, connectionRequestTimeout,
+ socketTimeout, followRedirects);
return checker.checkUrl(url);
} catch (CloudRuntimeException e) {
LOGGER.error(String.format("Cannot check URL %s is reachable due
to: %s", url, e.getMessage()), e);
@@ -72,27 +77,29 @@ public class DirectDownloadHelper {
}
}
- private static DirectTemplateDownloader getCheckerDownloader(String url,
Integer connectTimeout, Integer connectionRequestTimeout, Integer
socketTimeout) {
+ private static DirectTemplateDownloader getCheckerDownloader(String url,
Integer connectTimeout,
+ Integer connectionRequestTimeout, Integer socketTimeout, boolean
followRedirects) {
if (url.toLowerCase().startsWith("https:")) {
- return new HttpsDirectTemplateDownloader(url, connectTimeout,
connectionRequestTimeout, socketTimeout);
+ return new HttpsDirectTemplateDownloader(url, connectTimeout,
connectionRequestTimeout, socketTimeout, followRedirects);
} else if (url.toLowerCase().startsWith("http:")) {
- return new HttpDirectTemplateDownloader(url, connectTimeout,
socketTimeout);
+ return new HttpDirectTemplateDownloader(url, connectTimeout,
socketTimeout, followRedirects);
} else if (url.toLowerCase().startsWith("nfs:")) {
return new NfsDirectTemplateDownloader(url);
} else if (url.toLowerCase().endsWith(".metalink")) {
- return new MetalinkDirectTemplateDownloader(url, connectTimeout,
socketTimeout);
+ return new MetalinkDirectTemplateDownloader(url, connectTimeout,
socketTimeout, followRedirects);
} else {
throw new CloudRuntimeException(String.format("Cannot find a
download checker for url: %s", url));
}
}
- public static Long getFileSize(String url, String format) {
- DirectTemplateDownloader checker = getCheckerDownloader(url, null,
null, null);
+ public static Long getFileSize(String url, String format, boolean
followRedirects) {
+ DirectTemplateDownloader checker = getCheckerDownloader(url, null,
null, null, followRedirects);
return checker.getRemoteFileSize(url, format);
}
- public static Long getFileSize(String url, String format, Integer
connectTimeout, Integer connectionRequestTimeout, Integer socketTimeout) {
- DirectTemplateDownloader checker = getCheckerDownloader(url,
connectTimeout, connectionRequestTimeout, socketTimeout);
+ public static Long getFileSize(String url, String format, Integer
connectTimeout, Integer connectionRequestTimeout,
+ Integer socketTimeout, boolean followRedirects) {
+ DirectTemplateDownloader checker = getCheckerDownloader(url,
connectTimeout, connectionRequestTimeout, socketTimeout, followRedirects);
return checker.getRemoteFileSize(url, format);
}
}
diff --git
a/core/src/main/java/org/apache/cloudstack/direct/download/DirectTemplateDownloaderImpl.java
b/core/src/main/java/org/apache/cloudstack/direct/download/DirectTemplateDownloaderImpl.java
index 9476dbaa5ce..9431b8209b3 100644
---
a/core/src/main/java/org/apache/cloudstack/direct/download/DirectTemplateDownloaderImpl.java
+++
b/core/src/main/java/org/apache/cloudstack/direct/download/DirectTemplateDownloaderImpl.java
@@ -42,16 +42,19 @@ public abstract class DirectTemplateDownloaderImpl
implements DirectTemplateDown
private String checksum;
private boolean redownload = false;
protected String temporaryDownloadPath;
+ private boolean followRedirects;
public static final Logger s_logger =
Logger.getLogger(DirectTemplateDownloaderImpl.class.getName());
protected DirectTemplateDownloaderImpl(final String url, final String
destPoolPath, final Long templateId,
- final String checksum, final String
temporaryDownloadPath) {
+ final String checksum, final String
temporaryDownloadPath,
+ final boolean followRedirects) {
this.url = url;
this.destPoolPath = destPoolPath;
this.templateId = templateId;
this.checksum = checksum;
this.temporaryDownloadPath = temporaryDownloadPath;
+ this.followRedirects = followRedirects;
}
private static String directDownloadDir = "template";
@@ -111,6 +114,14 @@ public abstract class DirectTemplateDownloaderImpl
implements DirectTemplateDown
return redownload;
}
+ public boolean isFollowRedirects() {
+ return followRedirects;
+ }
+
+ public void setFollowRedirects(boolean followRedirects) {
+ this.followRedirects = followRedirects;
+ }
+
/**
* Create download directory (if it does not exist)
*/
diff --git
a/core/src/main/java/org/apache/cloudstack/direct/download/HttpDirectTemplateDownloader.java
b/core/src/main/java/org/apache/cloudstack/direct/download/HttpDirectTemplateDownloader.java
index e1b2f1fe429..a43ce9ba8e3 100644
---
a/core/src/main/java/org/apache/cloudstack/direct/download/HttpDirectTemplateDownloader.java
+++
b/core/src/main/java/org/apache/cloudstack/direct/download/HttpDirectTemplateDownloader.java
@@ -50,13 +50,15 @@ public class HttpDirectTemplateDownloader extends
DirectTemplateDownloaderImpl {
protected GetMethod request;
protected Map<String, String> reqHeaders = new HashMap<>();
- protected HttpDirectTemplateDownloader(String url, Integer connectTimeout,
Integer socketTimeout) {
- this(url, null, null, null, null, connectTimeout, socketTimeout, null);
+ protected HttpDirectTemplateDownloader(String url, Integer connectTimeout,
Integer socketTimeout,
+ boolean followRedirects) {
+ this(url, null, null, null, null, connectTimeout, socketTimeout, null,
followRedirects);
}
public HttpDirectTemplateDownloader(String url, Long templateId, String
destPoolPath, String checksum,
- Map<String, String> headers, Integer
connectTimeout, Integer soTimeout, String downloadPath) {
- super(url, destPoolPath, templateId, checksum, downloadPath);
+ Map<String, String> headers, Integer connectTimeout, Integer
soTimeout, String downloadPath,
+ boolean followRedirects) {
+ super(url, destPoolPath, templateId, checksum, downloadPath,
followRedirects);
s_httpClientManager.getParams().setConnectionTimeout(connectTimeout ==
null ? 5000 : connectTimeout);
s_httpClientManager.getParams().setSoTimeout(soTimeout == null ? 5000
: soTimeout);
client = new HttpClient(s_httpClientManager);
@@ -68,7 +70,7 @@ public class HttpDirectTemplateDownloader extends
DirectTemplateDownloaderImpl {
protected GetMethod createRequest(String downloadUrl, Map<String, String>
headers) {
GetMethod request = new GetMethod(downloadUrl);
- request.setFollowRedirects(true);
+ request.setFollowRedirects(this.isFollowRedirects());
if (MapUtils.isNotEmpty(headers)) {
for (String key : headers.keySet()) {
request.setRequestHeader(key, headers.get(key));
@@ -111,9 +113,11 @@ public class HttpDirectTemplateDownloader extends
DirectTemplateDownloaderImpl {
@Override
public boolean checkUrl(String url) {
HeadMethod httpHead = new HeadMethod(url);
+ httpHead.setFollowRedirects(this.isFollowRedirects());
try {
- if (client.executeMethod(httpHead) != HttpStatus.SC_OK) {
- s_logger.error(String.format("Invalid URL: %s", url));
+ int responseCode = client.executeMethod(httpHead);
+ if (responseCode != HttpStatus.SC_OK) {
+ s_logger.error(String.format("HTTP HEAD request to URL: %s
failed, response code: %d", url, responseCode));
return false;
}
return true;
@@ -128,9 +132,9 @@ public class HttpDirectTemplateDownloader extends
DirectTemplateDownloaderImpl {
@Override
public Long getRemoteFileSize(String url, String format) {
if ("qcow2".equalsIgnoreCase(format)) {
- return QCOW2Utils.getVirtualSize(url);
+ return QCOW2Utils.getVirtualSizeFromUrl(url,
this.isFollowRedirects());
} else {
- return UriUtils.getRemoteSize(url);
+ return UriUtils.getRemoteSize(url, this.isFollowRedirects());
}
}
diff --git
a/core/src/main/java/org/apache/cloudstack/direct/download/HttpsDirectTemplateDownloader.java
b/core/src/main/java/org/apache/cloudstack/direct/download/HttpsDirectTemplateDownloader.java
index 70a3eb29bc7..524c87b988c 100644
---
a/core/src/main/java/org/apache/cloudstack/direct/download/HttpsDirectTemplateDownloader.java
+++
b/core/src/main/java/org/apache/cloudstack/direct/download/HttpsDirectTemplateDownloader.java
@@ -68,20 +68,28 @@ public class HttpsDirectTemplateDownloader extends
DirectTemplateDownloaderImpl
protected CloseableHttpClient httpsClient;
private HttpUriRequest req;
- protected HttpsDirectTemplateDownloader(String url, Integer
connectTimeout, Integer connectionRequestTimeout, Integer socketTimeout) {
- this(url, null, null, null, null, connectTimeout, socketTimeout,
connectionRequestTimeout, null);
+ protected HttpsDirectTemplateDownloader(String url, Integer
connectTimeout, Integer connectionRequestTimeout,
+ Integer socketTimeout, boolean followRedirects) {
+ this(url, null, null, null, null, connectTimeout, socketTimeout,
+ connectionRequestTimeout, null, followRedirects);
}
- public HttpsDirectTemplateDownloader(String url, Long templateId, String
destPoolPath, String checksum, Map<String, String> headers,
- Integer connectTimeout, Integer
soTimeout, Integer connectionRequestTimeout, String temporaryDownloadPath) {
- super(url, destPoolPath, templateId, checksum, temporaryDownloadPath);
+ public HttpsDirectTemplateDownloader(String url, Long templateId, String
destPoolPath, String checksum,
+ Map<String, String> headers, Integer connectTimeout, Integer
soTimeout,
+ Integer connectionRequestTimeout, String
temporaryDownloadPath, boolean followRedirects) {
+ super(url, destPoolPath, templateId, checksum, temporaryDownloadPath,
followRedirects);
SSLContext sslcontext = getSSLContext();
SSLConnectionSocketFactory factory = new
SSLConnectionSocketFactory(sslcontext,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(connectTimeout == null ? 5000 :
connectTimeout)
.setConnectionRequestTimeout(connectionRequestTimeout == null
? 5000 : connectionRequestTimeout)
- .setSocketTimeout(soTimeout == null ? 5000 :
soTimeout).build();
- httpsClient =
HttpClients.custom().setSSLSocketFactory(factory).setDefaultRequestConfig(config).build();
+ .setSocketTimeout(soTimeout == null ? 5000 : soTimeout)
+ .setRedirectsEnabled(followRedirects)
+ .build();
+ httpsClient = HttpClients.custom()
+ .setSSLSocketFactory(factory)
+ .setDefaultRequestConfig(config)
+ .build();
createUriRequest(url, headers);
String downloadDir = getDirectDownloadTempPath(templateId);
File tempFile = createTemporaryDirectoryAndFile(downloadDir);
@@ -90,6 +98,7 @@ public class HttpsDirectTemplateDownloader extends
DirectTemplateDownloaderImpl
protected void createUriRequest(String downloadUrl, Map<String, String>
headers) {
req = new HttpGet(downloadUrl);
+ setFollowRedirects(this.isFollowRedirects());
if (MapUtils.isNotEmpty(headers)) {
for (String headerKey: headers.keySet()) {
req.setHeader(headerKey, headers.get(headerKey));
@@ -164,8 +173,9 @@ public class HttpsDirectTemplateDownloader extends
DirectTemplateDownloaderImpl
HttpHead httpHead = new HttpHead(url);
try {
CloseableHttpResponse response = httpsClient.execute(httpHead);
- if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
- s_logger.error(String.format("Invalid URL: %s", url));
+ int responseCode = response.getStatusLine().getStatusCode();
+ if (responseCode != HttpStatus.SC_OK) {
+ s_logger.error(String.format("HTTP HEAD request to URL: %s
failed, response code: %d", url, responseCode));
return false;
}
return true;
diff --git
a/core/src/main/java/org/apache/cloudstack/direct/download/MetalinkDirectTemplateDownloader.java
b/core/src/main/java/org/apache/cloudstack/direct/download/MetalinkDirectTemplateDownloader.java
index 06578d8c2b2..f6f7f7e48c2 100644
---
a/core/src/main/java/org/apache/cloudstack/direct/download/MetalinkDirectTemplateDownloader.java
+++
b/core/src/main/java/org/apache/cloudstack/direct/download/MetalinkDirectTemplateDownloader.java
@@ -42,16 +42,15 @@ public class MetalinkDirectTemplateDownloader extends
DirectTemplateDownloaderIm
private static final Logger s_logger =
Logger.getLogger(MetalinkDirectTemplateDownloader.class.getName());
protected DirectTemplateDownloader createDownloaderForMetalinks(String
url, Long templateId,
- String
destPoolPath, String checksum,
-
Map<String, String> headers,
- Integer
connectTimeout, Integer soTimeout,
- Integer
connectionRequestTimeout, String temporaryDownloadPath) {
+ String destPoolPath, String checksum, Map<String, String>
headers, Integer connectTimeout,
+ Integer soTimeout, Integer connectionRequestTimeout, String
temporaryDownloadPath) {
if (url.toLowerCase().startsWith("https:")) {
return new HttpsDirectTemplateDownloader(url, templateId,
destPoolPath, checksum, headers,
- connectTimeout, soTimeout, connectionRequestTimeout,
temporaryDownloadPath);
+ connectTimeout, soTimeout, connectionRequestTimeout,
temporaryDownloadPath,
+ this.isFollowRedirects());
} else if (url.toLowerCase().startsWith("http:")) {
return new HttpDirectTemplateDownloader(url, templateId,
destPoolPath, checksum, headers,
- connectTimeout, soTimeout, temporaryDownloadPath);
+ connectTimeout, soTimeout, temporaryDownloadPath,
this.isFollowRedirects());
} else if (url.toLowerCase().startsWith("nfs:")) {
return new NfsDirectTemplateDownloader(url);
} else {
@@ -60,13 +59,15 @@ public class MetalinkDirectTemplateDownloader extends
DirectTemplateDownloaderIm
}
}
- protected MetalinkDirectTemplateDownloader(String url, Integer
connectTimeout, Integer socketTimeout) {
- this(url, null, null, null, null, connectTimeout, socketTimeout, null);
+ protected MetalinkDirectTemplateDownloader(String url, Integer
connectTimeout, Integer socketTimeout,
+ boolean followRedirects) {
+ this(url, null, null, null, null, connectTimeout, socketTimeout, null,
followRedirects);
}
public MetalinkDirectTemplateDownloader(String url, String destPoolPath,
Long templateId, String checksum,
- Map<String, String> headers,
Integer connectTimeout, Integer soTimeout, String downloadPath) {
- super(url, destPoolPath, templateId, checksum, downloadPath);
+ Map<String, String> headers, Integer connectTimeout, Integer
soTimeout, String downloadPath,
+ boolean followRedirects) {
+ super(url, destPoolPath, templateId, checksum, downloadPath,
followRedirects);
this.headers = headers;
this.connectTimeout = connectTimeout;
this.soTimeout = soTimeout;
diff --git
a/core/src/main/java/org/apache/cloudstack/direct/download/NfsDirectTemplateDownloader.java
b/core/src/main/java/org/apache/cloudstack/direct/download/NfsDirectTemplateDownloader.java
index d606136e297..e5ff533cc97 100644
---
a/core/src/main/java/org/apache/cloudstack/direct/download/NfsDirectTemplateDownloader.java
+++
b/core/src/main/java/org/apache/cloudstack/direct/download/NfsDirectTemplateDownloader.java
@@ -57,8 +57,9 @@ public class NfsDirectTemplateDownloader extends
DirectTemplateDownloaderImpl {
this(url, null, null, null, null);
}
- public NfsDirectTemplateDownloader(String url, String destPool, Long
templateId, String checksum, String downloadPath) {
- super(url, destPool, templateId, checksum, downloadPath);
+ public NfsDirectTemplateDownloader(String url, String destPool, Long
templateId, String checksum,
+ String downloadPath) {
+ super(url, destPool, templateId, checksum, downloadPath, false);
parseUrl();
}
diff --git
a/core/src/main/java/org/apache/cloudstack/storage/command/DownloadCommand.java
b/core/src/main/java/org/apache/cloudstack/storage/command/DownloadCommand.java
index 29d737fcce9..7b41bd949e5 100644
---
a/core/src/main/java/org/apache/cloudstack/storage/command/DownloadCommand.java
+++
b/core/src/main/java/org/apache/cloudstack/storage/command/DownloadCommand.java
@@ -48,6 +48,8 @@ public class DownloadCommand extends AbstractDownloadCommand
implements Internal
private DataStoreTO _store;
private DataStoreTO cacheStore;
+ private boolean followRedirects = false;
+
protected DownloadCommand() {
}
@@ -64,6 +66,7 @@ public class DownloadCommand extends AbstractDownloadCommand
implements Internal
installPath = that.installPath;
_store = that._store;
_proxy = that._proxy;
+ followRedirects = that.followRedirects;
}
public DownloadCommand(TemplateObjectTO template, Long
maxDownloadSizeInBytes) {
@@ -79,6 +82,7 @@ public class DownloadCommand extends AbstractDownloadCommand
implements Internal
setSecUrl(((NfsTO)_store).getUrl());
}
this.maxDownloadSizeInBytes = maxDownloadSizeInBytes;
+ this.followRedirects = template.isFollowRedirects();
}
public DownloadCommand(TemplateObjectTO template, String user, String
passwd, Long maxDownloadSizeInBytes) {
@@ -94,6 +98,7 @@ public class DownloadCommand extends AbstractDownloadCommand
implements Internal
_store = volume.getDataStore();
this.maxDownloadSizeInBytes = maxDownloadSizeInBytes;
resourceType = ResourceType.VOLUME;
+ this.followRedirects = volume.isFollowRedirects();
}
@Override
@@ -181,4 +186,12 @@ public class DownloadCommand extends
AbstractDownloadCommand implements Internal
public DataStoreTO getCacheStore() {
return cacheStore;
}
+
+ public boolean isFollowRedirects() {
+ return followRedirects;
+ }
+
+ public void setFollowRedirects(boolean followRedirects) {
+ this.followRedirects = followRedirects;
+ }
}
diff --git
a/framework/config/src/main/java/org/apache/cloudstack/framework/config/ConfigDepot.java
b/core/src/main/java/org/apache/cloudstack/storage/to/DownloadableObjectTO.java
similarity index 66%
copy from
framework/config/src/main/java/org/apache/cloudstack/framework/config/ConfigDepot.java
copy to
core/src/main/java/org/apache/cloudstack/storage/to/DownloadableObjectTO.java
index 1ed37ab9969..70db8fafffc 100644
---
a/framework/config/src/main/java/org/apache/cloudstack/framework/config/ConfigDepot.java
+++
b/core/src/main/java/org/apache/cloudstack/storage/to/DownloadableObjectTO.java
@@ -14,21 +14,17 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
-package org.apache.cloudstack.framework.config;
-import java.util.Set;
+package org.apache.cloudstack.storage.to;
-/**
- * ConfigDepot is a repository of configurations.
- *
- */
-public interface ConfigDepot {
+public class DownloadableObjectTO {
+ protected boolean followRedirects = false;
- ConfigKey<?> get(String paramName);
+ public boolean isFollowRedirects() {
+ return followRedirects;
+ }
- Set<ConfigKey<?>> getConfigListByScope(String scope);
-
- <T> void set(ConfigKey<T> key, T value);
-
- <T> void createOrUpdateConfigObject(String componentName, ConfigKey<T>
key, String value);
+ public void setFollowRedirects(boolean followRedirects) {
+ this.followRedirects = followRedirects;
+ }
}
diff --git
a/core/src/main/java/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
b/core/src/main/java/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
index c62110b179e..72e6492aa52 100644
--- a/core/src/main/java/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
+++ b/core/src/main/java/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
@@ -30,7 +30,7 @@ import com.cloud.agent.api.to.DataStoreTO;
import com.cloud.agent.api.to.DataTO;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
-public class SnapshotObjectTO implements DataTO {
+public class SnapshotObjectTO extends DownloadableObjectTO implements DataTO {
private String path;
private VolumeObjectTO volume;
private String parentSnapshotPath;
diff --git
a/core/src/main/java/org/apache/cloudstack/storage/to/TemplateObjectTO.java
b/core/src/main/java/org/apache/cloudstack/storage/to/TemplateObjectTO.java
index a405785bf64..eafe8f83269 100644
--- a/core/src/main/java/org/apache/cloudstack/storage/to/TemplateObjectTO.java
+++ b/core/src/main/java/org/apache/cloudstack/storage/to/TemplateObjectTO.java
@@ -28,7 +28,7 @@ import com.cloud.hypervisor.Hypervisor;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.template.VirtualMachineTemplate;
-public class TemplateObjectTO implements DataTO {
+public class TemplateObjectTO extends DownloadableObjectTO implements DataTO {
private String path;
private String origUrl;
private String uuid;
@@ -87,6 +87,7 @@ public class TemplateObjectTO implements DataTO {
this.deployAsIs = template.isDeployAsIs();
this.deployAsIsConfiguration = template.getDeployAsIsConfiguration();
this.directDownload = template.isDirectDownload();
+ this.followRedirects = template.isFollowRedirects();
}
@Override
diff --git
a/core/src/main/java/org/apache/cloudstack/storage/to/VolumeObjectTO.java
b/core/src/main/java/org/apache/cloudstack/storage/to/VolumeObjectTO.java
index 8473ea7a49e..2bb67c80ce4 100644
--- a/core/src/main/java/org/apache/cloudstack/storage/to/VolumeObjectTO.java
+++ b/core/src/main/java/org/apache/cloudstack/storage/to/VolumeObjectTO.java
@@ -33,7 +33,7 @@ import com.cloud.storage.Volume;
import java.util.Arrays;
-public class VolumeObjectTO implements DataTO {
+public class VolumeObjectTO extends DownloadableObjectTO implements DataTO {
private String uuid;
private Volume.Type volumeType;
private DataStoreTO dataStore;
@@ -119,6 +119,7 @@ public class VolumeObjectTO implements DataTO {
this.vSphereStoragePolicyId = volume.getvSphereStoragePolicyId();
this.passphrase = volume.getPassphrase();
this.encryptFormat = volume.getEncryptFormat();
+ this.followRedirects = volume.isFollowRedirects();
}
public String getUuid() {
diff --git
a/core/src/test/java/org/apache/cloudstack/direct/download/BaseDirectTemplateDownloaderTest.java
b/core/src/test/java/org/apache/cloudstack/direct/download/BaseDirectTemplateDownloaderTest.java
index 2c7245662a2..b74dc9460d6 100644
---
a/core/src/test/java/org/apache/cloudstack/direct/download/BaseDirectTemplateDownloaderTest.java
+++
b/core/src/test/java/org/apache/cloudstack/direct/download/BaseDirectTemplateDownloaderTest.java
@@ -56,7 +56,7 @@ public class BaseDirectTemplateDownloaderTest {
private HttpEntity httpEntity;
@InjectMocks
- protected HttpsDirectTemplateDownloader httpsDownloader = new
HttpsDirectTemplateDownloader(httpUrl, 1000, 1000, 1000);
+ protected HttpsDirectTemplateDownloader httpsDownloader = new
HttpsDirectTemplateDownloader(httpUrl, 1000, 1000, 1000, false);
@Before
public void init() throws IOException {
diff --git
a/core/src/test/java/org/apache/cloudstack/direct/download/MetalinkDirectTemplateDownloaderTest.java
b/core/src/test/java/org/apache/cloudstack/direct/download/MetalinkDirectTemplateDownloaderTest.java
index 68982fb915f..81e504ec512 100644
---
a/core/src/test/java/org/apache/cloudstack/direct/download/MetalinkDirectTemplateDownloaderTest.java
+++
b/core/src/test/java/org/apache/cloudstack/direct/download/MetalinkDirectTemplateDownloaderTest.java
@@ -25,7 +25,7 @@ import org.mockito.InjectMocks;
public class MetalinkDirectTemplateDownloaderTest extends
BaseDirectTemplateDownloaderTest {
@InjectMocks
- protected MetalinkDirectTemplateDownloader metalinkDownloader = new
MetalinkDirectTemplateDownloader(httpsUrl, 1000, 1000);
+ protected MetalinkDirectTemplateDownloader metalinkDownloader = new
MetalinkDirectTemplateDownloader(httpsUrl, 1000, 1000, false);
@Test
public void testCheckUrlMetalink() {
diff --git
a/framework/config/src/main/java/org/apache/cloudstack/framework/config/ConfigDepot.java
b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DownloadableDataInfo.java
similarity index 66%
copy from
framework/config/src/main/java/org/apache/cloudstack/framework/config/ConfigDepot.java
copy to
engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DownloadableDataInfo.java
index 1ed37ab9969..63b0867d1ab 100644
---
a/framework/config/src/main/java/org/apache/cloudstack/framework/config/ConfigDepot.java
+++
b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DownloadableDataInfo.java
@@ -14,21 +14,11 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
-package org.apache.cloudstack.framework.config;
-import java.util.Set;
+package org.apache.cloudstack.engine.subsystem.api.storage;
-/**
- * ConfigDepot is a repository of configurations.
- *
- */
-public interface ConfigDepot {
-
- ConfigKey<?> get(String paramName);
-
- Set<ConfigKey<?>> getConfigListByScope(String scope);
-
- <T> void set(ConfigKey<T> key, T value);
-
- <T> void createOrUpdateConfigObject(String componentName, ConfigKey<T>
key, String value);
+public interface DownloadableDataInfo extends DataObject {
+ default public boolean isFollowRedirects() {
+ return true;
+ }
}
diff --git
a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/TemplateInfo.java
b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/TemplateInfo.java
index 1d49e19d2da..3bd3100e84e 100644
---
a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/TemplateInfo.java
+++
b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/TemplateInfo.java
@@ -21,7 +21,7 @@ package org.apache.cloudstack.engine.subsystem.api.storage;
import com.cloud.template.VirtualMachineTemplate;
import com.cloud.user.UserData;
-public interface TemplateInfo extends DataObject, VirtualMachineTemplate {
+public interface TemplateInfo extends DownloadableDataInfo,
VirtualMachineTemplate {
@Override
String getUniqueName();
diff --git
a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java
b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java
index be16c20d173..19b852bd912 100644
---
a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java
+++
b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java
@@ -26,7 +26,7 @@ import com.cloud.storage.Storage;
import com.cloud.storage.Volume;
import com.cloud.vm.VirtualMachine;
-public interface VolumeInfo extends DataObject, Volume {
+public interface VolumeInfo extends DownloadableDataInfo, Volume {
boolean isAttachedVM();
diff --git
a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
index 28e7c89419a..7fdec905242 100644
--- a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
+++ b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
@@ -191,6 +191,10 @@ public interface StorageManager extends StorageService {
true,
ConfigKey.Scope.Global,
null);
+ static final ConfigKey<Boolean> DataStoreDownloadFollowRedirects = new
ConfigKey<>(ConfigKey.CATEGORY_ADVANCED,
+ Boolean.class, "store.download.follow.redirects", "false",
+ "Whether HTTP redirect is followed during store downloads for
objects such as template, volume etc.",
+ true, ConfigKey.Scope.Global);
/**
* should we execute in sequence not involving any storages?
diff --git
a/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/TemplateServiceImpl.java
b/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/TemplateServiceImpl.java
index e6235a63c77..6c4fcab2f17 100644
---
a/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/TemplateServiceImpl.java
+++
b/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/TemplateServiceImpl.java
@@ -91,6 +91,7 @@ import com.cloud.storage.ScopeType;
import com.cloud.storage.Storage;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.Storage.TemplateType;
+import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool;
import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
@@ -366,6 +367,7 @@ public class TemplateServiceImpl implements TemplateService
{
toBeDownloaded.addAll(allTemplates);
final StateMachine2<VirtualMachineTemplate.State,
VirtualMachineTemplate.Event, VirtualMachineTemplate> stateMachine =
VirtualMachineTemplate.State.getStateMachine();
+ Boolean followRedirect =
StorageManager.DataStoreDownloadFollowRedirects.value();
for (VMTemplateVO tmplt : allTemplates) {
String uniqueName = tmplt.getUniqueName();
TemplateDataStoreVO tmpltStore =
_vmTemplateStoreDao.findByStoreTemplate(storeId, tmplt.getId());
@@ -446,7 +448,8 @@ public class TemplateServiceImpl implements TemplateService
{
try {
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(accountId),
com.cloud.configuration.Resource.ResourceType.secondary_storage,
- tmpltInfo.getSize() -
UriUtils.getRemoteSize(tmplt.getUrl()));
+ tmpltInfo.getSize() -
UriUtils.getRemoteSize(tmplt.getUrl(),
+ followRedirect));
} catch (ResourceAllocationException
e) {
s_logger.warn(e.getMessage());
_alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED,
zoneId, null, e.getMessage(), e.getMessage());
diff --git
a/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/store/TemplateObject.java
b/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/store/TemplateObject.java
index b688197bfb9..3883637cd07 100644
---
a/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/store/TemplateObject.java
+++
b/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/store/TemplateObject.java
@@ -23,6 +23,7 @@ import java.util.Map;
import javax.inject.Inject;
+import com.cloud.storage.StorageManager;
import com.cloud.user.UserData;
import org.apache.log4j.Logger;
@@ -73,8 +74,10 @@ public class TemplateObject implements TemplateInfo {
VMTemplatePoolDao templatePoolDao;
@Inject
TemplateDataStoreDao templateStoreDao;
+ final private boolean followRedirects;
public TemplateObject() {
+ this.followRedirects =
StorageManager.DataStoreDownloadFollowRedirects.value();
}
protected void configure(VMTemplateVO template, DataStore dataStore) {
@@ -573,4 +576,9 @@ public class TemplateObject implements TemplateInfo {
// TODO Auto-generated method stub
return null;
}
+
+ @Override
+ public boolean isFollowRedirects() {
+ return followRedirects;
+ }
}
diff --git
a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeObject.java
b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeObject.java
index 5ebee87acd4..b0f426a54c4 100644
---
a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeObject.java
+++
b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeObject.java
@@ -23,6 +23,7 @@ import javax.inject.Inject;
import com.cloud.configuration.Resource.ResourceType;
import com.cloud.dc.VsphereStoragePolicyVO;
import com.cloud.dc.dao.VsphereStoragePolicyDao;
+import com.cloud.storage.StorageManager;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallbackNoReturn;
import com.cloud.utils.db.TransactionStatus;
@@ -117,6 +118,7 @@ public class VolumeObject implements VolumeInfo {
private MigrationOptions migrationOptions;
private boolean directDownload;
private String vSphereStoragePolicyId;
+ private boolean followRedirects;
private final List<Volume.State>
volumeStatesThatShouldNotTransitWhenDataStoreRoleIsImage =
Arrays.asList(Volume.State.Migrating, Volume.State.Uploaded,
Volume.State.Copying,
Volume.State.Expunged);
@@ -127,6 +129,7 @@ public class VolumeObject implements VolumeInfo {
public VolumeObject() {
_volStateMachine = Volume.State.getStateMachine();
+ this.followRedirects =
StorageManager.DataStoreDownloadFollowRedirects.value();
}
protected void configure(DataStore dataStore, VolumeVO volumeVO) {
@@ -930,4 +933,9 @@ public class VolumeObject implements VolumeInfo {
public void setEncryptFormat(String encryptFormat) {
volumeVO.setEncryptFormat(encryptFormat);
}
+
+ @Override
+ public boolean isFollowRedirects() {
+ return followRedirects;
+ }
}
diff --git
a/framework/config/src/main/java/org/apache/cloudstack/framework/config/ConfigDepot.java
b/framework/config/src/main/java/org/apache/cloudstack/framework/config/ConfigDepot.java
index 1ed37ab9969..b38b30e88b8 100644
---
a/framework/config/src/main/java/org/apache/cloudstack/framework/config/ConfigDepot.java
+++
b/framework/config/src/main/java/org/apache/cloudstack/framework/config/ConfigDepot.java
@@ -31,4 +31,5 @@ public interface ConfigDepot {
<T> void set(ConfigKey<T> key, T value);
<T> void createOrUpdateConfigObject(String componentName, ConfigKey<T>
key, String value);
+ boolean isNewConfig(ConfigKey<?> configKey);
}
diff --git
a/framework/config/src/main/java/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java
b/framework/config/src/main/java/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java
index 75a3ea4d947..46a1de950dd 100644
---
a/framework/config/src/main/java/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java
+++
b/framework/config/src/main/java/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java
@@ -81,6 +81,7 @@ public class ConfigDepotImpl implements ConfigDepot,
ConfigDepotAdmin {
List<Configurable> _configurables;
List<ScopedConfigStorage> _scopedStorages;
Set<Configurable> _configured = Collections.synchronizedSet(new
HashSet<Configurable>());
+ Set<String> newConfigs = Collections.synchronizedSet(new HashSet<>());
private HashMap<String, Pair<String, ConfigKey<?>>> _allKeys = new
HashMap<String, Pair<String, ConfigKey<?>>>(1007);
@@ -193,6 +194,7 @@ public class ConfigDepotImpl implements ConfigDepot,
ConfigDepotAdmin {
}
_configDao.persist(vo);
+ newConfigs.add(vo.getName());
} else {
boolean configUpdated = false;
if (vo.isDynamic() != key.isDynamic() ||
!ObjectUtils.equals(vo.getDescription(), key.description()) ||
!ObjectUtils.equals(vo.getDefaultValue(), key.defaultValue()) ||
@@ -343,4 +345,9 @@ public class ConfigDepotImpl implements ConfigDepot,
ConfigDepotAdmin {
return new Pair<>(groupId, subGroupId);
}
+
+ @Override
+ public boolean isNewConfig(ConfigKey<?> configKey) {
+ return newConfigs.contains(configKey.key());
+ }
}
diff --git
a/framework/config/src/test/java/org/apache/cloudstack/framework/config/impl/ConfigDepotImplTest.java
b/framework/config/src/test/java/org/apache/cloudstack/framework/config/impl/ConfigDepotImplTest.java
index fed784cfe2d..8dd6f71af3c 100644
---
a/framework/config/src/test/java/org/apache/cloudstack/framework/config/impl/ConfigDepotImplTest.java
+++
b/framework/config/src/test/java/org/apache/cloudstack/framework/config/impl/ConfigDepotImplTest.java
@@ -18,9 +18,14 @@
//
package org.apache.cloudstack.framework.config.impl;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
import org.apache.cloudstack.framework.config.ConfigKey;
import org.junit.Assert;
import org.junit.Test;
+import org.springframework.test.util.ReflectionTestUtils;
public class ConfigDepotImplTest {
@@ -40,4 +45,16 @@ public class ConfigDepotImplTest {
}
}
+ @Test
+ public void testIsNewConfig() {
+ String validNewConfigKey = "CONFIG";
+ ConfigKey<Boolean> validNewConfig = new
ConfigKey<>(ConfigKey.CATEGORY_ADVANCED, Boolean.class, "CONFIG", "true", "",
true);
+ ConfigKey<Boolean> invalidNewConfig = new
ConfigKey<>(ConfigKey.CATEGORY_ADVANCED, Boolean.class, "CONFIG1", "true", "",
true);
+ Set<String> newConfigs = Collections.synchronizedSet(new HashSet<>());
+ newConfigs.add(validNewConfigKey);
+ ReflectionTestUtils.setField(configDepotImpl, "newConfigs",
newConfigs);
+ Assert.assertTrue(configDepotImpl.isNewConfig(validNewConfig));
+ Assert.assertFalse(configDepotImpl.isNewConfig(invalidNewConfig));
+ }
+
}
diff --git
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckUrlCommand.java
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckUrlCommand.java
index 5faad5633f3..9d003eb2096 100644
---
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckUrlCommand.java
+++
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckUrlCommand.java
@@ -38,13 +38,14 @@ public class LibvirtCheckUrlCommand extends
CommandWrapper<CheckUrlCommand, Chec
final Integer connectTimeout = cmd.getConnectTimeout();
final Integer connectionRequestTimeout =
cmd.getConnectionRequestTimeout();
final Integer socketTimeout = cmd.getSocketTimeout();
+ final boolean followRedirects = cmd.isFollowRedirects();
s_logger.info(String.format("Checking URL: %s, with connect timeout:
%d, connect request timeout: %d, socket timeout: %d", url, connectTimeout,
connectionRequestTimeout, socketTimeout));
Long remoteSize = null;
- boolean checkResult = DirectDownloadHelper.checkUrlExistence(url,
connectTimeout, connectionRequestTimeout, socketTimeout);
+ boolean checkResult = DirectDownloadHelper.checkUrlExistence(url,
connectTimeout, connectionRequestTimeout, socketTimeout, followRedirects);
if (checkResult) {
- remoteSize = DirectDownloadHelper.getFileSize(url,
cmd.getFormat(), connectTimeout, connectionRequestTimeout, socketTimeout);
+ remoteSize = DirectDownloadHelper.getFileSize(url,
cmd.getFormat(), connectTimeout, connectionRequestTimeout, socketTimeout,
followRedirects);
if (remoteSize == null || remoteSize < 0) {
s_logger.error(String.format("Couldn't properly retrieve the
remote size of the template on " +
"url %s, obtained size = %s", url, remoteSize));
diff --git
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
index dd31025d35f..0cfd83ae456 100644
---
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
+++
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
@@ -2361,7 +2361,7 @@ public class KVMStorageProcessor implements
StorageProcessor {
Long templateSize = null;
if (StringUtils.isNotBlank(cmd.getUrl())) {
String url = cmd.getUrl();
- templateSize = UriUtils.getRemoteSize(url);
+ templateSize = UriUtils.getRemoteSize(url,
cmd.isFollowRedirects());
}
s_logger.debug("Checking for free space on the host for
downloading the template with physical size: " + templateSize + " and virtual
size: " + cmd.getTemplateSize());
diff --git a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
index 643f29287e2..c6379a7e4c3 100644
--- a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
+++ b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
@@ -89,6 +89,7 @@ import
org.apache.cloudstack.engine.subsystem.api.storage.VolumeService;
import
org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult;
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
import org.apache.cloudstack.framework.async.AsyncCallFuture;
+import org.apache.cloudstack.framework.config.ConfigDepot;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
@@ -216,6 +217,7 @@ import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.EntityManager;
+import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericSearchBuilder;
import com.cloud.utils.db.GlobalLock;
import com.cloud.utils.db.JoinBuilder;
@@ -347,6 +349,11 @@ public class StorageManagerImpl extends ManagerBase
implements StorageManager, C
@Inject
protected UserVmManager userVmManager;
+ @Inject
+ ConfigDepot configDepot;
+ @Inject
+ ConfigurationDao configurationDao;
+
protected List<StoragePoolDiscoverer> _discoverers;
public List<StoragePoolDiscoverer> getDiscoverers() {
@@ -407,6 +414,23 @@ public class StorageManagerImpl extends ManagerBase
implements StorageManager, C
}
}
+ protected void
enableDefaultDatastoreDownloadRedirectionForExistingInstallations() {
+ if (!configDepot.isNewConfig(DataStoreDownloadFollowRedirects)) {
+ if (s_logger.isTraceEnabled()) {
+ s_logger.trace(String.format("%s is not a new configuration,
skipping updating its value",
+ DataStoreDownloadFollowRedirects.key()));
+ }
+ return;
+ }
+ List<DataCenterVO> zones =
+ _dcDao.listAll(new Filter(1));
+ if (CollectionUtils.isNotEmpty(zones)) {
+ s_logger.debug(String.format("Updating value for configuration: %s
to true",
+ DataStoreDownloadFollowRedirects.key()));
+ configurationDao.update(DataStoreDownloadFollowRedirects.key(),
"true");
+ }
+ }
+
@Override
public List<StoragePoolVO> ListByDataCenterHypervisor(long datacenterId,
HypervisorType type) {
List<StoragePoolVO> pools =
_storagePoolDao.listByDataCenterId(datacenterId);
@@ -638,7 +662,7 @@ public class StorageManagerImpl extends ManagerBase
implements StorageManager, C
}
_executor.scheduleWithFixedDelay(new DownloadURLGarbageCollector(),
_downloadUrlCleanupInterval, _downloadUrlCleanupInterval, TimeUnit.SECONDS);
-
+ enableDefaultDatastoreDownloadRedirectionForExistingInstallations();
return true;
}
@@ -3417,7 +3441,8 @@ public class StorageManagerImpl extends ManagerBase
implements StorageManager, C
SecStorageVMAutoScaleDown,
MountDisabledStoragePool,
VmwareCreateCloneFull,
- VmwareAllowParallelExecution
+ VmwareAllowParallelExecution,
+ DataStoreDownloadFollowRedirects
};
}
diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
index 06f6fcc8c2a..0907a847c03 100644
--- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
@@ -535,12 +535,14 @@ public class VolumeApiServiceImpl extends ManagerBase
implements VolumeApiServic
throw new InvalidParameterValueException("File:// type urls
are currently unsupported");
}
UriUtils.validateUrl(format, url);
+ boolean followRedirects =
StorageManager.DataStoreDownloadFollowRedirects.value();
if (VolumeUrlCheck.value()) { // global setting that can be set
when their MS does not have internet access
s_logger.debug("Checking url: " + url);
- DirectDownloadHelper.checkUrlExistence(url);
+ DirectDownloadHelper.checkUrlExistence(url, followRedirects);
}
// Check that the resource limit for secondary storage won't be
exceeded
-
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(ownerId),
ResourceType.secondary_storage, UriUtils.getRemoteSize(url));
+
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(ownerId),
ResourceType.secondary_storage,
+ UriUtils.getRemoteSize(url, followRedirects));
} else {
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(ownerId),
ResourceType.secondary_storage);
}
@@ -642,7 +644,8 @@ public class VolumeApiServiceImpl extends ManagerBase
implements VolumeApiServic
_resourceLimitMgr.incrementResourceCount(volume.getAccountId(),
ResourceType.volume);
//url can be null incase of postupload
if (url != null) {
-
_resourceLimitMgr.incrementResourceCount(volume.getAccountId(),
ResourceType.secondary_storage, UriUtils.getRemoteSize(url));
+
_resourceLimitMgr.incrementResourceCount(volume.getAccountId(),
ResourceType.secondary_storage,
+ UriUtils.getRemoteSize(url,
StorageManager.DataStoreDownloadFollowRedirects.value()));
}
return volume;
diff --git
a/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java
b/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java
index 1633cd8a360..2a536fa7a79 100644
--- a/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java
+++ b/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java
@@ -87,6 +87,7 @@ import com.cloud.server.StatsCollector;
import com.cloud.storage.ScopeType;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.Storage.TemplateType;
+import com.cloud.storage.StorageManager;
import com.cloud.storage.TemplateProfile;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
import com.cloud.storage.VMTemplateVO;
@@ -156,7 +157,8 @@ public class HypervisorTemplateAdapter extends
TemplateAdapterBase {
* Validate on random running KVM host that URL is reachable
* @param url url
*/
- private Long performDirectDownloadUrlValidation(final String format, final
String url, final List<Long> zoneIds) {
+ private Long performDirectDownloadUrlValidation(final String format, final
String url, final List<Long> zoneIds,
+ boolean followRedirects) {
HostVO host = null;
if (zoneIds != null && !zoneIds.isEmpty()) {
for (Long zoneId : zoneIds) {
@@ -175,7 +177,8 @@ public class HypervisorTemplateAdapter extends
TemplateAdapterBase {
Integer socketTimeout =
DirectDownloadManager.DirectDownloadSocketTimeout.value();
Integer connectRequestTimeout =
DirectDownloadManager.DirectDownloadConnectionRequestTimeout.value();
Integer connectTimeout =
DirectDownloadManager.DirectDownloadConnectTimeout.value();
- CheckUrlCommand cmd = new CheckUrlCommand(format, url, connectTimeout,
connectRequestTimeout, socketTimeout);
+ CheckUrlCommand cmd = new CheckUrlCommand(format, url, connectTimeout,
connectRequestTimeout, socketTimeout,
+ followRedirects);
s_logger.debug("Performing URL " + url + " validation on host " +
host.getId());
Answer answer = _agentMgr.easySend(host.getId(), cmd);
if (answer == null || !answer.getResult()) {
@@ -199,6 +202,7 @@ public class HypervisorTemplateAdapter extends
TemplateAdapterBase {
TemplateProfile profile = super.prepare(cmd);
String url = profile.getUrl();
UriUtils.validateUrl(ImageFormat.ISO.getFileExtension(), url);
+ boolean followRedirects =
StorageManager.DataStoreDownloadFollowRedirects.value();
if (cmd.isDirectDownload()) {
DigestHelper.validateChecksumString(cmd.getChecksum());
List<Long> zoneIds = null;
@@ -206,12 +210,15 @@ public class HypervisorTemplateAdapter extends
TemplateAdapterBase {
zoneIds = new ArrayList<>();
zoneIds.add(cmd.getZoneId());
}
- Long templateSize =
performDirectDownloadUrlValidation(ImageFormat.ISO.getFileExtension(), url,
zoneIds);
+ Long templateSize =
performDirectDownloadUrlValidation(ImageFormat.ISO.getFileExtension(), url,
zoneIds,
+ followRedirects);
profile.setSize(templateSize);
}
profile.setUrl(url);
// Check that the resource limit for secondary storage won't be
exceeded
-
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(cmd.getEntityOwnerId()),
ResourceType.secondary_storage, UriUtils.getRemoteSize(url));
+
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(cmd.getEntityOwnerId()),
+ ResourceType.secondary_storage,
+ UriUtils.getRemoteSize(url, followRedirects));
return profile;
}
@@ -229,14 +236,18 @@ public class HypervisorTemplateAdapter extends
TemplateAdapterBase {
TemplateProfile profile = super.prepare(cmd);
String url = profile.getUrl();
UriUtils.validateUrl(cmd.getFormat(), url, cmd.isDirectDownload());
+ boolean followRedirects =
StorageManager.DataStoreDownloadFollowRedirects.value();
if (cmd.isDirectDownload()) {
DigestHelper.validateChecksumString(cmd.getChecksum());
- Long templateSize =
performDirectDownloadUrlValidation(cmd.getFormat(), url, cmd.getZoneIds());
+ Long templateSize =
performDirectDownloadUrlValidation(cmd.getFormat(), url, cmd.getZoneIds(),
+ followRedirects);
profile.setSize(templateSize);
}
profile.setUrl(url);
// Check that the resource limit for secondary storage won't be
exceeded
-
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(cmd.getEntityOwnerId()),
ResourceType.secondary_storage, UriUtils.getRemoteSize(url));
+
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(cmd.getEntityOwnerId()),
+ ResourceType.secondary_storage,
+ UriUtils.getRemoteSize(url, followRedirects));
return profile;
}
diff --git
a/server/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java
b/server/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java
index af543c6c798..0a21815789d 100644
---
a/server/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java
+++
b/server/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java
@@ -272,7 +272,8 @@ public class DirectDownloadManagerImpl extends ManagerBase
implements DirectDown
PrimaryDataStoreTO to = (PrimaryDataStoreTO) primaryDataStore.getTO();
DownloadProtocol protocol = getProtocolFromUrl(url);
- DirectDownloadCommand cmd =
getDirectDownloadCommandFromProtocol(protocol, url, templateId, to, checksum,
headers);
+ DirectDownloadCommand cmd =
getDirectDownloadCommandFromProtocol(protocol, url, templateId, to, checksum,
+ headers);
cmd.setTemplateSize(template.getSize());
cmd.setFormat(template.getFormat());
@@ -393,19 +394,23 @@ public class DirectDownloadManagerImpl extends
ManagerBase implements DirectDown
/**
* Return DirectDownloadCommand according to the protocol
*/
- private DirectDownloadCommand
getDirectDownloadCommandFromProtocol(DownloadProtocol protocol, String url,
Long templateId, PrimaryDataStoreTO destPool,
- String
checksum, Map<String, String> httpHeaders) {
+ private DirectDownloadCommand
getDirectDownloadCommandFromProtocol(DownloadProtocol protocol, String url,
+ Long templateId, PrimaryDataStoreTO destPool, String checksum,
Map<String, String> httpHeaders) {
int connectTimeout = DirectDownloadConnectTimeout.value();
int soTimeout = DirectDownloadSocketTimeout.value();
int connectionRequestTimeout =
DirectDownloadConnectionRequestTimeout.value();
+ boolean followRedirects =
StorageManager.DataStoreDownloadFollowRedirects.value();
if (protocol.equals(DownloadProtocol.HTTP)) {
- return new HttpDirectDownloadCommand(url, templateId, destPool,
checksum, httpHeaders, connectTimeout, soTimeout);
+ return new HttpDirectDownloadCommand(url, templateId, destPool,
checksum, httpHeaders, connectTimeout,
+ soTimeout, followRedirects);
} else if (protocol.equals(DownloadProtocol.HTTPS)) {
- return new HttpsDirectDownloadCommand(url, templateId, destPool,
checksum, httpHeaders, connectTimeout, soTimeout, connectionRequestTimeout);
+ return new HttpsDirectDownloadCommand(url, templateId, destPool,
checksum, httpHeaders, connectTimeout,
+ soTimeout, connectionRequestTimeout, followRedirects);
} else if (protocol.equals(DownloadProtocol.NFS)) {
return new NfsDirectDownloadCommand(url, templateId, destPool,
checksum, httpHeaders);
} else if (protocol.equals(DownloadProtocol.METALINK)) {
- return new MetalinkDirectDownloadCommand(url, templateId,
destPool, checksum, httpHeaders, connectTimeout, soTimeout);
+ return new MetalinkDirectDownloadCommand(url, templateId,
destPool, checksum, httpHeaders, connectTimeout,
+ soTimeout, followRedirects);
} else {
return null;
}
diff --git a/server/src/test/java/com/cloud/storage/StorageManagerImplTest.java
b/server/src/test/java/com/cloud/storage/StorageManagerImplTest.java
index 20e1be95e52..ecbc9505e04 100644
--- a/server/src/test/java/com/cloud/storage/StorageManagerImplTest.java
+++ b/server/src/test/java/com/cloud/storage/StorageManagerImplTest.java
@@ -19,6 +19,8 @@ package com.cloud.storage;
import java.util.ArrayList;
import java.util.List;
+import org.apache.cloudstack.framework.config.ConfigDepot;
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.junit.Assert;
@@ -31,6 +33,8 @@ import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import com.cloud.agent.api.StoragePoolInfo;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.dao.DataCenterDao;
import com.cloud.host.Host;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.vm.VMInstanceVO;
@@ -44,6 +48,12 @@ public class StorageManagerImplTest {
@Mock
VMInstanceDao vmInstanceDao;
+ @Mock
+ ConfigDepot configDepot;
+ @Mock
+ ConfigurationDao configurationDao;
+ @Mock
+ DataCenterDao dataCenterDao;
@Spy
@InjectMocks
@@ -155,7 +165,38 @@ public class StorageManagerImplTest {
PrimaryDataStoreDao storagePoolDao =
Mockito.mock(PrimaryDataStoreDao.class);
storageManagerImpl._storagePoolDao = storagePoolDao;
Assert.assertTrue(storageManagerImpl.storagePoolCompatibleWithVolumePool(storagePool,
volume));
+ }
+ @Test
+ public void
testEnableDefaultDatastoreDownloadRedirectionForExistingInstallationsNoChange()
{
+
Mockito.when(configDepot.isNewConfig(StorageManager.DataStoreDownloadFollowRedirects))
+ .thenReturn(false);
+
storageManagerImpl.enableDefaultDatastoreDownloadRedirectionForExistingInstallations();
+ Mockito.verify(configurationDao,
Mockito.never()).update(Mockito.anyString(), Mockito.anyString());
+ }
+
+ @Test
+ public void
testEnableDefaultDatastoreDownloadRedirectionForExistingInstallationsOldInstall()
{
+
Mockito.when(configDepot.isNewConfig(StorageManager.DataStoreDownloadFollowRedirects))
+ .thenReturn(true);
+ Mockito.when(dataCenterDao.listAll(Mockito.any()))
+ .thenReturn(List.of(Mockito.mock(DataCenterVO.class)));
+
Mockito.doReturn(true).when(configurationDao).update(Mockito.anyString(),
Mockito.anyString());
+
storageManagerImpl.enableDefaultDatastoreDownloadRedirectionForExistingInstallations();
+ Mockito.verify(configurationDao, Mockito.times(1))
+ .update(StorageManager.DataStoreDownloadFollowRedirects.key(),
"true");
+ }
+
+ @Test
+ public void
testEnableDefaultDatastoreDownloadRedirectionForExistingInstallationsNewInstall()
{
+
Mockito.when(configDepot.isNewConfig(StorageManager.DataStoreDownloadFollowRedirects))
+ .thenReturn(true);
+ Mockito.when(dataCenterDao.listAll(Mockito.any()))
+ .thenReturn(new ArrayList<>()); //new installation
+
storageManagerImpl.enableDefaultDatastoreDownloadRedirectionForExistingInstallations();
+ Mockito.verify(configurationDao, Mockito.never())
+ .update(StorageManager.DataStoreDownloadFollowRedirects.key(),
+
StorageManager.DataStoreDownloadFollowRedirects.defaultValue());
}
}
diff --git
a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManager.java
b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManager.java
index a0417704028..5526835b8f2 100644
---
a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManager.java
+++
b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManager.java
@@ -41,17 +41,21 @@ public interface DownloadManager extends Manager {
* @param hvm whether the template is a hardware virtual machine
* @param accountId the accountId of the iso owner (null if public iso)
* @param descr description of the template
- * @param user username used for authentication to the server
- * @param password password used for authentication to the server
+ * @param userName username used for authentication to the server
+ * @param passwd password used for authentication to the server
* @param maxDownloadSizeInBytes (optional) max download size for the
template, in bytes.
* @param resourceType signifying the type of resource like template,
volume etc.
+ * @param followRedirects whether downloader follows redirections
* @return job-id that can be used to interrogate the status of the
download.
*/
- public String downloadPublicTemplate(long id, String url, String name,
ImageFormat format, boolean hvm, Long accountId, String descr, String cksum,
- String installPathPrefix, String templatePath, String userName, String
passwd, long maxDownloadSizeInBytes, Proxy proxy, ResourceType resourceType);
-
- public String downloadS3Template(S3TO s3, long id, String url, String
name, ImageFormat format, boolean hvm, Long accountId, String descr, String
cksum,
- String installPathPrefix, String user, String password, long
maxTemplateSizeInBytes, Proxy proxy, ResourceType resourceType);
+ public String downloadPublicTemplate(long id, String url, String name,
ImageFormat format, boolean hvm,
+ Long accountId, String descr, String cksum, String
installPathPrefix, String templatePath,
+ String userName, String passwd, long maxDownloadSizeInBytes,
Proxy proxy, ResourceType resourceType,
+ boolean followRedirects);
+
+ public String downloadS3Template(S3TO s3, long id, String url, String
name, ImageFormat format, boolean hvm,
+ Long accountId, String descr, String cksum, String
installPathPrefix, String user, String password,
+ long maxTemplateSizeInBytes, Proxy proxy, ResourceType
resourceType, boolean followRedirects);
Map<String, Processor> getProcessors();
diff --git
a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManagerImpl.java
b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManagerImpl.java
index f647b497f58..e14977682b6 100644
---
a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManagerImpl.java
+++
b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManagerImpl.java
@@ -549,8 +549,9 @@ public class DownloadManagerImpl extends ManagerBase
implements DownloadManager
}
@Override
- public String downloadS3Template(S3TO s3, long id, String url, String
name, ImageFormat format, boolean hvm, Long accountId, String descr, String
cksum,
- String installPathPrefix, String user, String password, long
maxTemplateSizeInBytes, Proxy proxy, ResourceType resourceType) {
+ public String downloadS3Template(S3TO s3, long id, String url, String
name, ImageFormat format, boolean hvm,
+ Long accountId, String descr, String cksum, String
installPathPrefix, String user, String password,
+ long maxTemplateSizeInBytes, Proxy proxy, ResourceType
resourceType, boolean followRedirects) {
UUID uuid = UUID.randomUUID();
String jobId = uuid.toString();
@@ -570,6 +571,7 @@ public class DownloadManagerImpl extends ManagerBase
implements DownloadManager
} else {
throw new CloudRuntimeException("Unable to download from URL: " +
url);
}
+ td.setFollowRedirects(followRedirects);
DownloadJob dj = new DownloadJob(td, jobId, id, name, format, hvm,
accountId, descr, cksum, installPathPrefix, resourceType);
dj.setTmpltPath(installPathPrefix);
jobs.put(jobId, dj);
@@ -579,8 +581,10 @@ public class DownloadManagerImpl extends ManagerBase
implements DownloadManager
}
@Override
- public String downloadPublicTemplate(long id, String url, String name,
ImageFormat format, boolean hvm, Long accountId, String descr, String cksum,
- String installPathPrefix, String templatePath, String user, String
password, long maxTemplateSizeInBytes, Proxy proxy, ResourceType resourceType) {
+ public String downloadPublicTemplate(long id, String url, String name,
ImageFormat format, boolean hvm,
+ Long accountId, String descr, String cksum, String
installPathPrefix, String templatePath, String user,
+ String password, long maxTemplateSizeInBytes, Proxy proxy,
ResourceType resourceType,
+ boolean followRedirects) {
UUID uuid = UUID.randomUUID();
String jobId = uuid.toString();
String tmpDir = installPathPrefix;
@@ -632,6 +636,7 @@ public class DownloadManagerImpl extends ManagerBase
implements DownloadManager
} else {
throw new CloudRuntimeException("Unable to download
from URL: " + url);
}
+ td.setFollowRedirects(followRedirects);
// NOTE the difference between installPathPrefix and
templatePath
// here. instalPathPrefix is the absolute path for template
// including mount directory
@@ -768,12 +773,16 @@ public class DownloadManagerImpl extends ManagerBase
implements DownloadManager
String jobId = null;
if (dstore instanceof S3TO) {
jobId =
- downloadS3Template((S3TO)dstore, cmd.getId(),
cmd.getUrl(), cmd.getName(), cmd.getFormat(), cmd.isHvm(), cmd.getAccountId(),
cmd.getDescription(),
- cmd.getChecksum(), installPathPrefix, user,
password, maxDownloadSizeInBytes, cmd.getProxy(), resourceType);
+ downloadS3Template((S3TO)dstore, cmd.getId(),
cmd.getUrl(), cmd.getName(), cmd.getFormat(),
+ cmd.isHvm(), cmd.getAccountId(),
cmd.getDescription(), cmd.getChecksum(),
+ installPathPrefix, user, password,
maxDownloadSizeInBytes, cmd.getProxy(), resourceType,
+ cmd.isFollowRedirects());
} else {
jobId =
- downloadPublicTemplate(cmd.getId(), cmd.getUrl(),
cmd.getName(), cmd.getFormat(), cmd.isHvm(), cmd.getAccountId(),
cmd.getDescription(),
- cmd.getChecksum(), installPathPrefix,
cmd.getInstallPath(), user, password, maxDownloadSizeInBytes, cmd.getProxy(),
resourceType);
+ downloadPublicTemplate(cmd.getId(), cmd.getUrl(),
cmd.getName(), cmd.getFormat(), cmd.isHvm(),
+ cmd.getAccountId(), cmd.getDescription(),
cmd.getChecksum(), installPathPrefix,
+ cmd.getInstallPath(), user, password,
maxDownloadSizeInBytes, cmd.getProxy(), resourceType,
+ cmd.isFollowRedirects());
}
sleep();
if (jobId == null) {
diff --git a/utils/src/main/java/com/cloud/utils/UriUtils.java
b/utils/src/main/java/com/cloud/utils/UriUtils.java
index a2bfa9eaa6f..7327218a897 100644
--- a/utils/src/main/java/com/cloud/utils/UriUtils.java
+++ b/utils/src/main/java/com/cloud/utils/UriUtils.java
@@ -213,7 +213,7 @@ public class UriUtils {
}
// Get the size of a file from URL response header.
- public static long getRemoteSize(String url) {
+ public static long getRemoteSize(String url, Boolean followRedirect) {
long remoteSize = 0L;
final String[] methods = new String[]{"HEAD", "GET"};
IllegalArgumentException exception = null;
@@ -228,6 +228,7 @@ public class UriUtils {
httpConn.setRequestMethod(method);
httpConn.setConnectTimeout(2000);
httpConn.setReadTimeout(5000);
+
httpConn.setInstanceFollowRedirects(Boolean.TRUE.equals(followRedirect));
String contentLength =
httpConn.getHeaderField("content-length");
if (contentLength != null) {
remoteSize = Long.parseLong(contentLength);
diff --git a/utils/src/main/java/com/cloud/utils/storage/QCOW2Utils.java
b/utils/src/main/java/com/cloud/utils/storage/QCOW2Utils.java
index 4daf138bb8c..300fc4da1fe 100644
--- a/utils/src/main/java/com/cloud/utils/storage/QCOW2Utils.java
+++ b/utils/src/main/java/com/cloud/utils/storage/QCOW2Utils.java
@@ -22,8 +22,9 @@ package com.cloud.utils.storage;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
@@ -32,7 +33,6 @@ import
org.apache.commons.compress.compressors.CompressorStreamFactory;
import org.apache.log4j.Logger;
import com.cloud.utils.NumbersUtil;
-import com.cloud.utils.UriUtils;
public final class QCOW2Utils {
public static final Logger LOGGER =
Logger.getLogger(QCOW2Utils.class.getName());
@@ -112,16 +112,23 @@ public final class QCOW2Utils {
}
}
- public static long getVirtualSize(String urlStr) {
+ public static long getVirtualSizeFromUrl(String urlStr, boolean
followRedirects) {
+ HttpURLConnection httpConn = null;
try {
- URL url = new URL(urlStr);
- return getVirtualSize(url.openStream(),
UriUtils.isUrlForCompressedFile(urlStr));
- } catch (MalformedURLException e) {
+ URI url = new URI(urlStr);
+ httpConn = (HttpURLConnection)url.toURL().openConnection();
+ httpConn.setInstanceFollowRedirects(followRedirects);
+ return getVirtualSizeFromInputStream(httpConn.getInputStream());
+ } catch (URISyntaxException e) {
LOGGER.warn("Failed to validate for qcow2, malformed URL: " +
urlStr + ", error: " + e.getMessage());
throw new IllegalArgumentException("Invalid URL: " + urlStr);
} catch (IOException e) {
LOGGER.warn("Failed to validate for qcow2, error: " +
e.getMessage());
throw new IllegalArgumentException("Failed to connect URL: " +
urlStr);
+ } finally {
+ if (httpConn != null) {
+ httpConn.disconnect();
+ }
}
}
}