Creating my first plugin
This is a brief walk through of creating a simple plugin that adds an additional command to the API to return the message "Hello World".
Letting Cloudstack know about the plugin
Before we can being we need to tell Cloudstack about the existance of our plugin. In order to do this we are required to edit some files related to the cloud-client-ui module
Navigate to the folder called client
Open pom.xml and add a dependency, this will look something like the following:
client/pom.xml
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-api-helloworld</artifactId>
<version>${project.version}</version>
</dependency>
Continuing with client as your working directory open up tomcatconf/applicationContext.xml.in
Within this file we must insert a bean to load our class:
client/tomcatconf/applicationContext.xml.in
<bean id="helloWorldImpl" class="org.apache.cloudstack.helloworld.HelloWorldImpl" />
Finally we need to register the additional API commands we add. Again with client as your working directory this is done by modifying tomcatconf/commands.properties.in
Within the file we simply add the names of the API commands we want to create followed by a permission number. 1 = admin, 2 = resource domain admin, 4 = domain admin, 8 = user.
tomcatconf/commands.properties.in
helloWorld=8
Creating the plugin
Within the Cloudstack filing structure all plugins live under the plugins folder. Since the sample plugin for this document is going to be API related it will live in plugins/api/helloworld. Along with this we will need a standard maven package layout, so lets create all the required folders:
$ mkdir -p plugins/api/helloworld/{src,target,test}
$ mkdir -p plugins/api/helloworld/src/org/apache/cloudstack/{api,helloworld}
$ mkdir -p plugins/api/helloworld/src/org/apache/cloudstack/api/{command,response}
$ mkdir -p plugins/api/helloworld/src/org/apache/cloudstack/api/command/user/helloworld
With helloworld as our working directory we should have a tree layout like the following:
$ cd plugins/api/helloworld
$ tree
.
|-- src
| `-- org
| `-- apache
| `-- cloudstack
| |-- api
| | |-- command
| | | `-- user
| | | `-- helloworld
| | |-- response
| `-- helloworld
|-- target
`-- test
12 directories, 0 files
First we will create a pom.xml for our plugin:
plugins/api/helloworld/pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-plugin-api-helloworld</artifactId>
<name>Apache CloudStack Plugin - Hello World Plugin</name>
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
<version>4.2.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-utils</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<defaultGoal>install</defaultGoal>
<sourceDirectory>src</sourceDirectory>
<testSourceDirectory>test</testSourceDirectory>
</build>
</project>
Next we need to make the root plugin pom aware of our plugin to do this simply edit plugins/pom.xml inserting a line like the following:
......
<module>api/helloworld</module>
......
Finally we will being to create code for your plugin. Create an interface called HelloWorld that will extend PluggableService within src/org/apache/cloudstack/hellowold
package org.apache.cloudstack.helloworld;
import com.cloud.utils.component.PluggableService;
public interface HelloWorld extends PluggableService { }
Create an implementation of HelloWorld called HelloWorldImpl:
package org.apache.cloudstack.helloworld;
import org.apache.cloudstack.api.command.user.helloworld.HelloWorldCmd;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import javax.ejb.Local;
import java.util.*;
@Component
@Local(value = HelloWorld.class)
public class HelloWorldImpl implements HelloWorld {
private static final Logger s_logger = Logger.getLogger(HelloWorldImpl.class);
public HelloWorldImpl() {
super();
}
/**
* This informs cloudstack of the API commands you are creating.
*/
@Override
public List<Class<?>> getCommands() {
List<Class<?>> cmdList = new ArrayList<Class<?>>();
cmdList.add(HelloWorldCmd.class);
return cmdList;
}
}
Next we will create our API command navigate to src/org/apache/cloudstack/api/command/user/helloworld and open up HelloWorldCmd.java, create it as follows
package org.apache.cloudstack.api.command.user.helloworld;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.response.HelloWorldResponse;
import org.apache.log4j.Logger;
// Note this name matches the name you inserted into client/tomcatconf/commands.properties.in
@APICommand(name = "helloWorld", responseObject = HelloWorldResponse.class, description = "Returns a hello world message", since = "4.2.0")
public class HelloWorldCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(HelloWorldCmd.class.getName());
private static final String s_name = "helloworldresponse";
@Override
public void execute()
{
HelloWorldResponse response = new HelloWorldResponse();
response.setObjectName("helloworld");
response.setResponseName(getCommandName());
this.setResponseObject(response);
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
return 0;
}
}
Finally we need to create our HelloWorldResponse class, this will exist within src/org/apache/cloudstack/api/response/
package org.apache.cloudstack.api.response;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.BaseResponse;
import com.cloud.serializer.Param;
@SuppressWarnings("unused")
public class HelloWorldResponse extends BaseResponse {
@SerializedName("HelloWorld") @Param(description="HelloWorld Response")
private String HelloWorld;
public HelloWorldResponse(){
this.HelloWorld = "Hello World";
}
}
Compiling your plugin:
Within the directory of your plugin i.e. plugins/api/helloworld run mvn clean install.
After this we need to recompile the client-cloud-ui to do this come back to the cloudstack base directory and execute mvn -pl client clean install
Starting Cloudstack and Testing:
Start up cloudstack with the normal mvn pl :client-cloud-ui jetty:run, wait a few moments for it to start up then head over to: localhost:8096/client/api?command=helloWorld and you should see your HelloWorld message.