Repository: jclouds-examples Updated Branches: refs/heads/master 934cdb085 -> a145a8fd2
Example of Dimension Data CloudControl provider Project: http://git-wip-us.apache.org/repos/asf/jclouds-examples/repo Commit: http://git-wip-us.apache.org/repos/asf/jclouds-examples/commit/a145a8fd Tree: http://git-wip-us.apache.org/repos/asf/jclouds-examples/tree/a145a8fd Diff: http://git-wip-us.apache.org/repos/asf/jclouds-examples/diff/a145a8fd Branch: refs/heads/master Commit: a145a8fd2eaffc20610d5b24396307e7d22156cf Parents: 934cdb0 Author: Trevor Flanagan <[email protected]> Authored: Fri Jul 6 11:30:56 2018 +0100 Committer: Ignasi Barrera <[email protected]> Committed: Thu Oct 11 11:45:05 2018 +0200 ---------------------------------------------------------------------- blobstore-uploader/dependency-reduced-pom.xml | 1 - compute-basics/pom.xml | 5 + dimensiondata/README.md | 57 +++++ dimensiondata/pom.xml | 100 +++++++++ .../DeleteServerVlanAndNetworkDomain.java | 207 +++++++++++++++++++ .../DeployNetworkDomainVlanAndServer.java | 190 +++++++++++++++++ .../cloudcontrol/NetworkDomainTearDown.java | 200 ++++++++++++++++++ .../cloudcontrol/WaitForUtils.java | 108 ++++++++++ dimensiondata/src/main/resources/logback.xml | 89 ++++++++ pom.xml | 1 + 10 files changed, 957 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jclouds-examples/blob/a145a8fd/blobstore-uploader/dependency-reduced-pom.xml ---------------------------------------------------------------------- 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> - http://git-wip-us.apache.org/repos/asf/jclouds-examples/blob/a145a8fd/compute-basics/pom.xml ---------------------------------------------------------------------- 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 --> http://git-wip-us.apache.org/repos/asf/jclouds-examples/blob/a145a8fd/dimensiondata/README.md ---------------------------------------------------------------------- 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. http://git-wip-us.apache.org/repos/asf/jclouds-examples/blob/a145a8fd/dimensiondata/pom.xml ---------------------------------------------------------------------- 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 http://git-wip-us.apache.org/repos/asf/jclouds-examples/blob/a145a8fd/dimensiondata/src/main/java/org/jclouds/examples/dimensiondata/cloudcontrol/DeleteServerVlanAndNetworkDomain.java ---------------------------------------------------------------------- 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); + + } + } + +} http://git-wip-us.apache.org/repos/asf/jclouds-examples/blob/a145a8fd/dimensiondata/src/main/java/org/jclouds/examples/dimensiondata/cloudcontrol/DeployNetworkDomainVlanAndServer.java ---------------------------------------------------------------------- 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; + } + +} http://git-wip-us.apache.org/repos/asf/jclouds-examples/blob/a145a8fd/dimensiondata/src/main/java/org/jclouds/examples/dimensiondata/cloudcontrol/NetworkDomainTearDown.java ---------------------------------------------------------------------- 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()); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/jclouds-examples/blob/a145a8fd/dimensiondata/src/main/java/org/jclouds/examples/dimensiondata/cloudcontrol/WaitForUtils.java ---------------------------------------------------------------------- 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); + } +} http://git-wip-us.apache.org/repos/asf/jclouds-examples/blob/a145a8fd/dimensiondata/src/main/resources/logback.xml ---------------------------------------------------------------------- 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> http://git-wip-us.apache.org/repos/asf/jclouds-examples/blob/a145a8fd/pom.xml ---------------------------------------------------------------------- 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>
