Skip to content

Commit 28a3002

Browse files
add method 'getProgramToGenerateIso' as suggested by rohit and Daan
1 parent 0f3d324 commit 28a3002

3 files changed

Lines changed: 155 additions & 6 deletions

File tree

engine/storage/configdrive/src/org/apache/cloudstack/storage/configdrive/ConfigDriveBuilder.java

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,13 @@ private static void deleteTempDir(Path tempDir) {
123123

124124
/**
125125
* Generates the ISO file that has the tempDir content.
126-
* We will use '/usr/bin/genisoimage' to create an ISO file based on tempDir content.
127126
*
128127
* Max allowed file size of config drive is 64MB [1]. Therefore, if the ISO is bigger than that, we throw a {@link CloudRuntimeException}.
129128
* [1] https://docs.openstack.org/project-install-guide/baremetal/draft/configdrive.html
130129
*/
131130
static String generateAndRetrieveIsoAsBase64Iso(String isoFileName, String driveLabel, String tempDirName) throws IOException {
132131
File tmpIsoStore = new File(tempDirName, isoFileName);
133-
Script command = new Script("/usr/bin/genisoimage", Duration.standardSeconds(300), LOG);
132+
Script command = new Script(getProgramToGenerateIso(), Duration.standardSeconds(300), LOG);
134133
command.add("-o", tmpIsoStore.getAbsolutePath());
135134
command.add("-ldots");
136135
command.add("-allow-lowercase");
@@ -145,7 +144,7 @@ static String generateAndRetrieveIsoAsBase64Iso(String isoFileName, String drive
145144
LOG.debug("Executing config drive creation command: " + command.toString());
146145
String result = command.execute();
147146
if (StringUtils.isNotBlank(result)) {
148-
String errMsg = "Unable to create iso file: " + isoFileName + " due to " + result;
147+
String errMsg = "Unable to create iso file: " + isoFileName + " due to ge" + result;
149148
LOG.warn(errMsg);
150149
throw new CloudRuntimeException(errMsg);
151150
}
@@ -156,6 +155,31 @@ static String generateAndRetrieveIsoAsBase64Iso(String isoFileName, String drive
156155
return fileToBase64String(tmpIsoFile);
157156
}
158157

158+
/**
159+
* Checks if the 'genisoimage' or 'mkisofs' is available and return the full qualified path for the program.
160+
* The path checked are the following:
161+
* <ul>
162+
* <li> /usr/bin/genisoimage
163+
* <li> /usr/bin/mkisofs
164+
* </ul> /usr/local/bin/mkisofs
165+
*/
166+
static String getProgramToGenerateIso() throws IOException {
167+
File isoCreator = new File("/usr/bin/genisoimage");
168+
if (!isoCreator.exists()) {
169+
isoCreator = new File("/usr/bin/mkisofs");
170+
if (!isoCreator.exists()) {
171+
isoCreator = new File("/usr/local/bin/mkisofs");
172+
}
173+
}
174+
if (!isoCreator.exists()) {
175+
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]");
176+
}
177+
if (!isoCreator.canExecute()) {
178+
throw new CloudRuntimeException("Cannot create iso for config drive using: " + isoCreator.getCanonicalPath());
179+
}
180+
return isoCreator.getCanonicalPath();
181+
}
182+
159183
/**
160184
* First we generate a JSON object using {@link #createJsonObjectWithVmData(List, String)}, then we write it to a file called "meta_data.json".
161185
*/

engine/storage/configdrive/test/org/apache/cloudstack/storage/configdrive/ConfigDriveBuilderTest.java

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,23 +294,31 @@ public void linkUserDataTest() throws Exception {
294294
Mockito.verify(scriptMock).execute();
295295
}
296296

297+
@SuppressWarnings("unchecked")
297298
@Test(expected = CloudRuntimeException.class)
298299
@PrepareForTest({Script.class, ConfigDriveBuilder.class})
299300
public void generateAndRetrieveIsoAsBase64IsoTestGenIsoFailure() throws Exception {
300-
PowerMockito.mockStatic(Script.class);
301+
PowerMockito.mockStatic(Script.class, ConfigDriveBuilder.class);
301302

302303
Script scriptMock = Mockito.mock(Script.class);
303304
PowerMockito.whenNew(Script.class).withAnyArguments().thenReturn(scriptMock);
304305

305306
Mockito.doReturn("scriptMessage").when(scriptMock).execute();
306307

308+
Method method = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("generateAndRetrieveIsoAsBase64Iso")).iterator().next();
309+
PowerMockito.when(ConfigDriveBuilder.class, method).withArguments(Mockito.any(File.class), Mockito.any(File.class), Mockito.any(File.class)).thenCallRealMethod();
310+
311+
Method getProgramToGenerateIsoMethod = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("getProgramToGenerateIso")).iterator().next();
312+
PowerMockito.when(ConfigDriveBuilder.class, getProgramToGenerateIsoMethod).withNoArguments().thenReturn("/usr/bin/genisoimage");
313+
307314
ConfigDriveBuilder.generateAndRetrieveIsoAsBase64Iso("isoFileName", "driveLabel", "tempDirName");
308315
}
309316

