Skip to content

Commit f02e402

Browse files
DaanHooglandrohityadavcloud
authored andcommitted
kvm: send unsupported answer only when applicable (apache#2714)
Throw specific NPE child when command is known not to be known. Add unit tests.
1 parent d4e302d commit f02e402

File tree

4 files changed

+55
-9
lines changed

4 files changed

+55
-9
lines changed

core/src/com/cloud/resource/RequestWrapper.java

+15-8
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,15 @@
2929
import com.cloud.agent.api.Command;
3030

3131
public abstract class RequestWrapper {
32+
static public class CommandNotSupported extends NullPointerException {
33+
public CommandNotSupported(String msg) {
34+
super(msg);
35+
}
36+
public CommandNotSupported(String msg, Throwable cause) {
37+
super(msg);
38+
initCause(cause);
39+
}
40+
}
3241

3342
private static final Logger s_logger = Logger.getLogger(RequestWrapper.class);
3443

@@ -52,7 +61,7 @@ protected Hashtable<Class<? extends Command>, CommandWrapper> retrieveResource(f
5261

5362
keepResourceClass = keepResourceClass2;
5463
} catch (final ClassCastException e) {
55-
throw new NullPointerException("No key found for '" + command.getClass() + "' in the Map!");
64+
throw new CommandNotSupported("No key found for '" + command.getClass() + "' in the Map!");
5665
}
5766
}
5867
return resource;
@@ -69,14 +78,14 @@ protected CommandWrapper<Command, Answer, ServerResource> retrieveCommands(final
6978
final Class<? extends Command> commandClass2 = (Class<? extends Command>) keepCommandClass.getSuperclass();
7079

7180
if (commandClass2 == null) {
72-
throw new NullPointerException("All the COMMAND hierarchy tree has been visited but no compliant key has been found for '" + commandClass + "'.");
81+
throw new CommandNotSupported("All the COMMAND hierarchy tree has been visited but no compliant key has been found for '" + commandClass + "'.");
7382
}
7483

7584
commandWrapper = resourceCommands.get(commandClass2);
7685

7786
keepCommandClass = commandClass2;
7887
} catch (final ClassCastException e) {
79-
throw new NullPointerException("No key found for '" + keepCommandClass.getClass() + "' in the Map!");
88+
throw new CommandNotSupported("No key found for '" + keepCommandClass.getClass() + "' in the Map!");
8089
} catch (final NullPointerException e) {
8190
// Will now traverse all the resource hierarchy. Returning null
8291
// is not a problem.
@@ -102,18 +111,16 @@ protected CommandWrapper<Command, Answer, ServerResource> retryWhenAllFails(fina
102111
final Class<? extends ServerResource> resourceClass2 = (Class<? extends ServerResource>) keepResourceClass.getSuperclass();
103112

104113
if (resourceClass2 == null) {
105-
throw new NullPointerException("All the SERVER-RESOURCE hierarchy tree has been visited but no compliant key has been found for '" + command.getClass() + "'.");
114+
throw new CommandNotSupported("All the SERVER-RESOURCE hierarchy tree has been visited but no compliant key has been found for '" + command.getClass() + "'.");
106115
}
107116

108117
final Hashtable<Class<? extends Command>, CommandWrapper> resourceCommands2 = retrieveResource(command,
109118
(Class<? extends ServerResource>) keepResourceClass.getSuperclass());
110119
keepResourceClass = resourceClass2;
111120

112121
commandWrapper = retrieveCommands(command.getClass(), resourceCommands2);
113-
} catch (final ClassCastException e) {
114-
throw new NullPointerException("No key found for '" + command.getClass() + "' in the Map!");
115-
} catch (final NullPointerException e) {
116-
throw e;
122+
} catch (final ClassCastException | NullPointerException e) {
123+
throw new CommandNotSupported("No key found for '" + command.getClass() + "' in the Map!", e);
117124
}
118125
}
119126
return commandWrapper;

plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import javax.xml.parsers.DocumentBuilderFactory;
4848
import javax.xml.parsers.ParserConfigurationException;
4949

50+
import com.cloud.resource.RequestWrapper;
5051
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
5152
import org.apache.cloudstack.storage.to.VolumeObjectTO;
5253
import org.apache.cloudstack.utils.hypervisor.HypervisorUtils;
@@ -1432,13 +1433,21 @@ public boolean stop() {
14321433
return true;
14331434
}
14341435

1436+
/**
1437+
* This finds a command wrapper to handle the command and executes it.
1438+
* If no wrapper is found an {@see UnsupportedAnswer} is sent back.
1439+
* Any other exceptions are to be caught and wrapped in an generic {@see Answer}, marked as failed.
1440+
*
1441+
* @param cmd the instance of a {@see Command} to execute.
1442+
* @return the for the {@see Command} appropriate {@see Answer} or {@see UnsupportedAnswer}
1443+
*/
14351444
@Override
14361445
public Answer executeRequest(final Command cmd) {
14371446

14381447
final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance();
14391448
try {
14401449
return wrapper.execute(cmd, this);
1441-
} catch (final Exception e) {
1450+
} catch (final RequestWrapper.CommandNotSupported cmde) {
14421451
return Answer.createUnsupportedCommandAnswer(cmd);
14431452
}
14441453
}

plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRequestWrapper.java

+3
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ public Answer execute(final Command command, final ServerResource serverResource
7272
commandWrapper = retryWhenAllFails(command, resourceClass, resourceCommands);
7373
}
7474

75+
if (commandWrapper == null) {
76+
throw new CommandNotSupported("No way to handle " + command.getClass());
77+
}
7578
return commandWrapper.execute(command, serverResource);
7679
}
7780
}

plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java

+27
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
import javax.xml.xpath.XPathExpressionException;
3939
import javax.xml.xpath.XPathFactory;
4040

41+
import com.cloud.agent.api.Command;
42+
import com.cloud.agent.api.UnsupportedAnswer;
4143
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.CpuTuneDef;
4244
import org.apache.commons.lang.SystemUtils;
4345
import org.joda.time.Duration;
@@ -5191,4 +5193,29 @@ public void testSetQuotaAndPeriodMinQuota() {
51915193
Assert.assertEquals(CpuTuneDef.MIN_QUOTA, cpuTuneDef.getQuota());
51925194
Assert.assertEquals((int) (CpuTuneDef.MIN_QUOTA / pct), cpuTuneDef.getPeriod());
51935195
}
5196+
5197+
@Test
5198+
public void testUnknownCommand() {
5199+
libvirtComputingResource = new LibvirtComputingResource();
5200+
Command cmd = new Command() {
5201+
@Override public boolean executeInSequence() {
5202+
return false;
5203+
}
5204+
};
5205+
Answer ans = libvirtComputingResource.executeRequest(cmd);
5206+
assertTrue(ans instanceof UnsupportedAnswer);
5207+
}
5208+
5209+
@Test
5210+
public void testKnownCommand() {
5211+
libvirtComputingResource = new LibvirtComputingResource();
5212+
Command cmd = new PingTestCommand() {
5213+
@Override public boolean executeInSequence() {
5214+
throw new NullPointerException("test succeeded");
5215+
}
5216+
};
5217+
Answer ans = libvirtComputingResource.executeRequest(cmd);
5218+
assertFalse(ans instanceof UnsupportedAnswer);
5219+
assertTrue(ans instanceof Answer);
5220+
}
51945221
}

0 commit comments

Comments
 (0)