Browse files

Initial checkin

  • Loading branch information...
1 parent 7ffb9be commit af6819ce64fc907a2b0643291e104a4c5cc25404 @greese committed Jun 23, 2012
Showing with 19,925 additions and 0 deletions.
  1. +202 −0 LICENSE-APACHE.txt
  2. +318 −0 pom.xml
  3. +15 −0 src/main/etc/header.txt
  4. +597 −0 src/main/java/org/dasein/cloud/aws/AWSCloud.java
  5. +362 −0 src/main/java/org/dasein/cloud/aws/RegionsAndZones.java
  6. +33 −0 src/main/java/org/dasein/cloud/aws/admin/AWSAdminServices.java
  7. +393 −0 src/main/java/org/dasein/cloud/aws/admin/ReservedInstance.java
  8. +1,078 −0 src/main/java/org/dasein/cloud/aws/compute/AMI.java
  9. +649 −0 src/main/java/org/dasein/cloud/aws/compute/AutoScaling.java
  10. +529 −0 src/main/java/org/dasein/cloud/aws/compute/EBSSnapshot.java
  11. +378 −0 src/main/java/org/dasein/cloud/aws/compute/EBSVolume.java
  12. +55 −0 src/main/java/org/dasein/cloud/aws/compute/EC2ComputeServices.java
  13. +62 −0 src/main/java/org/dasein/cloud/aws/compute/EC2Exception.java
  14. +1,425 −0 src/main/java/org/dasein/cloud/aws/compute/EC2Instance.java
  15. +666 −0 src/main/java/org/dasein/cloud/aws/compute/EC2Method.java
  16. +38 −0 src/main/java/org/dasein/cloud/aws/identity/AWSIdentityServices.java
  17. +1,877 −0 src/main/java/org/dasein/cloud/aws/identity/IAM.java
  18. +152 −0 src/main/java/org/dasein/cloud/aws/identity/IAMMethod.java
  19. +336 −0 src/main/java/org/dasein/cloud/aws/identity/Keypairs.java
  20. +54 −0 src/main/java/org/dasein/cloud/aws/network/EC2NetworkServices.java
  21. +72 −0 src/main/java/org/dasein/cloud/aws/network/ELBMethod.java
  22. +379 −0 src/main/java/org/dasein/cloud/aws/network/ElasticIP.java
  23. +687 −0 src/main/java/org/dasein/cloud/aws/network/ElasticLoadBalancer.java
  24. +607 −0 src/main/java/org/dasein/cloud/aws/network/Route53.java
  25. +470 −0 src/main/java/org/dasein/cloud/aws/network/Route53Method.java
  26. +570 −0 src/main/java/org/dasein/cloud/aws/network/SecurityGroup.java
  27. +783 −0 src/main/java/org/dasein/cloud/aws/network/VPC.java
  28. +103 −0 src/main/java/org/dasein/cloud/aws/network/VPCGateway.java
  29. +48 −0 src/main/java/org/dasein/cloud/aws/platform/AWSPlatformServices.java
  30. +512 −0 src/main/java/org/dasein/cloud/aws/platform/CloudFront.java
  31. +43 −0 src/main/java/org/dasein/cloud/aws/platform/CloudFrontAction.java
  32. +56 −0 src/main/java/org/dasein/cloud/aws/platform/CloudFrontException.java
  33. +326 −0 src/main/java/org/dasein/cloud/aws/platform/CloudFrontMethod.java
  34. +2,035 −0 src/main/java/org/dasein/cloud/aws/platform/RDS.java
  35. +510 −0 src/main/java/org/dasein/cloud/aws/platform/SNS.java
  36. +133 −0 src/main/java/org/dasein/cloud/aws/platform/SQS.java
  37. +578 −0 src/main/java/org/dasein/cloud/aws/platform/SimpleDB.java
  38. +35 −0 src/main/java/org/dasein/cloud/aws/storage/AWSCloudStorageServices.java
  39. +1,701 −0 src/main/java/org/dasein/cloud/aws/storage/S3.java
  40. +43 −0 src/main/java/org/dasein/cloud/aws/storage/S3Action.java
  41. +50 −0 src/main/java/org/dasein/cloud/aws/storage/S3Exception.java
  42. +572 −0 src/main/java/org/dasein/cloud/aws/storage/S3Method.java
  43. +111 −0 src/main/javadoc/dasein-javadoc.css
  44. +29 −0 src/main/javadoc/overview.html
  45. +152 −0 src/main/resources/LICENSE-APACHE.txt
  46. +30 −0 src/test/java/org/dasein/cloud/aws/AWSTestSuite.java
  47. +71 −0 src/test/resources/log4j.xml