317+
@SuppressWarnings("unchecked")
310318
@Test(expected = CloudRuntimeException.class)
311319
@PrepareForTest({File.class, Script.class, ConfigDriveBuilder.class})
312320
public void generateAndRetrieveIsoAsBase64IsoTestIsoTooBig() throws Exception {
313-
PowerMockito.mockStatic(File.class, Script.class);
321+
PowerMockito.mockStatic(File.class, Script.class, ConfigDriveBuilder.class);
314322

315323
File fileMock = Mockito.mock(File.class);
316324
PowerMockito.whenNew(File.class).withAnyArguments().thenReturn(fileMock);
@@ -321,6 +329,12 @@ public void generateAndRetrieveIsoAsBase64IsoTestIsoTooBig() throws Exception {
321329
Mockito.doReturn(StringUtils.EMPTY).when(scriptMock).execute();
322330
Mockito.doReturn(64L * 1024L * 1024L + 1l).when(fileMock).length();
323331

332+
Method method = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("generateAndRetrieveIsoAsBase64Iso")).iterator().next();
333+
PowerMockito.when(ConfigDriveBuilder.class, method).withArguments(Mockito.any(File.class), Mockito.any(File.class), Mockito.any(File.class)).thenCallRealMethod();
334+
335+
Method getProgramToGenerateIsoMethod = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("getProgramToGenerateIso")).iterator().next();
336+
PowerMockito.when(ConfigDriveBuilder.class, getProgramToGenerateIsoMethod).withNoArguments().thenReturn("/usr/bin/genisoimage");
337+
324338
ConfigDriveBuilder.generateAndRetrieveIsoAsBase64Iso("isoFileName", "driveLabel", "tempDirName");
325339
}
326340

@@ -343,6 +357,9 @@ public void generateAndRetrieveIsoAsBase64IsoTest() throws Exception {
343357
Method method = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("generateAndRetrieveIsoAsBase64Iso")).iterator().next();
344358
PowerMockito.when(ConfigDriveBuilder.class, method).withArguments(Mockito.any(File.class), Mockito.any(File.class), Mockito.any(File.class)).thenCallRealMethod();
345359

360+
Method getProgramToGenerateIsoMethod = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("getProgramToGenerateIso")).iterator().next();
361+
PowerMockito.when(ConfigDriveBuilder.class, getProgramToGenerateIsoMethod).withNoArguments().thenReturn("/usr/bin/genisoimage");
362+
346363
ConfigDriveBuilder.generateAndRetrieveIsoAsBase64Iso("isoFileName", "driveLabel", "tempDirName");
347364

348365
InOrder inOrder = Mockito.inOrder(scriptMock);
@@ -386,4 +403,95 @@ public void createJsonObjectWithVmDataTesT() throws Exception {
386403
Mockito.eq("content2"));
387404
}
388405

