The main motivation behind this refactor work is to increase the readability/quality of some of the ServerResource interface implementations, like the CitrixResourceBase, LibvirtComputingResource and NiciraNvpResource classes. There are several other implementations of ServerResource, but they won't be tackled on the 4.6.0 release of Apache CloudStack.
In order to fulfil our goal a number of points have to be worked on:
In order to give an idea on how the refactor took place for those ServerResource implementation, some extra documentation, including code snippets and diagrams, is available below. Although the diagrams and code snippets use the CitrixResrouceBase as example, the same approach has been successfully applied to LibvirtComputingResource and NiciraNvpResource. Although the latter is not an hypervisor implementation, but a network plugin.
The ServerResource.executeRequest() method expects a Command object, which is defined in the Cloud Core module. Since we could not change this structure, in order to avoid a major change in the whole API layer, we added a CommandWrapper to deal with the behaviour expected by each ServerResourse sub-class. In that sense, the whole XenServer, Libvirt and Nicira implementations are completely independent and don't change anything in the existing commands. Only extensions of the CommandWrapper<T extends Command, A extends Answer, R extends ServerResource> class will be enough to have the commands decoupled from the ServerResource implementation.
In order to have a smooth refactor, we added the following resources to the Cloud-Core module:
By using the 3 objects mentioned above we no longer need the 143 if/else block that were part of the 3 refactored classes; which also led to 143 private methods. Instead, we can simply load a command from the wrapper with the snippet below:
final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); try { return wrapper.execute(cmd, this); } catch (final Exception e) { return Answer.createUnsupportedCommandAnswer(cmd); }
The diagram below depicts the relationship between the CitrixResourceBase and the new classes. The same can be applied to LibvirtComputingResource and NiciraNvpResource. Future implementations will follow the same model.
Please keep in mind that It's just an exhibit of what has been done: we did not want to add all the new classes to the diagram.
The image is a bit too large, but one can download the original in order to have a better idea of the implementation.
In order to keep the maintenance of the ServerResource implementations easy, we also added the use of Reflections & Annotations in the current code. What kind of benefits does it bring?
The ResourceWrapper annotation is simple and contains only one attributes: handles. That attribute is used to indicate which Command should be handled by the Wrapper class. Check the annotation code below:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ResourceWrapper { Class<? extends Command> handles(); }
Loading CommandWrappers annotated with the ResourceWrapper will need three simple steps:
Load the CommadWrappers that are annotated
Reflections baseWrappers = new Reflections("com.cloud.hypervisor.xenserver.resource.wrapper.xenbase") Set<Class<? extends CommandWrapper>> baseSet = baseWrappers.getSubTypesOf(CommandWrapper.class);
Fill the resources
final Hashtable<Class<? extends Command>, CommandWrapper> citrixCommands = processAnnotations(baseSet); resources.put(CitrixResourceBase.class, citrixCommands);
The resources map is defined in the RequestWrapper abstract class.
When defining a new wrapper class for a given Command, we have to follow the following:
Check the snippet below:
@ResourceWrapper(handles = RebootRouterCommand.class) public final class CitrixRebootRouterCommandWrapper extends CommandWrapper<RebootRouterCommand, Answer, CitrixResourceBase> { ... }
1 Comment
Marco Sinhoreli
In OpenStack they are using the XAPI host.plugin call to execute commands in the Dom0 side and it can be extensible to connect in the SystemVMs and call shell commands in the Dom0. I started this discussion here:
http://mail-archives.apache.org/mod_mbox/cloudstack-dev/201411.mbox/%3CD0978DA1.106BC%25marco.sinhoreli@shapeblue.com%3E
Today only ROOT user is used to connect to the XenServer and it can be increased using the XenServer RBAC to enable non-root users for example.