jclouds is an open source multi-cloud toolkit for the Java platform that gives you the freedom to create applications that are portable across clouds while giving you full control to use cloud-specific features.

This guide will show you how to programmatically use the Dimension Data CloudControl provider in jclouds to perform common operations available in the CloudControl API.

Table of Contents


Concepts

The jclouds library wraps the Dimension Data CloudControl API. All operations are performed over SSL and authenticated using your Dimension Data CloudControl credentials. The API can be accessed directly over the Internet from any application that can send an HTTPS request and receive an HTTPS response.

Getting Started

Before you begin you will need to have a Dimension Data CloudControl account for your organization. The credentials will be used to authenticate against the API.

The Dimension Data CloudControl provider supports API version 2.4 currently. Upgrading to later versions, see JCLOUDS-1456 and JCLOUDS-1407 for current progress. and MCP 2.0 datacenters only.

Installation

jclouds has some pre-requisites before you're able to use it. You will need to:

    javac -version
    mvn -version

Now that you have validated the pre-requisities, you will want to do the following:

    mkdir jclouds

    cd jclouds
    mvn dependency:copy-dependencies "-DoutputDirectory=./lib"

You should now have a directory with the following structure:

    jclouds/
        pom.xml
        lib/        
            *.jar

The Dimension Data CloudControl provider is currently available as part of the jclouds labs project here. The Dimension Data CloudControl provider examples project is currently available as part of jclouds examples here.

Authentication

Connecting to Dimension Data CloudControl can be done by creating a compute connection with the dimensiondata-cloudcontrol provider.

To build an unwrapped version of the API do the following.

        ContextBuilder contextBuilder = ContextBuilder.newBuilder("dimensiondata-cloudcontrol");
        DimensionDataCloudControlApi api = contextBuilder
                .endpoint(endpoint)
                .credentials(username, password)
                .buildApi(DimensionDataCloudControlApi.class);

Caution: You will want to ensure you follow security best practices when using credentials within your code or stored in a file.

Portable Abstraction Usage

Terms

Like any cloud provider, Dimension Data CloudControl has its own set of terms in cloud computing. To abstract this into jclouds' Compute interface, these terms were associated:

Getting Started

    ComputeService compute = ContextBuilder.newBuilder( "dimensiondata-cloudcontrol" )
                             .credentials( "username", "password" )
                             .buildView( ComputeServiceContext.class )
                             .getComputeService();

The implementation of the jclouds abstraction is incomplete so it is best for now to use the unwrapped DimensionDataCloudControlApi.

Take note that these features are still accessible by unwrapping the Dimension Data CloudControl API, but this'll reduce portability of your code. See Concepts.

How To's

How to: List a Data Center

The Dimension Data CloudControl organization will be associated with one or more MCP 2.0 Data Centers. A Data Center is a container for the assets that will be deployed and created by the jclouds Dimension Data CloudControl Provider.

In jclouds terminology a Zone equates to a Data Center.

The following code example shows you how to programmatically list Data Centers:

     PagedIterable<Datacenter> datacenters = api.getInfrastructureApi().listDatacenters();

This responds with a paged result set containing the Data Centers visible to your organization.

How to: Deploy a Network Domain

For more information on Network Domains see here

The code to deploy a network domain follows.

        /*
         * Deploy Network Domain to the Zone / Datacenter we wish to operate on. The response from this API is the Network Domain Identifier.
         */
        String networkDomainId = api.getNetworkApi().deployNetworkDomain(AU9, "jclouds-example", "jclouds-example", "ESSENTIALS");

A Network Domain deployment is an asynchronous process. We need to wait for it to complete. The Dimension Data provider has built in google guice predicates that will block execution and check that the Network Domain's State has moved from PENDING_ADD to NORMAL.

Following is some example code that shows how the to use predicate suitable for asserting a Network Domain state has transitioned to the NORMAL state. The predicate uses the Network Domain Identifier we wish to check the state of.

        Injector injector = contextBuilder.buildInjector();
        Predicate<String> networkDomainNormalPredicate = injector.getInstance(Key.get(new TypeLiteral<Predicate<String>>()
        {
        }, Names.named("NETWORK_DOMAIN_NORMAL_PREDICATE")));
        networkDomainNormalPredicate.apply(networkDomainId);    

How to: Deploy a Vlan

For more information on Vlans see here