406+
@Test
407+
@PrepareForTest({File.class, ConfigDriveBuilder.class})
408+
public void getProgramToGenerateIsoTestGenIsoExistsAndIsExecutable() throws Exception {
409+
PowerMockito.mockStatic(File.class);
410+
411+
File genIsoFileMock = Mockito.mock(File.class);
412+
Mockito.doReturn(true).when(genIsoFileMock).exists();
413+
Mockito.doReturn(true).when(genIsoFileMock).canExecute();
414+
415+
PowerMockito.whenNew(File.class).withArguments("/usr/bin/genisoimage").thenReturn(genIsoFileMock);
416+
417+
ConfigDriveBuilder.getProgramToGenerateIso();
418+
419+
Mockito.verify(genIsoFileMock, Mockito.times(2)).exists();
420+
Mockito.verify(genIsoFileMock).canExecute();
421+
Mockito.verify(genIsoFileMock).getCanonicalPath();
422+
}
423+
424+
@Test(expected = CloudRuntimeException.class)
425+
@PrepareForTest({File.class, ConfigDriveBuilder.class})
426+
public void getProgramToGenerateIsoTestGenIsoExistsbutNotExecutable() throws Exception {
427+
PowerMockito.mockStatic(File.class);
428+
429+
File genIsoFileMock = Mockito.mock(File.class);
430+
Mockito.doReturn(true).when(genIsoFileMock).exists();
431+
Mockito.doReturn(false).when(genIsoFileMock).canExecute();
432+
433+
PowerMockito.whenNew(File.class).withArguments("/usr/bin/genisoimage").thenReturn(genIsoFileMock);
434+
435+
ConfigDriveBuilder.getProgramToGenerateIso();
436+
}
437+
438+
@Test
439+
@PrepareForTest({File.class, ConfigDriveBuilder.class})
440+
public void getProgramToGenerateIsoTestNotGenIsoMkIsoInLinux() throws Exception {
441+
PowerMockito.mockStatic(File.class);
442+
443+
File genIsoFileMock = Mockito.mock(File.class);
444+
Mockito.doReturn(false).when(genIsoFileMock).exists();
445+
446+
File mkIsoProgramInLinuxFileMock = Mockito.mock(File.class);
447+
Mockito.doReturn(true).when(mkIsoProgramInLinuxFileMock).exists();
448+
Mockito.doReturn(true).when(mkIsoProgramInLinuxFileMock).canExecute();
449+
450+
PowerMockito.whenNew(File.class).withArguments("/usr/bin/genisoimage").thenReturn(genIsoFileMock);
451+
PowerMockito.whenNew(File.class).withArguments("/usr/bin/mkisofs").thenReturn(mkIsoProgramInLinuxFileMock);
452+
453+
ConfigDriveBuilder.getProgramToGenerateIso();
454+
455+
Mockito.verify(genIsoFileMock, Mockito.times(1)).exists();
456+
Mockito.verify(genIsoFileMock, Mockito.times(0)).canExecute();
457+
Mockito.verify(genIsoFileMock, Mockito.times(0)).getCanonicalPath();
458+
459+
Mockito.verify(mkIsoProgramInLinuxFileMock, Mockito.times(2)).exists();
460+
Mockito.verify(mkIsoProgramInLinuxFileMock, Mockito.times(1)).canExecute();
461+
Mockito.verify(mkIsoProgramInLinuxFileMock, Mockito.times(1)).getCanonicalPath();
462+
}
463+
464+
@Test
465+
@PrepareForTest({File.class, ConfigDriveBuilder.class})
466+
public void getProgramToGenerateIsoTestMkIsoMac() throws Exception {
467+
PowerMockito.mockStatic(File.class);
468+
469+
File genIsoFileMock = Mockito.mock(File.class);
470+
Mockito.doReturn(false).when(genIsoFileMock).exists();
471+
472+
File mkIsoProgramInLinuxFileMock = Mockito.mock(File.class);
473+
Mockito.doReturn(false).when(mkIsoProgramInLinuxFileMock).exists();
474+
475+
File mkIsoProgramInMacOsFileMock = Mockito.mock(File.class);
476+
Mockito.doReturn(true).when(mkIsoProgramInMacOsFileMock).exists();
477+
Mockito.doReturn(true).when(mkIsoProgramInMacOsFileMock).canExecute();
478+
479+
PowerMockito.whenNew(File.class).withArguments("/usr/bin/genisoimage").thenReturn(genIsoFileMock);
480+
PowerMockito.whenNew(File.class).withArguments("/usr/bin/mkisofs").thenReturn(mkIsoProgramInLinuxFileMock);
481+
PowerMockito.whenNew(File.class).withArguments("/usr/local/bin/mkisofs").thenReturn(mkIsoProgramInMacOsFileMock);
482+
483+
ConfigDriveBuilder.getProgramToGenerateIso();
484+
485+
Mockito.verify(genIsoFileMock, Mockito.times(1)).exists();
486+
Mockito.verify(genIsoFileMock, Mockito.times(0)).canExecute();
487+
Mockito.verify(genIsoFileMock, Mockito.times(0)).getCanonicalPath();
488+
489+
Mockito.verify(mkIsoProgramInLinuxFileMock, Mockito.times(1)).exists();
490+
Mockito.verify(mkIsoProgramInLinuxFileMock, Mockito.times(0)).canExecute();
491+
Mockito.verify(mkIsoProgramInLinuxFileMock, Mockito.times(0)).getCanonicalPath();
492+
493+
Mockito.verify(mkIsoProgramInMacOsFileMock, Mockito.times(1)).exists();
494+
Mockito.verify(mkIsoProgramInMacOsFileMock, Mockito.times(1)).canExecute();
495+
Mockito.verify(mkIsoProgramInMacOsFileMock, Mockito.times(1)).getCanonicalPath();
496+
}
389497
}

