...
How to write an Apache CloudStack 4.1+ API:
...
1. Create a directory off of the plugins folder. The name does not matter. Example: cloudstack/plugins/api/timeofday
2. Create a pom.xml in cloudstack/plugins/api/timeofday. Make sure your "parent" relative path points back to plugins/pom.xml, otherwise it won't build. The main entries that matter are the artifactId (cloud-plugin-timeofday), as well as the dependencies.
Code Block |
---|
lang | xml |
---|
title | plugins/api/timeofday/pom.xml |
---|
borderStyle | solid |
---|
|
<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-timeofday</artifactId>
<name>Apache CloudStack Plugin - TimeOfDay</name>
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
<version>4.1.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>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${cs.mysql.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<defaultGoal>install</defaultGoal>
<sourceDirectory>src</sourceDirectory>
<testSourceDirectory>test</testSourceDirectory>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
|
3. Now create a src, target and test directory off of cloud-plugin-timeofday.
4. Create your code hierarchy ie: com.company.gadget.plugin. For this example I use plugins/api/timeofday/src/com/cloud/test
5. Create an interface that extends from PluggableService
Code Block |
---|
lang | java |
---|
title | plugins/api/timeofday/src/com/cloud/test/TimeOfDayManager.java |
---|
borderStyle | solid |
---|
|
package com.cloud.test;
import com.cloud.utils.component.PluggableService;
public interface TimeOfDayManager extends PluggableService { }
|
6. Create an implementation of your newly created interface, overriding the getCommands method, and populating it with the classes of each command you want to expose.
Code Block |
---|
lang | java |
---|
title | plugins/api/timeofday/src/com/cloud/test/TimeOfDayManagerImpl.java |
---|
borderStyle | solid |
---|
|
package com.cloud.test;
import com.cloud.utils.component.PluggableService;
import java.util.List;
import java.util.ArrayList;
import org.apache.log4j.Logger;
import com.cloud.test.GetTimeOfDayCmd;
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;
import javax.ejb.Local;
@Component
@Local(value = { TimeOfDayManager.class })
public class TimeOfDayManagerImpl implements TimeOfDayManager {
private static final Logger s_logger = Logger.getLogger(TimeOfDayManagerImpl.class);
public TimeOfDayManagerImpl() {
super();
}
@Override
public List<Class<?>> getCommands() {
List<Class<?>> cmdList = new ArrayList<Class<?>>();
cmdList.add(GetTimeOfDayCmd.class);
return cmdList;
}
}
|
7. Create an implementation of your newly created interface, overriding the getCommands method, and populating it with the classes of each command you want to expose.
Code Block |
---|
lang | java |
---|
title | plugins/api/timeofday/src/com/cloud/test/TimeOfDayManagerImpl.java |
---|
borderStyle | solid |
---|
|
package com.cloud.test;
import com.cloud.utils.component.PluggableService;
import java.util.List;
import java.util.ArrayList;
import org.apache.log4j.Logger;
import com.cloud.test.GetTimeOfDayCmd;
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;
import javax.ejb.Local;
@Component
@Local(value = { TimeOfDayManager.class })
public class TimeOfDayManagerImpl implements TimeOfDayManager {
private static final Logger s_logger = Logger.getLogger(TimeOfDayManagerImpl.class);
public TimeOfDayManagerImpl() {
super();
}
@Override
public List<Class<?>> getCommands() {
List<Class<?>> cmdList = new ArrayList<Class<?>>();
cmdList.add(GetTimeOfDayCmd.class);
return cmdList;
}
}
|
8. Write a command class that implements the correct annotations for a command:
Code Block |
---|
lang | java |
---|
title | plugins/api/timeofday/src/com/cloud/test/GetTimeOfDayCmd.java |
---|
borderStyle | solid |
---|
|
package com.cloud.test;
import javax.inject.Inject;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.Parameter;
@APICommand(name = "getTimeOfDay", description="Get Cloudstack's time of day", responseObject = GetTimeOfDayCmdResponse.class, includeInApiDoc=true)
public class GetTimeOfDayCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(GetTimeOfDayCmd.class.getName());
private static final String s_name = "gettimeofdayresponse";
@Parameter(name="example", type=CommandType.STRING, required=false, description="Just an example string that will be uppercased")
private String example;
public String getExample() {
return this.example;
}
@Override
public void execute()
{
GetTimeOfDayCmdResponse response = new GetTimeOfDayCmdResponse();
if ( this.example != null ) {
response.setExampleEcho(example);
}
response.setObjectName("timeofday"); // the inner part of the json structure
response.setResponseName(getCommandName()); // the outer part of the json structure
this.setResponseObject(response);
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
return 0;
}
}
|
9. Write a Response class for the command:
Code Block |
---|
lang | java |
---|
title | plugins/api/timeofday/src/com/cloud/test/GetTimeOfDayResponse.java |
---|
borderStyle | solid |
---|
|
package com.cloud.test;
import org.apache.cloudstack.api.ApiConstants;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.BaseResponse;
import java.util.Date;
import java.text.SimpleDateFormat;
@SuppressWarnings("unused")
public class GetTimeOfDayCmdResponse extends BaseResponse {
@SerializedName(ApiConstants.IS_ASYNC) @Param(description="true if api is asynchronous")
private Boolean isAsync;
@SerializedName("timeOfDay") @Param(description="The time of day from CloudStack")
private String timeOfDay;
@SerializedName("exampleEcho") @Param(description="An upper cased string")
private String exampleEcho;
public GetTimeOfDayCmdResponse(){
this.isAsync = false;
SimpleDateFormat dateformatYYYYMMDD = new SimpleDateFormat("yyyyMMdd hh:mm:ss");
this.setTimeOfDay( (new StringBuilder( dateformatYYYYMMDD.format( new Date() ) )).toString() );
}
public void setAsync(Boolean isAsync) {
this.isAsync = isAsync;
}
public boolean getAsync() {
return isAsync;
}
public void setTimeOfDay(String timeOfDay) {
this.timeOfDay = timeOfDay;
}
public void setExampleEcho(String exampleEcho) {
this.exampleEcho = exampleEcho.toUpperCase();
}
}
|
10. Update client/tomcatconf/componentContext.xml and add your new manager to it's configuration:
Code Block |
---|
|
<bean id="timeOfDayManagerImpl" class="com.cloud.test.TimeOfDayManagerImpl"> </bean>
|
11. Lastly, update client/tomcatconf/commands.properties.in, and add the command name (for the example this would be getTimeOfDay as stated in the @APICommand annotation).
12. You can test your new command via the browser, cloudmonkey or even curl. Here is a simple perl script that shows how to test the new getTimeOfDay command.
Code Block |
---|
lang | javascript |
---|
borderStyle | solid |
---|
|
#!/usr/bin/env perl
use strict;
use Data::Dumper;
use LWP::Simple;
use Mojo::JSON 'j';
my $content = j(get("http://localhost:8096/client/api?command=getTimeOfDay&response=json&example=moo"));
print Dumper($content);
|
And here is the output
Code Block |
---|
lang | javascript |
---|
borderStyle | solid |
---|
|
$VAR1 = {
'gettimeofdayresponse' => {
'timeofday' => {
'timeOfDay' => '20130404 09:24:00',
'exampleEcho' => 'MOO',
'isasync' => bless( do{\(my $o = 0)}, 'Mojo::JSON::_Bool' )
}
}
};
|
...