The code to deploy a Vlan follows.

        /*
         * Deploy the Vlan and associate it with the Network Domain that was previously created.
         * The Vlan is deployed with a privateIpv4BaseAddress and privateIpv4PrefixSize
         */
        String vlanId = api.getNetworkApi().deployVlan(networkDomainId, "jclouds-example-vlan", "jclouds-example-vlan", "10.0.0.0", 24);

A Vlan deployment is an asynchronous process. We need to wait for it to complete. The Dimension Data provider has built in predicates that will block execution and check that the Vlan's State has moved from PENDING_ADD to NORMAL.

Following is some example code that shows how the to use predicate suitable for asserting a Vlan state has transitioned to the NORMAL state. The predicate uses the Vlan Identifier we wish to check the state of.

        Injector injector = contextBuilder.buildInjector();
        Predicate<String> vlanNormalPredicate = injector.getInstance(Key.get(new TypeLiteral<Predicate<String>>()
        {
        }, Names.named("VLAN_NORMAL_PREDICATE")));
        vlanNormalPredicate.apply(vlanId);

How to: List Os Images

For more information on Os Images see here

An Image Id is required for deploying a server. It contains the hardware configuration that the deployed Server will have.

The code to list Os Images filtering on a datacenter follows.

   PaginatedCollection<OsImage> osImages = api.getServerImageApi().listOsImages(DatacenterIdListFilters.Builder.datacenterId("AU9"));

How to: Deploy a Server

For more information on Deploying Servers see here

The following example shows you how to create a new server in the virtual datacenter created above:

        /*
         * The Server that gets deployed will have some network configuration. It gets assigned to the Vlan that was created previously.
         */
        NetworkInfo networkInfo = NetworkInfo
                .create(networkDomainId, NIC.builder().vlanId(vlanId).build(), Lists.<NIC>newArrayList());
        /*
         * The Server that gets deployed will have some additional disk configuration.
         */
        List<Disk> disks = ImmutableList.of(Disk.builder().scsiId(0).speed("STANDARD").build());

        /*
         * The Server is deployed using the OS Image we selected,
         * a flag to signal if we want it started or not, an admin pass and the additional configuration we built.
         */
        String serverId = api.getServerApi()
                .deployServer("jclouds-server", imageId, true, networkInfo, "P$$ssWwrrdGoDd!", disks, null);

A Server deployment is an asynchronous process. We need to wait for it to complete. The Dimension Data provider has built in predicates that will block execution and check that the Server's State has moved from PENDING_ADD to NORMAL. This piece of sample code also waits for the Server to be started.

    static void waitForServerStartedAndNormal(Injector injector, String serverId)
    {
        Predicate<String> serverStartedPredicate = injector.getInstance(Key.get(new TypeLiteral<Predicate<String>>()
        {
        }, Names.named("SERVER_STARTED_PREDICATE")));
        Predicate<String> serverNormalPredicate = injector.getInstance(Key.get(new TypeLiteral<Predicate<String>>()
        {
        }, Names.named("SERVER_NORMAL_PREDICATE")));

        // Wait for Server to be started and NORMAL
        serverStartedPredicate.apply(serverId);
        serverNormalPredicate.apply(serverId);
    }

How to: Apply a Tag to an Asset

Dimension Data CloudControl allows for Tags to be applied to assets. There are two parts to the tagging process, first a tag key needs to be created, second the tag key is applied to an asset.

Create a tag key. We will use this to tag the assets that we create.

        String tagKeyId = api.getTagApi().createTagKey("jclouds", "owner of the asset", true, false);

Follows is the sample code for applying a Tag to the Server. We use AssetType SERVER. Pass in the tagKeyId and a value that we want to associate, in this case jclouds.

        api.getTagApi().applyTags(serverId, "SERVER", Collections.singletonList(TagInfo.create(tagKeyId, "jclouds")));

The full set of AssetTypes are SERVER, NETWORK_DOMAIN, VLAN, CUSTOMER_IMAGE, PUBLIC_IP_BLOCK or ACCOUNT.

Examples:

Deploy Network Domain, Vlan and Server. Associate a Tag with each of the assets.

