com.atlassian.confluence.content.render.xhtml.migration.exceptions.UnknownMacroMigrationException: The macro 'next_previous_link3' is unknown.

Adding Support for a New IaaS Provider

The WSO2 Private PaaS allows you to add a support for a new IaaS provider which Apache Jclouds supports. Following steps describe how you could leverage this feature and provides support for a new IaaS.

Above image depicts how WSO2 Private PaaS Cloud Controller communicates with the underlying IaaS via Apache Jclouds APIs. Cloud Controller introduces set of interfaces that you need to implement when you provide support for a new IaaS.

  1. org.apache.stratos.cloud.controller.interfaces.Iaas abstract class.
  2. org.apache.stratos.cloud.controller.validate.interfaces.PartitionValidator interface.

Let's look at how you can extend the Iaas abstract class. Following code block has the code of org.apache.stratos.cloud.controller.interfaces.Iaas abstract class.

/**
 * All IaaSes that are going to support by Cloud Controller, should extend this abstract class.
 */
public abstract class Iaas {
    /**
     * Reference to the corresponding {@link IaasProvider}
     */
    private IaasProvider iaasProvider;
    
    public Iaas(IaasProvider iaasProvider) {
        this.setIaasProvider(iaasProvider);
    }
    
    public IaasProvider getIaasProvider() {
        return iaasProvider;
    }
    public void setIaasProvider(IaasProvider iaasProvider) {
        this.iaasProvider = iaasProvider;
    }
    
    /**
     * This should build the {@link ComputeService} object and the {@link Template} object,
     * using the information from {@link IaasProvider} and should set the built 
     * {@link ComputeService} object in the {@link IaasProvider#setComputeService(ComputeService)}
     * and also should set the built {@link Template} object in the 
     * {@link IaasProvider#setTemplate(Template)}.
     */
    public abstract void buildComputeServiceAndTemplate();   
 
	/**
     * Builds only the jclouds {@link Template}
     */
    public abstract void buildTemplate();
  
 	/**
     * This method provides a way to set payload that can be obtained from {@link IaasProvider#getPayload()}
     * in the {@link Template} of this IaaS.
     */
    public abstract void setDynamicPayload();
    
    /**
     * This will obtain an IP address from the allocated list and associate that IP with this node.
     * @param node Node to be associated with an IP.
     * @return associated public IP.
     */
    public abstract String associateAddress(NodeMetadata node);
    
    /**
     * This will obtain a predefined IP address and associate that IP with this node, if ip is already in use allocate ip from pool 
     * (through associateAddress())
     * @param node Node to be associated with an IP.
     * @ip preallocated floating Ip
     * @return associated public IP.
     */
    public abstract String associatePredefinedAddress(NodeMetadata node, String ip);
    
    /**
     * This will deallocate/release the given IP address back to pool.
     * @param iaasInfo corresponding {@link IaasProvider}
     * @param ip public IP address to be released.
     */
    public abstract void releaseAddress(String ip);
    
    /**
     * This method should create a Key Pair corresponds to a given public key in the respective region having the name given.
     * Also should override the value of the key pair in the {@link Template} of this IaaS.
     * @param region region that the key pair will get created.
     * @param keyPairName name of the key pair. NOTE: Jclouds adds a prefix : <code>jclouds#</code>
     * @param publicKey public key, from which the key pair will be created.
     * @return whether the key pair creation is successful or not.
     */
    public abstract boolean createKeyPairFromPublicKey(String region, String keyPairName, String publicKey);
    
    /**
     * Validate a given region name against a particular IaaS.
     * If a particular IaaS doesn't have a concept called region, it can simply throw {@link InvalidRegionException}.
     * @param region name of the region.
     * @return whether the region is valid.
     * @throws InvalidRegionException if the region is invalid.
     */
    public abstract boolean isValidRegion(String region) throws InvalidRegionException;
    
    /**
     * Validate a given zone name against a particular region in an IaaS.
     * If a particular IaaS doesn't have a concept called zone, it can simply throw {@link InvalidZoneException}.
     * @param region region of the IaaS that the zone belongs to.
     * @param zone 
     * @return whether the zone is valid in the given region or not.
     * @throws InvalidZoneException if the zone is invalid in a given region.
     */
    public abstract boolean isValidZone(String region, String zone) throws InvalidZoneException;
    
