From 3de5d9db5fa0b3196a00784ffc2c04b998f64de2 Mon Sep 17 00:00:00 2001 From: Rajani Karuturi Date: Mon, 16 Mar 2015 12:41:58 +0530 Subject: [PATCH 1/5] volume upload: Restart of MS leads to loss of browser uploaded templates on restart of management server, template sync runs. It checks for templates in ssvm using the uniquename. If it doesnt find any, cleans the directory. In case of uploaded templates, these are getting saved using name instead on uniquename and hence template sync cant find them and does cleanup. Using uniquename in template.properties now. --- .../command/TemplateOrVolumePostUploadCommand.java | 10 ++++++++++ .../com/cloud/template/HypervisorTemplateAdapter.java | 3 ++- .../storage/resource/NfsSecondaryStorageResource.java | 7 ++++--- .../cloudstack/storage/template/UploadEntity.java | 9 +++++++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java b/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java index cc9df7146a3..0a5f1d68951 100644 --- a/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java +++ b/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java @@ -47,6 +47,8 @@ public class TemplateOrVolumePostUploadCommand { String maxUploadSize; + String description; + public TemplateOrVolumePostUploadCommand(long entityId, String entityUUID, String absolutePath, String checksum, String type, String name, String imageFormat, String dataTo, String dataToRole) { this.entityId = entityId; @@ -166,4 +168,12 @@ public class TemplateOrVolumePostUploadCommand { public void setMaxUploadSize(String maxUploadSize) { this.maxUploadSize = maxUploadSize; } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } } diff --git a/server/src/com/cloud/template/HypervisorTemplateAdapter.java b/server/src/com/cloud/template/HypervisorTemplateAdapter.java index 0cb48fc07c5..1ad2135a695 100755 --- a/server/src/com/cloud/template/HypervisorTemplateAdapter.java +++ b/server/src/com/cloud/template/HypervisorTemplateAdapter.java @@ -258,12 +258,13 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase { } TemplateOrVolumePostUploadCommand payload = new TemplateOrVolumePostUploadCommand(template.getId(), template.getUuid(), tmpl.getInstallPath(), tmpl.getChecksum(), tmpl - .getType().toString(), template.getName(), template.getFormat().toString(), templateOnStore.getDataStore().getUri(), templateOnStore.getDataStore().getRole() + .getType().toString(), template.getUniqueName(), template.getFormat().toString(), templateOnStore.getDataStore().getUri(), templateOnStore.getDataStore().getRole() .toString()); //using the existing max template size configuration payload.setMaxUploadSize(_configDao.getValue(Config.MaxTemplateAndIsoSize.key())); payload.setRemoteEndPoint(ep.getPublicAddr()); payload.setRequiresHvm(template.requiresHvm()); + payload.setDescription(template.getDisplayText()); payloads.add(payload); } _resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template); diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index 236498c4535..d10242c9e04 100755 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -2634,6 +2634,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S uploadEntity.setHvm(cmd.getRequiresHvm()); uploadEntity.setChksum(cmd.getChecksum()); uploadEntity.setMaxSizeInGB(maxSizeInGB); + uploadEntity.setDescription(cmd.getDescription()); // create a install dir if (!_storage.exists(installPathPrefix)) { _storage.mkdir(installPathPrefix); @@ -2677,9 +2678,9 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S Script scr = new Script(getScriptLocation(resourceType), timeout, s_logger); scr.add("-s", Integer.toString(imgSizeGigs)); scr.add("-S", Long.toString(UploadEntity.s_maxTemplateSize)); - //if (uploadEntity.getDescription() != null && dnld.getDescription().length() > 1) { - // scr.add("-d", dnld.getDescription()); - //} + if (uploadEntity.getDescription() != null && uploadEntity.getDescription().length() > 1) { + scr.add("-d", uploadEntity.getDescription()); + } if (uploadEntity.isHvm()) { scr.add("-h"); } diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/UploadEntity.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/UploadEntity.java index 15a6ef28c66..e9444c23d7b 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/UploadEntity.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/UploadEntity.java @@ -32,6 +32,7 @@ public class UploadEntity { private String chksum; private long physicalSize; private int maxSizeInGB; + private String description; public static enum ResourceType { VOLUME, TEMPLATE @@ -180,4 +181,12 @@ public class UploadEntity { public void setMaxSizeInGB(int maxSizeInGB) { this.maxSizeInGB = maxSizeInGB; } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } } From 7d1ca8a55c352ad2186dad47a6cdd3eea59e9e23 Mon Sep 17 00:00:00 2001 From: Rajani Karuturi Date: Tue, 17 Mar 2015 09:45:01 +0530 Subject: [PATCH 2/5] Fixed NPE with getUploadParamsForTemplate API call if isdynamicallyscalable optional parameter is not specified, its trying to cast null to Boolean and throws NPE --- .../command/user/template/GetUploadParamsForTemplateCmd.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/src/org/apache/cloudstack/api/command/user/template/GetUploadParamsForTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/GetUploadParamsForTemplateCmd.java index 79f920fc212..d1dc46898c0 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/GetUploadParamsForTemplateCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/GetUploadParamsForTemplateCmd.java @@ -109,6 +109,9 @@ public class GetUploadParamsForTemplateCmd extends AbstractGetUploadParamsCmd { } public Boolean isDynamicallyScalable() { + if (isDynamicallyScalable == null) { + return Boolean.FALSE; + } return isDynamicallyScalable; } From 6b8b4b92e6d5ec36d4b976e81083f72ae17245a3 Mon Sep 17 00:00:00 2001 From: Rajani Karuturi Date: Tue, 17 Mar 2015 15:17:33 +0530 Subject: [PATCH 3/5] handling tcp close event in netty server while the file is in uploading state and connection is reset by peer, volume upload request posted again shows the upload is IN_Progress state. marking them as errored --- .../storage/resource/HttpUploadServerHandler.java | 7 +++++++ .../storage/resource/NfsSecondaryStorageResource.java | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java index 7a17ef19d49..0caee32601c 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java @@ -94,6 +94,13 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler Date: Wed, 18 Mar 2015 12:17:15 +0530 Subject: [PATCH 4/5] volume upload: added md5 checksum validation also fixed the issue wherein the successful uploads where also moving to error state as the channelinactive is called after the end of successful upload as well. added a fileuploaded boolean to check when the channel is inactive. --- .../cloud/storage/VolumeApiServiceImpl.java | 2 +- .../resource/HttpUploadServerHandler.java | 38 +++++++++++-------- .../resource/NfsSecondaryStorageResource.java | 15 ++++---- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/com/cloud/storage/VolumeApiServiceImpl.java index d2c1c69a537..567a7426b5d 100644 --- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java @@ -333,7 +333,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic * encoded metadata using the post upload config key */ TemplateOrVolumePostUploadCommand command = - new TemplateOrVolumePostUploadCommand(vol.getId(), vol.getUuid(), volumeStore.getInstallPath(), volumeStore.getChecksum(), vol.getType().toString(), + new TemplateOrVolumePostUploadCommand(vol.getId(), vol.getUuid(), volumeStore.getInstallPath(), cmd.getChecksum(), vol.getType().toString(), vol.getName(), vol.getFormat().toString(), dataObject.getDataStore().getUri(), dataObject.getDataStore().getRole().toString()); command.setLocalPath(volumeStore.getLocalDownloadPath()); diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java index 0caee32601c..44a2b6043fc 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java @@ -75,6 +75,8 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler maxSize) { - throw new InvalidParameterValueException("Maximum file upload size exceeded. Physical file size: "+imgSizeGigs+"GB. Maximum allowed size: "+maxSize+"GB."); + String errorMessage = "Maximum file upload size exceeded. Physical file size: " + imgSizeGigs + "GB. Maximum allowed size: " + maxSize + "GB."; + s_logger.error(errorMessage); + return errorMessage; } imgSizeGigs++; // add one just in case long timeout = (long)imgSizeGigs * installTimeoutPerGig; @@ -2684,6 +2681,10 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S if (uploadEntity.isHvm()) { scr.add("-h"); } + String checkSum = uploadEntity.getChksum(); + if (StringUtils.isNotBlank(checkSum)) { + scr.add("-c", checkSum); + } // add options common to ISO and template String extension = uploadEntity.getFormat().getFileExtension(); @@ -2734,7 +2735,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S } catch (IOException e) { s_logger.warn("Something is wrong with template location " + resourcePath, e); loc.purge(); - return "Unable to download due to " + e.getMessage(); + return "Unable to upload due to " + e.getMessage(); } Map processors = _dlMgr.getProcessors(); From 018023c1ef7fc5216a607e40811ff20f185d295c Mon Sep 17 00:00:00 2001 From: Rajani Karuturi Date: Thu, 19 Mar 2015 11:54:51 +0530 Subject: [PATCH 5/5] volume upload: added validation for file formats merged TemplateUtils and ImageStoreUtil to a singe ImageStoreUtil also added a unittest for ImageStoreUtil --- .../template/HttpTemplateDownloader.java | 4 +- .../cloud/storage/VolumeApiServiceImpl.java | 2 +- .../cloud/template/TemplateManagerImpl.java | 2 +- .../resource/HttpUploadServerHandler.java | 10 +++ .../resource/NfsSecondaryStorageResource.java | 14 ++++ utils/src/com/cloud/utils/ImageStoreUtil.java | 39 ----------- .../ImageStoreUtil.java} | 65 +++++++++++-------- .../utils/imagestore/ImageStoreUtilTest.java | 38 +++++++++++ 8 files changed, 105 insertions(+), 69 deletions(-) delete mode 100644 utils/src/com/cloud/utils/ImageStoreUtil.java rename utils/src/org/apache/cloudstack/utils/{template/TemplateUtils.java => imagestore/ImageStoreUtil.java} (61%) create mode 100644 utils/test/org/apache/cloudstack/utils/imagestore/ImageStoreUtilTest.java diff --git a/core/src/com/cloud/storage/template/HttpTemplateDownloader.java b/core/src/com/cloud/storage/template/HttpTemplateDownloader.java index 5644af4f8e8..632a80963e9 100644 --- a/core/src/com/cloud/storage/template/HttpTemplateDownloader.java +++ b/core/src/com/cloud/storage/template/HttpTemplateDownloader.java @@ -28,6 +28,7 @@ import java.net.URISyntaxException; import java.net.URL; import java.util.Date; +import org.apache.cloudstack.utils.imagestore.ImageStoreUtil; import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpClient; @@ -45,7 +46,6 @@ import org.apache.log4j.Logger; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.storage.command.DownloadCommand.ResourceType; -import org.apache.cloudstack.utils.template.TemplateUtils; import com.cloud.agent.api.storage.Proxy; import com.cloud.storage.StorageLayer; @@ -259,7 +259,7 @@ public class HttpTemplateDownloader extends ManagedContextRunnable implements Te } catch (URISyntaxException e) { s_logger.warn("Invalid download url: " + getDownloadUrl() + ", This should not happen since we have validated the url before!!"); } - String unsupportedFormat = TemplateUtils.checkTemplateFormat(file.getAbsolutePath(), uripath); + String unsupportedFormat = ImageStoreUtil.checkTemplateFormat(file.getAbsolutePath(), uripath); if (unsupportedFormat == null || !unsupportedFormat.isEmpty()) { try { request.abort(); diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/com/cloud/storage/VolumeApiServiceImpl.java index 567a7426b5d..4ff7686cab8 100644 --- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java @@ -29,7 +29,6 @@ import java.util.concurrent.ExecutionException; import javax.inject.Inject; import com.cloud.utils.EncryptionUtil; -import com.cloud.utils.ImageStoreUtil; import com.cloud.utils.db.TransactionCallbackWithException; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -39,6 +38,7 @@ import org.apache.cloudstack.api.response.GetUploadParamsResponse; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand; +import org.apache.cloudstack.utils.imagestore.ImageStoreUtil; import org.apache.log4j.Logger; import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 9747ad00f6f..10ff77f5dd2 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -35,13 +35,13 @@ import javax.naming.ConfigurationException; import com.cloud.storage.ImageStoreUploadMonitorImpl; import com.cloud.utils.EncryptionUtil; -import com.cloud.utils.ImageStoreUtil; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import org.apache.cloudstack.api.command.user.template.GetUploadParamsForTemplateCmd; import org.apache.cloudstack.api.response.GetUploadParamsResponse; import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand; +import org.apache.cloudstack.utils.imagestore.ImageStoreUtil; import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import org.apache.cloudstack.acl.SecurityChecker.AccessType; diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java index 44a2b6043fc..4a3fa86d9d8 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java @@ -28,6 +28,8 @@ import java.util.Map; import java.util.Map.Entry; import org.apache.cloudstack.storage.template.UploadEntity; +import org.apache.cloudstack.utils.imagestore.ImageStoreUtil; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import com.cloud.exception.InvalidParameterValueException; @@ -228,6 +230,14 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler maxSize) { diff --git a/utils/src/com/cloud/utils/ImageStoreUtil.java b/utils/src/com/cloud/utils/ImageStoreUtil.java deleted file mode 100644 index 52f13244c16..00000000000 --- a/utils/src/com/cloud/utils/ImageStoreUtil.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package com.cloud.utils; - -import org.apache.log4j.Logger; - -public class ImageStoreUtil { - public static final Logger s_logger = Logger.getLogger(ImageStoreUtil.class.getName()); - - public static String generatePostUploadUrl(String ssvmUrlDomain, String ipAddress, String uuid) { - String hostname = ipAddress; - - //if ssvm url domain is present, use it to construct hostname in the format 1-2-3-4.domain - // if the domain name is not present, ssl validation fails and has to be ignored - if(StringUtils.isNotBlank(ssvmUrlDomain)) { - hostname = ipAddress.replace(".", "-"); - hostname = hostname + ssvmUrlDomain.substring(1); - } - - //only https works with postupload and url format is fixed - return "https://" + hostname + "/upload/" + uuid; - } -} diff --git a/utils/src/org/apache/cloudstack/utils/template/TemplateUtils.java b/utils/src/org/apache/cloudstack/utils/imagestore/ImageStoreUtil.java similarity index 61% rename from utils/src/org/apache/cloudstack/utils/template/TemplateUtils.java rename to utils/src/org/apache/cloudstack/utils/imagestore/ImageStoreUtil.java index 53aa9113a9b..ed1336027eb 100644 --- a/utils/src/org/apache/cloudstack/utils/template/TemplateUtils.java +++ b/utils/src/org/apache/cloudstack/utils/imagestore/ImageStoreUtil.java @@ -1,30 +1,43 @@ -// -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -package org.apache.cloudstack.utils.template; - -import org.apache.log4j.Logger; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.utils.imagestore; import com.cloud.utils.script.Script; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; -public class TemplateUtils { - public static final Logger s_logger = Logger.getLogger(TemplateUtils.class.getName()); +public class ImageStoreUtil { + public static final Logger s_logger = Logger.getLogger(ImageStoreUtil.class.getName()); + + public static String generatePostUploadUrl(String ssvmUrlDomain, String ipAddress, String uuid) { + String hostname = ipAddress; + + //if ssvm url domain is present, use it to construct hostname in the format 1-2-3-4.domain + // if the domain name is not present, ssl validation fails and has to be ignored + if(StringUtils.isNotBlank(ssvmUrlDomain)) { + hostname = ipAddress.replace(".", "-"); + hostname = hostname + ssvmUrlDomain.substring(1); + } + + //only https works with postupload and url format is fixed + return "https://" + hostname + "/upload/" + uuid; + } // given a path, returns empty if path is supported image, and the file type if unsupported // this is meant to catch things like accidental upload of ASCII text .vmdk descriptor @@ -75,7 +88,7 @@ public class TemplateUtils { return output; } - public static boolean isCorrectExtension(String path, String ext) { + private static boolean isCorrectExtension(String path, String ext) { if (path.toLowerCase().endsWith(ext) || path.toLowerCase().endsWith(ext + ".gz") || path.toLowerCase().endsWith(ext + ".bz2") @@ -85,7 +98,7 @@ public class TemplateUtils { return false; } - public static boolean isCompressedExtension(String path) { + private static boolean isCompressedExtension(String path) { if (path.toLowerCase().endsWith(".gz") || path.toLowerCase().endsWith(".bz2") || path.toLowerCase().endsWith(".zip")) { diff --git a/utils/test/org/apache/cloudstack/utils/imagestore/ImageStoreUtilTest.java b/utils/test/org/apache/cloudstack/utils/imagestore/ImageStoreUtilTest.java new file mode 100644 index 00000000000..e1b55780442 --- /dev/null +++ b/utils/test/org/apache/cloudstack/utils/imagestore/ImageStoreUtilTest.java @@ -0,0 +1,38 @@ +package org.apache.cloudstack.utils.imagestore; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.UUID; + +import org.junit.Assert; +import org.junit.Test; + +public class ImageStoreUtilTest { + + @Test + public void testgeneratePostUploadUrl() throws MalformedURLException { + String ssvmdomain = "*.realhostip.com"; + String ipAddress = "10.147.28.14"; + String uuid = UUID.randomUUID().toString(); + + //ssvm domain is not set + String url = ImageStoreUtil.generatePostUploadUrl(null, ipAddress, uuid); + assertPostUploadUrl(url, ipAddress, uuid); + + //ssvm domain is set to empty value + url = ImageStoreUtil.generatePostUploadUrl("", ipAddress, uuid); + assertPostUploadUrl(url, ipAddress, uuid); + + //ssvm domain is set to a valid value + url = ImageStoreUtil.generatePostUploadUrl(ssvmdomain, ipAddress, uuid); + assertPostUploadUrl(url, ipAddress.replace(".", "-") + ssvmdomain.substring(1), uuid); + } + + private void assertPostUploadUrl(String urlStr, String domain, String uuid) throws MalformedURLException { + URL url = new URL(urlStr); + Assert.assertNotNull(url); + Assert.assertEquals(url.getHost(), domain); + Assert.assertEquals(url.getPath(), "/upload/" + uuid); + } + +} \ No newline at end of file