package org.jclouds.examples.dimensiondata.cloudcontrol;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.inject.Injector;
import com.google.inject.Module;
import org.jclouds.ContextBuilder;
import org.jclouds.dimensiondata.cloudcontrol.DimensionDataCloudControlApi;
import org.jclouds.dimensiondata.cloudcontrol.domain.Disk;
import org.jclouds.dimensiondata.cloudcontrol.domain.NIC;
import org.jclouds.dimensiondata.cloudcontrol.domain.NetworkInfo;
import org.jclouds.dimensiondata.cloudcontrol.domain.TagInfo;
import org.jclouds.dimensiondata.cloudcontrol.options.DatacenterIdListFilters;
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;

import java.util.Collections;
import java.util.List;

import static org.jclouds.examples.dimensiondata.cloudcontrol.WaitForUtils.*;

/**
 * This class will attempt to Deploy:
 * <ol>Network Domain</ol>
 * <ol>Vlan</ol>
 * <ol>Server</ol>
 * For each of these deployed assets we will tag them so that we know they were created by jclouds.
 */
public class DeployNetworkDomainVlanAndServer
{

    private static final String AU_9 = "AU9";
    private static final String DIMENSIONDATA_CLOUDCONTROL_PROVIDER = "dimensiondata-cloudcontrol";

    public static void main(String[] args)
    {
        String endpoint = args[0];
        String username = args[1];
        String password = args[2];
        /*
         * Build an instance of the Dimension Data CloudControl Provider using the endpoint provided.
         * Typically the endpoint will be of the form https://api-GEO.dimensiondata.com/caas
         * We also need to provide authenticate details, a username and password.
         *
         * Internally the Dimension Data CloudControl Provider will use the org.jclouds.dimensiondata.cloudcontrol.features.AccountApi
         * to lookup the organization identifier so that it is used as part of the requests.
         *
         */
        ContextBuilder contextBuilder = ContextBuilder.newBuilder(DIMENSIONDATA_CLOUDCONTROL_PROVIDER);
        DimensionDataCloudControlApi api = contextBuilder
                .endpoint(endpoint)
                .credentials(username, password)
                .modules(ImmutableSet.<Module>of(new SLF4JLoggingModule()))
                .buildApi(DimensionDataCloudControlApi.class);

        /*
         * Retrieve the Guice injector from the context.
         * We will use this for retrieving the some Predicates that are used by the following operations.
         */
        Injector injector = contextBuilder.buildInjector();

        /*
         * Create a tag key. We will use this to tag the assets that we create.
         */
        String tagKeyId = api.getTagApi().createTagKey("jclouds", "owner of the asset", true, false);

        String networkDomainId = deployNetworkDomain(api, injector, tagKeyId);
        String vlanId = deployVlan(api, injector, networkDomainId, tagKeyId);

        deployServer(api, injector, networkDomainId, vlanId, tagKeyId);
    }

    private static void deployServer(DimensionDataCloudControlApi api, Injector injector, String networkDomainId, String vlanId, String tagKeyId)
    {
        /*
         * The server we deploy will use a pre-configured image.
         *
         * In Dimension Data CloudControl we support OS Images and
         * Customer Images (user created using the org.jclouds.dimensiondata.cloudcontrol.features.ServerApi.cloneServer operation)
         */
        String imageId = getOsImage(api);

        /*
         * The Server that gets deployed will have some network configuration. It gets assigned to the Vlan that was created previously.
         */
        NetworkInfo networkInfo = NetworkInfo
                .create(networkDomainId, NIC.builder().vlanId(vlanId).build(), Lists.<NIC>newArrayList());
        /*
         * The Server that gets deployed will have some additional disk configuration.
         */
        List<Disk> disks = ImmutableList.of(Disk.builder().scsiId(0).speed("STANDARD").build());

        /*
         * The Server is deployed using the OS Image we selected,
         * a flag to signal if we want it started or not, an admin pass and the additional configuration we built.
         */
        String serverId = api.getServerApi()
                .deployServer("jclouds-server", imageId, true, networkInfo, "P$$ssWwrrdGoDd!", disks, null);

        /*
         * A Server deployment is an asynchronous process. We need to wait for it to complete. The Dimension Data provider
         * has built in predicates that will block execution and check that the Server's State has moved from PENDING_ADD to NORMAL.
         */
        waitForServerStartedAndNormal(injector, serverId);

        /*
         * Apply a Tag to the Server. We use AssetType SERVER.
         * We pass in the tagKeyId and a value that we want to associate, in this case jclouds.
         */
        api.getTagApi().applyTags(serverId, "SERVER", Collections.singletonList(TagInfo.create(tagKeyId, "jclouds")));
    }

