Acquiring and releasing cloud servers in Java using JClouds

Acquiring and releasing cloud servers in Java using JClouds

In this post, we will look at an example of how to programmatically acquire and release cloud servers using the JClouds API. The JClouds API works with a large number of cloud providers including Amazon EC2  and Rackspace and allows you to perform a large number of operations using Java Code as opposed to interacting with individual APIs of these providers. In this example, we are using rackspace as our cloud provider.

Let’s first get jars for jclouds. If you are using Maven, following are the maven dependencies. You may want to check if newer versions are available when you plan to implement this.


<dependency>
     <groupId>org.jclouds</groupId>
     <artifactId>jclouds-allcompute</artifactId>
     <version>1.5.2</version>
</dependency>
<dependency>
     <groupId>org.jclouds.driver</groupId>
     <artifactId>jclouds-sshj</artifactId>
     <version>1.5.1</version>
</dependency>
<dependency>
     <groupId>org.jclouds.driver</groupId>
     <artifactId>jclouds-log4j</artifactId>
     <version>1.5.1</version>
</dependency>

Creating a Compute Service

Lets create a class ‘CloudService’. In the constructor of this class, we will set API information such as username and API key, as well as create an instance of the ‘compute service’ object.


package co.syntx.examples.jclouds;

import static org.jclouds.compute.predicates.NodePredicates.inGroup;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.jclouds.ContextBuilder;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;

public class CloudService {

    private ComputeService compute;
    private String location;
    public static final Logger logger = Logger.getLogger(CloudService.class);

    /**
     *  Constructor for the CloudService Class. Requires you to specify the cloud provider string, datacenter location,  the username and the API Key.
     * @param provider
     * @param location
     * @param username
     * @param apiKey
     */

     public CloudService(String provider, String location, String username, String apiKey) {
        this.location = location;  
         ComputeServiceContext context = ContextBuilder.newBuilder(provider).credentials(username, apiKey)
					.buildView(ComputeServiceContext.class);
         compute = context.getComputeService();
         logger.info("Cloud Compute Service Context Created");
     }

Function to Acquire a Server

Next, we will write the function that acquires servers from our cloud provider. The parameters of the function are

  • groupName: if you acquire multiple servers, all servers will have groupName as the prefix. This helps in identification and categorization.
  • OS: The name of the Operating System
  • osVersion: The version of the Operating System
  • ram: The size of RAM
  • count: Number of cloud servers required

/**
* Acquire Servers by specifying specs
* @param groupName
* @param os
* @param osVersion
* @param ram
* @param count
* @throws Exception
*/
public void aquireServer(String groupName, String os, String osVersion, Integer ram, Integer count) throws Exception {

     TemplateBuilder templateBuilder = compute.templateBuilder();
     Template template = templateBuilder
                         .locationId(this.location)
                         .os64Bit(true)
                         .osDescriptionMatches(os)
                         .osVersionMatches(osVersion)
                         .minRam(ram)
                         .build();

      logger.info("Acquiring "+ count+ " server(s).");
      Set<? extends NodeMetadata> nodes = compute.createNodesInGroup(groupName,count, template);
      logger.info(nodes.size() + " server(s) acquired!");
}

Function to release servers belonging to a group

You can release servers that belong to a group in one go. You can also release individual servers. The following code releases all servers belonging to a particular group.


public void releaseGroup(String groupName) throws Exception {
    logger.info("Releasing server(s) from group " + groupName);
    Set<? extends NodeMetadata> servers = compute.destroyNodesMatching(inGroup(groupName));		
    logger.info(servers.size() + " released from group " + groupName);
}

Putting it together

Finally, we will create an instance of our class and call the functions we have written earlier. Specify method parameters according to your environment. Prior to calling the acquire function, your rackspace dashboard may look something like this.

rackspace dashboard

 

CloudService cloudService = new CloudService("rackspace-cloudservers-us","DFW", "yourUsername", "yourAPIKey");
cloudService.aquireServer("my-test-servers","Ubuntu","12.04",512,2);

The acquireServer call will block until servers are successfully acquired. During the acquisition, your dashboard will look something like this.

rackspace dashboard, pending servers

Finally, the releaseGroup function call, releases the acquired servers.


cloudService.releaseGroup("my-test-servers");

This is a very basic example of using JClouds. The library is very extensive and lots more functionality. The best part is that JClouds abstracts out your choice of cloud provider and your code will suffer zero or minimal change in case you decide to shift cloud vendors.