Example of Dimension Data CloudControl provider
diff --git a/blobstore-uploader/dependency-reduced-pom.xml b/blobstore-uploader/dependency-reduced-pom.xml
index 2a895db..a5ca3ad 100644
--- a/blobstore-uploader/dependency-reduced-pom.xml
+++ b/blobstore-uploader/dependency-reduced-pom.xml
@@ -34,4 +34,3 @@
<jclouds.version>2.1.0</jclouds.version>
</properties>
</project>
-
diff --git a/compute-basics/pom.xml b/compute-basics/pom.xml
index 088eb88..217da90 100644
--- a/compute-basics/pom.xml
+++ b/compute-basics/pom.xml
@@ -41,6 +41,11 @@
<artifactId>jclouds-allcompute</artifactId>
<version>${jclouds.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.jclouds.labs</groupId>
+ <artifactId>dimensiondata-cloudcontrol</artifactId>
+ <version>2.2.0-SNAPSHOT</version>
+ </dependency>
<!-- note that if you want a smaller distribution
remove the above dependency and place something
like below -->
diff --git a/dimensiondata/README.md b/dimensiondata/README.md
new file mode 100644
index 0000000..54a379b
--- /dev/null
+++ b/dimensiondata/README.md
@@ -0,0 +1,57 @@
+# Dimension Data Examples
+Example code that uses jclouds to perform common tasks on an Dimension Data CloudControl. The class names are self-explanatory and the code is well commented for you to follow along.
+
+- [Requirements](#requirements)
+- [Environment](#environment)
+- [The Examples](#examples)
+- [Support and Feedback](#support-and-feedback)
+
+## Requirements
+
+1. Username and password for Dimension Data CloudControl - See the [Getting Started guide](http://jclouds.apache.org/guides/dimensiondata/).
+1. Java Development Kit (JDK) version 6 or later - [Download](http://www.oracle.com/technetwork/java/javase/downloads/index.html).
+1. Apache Maven - [Maven in 5 Minutes](http://maven.apache.org/guides/getting-started/maven-in-five-minutes.html).
+1. Git - [Download](http://git-scm.com/downloads).
+
+## Environment
+To setup an environment to compile and run the examples use these commands:
+
+```
+git clone https://github.com/jclouds/jclouds-examples.git
+cd jclouds-examples/dimensiondata/
+```
+
+To package the examples jar file and dependencies run:
+
+```
+mvn package
+```
+
+## Examples
+
+To run individual examples from the command line use these commands:
+
+Every example class has a main method that takes the following arguments in the listed order:
+
+1. API Endpoint
+1. Username
+1. Password
+
+If there are other arguments required they will follow. The command line format looks like this:
+```
+java -cp target\dimensiondata-cloudcontrol-examples-<VERSION>-jar-with-dependencies.jar <MAIN_CLASS> apiEndpoint username password <PARAMETERS>
+```
+
+Try out an example.
+
+```
+java -cp target\dimensiondata-cloudcontrol-examples-<VERSION>-jar-with-dependencies.jar org.jclouds.examples.dimensiondata.cloudcontrol.DeployNetworkDomainVlanAndServer apiEndpoint username password
+```
+
+Watch the terminal for output!
+
+## Support and Feedback
+
+Your feedback is appreciated! If you have specific issues with Dimension Data CloudControl support in jclouds, we'd prefer that you file an issue via [JIRA](https://issues.apache.org/jira/browse/JCLOUDS).
+
+If you have questions or need help, please join our [community](http://jclouds.apache.org/community/) and subscribe to the jclouds user mailing list.
diff --git a/dimensiondata/pom.xml b/dimensiondata/pom.xml
new file mode 100644
index 0000000..8dcb1c2
--- /dev/null
+++ b/dimensiondata/pom.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<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>
+
+ <parent>
+ <groupId>org.apache.jclouds.examples</groupId>
+ <artifactId>jclouds-examples</artifactId>
+ <version>2.2.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>dimensiondata-cloudcontrol-examples</artifactId>
+ <name>dimensiondata-cloudcontrol-examples</name>
+ <version>2.2.0-SNAPSHOT</version>
+
+ <properties>
+ <jclouds.version>2.2.0-SNAPSHOT</jclouds.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.jclouds.labs</groupId>
+ <artifactId>dimensiondata-cloudcontrol</artifactId>
+ <version>${jclouds.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds</groupId>
+ <artifactId>jclouds-compute</artifactId>
+ <version>${jclouds.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds.driver</groupId>
+ <artifactId>jclouds-slf4j</artifactId>
+ <version>${jclouds.version}</version>
+ </dependency>
+ <!-- 3rd party dependencies -->
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.0.13</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds.driver</groupId>
+ <artifactId>jclouds-slf4j</artifactId>
+ <version>${jclouds.version}</version>
+ <scope>compile</scope>
+ </dependency>
+
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.1</version>
+ <configuration>
+ <encoding>${project.build.sourceEncoding}</encoding>
+ <source>1.7</source>
+ <target>1.7</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.2.1</version>
+ <configuration>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
diff --git a/dimensiondata/src/main/java/org/jclouds/examples/dimensiondata/cloudcontrol/DeleteServerVlanAndNetworkDomain.java b/dimensiondata/src/main/java/org/jclouds/examples/dimensiondata/cloudcontrol/DeleteServerVlanAndNetworkDomain.java
new file mode 100644
index 0000000..8260277
--- /dev/null
+++ b/dimensiondata/src/main/java/org/jclouds/examples/dimensiondata/cloudcontrol/DeleteServerVlanAndNetworkDomain.java
@@ -0,0 +1,207 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 org.jclouds.ContextBuilder;
+import org.jclouds.dimensiondata.cloudcontrol.DimensionDataCloudControlApi;
+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 org.jclouds.rest.ApiContext;
+
+import static org.jclouds.examples.dimensiondata.cloudcontrol.WaitForUtils.*;
+
+/**
+ * This class will attempt to delete the assets created in org.jclouds.examples.dimensiondata.cloudcontrol.DeployNetworkDomainVlanAndServer:
+ * <ul>
+ * <li>Server</li>
+ * <li>Vlan</li>
+ * <li>Network Domain</li>
+ * <li>Tag Key</li>
+ * </ul>
+ */
+public class DeleteServerVlanAndNetworkDomain
+{
+ private static final String ZONE = System.getProperty("jclouds.zone", "AU9");
+ private static final String DIMENSIONDATA_CLOUDCONTROL_PROVIDER = "dimensiondata-cloudcontrol";
+
+ public static void main(String[] args)
+ {
+ /*
+ * Build an instance of the Dimension DataCloud Control 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];
+
+ try (ApiContext<DimensionDataCloudControlApi> ctx = ContextBuilder.newBuilder(DIMENSIONDATA_CLOUDCONTROL_PROVIDER)
+ .endpoint(endpoint)
+ .credentials(username, password)
+ .modules(ImmutableSet.of(new SLF4JLoggingModule()))
+ .build())
+ {
+ /*
+ * 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 = ctx.utils().injector();
+ DimensionDataCloudControlApi api = ctx.getApi();
+
+ /*
+ * 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(ZONE, 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(ZONE)).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);
+
+ }
+ }
+
+}
diff --git a/dimensiondata/src/main/java/org/jclouds/examples/dimensiondata/cloudcontrol/DeployNetworkDomainVlanAndServer.java b/dimensiondata/src/main/java/org/jclouds/examples/dimensiondata/cloudcontrol/DeployNetworkDomainVlanAndServer.java
new file mode 100644
index 0000000..f6521e4
--- /dev/null
+++ b/dimensiondata/src/main/java/org/jclouds/examples/dimensiondata/cloudcontrol/DeployNetworkDomainVlanAndServer.java
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 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 org.jclouds.rest.ApiContext;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.jclouds.examples.dimensiondata.cloudcontrol.WaitForUtils.*;
+
+/**
+ * This class will attempt to Deploy:
+ * <ul>
+ * <li>Network Domain</li>
+ * <li>Vlan</li>
+ * <li>Server</li>cd ..
+ * </ul>
+ * <p>
+ * 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 ZONE = System.getProperty("jclouds.zone", "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 DataCloud Control 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.
+ *
+ */
+ try (ApiContext<DimensionDataCloudControlApi> ctx = ContextBuilder.newBuilder(DIMENSIONDATA_CLOUDCONTROL_PROVIDER)
+ .endpoint(endpoint)
+ .credentials(username, password)
+ .modules(ImmutableSet.of(new SLF4JLoggingModule()))
+ .build())
+ {
+ /*
+ * 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 = ctx.utils().injector();
+ DimensionDataCloudControlApi api = ctx.getApi();
+
+ /*
+ * 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 Cloud Control 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(ZONE)).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(ZONE, "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;
+ }
+
+}
diff --git a/dimensiondata/src/main/java/org/jclouds/examples/dimensiondata/cloudcontrol/NetworkDomainTearDown.java b/dimensiondata/src/main/java/org/jclouds/examples/dimensiondata/cloudcontrol/NetworkDomainTearDown.java
new file mode 100644
index 0000000..8048f4c
--- /dev/null
+++ b/dimensiondata/src/main/java/org/jclouds/examples/dimensiondata/cloudcontrol/NetworkDomainTearDown.java
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.examples.dimensiondata.cloudcontrol;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Injector;
+import org.jclouds.ContextBuilder;
+import org.jclouds.dimensiondata.cloudcontrol.DimensionDataCloudControlApi;
+import org.jclouds.dimensiondata.cloudcontrol.domain.*;
+import org.jclouds.dimensiondata.cloudcontrol.options.DatacenterIdListFilters;
+import org.jclouds.logging.Logger;
+import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
+import org.jclouds.rest.ApiContext;
+
+import static org.jclouds.examples.dimensiondata.cloudcontrol.WaitForUtils.*;
+
+/**
+ * This example shows how a Network Domain and all of it's associated assets are removed.
+ * Takes 4 Program Arguments:
+ * <ul>
+ * <li>Endpoint URL</li>
+ * <li>Usernamme</li>
+ * <li>Password</li>
+ * <li>Network Domain Id</li>
+ * </ul>
+ */
+public class NetworkDomainTearDown
+{
+ private static final Logger logger = Logger.CONSOLE;
+
+ public static void main(String[] args)
+ {
+ String provider = "dimensiondata-cloudcontrol";
+ String endpoint = args[0];
+ String username = args[1];
+ String password = args[2];
+ String networkDomainId = args[3];
+
+ try (ApiContext<DimensionDataCloudControlApi> ctx = ContextBuilder.newBuilder(provider)
+ .endpoint(endpoint)
+ .credentials(username, password)
+ .modules(ImmutableSet.of(new SLF4JLoggingModule()))
+ .build())
+ {
+
+ /*
+ * 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 = ctx.utils().injector();
+ DimensionDataCloudControlApi api = ctx.getApi();
+
+
+ logger.info("Deleting resources for network domain %s", networkDomainId);
+ NetworkDomain networkDomain = api.getNetworkApi().getNetworkDomain(networkDomainId);
+ if (networkDomain == null)
+ {
+ logger.info("Network Domain with Id %s is not found", networkDomainId);
+ return;
+ }
+ if (networkDomain.state() != State.NORMAL)
+ {
+ logger.info("Network Domain with Id %s is not in a NORMAL state, cannot delete", networkDomain.id());
+ return;
+ }
+
+ String datacenterId = networkDomain.datacenterId();
+
+ removePublicIpBlocks(networkDomainId, api);
+
+ deleteNatRules(networkDomainId, api);
+
+ deleteFirewallRules(networkDomainId, api);
+
+ deleteServers(api, injector, datacenterId);
+
+ ImmutableList<Server> servers = api.getServerApi().listServers().concat().toList();
+ if (!servers.isEmpty())
+ {
+ logger.info("Could not delete all Servers. Servers not deleted:");
+ for (Server server : servers)
+ {
+ logger.info("Id %s, Name %s, State, %s", server.id(), server.name(), server.state());
+ }
+ return;
+ }
+ deleteVlans(api, injector, networkDomain);
+
+ deleteNetworkDomain(networkDomainId, api, injector);
+ }
+ }
+
+ private static void removePublicIpBlocks(String networkDomainId, DimensionDataCloudControlApi api)
+ {
+ for (PublicIpBlock publicIpBlock : api.getNetworkApi().listPublicIPv4AddressBlocks(networkDomainId).concat().toList())
+ {
+ logger.info("Deleting PublicIpBlock with Id %s", publicIpBlock.id());
+ api.getNetworkApi().removePublicIpBlock(publicIpBlock.id());
+ }
+ }
+
+ private static void deleteFirewallRules(String networkDomainId, DimensionDataCloudControlApi api)
+ {
+ for (FirewallRule firewallRule : api.getNetworkApi().listFirewallRules(networkDomainId).concat().toList())
+ {
+ if (firewallRule.ruleType().equals("CLIENT_RULE"))
+ {
+ logger.info("Deleting FirewallRule with Id %s", firewallRule.id());
+ api.getNetworkApi().deleteFirewallRule(firewallRule.id());
+ }
+ }
+ }
+
+ private static void deleteNatRules(String networkDomainId, DimensionDataCloudControlApi api)
+ {
+ for (NatRule natRule : api.getNetworkApi().listNatRules(networkDomainId).concat().toList())
+ {
+ logger.info("Deleting NatRule with Id %s", natRule.id());
+ api.getNetworkApi().deleteNatRule(natRule.id());
+ }
+ }
+
+ private static void deleteNetworkDomain(String networkDomainId, DimensionDataCloudControlApi api, Injector injector)
+ {
+ logger.info("Deleting Network Domain with Id %s", networkDomainId);
+ api.getNetworkApi().deleteNetworkDomain(networkDomainId);
+ waitForDeleteNetworkDomain(injector, networkDomainId);
+ }
+
+ private static void deleteVlans(DimensionDataCloudControlApi api, Injector injector, NetworkDomain networkDomain)
+ {
+ for (Vlan vlan : api.getNetworkApi().listVlans(networkDomain.id()).concat().toList())
+ {
+ try
+ {
+ if (vlan.state() != State.NORMAL)
+ {
+ logger.info("Vlan with Id %s is not in a NORMAL state, cannot delete", vlan.id());
+ continue;
+ }
+ logger.info("Deleting Vlan with Id %s", vlan.id());
+ api.getNetworkApi().deleteVlan(vlan.id());
+ waitForDeleteVlan(injector, vlan);
+ }
+ catch (Exception e)
+ {
+ logger.error("Unable to delete Vlan with Id %s due to: %s", vlan.id(), e.getMessage());
+ }
+ }
+ }
+
+ private static void deleteServers(DimensionDataCloudControlApi api, Injector injector, String datacenterId)
+ {
+ for (Server server : api.getServerApi().listServers(DatacenterIdListFilters.Builder.datacenterId(datacenterId)))
+ {
+ try
+ {
+ if (server.state() == State.FAILED_ADD)
+ {
+ logger.info("Server with Id %s is not in a FAILED_ADD state, manually run Clean Server operation.", server.id());
+ continue;
+ }
+ if (server.state() != State.NORMAL)
+ {
+ logger.info("Server with Id %s is not in a NORMAL state, current state %s - cannot delete", server.id(), server.state());
+ continue;
+ }
+ if (server.started())
+ {
+ logger.info("Shutting down Server with Id %s", server.id());
+ api.getServerApi().shutdownServer(server.id());
+ waitForServerStopped(injector, server);
+ }
+ logger.info("Deleting Server with Id %s", server.id());
+ api.getServerApi().deleteServer(server.id());
+ waitForServerDeleted(injector, server);
+ }
+ catch (Exception e)
+ {
+ logger.error("Unable to Delete Server with Id %s due to: %s", server.id(), e.getMessage());
+ }
+ }
+ }
+
+}
diff --git a/dimensiondata/src/main/java/org/jclouds/examples/dimensiondata/cloudcontrol/WaitForUtils.java b/dimensiondata/src/main/java/org/jclouds/examples/dimensiondata/cloudcontrol/WaitForUtils.java
new file mode 100644
index 0000000..53bae18
--- /dev/null
+++ b/dimensiondata/src/main/java/org/jclouds/examples/dimensiondata/cloudcontrol/WaitForUtils.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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
+{
+
+ private static final String SERVER_STARTED_PREDICATE = "SERVER_STARTED_PREDICATE";
+ private static final String SERVER_NORMAL_PREDICATE = "SERVER_NORMAL_PREDICATE";
+ private static final String NETWORK_DOMAIN_NORMAL_PREDICATE = "NETWORK_DOMAIN_NORMAL_PREDICATE";
+ private static final String VLAN_NORMAL_PREDICATE = "VLAN_NORMAL_PREDICATE";
+ private static final String SERVER_DELETED_PREDICATE = "SERVER_DELETED_PREDICATE";
+ private static final String NETWORK_DOMAIN_DELETED_PREDICATE = "NETWORK_DOMAIN_DELETED_PREDICATE";
+ private static final String VLAN_DELETED_PREDICATE = "VLAN_DELETED_PREDICATE";
+ private static final String SERVER_STOPPED_PREDICATE = "SERVER_STOPPED_PREDICATE";
+
+ 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);
+ }
+}
diff --git a/dimensiondata/src/main/resources/logback.xml b/dimensiondata/src/main/resources/logback.xml
new file mode 100644
index 0000000..b869509
--- /dev/null
+++ b/dimensiondata/src/main/resources/logback.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+
+<configuration scan="false">
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>- %m%n</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="FILE" class="ch.qos.logback.core.FileAppender">
+ <file>target/test-data/jclouds.log</file>
+
+ <encoder>
+ <Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
+ </encoder>
+ </appender>
+
+ <appender name="WIREFILE" class="ch.qos.logback.core.FileAppender">
+ <file>target/test-data/jclouds-wire.log</file>
+
+ <encoder>
+ <Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
+ </encoder>
+ </appender>
+
+ <appender name="COMPUTEFILE" class="ch.qos.logback.core.FileAppender">
+ <file>target/test-data/jclouds-compute.log</file>
+
+ <encoder>
+ <Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
+ </encoder>
+ </appender>
+
+ <appender name="SSHFILE" class="ch.qos.logback.core.FileAppender">
+ <file>target/test-data/jclouds-ssh.log</file>
+
+ <encoder>
+ <Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
+ </encoder>
+ </appender>
+
+ <root>
+ <level value="warn" />
+ </root>
+
+ <logger name="org.jclouds">
+ <level value="DEBUG" />
+ <appender-ref ref="FILE" />
+ </logger>
+
+ <logger name="jclouds.wire">
+ <level value="DEBUG" />
+ <appender-ref ref="STDOUT" />
+ </logger>
+
+ <logger name="jclouds.headers">
+ <level value="DEBUG" />
+ <appender-ref ref="STDOUT" />
+ </logger>
+
+ <logger name="jclouds.compute">
+ <level value="DEBUG" />
+ <appender-ref ref="COMPUTEFILE" />
+ </logger>
+
+ <logger name="jclouds.ssh">
+ <level value="DEBUG" />
+ <appender-ref ref="SSHFILE" />
+ </logger>
+
+</configuration>
diff --git a/pom.xml b/pom.xml
index b2aa183..41f2eb8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -69,6 +69,7 @@
<module>google-lb</module>
<module>openstack</module>
<module>rackspace</module>
+ <module>dimensiondata</module>
</modules>
<build>