    /**
     * Validate a given host id against a particular zone in an IaaS.
     * If a particular IaaS doesn't have a concept called hosts, it can simply throw {@link InvalidHostException}.
     * @param zone zone of the IaaS that the host belongs to.
     * @param host
     * @return whether the host is valid in the given zone or not.
     * @throws InvalidHostException if the host is invalid in a given zone.
     */
    public abstract boolean isValidHost(String zone, String host) throws InvalidHostException;
    
    /**
     * provides the {@link PartitionValidator} corresponds to this particular IaaS.
     * @return {@link PartitionValidator}
     */
    public abstract PartitionValidator getPartitionValidator();
    
    /**
     * Create a new volume in the respective Iaas.
     * @param sizeGB size of the volume in Giga Bytes.
     * @return Id of the created volume.
     */
    public abstract String createVolume(int sizeGB);
   
    /**
     * Attach a given volume to an instance at the specified device path.
     * @param instanceId of the instance.
     * @param volumeId volume id of the volume to be attached.
     * @param deviceName name of the device that the volume would bind to.
     * @return the status of the attachment.
     */
    public abstract String attachVolume(String instanceId, String volumeId, String deviceName);
    
    /**
     * Detach a given volume from the given instance.
     * @param instanceId of the instance.
     * @param volumeId volume id of the volume to be detached.
     */
    public abstract void detachVolume(String instanceId, String volumeId);
    
    /**
     * Delete a given volume.
     * @param volumeId volume id of the volume to be detached.
     */
    public abstract void deleteVolume(String volumeId);

 	/**
     * This returns the device of the volume specified by the user. This is depends on IAAS. 
     * For an instance /dev/sdf maps to /dev/xvdf in EC2.
     */
    public abstract String getIaasDevice(String device);
}

As you can see at line 8, this class holds an instance of IaasProvider class which is responsible for providing all IaaS related configurations that you have made using both cloud-controller.xml file and Cartridge definition file. That in turn means that within your Iaas implementation class, you have the access to all the IaaS specific configurations.

Best way to get started with your IaaS specific implementation is to look at an existing Iaas implementation. As you can see, what you have to mainly do is to call the relevant Jclouds APIs within each of the methods that you need to override.

Secondly, you need to implement the org.apache.stratos.cloud.controller.validate.interfaces.PartitionValidator interface which is used to validate the Partition deployment against the respective IaaS.

public interface PartitionValidator {
    
    /**
     * set the IaasProvider reference.
     * @param iaas {@link IaasProvider}
     */
    public void setIaasProvider(IaasProvider iaas);
    /**
     * Validate the given properties for its existent in this partition.
     * @param partitionId partition id.
     * @param properties set of properties to be validated.
     * @return cloned and modified {@link IaasProvider} which maps to the given partition. 
     * @throws InvalidPartitionException if at least one property is evaluated to be invalid.
     */
    public IaasProvider validate(String partitionId, Properties properties) throws InvalidPartitionException;
}

Again, you could have a look at an existing implementation of this interface to get a better understanding.

Once you have these two implementations developed, you can perform following steps to get your implementation to the Stratos runtime.

  1. Wrap the implementation in an OSGi bundle. It should be a fragment bundle of the Cloud Controller component. You can specify this via your bundle's POM file.
    Add the following line as a configuration instruction of maven bundle plugin:

    <Fragment-Host>org.apache.stratos.cloud.controller</Fragment-Host>
  2. Add the cloud-controller component as a dependency in your bundle’s pom file.
  3. Drop the built bundle to the   <APACHE-STRATOS-CC>/repository/components/dropins/  directory.
  4. Define the IaasProvider you are going to add and your implementation class in the Cloud Controller's  cloud-controller.xml file. 

    <iaasProvider type="vcloud" name="vcloud specific details">
    	<className>org.apache.stratos.iaas.VcloudIaas</className>
      	<provider>vcloud</provider>
      	<identity svns:secretAlias="cloud.controller.vcloud.identity"/>
      	<credential svns:secretAlias="cloud.controller.vcloud.credential"/>
       	<property name="securityGroups" value="default"/>
       	<property name="instanceType" value="m1.large"/>
       	<property name="keyPair" value="abc-key"/>
    </iaasProvider>
  5. Now, you can start using the newly added IaaS in your Cartridge definition files.
com.atlassian.confluence.content.render.xhtml.migration.exceptions.UnknownMacroMigrationException: The macro 'next_previous_links2' is unknown.