    private static String getOsImage(DimensionDataCloudControlApi api)
    {
        /*
         * We list available OS Images filtering on the Region (Datacenter) we wish to operate on.
         */
        return api.getServerImageApi().listOsImages(DatacenterIdListFilters.Builder.datacenterId(AU_9)).iterator().next().id();
    }

    private static String deployNetworkDomain(DimensionDataCloudControlApi api, Injector injector, String tagKeyId)
    {

        /*
         * Deploy Network Domain to the Region we wish to operate on. The response from this API is the Network Domain Identifier.
         */
        String networkDomainId = api.getNetworkApi().deployNetworkDomain(AU_9, "jclouds-example", "jclouds-example", "ESSENTIALS");

        /*
         * A Network Domain deployment is an asynchronous process. We need to wait for it to complete. The Dimension Data provider
         * has built in predicates that will block execution and check that the Network Domain's State has moved from PENDING_ADD to NORMAL.
         * We pass the Network Domain Identifier we wish to check the state of.
         */
        waitForNetworkDomainNormal(injector, networkDomainId);

        /*
         * Apply a Tag to the Network Domain. We use AssetType NETWORK_DOMAIN.
         * We pass in the tagKeyId and a value that we want to associate, in this case jclouds.
         */
        api.getTagApi().applyTags(networkDomainId, "NETWORK_DOMAIN", Collections.singletonList(TagInfo.create(tagKeyId, "jclouds")));
        return networkDomainId;
    }

    private static String deployVlan(DimensionDataCloudControlApi api, Injector injector, String networkDomainId, String tagKeyId)
    {

        /*
         * Deploy the Vlan and associate it with the Network Domain that was previously created.
         * The Vlan is deployed with a privateIpv4BaseAddress and privateIpv4PrefixSize
         */
        String vlanId = api.getNetworkApi().deployVlan(networkDomainId, "jclouds-example-vlan", "jclouds-example-vlan", "10.0.0.0", 24);

        /*
         * A Vlan deployment is an asynchronous process. We need to wait for it to complete. The Dimension Data provider
         * has built in predicates that will block execution and check that the Vlan's State has moved from PENDING_ADD to NORMAL.
         */
        waitForVlanNormal(injector, vlanId);

        /*
         * Apply a Tag to the Vlan. We use AssetType VLAN.
         * We pass in the tagKeyId and a value that we want to associate, in this case jclouds.
         */
        api.getTagApi().applyTags(vlanId, "VLAN", Collections.singletonList(TagInfo.create(tagKeyId, "jclouds")));
        return vlanId;
    }

}

Delete Network Domain, Vlan and Server and clean up Tags

package org.jclouds.examples.dimensiondata.cloudcontrol;

import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Injector;
import com.google.inject.Module;
import org.jclouds.ContextBuilder;
import org.jclouds.collect.PagedIterable;
import org.jclouds.dimensiondata.cloudcontrol.DimensionDataCloudControlApi;
import org.jclouds.dimensiondata.cloudcontrol.domain.Datacenter;
import org.jclouds.dimensiondata.cloudcontrol.domain.Server;
import org.jclouds.dimensiondata.cloudcontrol.domain.TagKey;
import org.jclouds.dimensiondata.cloudcontrol.domain.Vlan;
import org.jclouds.dimensiondata.cloudcontrol.options.DatacenterIdListFilters;
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;

import static org.jclouds.examples.dimensiondata.cloudcontrol.WaitForUtils.*;

/**
 * This class will attempt to delete the assets created in org.jclouds.examples.dimensiondata.cloudcontrol.DeployNetworkDomainVlanAndServer:
 * <ol>Server</ol>
 * <ol>Vlan</ol>
 * <ol>Network Domain</ol>
 * <ol>Tag Key</ol>
 */
public class DeleteServerVlanAndNetworkDomain
{
    private static final String AU_9 = "AU9";
    private static final String DIMENSIONDATA_CLOUDCONTROL_PROVIDER = "dimensiondata-cloudcontrol";

