diff --git a/engine/storage/configdrive/src/org/apache/cloudstack/storage/configdrive/ConfigDrive.java b/engine/storage/configdrive/src/org/apache/cloudstack/storage/configdrive/ConfigDrive.java index ec461991537..07cfdc883ca 100644 --- a/engine/storage/configdrive/src/org/apache/cloudstack/storage/configdrive/ConfigDrive.java +++ b/engine/storage/configdrive/src/org/apache/cloudstack/storage/configdrive/ConfigDrive.java @@ -26,11 +26,12 @@ public class ConfigDrive { public static final String openStackConfigDriveName = "/openstack/latest/"; /** - * This is the path to iso file relative to mount point - * @return config drive iso file path + * Creates the path to ISO file relative to mount point. + * The config driver path will have the following formated: {@link #CONFIGDRIVEDIR} + / + instanceName + / + {@link #CONFIGDRIVEFILENAME} + * + * @return config drive ISO file path */ - public static String createConfigDrivePath(final String instanceName) { + public static String createConfigDrivePath(String instanceName) { return ConfigDrive.CONFIGDRIVEDIR + "/" + instanceName + "/" + ConfigDrive.CONFIGDRIVEFILENAME; } - -} +} \ No newline at end of file diff --git a/engine/storage/configdrive/src/org/apache/cloudstack/storage/configdrive/ConfigDriveBuilder.java b/engine/storage/configdrive/src/org/apache/cloudstack/storage/configdrive/ConfigDriveBuilder.java index d847aa1d1d7..dc6b8893495 100644 --- a/engine/storage/configdrive/src/org/apache/cloudstack/storage/configdrive/ConfigDriveBuilder.java +++ b/engine/storage/configdrive/src/org/apache/cloudstack/storage/configdrive/ConfigDriveBuilder.java @@ -23,9 +23,7 @@ import static com.cloud.network.NetworkModel.CONFIGDATA_FILE; import static com.cloud.network.NetworkModel.PASSWORD_FILE; import static com.cloud.network.NetworkModel.USERDATA_FILE; -import java.io.BufferedWriter; import java.io.File; -import java.io.FileWriter; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -42,7 +40,6 @@ import org.joda.time.Duration; import com.cloud.network.NetworkModel; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; -import com.google.common.base.Strings; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -51,30 +48,45 @@ public class ConfigDriveBuilder { public static final Logger LOG = Logger.getLogger(ConfigDriveBuilder.class); - private static void writeFile(final File folder, final String file, final String content) { - if (folder == null || Strings.isNullOrEmpty(file)) { - return; - } - final File vendorDataFile = new File(folder, file); - try (final FileWriter fw = new FileWriter(vendorDataFile); final BufferedWriter bw = new BufferedWriter(fw)) { - bw.write(content); + /** + * Writes a content {@link String} to a file that is going to be created in a folder. We will not append to the file if it already exists. Therefore, its content will be overwritten. + * Moreover, the charset used is {@link com.cloud.utils.StringUtils#getPreferredCharset()}. + * + * We expect the folder object and the file not to be null/empty. + */ + static void writeFile(File folder, String file, String content) { + try { + FileUtils.write(new File(folder, file), content, com.cloud.utils.StringUtils.getPreferredCharset(), false); } catch (IOException ex) { throw new CloudRuntimeException("Failed to create config drive file " + file, ex); } } - public static String fileToBase64String(final File isoFile) throws IOException { + /** + * Read the content of a {@link File} and convert it to a String in base 64. + * We expect the content of the file to be encoded using {@link StandardCharsets#US_ASC} + */ + public static String fileToBase64String(File isoFile) throws IOException { byte[] encoded = Base64.encodeBase64(FileUtils.readFileToByteArray(isoFile)); return new String(encoded, StandardCharsets.US_ASCII); } - public static File base64StringToFile(final String encodedIsoData, final String folder, final String fileName) throws IOException { + /** + * Writes a String encoded in base 64 to a file in the given folder. + * The content will be decoded and then written to the file. Be aware that we will overwrite the content of the file if it already exists. + * Moreover, the content will must be encoded in {@link StandardCharsets#US_ASCII} before it is encoded in base 64. + */ + public static File base64StringToFile(String encodedIsoData, String folder, String fileName) throws IOException { byte[] decoded = Base64.decodeBase64(encodedIsoData.getBytes(StandardCharsets.US_ASCII)); Path destPath = Paths.get(folder, fileName); return Files.write(destPath, decoded).toFile(); } - public static String buildConfigDrive(final List vmData, final String isoFileName, final String driveLabel) { + /** + * This method will build the metadata files required by OpenStack driver. Then, an ISO is going to be generated and returned as a String in base 64. + * If vmData is null, we throw a {@link CloudRuntimeException}. Moreover, {@link IOException} are captured and re-thrown as {@link CloudRuntimeException}. + */ + public static String buildConfigDrive(List vmData, String isoFileName, String driveLabel) { if (vmData == null) { throw new CloudRuntimeException("No VM metadata provided"); } @@ -86,103 +98,180 @@ public class ConfigDriveBuilder { tempDirName = tempDir.toString(); File openStackFolder = new File(tempDirName + ConfigDrive.openStackConfigDriveName); - if (openStackFolder.exists() || openStackFolder.mkdirs()) { - writeFile(openStackFolder, "vendor_data.json", "{}"); - writeFile(openStackFolder, "network_data.json", "{}"); - } else { - throw new CloudRuntimeException("Failed to create folder " + openStackFolder); - } - JsonObject metaData = new JsonObject(); - for (String[] item : vmData) { - String dataType = item[CONFIGDATA_DIR]; - String fileName = item[CONFIGDATA_FILE]; - String content = item[CONFIGDATA_CONTENT]; - LOG.debug(String.format("[createConfigDriveIsoForVM] dataType=%s, filename=%s, content=%s", - dataType, fileName, (fileName.equals(PASSWORD_FILE)?"********":content))); + writeVendorAndNetworkEmptyJsonFile(openStackFolder); + writeVmMetadata(vmData, tempDirName, openStackFolder); - // create file with content in folder - if (dataType != null && !dataType.isEmpty()) { - //create folder - File typeFolder = new File(tempDirName + ConfigDrive.cloudStackConfigDriveName + dataType); - if (typeFolder.exists() || typeFolder.mkdirs()) { - if (StringUtils.isNotEmpty(content)) { - File file = new File(typeFolder, fileName + ".txt"); - try { - if (fileName.equals(USERDATA_FILE)) { - // User Data is passed as a base64 encoded string - FileUtils.writeByteArrayToFile(file, Base64.decodeBase64(content)); - } else { - FileUtils.write(file, content, com.cloud.utils.StringUtils.getPreferredCharset()); - } - } catch (IOException ex) { - throw new CloudRuntimeException("Failed to create file ", ex); - } - } - } else { - throw new CloudRuntimeException("Failed to create folder: " + typeFolder); - } + linkUserData(tempDirName); - //now write the file to the OpenStack directory - metaData = buildOpenStackMetaData(metaData, dataType, fileName, content); - } - } - writeFile(openStackFolder, "meta_data.json", metaData.toString()); - - String linkResult = linkUserData(tempDirName); - if (linkResult != null) { - String errMsg = "Unable to create user_data link due to " + linkResult; - throw new CloudRuntimeException(errMsg); - } - - File tmpIsoStore = new File(tempDirName, new File(isoFileName).getName()); - Script command = new Script("/usr/bin/genisoimage", Duration.standardSeconds(300), LOG); - command.add("-o", tmpIsoStore.getAbsolutePath()); - command.add("-ldots"); - command.add("-allow-lowercase"); - command.add("-allow-multidot"); - command.add("-cache-inodes"); // Enable caching inode and device numbers to find hard links to files. - command.add("-l"); - command.add("-quiet"); - command.add("-J"); - command.add("-r"); - command.add("-V", driveLabel); - command.add(tempDirName); - LOG.debug("Executing config drive creation command: " + command.toString()); - String result = command.execute(); - if (result != null) { - String errMsg = "Unable to create iso file: " + isoFileName + " due to " + result; - LOG.warn(errMsg); - throw new CloudRuntimeException(errMsg); - } - File tmpIsoFile = new File(tmpIsoStore.getAbsolutePath()); - // Max allowed file size of config drive is 64MB: https://docs.openstack.org/project-install-guide/baremetal/draft/configdrive.html - if (tmpIsoFile.length() > (64L * 1024L * 1024L)) { - throw new CloudRuntimeException("Config drive file exceeds maximum allowed size of 64MB"); - } - return fileToBase64String(tmpIsoFile); + return generateAndRetrieveIsoAsBase64Iso(isoFileName, driveLabel, tempDirName); } catch (IOException e) { throw new CloudRuntimeException("Failed due to", e); } finally { - try { - FileUtils.deleteDirectory(tempDir.toFile()); - } catch (IOException ioe) { - LOG.warn("Failed to delete ConfigDrive temporary directory: " + tempDirName, ioe); - } + deleteTempDir(tempDir); } } - private static String linkUserData(String tempDirName) { - //Hard link the user_data.txt file with the user_data file in the OpenStack directory. + private static void deleteTempDir(Path tempDir) { + try { + if (tempDir != null) { + FileUtils.deleteDirectory(tempDir.toFile()); + } + } catch (IOException ioe) { + LOG.warn("Failed to delete ConfigDrive temporary directory: " + tempDir.toString(), ioe); + } + } + + /** + * Generates the ISO file that has the tempDir content. + * + * Max allowed file size of config drive is 64MB [1]. Therefore, if the ISO is bigger than that, we throw a {@link CloudRuntimeException}. + * [1] https://docs.openstack.org/project-install-guide/baremetal/draft/configdrive.html + */ + static String generateAndRetrieveIsoAsBase64Iso(String isoFileName, String driveLabel, String tempDirName) throws IOException { + File tmpIsoStore = new File(tempDirName, isoFileName); + Script command = new Script(getProgramToGenerateIso(), Duration.standardSeconds(300), LOG); + command.add("-o", tmpIsoStore.getAbsolutePath()); + command.add("-ldots"); + command.add("-allow-lowercase"); + command.add("-allow-multidot"); + command.add("-cache-inodes"); // Enable caching inode and device numbers to find hard links to files. + command.add("-l"); + command.add("-quiet"); + command.add("-J"); + command.add("-r"); + command.add("-V", driveLabel); + command.add(tempDirName); + LOG.debug("Executing config drive creation command: " + command.toString()); + String result = command.execute(); + if (StringUtils.isNotBlank(result)) { + String errMsg = "Unable to create iso file: " + isoFileName + " due to ge" + result; + LOG.warn(errMsg); + throw new CloudRuntimeException(errMsg); + } + File tmpIsoFile = new File(tmpIsoStore.getAbsolutePath()); + if (tmpIsoFile.length() > (64L * 1024L * 1024L)) { + throw new CloudRuntimeException("Config drive file exceeds maximum allowed size of 64MB"); + } + return fileToBase64String(tmpIsoFile); + } + + /** + * Checks if the 'genisoimage' or 'mkisofs' is available and return the full qualified path for the program. + * The path checked are the following: + * /usr/local/bin/mkisofs + */ + static String getProgramToGenerateIso() throws IOException { + File isoCreator = new File("/usr/bin/genisoimage"); + if (!isoCreator.exists()) { + isoCreator = new File("/usr/bin/mkisofs"); + if (!isoCreator.exists()) { + isoCreator = new File("/usr/local/bin/mkisofs"); + } + } + if (!isoCreator.exists()) { + throw new CloudRuntimeException("Cannot create iso for config drive using any know tool. Known paths [/usr/bin/genisoimage, /usr/bin/mkisofs, /usr/local/bin/mkisofs]"); + } + if (!isoCreator.canExecute()) { + throw new CloudRuntimeException("Cannot create iso for config drive using: " + isoCreator.getCanonicalPath()); + } + return isoCreator.getCanonicalPath(); + } + + /** + * First we generate a JSON object using {@link #createJsonObjectWithVmData(List, String)}, then we write it to a file called "meta_data.json". + */ + static void writeVmMetadata(List vmData, String tempDirName, File openStackFolder) { + JsonObject metaData = createJsonObjectWithVmData(vmData, tempDirName); + writeFile(openStackFolder, "meta_data.json", metaData.toString()); + } + + /** + * Writes the following empty JSON files: + *
    + *
  • vendor_data.json + *
  • network_data.json + *
+ * + * If the folder does not exist and we cannot create it, we throw a {@link CloudRuntimeException}. + */ + static void writeVendorAndNetworkEmptyJsonFile(File openStackFolder) { + if (openStackFolder.exists() || openStackFolder.mkdirs()) { + writeFile(openStackFolder, "vendor_data.json", "{}"); + writeFile(openStackFolder, "network_data.json", "{}"); + } else { + throw new CloudRuntimeException("Failed to create folder " + openStackFolder); + } + } + + /** + * Creates the {@link JsonObject} with VM's metadata. The vmData is a list of arrays; we expect this list to have the following entries: + *
    + *
  • [0]: config data type + *
  • [1]: config data file name + *
  • [2]: config data file content + *
+ */ + static JsonObject createJsonObjectWithVmData(List vmData, String tempDirName) { + JsonObject metaData = new JsonObject(); + for (String[] item : vmData) { + String dataType = item[CONFIGDATA_DIR]; + String fileName = item[CONFIGDATA_FILE]; + String content = item[CONFIGDATA_CONTENT]; + LOG.debug(String.format("[createConfigDriveIsoForVM] dataType=%s, filename=%s, content=%s", dataType, fileName, (PASSWORD_FILE.equals(fileName) ? "********" : content))); + + createFileInTempDirAnAppendOpenStackMetadataToJsonObject(tempDirName, metaData, dataType, fileName, content); + } + return metaData; + } + + static void createFileInTempDirAnAppendOpenStackMetadataToJsonObject(String tempDirName, JsonObject metaData, String dataType, String fileName, String content) { + if (StringUtils.isBlank(dataType)) { + return; + } + //create folder + File typeFolder = new File(tempDirName + ConfigDrive.cloudStackConfigDriveName + dataType); + if (!typeFolder.exists() && !typeFolder.mkdirs()) { + throw new CloudRuntimeException("Failed to create folder: " + typeFolder); + } + if (StringUtils.isNotBlank(content)) { + File file = new File(typeFolder, fileName + ".txt"); + try { + if (fileName.equals(USERDATA_FILE)) { + // User Data is passed as a base64 encoded string + FileUtils.writeByteArrayToFile(file, Base64.decodeBase64(content)); + } else { + FileUtils.write(file, content, com.cloud.utils.StringUtils.getPreferredCharset()); + } + } catch (IOException ex) { + throw new CloudRuntimeException("Failed to create file ", ex); + } + } + + //now write the file to the OpenStack directory + buildOpenStackMetaData(metaData, dataType, fileName, content); + } + + /** + * Hard link the user_data.txt file with the user_data file in the OpenStack directory. + */ + static void linkUserData(String tempDirName) { String userDataFilePath = tempDirName + ConfigDrive.cloudStackConfigDriveName + "userdata/user_data.txt"; - if ((new File(userDataFilePath).exists())) { + File file = new File(userDataFilePath); + if (file.exists()) { Script hardLink = new Script("ln", Duration.standardSeconds(300), LOG); hardLink.add(userDataFilePath); hardLink.add(tempDirName + ConfigDrive.openStackConfigDriveName + "user_data"); LOG.debug("execute command: " + hardLink.toString()); - return hardLink.execute(); + + String executionResult = hardLink.execute(); + if (StringUtils.isNotBlank(executionResult)) { + throw new CloudRuntimeException("Unable to create user_data link due to " + executionResult); + } } - return null; } private static JsonArray arrayOf(JsonElement... elements) { @@ -193,30 +282,33 @@ public class ConfigDriveBuilder { return array; } - private static JsonObject buildOpenStackMetaData(JsonObject metaData, String dataType, String fileName, String content) { - if (dataType.equals(NetworkModel.METATDATA_DIR) && StringUtils.isNotEmpty(content)) { - //keys are a special case in OpenStack format - if (NetworkModel.PUBLIC_KEYS_FILE.equals(fileName)) { - String[] keyArray = content.replace("\\n", "").split(" "); - String keyName = "key"; - if (keyArray.length > 3 && StringUtils.isNotEmpty(keyArray[2])){ - keyName = keyArray[2]; - } - - JsonObject keyLegacy = new JsonObject(); - keyLegacy.addProperty("type", "ssh"); - keyLegacy.addProperty("data", content.replace("\\n", "")); - keyLegacy.addProperty("name", keyName); - metaData.add("keys", arrayOf(keyLegacy)); - - JsonObject key = new JsonObject(); - key.addProperty(keyName, content); - metaData.add("public_keys", key); - } else if (NetworkModel.openStackFileMapping.get(fileName) != null) { - metaData.addProperty(NetworkModel.openStackFileMapping.get(fileName), content); - } + private static void buildOpenStackMetaData(JsonObject metaData, String dataType, String fileName, String content) { + if (!NetworkModel.METATDATA_DIR.equals(dataType)) { + return; + } + if (StringUtils.isNotBlank(content)) { + return; + } + //keys are a special case in OpenStack format + if (NetworkModel.PUBLIC_KEYS_FILE.equals(fileName)) { + String[] keyArray = content.replace("\\n", "").split(" "); + String keyName = "key"; + if (keyArray.length > 3 && StringUtils.isNotEmpty(keyArray[2])) { + keyName = keyArray[2]; + } + + JsonObject keyLegacy = new JsonObject(); + keyLegacy.addProperty("type", "ssh"); + keyLegacy.addProperty("data", content.replace("\\n", "")); + keyLegacy.addProperty("name", keyName); + metaData.add("keys", arrayOf(keyLegacy)); + + JsonObject key = new JsonObject(); + key.addProperty(keyName, content); + metaData.add("public_keys", key); + } else if (NetworkModel.openStackFileMapping.get(fileName) != null) { + metaData.addProperty(NetworkModel.openStackFileMapping.get(fileName), content); } - return metaData; } } diff --git a/engine/storage/configdrive/test/org/apache/cloudstack/storage/configdrive/ConfigDriveBuilderTest.java b/engine/storage/configdrive/test/org/apache/cloudstack/storage/configdrive/ConfigDriveBuilderTest.java index 50a4384d5c8..96032738edc 100644 --- a/engine/storage/configdrive/test/org/apache/cloudstack/storage/configdrive/ConfigDriveBuilderTest.java +++ b/engine/storage/configdrive/test/org/apache/cloudstack/storage/configdrive/ConfigDriveBuilderTest.java @@ -17,49 +17,481 @@ package org.apache.cloudstack.storage.configdrive; +import static org.mockito.Mockito.times; + import java.io.File; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; +import java.lang.reflect.Method; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.List; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; import org.junit.Assert; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.reflections.ReflectionUtils; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.script.Script; +import com.google.gson.JsonObject; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({FileUtils.class}) public class ConfigDriveBuilderTest { @Test - public void testConfigDriveIsoPath() throws IOException { - Assert.assertEquals(ConfigDrive.createConfigDrivePath("i-x-y"), "configdrive/i-x-y/configdrive.iso"); + public void writeFileTest() throws Exception { + PowerMockito.mockStatic(FileUtils.class); + + ConfigDriveBuilder.writeFile(new File("folder"), "subfolder", "content"); + + PowerMockito.verifyStatic(); + FileUtils.write(Mockito.any(File.class), Mockito.anyString(), Mockito.any(Charset.class), Mockito.eq(false)); + } + + @SuppressWarnings("unchecked") + @Test(expected = CloudRuntimeException.class) + public void writeFileTestwriteFileTestIOExceptionWhileWritingFile() throws Exception { + PowerMockito.mockStatic(FileUtils.class); + + //Does not look good, I know... but this is the price of static methods. + Method method = ReflectionUtils.getMethods(FileUtils.class, ReflectionUtils.withParameters(File.class, CharSequence.class, Charset.class, Boolean.TYPE)).iterator().next(); + PowerMockito.when(FileUtils.class, method).withArguments(Mockito.any(File.class), Mockito.anyString(), Mockito.any(Charset.class), Mockito.anyBoolean()).thenThrow(IOException.class); + + ConfigDriveBuilder.writeFile(new File("folder"), "subfolder", "content"); } @Test - public void testConfigDriveBuild() throws IOException { - List actualVmData = Arrays.asList( - new String[]{"userdata", "user_data", "c29tZSB1c2VyIGRhdGE="}, - new String[]{"metadata", "service-offering", "offering"}, - new String[]{"metadata", "availability-zone", "zone1"}, - new String[]{"metadata", "local-hostname", "hostname"}, - new String[]{"metadata", "local-ipv4", "192.168.111.111"}, - new String[]{"metadata", "public-hostname", "7.7.7.7"}, - new String[]{"metadata", "public-ipv4", "7.7.7.7"}, - new String[]{"metadata", "vm-id", "uuid"}, - new String[]{"metadata", "instance-id", "i-x-y"}, - new String[]{"metadata", "public-keys", "ssh-rsa some-key"}, - new String[]{"metadata", "cloud-identifier", String.format("CloudStack-{%s}", "uuid")}, - new String[]{"password", "vm_password", "password123"} - ); + public void fileToBase64StringTest() throws Exception { + PowerMockito.mockStatic(FileUtils.class); - final Path tempDir = Files.createTempDirectory(ConfigDrive.CONFIGDRIVEDIR); - final String isoData = ConfigDriveBuilder.buildConfigDrive(actualVmData, "i-x-y.iso", "config-2"); - final File isoFile = ConfigDriveBuilder.base64StringToFile(isoData, tempDir.toAbsolutePath().toString(), ConfigDrive.CONFIGDRIVEFILENAME); + String fileContent = "content"; + Method method = getFileUtilsReadfileToByteArrayMethod(); + PowerMockito.when(FileUtils.class, method).withArguments(Mockito.any(File.class)).thenReturn(fileContent.getBytes()); - Assert.assertTrue(isoFile.exists()); - Assert.assertTrue(isoFile.isFile()); - Assert.assertTrue(isoFile.length() > 0L); + String returnedContentInBase64 = ConfigDriveBuilder.fileToBase64String(new File("file")); - FileUtils.deleteDirectory(tempDir.toFile()); + Assert.assertEquals("Y29udGVudA==", returnedContentInBase64); + } + + @SuppressWarnings("unchecked") + @Test(expected = IOException.class) + public void fileToBase64StringTestIOException() throws Exception { + PowerMockito.mockStatic(FileUtils.class); + + Method method = getFileUtilsReadfileToByteArrayMethod(); + PowerMockito.when(FileUtils.class, method).withArguments(Mockito.any(File.class)).thenThrow(IOException.class); + + ConfigDriveBuilder.fileToBase64String(new File("file")); + } + + @SuppressWarnings("unchecked") + private Method getFileUtilsReadfileToByteArrayMethod() { + return ReflectionUtils.getMethods(FileUtils.class, ReflectionUtils.withName("readFileToByteArray")).iterator().next(); + } + + @Test + public void base64StringToFileTest() throws Exception { + String encodedIsoData = "Y29udGVudA=="; + + String parentFolder = "parentFolder"; + String fileName = "fileName"; + + File parentFolderFile = new File(parentFolder); + parentFolderFile.mkdir(); + + ConfigDriveBuilder.base64StringToFile(encodedIsoData, parentFolder, fileName); + + File file = new File(parentFolderFile, fileName); + String contentOfFile = new String(FileUtils.readFileToByteArray(file), StandardCharsets.US_ASCII); + + Assert.assertEquals("content", contentOfFile); + + file.delete(); + parentFolderFile.delete(); + } + + @Test(expected = CloudRuntimeException.class) + public void buildConfigDriveTestNoVmData() { + ConfigDriveBuilder.buildConfigDrive(null, "teste", "C:"); + } + + @SuppressWarnings("unchecked") + @PrepareForTest({ConfigDriveBuilder.class}) + @Test(expected = CloudRuntimeException.class) + public void buildConfigDriveTestIoException() throws Exception { + PowerMockito.mockStatic(ConfigDriveBuilder.class); + + Method method = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("writeVendorAndNetworkEmptyJsonFile")).iterator().next(); + PowerMockito.when(ConfigDriveBuilder.class, method).withArguments(Mockito.any(File.class)).thenThrow(IOException.class); + + //This is odd, but it was necessary to allow us to check if we catch the IOexception and re-throw as a CloudRuntimeException + //We are mocking the class being tested; therefore, we needed to force the execution of the real method we want to test. + PowerMockito.when(ConfigDriveBuilder.class, new ArrayList<>(), "teste", "C:").thenCallRealMethod(); + + ConfigDriveBuilder.buildConfigDrive(new ArrayList<>(), "teste", "C:"); + } + + @Test + @SuppressWarnings("unchecked") + @PrepareForTest({ConfigDriveBuilder.class}) + public void buildConfigDriveTest() throws Exception { + PowerMockito.mockStatic(ConfigDriveBuilder.class); + + Method writeVendorAndNetworkEmptyJsonFileMethod = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("writeVendorAndNetworkEmptyJsonFile")).iterator().next(); + PowerMockito.doNothing().when(ConfigDriveBuilder.class, writeVendorAndNetworkEmptyJsonFileMethod).withArguments(Mockito.any(File.class)); + + Method writeVmMetadataMethod = getWriteVmMetadataMethod(); + PowerMockito.doNothing().when(ConfigDriveBuilder.class, writeVmMetadataMethod).withArguments(Mockito.anyListOf(String[].class), Mockito.anyString(), Mockito.any(File.class)); + + Method linkUserDataMethod = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("linkUserData")).iterator().next(); + PowerMockito.doNothing().when(ConfigDriveBuilder.class, linkUserDataMethod).withArguments(Mockito.anyString()); + + Method generateAndRetrieveIsoAsBase64IsoMethod = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("generateAndRetrieveIsoAsBase64Iso")).iterator().next(); + PowerMockito.doReturn("mockIsoDataBase64").when(ConfigDriveBuilder.class, generateAndRetrieveIsoAsBase64IsoMethod).withArguments(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); + + //force execution of real method + PowerMockito.when(ConfigDriveBuilder.class, new ArrayList<>(), "teste", "C:").thenCallRealMethod(); + + String returnedIsoData = ConfigDriveBuilder.buildConfigDrive(new ArrayList<>(), "teste", "C:"); + + Assert.assertEquals("mockIsoDataBase64", returnedIsoData); + + PowerMockito.verifyStatic(); + ConfigDriveBuilder.writeVendorAndNetworkEmptyJsonFile(Mockito.any(File.class)); + ConfigDriveBuilder.writeVmMetadata(Mockito.anyListOf(String[].class), Mockito.anyString(), Mockito.any(File.class)); + ConfigDriveBuilder.linkUserData(Mockito.anyString()); + ConfigDriveBuilder.generateAndRetrieveIsoAsBase64Iso(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); + } + + @SuppressWarnings("unchecked") + private Method getWriteVmMetadataMethod() { + return ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("writeVmMetadata")).iterator().next(); + } + + @Test(expected = CloudRuntimeException.class) + public void writeVendorAndNetworkEmptyJsonFileTestCannotCreateOpenStackFolder() { + File folderFileMock = Mockito.mock(File.class); + Mockito.doReturn(false).when(folderFileMock).mkdirs(); + + ConfigDriveBuilder.writeVendorAndNetworkEmptyJsonFile(folderFileMock); + } + + @Test(expected = CloudRuntimeException.class) + public void writeVendorAndNetworkEmptyJsonFileTest() { + File folderFileMock = Mockito.mock(File.class); + Mockito.doReturn(false).when(folderFileMock).mkdirs(); + + ConfigDriveBuilder.writeVendorAndNetworkEmptyJsonFile(folderFileMock); + } + + @Test + @PrepareForTest({ConfigDriveBuilder.class}) + public void writeVendorAndNetworkEmptyJsonFileTestCreatingFolder() throws Exception { + PowerMockito.mockStatic(ConfigDriveBuilder.class); + + File folderFileMock = Mockito.mock(File.class); + Mockito.doReturn(false).when(folderFileMock).exists(); + Mockito.doReturn(true).when(folderFileMock).mkdirs(); + + //force execution of real method + Method writeVendorAndNetworkEmptyJsonFileMethod = getWriteVendorAndNetworkEmptyJsonFileMethod(); + PowerMockito.when(ConfigDriveBuilder.class, writeVendorAndNetworkEmptyJsonFileMethod).withArguments(folderFileMock).thenCallRealMethod(); + + ConfigDriveBuilder.writeVendorAndNetworkEmptyJsonFile(folderFileMock); + + Mockito.verify(folderFileMock).exists(); + Mockito.verify(folderFileMock).mkdirs(); + + PowerMockito.verifyStatic(); + ConfigDriveBuilder.writeFile(Mockito.any(File.class), Mockito.eq("vendor_data.json"), Mockito.eq("{}")); + ConfigDriveBuilder.writeFile(Mockito.any(File.class), Mockito.eq("network_data.json"), Mockito.eq("{}")); + } + + @SuppressWarnings("unchecked") + private Method getWriteVendorAndNetworkEmptyJsonFileMethod() { + return ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("writeVendorAndNetworkEmptyJsonFile")).iterator().next(); + } + + @Test + @SuppressWarnings("unchecked") + @PrepareForTest({ConfigDriveBuilder.class}) + public void writeVmMetadataTest() throws Exception { + PowerMockito.mockStatic(ConfigDriveBuilder.class); + + Method method = getWriteVmMetadataMethod(); + PowerMockito.when(ConfigDriveBuilder.class, method).withArguments(new ArrayList<>(), "metadataFile", new File("folder")).thenCallRealMethod(); + + Method createJsonObjectWithVmDataMethod = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("createJsonObjectWithVmData")).iterator().next(); + PowerMockito.when(ConfigDriveBuilder.class, createJsonObjectWithVmDataMethod).withArguments(Mockito.anyListOf(String[].class), Mockito.any(File.class)).thenReturn(new JsonObject()); + + ConfigDriveBuilder.writeVmMetadata(new ArrayList<>(), "metadataFile", new File("folder")); + + PowerMockito.verifyStatic(); + ConfigDriveBuilder.createJsonObjectWithVmData(Mockito.anyListOf(String[].class), Mockito.anyString()); + ConfigDriveBuilder.writeFile(Mockito.any(File.class), Mockito.eq("meta_data.json"), Mockito.eq("{}")); + } + + @Test + @PrepareForTest({File.class, Script.class, ConfigDriveBuilder.class}) + public void linkUserDataTestUserDataFilePathDoesNotExist() throws Exception { + File fileMock = Mockito.mock(File.class); + Mockito.doReturn(false).when(fileMock).exists(); + + PowerMockito.mockStatic(File.class, Script.class); + PowerMockito.whenNew(File.class).withArguments(Mockito.anyString()).thenReturn(fileMock); + + Script scriptMock = Mockito.mock(Script.class); + PowerMockito.whenNew(Script.class).withAnyArguments().thenReturn(scriptMock); + + ConfigDriveBuilder.linkUserData("test"); + + Mockito.verify(scriptMock, times(0)).execute(); + } + + @Test(expected = CloudRuntimeException.class) + @PrepareForTest({File.class, Script.class, ConfigDriveBuilder.class}) + public void linkUserDataTestUserDataFilePathExistAndExecutionPresentedSomeError() throws Exception { + File fileMock = Mockito.mock(File.class); + Mockito.doReturn(true).when(fileMock).exists(); + + PowerMockito.mockStatic(File.class, Script.class); + PowerMockito.whenNew(File.class).withArguments(Mockito.anyString()).thenReturn(fileMock); + + Script scriptMock = Mockito.mock(Script.class); + PowerMockito.whenNew(Script.class).withAnyArguments().thenReturn(scriptMock); + + Mockito.doReturn("message").when(scriptMock).execute(); + ConfigDriveBuilder.linkUserData("test"); + } + + @Test + @PrepareForTest({File.class, Script.class, ConfigDriveBuilder.class}) + public void linkUserDataTest() throws Exception { + File fileMock = Mockito.mock(File.class); + Mockito.doReturn(true).when(fileMock).exists(); + + PowerMockito.mockStatic(File.class, Script.class); + PowerMockito.whenNew(File.class).withArguments(Mockito.anyString()).thenReturn(fileMock); + + Script scriptMock = Mockito.mock(Script.class); + PowerMockito.whenNew(Script.class).withAnyArguments().thenReturn(scriptMock); + + Mockito.doReturn(StringUtils.EMPTY).when(scriptMock).execute(); + String tempDirName = "test"; + ConfigDriveBuilder.linkUserData(tempDirName); + + Mockito.verify(scriptMock).add(tempDirName + ConfigDrive.cloudStackConfigDriveName + "userdata/user_data.txt"); + Mockito.verify(scriptMock).add(tempDirName + ConfigDrive.openStackConfigDriveName + "user_data"); + Mockito.verify(scriptMock).execute(); + } + + @SuppressWarnings("unchecked") + @Test(expected = CloudRuntimeException.class) + @PrepareForTest({Script.class, ConfigDriveBuilder.class}) + public void generateAndRetrieveIsoAsBase64IsoTestGenIsoFailure() throws Exception { + PowerMockito.mockStatic(Script.class, ConfigDriveBuilder.class); + + Script scriptMock = Mockito.mock(Script.class); + PowerMockito.whenNew(Script.class).withAnyArguments().thenReturn(scriptMock); + + Mockito.doReturn("scriptMessage").when(scriptMock).execute(); + + Method method = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("generateAndRetrieveIsoAsBase64Iso")).iterator().next(); + PowerMockito.when(ConfigDriveBuilder.class, method).withArguments(Mockito.any(File.class), Mockito.any(File.class), Mockito.any(File.class)).thenCallRealMethod(); + + Method getProgramToGenerateIsoMethod = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("getProgramToGenerateIso")).iterator().next(); + PowerMockito.when(ConfigDriveBuilder.class, getProgramToGenerateIsoMethod).withNoArguments().thenReturn("/usr/bin/genisoimage"); + + ConfigDriveBuilder.generateAndRetrieveIsoAsBase64Iso("isoFileName", "driveLabel", "tempDirName"); + } + + @SuppressWarnings("unchecked") + @Test(expected = CloudRuntimeException.class) + @PrepareForTest({File.class, Script.class, ConfigDriveBuilder.class}) + public void generateAndRetrieveIsoAsBase64IsoTestIsoTooBig() throws Exception { + PowerMockito.mockStatic(File.class, Script.class, ConfigDriveBuilder.class); + + File fileMock = Mockito.mock(File.class); + PowerMockito.whenNew(File.class).withAnyArguments().thenReturn(fileMock); + + Script scriptMock = Mockito.mock(Script.class); + PowerMockito.whenNew(Script.class).withAnyArguments().thenReturn(scriptMock); + + Mockito.doReturn(StringUtils.EMPTY).when(scriptMock).execute(); + Mockito.doReturn(64L * 1024L * 1024L + 1l).when(fileMock).length(); + + Method method = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("generateAndRetrieveIsoAsBase64Iso")).iterator().next(); + PowerMockito.when(ConfigDriveBuilder.class, method).withArguments(Mockito.any(File.class), Mockito.any(File.class), Mockito.any(File.class)).thenCallRealMethod(); + + Method getProgramToGenerateIsoMethod = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("getProgramToGenerateIso")).iterator().next(); + PowerMockito.when(ConfigDriveBuilder.class, getProgramToGenerateIsoMethod).withNoArguments().thenReturn("/usr/bin/genisoimage"); + + ConfigDriveBuilder.generateAndRetrieveIsoAsBase64Iso("isoFileName", "driveLabel", "tempDirName"); + } + + @Test + @SuppressWarnings("unchecked") + @PrepareForTest({File.class, Script.class, ConfigDriveBuilder.class}) + public void generateAndRetrieveIsoAsBase64IsoTest() throws Exception { + PowerMockito.mockStatic(File.class, Script.class, ConfigDriveBuilder.class); + + File fileMock = Mockito.mock(File.class); + PowerMockito.whenNew(File.class).withArguments("tempDirName", "isoFileName").thenReturn(fileMock); + + Script scriptMock = Mockito.mock(Script.class); + PowerMockito.whenNew(Script.class).withAnyArguments().thenReturn(scriptMock); + + Mockito.when(fileMock.getAbsolutePath()).thenReturn("absolutePath"); + Mockito.doReturn(StringUtils.EMPTY).when(scriptMock).execute(); + Mockito.doReturn(64L * 1024L * 1024L).when(fileMock).length(); + + Method method = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("generateAndRetrieveIsoAsBase64Iso")).iterator().next(); + PowerMockito.when(ConfigDriveBuilder.class, method).withArguments(Mockito.any(File.class), Mockito.any(File.class), Mockito.any(File.class)).thenCallRealMethod(); + + Method getProgramToGenerateIsoMethod = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("getProgramToGenerateIso")).iterator().next(); + PowerMockito.when(ConfigDriveBuilder.class, getProgramToGenerateIsoMethod).withNoArguments().thenReturn("/usr/bin/genisoimage"); + + ConfigDriveBuilder.generateAndRetrieveIsoAsBase64Iso("isoFileName", "driveLabel", "tempDirName"); + + InOrder inOrder = Mockito.inOrder(scriptMock); + inOrder.verify(scriptMock).add("-o", "absolutePath"); + inOrder.verify(scriptMock).add("-ldots"); + inOrder.verify(scriptMock).add("-allow-lowercase"); + inOrder.verify(scriptMock).add("-allow-multidot"); + inOrder.verify(scriptMock).add("-cache-inodes"); + inOrder.verify(scriptMock).add("-l"); + inOrder.verify(scriptMock).add("-quiet"); + inOrder.verify(scriptMock).add("-J"); + inOrder.verify(scriptMock).add("-r"); + inOrder.verify(scriptMock).add("-V", "driveLabel"); + inOrder.verify(scriptMock).add("tempDirName"); + inOrder.verify(scriptMock).execute(); + + PowerMockito.verifyStatic(); + ConfigDriveBuilder.fileToBase64String(Mockito.any(File.class)); + + } + + @Test + @SuppressWarnings("unchecked") + @PrepareForTest({ConfigDriveBuilder.class}) + public void createJsonObjectWithVmDataTesT() throws Exception { + PowerMockito.mockStatic(ConfigDriveBuilder.class); + + Method method = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("createJsonObjectWithVmData")).iterator().next(); + PowerMockito.when(ConfigDriveBuilder.class, method).withArguments(Mockito.anyListOf(String[].class), Mockito.anyString()).thenCallRealMethod(); + + List vmData = new ArrayList<>(); + vmData.add(new String[] {"dataType", "fileName", "content"}); + vmData.add(new String[] {"dataType2", "fileName2", "content2"}); + + ConfigDriveBuilder.createJsonObjectWithVmData(vmData, "tempDirName"); + + PowerMockito.verifyStatic(Mockito.times(1)); + ConfigDriveBuilder.createFileInTempDirAnAppendOpenStackMetadataToJsonObject(Mockito.eq("tempDirName"), Mockito.any(JsonObject.class), Mockito.eq("dataType"), Mockito.eq("fileName"), + Mockito.eq("content")); + ConfigDriveBuilder.createFileInTempDirAnAppendOpenStackMetadataToJsonObject(Mockito.eq("tempDirName"), Mockito.any(JsonObject.class), Mockito.eq("dataType2"), Mockito.eq("fileName2"), + Mockito.eq("content2")); + } + + @Test + @PrepareForTest({File.class, ConfigDriveBuilder.class}) + public void getProgramToGenerateIsoTestGenIsoExistsAndIsExecutable() throws Exception { + PowerMockito.mockStatic(File.class); + + File genIsoFileMock = Mockito.mock(File.class); + Mockito.doReturn(true).when(genIsoFileMock).exists(); + Mockito.doReturn(true).when(genIsoFileMock).canExecute(); + + PowerMockito.whenNew(File.class).withArguments("/usr/bin/genisoimage").thenReturn(genIsoFileMock); + + ConfigDriveBuilder.getProgramToGenerateIso(); + + Mockito.verify(genIsoFileMock, Mockito.times(2)).exists(); + Mockito.verify(genIsoFileMock).canExecute(); + Mockito.verify(genIsoFileMock).getCanonicalPath(); + } + + @Test(expected = CloudRuntimeException.class) + @PrepareForTest({File.class, ConfigDriveBuilder.class}) + public void getProgramToGenerateIsoTestGenIsoExistsbutNotExecutable() throws Exception { + PowerMockito.mockStatic(File.class); + + File genIsoFileMock = Mockito.mock(File.class); + Mockito.doReturn(true).when(genIsoFileMock).exists(); + Mockito.doReturn(false).when(genIsoFileMock).canExecute(); + + PowerMockito.whenNew(File.class).withArguments("/usr/bin/genisoimage").thenReturn(genIsoFileMock); + + ConfigDriveBuilder.getProgramToGenerateIso(); + } + + @Test + @PrepareForTest({File.class, ConfigDriveBuilder.class}) + public void getProgramToGenerateIsoTestNotGenIsoMkIsoInLinux() throws Exception { + PowerMockito.mockStatic(File.class); + + File genIsoFileMock = Mockito.mock(File.class); + Mockito.doReturn(false).when(genIsoFileMock).exists(); + + File mkIsoProgramInLinuxFileMock = Mockito.mock(File.class); + Mockito.doReturn(true).when(mkIsoProgramInLinuxFileMock).exists(); + Mockito.doReturn(true).when(mkIsoProgramInLinuxFileMock).canExecute(); + + PowerMockito.whenNew(File.class).withArguments("/usr/bin/genisoimage").thenReturn(genIsoFileMock); + PowerMockito.whenNew(File.class).withArguments("/usr/bin/mkisofs").thenReturn(mkIsoProgramInLinuxFileMock); + + ConfigDriveBuilder.getProgramToGenerateIso(); + + Mockito.verify(genIsoFileMock, Mockito.times(1)).exists(); + Mockito.verify(genIsoFileMock, Mockito.times(0)).canExecute(); + Mockito.verify(genIsoFileMock, Mockito.times(0)).getCanonicalPath(); + + Mockito.verify(mkIsoProgramInLinuxFileMock, Mockito.times(2)).exists(); + Mockito.verify(mkIsoProgramInLinuxFileMock, Mockito.times(1)).canExecute(); + Mockito.verify(mkIsoProgramInLinuxFileMock, Mockito.times(1)).getCanonicalPath(); + } + + @Test + @PrepareForTest({File.class, ConfigDriveBuilder.class}) + public void getProgramToGenerateIsoTestMkIsoMac() throws Exception { + PowerMockito.mockStatic(File.class); + + File genIsoFileMock = Mockito.mock(File.class); + Mockito.doReturn(false).when(genIsoFileMock).exists(); + + File mkIsoProgramInLinuxFileMock = Mockito.mock(File.class); + Mockito.doReturn(false).when(mkIsoProgramInLinuxFileMock).exists(); + + File mkIsoProgramInMacOsFileMock = Mockito.mock(File.class); + Mockito.doReturn(true).when(mkIsoProgramInMacOsFileMock).exists(); + Mockito.doReturn(true).when(mkIsoProgramInMacOsFileMock).canExecute(); + + PowerMockito.whenNew(File.class).withArguments("/usr/bin/genisoimage").thenReturn(genIsoFileMock); + PowerMockito.whenNew(File.class).withArguments("/usr/bin/mkisofs").thenReturn(mkIsoProgramInLinuxFileMock); + PowerMockito.whenNew(File.class).withArguments("/usr/local/bin/mkisofs").thenReturn(mkIsoProgramInMacOsFileMock); + + ConfigDriveBuilder.getProgramToGenerateIso(); + + Mockito.verify(genIsoFileMock, Mockito.times(1)).exists(); + Mockito.verify(genIsoFileMock, Mockito.times(0)).canExecute(); + Mockito.verify(genIsoFileMock, Mockito.times(0)).getCanonicalPath(); + + Mockito.verify(mkIsoProgramInLinuxFileMock, Mockito.times(1)).exists(); + Mockito.verify(mkIsoProgramInLinuxFileMock, Mockito.times(0)).canExecute(); + Mockito.verify(mkIsoProgramInLinuxFileMock, Mockito.times(0)).getCanonicalPath(); + + Mockito.verify(mkIsoProgramInMacOsFileMock, Mockito.times(1)).exists(); + Mockito.verify(mkIsoProgramInMacOsFileMock, Mockito.times(1)).canExecute(); + Mockito.verify(mkIsoProgramInMacOsFileMock, Mockito.times(1)).getCanonicalPath(); } } \ No newline at end of file diff --git a/engine/storage/configdrive/test/org/apache/cloudstack/storage/configdrive/ConfigDriveTest.java b/engine/storage/configdrive/test/org/apache/cloudstack/storage/configdrive/ConfigDriveTest.java new file mode 100644 index 00000000000..81294d4331b --- /dev/null +++ b/engine/storage/configdrive/test/org/apache/cloudstack/storage/configdrive/ConfigDriveTest.java @@ -0,0 +1,32 @@ +// 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.storage.configdrive; + +import java.io.IOException; + +import org.junit.Assert; +import org.junit.Test; + +public class ConfigDriveTest { + + @Test + public void testConfigDriveIsoPath() throws IOException { + Assert.assertEquals(ConfigDrive.createConfigDrivePath("i-x-y"), "configdrive/i-x-y/configdrive.iso"); + } + +} \ No newline at end of file diff --git a/server/test/com/cloud/network/element/ConfigDriveNetworkElementTest.java b/server/test/com/cloud/network/element/ConfigDriveNetworkElementTest.java index e964999ee9d..01713de389d 100644 --- a/server/test/com/cloud/network/element/ConfigDriveNetworkElementTest.java +++ b/server/test/com/cloud/network/element/ConfigDriveNetworkElementTest.java @@ -31,6 +31,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -41,12 +42,20 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.storage.configdrive.ConfigDrive; +import org.apache.cloudstack.storage.configdrive.ConfigDriveBuilder; +import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.Spy; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.reflections.ReflectionUtils; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; @@ -90,6 +99,7 @@ import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.VMInstanceDao; import com.google.common.collect.Maps; +@RunWith(PowerMockRunner.class) public class ConfigDriveNetworkElementTest { public static final String CLOUD_ID = "xx"; @@ -140,7 +150,7 @@ public class ConfigDriveNetworkElementTest { @InjectMocks private final ConfigDriveNetworkElement _configDrivesNetworkElement = new ConfigDriveNetworkElement(); @InjectMocks @Spy private NetworkModelImpl _networkModel = new NetworkModelImpl(); - @org.junit.Before + @Before public void setUp() throws NoSuchFieldException, IllegalAccessException { MockitoAnnotations.initMocks(this); @@ -243,7 +253,14 @@ public class ConfigDriveNetworkElementTest { } @Test + @SuppressWarnings("unchecked") + @PrepareForTest({ConfigDriveBuilder.class}) public void testAddPasswordAndUserData() throws Exception { + PowerMockito.mockStatic(ConfigDriveBuilder.class); + + Method method = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("buildConfigDrive")).iterator().next(); + PowerMockito.when(ConfigDriveBuilder.class, method).withArguments(Mockito.anyListOf(String[].class), Mockito.anyString(), Mockito.anyString()).thenReturn("content"); + final Answer answer = mock(Answer.class); final UserVmDetailVO userVmDetailVO = mock(UserVmDetailVO.class); when(agentManager.easySend(anyLong(), any(HandleConfigDriveIsoCommand.class))).thenReturn(answer); diff --git a/services/console-proxy-rdp/rdpconsole/src/test/java/rdpclient/MockServerTest.java b/services/console-proxy-rdp/rdpconsole/src/test/java/rdpclient/MockServerTest.java index 3462618fed9..f2e611de24f 100644 --- a/services/console-proxy-rdp/rdpconsole/src/test/java/rdpclient/MockServerTest.java +++ b/services/console-proxy-rdp/rdpconsole/src/test/java/rdpclient/MockServerTest.java @@ -29,10 +29,9 @@ import javax.net.SocketFactory; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; -import junit.framework.TestCase; - import org.junit.Test; +import junit.framework.TestCase; import streamer.debug.MockServer; import streamer.debug.MockServer.Packet; @@ -93,7 +92,6 @@ public class MockServerTest extends TestCase { @Test public void testIsMockServerCanUpgradeConnectionToSsl() throws Exception { - final byte[] mockClientData1 = new byte[] {0x01, 0x02, 0x03}; final byte[] mockServerData1 = new byte[] {0x03, 0x02, 0x01}; @@ -161,8 +159,7 @@ public class MockServerTest extends TestCase { final SSLSocketFactory sslSocketFactory = (SSLSocketFactory)SSLSocketFactory.getDefault(); SSLSocket sslSocket = (SSLSocket)sslSocketFactory.createSocket(socket, address.getHostName(), address.getPort(), true); - //sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites()); - sslSocket.setEnabledCipherSuites(new String[] { "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA" }); + sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites()); sslSocket.startHandshake(); InputStream is = sslSocket.getInputStream(); 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 125512bba91..0bb923f8053 100644 --- 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 @@ -584,16 +584,19 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S StringBuffer sb = new StringBuffer(); sb.append(secStorageMountPoint); - if (!secStorageMountPoint.endsWith("/")) + if (!secStorageMountPoint.endsWith("/")) { sb.append("/"); + } sb.append(templateRelativeFolderPath); - if (!secStorageMountPoint.endsWith("/")) + if (!secStorageMountPoint.endsWith("/")) { sb.append("/"); + } sb.append(templateName); - if (!fileExtension.startsWith(".")) + if (!fileExtension.startsWith(".")) { sb.append("."); + } sb.append(fileExtension); return sb.toString(); @@ -904,7 +907,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S try { _storage.create(destFile.getAbsolutePath(), _tmpltpp); try ( // generate template.properties file - FileWriter writer = new FileWriter(metaFile); BufferedWriter bufferWriter = new BufferedWriter(writer);) { + FileWriter writer = new FileWriter(metaFile); BufferedWriter bufferWriter = new BufferedWriter(writer);) { // KVM didn't change template unique name, just used the template name passed from orchestration layer, so no need // to send template name back. bufferWriter.write("uniquename=" + destData.getName()); @@ -1450,7 +1453,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S Script command = new Script("/bin/bash", s_logger); command.add("-c"); command.add("/usr/bin/python /usr/local/cloud/systemvm/scripts/storage/secondary/swift -A " + swift.getUrl() + " -U " + swift.getAccount() + ":" + swift.getUserName() - + " -K " + swift.getKey() + " download " + container + " " + rfilename + " -o " + lFullPath); + + " -K " + swift.getKey() + " download " + container + " " + rfilename + " -o " + lFullPath); OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser(); String result = command.execute(parser); if (result != null) { @@ -1554,7 +1557,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S Script command = new Script("/bin/bash", s_logger); command.add("-c"); command.add("/usr/bin/python /usr/local/cloud/systemvm/scripts/storage/secondary/swift -A " + swift.getUrl() + " -U " + swift.getAccount() + ":" + swift.getUserName() - + " -K " + swift.getKey() + " list " + container + " " + rFilename); + + " -K " + swift.getKey() + " list " + container + " " + rFilename); OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser(); String result = command.execute(parser); if (result == null && parser.getLines() != null) { @@ -1576,7 +1579,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S Script command = new Script("/bin/bash", s_logger); command.add("-c"); command.add("/usr/bin/python /usr/local/cloud/systemvm/scripts/storage/secondary/swift -A " + swift.getUrl() + " -U " + swift.getAccount() + ":" + swift.getUserName() - + " -K " + swift.getKey() + " delete " + container + " " + object); + + " -K " + swift.getKey() + " delete " + container + " " + object); OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser(); String result = command.execute(parser); if (result != null) { @@ -3316,7 +3319,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S for (Processor processor : processors.values()) { FormatInfo info = null; try { - info = processor.process(resourcePath, null, templateName, processTimeout * 1000); + info = processor.process(resourcePath, null, templateName, processTimeout * 1000); } catch (InternalErrorException e) { s_logger.error("Template process exception ", e); return e.toString();