server/test/com/cloud/network/element/ConfigDriveNetworkElementTest.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import static org.mockito.Mockito.when;
3232

3333
import java.lang.reflect.Field;
34+
import java.lang.reflect.Method;
3435
import java.util.Arrays;
3536
import java.util.List;
3637
import java.util.Map;
@@ -41,12 +42,20 @@
4142
import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
4243
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
4344
import org.apache.cloudstack.storage.configdrive.ConfigDrive;
45+
import org.apache.cloudstack.storage.configdrive.ConfigDriveBuilder;
46+
import org.junit.Before;
4447
import org.junit.Test;
48+
import org.junit.runner.RunWith;
4549
import org.mockito.ArgumentCaptor;
4650
import org.mockito.InjectMocks;
4751
import org.mockito.Mock;
52+
import org.mockito.Mockito;
4853
import org.mockito.MockitoAnnotations;
4954
import org.mockito.Spy;
55+
import org.powermock.api.mockito.PowerMockito;
56+
import org.powermock.core.classloader.annotations.PrepareForTest;
57+
import org.powermock.modules.junit4.PowerMockRunner;
58+
import org.reflections.ReflectionUtils;
5059

5160
import com.cloud.agent.AgentManager;
5261
import com.cloud.agent.api.Answer;
@@ -90,6 +99,7 @@
9099
import com.cloud.vm.dao.VMInstanceDao;
91100
import com.google.common.collect.Maps;
92101

102+
@RunWith(PowerMockRunner.class)
93103
public class ConfigDriveNetworkElementTest {
94104

95105
public static final String CLOUD_ID = "xx";
@@ -140,7 +150,7 @@ public class ConfigDriveNetworkElementTest {
140150
@InjectMocks private final ConfigDriveNetworkElement _configDrivesNetworkElement = new ConfigDriveNetworkElement();
141151
@InjectMocks @Spy private NetworkModelImpl _networkModel = new NetworkModelImpl();
142152

143-
@org.junit.Before
153+
@Before
144154
public void setUp() throws NoSuchFieldException, IllegalAccessException {
145155
MockitoAnnotations.initMocks(this);
146156

@@ -243,7 +253,14 @@ public void testGetCapabilities () {
243253
}
244254

245255
@Test
256+
@SuppressWarnings("unchecked")
257+
@PrepareForTest({ConfigDriveBuilder.class})
246258
public void testAddPasswordAndUserData() throws Exception {
259+
PowerMockito.mockStatic(ConfigDriveBuilder.class);
260+
261+
Method method = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("buildConfigDrive")).iterator().next();
262+
PowerMockito.when(ConfigDriveBuilder.class, method).withArguments(Mockito.anyListOf(String[].class), Mockito.anyString(), Mockito.anyString()).thenReturn("content");
263+
247264
final Answer answer = mock(Answer.class);
248265
final UserVmDetailVO userVmDetailVO = mock(UserVmDetailVO.class);
249266
when(agentManager.easySend(anyLong(), any(HandleConfigDriveIsoCommand.class))).thenReturn(answer);

0 commit comments

Comments
 (0)