    public static void main(String[] args)
    {
        /*
         * Build an instance of the Dimension Data CloudControl Provider using the endpoint provided.
         * Typically the endpoint will be of the form https://api-GEO.dimensiondata.com/caas
         * We also need to provide authenticate details, a username and password.
         *
         * Internally the Dimension Data CloudControl Provider will use the org.jclouds.dimensiondata.cloudcontrol.features.AccountApi
         * to lookup the organization identifier so that it is used as part of the requests.
         *
         */
        String endpoint = args[0];
        String username = args[1];
        String password = args[2];
        ContextBuilder contextBuilder = ContextBuilder.newBuilder(DIMENSIONDATA_CLOUDCONTROL_PROVIDER);
        DimensionDataCloudControlApi api = contextBuilder
                .endpoint(endpoint)
                .credentials(username, password)
                .modules(ImmutableSet.<Module>of(new SLF4JLoggingModule()))
                .buildApi(DimensionDataCloudControlApi.class);

        PagedIterable<Datacenter> datacenters = api.getInfrastructureApi().listDatacenters();

        /*
         * Retrieve the Guice injector from the context.
         * We will use this for retrieving the some Predicates that are used by the following operations.
         */
        Injector injector = contextBuilder.buildInjector();

        /*
         * Referencing the asset created in org.jclouds.examples.dimensiondata.cloudcontrol.DeployNetworkDomainVlanAndServer
         */
        final String networkDomainName = "jclouds-example";
        String networkDomainId = getNetworkDomainId(api, networkDomainName);
        final String serverName = "jclouds-server";
        final String vlanName = "jclouds-example-vlan";

        deleteServer(api, injector, serverName);
        deleteVlan(api, injector, vlanName, networkDomainId);
        deleteNetworkDomain(api, injector, networkDomainId);
        deleteTagKey(api, "jclouds");
    }

    private static void deleteTagKey(DimensionDataCloudControlApi api, final String tagkeyName)
    {
        /*
         * Find the Tag Key and Delete using the id.
         */
        Optional<TagKey> tagKeyOptional = api.getTagApi().listTagKeys().concat().firstMatch(new Predicate<TagKey>()
        {
            @Override
            public boolean apply(TagKey input)
            {
                return input.name().equals(tagkeyName);
            }
        });
        if (tagKeyOptional.isPresent())
        {
            api.getTagApi().deleteTagKey(tagKeyOptional.get().id());
        }
    }

    private static String getNetworkDomainId(DimensionDataCloudControlApi api, final String networkDomainName)
    {
        /*
         * Find the Network Domain that was deployed by doing a filtered lookup using the datacenter and the network domain name.
         */
        return api.getNetworkApi().listNetworkDomainsWithDatacenterIdAndName(AU_9, networkDomainName).concat().toList().get(0).id();
    }

    private static void deleteVlan(DimensionDataCloudControlApi api, Injector injector, final String vlanName, String networkDomainId)
    {
        /*
         * Find the Vlan that was deployed by listing all Vlans for the Network Domain and filtering by name
         */
        Optional<Vlan> vlanOptional = api.getNetworkApi().listVlans(networkDomainId).concat().firstMatch(new Predicate<Vlan>()
        {
            @Override
            public boolean apply(Vlan input)
            {
                return input.name().equals(vlanName);
            }
        });
        if (vlanOptional.isPresent())
        {
            Vlan vlan = vlanOptional.get();

            /*
             * Delete the Vlan using the id.
             */
            api.getNetworkApi().deleteVlan(vlan.id());

            /*
             * A Vlan delete is an asynchronous process. We need to wait for it to complete. The Dimension Data provider
             * has built in predicates that will block execution and check that the Vlan is not found.
             */
            waitForDeleteVlan(injector, vlan);
        }
    }

    private static void deleteNetworkDomain(DimensionDataCloudControlApi api, Injector injector, String networkDomainId)
    {
        /*
         * Network Domain is deleted using the id.
         */
        api.getNetworkApi().deleteNetworkDomain(networkDomainId);

        /*
         * A Network Domain delete is an asynchronous process. We need to wait for it to complete. The Dimension Data provider
         * has built in predicates that will block execution and check that the Network Domain is not found.
         */
        waitForDeleteNetworkDomain(injector, networkDomainId);
    }