View
202 LICENSE-APACHE.txt
@@ -0,0 +1,202 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
+
View
318 pom.xml
@@ -0,0 +1,318 @@
+<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">
+<!--
+ Copyright (C) 2008-2012 enStratus Networks Inc (http://www.enstratus.com)
+
+ ====================================================================
+ Licensed 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.
+ ====================================================================
+-->
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.dasein</groupId>
+ <artifactId>dasein-cloud-aws</artifactId>
+ <version>2012.07-SNAPSHOT</version>
+ <packaging>jar</packaging>
+
+ <name>dasein-cloud-aws</name>
+ <description>
+ Implementation of the Dasein Cloud API for AWS.
+ </description>
+ <inceptionYear>2009</inceptionYear>
+ <url>http://github.com/greese/dasein-cloud-aws</url>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <licenses>
+ <license>
+ <name>Apache License 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.html</url>
+ </license>
+ </licenses>
+
+ <organization>
+ <name>enStratus Networks Inc</name>
+ <url>http://www.enstratus.com</url>
+ </organization>
+
+ <scm>
+ <connection>scm:git:git://github.com/greese/dasein-cloud-aws.git</connection>
+ <developerConnection>scm:git:ssh://git@github.com/greese/dasein-cloud-aws.git</developerConnection>
+ <url>http://github.com/greese/dasein-cloud-aws</url>
+ </scm>
+
+ <parent>
+ <groupId>org.sonatype.oss</groupId>
+ <artifactId>oss-parent</artifactId>
+ <version>5</version>
+ </parent>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.dasein</groupId>
+ <artifactId>dasein-cloud-core</artifactId>
+ <version>2012.07-SNAPSHOT</version>
+ <scope>compile</scope>
+ <optional>false</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.dasein</groupId>
+ <artifactId>dasein-cloud-test</artifactId>
+ <version>2012.04</version>
+ <scope>test</scope>
+ <optional>false</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.dasein</groupId>
+ <artifactId>dasein-util</artifactId>
+ <version>2012.02</version>
+ <scope>compile</scope>
+ <optional>false</optional>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.9</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.17</version>
+ <scope>compile</scope>
+ <optional>false</optional>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.json</groupId>
+ <artifactId>json</artifactId>
+ <version>20090211</version>
+ <scope>compile</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.0.2</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.7</version>
+ <executions>
+ <execution>
+ <id>javadoc</id>
+ <phase>package</phase>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <encoding>utf-8</encoding>
+ <quiet>true</quiet>
+ <links>
+ <link>http://java.sun.com/javase/6/docs/api/</link>
+ <link>http://java.sun.com/javaee/6/docs/api/</link>
+ </links>
+ <stylesheetfile>dasein-javadoc.css</stylesheetfile>
+ <footer />
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>com.mycila.maven-license-plugin</groupId>
+ <artifactId>maven-license-plugin</artifactId>
+ <version>1.8.0</version>
+ <configuration>
+ <strictCheck>true</strictCheck>
+ <encoding>utf-8</encoding>
+ <aggregate>true</aggregate>
+ <header>src/main/etc/header.txt</header>
+ <mapping>
+ <clj>SEMICOLON_STYLE</clj>
+ </mapping>
+ <excludes>
+ <exclude>thirdparty/**</exclude>
+ <exclude>**/src/**/resources/**</exclude>
+ <exclude>**/LICENSE-APACHE.txt</exclude>
+ </excludes>
+ <properties>
+ <year>2009-2012</year>
+ <copyrightHolder>enStratus Networks Inc</copyrightHolder>
+ </properties>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <version>2.1.2</version>
+ <executions>
+ <execution>
+ <id>source</id>
+ <phase>package</phase>
+ <goals>
+ <goal>jar-no-fork</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-release-plugin</artifactId>
+ <version>2.1</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.6</version>
+ <configuration>
+ <systemProperties>
+ <property>
+ <name>endpoint</name>
+ <value>${org.dasein.cloud.aws.endpoint}</value>
+ </property>
+ <property>
+ <name>accountNumber</name>
+ <value>${org.dasein.cloud.aws.accountNumber}</value>
+ </property>
+ <property>
+ <name>apiSharedKey</name>
+ <value>${org.dasein.cloud.aws.apiSharedKey}</value>
+ </property>
+ <property>
+ <name>x509Cert</name>
+ <value>${org.dasein.cloud.aws.x509Cert}</value>
+ </property>
+ <property>
+ <name>x509Key</name>
+ <value>${org.dasein.cloud.aws.x509Key}</value>
+ </property>
+ <property>
+ <name>apiSecretKey</name>
+ <value>${org.dasein.cloud.aws.apiSecretKey}</value>
+ </property>
+ <property>
+ <name>cloudName</name>
+ <value>${org.dasein.cloud.aws.cloudName}</value>
+ </property>
+ <property>
+ <name>providerName</name>
+ <value>${org.dasein.cloud.aws.providerName}</value>
+ </property>
+ <property>
+ <name>regionId</name>
+ <value>${org.dasein.cloud.aws.regionId}</value>
+ </property>
+ <property>
+ <name>test.region</name>
+ <value>${org.dasein.cloud.aws.test.region}</value>
+ </property>
+ <property>
+ <name>test.dataCenter</name>
+ <value>${org.dasein.cloud.aws.test.dataCenter}</value>
+ </property>
+ <property>
+ <name>test.machineImage</name>
+ <value>${org.dasein.cloud.aws.test.machineImage}</value>
+ </property>
+ <property>
+ <name>test.product</name>
+ <value>${org.dasein.cloud.aws.test.product}</value>
+ </property>
+
+ </systemProperties>
+ <includes>
+ <!-- <include>**/AWSTestSuite.java</include> -->
+ </includes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}/lib</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <distributionManagement>
+ <repository>
+ <id>sonatype-nexus-staging</id>
+ <url>https://oss.sonatype.org/service/local/staging/deploy/maven2</url>
+ <uniqueVersion>false</uniqueVersion>
+ </repository>
+ <snapshotRepository>
+ <id>sonatype-nexus-snapshots</id>
+ <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+ </snapshotRepository>
+ </distributionManagement>
+
+ <developers>
+ <developer>
+ <name>George Reese</name>
+ <id>georgereese</id>
+ <email>george.reese -at- enstratus -dot- com</email>
+ <organization>enStratus</organization>
+ <roles>
+ <role>Java Developer</role>
+ <role>PMC</role>
+ </roles>
+ <url>http://www.enstratus.com</url>
+ <timezone>-6</timezone>
+ </developer>
+ <developer>
+ <name>Morgan Catlin</name>
+ <id>sylistron</id>
+ <email>morgan.catlin -at- valtira -dot- com</email>
+ <organization>enStratus</organization>
+ <roles>
+ <role>Java Developer</role>
+ </roles>
+ <url>http://www.valtira.com</url>
+ <timezone>-6</timezone>
+ </developer>
+ <developer>
+ <name>Adrian Cole</name>
+ <id>ferncam1</id>
+ <email>adrian -at- jclouds -dot- org</email>
+ <organization>jclouds</organization>
+ <roles>
+ <role>Java Developer</role>
+ <role>PMC</role>
+ </roles>
+ <url>http://www.jclouds.org</url>
+ <timezone>-8</timezone>
+ </developer>
+ </developers>
+</project>
View
15 src/main/etc/header.txt
@@ -0,0 +1,15 @@
+Copyright (C) ${year} ${copyrightHolder}
+
+====================================================================
+Licensed 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.
+====================================================================
View
597 src/main/java/org/dasein/cloud/aws/AWSCloud.java
@@ -0,0 +1,597 @@
+/**
+ * Copyright (C) 2009-2012 enStratus Networks Inc
+ *
+ * ====================================================================
+ * Licensed 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.dasein.cloud.aws;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.TreeSet;
+
+import javax.annotation.Nonnull;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.log4j.Logger;
+import org.dasein.cloud.AbstractCloud;
+import org.dasein.cloud.CloudException;
+import org.dasein.cloud.InternalException;
+import org.dasein.cloud.ProviderContext;
+import org.dasein.cloud.Tag;
+import org.dasein.cloud.aws.admin.AWSAdminServices;
+import org.dasein.cloud.aws.compute.EC2ComputeServices;
+import org.dasein.cloud.aws.compute.EC2Exception;
+import org.dasein.cloud.aws.compute.EC2Method;
+import org.dasein.cloud.aws.identity.AWSIdentityServices;
+import org.dasein.cloud.aws.network.EC2NetworkServices;
+import org.dasein.cloud.aws.platform.AWSPlatformServices;
+import org.dasein.cloud.aws.storage.AWSCloudStorageServices;
+
+public class AWSCloud extends AbstractCloud {
+ static private String getLastItem(String name) {
+ int idx = name.lastIndexOf('.');
+
+ if( idx < 0 ) {
+ return name;
+ }
+ else if( idx == (name.length()-1) ) {
+ return "";
+ }
+ return name.substring(idx+1);
+ }
+
+ static public Logger getLogger(Class<?> cls) {
+ String pkg = getLastItem(cls.getPackage().getName());
+
+ if( pkg.equals("aws") ) {
+ pkg = "";
+ }
+ else {
+ pkg = pkg + ".";
+ }
+ return Logger.getLogger("dasein.cloud.aws.std." + pkg + getLastItem(cls.getName()));
+ }
+
+ static public Logger getWireLogger(Class<?> cls) {
+ return Logger.getLogger("dasein.cloud.aws.wire." + getLastItem(cls.getPackage().getName()) + "." + getLastItem(cls.getName()));
+ }
+
+ static private final Logger logger = getLogger(AWSCloud.class);
+
+ static public final String P_ACCESS = "AWSAccessKeyId";
+ static public final String P_ACTION = "Action";
+ static public final String P_CFAUTH = "Authorization";
+ static public final String P_DATE = "x-amz-date";
+ static public final String P_SIGNATURE = "Signature";
+ static public final String P_SIGNATURE_METHOD = "SignatureMethod";
+ static public final String P_SIGNATURE_VERSION = "SignatureVersion";
+ static public final String P_TIMESTAMP = "Timestamp";
+ static public final String P_VERSION = "Version";
+
+ static public final String CLOUD_FRONT_ALGORITHM = "HmacSHA1";
+ static public final String EC2_ALGORITHM = "HmacSHA256";
+ static public final String S3_ALGORITHM = "HmacSHA1";
+ static public final String SIGNATURE = "2";
+ static public final String VERSION = "2011-07-15";
+ static public final String AUTO_SCALE_VERSION = "2009-05-15";
+ static public final String ELB_VERSION = "2009-05-15";
+ static public final String CLOUD_WATCH_VERSION = "2009-05-15";
+ static public final String RDS_VERSION = "2011-04-01";
+ static public final String ROUTE53_VERSION = "2010-10-01";
+ static public final String SDB_VERSION = "2009-04-15";
+ static public final String SNS_VERSION = "2010-03-31";
+ static public final String SQS_VERSION = "2009-02-01";
+
+ static public String encode(String value, boolean encodePath) throws InternalException {
+ String encoded = null;
+
+ try {
+ encoded = URLEncoder.encode(value, "utf-8").replace("+", "%20").replace("*", "%2A").replace("%7E","~");
+ if( encodePath ) {
+ encoded = encoded.replace("%2F", "/");
+ }
+ }
+ catch( UnsupportedEncodingException e ) {
+ logger.error(e);
+ e.printStackTrace();
+ throw new InternalException(e);
+ }
+ return encoded;
+ }
+
+ static public String escapeXml(String nonxml) {
+ StringBuilder str = new StringBuilder();
+
+ for( int i=0; i<nonxml.length(); i++ ) {
+ char c = nonxml.charAt(i);
+
+ switch( c ) {
+ case '&': str.append("&amp;"); break;
+ case '>': str.append("&gt;"); break;
+ case '<': str.append("&lt;"); break;
+ case '"': str.append("&quot;"); break;
+ case '[': str.append("&#091;"); break;
+ case ']': str.append("&#093;"); break;
+ case '!': str.append("&#033;"); break;
+ default: str.append(c);
+ }
+ }
+ return str.toString();
+ }
+
+ public AWSCloud() { }
+
+ private String buildEc2AuthString(String method, String serviceUrl, Map<String, String> parameters) throws InternalException {
+ StringBuilder authString = new StringBuilder();
+ TreeSet<String> sortedKeys;
+ URI endpoint = null;
+ String tmp;
+
+ authString.append(method);
+ authString.append("\n");
+ try {
+ endpoint = new URI(serviceUrl);
+ }
+ catch( URISyntaxException e ) {
+ logger.error(e);
+ e.printStackTrace();
+ throw new InternalException(e);
+ }
+ authString.append(endpoint.getHost().toLowerCase());
+ authString.append("\n");
+ tmp = endpoint.getPath();
+ if( tmp == null || tmp.length() == 0) {
+ tmp = "/";
+ }
+ authString.append(encode(tmp, true));
+ authString.append("\n");
+ sortedKeys = new TreeSet<String>();
+ sortedKeys.addAll(parameters.keySet());
+ boolean first = true;
+ for( String key : sortedKeys ) {
+ String value = parameters.get(key);
+
+ if( !first ) {
+ authString.append("&");
+ }
+ else {
+ first = false;
+ }
+ authString.append(encode(key, false));
+ authString.append("=");
+ authString.append(encode(value, false));
+ }
+ return authString.toString();
+ }
+
+ public boolean createTags(String resourceId, Tag ... keyValuePairs) {
+ try {
+ Map<String,String> parameters = getStandardParameters(getContext(), "CreateTags");
+ EC2Method method;
+
+ parameters.put("ResourceId.1", resourceId);
+ for( int i=0; i<keyValuePairs.length; i++ ) {
+ String key = keyValuePairs[i].getKey();
+ String value = keyValuePairs[i].getValue();
+
+ parameters.put("Tag." + i + ".Key", key);
+ parameters.put("Tag." + i + ".Value", value);
+ }
+ method = new EC2Method(this, getEc2Url(), parameters);
+ try {
+ method.invoke();
+ }
+ catch( EC2Exception e ) {
+ String code = e.getCode();
+
+ if( code != null && code.equals("InvalidInstanceID.NotFound") ) {
+ try { Thread.sleep(5000L); }
+ catch( InterruptedException ignore ) { }
+ parameters = getStandardParameters(getContext(), "CreateTags");
+ parameters.put("ResourceId.1", resourceId);
+ for( int i=0; i<keyValuePairs.length; i++ ) {
+ String key = keyValuePairs[i].getKey();
+ String value = keyValuePairs[i].getValue();
+
+ parameters.put("Tag." + i + ".Key", key);
+ parameters.put("Tag." + i + ".Value", value);
+ }
+ method = new EC2Method(this, getEc2Url(), parameters);
+ try {
+ method.invoke();
+ return true;
+ }
+ catch( EC2Exception ignore ) {
+ // ignore me
+ }
+ }
+ logger.error("EC2 error settings tags for " + resourceId + ": " + e.getSummary());
+ return false;
+ }
+ return true;
+ }
+ catch( Throwable ignore ) {
+ return false;
+ }
+ }
+
+ @Override
+ public AWSAdminServices getAdminServices() {
+ return new AWSAdminServices(this);
+ }
+
+ private String[] getBootstrapUrls(ProviderContext ctx) {
+ String endpoint = ctx.getEndpoint();
+
+ if( endpoint == null ) {
+ return new String[0];
+ }
+ if( endpoint.indexOf(",") == -1 ) {
+ return new String[] { endpoint };
+ }
+ String[] endpoints = endpoint.split(",");
+ if( endpoints != null && endpoints.length > 1 ) {
+ String second = endpoints[1];
+
+ if( !second.startsWith("http") ) {
+ if( endpoints[0].startsWith("http") ) {
+ // likely a URL with a , in it
+ return new String[] { endpoint + (isAmazon() ? "" : "/Eucalyptus") };
+ }
+ }
+ }
+ for( int i=0; i<endpoints.length; i++ ) {
+ if( !endpoints[i].startsWith("http") ) {
+ endpoints[i] = "https://" + endpoints[i] + (isAmazon() ? "" : "/Eucalyptus");
+ }
+ }
+ return endpoints;
+ }
+
+ @Override
+ public String getCloudName() {
+ String name = getContext().getCloudName();
+
+ return ((name == null ) ? "AWS" : name);
+ }
+
+ @Override
+ public EC2ComputeServices getComputeServices() {
+ return new EC2ComputeServices(this);
+ }
+
+ @Override
+ public RegionsAndZones getDataCenterServices() {
+ return new RegionsAndZones(this);
+ }
+
+ public String getEc2Url() throws InternalException, CloudException {
+ String url = getEc2Url(getContext().getRegionId());
+
+ if( isAmazon() ) {
+ return url;
+ }
+ else {
+ return url + "/Eucalyptus";
+ }
+ }
+
+ String getEc2Url(String regionId) throws InternalException, CloudException {
+ String url;
+
+ if( regionId == null ) {
+ return getBootstrapUrls(getContext())[0];
+ }
+ if( isAmazon() ) {
+ if( !getContext().getEndpoint().contains("amazon") ) {
+ url = getContext().getEndpoint();
+ if( url == null ) {
+ return null;
+ }
+ if( !url.startsWith("http") ) {
+ String cloudUrl = getContext().getEndpoint();
+
+ if( cloudUrl != null && cloudUrl.startsWith("http:") ) {
+ return "http://" + url + "/" + regionId;
+ }
+ return "https://" + url + "/" + regionId;
+ }
+ else {
+ return url + "/" + regionId;
+ }
+ }
+ else {
+ url = getContext().getEndpoint();
+ if( url != null && url.endsWith("amazonaws.com") ) {
+ return "https://ec2." + regionId + ".amazonaws.com";
+ }
+ return "https://ec2." + regionId + ".amazonaws.com";
+ }
+ }
+ url = getContext().getEndpoint();
+ if( url == null ) {
+ return null;
+ }
+ if( !url.startsWith("http") ) {
+ String cloudUrl = getContext().getEndpoint();
+
+ if( cloudUrl != null && cloudUrl.startsWith("http:") ) {
+ return "http://" + url;
+ }
+ return "https://" + url;
+ }
+ else {
+ return url;
+ }
+ }
+
+ @Override
+ public AWSIdentityServices getIdentityServices() {
+ return new AWSIdentityServices(this);
+ }
+
+ @Override
+ public EC2NetworkServices getNetworkServices() {
+ return new EC2NetworkServices(this);
+ }
+
+ @Override
+ public AWSPlatformServices getPlatformServices() {
+ return new AWSPlatformServices(this);
+ }
+
+ @Override
+ public String getProviderName() {
+ String name = getContext().getProviderName();
+
+ return ((name == null) ? "Amazon" : name);
+ }
+
+ public String getProxyHost() {
+ return getContext().getCustomProperties().getProperty("proxyHost");
+ }
+
+ public int getProxyPort() {
+ String port = getContext().getCustomProperties().getProperty("proxyPort");
+
+ if( port != null ) {
+ return Integer.parseInt(port);
+ }
+ return -1;
+ }
+
+ @Override
+ public @Nonnull AWSCloudStorageServices getStorageServices() {
+ return new AWSCloudStorageServices(this);
+ }
+
+ public Map<String,String> getStandardParameters(ProviderContext ctx, String action) throws InternalException {
+ return getStandardParameters(ctx, action, VERSION);
+ }
+
+ public Map<String,String> getStandardParameters(ProviderContext ctx, String action, String version) throws InternalException {
+ HashMap<String,String> parameters = new HashMap<String,String>();
+
+ parameters.put(P_ACTION, action);
+ parameters.put(P_SIGNATURE_VERSION, SIGNATURE);
+ try {
+ parameters.put(P_ACCESS, new String(ctx.getAccessPublic(), "utf-8"));
+ }
+ catch( UnsupportedEncodingException e ) {
+ logger.error(e);
+ e.printStackTrace();
+ throw new InternalException(e);
+ }
+ parameters.put(P_SIGNATURE_METHOD, EC2_ALGORITHM);
+ parameters.put(P_TIMESTAMP, getTimestamp(System.currentTimeMillis(), true));
+ parameters.put(P_VERSION, version);
+ return parameters;
+ }
+
+ public Map<String,String> getStandardCloudWatchParameters(ProviderContext ctx, String action) throws InternalException {
+ Map<String,String> parameters = getStandardParameters(ctx, action);
+
+ parameters.put(P_VERSION, CLOUD_WATCH_VERSION);
+ return parameters;
+ }
+
+ public Map<String,String> getStandardRdsParameters(ProviderContext ctx, String action) throws InternalException {
+ Map<String,String> parameters = getStandardParameters(ctx, action);
+
+ parameters.put(P_VERSION, RDS_VERSION);
+ return parameters;
+ }
+
+ public Map<String,String> getStandardSimpleDBParameters(ProviderContext ctx, String action) throws InternalException {
+ Map<String,String> parameters = getStandardParameters(ctx, action);
+
+ parameters.put(P_VERSION, SDB_VERSION);
+ return parameters;
+ }
+
+ public Map<String,String> getStandardSnsParameters(ProviderContext ctx, String action) throws InternalException {
+ Map<String,String> parameters = getStandardParameters(ctx, action);
+
+ parameters.put(P_VERSION, SNS_VERSION);
+ return parameters;
+ }
+
+ public Map<String,String> getStandardSqsParameters(ProviderContext ctx, String action) throws InternalException {
+ Map<String,String> parameters = getStandardParameters(ctx, action);
+
+ parameters.put(P_VERSION, SQS_VERSION);
+ return parameters;
+ }
+
+ public String getTimestamp(long timestamp, boolean withMillis) {
+ SimpleDateFormat fmt;
+
+ if( withMillis ) {
+ fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+ }
+ else {
+ fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+ }
+ fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
+ return fmt.format(new Date(timestamp));
+ }
+
+ public boolean isAmazon() {
+ return (getContext().getEndpoint().contains("amazon") || getContext().getEndpoint().contains("enstratus"));
+ }
+
+ public long parseTime(String time) throws CloudException {
+ if( time == null ) {
+ return 0L;
+ }
+ SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+
+ if( time.length() > 0 ) {
+ try {
+ return fmt.parse(time).getTime();
+ }
+ catch( ParseException e ) {
+ fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+ try {
+ return fmt.parse(time).getTime();
+ }
+ catch( ParseException encore ) {
+ throw new CloudException("Could not parse date: " + time);
+ }
+ }
+ }
+ return 0L;
+ }
+
+ private String sign(byte[] key, String authString, String algorithm) throws InternalException {
+ try {
+ Mac mac = Mac.getInstance(algorithm);
+
+ mac.init(new SecretKeySpec(key, algorithm));
+ return new String(Base64.encodeBase64(mac.doFinal(authString.getBytes("utf-8"))));
+ }
+ catch( NoSuchAlgorithmException e ) {
+ logger.error(e);
+ e.printStackTrace();
+ throw new InternalException(e);
+ }
+ catch( InvalidKeyException e ) {
+ logger.error(e);
+ e.printStackTrace();
+ throw new InternalException(e);
+ }
+ catch( IllegalStateException e ) {
+ logger.error(e);
+ e.printStackTrace();
+ throw new InternalException(e);
+ }
+ catch( UnsupportedEncodingException e ) {
+ logger.error(e);
+ e.printStackTrace();
+ throw new InternalException(e);
+ }
+ }
+
+ public String signUploadPolicy(String base64Policy) throws InternalException {
+ return sign(getContext().getAccessPrivate(), base64Policy, S3_ALGORITHM);
+ }
+
+ public String signCloudFront(String accessKey, byte[] secretKey, String dateString) throws InternalException {
+ String signature = sign(secretKey, dateString, CLOUD_FRONT_ALGORITHM);
+
+ return ("AWS" + " " + accessKey + ":" + signature);
+ }
+
+ public String signEc2(byte[] key, String serviceUrl, Map<String, String> parameters) throws InternalException {
+ return sign(key, buildEc2AuthString("POST", serviceUrl, parameters), EC2_ALGORITHM);
+ }
+
+ public String signAWS3(String keyId, byte[] key, String dateString) throws InternalException {
+ return ("AWS3-HTTPS AWSAccessKeyId=" + keyId + ",Algorithm=" + EC2_ALGORITHM + ",Signature=" + sign(key, dateString, EC2_ALGORITHM));
+ }
+
+ public String signS3(String accessKey, byte[] secretKey, String action, String hash, String contentType, Map<String,String> headers, String bucket, String object) throws InternalException {
+ StringBuilder toSign = new StringBuilder();
+
+ toSign.append(action);
+ toSign.append("\n");
+ if( hash != null ) {
+ toSign.append(hash);
+ }
+ toSign.append("\n");
+ if( contentType != null ) {
+ toSign.append(contentType);
+ }
+ toSign.append("\n\n");
+ ArrayList<String> keys = new ArrayList<String>();
+ keys.addAll(headers.keySet());
+ Collections.sort(keys);
+ for( String hkey : keys ) {
+ if( hkey.startsWith("x-amz") ) {
+ String val = headers.get(hkey);
+
+ if( val != null ) {
+ toSign.append(hkey);
+ toSign.append(":");
+ toSign.append(headers.get(hkey).trim());
+ toSign.append("\n");
+ }
+ }
+ }
+ toSign.append("/");
+ if( !isAmazon() ) {
+ toSign.append("services/Walrus/");
+ }
+ if( bucket != null ) {
+ toSign.append(bucket);
+ toSign.append("/");
+ }
+ if( object != null ) {
+ toSign.append(object.toLowerCase());
+ }
+ String signature = sign(secretKey, toSign.toString(), S3_ALGORITHM);
+
+ return ("AWS" + " " + accessKey + ":" + signature);
+ }
+
+ @Override
+ public String testContext() {
+ try {
+ if( !getComputeServices().getVirtualMachineSupport().isSubscribed() ) {
+ return null;
+ }
+ }
+ catch( Throwable t ) {
+ logger.warn("Unable to connect to AWS for " + getContext().getAccountNumber() + ": " + t.getMessage());
+ return null;
+ }
+ return getContext().getAccountNumber();
+ }
+}
View
362 src/main/java/org/dasein/cloud/aws/RegionsAndZones.java
@@ -0,0 +1,362 @@
+/**
+ * Copyright (C) 2009-2012 enStratus Networks Inc
+ *
+ * ====================================================================
+ * Licensed 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.dasein.cloud.aws;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.dasein.cloud.CloudException;
+import org.dasein.cloud.InternalException;
+import org.dasein.cloud.aws.compute.EC2Exception;
+import org.dasein.cloud.aws.compute.EC2Method;
+import org.dasein.cloud.dc.DataCenter;
+import org.dasein.cloud.dc.DataCenterServices;
+import org.dasein.cloud.dc.Region;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class RegionsAndZones implements DataCenterServices {
+ static private final Logger logger = Logger.getLogger(RegionsAndZones.class);
+
+ static public final String DESCRIBE_AVAILABILITY_ZONES = "DescribeAvailabilityZones";
+ static public final String DESCRIBE_REGIONS = "DescribeRegions";
+
+ private AWSCloud provider = null;
+
+ RegionsAndZones(AWSCloud provider) {
+ this.provider = provider;
+ }
+
+ @Override
+ public DataCenter getDataCenter(String zoneId) throws InternalException, CloudException {
+ Map<String,String> parameters = provider.getStandardParameters(provider.getContext(), DESCRIBE_AVAILABILITY_ZONES);
+ EC2Method method;
+ NodeList blocks;
+ Document doc;
+
+ parameters.put("ZoneName", zoneId);
+ method = new EC2Method(provider, provider.getEc2Url(), parameters);
+ try {
+ doc = method.invoke();
+ }
+ catch( EC2Exception e ) {
+ String code = e.getCode();
+
+ if( code != null && code.startsWith("InvalidZone") ) {
+ return null;
+ }
+ if( code != null && code.equals("InvalidParameterValue") ) {
+ String message = e.getMessage();
+
+ if( message != null && message.startsWith("Invalid availability") ) {
+ return null;
+ }
+ }
+ logger.error(e.getSummary());
+ throw new CloudException(e);
+ }
+ blocks = doc.getElementsByTagName("availabilityZoneInfo");
+ for( int i=0; i<blocks.getLength(); i++ ) {
+ NodeList zones = blocks.item(i).getChildNodes();
+
+ for( int j=0; j<zones.getLength(); j++ ) {
+ Node region = zones.item(j);
+
+ if( region.getNodeName().equals("item") ) {
+ DataCenter dc = toDataCenter(null, zones.item(j));
+
+ if( dc != null && dc.getProviderDataCenterId().equals(zoneId) ) {
+ if( dc.getRegionId() == null ) {
+ for( Region r : listRegions() ) {
+ for( DataCenter d : listDataCenters(r.getProviderRegionId()) ) {
+ if( d.getProviderDataCenterId().equals(dc.getProviderDataCenterId()) ) {
+ dc.setRegionId(r.getProviderRegionId());
+ break;
+ }
+ }
+ if( dc.getRegionId() != null ) {
+ break;
+ }
+ }
+ }
+ return dc;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String getProviderTermForDataCenter(Locale locale) {
+ return "availability zone";
+ }
+
+ @Override
+ public String getProviderTermForRegion(Locale locale) {
+ return "region";
+ }
+
+ @Override
+ public Region getRegion(String regionId) throws InternalException, CloudException {
+ Map<String,String> parameters = provider.getStandardParameters(provider.getContext(), DESCRIBE_REGIONS);
+ NodeList blocks, regions;
+ EC2Method method;
+ Document doc;
+
+ parameters.put("RegionName.1", regionId);
+ method = new EC2Method(provider, provider.getEc2Url(), parameters);
+ try {
+ doc = method.invoke();
+ }
+ catch( EC2Exception e ) {
+ String code = e.getCode();
+
+ if( code != null && code.startsWith("InvalidRegion") ) {
+ return null;
+ }
+ if( code != null && code.equals("InvalidParameterValue") ) {
+ String message = e.getMessage();
+
+ if( message != null && message.startsWith("Invalid region") ) {
+ return null;
+ }
+ }
+ logger.error(e.getSummary());
+ throw new CloudException(e);
+ }
+ blocks = doc.getElementsByTagName("regionInfo");
+ for( int i=0; i<blocks.getLength(); i++ ) {
+ regions = blocks.item(i).getChildNodes();
+ for( int j=0; j<regions.getLength(); j++ ) {
+ Node region = regions.item(j);
+
+ if( region.getNodeName().equals("item") ) {
+ Region r = toRegion(region);
+
+ if( r != null ) {
+ return r;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Collection<DataCenter> listDataCenters(String regionId) throws InternalException, CloudException {
+ Map<String,String> parameters = provider.getStandardParameters(provider.getContext(), DESCRIBE_AVAILABILITY_ZONES);
+ EC2Method method = new EC2Method(provider, provider.getEc2Url(), parameters);
+ ArrayList<DataCenter> list = new ArrayList<DataCenter>();
+ NodeList blocks;
+ Document doc;
+
+ try {
+ doc = method.invoke();
+ }
+ catch( EC2Exception e ) {
+ logger.error(e.getSummary());
+ throw new CloudException(e);
+ }
+ blocks = doc.getElementsByTagName("availabilityZoneInfo");
+ for( int i=0; i<blocks.getLength(); i++ ) {
+ NodeList zones = blocks.item(i).getChildNodes();
+
+ for( int j=0; j<zones.getLength(); j++ ) {
+ Node region = zones.item(j);
+
+ if( region.getNodeName().equals("item") ) {
+ list.add(toDataCenter(regionId, zones.item(j)));
+ }
+ }
+ }
+ return list;
+ }
+
+ @Override
+ public Collection<Region> listRegions() throws InternalException, CloudException {
+ ArrayList<Region> list = new ArrayList<Region>();
+
+ Map<String,String> parameters = provider.getStandardParameters(provider.getContext(), DESCRIBE_REGIONS);
+ EC2Method method = new EC2Method(provider, provider.getEc2Url(), parameters);
+ NodeList blocks, regions;
+ Document doc;
+
+ try {
+ doc = method.invoke();
+ }
+ catch( EC2Exception e ) {
+ e.printStackTrace();
+ logger.error(e.getSummary());
+ throw new CloudException(e);
+ }
+ blocks = doc.getElementsByTagName("regionInfo");
+ for( int i=0; i<blocks.getLength(); i++ ) {
+ regions = blocks.item(i).getChildNodes();
+ for( int j=0; j<regions.getLength(); j++ ) {
+ Node region = regions.item(j);
+
+ if( region.getNodeName().equals("item") ) {
+ Region r = toRegion(regions.item(j));
+
+ if( !provider.isAmazon() ) {
+ if( r.getProviderRegionId().equalsIgnoreCase("eucalyptus") ) {
+ list.add(r);
+ }
+ }
+ else {
+ list.add(r);
+ }
+ }
+ }
+ }
+
+ return list;
+ }
+
+ Map<String,String> mapRegions(String url) throws InternalException, CloudException {
+ Map<String,String> parameters = provider.getStandardParameters(provider.getContext(), DESCRIBE_REGIONS);
+ HashMap<String,String> results = new HashMap<String,String>();
+ EC2Method method = new EC2Method(provider, url, parameters);
+ NodeList blocks, regions;
+ Document doc;
+
+ try {
+ doc = method.invoke();
+ }
+ catch( EC2Exception e ) {
+ logger.error(e.getSummary());
+ throw new CloudException(e);
+ }
+ blocks = doc.getElementsByTagName("regionInfo");
+ for( int i=0; i<blocks.getLength(); i++ ) {
+ regions = blocks.item(i).getChildNodes();
+ for( int j=0; j<regions.getLength(); j++ ) {
+ Node region = regions.item(j);
+
+ if( region.getNodeName().equals("item") ) {
+ NodeList data = region.getChildNodes();
+ String name = null, endpoint = null;
+
+ for( int k=0; k<data.getLength(); k++ ) {
+ Node item = data.item(k);
+
+ if( item.getNodeName().equals("regionName") ) {
+ name = item.getFirstChild().getNodeValue();
+ }
+ else if( item.getNodeName().equals("regionEndpoint") ) {
+ endpoint = item.getFirstChild().getNodeValue();
+ }
+ }
+ if( name != null && endpoint != null ) {
+ logger.debug(name + "=" + endpoint);
+ results.put(name, endpoint);
+ }
+ }
+ }
+ }
+ return results;
+ }
+
+ private DataCenter toDataCenter(String regionId, Node zone) throws CloudException {
+ NodeList data = zone.getChildNodes();
+ DataCenter dc = new DataCenter();
+
+ dc.setActive(true);
+ dc.setAvailable(false);
+ dc.setRegionId(regionId);
+ for( int i=0; i<data.getLength(); i++ ) {
+ Node item = data.item(i);
+ String name = item.getNodeName();
+
+ if( name.equals("zoneName") ) {
+ String value = item.getFirstChild().getNodeValue().trim();
+
+ dc.setName(value);
+ dc.setProviderDataCenterId(value);
+ }
+ else if( name.equals("zoneState") ) {
+ String value = item.getFirstChild().getNodeValue();
+
+ if( !provider.isAmazon() ) {
+ dc.setAvailable(true);
+ }
+ else {
+ dc.setAvailable(value != null && value.trim().equalsIgnoreCase("available"));
+ }
+ }
+ else if( name.equals("regionName") ) {
+ if( item.hasChildNodes() ) {
+ String value = item.getFirstChild().getNodeValue();
+
+ if( value != null ) {
+ dc.setRegionId(value.trim());
+ }
+ }
+ }
+ }
+ if( dc.getName() == null ) {
+ throw new CloudException("Availability zone info is incomplete for " + dc.getProviderDataCenterId() + ".");
+ }
+ return dc;
+ }
+
+ private Region toRegion(Node region) throws CloudException {
+ String name = null, endpoint = null;
+ NodeList data;
+
+ data = region.getChildNodes();
+ for( int i=0; i<data.getLength(); i++ ) {
+ Node item = data.item(i);
+
+ if( item.getNodeName().equals("regionName") ) {
+ name = item.getFirstChild().getNodeValue();
+ }
+ else if( item.getNodeName().equals("regionEndpoint") ) {
+ endpoint = item.getFirstChild().getNodeValue();
+ }
+ }
+ if( name == null || endpoint == null ) {
+ throw new CloudException("Invalid region data.");
+ }
+ Region r = new Region();
+ r.setActive(true);
+ r.setAvailable(true);
+ r.setName(name);
+ r.setProviderRegionId(name);
+ if( name.startsWith("eu") ) {
+ r.setJurisdiction("EU");
+ }
+ else if( name.startsWith("ap-northeast") ) {
+ r.setJurisdiction("JP");
+ }
+ else if( name.startsWith("ap-southeast") ) {
+ r.setJurisdiction("SG");
+ }
+ else {
+ r.setJurisdiction("US");
+ }
+ return r;
+ }
+}
View
33 src/main/java/org/dasein/cloud/aws/admin/AWSAdminServices.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (C) 2009-2012 enStratus Networks Inc
+ *
+ * ====================================================================
+ * Licensed 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.dasein.cloud.aws.admin;
+
+import org.dasein.cloud.admin.AbstractAdminServices;
+import org.dasein.cloud.aws.AWSCloud;
+
+public class AWSAdminServices extends AbstractAdminServices {
+ private AWSCloud cloud;
+
+ public AWSAdminServices(AWSCloud cloud) { this.cloud = cloud; }
+
+ @Override
+ public ReservedInstance getPrepaymentSupport() {
+ return new ReservedInstance(cloud);
+ }
+}
View
393 src/main/java/org/dasein/cloud/aws/admin/ReservedInstance.java
@@ -0,0 +1,393 @@
+/**
+ * Copyright (C) 2009-2012 enStratus Networks Inc
+ *
+ * ====================================================================
+ * Licensed 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.dasein.cloud.aws.admin;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.dasein.cloud.CloudException;
+import org.dasein.cloud.InternalException;
+import org.dasein.cloud.admin.Offering;
+import org.dasein.cloud.admin.Prepayment;
+import org.dasein.cloud.admin.PrepaymentState;
+import org.dasein.cloud.admin.PrepaymentSupport;
+import org.dasein.cloud.aws.AWSCloud;
+import org.dasein.cloud.aws.compute.EC2Exception;
+import org.dasein.cloud.aws.compute.EC2Method;
+import org.dasein.cloud.compute.ComputeServices;
+import org.dasein.cloud.compute.Platform;
+import org.dasein.cloud.compute.VirtualMachineSupport;
+import org.dasein.cloud.identity.ServiceAction;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+public class ReservedInstance implements PrepaymentSupport {
+ static private final Logger logger = AWSCloud.getLogger(ReservedInstance.class);
+
+ static private final int SECONDS_IN_DAY = (60 * 60 * 24);
+
+ private AWSCloud provider = null;
+
+ ReservedInstance(@Nonnull AWSCloud provider) {
+ this.provider = provider;
+ }
+
+ @Override
+ public @Nullable Offering getOffering(@Nonnull String offeringId) throws InternalException, CloudException {
+ Map<String,String> parameters = provider.getStandardParameters(provider.getContext(), EC2Method.DESCRIBE_RESERVED_INSTANCES_OFFERINGS);
+ EC2Method method;
+ NodeList blocks;
+ Document doc;
+
+ parameters.put("ReservedInstancesOfferingId", offeringId);
+ method = new EC2Method(provider, provider.getEc2Url(), parameters);
+ try {
+ doc = method.invoke();
+ }
+ catch( EC2Exception e ) {
+ String code = e.getCode();
+
+ if( code != null && code.startsWith("InvalidReservedInstancesOfferingId") ) {
+ return null;
+ }
+ logger.error(e.getSummary());
+ throw new CloudException(e);
+ }
+ blocks = doc.getElementsByTagName("reservedInstancesOfferingsSet");
+ for( int i=0; i<blocks.getLength(); i++ ) {
+ NodeList items = blocks.item(i).getChildNodes();
+
+ for( int j=0; j<items.getLength(); j++ ) {
+ Node item = items.item(j);
+
+ if( item.getNodeName().equals("item") ) {
+ Offering offering = toOffering(item);
+
+ if( offering != null && offering.getProviderOfferingId().equals(offeringId) ) {
+ return offering;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public @Nullable Prepayment getPrepayment(@Nonnull String prepaymentId) throws InternalException, CloudException {
+ Map<String,String> parameters = provider.getStandardParameters(provider.getContext(), EC2Method.DESCRIBE_RESERVED_INSTANCES);
+ EC2Method method;
+ NodeList blocks;
+ Document doc;
+
+ parameters.put("ReservedInstancesId.1", prepaymentId);
+ method = new EC2Method(provider, provider.getEc2Url(), parameters);
+ try {
+ doc = method.invoke();
+ }
+ catch( EC2Exception e ) {
+ String code = e.getCode();
+
+ if( code != null && code.startsWith("InvalidReservedInstancesId") ) {
+ return null;
+ }
+ logger.error(e.getSummary());
+ throw new CloudException(e);
+ }
+ blocks = doc.getElementsByTagName("reservedInstancesSet");
+ for( int i=0; i<blocks.getLength(); i++ ) {
+ NodeList items = blocks.item(i).getChildNodes();
+
+ for( int j=0; j<items.getLength(); j++ ) {
+ Node item = items.item(j);
+
+ if( item.getNodeName().equals("item") ) {
+ Prepayment prepayment = toPrepayment(item);
+
+ if( prepayment != null && prepayment.getProviderPrepaymentId().equals(prepaymentId) ) {
+ return prepayment;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public @Nonnull String getProviderTermForOffering(@Nonnull Locale locale) {
+ return "offering";
+ }
+
+ @Override
+ public @Nonnull String getProviderTermForPrepayment(@Nonnull Locale locale) {
+ return "reserved instance";
+ }
+
+ @Override
+ public boolean isSubscribed() throws CloudException, InternalException {
+ ComputeServices svc = provider.getComputeServices();
+
+ if( svc == null ) {
+ return false;
+ }
+ VirtualMachineSupport support = svc.getVirtualMachineSupport();
+
+ return (support != null && support.isSubscribed());
+ }
+
+ @Override
+ public @Nonnull Collection<Offering> listOfferings() throws InternalException, CloudException {
+ Map<String,String> parameters = provider.getStandardParameters(provider.getContext(), EC2Method.DESCRIBE_RESERVED_INSTANCES_OFFERINGS);
+ ArrayList<Offering> list = new ArrayList<Offering>();
+ EC2Method method;
+ NodeList blocks;
+ Document doc;
+
+ method = new EC2Method(provider, provider.getEc2Url(), parameters);
+ try {
+ doc = method.invoke();
+ }
+ catch( EC2Exception e ) {
+ logger.error(e.getSummary());
+ throw new CloudException(e);
+ }
+ blocks = doc.getElementsByTagName("reservedInstancesOfferingsSet");
+ for( int i=0; i<blocks.getLength(); i++ ) {
+ NodeList items = blocks.item(i).getChildNodes();
+
+ for( int j=0; j<items.getLength(); j++ ) {
+ Node item = items.item(j);
+
+ if( item.getNodeName().equals("item") ) {
+ Offering offering = toOffering(item);
+
+ if( offering != null ) {
+ list.add(offering);
+ }
+ }
+ }
+ }
+ return list;
+ }
+
+ @Override
+ public @Nonnull Collection<Prepayment> listPrepayments() throws InternalException, CloudException {
+ Map<String,String> parameters = provider.getStandardParameters(provider.getContext(), EC2Method.DESCRIBE_RESERVED_INSTANCES);
+ ArrayList<Prepayment> list = new ArrayList<Prepayment>();
+ EC2Method method;
+ NodeList blocks;
+ Document doc;
+
+ method = new EC2Method(provider, provider.getEc2Url(), parameters);
+ try {
+ doc = method.invoke();
+ }
+ catch( EC2Exception e ) {
+ logger.error(e.getSummary());
+ throw new CloudException(e);
+ }
+ blocks = doc.getElementsByTagName("reservedInstancesSet");
+ for( int i=0; i<blocks.getLength(); i++ ) {
+ NodeList items = blocks.item(i).getChildNodes();
+
+ for( int j=0; j<items.getLength(); j++ ) {
+ Node item = items.item(j);
+
+ if( item.getNodeName().equals("item") ) {
+ Prepayment prepayment = toPrepayment(item);
+
+ if( prepayment != null ) {
+ list.add(prepayment);
+ }
+ }
+ }
+ }
+ return list;
+ }
+
+ @Override
+ public @Nonnull String[] mapServiceAction(@Nonnull ServiceAction action) {
+ if( action.equals(PrepaymentSupport.ANY) ) {
+ return new String[] { EC2Method.EC2_PREFIX + "*" };
+ }
+ else if( action.equals(PrepaymentSupport.GET_OFFERING) || action.equals(PrepaymentSupport.LIST_OFFERING) ) {
+ return new String[] { EC2Method.EC2_PREFIX + EC2Method.DESCRIBE_RESERVED_INSTANCES_OFFERINGS };
+ }
+ else if( action.equals(PrepaymentSupport.GET_PREPAYMENT) || action.equals(PrepaymentSupport.LIST_PREPAYMENT) ) {
+ return new String[] { EC2Method.EC2_PREFIX + EC2Method.DESCRIBE_RESERVED_INSTANCES };
+ }
+ else if( action.equals(PrepaymentSupport.PREPAY) ) {
+ return new String[] { EC2Method.EC2_PREFIX + EC2Method.PURCHASE_RESERVED_INSTANCES_OFFERING };
+ }
+ return new String[0];
+ }
+
+ @Override
+ public @Nonnull String prepay(@Nonnull String offeringId, @Nonnegative int count) throws InternalException, CloudException {
+ Map<String,String> parameters = provider.getStandardParameters(provider.getContext(), EC2Method.PURCHASE_RESERVED_INSTANCES_OFFERING);
+ EC2Method method;
+ NodeList blocks;
+ Document doc;
+
+ parameters.put("ReservedInstanceOfferingId.1", offeringId);
+ parameters.put("InstanceCount.1", String.valueOf(count));
+ method = new EC2Method(provider, provider.getEc2Url(), parameters);
+ try {
+ doc = method.invoke();
+ }
+ catch( EC2Exception e ) {
+ logger.error(e.getSummary());
+ throw new CloudException(e);
+ }
+ blocks = doc.getElementsByTagName("reservedInstancesId");
+ if( blocks.getLength() > 0 ) {
+ return blocks.item(0).getFirstChild().getNodeValue().trim();
+ }
+ throw new CloudException("Unable to identify newly reserved instance");
+ }
+
+ private @Nullable Offering toOffering(@Nullable Node node) throws CloudException {
+ if( node == null ) {
+ return null;
+ }
+ Offering offering = new Offering();
+ NodeList attrs = node.getChildNodes();
+
+ for( int i=0; i<attrs.getLength(); i++ ) {
+ Node attr = attrs.item(i);
+ String name;
+
+ name = attr.getNodeName();
+ if( name.equals("reservedInstancesOfferingId") ) {
+ offering.setOfferingId(attr.getFirstChild().getNodeValue().trim());
+ }
+ else if( name.equals("instanceType") ) {
+ offering.setSize(attr.getFirstChild().getNodeValue().trim());
+ }
+ else if( name.equals("availabilityZone") ) {
+ offering.setDataCenterId(attr.getFirstChild().getNodeValue().trim());
+ }
+ else if( name.equals("fixedPrice") ) {
+ double fixedFee = Double.parseDouble(attr.getFirstChild().getNodeValue().trim());
+
+ offering.setFixedFee(fixedFee);
+ }
+ else if( name.equals("usagePrice") ) {
+ double usageFee = Double.parseDouble(attr.getFirstChild().getNodeValue().trim());
+
+ offering.setUsageFee(usageFee);
+ }
+ else if( name.equals("duration") ) {
+ int seconds = Integer.parseInt(attr.getFirstChild().getNodeValue().trim());
+
+ offering.setPeriodInDays(seconds/SECONDS_IN_DAY);
+ }
+ }
+ offering.setCurrencyCode("USD");
+ offering.setPlatform(Platform.UNIX);
+ offering.setSoftware(null);
+ return offering;
+ }
+
+ private @Nullable Prepayment toPrepayment(@Nullable Node node) throws CloudException {
+ if( node == null ) {
+ return null;
+ }
+ Prepayment prepayment = new Prepayment();
+ NodeList attrs = node.getChildNodes();
+
+ for( int i=0; i<attrs.getLength(); i++ ) {
+ Node attr = attrs.item(i);
+ String name;
+
+ name = attr.getNodeName();
+ if( name.equals("reservedInstancesId") ) {
+ prepayment.setPrepaymentId(attr.getFirstChild().getNodeValue().trim());
+ }
+ else if( name.equals("instanceType") ) {
+ prepayment.setSize(attr.getFirstChild().getNodeValue().trim());
+ }
+ else if( name.equals("availabilityZone") ) {
+ prepayment.setDataCenterId(attr.getFirstChild().getNodeValue().trim());
+ }
+ else if( name.equals("instanceCount") ) {
+ int count = Integer.parseInt(attr.getFirstChild().getNodeValue().trim());
+
+ prepayment.setCount(count);
+ }
+ else if( name.equals("fixedPrice") ) {
+ double fixedFee = Double.parseDouble(attr.getFirstChild().getNodeValue().trim());
+
+ prepayment.setFixedFee(fixedFee);
+ }
+ else if( name.equals("usagePrice") ) {
+ double usageFee = Double.parseDouble(attr.getFirstChild().getNodeValue().trim());
+
+ prepayment.setUsageFee(usageFee);
+ }
+ else if( name.equals("duration") ) {
+ int seconds = Integer.parseInt(attr.getFirstChild().getNodeValue().trim());
+
+ prepayment.setPeriodInDays(seconds/SECONDS_IN_DAY);
+ }
+ else if( name.equals("start") ) {
+ SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+ String start = attr.getFirstChild().getNodeValue().trim();
+
+ try {
+ prepayment.setPeriodStartTimestamp(fmt.parse(start).getTime());
+ }
+ catch( ParseException e ) {
+ logger.error(e);
+ e.printStackTrace();
+ throw new CloudException(e);
+ }
+ }
+ else if( name.equals("state") ) {
+ String state = attr.getFirstChild().getNodeValue().trim();
+
+ if( state.equalsIgnoreCase("active") ) {
+ prepayment.setPrepaymentState(PrepaymentState.PAID);
+ }
+ else if( state.equalsIgnoreCase("payment-failed") ) {
+ prepayment.setPrepaymentState(PrepaymentState.REJECTED);
+ }
+ else if( state.equalsIgnoreCase("retired") ) {
+ prepayment.setPrepaymentState(PrepaymentState.RETIRED);
+ }
+ else {
+ prepayment.setPrepaymentState(PrepaymentState.PENDING);
+ }
+ }
+ }
+ prepayment.setCurrencyCode("USD");
+ prepayment.setPlatform(Platform.UNIX);
+ prepayment.setSoftware(null);
+ return prepayment;
+ }
+}
View
1,078 src/main/java/org/dasein/cloud/aws/compute/AMI.java
@@ -0,0 +1,1078 @@
+/**
+ * Copyright (C) 2009-2012 enStratus Networks Inc
+ *
+ * ====================================================================
+ * Licensed 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.dasein.cloud.aws.compute;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.dasein.cloud.AsynchronousTask;
+import org.dasein.cloud.CloudException;
+import org.dasein.cloud.CloudProvider;
+import org.dasein.cloud.InternalException;
+import org.dasein.cloud.aws.AWSCloud;
+import org.dasein.cloud.aws.storage.S3Method;
+import org.dasein.cloud.compute.Architecture;
+import org.dasein.cloud.compute.MachineImage;
+import org.dasein.cloud.compute.MachineImageFormat;
+import org.dasein.cloud.compute.MachineImageState;
+import org.dasein.cloud.compute.MachineImageSupport;
+import org.dasein.cloud.compute.MachineImageType;
+import org.dasein.cloud.compute.Platform;
+import org.dasein.cloud.identity.ServiceAction;
+import org.dasein.cloud.storage.CloudStoreObject;
+import org.dasein.util.CalendarWrapper;
+import org.dasein.util.Jiterator;
+import org.dasein.util.JiteratorPopulator;
+import org.dasein.util.PopulatorThread;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import javax.annotation.Nonnull;
+
+public class AMI implements MachineImageSupport {
+ static private final Logger logger = Logger.getLogger(AMI.class);
+
+ private AWSCloud provider = null;
+
+ AMI(AWSCloud provider) {
+ this.provider = provider;
+ }
+
+ @Override
+ public void downloadImage(String machineImageId, OutputStream toOutput) throws CloudException, InternalException {
+ CloudStoreObject manifest = getManifest(machineImageId);
+
+ if( manifest == null ) {
+ throw new CloudException("No such image manifest: " + machineImageId);
+ }
+ String name = manifest.getName();
+ int idx = name.indexOf(".manifest.xml");
+
+ if( idx < 1 ) {
+ throw new CloudException("Nonsense manifest: " + name);
+ }
+ name = name.substring(0, idx);
+ idx = 0;
+ while( true ) {
+ String postfix = ".part." + (idx < 10 ? ("0" + idx) : String.valueOf(idx));
+ long len = provider.getStorageServices().getBlobStoreSupport().exists(manifest.getDirectory(), name + postfix, false);
+
+ if( len < 1 ) {
+ return;
+ }
+ // TODO: get source file
+ // TODO: read to stream
+ // provider.getStorageServices().getBlobStoreSupport().download(sourceFile, toFile)
+ }
+ }
+
+ private String getImageLocation(String imageId) throws CloudException, InternalException {
+ Map<String,String> parameters = provider.getStandardParameters(provider.getContext(), EC2Method.DESCRIBE_IMAGES);
+ NodeList blocks;
+ EC2Method method;
+ Document doc;
+
+ parameters.put("ImageId", imageId);
+ method = new EC2Method(provider, provider.getEc2Url(), parameters);
+ try {
+ doc = method.invoke();
+ }
+ catch( EC2Exception e ) {
+ String code = e.getCode();
+
+ if( code != null && code.startsWith("InvalidAMIID") ) {
+ return null;
+ }
+ logger.error(e.getSummary());
+ throw new CloudException(e);
+ };
+ blocks = doc.getElementsByTagName("imagesSet");
+ for( int i=0; i<blocks.getLength(); i++ ) {
+ NodeList instances = blocks.item(i).getChildNodes();
+
+ for( int j=0; j<instances.getLength(); j++ ) {
+ Node instance = instances.item(j);
+
+ if( instance.getNodeName().equals("item") ) {
+ NodeList attributes = instance.getChildNodes();
+
+ for( int k=0; k<attributes.getLength(); k++ ) {
+ Node attribute = attributes.item(i);
+ String name = attribute.getNodeName();
+
+ if( name.equals("imageLocation") ) {
+ return attribute.getFirstChild().getNodeValue().trim();
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+
+ @Override
+ public MachineImage getMachineImage(String imageId) throws InternalException, CloudException {
+ if( provider.isAmazon() ) {
+ Map<String,String> parameters = provider.getStandardParameters(provider.getContext(), EC2Method.DESCRIBE_IMAGES);
+ NodeList blocks;
+ EC2Method method;
+ Document doc;
+
+ parameters.put("ImageId", imageId);
+ method = new EC2Method(provider, provider.getEc2Url(), parameters);
+ try {
+ doc = method.invoke();
+ }
+ catch( EC2Exception e ) {
+ String code = e.getCode();
+
+ if( code != null && code.startsWith("InvalidAMIID") ) {
+ return null;
+ }
+ logger.error(e.getSummary());
+ throw new CloudException(e);
+ }
+ blocks = doc.getElementsByTagName("imagesSet");
+ for( int i=0; i<blocks.getLength(); i++ ) {
+ NodeList instances = blocks.item(i).getChildNodes();
+
+ for( int j=0; j<instances.getLength(); j++ ) {
+ Node instance = instances.item(j);
+
+ if( instance.getNodeName().equals("item") ) {
+ MachineImage image = toMachineImage(instance);
+
+ if( image != null && image.getProviderMachineImageId().equals(imageId) ) {
+ return image;
+ }
+ }
+ }
+ }
+ return null;
+ }
+ else {
+ for( MachineImage image : listMachineImages() ) {
+ if( image.getProviderMachineImageId().equals(imageId) ) {
+ return image;
+ }
+ }
+ return null;
+ }
+ }
+
+ private CloudStoreObject getManifest(String imageId) throws CloudException, InternalException {
+ String location = getImageLocation(imageId);
+
+ if( location != null ) {
+ String[] parts = location.split("/");
+ CloudStoreObject file = new CloudStoreObject();
+
+ file.setContainer(false);
+ file.setDirectory(parts[0]);
+ file.setLocation(location);
+ file.setName(parts[1]);
+ return file;
+ }
+ return null;
+ }
+
+ @Override
+ public String getProviderTermForImage(Locale locale) {
+ return "AMI";
+ }
+
+ @Override
+ public boolean hasPublicLibrary() {
+ return true;
+ }
+
+ @Override
+ public AsynchronousTask<String> imageVirtualMachine(String vmId, String name, String description) throws CloudException, InternalException {
+ final AsynchronousTask<String> task = new AsynchronousTask<String>();
+ final String fvmId = vmId;
+ final String fname = name;
+ final String fdesc = description;
+
+ Thread t = new Thread() {
+ public void run() {
+ try {
+ task.completeWithResult(imageVirtualMachine(fvmId, fname, fdesc, task));
+ }
+ catch( Throwable t ) {
+ task.complete(t);
+ }
+ }
+ };
+
+ t.setName("Imaging " + vmId + " as " + name);
+ t.setDaemon(true);
+ t.start();
+ return task;
+ }
+
+ private String imageVirtualMachine(String vmId, String name, String description, AsynchronousTask<String> task) throws CloudException, InternalException {
+ Map<String,String> parameters = provider.getStandardParameters(provider.getContext(), EC2Method.CREATE_IMAGE);
+ NodeList blocks;
+ EC2Method method;
+ Document doc;
+
+ parameters.put("InstanceId", vmId);
+ parameters.put("Name", name + "-" + System.currentTimeMillis());
+ parameters.put("Description", description);
+ method = new EC2Method(provider, provider.getEc2Url(), parameters);
+ try {
+ doc = method.invoke();
+ }
+ catch( EC2Exception e ) {
+ logger.error(e.getSummary());
+ throw new CloudException(e);
+ }
+ blocks = doc.getElementsByTagName("imageId");
+ if( blocks.getLength() > 0 ) {
+ Node imageIdNode = blocks.item(0);
+
+ return imageIdNode.getFirstChild().getNodeValue().trim();
+ }
+ return null;
+ }
+
+ @Override
+ public AsynchronousTask<String> imageVirtualMachineToStorage(String vmId, String name, String description, String directory) throws CloudException, InternalException {
+ Map<String,String> parameters = provider.getStandardParameters(provider.getContext(), EC2Method.BUNDLE_INSTANCE);
+ StringBuilder uploadPolicy = new StringBuilder();
+ NodeList blocks;
+ EC2Method method;
+ Document doc;
+
+ uploadPolicy.append("{");
+ uploadPolicy.append("\"expiration\":\"");
+ {
+ SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+ Date date = new Date(System.currentTimeMillis() + (CalendarWrapper.HOUR*12L));
+
+ uploadPolicy.append(fmt.format(date));
+ }
+ uploadPolicy.append("\",\"conditions\":");
+ {
+ uploadPolicy.append("[");
+ uploadPolicy.append("{\"bucket\":\"");
+ uploadPolicy.append(directory);
+ uploadPolicy.append("\"},");
+ uploadPolicy.append("{\"acl\": \"ec2-bundle-read\"},");
+ uploadPolicy.append("[\"starts-with\", \"$key\", \"");
+ uploadPolicy.append(name);
+ uploadPolicy.append("\"]");
+ uploadPolicy.append("]");
+ }
+ uploadPolicy.append("}");
+ String base64Policy;
+
+ try {
+ base64Policy = S3Method.toBase64(uploadPolicy.toString().getBytes("utf-8"));
+ }
+ catch( UnsupportedEncodingException e ) {
+ logger.error(e);
+ e.printStackTrace();
+ throw new InternalException(e);
+ }
+ parameters.put("InstanceId", vmId);
+ parameters.put("Storage.S3.Bucket", directory);
+ parameters.put("Storage.S3.Prefix", name);
+ parameters.put("Storage.S3.AWSAccessKeyId", provider.getContext().getAccountNumber());
+ parameters.put("Storage.S3.UploadPolicy", base64Policy);
+ parameters.put("Storage.S3.UploadPolicySignature", provider.signUploadPolicy(base64Policy));
+ method = new EC2Method(provider, provider.getEc2Url(), parameters);
+ try {
+ doc = method.invoke();
+ }
+ catch( EC2Exception e ) {
+ logger.error(e.getSummary());
+ throw new CloudException(e);
+ }
+ blocks = doc.getElementsByTagName("bundleId");
+ if( blocks.getLength() < 1 ) {
+ throw new CloudException("Unable to identify the bundle task ID.");
+ }
+ final String bundleId = blocks.item(0).getFirstChild().getNodeValue();
+ final AsynchronousTask<String> task = new AsynchronousTask<String>();
+ final String manifest = (directory + "/" + name + ".manifest.xml");
+
+ Thread t = new Thread() {
+ public void run() {
+ waitForBundle(bundleId, manifest, task);
+
+ }
+ };
+
+ t.setName("Bundle Task: " + manifest);
+ t.setDaemon(true);
+ t.start();
+ return task;
+ }
+
+ @Override
+ public String installImageFromUpload(MachineImageFormat format, InputStream imageStream) throws CloudException, InternalException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean isImageSharedWithPublic(String machineImageId) throws CloudException, InternalException {
+ MachineImage image = getMachineImage(machineImageId);
+
+ if( image == null ) {
+ return false;
+ }
+ String p = (String)image.getTag("public");
+
+ return (p != null && p.equalsIgnoreCase("true"));
+ }
+
+ @Override
+ public boolean isSubscribed() throws CloudException, InternalException {
+ Map<String,String> parameters = provider.getStandardParameters(provider.getContext(), EC2Method.DESCRIBE_IMAGES);
+ EC2Method method;
+
+ if( provider.isAmazon() ) {