    private static void deleteServer(DimensionDataCloudControlApi api, Injector injector, final String serverName)
    {
        /*
         * We list all servers known to this organisation for the datacenter we are operating on. We filter the one that matches the server name we used to create it.
         */
        Optional<Server> serverOptional = api.getServerApi().listServers(DatacenterIdListFilters.Builder.datacenterId(AU_9)).firstMatch(new Predicate<Server>()
        {
            @Override
            public boolean apply(Server input)
            {
                return input.name().equals(serverName);
            }
        });

        if (serverOptional.isPresent())
        {
            Server server = serverOptional.get();
            if (server.started())
            {
                /*
                 * A Server must not be started in order to delete it. We call the shutdown server operation.
                 */
                api.getServerApi().shutdownServer(server.id());

                /*
                 * A Shutdown Server operation is an asynchronous process. We need to wait for it to complete. The Dimension Data provider
                 * has built in predicates that will block execution and check that the Server is shutdown.
                 */
                waitForServerStopped(injector, server);
            }

            /*
             * Server is deleted using the id.
             */
            api.getServerApi().deleteServer(server.id());

            /*
             * A Server delete is an asynchronous process. We need to wait for it to complete. The Dimension Data provider
             * has built in predicates that will block execution and check that the Server is not found.
             */
            waitForServerDeleted(injector, server);

        }
    }

}

Useful utility for asserting that operations are completed.

package org.jclouds.examples.dimensiondata.cloudcontrol;

import com.google.common.base.Predicate;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Names;
import org.jclouds.dimensiondata.cloudcontrol.domain.Server;
import org.jclouds.dimensiondata.cloudcontrol.domain.Vlan;

public class WaitForUtils
{
    public static void waitForServerStopped(Injector injector, Server server)
    {
        Predicate<String> serverStoppedPredicate = injector.getInstance(Key.get(new TypeLiteral<Predicate<String>>()
        {
        }, Names.named("SERVER_STOPPED_PREDICATE")));

        // Wait for Server to be STOPPED
        serverStoppedPredicate.apply(server.id());
    }

    static void waitForDeleteVlan(Injector injector, Vlan vlan)
    {
        Predicate<String> vlanDeletedPredicate = injector.getInstance(Key.get(new TypeLiteral<Predicate<String>>()
        {
        }, Names.named("VLAN_DELETED_PREDICATE")));

        // Wait for VLAN to be DELETED
        vlanDeletedPredicate.apply(vlan.id());
    }

    static void waitForDeleteNetworkDomain(Injector injector, String networkDomainId)
    {
        Predicate<String> networkDomainDeletedPredicate = injector.getInstance(Key.get(new TypeLiteral<Predicate<String>>()
        {
        }, Names.named("NETWORK_DOMAIN_DELETED_PREDICATE")));

        // Wait for NETWORK DOMAIN to be DELETED
        networkDomainDeletedPredicate.apply(networkDomainId);
    }

    static void waitForServerDeleted(Injector injector, Server server)
    {
        Predicate<String> serverDeletedPredicate = injector.getInstance(Key.get(new TypeLiteral<Predicate<String>>()
        {
        }, Names.named("SERVER_DELETED_PREDICATE")));

        // Wait for Server to be DELETED
        serverDeletedPredicate.apply(server.id());
    }

    static void waitForServerStartedAndNormal(Injector injector, String serverId)
    {
        Predicate<String> serverStartedPredicate = injector.getInstance(Key.get(new TypeLiteral<Predicate<String>>()
        {
        }, Names.named("SERVER_STARTED_PREDICATE")));
        Predicate<String> serverNormalPredicate = injector.getInstance(Key.get(new TypeLiteral<Predicate<String>>()
        {
        }, Names.named("SERVER_NORMAL_PREDICATE")));

        // Wait for Server to be started and NORMAL
        serverStartedPredicate.apply(serverId);
        serverNormalPredicate.apply(serverId);
    }

    static void waitForNetworkDomainNormal(Injector injector, String networkDomainId)
    {
        Predicate<String> networkDomainNormalPredicate = injector.getInstance(Key.get(new TypeLiteral<Predicate<String>>()
        {
        }, Names.named("NETWORK_DOMAIN_NORMAL_PREDICATE")));
        networkDomainNormalPredicate.apply(networkDomainId);
    }

    static void waitForVlanNormal(Injector injector, String vlanId)
    {
        Predicate<String> vlanNormalPredicate = injector.getInstance(Key.get(new TypeLiteral<Predicate<String>>()
        {
        }, Names.named("VLAN_NORMAL_PREDICATE")));
        vlanNormalPredicate.apply(vlanId);
    }
}

Support and Feedback

Your feedback is welcome! If you have comments or questions regarding using Dimension Data CloudControl via jclouds, please reach out to us at jclouds community.