You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by za...@apache.org on 2013/12/13 00:38:17 UTC

[1/4] Moving trove to jclouds from jclouds-openstack-labs https://issues.apache.org/jira/browse/JCLOUDS-102

Updated Branches:
  refs/heads/master cec0981bb -> 6de84cb00


http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/user_create_simple_request.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/user_create_simple_request.json b/apis/openstack-trove/src/test/resources/user_create_simple_request.json
new file mode 100644
index 0000000..e28d0d7
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/user_create_simple_request.json
@@ -0,0 +1,13 @@
+{
+    "users":[
+        {
+            "databases":[
+                {
+                    "name":"databaseA"
+                }
+            ],
+            "name":"dbuser1",
+            "password":"password"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/user_create_with_host_simple_request.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/user_create_with_host_simple_request.json b/apis/openstack-trove/src/test/resources/user_create_with_host_simple_request.json
new file mode 100644
index 0000000..0449f49
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/user_create_with_host_simple_request.json
@@ -0,0 +1,14 @@
+{
+    "users":[
+        {
+            "databases":[
+                {
+                    "name":"databaseA"
+                }
+            ],
+            "name":"dbuser1",
+            "password":"password",
+            "host":"192.168.64.64"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/user_get.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/user_get.json b/apis/openstack-trove/src/test/resources/user_get.json
new file mode 100644
index 0000000..478a94d
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/user_get.json
@@ -0,0 +1,14 @@
+{
+   "user": {
+      "name": "exampleuser",
+      "host": "%",
+      "databases": [
+         {
+            "name": "databaseA"
+         },
+         {
+            "name": "databaseB"
+         }
+      ]
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/user_get_withhost.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/user_get_withhost.json b/apis/openstack-trove/src/test/resources/user_get_withhost.json
new file mode 100644
index 0000000..2827568
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/user_get_withhost.json
@@ -0,0 +1,14 @@
+{
+   "user": {
+      "name": "example.user",
+      "host": "192.168.64.64",
+      "databases": [
+         {
+            "name": "databaseA"
+         },
+         {
+            "name": "databaseB"
+         }
+      ]
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/user_grant_request.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/user_grant_request.json b/apis/openstack-trove/src/test/resources/user_grant_request.json
new file mode 100644
index 0000000..97a1239
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/user_grant_request.json
@@ -0,0 +1,10 @@
+{
+   "databases": [
+      {
+         "name": "databaseC"
+      },
+      {
+         "name": "databaseD"
+      }
+   ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/user_grant_simple_request.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/user_grant_simple_request.json b/apis/openstack-trove/src/test/resources/user_grant_simple_request.json
new file mode 100644
index 0000000..5113e4f
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/user_grant_simple_request.json
@@ -0,0 +1,7 @@
+{
+   "databases": [
+      {
+         "name": "databaseZ"
+      }
+   ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/user_list_access.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/user_list_access.json b/apis/openstack-trove/src/test/resources/user_list_access.json
new file mode 100644
index 0000000..c58e1fa
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/user_list_access.json
@@ -0,0 +1,10 @@
+{
+   "databases": [
+      {
+         "name": "databaseA"
+      },
+      {
+         "name": "databaseB"
+      }
+   ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/user_password_request.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/user_password_request.json b/apis/openstack-trove/src/test/resources/user_password_request.json
new file mode 100644
index 0000000..e42b277
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/user_password_request.json
@@ -0,0 +1,12 @@
+{
+   "users": [
+      {
+          "name": "dbuser1",
+          "password": "newpassword"
+      },
+      {
+           "name": "dbuser2",
+           "password": "anotherpassword"
+      }
+   ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/pom.xml
----------------------------------------------------------------------
diff --git a/apis/pom.xml b/apis/pom.xml
index 6a1ac22..4047677 100644
--- a/apis/pom.xml
+++ b/apis/pom.xml
@@ -46,6 +46,7 @@
     <module>openstack-cinder</module>
     <module>openstack-nova</module>
     <module>openstack-nova-ec2</module>
+    <module>openstack-trove</module>
     <module>cloudfiles</module>
     <module>cloudservers</module>
     <module>rackspace-cloudidentity</module>

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/pom.xml
----------------------------------------------------------------------
diff --git a/providers/pom.xml b/providers/pom.xml
index 320aa88..d46571f 100644
--- a/providers/pom.xml
+++ b/providers/pom.xml
@@ -61,6 +61,8 @@
     <module>cloudfiles-uk</module>
     <module>rackspace-clouddns-us</module>
     <module>rackspace-clouddns-uk</module>
+    <module>rackspace-clouddatabases-us</module>
+    <module>rackspace-clouddatabases-uk</module>
     <module>rackspace-cloudloadbalancers-us</module>
     <module>rackspace-cloudloadbalancers-uk</module>
     <module>rackspace-cloudservers-us</module>

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-uk/README.md
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-uk/README.md b/providers/rackspace-clouddatabases-uk/README.md
new file mode 100644
index 0000000..9357d9a
--- /dev/null
+++ b/providers/rackspace-clouddatabases-uk/README.md
@@ -0,0 +1,7 @@
+Rackspace Cloud Databases UK
+============================
+
+The Rackspace deployment of OpenStack Trove, the Database as a Service.
+
+Production ready?
+Yes

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-uk/pom.xml
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-uk/pom.xml b/providers/rackspace-clouddatabases-uk/pom.xml
new file mode 100644
index 0000000..f3e50a7
--- /dev/null
+++ b/providers/rackspace-clouddatabases-uk/pom.xml
@@ -0,0 +1,148 @@
+<?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/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.jclouds</groupId>
+    <artifactId>jclouds-project</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+    <relativePath>../../project/pom.xml</relativePath>
+  </parent>
+  <groupId>org.apache.jclouds.provider</groupId>
+  <artifactId>rackspace-clouddatabases-uk</artifactId>
+  <name>jclouds Rackspace Cloud Databases UK provider</name>
+  <description>OpenStack Trove implementation targeted to Rackspace Cloud Databases UK</description>
+  <packaging>bundle</packaging>
+
+  <properties>
+    <test.rackspace-clouddatabases-uk.endpoint>https://identity.api.rackspacecloud.com/v2.0/</test.rackspace-clouddatabases-uk.endpoint>
+    <test.rackspace-clouddatabases-uk.api-version>1</test.rackspace-clouddatabases-uk.api-version>
+    <test.rackspace-clouddatabases-uk.build-version />
+    <test.rackspace-clouddatabases-uk.identity>${test.rackspace-uk.identity}</test.rackspace-clouddatabases-uk.identity>
+    <test.rackspace-clouddatabases-uk.credential>${test.rackspace-uk.credential}</test.rackspace-clouddatabases-uk.credential>
+    <test.rackspace-clouddatabases-uk.template />
+    <jclouds.osgi.export>org.jclouds.rackspace.clouddatabases.uk*;version="${project.version}"</jclouds.osgi.export>
+    <jclouds.osgi.import>
+      org.jclouds.compute.internal;version="${project.version}",
+      org.jclouds.rest.internal;version="${project.version}",
+      org.jclouds*;version="${project.version}",
+      *
+    </jclouds.osgi.import>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.jclouds</groupId>
+      <artifactId>jclouds-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.labs</groupId>
+      <artifactId>openstack-trove</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.api</groupId>
+      <artifactId>openstack-keystone</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.api</groupId>
+      <artifactId>rackspace-cloudidentity</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds</groupId>
+      <artifactId>jclouds-core</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.labs</groupId>
+      <artifactId>openstack-trove</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.api</groupId>
+      <artifactId>openstack-keystone</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.api</groupId>
+      <artifactId>rackspace-cloudidentity</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.driver</groupId>
+      <artifactId>jclouds-slf4j</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <profiles>
+    <profile>
+      <id>live</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>integration</id>
+                <phase>integration-test</phase>
+                <goals>
+                  <goal>test</goal>
+                </goals>
+                <configuration>
+                  <forkCount>5</forkCount>
+                  <reuseForks>true</reuseForks>
+                  <parallel>classes</parallel>
+                  <systemPropertyVariables>
+                    <test.rackspace-clouddatabases-uk.endpoint>${test.rackspace-clouddatabases-uk.endpoint}</test.rackspace-clouddatabases-uk.endpoint>
+                    <test.rackspace-clouddatabases-uk.api-version>${test.rackspace-clouddatabases-uk.api-version}</test.rackspace-clouddatabases-uk.api-version>
+                    <test.rackspace-clouddatabases-uk.build-version>${test.rackspace-clouddatabases-uk.build-version}</test.rackspace-clouddatabases-uk.build-version>
+                    <test.rackspace-clouddatabases-uk.identity>${test.rackspace-clouddatabases-uk.identity}</test.rackspace-clouddatabases-uk.identity>
+                    <test.rackspace-clouddatabases-uk.credential>${test.rackspace-clouddatabases-uk.credential}</test.rackspace-clouddatabases-uk.credential>
+                    <test.rackspace-clouddatabases-uk.template>${test.rackspace-clouddatabases-uk.template}</test.rackspace-clouddatabases-uk.template>
+                  </systemPropertyVariables>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
+</project>

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-uk/src/main/java/org/jclouds/rackspace/clouddatabases/uk/CloudDatabasesUKProviderMetadata.java
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-uk/src/main/java/org/jclouds/rackspace/clouddatabases/uk/CloudDatabasesUKProviderMetadata.java b/providers/rackspace-clouddatabases-uk/src/main/java/org/jclouds/rackspace/clouddatabases/uk/CloudDatabasesUKProviderMetadata.java
new file mode 100644
index 0000000..f6cfaa0
--- /dev/null
+++ b/providers/rackspace-clouddatabases-uk/src/main/java/org/jclouds/rackspace/clouddatabases/uk/CloudDatabasesUKProviderMetadata.java
@@ -0,0 +1,112 @@
+/*
+ * 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.rackspace.clouddatabases.uk;
+
+import static org.jclouds.location.reference.LocationConstants.ISO3166_CODES;
+import static org.jclouds.location.reference.LocationConstants.PROPERTY_ZONE;
+import static org.jclouds.location.reference.LocationConstants.PROPERTY_ZONES;
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.ZoneModule;
+import org.jclouds.openstack.trove.v1.TroveApiMetadata;
+import org.jclouds.openstack.trove.v1.config.TroveHttpApiModule;
+import org.jclouds.openstack.trove.v1.config.TroveParserModule;
+import org.jclouds.providers.ProviderMetadata;
+import org.jclouds.providers.internal.BaseProviderMetadata;
+import org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityAuthenticationApiModule;
+import org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityAuthenticationModule;
+import org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityCredentialTypes;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+
+/**
+ * Implementation of {@link org.jclouds.types.ProviderMetadata} for Rackspace Cloud Databases.
+ * 
+ * @author Zack Shoylev
+ */
+public class CloudDatabasesUKProviderMetadata extends BaseProviderMetadata {
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   @Override
+   public Builder toBuilder() {
+      return builder().fromProviderMetadata(this);
+   }
+
+   public CloudDatabasesUKProviderMetadata() {
+      super(builder());
+   }
+
+   public CloudDatabasesUKProviderMetadata(Builder builder) {
+      super(builder);
+   }
+
+   public static Properties defaultProperties() {
+      Properties properties = new Properties();
+      properties.setProperty(CREDENTIAL_TYPE, CloudIdentityCredentialTypes.API_KEY_CREDENTIALS);
+      properties.setProperty(SERVICE_TYPE, "rax:database"); 
+      properties.setProperty(PROPERTY_ZONES, "LON");
+      properties.setProperty(PROPERTY_ZONE + ".LON." + ISO3166_CODES, "GB-SLG");
+      return properties;
+   }
+   
+   public static class Builder extends BaseProviderMetadata.Builder {
+
+      protected Builder(){
+         id("rackspace-clouddatabases-uk")
+         .name("Rackspace Clouddatabases UK")
+         .apiMetadata(new TroveApiMetadata().toBuilder()
+                  .identityName("${userName}")
+                  .credentialName("${apiKey}")
+                  .defaultEndpoint("https://lon.identity.api.rackspacecloud.com/v2.0")
+                  .endpointName("identity service url ending in /v2.0/")
+                  .documentation(URI.create("http://docs.rackspace.com/cbs/api/v1.0/cbs-devguide/content/overview.html"))
+                  .defaultModules(ImmutableSet.<Class<? extends Module>>builder()
+                                              .add(CloudIdentityAuthenticationApiModule.class)
+                                              .add(CloudIdentityAuthenticationModule.class)
+                                              .add(ZoneModule.class)
+                                              .add(TroveParserModule.class)
+                                              .add(TroveHttpApiModule.class).build())
+                  .build())
+         .homepage(URI.create("http://www.rackspace.com/cloud/public/databases/"))
+         .console(URI.create("https://mycloud.rackspace.com"))
+         .linkedServices("rackspace-cloudservers-uk", "cloudfiles-uk")
+         .iso3166Codes("GB-SLG")
+         .endpoint("https://lon.identity.api.rackspacecloud.com/v2.0")
+         .defaultProperties(CloudDatabasesUKProviderMetadata.defaultProperties());
+      }
+
+      @Override
+      public CloudDatabasesUKProviderMetadata build() {
+         return new CloudDatabasesUKProviderMetadata(this);
+      }
+
+      @Override
+      public Builder fromProviderMetadata(ProviderMetadata in) {
+         super.fromProviderMetadata(in);
+         return this;
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-uk/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-uk/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata b/providers/rackspace-clouddatabases-uk/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
new file mode 100644
index 0000000..a6a3c9a
--- /dev/null
+++ b/providers/rackspace-clouddatabases-uk/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
@@ -0,0 +1 @@
+org.jclouds.rackspace.clouddatabases.uk.CloudDatabasesUKProviderMetadata

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/CloudDatabasesUKProviderMetadataExpectTest.java
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/CloudDatabasesUKProviderMetadataExpectTest.java b/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/CloudDatabasesUKProviderMetadataExpectTest.java
new file mode 100644
index 0000000..d0f7143
--- /dev/null
+++ b/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/CloudDatabasesUKProviderMetadataExpectTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.rackspace.clouddatabases.uk;
+
+import static org.testng.Assert.assertEquals;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.trove.v1.TroveApi;
+import org.jclouds.openstack.trove.v1.internal.BaseTroveApiExpectTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * This test ensures that the wiring in {@link CloudDatabasesUKProviderMetadata} is correct.
+ * 
+ * @author Zack Shoylev
+ */
+@Test(groups = "unit", testName = "CloudDatabasesUKProviderMetadataExpectTest")
+public class CloudDatabasesUKProviderMetadataExpectTest extends BaseTroveApiExpectTest {
+
+   public CloudDatabasesUKProviderMetadataExpectTest() {
+      this.provider = "rackspace-clouddatabases-uk";
+      this.identity = "myUsername";
+      this.credential = "myApiKey";
+   }
+
+   public void testCanGetConfiguredZones() {
+      
+      HttpRequest authenticate = HttpRequest.builder().method("POST")
+            .endpoint("https://lon.identity.api.rackspacecloud.com/v2.0/tokens")
+            .addHeader("Accept", "application/json")
+            .payload(payloadFromStringWithContentType(
+                     "{\"auth\":{\"RAX-KSKEY:apiKeyCredentials\":{\"username\":\"myUsername\",\"apiKey\":\"myApiKey\"}}}"
+                     , "application/json")).build();
+      
+
+      HttpResponse authenticationResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResourceWithContentType("/access_rax_uk.json", "application/json"))
+            .build();
+
+      TroveApi whenNovaRegionExists = requestSendsResponse(authenticate, authenticationResponse);
+
+      assertEquals(whenNovaRegionExists.getConfiguredZones(), ImmutableSet.of("LON"));
+
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/CloudDatabasesUKProviderTest.java
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/CloudDatabasesUKProviderTest.java b/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/CloudDatabasesUKProviderTest.java
new file mode 100644
index 0000000..a4bb2c9
--- /dev/null
+++ b/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/CloudDatabasesUKProviderTest.java
@@ -0,0 +1,32 @@
+/*
+ * 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.rackspace.clouddatabases.uk;
+
+import org.jclouds.openstack.trove.v1.TroveApiMetadata;
+import org.jclouds.providers.internal.BaseProviderMetadataTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Zack Shoylev
+ */
+@Test(groups = "unit", testName = "CloudDatabasesUKProviderTest")
+public class CloudDatabasesUKProviderTest extends BaseProviderMetadataTest {
+
+   public CloudDatabasesUKProviderTest() {
+      super(new CloudDatabasesUKProviderMetadata(), new TroveApiMetadata());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/features/CloudDatabasesUKDatabaseApiLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/features/CloudDatabasesUKDatabaseApiLiveTest.java b/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/features/CloudDatabasesUKDatabaseApiLiveTest.java
new file mode 100644
index 0000000..294e021
--- /dev/null
+++ b/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/features/CloudDatabasesUKDatabaseApiLiveTest.java
@@ -0,0 +1,30 @@
+/*
+ * 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.rackspace.clouddatabases.uk.features;
+
+import org.jclouds.openstack.trove.v1.features.DatabaseApiLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Zack Shoylev
+ */
+@Test(groups = "live", testName = "CloudDatabasesUKDatabaseApiLiveTest")
+public class CloudDatabasesUKDatabaseApiLiveTest extends DatabaseApiLiveTest {
+   public CloudDatabasesUKDatabaseApiLiveTest() {
+      provider = "rackspace-clouddatabases-uk";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/features/CloudDatabasesUKFlavorApiLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/features/CloudDatabasesUKFlavorApiLiveTest.java b/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/features/CloudDatabasesUKFlavorApiLiveTest.java
new file mode 100644
index 0000000..75d0f4f
--- /dev/null
+++ b/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/features/CloudDatabasesUKFlavorApiLiveTest.java
@@ -0,0 +1,30 @@
+/*
+ * 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.rackspace.clouddatabases.uk.features;
+
+import org.jclouds.openstack.trove.v1.features.FlavorApiLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Zack Shoylev
+ */
+@Test(groups = "live", testName = "CloudDatabasesUKFlavorApiLiveTest")
+public class CloudDatabasesUKFlavorApiLiveTest extends FlavorApiLiveTest {
+   public CloudDatabasesUKFlavorApiLiveTest() {
+      provider = "rackspace-clouddatabases-uk";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/features/CloudDatabasesUKInstanceApiLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/features/CloudDatabasesUKInstanceApiLiveTest.java b/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/features/CloudDatabasesUKInstanceApiLiveTest.java
new file mode 100644
index 0000000..7419e18
--- /dev/null
+++ b/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/features/CloudDatabasesUKInstanceApiLiveTest.java
@@ -0,0 +1,30 @@
+/*
+ * 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.rackspace.clouddatabases.uk.features;
+
+import org.jclouds.openstack.trove.v1.features.InstanceApiLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Zack Shoylev
+ */
+@Test(groups = "live", testName = "CloudDatabasesUKInstanceApiLiveTest")
+public class CloudDatabasesUKInstanceApiLiveTest extends InstanceApiLiveTest {
+   public CloudDatabasesUKInstanceApiLiveTest() {
+      provider = "rackspace-clouddatabases-uk";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/features/CloudDatabasesUKUserApiLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/features/CloudDatabasesUKUserApiLiveTest.java b/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/features/CloudDatabasesUKUserApiLiveTest.java
new file mode 100644
index 0000000..afde455
--- /dev/null
+++ b/providers/rackspace-clouddatabases-uk/src/test/java/org/jclouds/rackspace/clouddatabases/uk/features/CloudDatabasesUKUserApiLiveTest.java
@@ -0,0 +1,30 @@
+/*
+ * 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.rackspace.clouddatabases.uk.features;
+
+import org.jclouds.openstack.trove.v1.features.UserApiLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Zack Shoylev
+ */
+@Test(groups = "live", testName = "CloudDatabasesUKUserApiLiveTest")
+public class CloudDatabasesUKUserApiLiveTest extends UserApiLiveTest {
+   public CloudDatabasesUKUserApiLiveTest() {
+      provider = "rackspace-clouddatabases-uk";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-uk/src/test/resources/access_rax_uk.json
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-uk/src/test/resources/access_rax_uk.json b/providers/rackspace-clouddatabases-uk/src/test/resources/access_rax_uk.json
new file mode 100644
index 0000000..3a94f6c
--- /dev/null
+++ b/providers/rackspace-clouddatabases-uk/src/test/resources/access_rax_uk.json
@@ -0,0 +1,129 @@
+{
+    "access": {
+        "token": {
+            "id": "bdd18214-e266-4ad3-b985-d9bfb22c8da8",
+            "expires": "2012-10-01T02:11:16.000+01:00",
+            "tenant": {
+                "id": "10001786",
+                "name": "10001786"
+            }
+        },
+        "serviceCatalog": [
+            {
+                "endpoints": [
+                    {
+                        "region": "LON",
+                        "tenantId": "MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953",
+                        "publicURL": "https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953",
+                        "internalURL": "https://snet-storage101.lon3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"
+                    }
+                ],
+                "name": "cloudFiles",
+                "type": "object-store"
+            },
+            {
+                "endpoints": [
+                    {
+                        "region": "LON",
+                        "tenantId": "MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953",
+                        "publicURL": "https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"
+                    }
+                ],
+                "name": "cloudFilesCDN",
+                "type": "rax:object-cdn"
+            },
+            {
+                "endpoints": [
+                    {
+                        "tenantId": "10001786",
+                        "publicURL": "https://lon.servers.api.rackspacecloud.com/v1.0/10001786",
+                        "versionInfo": "https://lon.servers.api.rackspacecloud.com/v1.0",
+                        "versionList": "https://lon.servers.api.rackspacecloud.com/",
+                        "versionId": "1.0"
+                    }
+                ],
+                "name": "cloudServers",
+                "type": "compute"
+            },
+            {
+                "endpoints": [
+                    {
+                        "tenantId": "10001786",
+                        "publicURL": "https://lon.dns.api.rackspacecloud.com/v1.0/10001786"
+                    }
+                ],
+                "name": "cloudDNS",
+                "type": "rax:dns"
+            },
+            {
+                "endpoints": [
+                    {
+                        "region": "LON",
+                        "tenantId": "10001786",
+                        "publicURL": "https://lon.loadbalancers.api.rackspacecloud.com/v1.0/10001786"
+                    }
+                ],
+                "name": "cloudLoadBalancers",
+                "type": "rax:load-balancer"
+            },
+            {
+                "endpoints": [
+                    {
+                        "tenantId": "10001786",
+                        "publicURL": "https://monitoring.api.rackspacecloud.com/v1.0/10001786"
+                    }
+                ],
+                "name": "cloudMonitoring",
+                "type": "rax:monitor"
+            },
+            {
+                "endpoints": [
+                    {
+                        "region": "LON",
+                        "tenantId": "10001786",
+                        "publicURL": "https://lon.databases.api.rackspacecloud.com/v1.0/10001786"
+                    }
+                ],
+                "name": "cloudDatabases",
+                "type": "rax:database"
+            },
+            {
+                "endpoints": [
+                    {
+                        "region": "LON",
+                        "tenantId": "10001786",
+                        "publicURL": "https://lon.servers.api.rackspacecloud.com/v2/10001786",
+                        "versionInfo": "https://lon.servers.api.rackspacecloud.com/v2",
+                        "versionList": "https://lon.servers.api.rackspacecloud.com/",
+                        "versionId": "2"
+                    }
+                ],
+                "name": "cloudServersOpenStack",
+                "type": "compute"
+            },
+            {
+                "endpoints": [
+                    {
+                        "publicURL": "https://lon.blockstorage.api.rackspacecloud.com/v1/10001786",
+                        "tenantId": "10001786",
+                        "region": "LON"
+                    }
+                ],
+                "name": "cloudBlockStorage",
+                "type": "volume"
+            }
+        ],
+        "user": {
+            "id": "378",
+            "roles": [
+                {
+                    "id": "3",
+                    "description": "User Admin Role.",
+                    "name": "identity:user-admin"
+                }
+            ],
+            "name": "jclouds",
+            "RAX-AUTH:defaultRegion": ""
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-uk/src/test/resources/logback.xml
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-uk/src/test/resources/logback.xml b/providers/rackspace-clouddatabases-uk/src/test/resources/logback.xml
new file mode 100644
index 0000000..6559c23
--- /dev/null
+++ b/providers/rackspace-clouddatabases-uk/src/test/resources/logback.xml
@@ -0,0 +1,69 @@
+<?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="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="BLOBSTOREFILE" class="ch.qos.logback.core.FileAppender">
+        <file>target/test-data/jclouds-blobstore.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="WIREFILE" />
+    </logger>
+
+    <logger name="jclouds.headers">
+        <level value="DEBUG" />
+        <appender-ref ref="WIREFILE" />
+    </logger>
+
+    <logger name="jclouds.blobstore">
+        <level value="DEBUG" />
+        <appender-ref ref="BLOBSTOREFILE" />
+    </logger>
+
+</configuration>

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-us/README.md
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-us/README.md b/providers/rackspace-clouddatabases-us/README.md
new file mode 100644
index 0000000..b3eabc1
--- /dev/null
+++ b/providers/rackspace-clouddatabases-us/README.md
@@ -0,0 +1,7 @@
+Rackspace Cloud Databases US
+============================
+
+The Rackspace deployment of OpenStack Trove, the Database as a Service.
+
+Production ready?
+Yes

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-us/pom.xml
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-us/pom.xml b/providers/rackspace-clouddatabases-us/pom.xml
new file mode 100644
index 0000000..5363572
--- /dev/null
+++ b/providers/rackspace-clouddatabases-us/pom.xml
@@ -0,0 +1,148 @@
+<?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/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.jclouds</groupId>
+    <artifactId>jclouds-project</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+    <relativePath>../../project/pom.xml</relativePath>
+  </parent>
+  <groupId>org.apache.jclouds.provider</groupId>
+  <artifactId>rackspace-clouddatabases-us</artifactId>
+  <name>jclouds Rackspace Cloud Databases US provider</name>
+  <description>OpenStack Trove implementation targeted to Rackspace Cloud Databases US</description>
+  <packaging>bundle</packaging>
+
+  <properties>
+    <test.rackspace-clouddatabases-us.endpoint>https://identity.api.rackspacecloud.com/v2.0/</test.rackspace-clouddatabases-us.endpoint>
+    <test.rackspace-clouddatabases-us.api-version>1</test.rackspace-clouddatabases-us.api-version>
+    <test.rackspace-clouddatabases-us.build-version />
+    <test.rackspace-clouddatabases-us.identity>${test.rackspace-us.identity}</test.rackspace-clouddatabases-us.identity>
+    <test.rackspace-clouddatabases-us.credential>${test.rackspace-us.credential}</test.rackspace-clouddatabases-us.credential>
+    <test.rackspace-clouddatabases-us.template />
+    <jclouds.osgi.export>org.jclouds.rackspace.clouddatabases.us*;version="${project.version}"</jclouds.osgi.export>
+    <jclouds.osgi.import>
+      org.jclouds.compute.internal;version="${project.version}",
+      org.jclouds.rest.internal;version="${project.version}",
+      org.jclouds*;version="${project.version}",
+      *
+    </jclouds.osgi.import>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.jclouds</groupId>
+      <artifactId>jclouds-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.labs</groupId>
+      <artifactId>openstack-trove</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.api</groupId>
+      <artifactId>openstack-keystone</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.api</groupId>
+      <artifactId>rackspace-cloudidentity</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds</groupId>
+      <artifactId>jclouds-core</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.labs</groupId>
+      <artifactId>openstack-trove</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.api</groupId>
+      <artifactId>openstack-keystone</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.api</groupId>
+      <artifactId>rackspace-cloudidentity</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.driver</groupId>
+      <artifactId>jclouds-slf4j</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <profiles>
+    <profile>
+      <id>live</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>integration</id>
+                <phase>integration-test</phase>
+                <goals>
+                  <goal>test</goal>
+                </goals>
+                <configuration>
+                  <forkCount>5</forkCount>
+                  <reuseForks>true</reuseForks>
+                  <parallel>classes</parallel>
+                  <systemPropertyVariables>
+                    <test.rackspace-clouddatabases-us.endpoint>${test.rackspace-clouddatabases-us.endpoint}</test.rackspace-clouddatabases-us.endpoint>
+                    <test.rackspace-clouddatabases-us.api-version>${test.rackspace-clouddatabases-us.api-version}</test.rackspace-clouddatabases-us.api-version>
+                    <test.rackspace-clouddatabases-us.build-version>${test.rackspace-clouddatabases-us.build-version}</test.rackspace-clouddatabases-us.build-version>
+                    <test.rackspace-clouddatabases-us.identity>${test.rackspace-clouddatabases-us.identity}</test.rackspace-clouddatabases-us.identity>
+                    <test.rackspace-clouddatabases-us.credential>${test.rackspace-clouddatabases-us.credential}</test.rackspace-clouddatabases-us.credential>
+                    <test.rackspace-clouddatabases-us.template>${test.rackspace-clouddatabases-us.template}</test.rackspace-clouddatabases-us.template>
+                  </systemPropertyVariables>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
+</project>

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-us/src/main/java/org/jclouds/rackspace/clouddatabases/us/CloudDatabasesUSProviderMetadata.java
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-us/src/main/java/org/jclouds/rackspace/clouddatabases/us/CloudDatabasesUSProviderMetadata.java b/providers/rackspace-clouddatabases-us/src/main/java/org/jclouds/rackspace/clouddatabases/us/CloudDatabasesUSProviderMetadata.java
new file mode 100644
index 0000000..fc024ed
--- /dev/null
+++ b/providers/rackspace-clouddatabases-us/src/main/java/org/jclouds/rackspace/clouddatabases/us/CloudDatabasesUSProviderMetadata.java
@@ -0,0 +1,116 @@
+/*
+ * 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.rackspace.clouddatabases.us;
+
+import static org.jclouds.location.reference.LocationConstants.ISO3166_CODES;
+import static org.jclouds.location.reference.LocationConstants.PROPERTY_ZONE;
+import static org.jclouds.location.reference.LocationConstants.PROPERTY_ZONES;
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.openstack.trove.v1.TroveApiMetadata;
+import org.jclouds.openstack.trove.v1.config.TroveParserModule;
+import org.jclouds.openstack.trove.v1.config.TroveHttpApiModule;
+import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.ZoneModule;
+import org.jclouds.providers.ProviderMetadata;
+import org.jclouds.providers.internal.BaseProviderMetadata;
+import org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityAuthenticationModule;
+import org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityCredentialTypes;
+import org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityAuthenticationApiModule;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+
+/**
+ * Implementation of {@link org.jclouds.types.ProviderMetadata} for Rackspace Cloud Databases.
+ * 
+ * @author Zack Shoylev
+ */
+public class CloudDatabasesUSProviderMetadata extends BaseProviderMetadata {
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   @Override
+   public Builder toBuilder() {
+      return builder().fromProviderMetadata(this);
+   }
+
+   public CloudDatabasesUSProviderMetadata() {
+      super(builder());
+   }
+
+   public CloudDatabasesUSProviderMetadata(Builder builder) {
+      super(builder);
+   }
+
+   public static Properties defaultProperties() {
+      Properties properties = new Properties();
+      properties.setProperty(CREDENTIAL_TYPE, CloudIdentityCredentialTypes.API_KEY_CREDENTIALS);
+      properties.setProperty(SERVICE_TYPE, "rax:database"); 
+      properties.setProperty(PROPERTY_ZONES, "ORD,DFW,IAD,SYD,HKG");
+      properties.setProperty(PROPERTY_ZONE + ".ORD." + ISO3166_CODES, "US-IL");
+      properties.setProperty(PROPERTY_ZONE + ".DFW." + ISO3166_CODES, "US-TX");
+      properties.setProperty(PROPERTY_ZONE + ".IAD." + ISO3166_CODES, "US-VA");
+      properties.setProperty(PROPERTY_ZONE + ".SYD." + ISO3166_CODES, "AU-NSW");
+      properties.setProperty(PROPERTY_ZONE + ".HKG." + ISO3166_CODES, "HK");
+      return properties;
+   }
+   
+   public static class Builder extends BaseProviderMetadata.Builder {
+
+      protected Builder(){
+         id("rackspace-clouddatabases-us")
+         .name("Rackspace Clouddatabases US")
+         .apiMetadata(new TroveApiMetadata().toBuilder()
+                  .identityName("${userName}")
+                  .credentialName("${apiKey}")
+                  .defaultEndpoint("https://identity.api.rackspacecloud.com/v2.0/")
+                  .endpointName("identity service url ending in /v2.0/")
+                  .documentation(URI.create("http://docs.rackspace.com/cbs/api/v1.0/cbs-devguide/content/overview.html"))
+                  .defaultModules(ImmutableSet.<Class<? extends Module>>builder()
+                                              .add(CloudIdentityAuthenticationApiModule.class)
+                                              .add(CloudIdentityAuthenticationModule.class)
+                                              .add(ZoneModule.class)
+                                              .add(TroveParserModule.class)
+                                              .add(TroveHttpApiModule.class).build())
+                  .build())
+         .homepage(URI.create("http://www.rackspace.com/cloud/public/databases/"))
+         .console(URI.create("https://mycloud.rackspace.com"))
+         .linkedServices("rackspace-cloudservers-us", "cloudfiles-us")
+         .iso3166Codes("US-IL", "US-TX")
+         .endpoint("https://identity.api.rackspacecloud.com/v2.0/")
+         .defaultProperties(CloudDatabasesUSProviderMetadata.defaultProperties());
+      }
+
+      @Override
+      public CloudDatabasesUSProviderMetadata build() {
+         return new CloudDatabasesUSProviderMetadata(this);
+      }
+
+      @Override
+      public Builder fromProviderMetadata(ProviderMetadata in) {
+         super.fromProviderMetadata(in);
+         return this;
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-us/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-us/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata b/providers/rackspace-clouddatabases-us/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
new file mode 100644
index 0000000..607e501
--- /dev/null
+++ b/providers/rackspace-clouddatabases-us/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
@@ -0,0 +1 @@
+org.jclouds.rackspace.clouddatabases.us.CloudDatabasesUSProviderMetadata

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/CloudDatabasesUSProviderMetadataExpectTest.java
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/CloudDatabasesUSProviderMetadataExpectTest.java b/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/CloudDatabasesUSProviderMetadataExpectTest.java
new file mode 100644
index 0000000..ac49b61
--- /dev/null
+++ b/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/CloudDatabasesUSProviderMetadataExpectTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.rackspace.clouddatabases.us;
+
+import static org.testng.Assert.assertEquals;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.trove.v1.TroveApi;
+import org.jclouds.openstack.trove.v1.internal.BaseTroveApiExpectTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * This test ensures that the wiring in {@link CloudDatabasesUSProviderMetadata} is correct.
+ * 
+ * @author Zack Shoylev
+ */
+@Test(groups = "unit", testName = "CloudDatabasesUSProviderMetadataExpectTest")
+public class CloudDatabasesUSProviderMetadataExpectTest extends BaseTroveApiExpectTest {
+
+   public CloudDatabasesUSProviderMetadataExpectTest() {
+      this.provider = "rackspace-clouddatabases-us";
+      this.identity = "myUsername";
+      this.credential = "myApiKey";
+   }
+
+   public void testCanGetConfiguredZones() {
+      
+      HttpRequest authenticate = HttpRequest.builder().method("POST")
+            .endpoint("https://identity.api.rackspacecloud.com/v2.0/tokens")
+            .addHeader("Accept", "application/json")
+            .payload(payloadFromStringWithContentType(
+                     "{\"auth\":{\"RAX-KSKEY:apiKeyCredentials\":{\"username\":\"myUsername\",\"apiKey\":\"myApiKey\"}}}"
+                     , "application/json")).build();
+      
+
+      HttpResponse authenticationResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResourceWithContentType("/access_rax_us.json", "application/json"))
+            .build();
+
+      TroveApi whenRegionExists = requestSendsResponse(authenticate, authenticationResponse);
+
+      assertEquals(whenRegionExists.getConfiguredZones(), ImmutableSet.of("ORD", "DFW", "SYD"));
+
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/CloudDatabasesUSProviderTest.java
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/CloudDatabasesUSProviderTest.java b/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/CloudDatabasesUSProviderTest.java
new file mode 100644
index 0000000..e6dbbed
--- /dev/null
+++ b/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/CloudDatabasesUSProviderTest.java
@@ -0,0 +1,32 @@
+/*
+ * 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.rackspace.clouddatabases.us;
+
+import org.jclouds.openstack.trove.v1.TroveApiMetadata;
+import org.jclouds.providers.internal.BaseProviderMetadataTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Zack Shoylev
+ */
+@Test(groups = "unit", testName = "CloudDatabasesUSProviderTest")
+public class CloudDatabasesUSProviderTest extends BaseProviderMetadataTest {
+
+   public CloudDatabasesUSProviderTest() {
+      super(new CloudDatabasesUSProviderMetadata(), new TroveApiMetadata());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/features/CloudDatabasesUSDatabaseApiLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/features/CloudDatabasesUSDatabaseApiLiveTest.java b/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/features/CloudDatabasesUSDatabaseApiLiveTest.java
new file mode 100644
index 0000000..982c88a
--- /dev/null
+++ b/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/features/CloudDatabasesUSDatabaseApiLiveTest.java
@@ -0,0 +1,30 @@
+/*
+ * 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.rackspace.clouddatabases.us.features;
+
+import org.jclouds.openstack.trove.v1.features.DatabaseApiLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Zack Shoylev
+ */
+@Test(groups = "live", testName = "CloudDatabasesUSDatabaseApiLiveTest")
+public class CloudDatabasesUSDatabaseApiLiveTest extends DatabaseApiLiveTest {
+   public CloudDatabasesUSDatabaseApiLiveTest() {
+      provider = "rackspace-clouddatabases-us";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/features/CloudDatabasesUSFlavorApiLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/features/CloudDatabasesUSFlavorApiLiveTest.java b/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/features/CloudDatabasesUSFlavorApiLiveTest.java
new file mode 100644
index 0000000..369d9c2
--- /dev/null
+++ b/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/features/CloudDatabasesUSFlavorApiLiveTest.java
@@ -0,0 +1,30 @@
+/*
+ * 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.rackspace.clouddatabases.us.features;
+
+import org.jclouds.openstack.trove.v1.features.FlavorApiLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Zack Shoylev
+ */
+@Test(groups = "live", testName = "CloudDatabasesUSFlavorApiLiveTest")
+public class CloudDatabasesUSFlavorApiLiveTest extends FlavorApiLiveTest {
+   public CloudDatabasesUSFlavorApiLiveTest() {
+      provider = "rackspace-clouddatabases-us";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/features/CloudDatabasesUSInstanceApiLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/features/CloudDatabasesUSInstanceApiLiveTest.java b/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/features/CloudDatabasesUSInstanceApiLiveTest.java
new file mode 100644
index 0000000..2498e04
--- /dev/null
+++ b/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/features/CloudDatabasesUSInstanceApiLiveTest.java
@@ -0,0 +1,30 @@
+/*
+ * 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.rackspace.clouddatabases.us.features;
+
+import org.jclouds.openstack.trove.v1.features.InstanceApiLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Zack Shoylev
+ */
+@Test(groups = "live", testName = "CloudDatabasesUSInstanceApiLiveTest")
+public class CloudDatabasesUSInstanceApiLiveTest extends InstanceApiLiveTest {
+   public CloudDatabasesUSInstanceApiLiveTest() {
+      provider = "rackspace-clouddatabases-us";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/features/CloudDatabasesUSUserApiLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/features/CloudDatabasesUSUserApiLiveTest.java b/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/features/CloudDatabasesUSUserApiLiveTest.java
new file mode 100644
index 0000000..95daa4d
--- /dev/null
+++ b/providers/rackspace-clouddatabases-us/src/test/java/org/jclouds/rackspace/clouddatabases/us/features/CloudDatabasesUSUserApiLiveTest.java
@@ -0,0 +1,30 @@
+/*
+ * 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.rackspace.clouddatabases.us.features;
+
+import org.jclouds.openstack.trove.v1.features.UserApiLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Zack Shoylev
+ */
+@Test(groups = "live", testName = "CloudDatabasesUSUserApiLiveTest")
+public class CloudDatabasesUSUserApiLiveTest extends UserApiLiveTest {
+   public CloudDatabasesUSUserApiLiveTest() {
+      provider = "rackspace-clouddatabases-us";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/providers/rackspace-clouddatabases-us/src/test/resources/logback.xml
----------------------------------------------------------------------
diff --git a/providers/rackspace-clouddatabases-us/src/test/resources/logback.xml b/providers/rackspace-clouddatabases-us/src/test/resources/logback.xml
new file mode 100644
index 0000000..6559c23
--- /dev/null
+++ b/providers/rackspace-clouddatabases-us/src/test/resources/logback.xml
@@ -0,0 +1,69 @@
+<?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="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="BLOBSTOREFILE" class="ch.qos.logback.core.FileAppender">
+        <file>target/test-data/jclouds-blobstore.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="WIREFILE" />
+    </logger>
+
+    <logger name="jclouds.headers">
+        <level value="DEBUG" />
+        <appender-ref ref="WIREFILE" />
+    </logger>
+
+    <logger name="jclouds.blobstore">
+        <level value="DEBUG" />
+        <appender-ref ref="BLOBSTOREFILE" />
+    </logger>
+
+</configuration>


[4/4] git commit: Moving trove to jclouds from jclouds-openstack-labs https://issues.apache.org/jira/browse/JCLOUDS-102

Posted by za...@apache.org.
Moving trove to jclouds from jclouds-openstack-labs https://issues.apache.org/jira/browse/JCLOUDS-102


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/6de84cb0
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/6de84cb0
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/6de84cb0

Branch: refs/heads/master
Commit: 6de84cb003755732d810fe95364479442612f352
Parents: cec0981
Author: Zack Shoylev <za...@rackspace.com>
Authored: Thu Dec 12 13:30:39 2013 -0600
Committer: Zack Shoylev <za...@rackspace.com>
Committed: Thu Dec 12 17:13:38 2013 -0600

----------------------------------------------------------------------
 apis/openstack-trove/README.md                  |   7 +
 apis/openstack-trove/pom.xml                    | 124 ++++++
 .../jclouds/openstack/trove/v1/TroveApi.java    |  87 ++++
 .../openstack/trove/v1/TroveApiMetadata.java    |  95 ++++
 .../v1/binders/BindCreateDatabaseToJson.java    |  58 +++
 .../v1/binders/BindCreateInstanceToJson.java    |  50 +++
 .../trove/v1/binders/BindCreateUserToJson.java  |  69 +++
 .../trove/v1/binders/BindGrantUserToJson.java   |  61 +++
 .../trove/v1/config/TroveHttpApiModule.java     |  82 ++++
 .../trove/v1/config/TroveParserModule.java      |  32 ++
 .../openstack/trove/v1/domain/Flavor.java       | 169 ++++++++
 .../openstack/trove/v1/domain/Instance.java     | 301 +++++++++++++
 .../jclouds/openstack/trove/v1/domain/User.java | 234 ++++++++++
 .../trove/v1/features/DatabaseApi.java          | 109 +++++
 .../openstack/trove/v1/features/FlavorApi.java  |  92 ++++
 .../trove/v1/features/InstanceApi.java          | 162 +++++++
 .../openstack/trove/v1/features/UserApi.java    | 237 ++++++++++
 .../trove/v1/filters/EncodeDotsForUserGet.java  |  49 +++
 .../v1/functions/ParseDatabaseListForUser.java  |  54 +++
 .../ParsePasswordFromRootedInstance.java        |  49 +++
 .../trove/v1/handlers/TroveErrorHandler.java    |  69 +++
 .../openstack/trove/v1/internal/Volume.java     |  32 ++
 .../trove/v1/predicates/InstancePredicates.java | 144 ++++++
 .../openstack/trove/v1/utils/TroveUtils.java    | 107 +++++
 .../services/org.jclouds.apis.ApiMetadata       |  18 +
 .../openstack/trove/v1/domain/FlavorTest.java   |  55 +++
 .../openstack/trove/v1/domain/InstanceTest.java |  53 +++
 .../openstack/trove/v1/domain/UserTest.java     |  47 ++
 .../v1/features/DatabaseApiExpectTest.java      | 161 +++++++
 .../trove/v1/features/DatabaseApiLiveTest.java  | 114 +++++
 .../trove/v1/features/FlavorApiExpectTest.java  | 111 +++++
 .../trove/v1/features/FlavorApiLiveTest.java    |  87 ++++
 .../v1/features/InstanceApiExpectTest.java      | 217 ++++++++++
 .../trove/v1/features/InstanceApiLiveTest.java  | 137 ++++++
 .../trove/v1/features/UserApiExpectTest.java    | 433 +++++++++++++++++++
 .../trove/v1/features/UserApiLiveTest.java      | 207 +++++++++
 .../v1/internal/BaseTroveApiExpectTest.java     |  27 ++
 .../trove/v1/internal/BaseTroveApiLiveTest.java |  43 ++
 .../trove/v1/internal/BaseTroveExpectTest.java  |  78 ++++
 .../trove/v1/parse/ParseFlavorListTest.java     | 108 +++++
 .../trove/v1/parse/ParseInstanceListTest.java   |  95 ++++
 .../trove/v1/parse/ParseUserListTest.java       |  66 +++
 .../trove/v1/utils/TroveUtilsExpectTest.java    |  67 +++
 .../src/test/resources/access_rax_us.json       | 168 +++++++
 .../test/resources/database_create_request.json |   9 +
 .../database_create_simple_request.json         |   7 +
 .../src/test/resources/database_list.json       |  19 +
 .../src/test/resources/flavor_get.json          |  17 +
 .../src/test/resources/flavor_list.json         |  94 ++++
 .../src/test/resources/instance_create.json     |  35 ++
 .../test/resources/instance_create_request.json |   9 +
 .../src/test/resources/instance_get.json        |  37 ++
 .../resources/instance_get_bad_instance.json    |  37 ++
 .../src/test/resources/instance_is_rooted.json  |   3 +
 .../resources/instance_is_rooted_false.json     |   3 +
 .../src/test/resources/instance_list.json       |  66 +++
 .../src/test/resources/instance_root.json       |   6 +
 .../src/test/resources/logback-test.xml         |  69 +++
 .../src/test/resources/logback.xml              |  69 +++
 .../src/test/resources/trove_user_list.json     |  35 ++
 .../src/test/resources/user_create_request.json |  35 ++
 .../resources/user_create_simple_request.json   |  13 +
 .../user_create_with_host_simple_request.json   |  14 +
 .../src/test/resources/user_get.json            |  14 +
 .../src/test/resources/user_get_withhost.json   |  14 +
 .../src/test/resources/user_grant_request.json  |  10 +
 .../resources/user_grant_simple_request.json    |   7 +
 .../src/test/resources/user_list_access.json    |  10 +
 .../test/resources/user_password_request.json   |  12 +
 apis/pom.xml                                    |   1 +
 providers/pom.xml                               |   2 +
 providers/rackspace-clouddatabases-uk/README.md |   7 +
 providers/rackspace-clouddatabases-uk/pom.xml   | 148 +++++++
 .../uk/CloudDatabasesUKProviderMetadata.java    | 112 +++++
 .../org.jclouds.providers.ProviderMetadata      |   1 +
 ...udDatabasesUKProviderMetadataExpectTest.java |  64 +++
 .../uk/CloudDatabasesUKProviderTest.java        |  32 ++
 .../CloudDatabasesUKDatabaseApiLiveTest.java    |  30 ++
 .../CloudDatabasesUKFlavorApiLiveTest.java      |  30 ++
 .../CloudDatabasesUKInstanceApiLiveTest.java    |  30 ++
 .../CloudDatabasesUKUserApiLiveTest.java        |  30 ++
 .../src/test/resources/access_rax_uk.json       | 129 ++++++
 .../src/test/resources/logback.xml              |  69 +++
 providers/rackspace-clouddatabases-us/README.md |   7 +
 providers/rackspace-clouddatabases-us/pom.xml   | 148 +++++++
 .../us/CloudDatabasesUSProviderMetadata.java    | 116 +++++
 .../org.jclouds.providers.ProviderMetadata      |   1 +
 ...udDatabasesUSProviderMetadataExpectTest.java |  64 +++
 .../us/CloudDatabasesUSProviderTest.java        |  32 ++
 .../CloudDatabasesUSDatabaseApiLiveTest.java    |  30 ++
 .../CloudDatabasesUSFlavorApiLiveTest.java      |  30 ++
 .../CloudDatabasesUSInstanceApiLiveTest.java    |  30 ++
 .../CloudDatabasesUSUserApiLiveTest.java        |  30 ++
 .../src/test/resources/logback.xml              |  69 +++
 94 files changed, 6651 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/README.md
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/README.md b/apis/openstack-trove/README.md
new file mode 100644
index 0000000..ef8c513
--- /dev/null
+++ b/apis/openstack-trove/README.md
@@ -0,0 +1,7 @@
+OpenStack Trove
+===============
+
+Trove is Database as a Service for OpenStack.
+
+Production ready?
+Yes

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/pom.xml
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/pom.xml b/apis/openstack-trove/pom.xml
new file mode 100644
index 0000000..e63b4fa
--- /dev/null
+++ b/apis/openstack-trove/pom.xml
@@ -0,0 +1,124 @@
+<?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/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.jclouds</groupId>
+    <artifactId>jclouds-project</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+    <relativePath>../../project/pom.xml</relativePath>
+  </parent>
+  <groupId>org.apache.jclouds.api</groupId>
+  <artifactId>openstack-trove</artifactId>
+  <name>jclouds openstack-trove api</name>
+  <description>jclouds components to access an implementation of OpenStack Trove</description>
+  <packaging>bundle</packaging>
+
+  <properties>
+    <test.openstack-trove.endpoint>http://localhost:5000/v2.0/</test.openstack-trove.endpoint>
+    <test.openstack-trove.api-version>1.0</test.openstack-trove.api-version>
+    <test.openstack-trove.build-version />
+    <test.openstack-trove.identity>FIXME_IDENTITY</test.openstack-trove.identity>
+    <test.openstack-trove.credential>FIXME_CREDENTIALS</test.openstack-trove.credential>
+    <test.jclouds.keystone.credential-type>passwordCredentials</test.jclouds.keystone.credential-type>
+
+    <jclouds.osgi.export>org.jclouds.openstack.trove.v1_0*;version="${project.version}"</jclouds.osgi.export>
+    <jclouds.osgi.import>
+      org.jclouds.rest.internal;version="${jclouds.version}",
+      org.jclouds.labs*;version="${project.version}",
+      org.jclouds*;version="${jclouds.version}",
+      *
+    </jclouds.osgi.import>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.jclouds.api</groupId>
+      <artifactId>openstack-keystone</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds</groupId>
+      <artifactId>jclouds-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds</groupId>
+      <artifactId>jclouds-core</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.api</groupId>
+      <artifactId>openstack-keystone</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.driver</groupId>
+      <artifactId>jclouds-slf4j</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <profiles>
+    <profile>
+      <id>live</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>integration</id>
+                <phase>integration-test</phase>
+                <goals>
+                  <goal>test</goal>
+                </goals>
+                <configuration>
+                  <forkCount>5</forkCount>
+                  <reuseForks>true</reuseForks>
+                  <parallel>classes</parallel>
+                  <systemPropertyVariables>
+                    <test.openstack-trove.endpoint>${test.openstack-trove.endpoint}</test.openstack-trove.endpoint>
+                    <test.openstack-trove.api-version>${test.openstack-trove.api-version}</test.openstack-trove.api-version>
+                    <test.openstack-trove.build-version>${test.openstack-trove.build-version}</test.openstack-trove.build-version>
+                    <test.openstack-trove.identity>${test.openstack-trove.identity}</test.openstack-trove.identity>
+                    <test.openstack-trove.credential>${test.openstack-trove.credential}</test.openstack-trove.credential>
+                    <test.jclouds.keystone.credential-type>${test.jclouds.keystone.credential-type}</test.jclouds.keystone.credential-type>
+                  </systemPropertyVariables>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
+</project>

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/TroveApi.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/TroveApi.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/TroveApi.java
new file mode 100644
index 0000000..798ebd3
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/TroveApi.java
@@ -0,0 +1,87 @@
+/*
+ * 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.openstack.trove.v1;
+
+import java.io.Closeable;
+import java.util.Set;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.location.Zone;
+import org.jclouds.location.functions.ZoneToEndpoint;
+import org.jclouds.openstack.keystone.v2_0.domain.Tenant;
+import org.jclouds.openstack.trove.v1.features.DatabaseApi;
+import org.jclouds.openstack.trove.v1.features.FlavorApi;
+import org.jclouds.openstack.trove.v1.features.InstanceApi;
+import org.jclouds.openstack.trove.v1.features.UserApi;
+import org.jclouds.rest.annotations.Delegate;
+import org.jclouds.rest.annotations.EndpointParam;
+import com.google.common.base.Optional;
+import com.google.inject.Provides;
+
+/**
+ * Provides access to Trove.
+ *  
+ * @see <a href="http://api.openstack.org/">API Doc</a>
+ * @author Zack Shoylev
+ */
+public interface TroveApi extends Closeable{
+   /**
+    * Provides a set of all zones available.
+    * 
+    * @return the Zone codes configured
+    */
+   @Provides
+   @Zone
+   Set<String> getConfiguredZones();
+
+   /**
+    * Provides access to Flavor features.
+    */
+   @Delegate
+   FlavorApi getFlavorApiForZone(
+         @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
+
+   /**
+    * Provides access to Instance features.
+    */
+   @Delegate
+   InstanceApi getInstanceApiForZone(
+         @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
+
+   /**
+    * Provides access to User features.
+    */
+   @Delegate
+   @Path("/instances/{instanceId}")
+   UserApi getUserApiForZoneAndInstance(@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone,
+         @PathParam("instanceId") String instanceId);
+
+   /**
+    * Provides access to Database features.
+    */
+   @Delegate
+   @Path("/instances/{instanceId}")
+   DatabaseApi getDatabaseApiForZoneAndInstance(@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone,
+         @PathParam("instanceId") String instanceId);
+
+   /**
+    * Provides the Tenant.
+    */
+   @Provides 
+   Optional<Tenant> getCurrentTenantId();
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/TroveApiMetadata.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/TroveApiMetadata.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/TroveApiMetadata.java
new file mode 100644
index 0000000..947e0bc
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/TroveApiMetadata.java
@@ -0,0 +1,95 @@
+/*
+ * 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.openstack.trove.v1;
+
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.openstack.keystone.v2_0.config.AuthenticationApiModule;
+import org.jclouds.openstack.keystone.v2_0.config.CredentialTypes;
+import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule;
+import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.ZoneModule;
+import org.jclouds.openstack.trove.v1.config.TroveHttpApiModule;
+import org.jclouds.openstack.trove.v1.config.TroveParserModule;
+import org.jclouds.openstack.v2_0.ServiceType;
+import org.jclouds.rest.internal.BaseHttpApiMetadata;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+
+/**
+ * Implementation of {@link ApiMetadata} for Trove API
+ * 
+ * @author Zack Shoylev
+ */
+public class TroveApiMetadata extends BaseHttpApiMetadata<TroveApi> {
+      
+   @Override
+   public Builder toBuilder() {
+      return new Builder().fromApiMetadata(this);
+   }
+
+   public TroveApiMetadata() {
+      this(new Builder());
+   }
+
+   protected TroveApiMetadata(Builder builder) {
+      super(builder);
+   }
+
+   public static Properties defaultProperties() {
+      Properties properties = BaseHttpApiMetadata.defaultProperties();
+      properties.setProperty(SERVICE_TYPE, ServiceType.DATABASE_SERVICE);      
+      properties.setProperty(CREDENTIAL_TYPE, CredentialTypes.PASSWORD_CREDENTIALS);
+      return properties;
+   }
+
+   public static class Builder extends BaseHttpApiMetadata.Builder<TroveApi, Builder> {
+
+      protected Builder() {         
+          id("openstack-trove")
+         .name("OpenStack Trove API")
+         .identityName("${tenantName}:${userName} or ${userName}, if your keystone supports a default tenant")
+         .credentialName("${password}")
+         .endpointName("Keystone base URL ending in /v2.0/")
+         .documentation(URI.create("http://api.openstack.org/"))
+         .version("1.0")
+         .defaultEndpoint("http://localhost:5000/v2.0/")
+         .defaultProperties(TroveApiMetadata.defaultProperties())
+         .defaultModules(ImmutableSet.<Class<? extends Module>>builder()
+                                     .add(AuthenticationApiModule.class)
+                                     .add(KeystoneAuthenticationModule.class)
+                                     .add(ZoneModule.class)
+                                     .add(TroveParserModule.class)
+                                     .add(TroveHttpApiModule.class)
+                                     .build());
+      }
+      
+      @Override
+      public TroveApiMetadata build() {
+         return new TroveApiMetadata(this);
+      }
+
+      @Override
+      protected Builder self() {
+         return this;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/binders/BindCreateDatabaseToJson.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/binders/BindCreateDatabaseToJson.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/binders/BindCreateDatabaseToJson.java
new file mode 100644
index 0000000..50bbdfc
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/binders/BindCreateDatabaseToJson.java
@@ -0,0 +1,58 @@
+/*
+ * 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.openstack.trove.v1.binders;
+
+import java.util.Map;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.MapBinder;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Inject;
+
+/**
+ * @author Zack Shoylev
+ */
+public class BindCreateDatabaseToJson implements MapBinder {
+
+   @Inject
+   private BindToJsonPayload jsonBinder;
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
+      Builder<String, String> databaseBuilder = ImmutableMap.builder();
+
+      databaseBuilder.put("name", (String) postParams.get("database"));
+
+      if (postParams.get("character_set") != null) {
+         databaseBuilder.put("character_set", (String) postParams.get("character_set"));
+      }
+      if (postParams.get("collate") != null) {
+         databaseBuilder.put("collate", (String) postParams.get("collate"));
+      }
+
+      return jsonBinder.bindToRequest(request, ImmutableMap.of("databases", ImmutableSet.of(databaseBuilder.build())));
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
+      throw new IllegalStateException("Create database is a POST operation");
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/binders/BindCreateInstanceToJson.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/binders/BindCreateInstanceToJson.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/binders/BindCreateInstanceToJson.java
new file mode 100644
index 0000000..6ee0e22
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/binders/BindCreateInstanceToJson.java
@@ -0,0 +1,50 @@
+/*
+ * 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.openstack.trove.v1.binders;
+
+import java.util.Map;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.openstack.trove.v1.internal.Volume;
+import org.jclouds.rest.MapBinder;
+import org.jclouds.rest.binders.BindToJsonPayload;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.google.inject.Inject;
+
+/**
+ * @author Zack Shoylev
+ */
+public class BindCreateInstanceToJson implements MapBinder {
+    
+    @Inject
+    private BindToJsonPayload jsonBinder;
+    
+    @Override    
+    public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
+       Map<String, Object> databaseInstance = Maps.newHashMap();
+       databaseInstance.put("flavorRef", postParams.get("flavorRef"));
+       databaseInstance.put("volume", new Volume((Integer) postParams.get("size")));
+       if (postParams.get("name") != null)
+           databaseInstance.put("name", postParams.get("name"));
+       return jsonBinder.bindToRequest(request, ImmutableMap.of("instance", databaseInstance));
+    }
+
+    @Override
+    public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
+       throw new IllegalStateException("CreateInstance is a POST operation");
+    }    
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/binders/BindCreateUserToJson.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/binders/BindCreateUserToJson.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/binders/BindCreateUserToJson.java
new file mode 100644
index 0000000..2e17677
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/binders/BindCreateUserToJson.java
@@ -0,0 +1,69 @@
+/*
+ * 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.openstack.trove.v1.binders;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.openstack.trove.v1.domain.User;
+import org.jclouds.openstack.trove.v1.domain.User.Builder;
+import org.jclouds.rest.MapBinder;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+
+/**
+ * @author Zack Shoylev
+ */
+public class BindCreateUserToJson implements MapBinder {
+
+   @Inject
+   private BindToJsonPayload jsonBinder;
+
+   @SuppressWarnings("unchecked")
+   @Override    
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
+      Set<User> users = Sets.newHashSet();
+      if( postParams.get("name") != null ) {
+         Set<String> databases = Sets.newHashSet();
+         if(postParams.get("databaseName")!=null)
+            databases.add((String) postParams.get("databaseName"));
+         
+         Builder builder = User.builder();
+         builder.name((String) postParams.get("name"))
+                .password((String) postParams.get("password"));
+         
+         builder.host((String) postParams.get("host"));
+         builder.databases(databases);
+         
+         User user = builder.build();
+         users.add(user);
+      }
+      else if( postParams.get("users") != null ) {
+         users = (Set<User>) postParams.get("users");
+      }
+      return jsonBinder.bindToRequest(request, ImmutableMap.of("users", users));
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
+      throw new IllegalStateException("Create user is a POST operation");
+   }    
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/binders/BindGrantUserToJson.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/binders/BindGrantUserToJson.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/binders/BindGrantUserToJson.java
new file mode 100644
index 0000000..cb8fe7c
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/binders/BindGrantUserToJson.java
@@ -0,0 +1,61 @@
+/*
+ * 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.openstack.trove.v1.binders;
+
+import java.util.List;
+import java.util.Map;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.MapBinder;
+import org.jclouds.rest.binders.BindToJsonPayload;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.inject.Inject;
+
+/**
+ * @author Zack Shoylev
+ */
+public class BindGrantUserToJson implements MapBinder {
+    
+    @Inject
+    private BindToJsonPayload jsonBinder;
+    
+    @SuppressWarnings("unchecked")
+    @Override    
+    public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
+       List<String> databases = Lists.newArrayList();
+       if( postParams.get("databaseName")!=null ) {
+          databases.add((String)postParams.get("databaseName"));
+       }
+       else if( postParams.get("databases")!=null ) {
+          databases = (List<String>) postParams.get("databases");
+       }
+       
+       List<Map<String,String>> databaseList = Lists.newArrayList();       
+       for(String databaseName : databases) {
+           Map<String,String> singleDatabase = Maps.newHashMap();
+           singleDatabase.put("name", databaseName);
+           databaseList.add(singleDatabase);
+       }
+       return jsonBinder.bindToRequest(request, ImmutableMap.of("databases", databaseList));
+    }
+
+    @Override
+    public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
+       throw new IllegalStateException("Grant user is a PUT operation");
+    }    
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/config/TroveHttpApiModule.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/config/TroveHttpApiModule.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/config/TroveHttpApiModule.java
new file mode 100644
index 0000000..2ff5940
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/config/TroveHttpApiModule.java
@@ -0,0 +1,82 @@
+/*
+ * 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.openstack.trove.v1.config;
+
+import java.net.URI;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.annotation.ClientError;
+import org.jclouds.http.annotation.Redirection;
+import org.jclouds.http.annotation.ServerError;
+import org.jclouds.json.config.GsonModule.DateAdapter;
+import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
+import org.jclouds.openstack.keystone.v2_0.domain.Access;
+import org.jclouds.openstack.keystone.v2_0.domain.Tenant;
+import org.jclouds.openstack.trove.v1.TroveApi;
+import org.jclouds.openstack.trove.v1.handlers.TroveErrorHandler;
+import org.jclouds.rest.ConfiguresHttpApi;
+import org.jclouds.rest.config.HttpApiModule;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Multimap;
+import com.google.inject.Provides;
+
+/**
+ * Configures the Trove connection.
+ * 
+ * @author Zack Shoylev
+ */
+@ConfiguresHttpApi
+public class TroveHttpApiModule extends HttpApiModule<TroveApi> {
+   
+   @Override
+   protected void configure() {
+      bind(DateAdapter.class).to(Iso8601DateAdapter.class);
+      super.configure();
+   }
+   
+   @Provides
+   @Singleton
+   public Multimap<URI, URI> aliases() {
+      return ImmutableMultimap.<URI, URI>builder().build();
+   }
+
+   @Override
+   protected void bindErrorHandlers() {
+      bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(TroveErrorHandler.class);
+      bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(TroveErrorHandler.class);
+      bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(TroveErrorHandler.class);
+   }
+   
+   @Provides
+   Supplier<Optional<Tenant>> supplyTenant(Supplier<Access> access) {
+      return Suppliers.compose(GetTenant.INSTANCE, access);
+   }
+   
+   private static enum GetTenant implements Function<Access, Optional<Tenant>> {
+      INSTANCE;
+      public Optional<Tenant> apply(Access in){
+         return in.getToken().getTenant();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/config/TroveParserModule.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/config/TroveParserModule.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/config/TroveParserModule.java
new file mode 100644
index 0000000..2406c13
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/config/TroveParserModule.java
@@ -0,0 +1,32 @@
+/*
+ * 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.openstack.trove.v1.config;
+
+import org.jclouds.json.config.GsonModule;
+import org.jclouds.json.config.GsonModule.DateAdapter;
+
+import com.google.inject.AbstractModule;
+
+/**
+ * @author Everett Toews
+ */
+public class TroveParserModule extends AbstractModule {
+   @Override
+   protected void configure() {
+      bind(DateAdapter.class).to(GsonModule.Iso8601DateAdapter.class);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/domain/Flavor.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/domain/Flavor.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/domain/Flavor.java
new file mode 100644
index 0000000..ff68f83
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/domain/Flavor.java
@@ -0,0 +1,169 @@
+/*
+ * 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.openstack.trove.v1.domain;
+
+import java.beans.ConstructorProperties;
+import java.util.List;
+
+import org.jclouds.openstack.v2_0.domain.Link;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * An Openstack Trove Flavor.
+ * 
+ * @author Zack Shoylev
+ */
+public class Flavor implements Comparable<Flavor>{
+
+   private final int id;
+   private final Optional<String> name;
+   private final int ram;
+   private final List<Link> links;
+
+   @ConstructorProperties({
+      "id", "name", "ram", "links"
+   })
+   protected Flavor(int id, String name, int ram, List<Link> links) {
+      this.id = id;
+      this.name = Optional.fromNullable(name);
+      this.ram = ram;
+      this.links = links;
+   }
+
+   /**
+    * @return the id of this flavor.
+    */
+   public int getId() {
+      return this.id;
+   }
+
+   /**
+    * @return the name of this flavor.
+    */
+   public String getName() {
+      return this.name.orNull();
+   }
+
+   /**
+    * @return the RAM amount for this flavor.
+    */
+   public int getRam() {
+      return this.ram;
+   }
+
+   /**
+    * @return the flavor links for this flavor. These are used during database instance creation.
+    */
+   public List<Link> getLinks() {
+      return this.links;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      Flavor that = Flavor.class.cast(obj);
+      return Objects.equal(this.id, that.id);
+   }
+
+   protected ToStringHelper string() {
+      return Objects.toStringHelper(this)
+            .add("id", id).add("name", name).add("ram", ram);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   @Override
+   public int compareTo(Flavor that) {
+      if (that == null)
+         return 1;
+      if (this == that)
+         return 0;
+      return this.getId() > that.getId() ? +1 : this.getId() < this.getId() ? -1 : 0;
+   }
+
+   public static Builder builder() { 
+      return new Builder();
+   }
+
+   public Builder toBuilder() { 
+      return new Builder().fromFlavor(this);
+   }    
+
+   public static class Builder {
+      protected int id;
+      protected String name;
+      protected int ram;
+      protected List<Link> links;
+
+      /** 
+       * @see Flavor#getId()
+       */
+      public Builder id(int id) {
+         this.id = id;
+         return this;
+      }
+
+      /** 
+       * @see Flavor#getName()
+       */
+      public Builder name(String name) {
+         this.name = name;
+         return this;
+      }
+
+      /** 
+       * @see Flavor#getRam()
+       */
+      public Builder ram(int ram) {
+         this.ram = ram;
+         return this;
+      }
+
+      /** 
+       * @see Flavor#getLinks()
+       */
+      public Builder links(List<Link> links) {
+         this.links = ImmutableList.copyOf(links);
+         return this;
+      }
+
+      public Flavor build() {
+         return new Flavor(id, name, ram, links);
+      }
+
+      public Builder fromFlavor(Flavor in) {
+         return this
+               .id(in.getId())
+               .name(in.getName())
+               .ram(in.getRam())
+               .links(in.getLinks());
+      }
+   }    
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/domain/Instance.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/domain/Instance.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/domain/Instance.java
new file mode 100644
index 0000000..2002fde
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/domain/Instance.java
@@ -0,0 +1,301 @@
+/*
+ * 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.openstack.trove.v1.domain;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import java.beans.ConstructorProperties;
+import java.util.List;
+
+import org.jclouds.openstack.trove.v1.internal.Volume;
+import org.jclouds.openstack.v2_0.domain.Link;
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * An Openstack Trove Database Instance.
+ * 
+ * @author Zack Shoylev
+ */
+public class Instance implements Comparable<Instance>{
+
+   private final String id;
+   private final String name;
+   private final Flavor flavor;
+   private final Volume volume;
+   private final Status status;
+   private final List<Link> links;
+   private final String hostname;
+
+   @ConstructorProperties({
+      "id", "name", "flavor", "volume", "status", "links", "hostname"
+   })
+   protected Instance(String id, String name, Flavor flavor, Volume volume, Status status, List<Link> links, String hostname) {
+      this.id = checkNotNull(id, "id required");
+      this.name = checkNotNull(name, "name required");
+      this.flavor = checkNotNull(flavor, "flavor required");
+      this.volume =  checkNotNull(volume, "volume required");
+      checkArgument(volume.getSize() > 0, "Size must be greater than 0");
+      this.status = checkNotNull(status, "status required");
+      this.links = checkNotNull(links, "links required");
+      this.hostname = hostname; // Hostname is sometimes null. See Instance#getHostname() for details
+   }
+
+   /**
+    * @return the id of this instance.
+    */
+   public String getId() {
+      return this.id;
+   }
+
+   /**
+    * @return the name of this instance.
+    * @see Instance.Builder#name(String)
+    */
+   public String getName() {
+      return this.name;
+   }
+
+   /**
+    * @return the flavor of this instance.
+    * @see Instance.Builder#flavor(Flavor)
+    */
+   public Flavor getFlavor() {
+      return this.flavor;
+   }
+
+   /**
+    * @return the volume size for this instance in gigabytes (GB).
+    * @see Instance.Builder#size(int)
+    */
+   public int getSize() {
+      return this.volume.getSize();
+   }
+
+   /**
+    * @return the status for this instance.
+    * @see Instance.Builder#status(Instance.Status)
+    */
+   public Status getStatus() {
+      return this.status;
+   }
+
+   /**
+    * @return the Links for this instance.
+    * @see Instance.Builder#links(ImmutableList)
+    */
+   public List<Link> getLinks() {
+      return this.links;
+   }
+   
+   /**
+    * @return the hostname of this instance. The hostname is null unless this Instance was obtained with {@link InstanceApi#get(String)}.
+    * @see Instance.Builder#hostname(String)
+    */
+   public String getHostname() {
+      return this.hostname;
+   }
+
+   /**
+    * Lists possible Instance status.
+    * @author zack-shoylev
+    *
+    */
+   public enum Status {
+      /**
+       * The database instance is being provisioned.
+       * */
+      BUILD, 
+      /**
+       * The database instance is rebooting.
+       */
+      REBOOT,
+      /**
+       * The database instance is online and available to take requests.
+       * */
+      ACTIVE,
+      /**
+       * The database instance is unresponsive at the moment.
+       */
+      BLOCKED,
+      /**
+       * The database instance is being resized at the moment.
+       */
+      RESIZE,
+      /**
+       * The database instance is terminating services. Also, SHUTDOWN is returned if for any reason the instance is shut down but not the actual server.
+       */
+      SHUTDOWN, 
+      /**
+       * Unrecognized status response.
+       */
+      UNRECOGNIZED;
+
+      public String value() {
+         return name();
+      }
+
+      @Override
+      public String toString() {
+         return value();
+      }
+
+      public static Status fromValue(String status) {
+         try {
+            return valueOf(checkNotNull(status, "type"));
+         } catch (IllegalArgumentException e) {
+            return UNRECOGNIZED;
+         }
+      }
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id, name, volume.getSize(), flavor, status, links, hostname);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      Instance that = Instance.class.cast(obj);
+      return Objects.equal(this.id, that.id);
+   }
+
+   protected ToStringHelper string() {
+      return Objects.toStringHelper(this)
+            .add("id", id).add("name", name).add("flavor", flavor).add("volume size", volume.getSize()).add("links", links).add("hostname", hostname);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   public static Builder builder() { 
+      return new Builder();
+   }
+
+   public Builder toBuilder() { 
+      return new Builder().fromInstance(this);
+   }
+
+   public static class Builder {
+      protected String id;
+      protected String name;
+      protected int size;
+      protected Flavor flavor;
+      protected Status status;
+      protected ImmutableList<Link> links;
+      protected String hostname;
+
+      /** 
+       * @param id The id of this instance.
+       * @return The builder object.
+       * @see Instance#getId()
+       */
+      public Builder id(String id) {
+         this.id = id;
+         return this;
+      }
+
+      /** 
+       * @param name The name of this instance.
+       * @return The builder object.
+       * @see Instance#getName()
+       */
+      public Builder name(String name) {
+         this.name = name;
+         return this;
+      }
+
+      /** 
+       * @param size Specifies the volume size in gigabytes (GB).
+       * @return The builder object.
+       * @see Instance#getSize()
+       */
+      public Builder size(int size) {
+         this.size = size;
+         return this;
+      }
+
+      /** 
+       * @param flavor The Flavor of this instance as specified in the response from the List Flavors API call.
+       * @return The builder object.
+       * @see Instance#getFlavor()
+       */
+      public Builder flavor(Flavor flavor) {
+         this.flavor = flavor;
+         return this;
+      }
+
+      /** 
+       * @param status The status of this instance.
+       * @return The builder object.
+       * @see Instance#getStatus()
+       */
+      public Builder status(Status status) {
+         this.status = status;
+         return this;
+      }
+
+      /** 
+       * @param links The links to this instance.
+       * @return The builder object.
+       * @see Instance#getLinks()
+       */
+      public Builder links(ImmutableList<Link> links) {
+         this.links = links;
+         return this;
+      }
+      
+      /** 
+       * @param name The hostname of this instance.
+       * @return The builder object.
+       * @see Instance#getHostname()
+       */
+      public Builder hostname(String hostname) {
+         this.hostname = hostname;
+         return this;
+      }
+
+      /**
+       * 
+       * @return A new Instance object.
+       */
+      public Instance build() {
+         return new Instance(id, name, flavor, new Volume(size), status, links, hostname);
+      }
+
+      public Builder fromInstance(Instance in) {
+         return this
+               .id(in.getId())
+               .name(in.getName())
+               .flavor(in.getFlavor())
+               .size(in.getSize())
+               .status(in.getStatus())
+               .links(links)
+               .hostname(hostname);
+      }        
+   }
+
+   @Override
+   public int compareTo(Instance that) {
+      return this.getId().compareTo(that.getId());
+   }   
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/domain/User.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/domain/User.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/domain/User.java
new file mode 100644
index 0000000..965e6e0
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/domain/User.java
@@ -0,0 +1,234 @@
+/*
+ * 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.openstack.trove.v1.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import java.beans.ConstructorProperties;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+/**
+ * An Openstack Trove Database User.
+ * 
+ * @author Zack Shoylev
+ */
+public class User implements Comparable<User>{
+   private final String name;
+   private final String password;
+   private final String host;
+   private final List<Map<String,String>> databases;
+
+   @ConstructorProperties({
+      "name", "password", "host", "databases"
+   })
+   protected User(String name, String password, String host, List<Map<String,String>> databases) {
+      this.name = checkNotNull(name, "name required");
+      this.password = password;
+      this.host = host;
+      // Set databases to an empty list instead of null
+      if(databases == null) {
+         this.databases = Lists.newArrayList();
+      }
+      else {
+         this.databases = databases;
+      }
+   }    
+
+   protected User(String name, String password, String host, Set<String> databases) {
+      this.name = checkNotNull(name, "name required");
+      this.password = password;
+      this.host = host;
+      // Set databases to an empty list instead of null
+      if(databases == null) {
+         this.databases = Lists.newArrayList();
+      }
+      else {
+         // Using List<Map<String,String>> as the internal representation makes it easy to serialize properly
+         // with less code; this code is to present databases as List<String> to the user.
+         List<Map<String,String>> databaseList = Lists.newArrayList();
+         for(String databaseName : databases) {
+            Map<String,String> singleDatabase = Maps.newHashMap();
+            singleDatabase.put("name", databaseName);
+            databaseList.add(singleDatabase);
+         }
+         this.databases = ImmutableList.copyOf(databaseList);
+      }
+   }   
+
+   /**
+    * @return the name of this user. The name is not a unique or even sufficient identifier in some cases.
+    * @see User#getIdentifier()
+    * @see User.Builder#name(String)
+    */
+   public String getName() {
+      return this.name;
+   }   
+   
+   /**
+    * @return the password for this user.
+    * @see User.Builder#password(String)
+    */
+   public String getPassword() {
+      return this.password;
+   }
+   
+   /**
+    * @return the host for this user.
+    * @see User.Builder#host(String)
+    */
+   public String getHost() {
+      return this.host;
+   }
+   
+   /**
+    * @return a unique identifier for this user. In most cases, this is just the name. If the user is restricted to connections from a specific host, the hostname must be appended to the user name with a "@".
+    */
+   public String getIdentifier() {
+      if(host==null || "%".equals(host))
+         return name;
+      else 
+         return name + "@" + host;
+   }
+
+   /**
+    * @return the databases for this user.
+    * @see User.Builder#databases(String)
+    */
+   public List<String> getDatabases() {
+      List<String> databaseList = Lists.newArrayList();
+      for(Map<String,String> database : this.databases) {
+         databaseList.add(database.get("name"));
+      }
+      return ImmutableList.copyOf(databaseList);
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(name, password, databases);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      User that = User.class.cast(obj);
+      return Objects.equal(this.name, that.name) && 
+            Objects.equal(this.password, that.password) &&
+            Objects.equal(this.host, that.host) &&
+            Objects.equal(this.databases, that.databases);
+   }
+
+   protected ToStringHelper string() {
+      return Objects.toStringHelper(this)
+            .add("name", name)
+            .add("password", password)
+            .add("host", host)
+            .add("databases", databases);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   public static Builder builder() { 
+      return new Builder();
+   }
+
+   public Builder toBuilder() { 
+      return new Builder().fromUser(this);
+   }
+
+   public static class Builder {
+      protected String name;
+      protected String password;
+      protected String host;
+      protected Set<String> databases;
+      
+      /** 
+       * @param name The name of this user.
+       * @return The builder object.
+       * @see User#getName()
+       */
+      public Builder name(String name) {
+         this.name = name;
+         return this;
+      }
+
+      /** 
+       * @param name The password for this user.
+       * @return The builder object.
+       * @see User#getPassword()
+       */
+      public Builder password(String password) {
+         this.password = password;
+         return this;
+      }
+      
+      /** 
+       * @param host Specifies the host from which a user is allowed to connect to the database. 
+       * Possible values are a string containing an IPv4 address or "%" to allow connecting from any host. 
+       * Refer to Section 3.11.1, “User Access Restriction by Host” in the Rackspace Cloud Databases Developer Guide for details.
+       * If host is not specified, it defaults to "%".
+       * @return The builder object.
+       * @see <a href="http://docs.rackspace.com/cdb/api/v1.0/cdb-devguide/content/user_access_restrict_by_host-dle387.html">User Access Restriction by Host</a>
+       * @see User#getHost()
+       */
+      public Builder host(String host) {
+         this.host = host;
+         return this;
+      }
+
+      /** 
+       * @param name The databases for this user.
+       * @return The builder object.
+       * @see User#getDatabases()
+       */
+      public Builder databases(Set<String> databases) {
+         this.databases = databases;
+         return this;
+      }
+
+      /**
+       * 
+       * @return A new User object.
+       */
+      public User build() {
+         return new User(name, password, host, databases);
+      }
+
+      public Builder fromUser(User in) {
+         return this
+               .name(in.getName())
+               .password(in.getPassword())
+               .host(in.getHost())
+               .databases(ImmutableSet.copyOf( in.getDatabases() ));
+      }        
+   }
+
+   @Override
+   public int compareTo(User that) {
+      return this.getName().compareTo(that.getName());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/features/DatabaseApi.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/features/DatabaseApi.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/features/DatabaseApi.java
new file mode 100644
index 0000000..cf6c869
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/features/DatabaseApi.java
@@ -0,0 +1,109 @@
+/*
+ * 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.openstack.trove.v1.features;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.Fallbacks.EmptyFluentIterableOnNotFoundOr404;
+import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.trove.v1.binders.BindCreateDatabaseToJson;
+import org.jclouds.openstack.trove.v1.functions.ParseDatabaseListForUser;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.SkipEncoding;
+
+import com.google.common.collect.FluentIterable;
+
+/**
+ * This API is for creating, listing, and deleting a Database
+ * 
+ * @see <a href="http://sourceforge.net/apps/trac/reddwarf/">api doc</a>
+ * @see <a
+ *      href="https://github.com/reddwarf-nextgen/reddwarf">api
+ *      src</a>
+ *      
+ * @author Zack Shoylev
+ */
+@SkipEncoding({'/', '='})
+@RequestFilters(AuthenticateRequest.class)
+public interface DatabaseApi {
+    
+   /**
+    * Same as create(String, null, null)
+    * @see DatabaseApi#create(String, String, String) 
+    */
+   @Named("database:create")
+   @POST
+   @Path("/databases")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(FalseOnNotFoundOr404.class)
+   @MapBinder(BindCreateDatabaseToJson.class)
+   boolean create(@PayloadParam("database") String database);
+   
+   /**
+    * This operation creates a new database within the specified instance.
+    * 
+    * @param database The name of the database to be created
+    * @param character_set Optional. Set of symbols and encodings. The default character set is utf8.
+    * @param collate Optional. Set of rules for comparing characters in a character set. The default value for collate is utf8_general_ci.
+    * @return true if successful.
+    */
+   @Named("database:create")
+   @POST
+   @Path("/databases")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(FalseOnNotFoundOr404.class)
+   @MapBinder(BindCreateDatabaseToJson.class)
+   boolean create(@PayloadParam("database") String database, @PayloadParam("character_set") String character_set, @PayloadParam("collate") String collate);
+   
+   /**
+    * This operation deletes the specified database for the specified database instance.
+    *
+    * @param databaseName The name for the specified database.
+    * @return true if successful.
+    */
+   @Named("databases:delete")
+   @DELETE
+   @Path("/databases/{name}")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(FalseOnNotFoundOr404.class)
+   boolean delete(@PathParam("name") String databaseName);
+   
+   /**
+    * This operation lists the databases for the specified database instance.
+    *
+    * @return The list of Databases.
+    */
+   @Named("database:list")
+   @GET
+   @Path("/databases")   
+   @ResponseParser(ParseDatabaseListForUser.class)
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(EmptyFluentIterableOnNotFoundOr404.class)   
+   FluentIterable<String> list();   
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/features/FlavorApi.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/features/FlavorApi.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/features/FlavorApi.java
new file mode 100644
index 0000000..7d13483
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/features/FlavorApi.java
@@ -0,0 +1,92 @@
+/*
+ * 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.openstack.trove.v1.features;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.Fallbacks.EmptyFluentIterableOnNotFoundOr404;
+import org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.trove.v1.domain.Flavor;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.annotations.SkipEncoding;
+
+import com.google.common.collect.FluentIterable;
+
+/**
+ * This API strictly for listing and retrieving Flavor. Flavors cannot be created or deleted.
+ * @see org.jclouds.openstack.trove.v1.domain.Flavor
+ * Flavor
+ * 
+ * @see <a href="http://sourceforge.net/apps/trac/reddwarf/">api doc</a>
+ * @see <a
+ *      href="https://github.com/reddwarf-nextgen/reddwarf">api
+ *      src</a>
+ *      
+ * @author Zack Shoylev
+ */
+@SkipEncoding({'/', '='})
+@RequestFilters(AuthenticateRequest.class)
+public interface FlavorApi {
+   /**
+    * Returns a summary list of Flavors.
+    *
+    * @return The list of Flavors.
+    */
+   @Named("flavor:list")
+   @GET
+   @Path("/flavors")
+   @SelectJson("flavors")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(EmptyFluentIterableOnNotFoundOr404.class)
+   FluentIterable<Flavor> list();
+   
+   /**
+    * Returns a Flavor by id.
+    *
+    * @param flavorId The id of the Flavor.
+    * @return Flavor The Flavor for the specified id.
+    */
+   @Named("flavors:get/{id}")
+   @GET
+   @Path("/flavors/{id}")
+   @SelectJson("flavor")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(NullOnNotFoundOr404.class)
+   Flavor get(@PathParam("id") int flavorId);
+   
+   /**
+    * Returns a list of Flavors by Account ID (Tenant Id).
+    *
+    * @param flavorId The id of the tenant.
+    * @return The list of Flavors for Account/Tenant Id.
+    */
+   @Named("flavors:get/{id}")
+   @GET
+   @Path("/flavors/{id}")
+   @SelectJson("flavors")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(EmptyFluentIterableOnNotFoundOr404.class)
+   FluentIterable<Flavor> list(@PathParam("id") String accountId);
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/features/InstanceApi.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/features/InstanceApi.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/features/InstanceApi.java
new file mode 100644
index 0000000..3512c65
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/features/InstanceApi.java
@@ -0,0 +1,162 @@
+/*
+ * 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.openstack.trove.v1.features;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.MediaType;
+import org.jclouds.Fallbacks.EmptyFluentIterableOnNotFoundOr404;
+import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
+import org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.trove.v1.binders.BindCreateInstanceToJson;
+import org.jclouds.openstack.trove.v1.domain.Instance;
+import org.jclouds.openstack.trove.v1.functions.ParsePasswordFromRootedInstance;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.annotations.SkipEncoding;
+import com.google.common.collect.FluentIterable;
+
+/**
+ * This API is for creating, listing, and deleting an Instance, and allows enabling a root user.
+ * @see org.jclouds.openstack.trove.v1.domain.Instance
+ * Instance
+ * 
+ * @see <a href="http://sourceforge.net/apps/trac/reddwarf/">api doc</a>
+ * @see <a
+ *      href="https://github.com/reddwarf-nextgen/reddwarf">api
+ *      src</a>
+ *      
+ * @author Zack Shoylev
+ */
+@SkipEncoding({'/', '='})
+@RequestFilters(AuthenticateRequest.class)
+public interface InstanceApi {
+    
+   /**
+    * Same as {@link #create(String, int, String)} but accept an integer Flavor ID.
+    *
+    * @param flavor The flavor ID.
+    * @param volumeSize The size in GB of the instance volume.
+    * @param name The name of the instance.
+    * @return The instance created.
+    * 
+    * @see InstanceApi#create(String, int, String)
+    */
+   @Named("instance:create")
+   @POST
+   @Path("/instances")
+   @SelectJson("instance")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @MapBinder(BindCreateInstanceToJson.class)
+   Instance create(@PayloadParam("flavorRef") int flavor, @PayloadParam("size") int volumeSize, @PayloadParam("name") String name);
+
+   /**
+    * Create a database instance by flavor type and volume size.
+    *
+    * @param flavor The flavor URL or flavor id as string.
+    * @param volumeSize The size in GB of the instance volume.
+    * @param name The name of the instance.
+    * @return The instance created.
+    */
+   @Named("instance:create")
+   @POST
+   @Path("/instances")
+   @SelectJson("instance")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @MapBinder(BindCreateInstanceToJson.class)
+   Instance create(@PayloadParam("flavorRef") String flavor, @PayloadParam("size") int volumeSize, @PayloadParam("name") String name);
+   
+   /**
+    * Deletes an Instance by id.
+    *
+    * @param instanceId The instance id.
+    * @return true if successful.
+    */
+   @Named("instances:delete/{id}")
+   @DELETE
+   @Path("/instances/{id}")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(FalseOnNotFoundOr404.class)
+   boolean delete(@PathParam("id") String instanceId);
+   
+   /**
+    * Enables root for an instance.
+    *
+    * @param instanceId The instance id.
+    * @return String The password for the root user.
+    */
+   @Named("instances/{id}/root")
+   @POST
+   @Path("/instances/{id}/root")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ResponseParser(ParsePasswordFromRootedInstance.class)
+   @Fallback(NullOnNotFoundOr404.class)
+   String enableRoot(@PathParam("id") String instanceId);
+   
+   /**
+    * Checks to see if root is enabled for an instance.
+    *
+    * @param instanceId The instance id.
+    * @throws ResourceNotFoundException
+    * @return boolean True if root is enabled.
+    */
+   @Named("instances/{id}/root")
+   @GET
+   @Path("/instances/{id}/root")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @SelectJson("rootEnabled")
+   boolean isRooted(@PathParam("id") String instanceId);
+   
+   /**
+    * Returns a summary list of Instances.
+    *
+    * @return The list of Instances.
+    */
+   @Named("instance:list")
+   @GET
+   @Path("/instances")
+   @SelectJson("instances")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(EmptyFluentIterableOnNotFoundOr404.class)
+   FluentIterable<Instance> list();
+      
+   /**
+    * Returns an Instance by id.
+    *
+    * @param instanceId The instance id.
+    * @return Instance or Null on not found.
+    */
+   @Named("instances:get/{id}")
+   @GET
+   @Path("/instances/{id}")
+   @SelectJson("instance")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(NullOnNotFoundOr404.class)
+   @Nullable
+   Instance get(@PathParam("id") String instanceId);
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/features/UserApi.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/features/UserApi.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/features/UserApi.java
new file mode 100644
index 0000000..c153358
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/features/UserApi.java
@@ -0,0 +1,237 @@
+/*
+ * 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.openstack.trove.v1.features;
+
+import java.util.List;
+import java.util.Set;
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.MediaType;
+import org.jclouds.Fallbacks.EmptyFluentIterableOnNotFoundOr404;
+import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
+import org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.trove.v1.binders.BindCreateUserToJson;
+import org.jclouds.openstack.trove.v1.binders.BindGrantUserToJson;
+import org.jclouds.openstack.trove.v1.domain.User;
+import org.jclouds.openstack.trove.v1.filters.EncodeDotsForUserGet;
+import org.jclouds.openstack.trove.v1.functions.ParseDatabaseListForUser;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.annotations.SkipEncoding;
+import com.google.common.collect.FluentIterable;
+
+/**
+ * This API is for creating, listing, and deleting a User. Also allows listing, granting, and revoking access permissions for users.
+ * @see org.jclouds.openstack.trove.v1.domain.User
+ * User
+ * 
+ * @see <a href="http://sourceforge.net/apps/trac/reddwarf/">api doc</a>
+ * @see <a
+ *      href="https://github.com/reddwarf-nextgen/reddwarf">api
+ *      src</a>
+ *      
+ * @author Zack Shoylev
+ */
+@SkipEncoding({'/', '='})
+@RequestFilters(AuthenticateRequest.class)
+public interface UserApi {
+    
+   /**
+    * Create database users.
+    * A user is granted all privileges on the specified databases.
+    * The following user name is reserved and cannot be used for creating users: root.
+    * This method can be used to create users with access restrictions by host
+    *
+    * @param users List of users to be created.
+    * @return true if successful.
+    * @see <a href="http://docs.rackspace.com/cdb/api/v1.0/cdb-devguide/content/user_access_restrict_by_host-dle387.html">User Access Restriction by Host</a>
+    */
+   @Named("user:create")
+   @POST
+   @Path("/users")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(FalseOnNotFoundOr404.class)
+   @MapBinder(BindCreateUserToJson.class)
+   boolean create(@PayloadParam("users") Set<User> users);
+   
+   /**
+    * Create a database user by name, password, and database name. Simpler overload for {@link #create(String, Set)}.
+    *
+    * @param userName Name of the user for the database.
+    * @param password User password for database access.
+    * @param databaseName Name of the database that the user can access.
+    * @return true if successful.
+    */
+   @Named("user:create")
+   @POST
+   @Path("/users")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(FalseOnNotFoundOr404.class)
+   @MapBinder(BindCreateUserToJson.class)
+   boolean create(@PayloadParam("name") String userName, @PayloadParam("password") String password, @PayloadParam("databaseName") String databaseName);
+   
+   /**
+    * Create a database user by name, password, and database name. Simpler overload for {@link #create(String, Set)}.
+    *
+    * @param userName Name of the user for the database.
+    * @param password User password for database access.
+    * @param host Specifies the host from which a user is allowed to connect to the database. Possible values are a string containing an IPv4 address or "%" to allow connecting from any host. Refer to Section 3.11.1, “User Access Restriction by Host” for details. If host is not specified, it defaults to "%".
+    * @param databaseName Name of the database that the user can access.
+    * @return true if successful.
+    */
+   @Named("user:create")
+   @POST
+   @Path("/users")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(FalseOnNotFoundOr404.class)
+   @MapBinder(BindCreateUserToJson.class)
+   boolean create(@PayloadParam("name") String userName, @PayloadParam("password") String password, @PayloadParam("host") String host, @PayloadParam("databaseName") String databaseName);
+
+   /**
+    * This operation grants access for the specified user to a database for the specified instance.
+    * The user is granted all privileges.
+    *
+    * @param userName The name of the specified user.
+    * @param databases List of the databases that the user should be granted access to.
+    * @return true if successful.
+    */
+   @Named("user:grant")
+   @PUT
+   @Path("/users/{name}/databases")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(FalseOnNotFoundOr404.class)
+   @MapBinder(BindGrantUserToJson.class)
+   boolean grant(@PathParam("name") String userName, @PayloadParam("databases") List<String> databases);
+   
+   /**
+    * This operation grants access for the specified user to a database for the specified instance. Simpler overload for {@link #create(String, Set)}.
+    * The user is granted all privileges.
+    *
+    * @param userName Name of the user for the database.
+    * @param databaseName Name of the database that the user can access.
+    * @return true if successful.
+    */
+   @Named("user:grant")
+   @PUT
+   @Path("/users/{name}/databases")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(FalseOnNotFoundOr404.class)
+   @MapBinder(BindGrantUserToJson.class)
+   boolean grant(@PathParam("name") String userName, @PayloadParam("databaseName") String databaseName);
+   
+   /**
+    * This operation grants access for the specified user to a database for the specified instance.
+    * The user is granted all privileges.
+    *
+    * @param userName Name of the user for the database.
+    * @param databaseName Name of the database that the user can access.
+    * @return true if successful.
+    */
+   @Named("user:revoke")
+   @DELETE
+   @Path("/users/{name}/databases/{databaseName}")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(FalseOnNotFoundOr404.class)
+   boolean revoke(@PathParam("name") String userName, @PathParam("databaseName") String databaseName);
+   
+   /**
+    * This operation deletes the specified user for the specified database instance.
+    *
+    * @param userName The name for the specified user.
+    * @return true if successful.
+    */
+   @Named("users:delete/{name}")
+   @DELETE
+   @Path("/users/{name}")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(FalseOnNotFoundOr404.class)
+   boolean delete(@PathParam("name") String userName);
+   
+   /**
+    * This operation lists the users in the specified database instance.
+    * This operation does not return the system users (database administrators that administer the health of the database). Also, this operation returns the "root" user only if "root" user has been enabled.
+    *
+    * @return The list of Users.
+    */
+   @Named("user:list")
+   @GET
+   @Path("/users")
+   @SelectJson("users")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(EmptyFluentIterableOnNotFoundOr404.class)
+   FluentIterable<User> list();
+   
+   /**
+    * This operation shows a list of all databases to which a user has access.
+    *
+    * @param instanceId The instance ID for the specified database instance.
+    * @param userName The name for the specified user.
+    * @return The list of Users.
+    */
+   @Named("user:getDatabaseList/{name}")
+   @GET
+   @Path("/users/{name}/databases")
+   @ResponseParser(ParseDatabaseListForUser.class)
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(EmptyFluentIterableOnNotFoundOr404.class)
+   FluentIterable<String> getDatabaseList(@PathParam("name") String userName);
+      
+   /**
+    * Returns a User by identifier.
+    *
+    * @param name The name or identifier for the specified user.
+    * @return User or Null on not found.
+    */
+   @Named("user:get/{name}")
+   @GET
+   @Path("/users/{name}")
+   @RequestFilters(EncodeDotsForUserGet.class)
+   @SelectJson("user")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(NullOnNotFoundOr404.class)
+   @Nullable
+   User get(@PathParam("name") String name);
+   
+   /**
+    * Returns a User by name and allowed host.
+    *
+    * @param name The name for the specified user.
+    * @param host The associated hostname.
+    * @return User or Null on not found.
+    */
+   @Named("user:get/{name}@{hostname}")
+   @GET
+   @Path("/users/{name}@{hostname}")
+   @RequestFilters(EncodeDotsForUserGet.class)
+   @SelectJson("user")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(NullOnNotFoundOr404.class)
+   @Nullable
+   User get(@PathParam("name") String name, @PathParam("hostname") String hostname);
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/filters/EncodeDotsForUserGet.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/filters/EncodeDotsForUserGet.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/filters/EncodeDotsForUserGet.java
new file mode 100644
index 0000000..4be330f
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/filters/EncodeDotsForUserGet.java
@@ -0,0 +1,49 @@
+/*
+ * 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.openstack.trove.v1.filters;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpRequestFilter;
+
+/**
+ * Encodes "." as %2e when getting a user with restricted hostname
+ * 
+ * @author Zack Shoylev
+ * 
+ */
+@Singleton
+public class EncodeDotsForUserGet implements HttpRequestFilter {
+   private final Pattern pattern = Pattern.compile("/[^/]*$"); // From last / to the end of the line 
+   
+   @Override
+   public HttpRequest filter(HttpRequest request) throws HttpException {
+      String endpoint = request.getEndpoint().toString();      
+      Matcher matcher = pattern.matcher(endpoint);
+      if(!matcher.find())
+         return request; // do not modify if not found. This however is not expected to happen.
+      String encodable = matcher.group();
+      String encoded = encodable.replace(".", "%2e");
+      String newEndpoint = matcher.replaceFirst(encoded);
+      return request.toBuilder().endpoint(newEndpoint).build();
+   }
+}


[3/4] Moving trove to jclouds from jclouds-openstack-labs https://issues.apache.org/jira/browse/JCLOUDS-102

Posted by za...@apache.org.
http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/functions/ParseDatabaseListForUser.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/functions/ParseDatabaseListForUser.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/functions/ParseDatabaseListForUser.java
new file mode 100644
index 0000000..e357d11
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/functions/ParseDatabaseListForUser.java
@@ -0,0 +1,54 @@
+/*
+ * 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.openstack.trove.v1.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import java.util.List;
+import java.util.Map;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseJson;
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Lists;
+import com.google.inject.Inject;
+
+/**
+ * This parses the list of databases
+ * 
+ * @author Zack Shoylev
+ */
+public class ParseDatabaseListForUser implements Function<HttpResponse, FluentIterable<String>> {
+
+   private final ParseJson<Map<String, List<Map<String, String>>>> json;
+
+   @Inject
+   ParseDatabaseListForUser(ParseJson<Map<String, List<Map<String, String>>>> json) {
+      this.json = checkNotNull(json, "json");
+   }
+
+   /**
+    * Parses the database list from the json response
+    */
+   public FluentIterable<String> apply(HttpResponse from) {
+      List<String> resultDatabases = Lists.newArrayList();
+      Map<String, List<Map<String, String>>> result = json.apply(from);
+      for(Map<String, String> database : result.get("databases")) {
+         resultDatabases.add(database.get("name"));
+      }
+      return FluentIterable.from(resultDatabases);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/functions/ParsePasswordFromRootedInstance.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/functions/ParsePasswordFromRootedInstance.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/functions/ParsePasswordFromRootedInstance.java
new file mode 100644
index 0000000..582b01f
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/functions/ParsePasswordFromRootedInstance.java
@@ -0,0 +1,49 @@
+/*
+ * 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.openstack.trove.v1.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import java.util.Map;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseJson;
+import com.google.common.base.Function;
+import com.google.inject.Inject;
+
+/**
+ * This parses the password
+ * 
+ * @author Zack Shoylev
+ */
+public class ParsePasswordFromRootedInstance implements Function<HttpResponse, String> {
+
+   private final ParseJson<Map<String, Map<String, String>>> json;
+
+   @Inject
+   ParsePasswordFromRootedInstance(ParseJson<Map<String, Map<String, String>>> json) {
+      this.json = checkNotNull(json, "json");
+   }
+
+   /**
+    * Extracts the user password from the json response
+    */
+   public String apply(HttpResponse from) {
+      Map<String, Map<String, String>> result = json.apply(from);
+      if(result.get("user") == null) 
+         return null;
+      return result.get("user").get("password");
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/handlers/TroveErrorHandler.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/handlers/TroveErrorHandler.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/handlers/TroveErrorHandler.java
new file mode 100644
index 0000000..887c541
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/handlers/TroveErrorHandler.java
@@ -0,0 +1,69 @@
+/*
+ * 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.openstack.trove.v1.handlers;
+
+import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.InsufficientResourcesException;
+import org.jclouds.rest.ResourceNotFoundException;
+
+/**
+ * This will parse and set an appropriate exception on the command object.
+ * 
+ * @author Zack Shoylev
+ * 
+ */
+@Singleton
+public class TroveErrorHandler implements HttpErrorHandler {
+
+   public void handleError(HttpCommand command, HttpResponse response) {
+      // it is important to always read fully and close streams
+      byte[] data = closeClientButKeepContentStream(response);
+      String message = data != null ? new String(data) : null;
+
+      Exception exception = message != null ? new HttpResponseException(command, response, message)
+               : new HttpResponseException(command, response);
+      message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
+               response.getStatusLine());
+      switch (response.getStatusCode()) {
+         case 400:
+            if (message.contains("quota exceeded"))
+               exception = new InsufficientResourcesException(message, exception);
+            break;
+         case 401:
+         case 403:
+            exception = new AuthorizationException(message, exception);
+            break;
+         case 404:
+            if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
+               exception = new ResourceNotFoundException(message, exception);
+            }
+            break;
+         case 413:
+            exception = new InsufficientResourcesException(message, exception);
+            break;
+      }
+      command.setException(exception);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/internal/Volume.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/internal/Volume.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/internal/Volume.java
new file mode 100644
index 0000000..74c16cf
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/internal/Volume.java
@@ -0,0 +1,32 @@
+/*
+ * 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.openstack.trove.v1.internal;
+
+public class Volume{
+   private final int size;
+   
+   public Volume(int size){
+      this.size = size;
+   }
+
+   /**
+    * @return the size
+    */
+   public int getSize() {
+      return size;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/predicates/InstancePredicates.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/predicates/InstancePredicates.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/predicates/InstancePredicates.java
new file mode 100644
index 0000000..6149eff
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/predicates/InstancePredicates.java
@@ -0,0 +1,144 @@
+/*
+ * 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.openstack.trove.v1.predicates;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.jclouds.util.Predicates2.retry;
+import org.jclouds.openstack.trove.v1.domain.Instance;
+import org.jclouds.openstack.trove.v1.domain.Instance.Status;
+import org.jclouds.openstack.trove.v1.features.InstanceApi;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Tests to see if instance has reached status. This class is most useful when paired with a RetryablePredicate as
+ * in the code below. This class can be used to block execution until the Instance status has reached a desired state.
+ * This is useful when your Instance needs to be 100% ready before you can continue with execution.
+ *
+ * <pre>
+ * {@code
+ * Instance instance = instanceApi.create(100);
+ * 
+ * RetryablePredicate<String> awaitAvailable = RetryablePredicate.create(
+ *    InstancePredicates.available(instanceApi), 600, 10, 10, TimeUnit.SECONDS);
+ * 
+ * if (!awaitAvailable.apply(instance.getId())) {
+ *    throw new TimeoutException("Timeout on instance: " + instance); 
+ * }    
+ * }
+ * </pre>
+ * 
+ * You can also use the static convenience methods as follows.
+ * 
+ * <pre>
+ * {@code
+ * Instance instance = instanceApi.create(100);
+ * 
+ * if (!InstancePredicates.awaitAvailable(instanceApi).apply(instance.getId())) {
+ *    throw new TimeoutException("Timeout on instance: " + instance);     
+ * }
+ * }
+ * </pre>
+ * 
+ * @author Zack Shoylev
+ */
+public class InstancePredicates {
+   /**
+    * Wait until an Instance is Available.
+    * 
+    * @param instanceApi The InstanceApi in the zone where your Instance resides.
+    * @return RetryablePredicate That will check the status every 5 seconds for a maxiumum of 10 minutes.
+    */
+   public static Predicate<Instance> awaitAvailable(InstanceApi instanceApi) {
+      StatusUpdatedPredicate statusPredicate = new StatusUpdatedPredicate(instanceApi, Instance.Status.ACTIVE);
+      return retry(statusPredicate, 600, 5, 5, SECONDS);
+   }
+
+   /**
+    * Wait until an Instance no longer exists.
+    * 
+    * @param instanceApi The InstanceApi in the zone where your Instance resides.
+    * @return RetryablePredicate That will check whether the Instance exists.
+    * every 5 seconds for a maxiumum of 10 minutes.
+    */
+   public static Predicate<Instance> awaitDeleted(InstanceApi instanceApi) {
+      DeletedPredicate deletedPredicate = new DeletedPredicate(instanceApi);
+      return retry(deletedPredicate, 600, 5, 5, SECONDS);
+   }
+   
+   /**
+    * Wait until instance is in the status specified.
+    * 
+    * @param instanceApi The InstanceApi in the zone where your Instance resides.
+    * @param status Wait until instance in in this status.
+    * @param maxWaitInSec Maximum time to wait.
+    * @param periodInSec Interval between retries.
+    * @return RetryablePredicate That will check whether the Instance exists.
+    */
+   public static Predicate<Instance> awaitStatus(
+         InstanceApi instanceApi, Instance.Status status, long maxWaitInSec, long periodInSec) {
+      StatusUpdatedPredicate statusPredicate = new StatusUpdatedPredicate(instanceApi, status);
+      return retry(statusPredicate, maxWaitInSec, periodInSec, periodInSec, SECONDS);
+   }
+   
+   private static class StatusUpdatedPredicate implements Predicate<Instance> {
+      private InstanceApi instanceApi;
+      private Status status;
+
+      public StatusUpdatedPredicate(InstanceApi instanceApi, Instance.Status status) {
+         this.instanceApi = checkNotNull(instanceApi, "instanceApi must be defined");
+         this.status = checkNotNull(status, "status must be defined");
+      }
+
+      /**
+       * @return boolean Return true when the instance reaches status, false otherwise.
+       */
+      @Override
+      public boolean apply(Instance instance) {
+         checkNotNull(instance, "instance must be defined");
+         
+         if (status.equals(instance.getStatus())) {
+            return true;
+         }
+         else {
+            Instance instanceUpdated = instanceApi.get(instance.getId());
+            checkNotNull(instanceUpdated, "Instance %s not found.", instance.getId());
+            
+            return status.equals(instanceUpdated.getStatus());
+         }
+      }
+   }
+
+   private static class DeletedPredicate implements Predicate<Instance> {
+      private InstanceApi instanceApi;
+
+      public DeletedPredicate(InstanceApi instanceApi) {
+         this.instanceApi = checkNotNull(instanceApi, "instanceApi must be defined");
+      }
+
+      /**
+       * @return boolean Return true when the snapshot is deleted, false otherwise.
+       */
+      @Override
+      public boolean apply(Instance instance) {
+         checkNotNull(instance, "instance must be defined");
+
+         return instanceApi.get(instance.getId()) == null;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/utils/TroveUtils.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/utils/TroveUtils.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/utils/TroveUtils.java
new file mode 100644
index 0000000..dbc17f2
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/utils/TroveUtils.java
@@ -0,0 +1,107 @@
+/*
+ * 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.openstack.trove.v1.utils;
+
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.Resource;
+
+import org.jclouds.openstack.trove.v1.TroveApi;
+import org.jclouds.openstack.trove.v1.domain.Instance;
+import org.jclouds.openstack.trove.v1.features.InstanceApi;
+import org.jclouds.openstack.trove.v1.predicates.InstancePredicates;
+import org.jclouds.logging.Logger;
+
+import com.google.common.util.concurrent.Uninterruptibles;
+
+/**
+ * @author Zack Shoylev
+ * 
+ * Helper methods for dealing with instances that get created with errors.
+ */
+public class TroveUtils {
+   private final TroveApi api;
+   @Resource
+   protected Logger logger = Logger.NULL;
+
+   public TroveUtils(TroveApi api) {
+      this.api = api;
+   }
+
+   /**
+    * Create an ACTIVE operational instance.
+    * 
+    * @see InstanceApi#create(String, int, String)
+    * 
+    * @param zone
+    *           The instance zone or region.
+    * @param name
+    *           Instance name.
+    * @param flavorId
+    *           Id of the flavor to be used when creating the instance.
+    * @param size
+    *           Size of the instance.
+    * @return Instance object in active state or NULL.
+    */
+   public Instance getWorkingInstance(String zone, String name, String flavorId, int size) {
+      InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+      for (int retries = 0; retries < 10; retries++) {
+         Instance instance = null;
+         try {
+            instance = instanceApi.create(flavorId, size, name);
+         } catch (Exception e) {
+
+            Uninterruptibles.sleepUninterruptibly(15, TimeUnit.SECONDS);
+
+            logger.error(e.getStackTrace().toString());
+            continue;
+         }
+
+         Instance updatedInstance = awaitAvailable(instance, instanceApi);
+         if (updatedInstance != null) {
+            return updatedInstance;
+         }
+         instanceApi.delete(instance.getId());
+         InstancePredicates.awaitDeleted(instanceApi).apply(instance);
+         
+      }
+      return null;
+   }
+
+   /**
+    * This will return a small working instance.
+    * 
+    * @param zone The zone where the instance should be created.
+    * @return A working database instance.
+    */
+   public Instance getWorkingInstance(String zone) {
+      return getWorkingInstance(zone, UUID.randomUUID().toString(), "1", 1);
+   }
+
+   private Instance awaitAvailable(Instance instance, InstanceApi iapi) {
+      for (int n = 0; n < 100; n = n + 1) {
+         Instance updatedInstance = iapi.get(instance.getId());
+         if (updatedInstance.getStatus() == Instance.Status.ACTIVE)
+            return updatedInstance;
+         if (updatedInstance.getStatus() == Instance.Status.UNRECOGNIZED)
+            return null; // fast fail
+         Uninterruptibles.sleepUninterruptibly(15, TimeUnit.SECONDS);
+      }
+      return null;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/apis/openstack-trove/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
new file mode 100644
index 0000000..558658c
--- /dev/null
+++ b/apis/openstack-trove/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+org.jclouds.openstack.trove.v1.TroveApiMetadata

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/FlavorTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/FlavorTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/FlavorTest.java
new file mode 100644
index 0000000..0b9d1b1
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/FlavorTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.openstack.trove.v1.domain;
+
+import org.jclouds.http.Uris;
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.openstack.v2_0.domain.Link.Relation;
+import org.testng.annotations.Test;
+import com.google.common.collect.ImmutableList;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+@Test(groups = "unit", testName = "FlavorTest")
+public class FlavorTest {
+   public void testFlavorForId() {
+      Flavor flavor1 = forId(1);
+      Flavor flavor2 = forId(2);
+      assertEquals(flavor1.getId(), 1);
+      assertEquals(flavor1.getName(), "small");
+      assertFalse(flavor1.equals(flavor2));
+   }
+   
+   /**
+    * Creates a dummy Flavor when you need a Flavor with just the flavorId. 
+    * 
+    * 1. name  = small
+    * 2. ram   = 512
+    * 3. links = self, bookmark
+    */
+   public static Flavor forId(int flavorId) {       
+       return Flavor.builder()
+               .id(flavorId)
+               .name("small")
+               .ram(512)
+               .links( 
+                       ImmutableList.of(
+                               Link.create(Relation.SELF, Uris.uriBuilder("http://test1").build() ),
+                               Link.create(Relation.BOOKMARK, Uris.uriBuilder("http://test2").build() )
+                               ) ).build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/InstanceTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/InstanceTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/InstanceTest.java
new file mode 100644
index 0000000..d0cf6f2
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/InstanceTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.openstack.trove.v1.domain;
+
+import org.jclouds.http.Uris;
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.openstack.v2_0.domain.Link.Relation;
+import org.testng.annotations.Test;
+import com.google.common.collect.ImmutableList;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+@Test(groups = "unit", testName = "InstanceTest")
+public class InstanceTest {
+   public void testInstanceForId() {
+      Instance instance1 = forId("1");
+      Instance instance2 = forId("2");
+      assertEquals(instance1.getId(), "1");
+      assertEquals(instance1.getName(), "json");
+      assertFalse(instance1.equals(instance2));
+   }
+   
+   /**
+    * Creates a dummy Instance when you need an Instance with just the instanceId.
+    */
+   public static Instance forId(String instanceId) {       
+       return Instance.builder()
+               .id(instanceId)
+               .name("json")
+               .status(Instance.Status.ACTIVE)
+               .size(2)
+               .flavor( FlavorTest.forId(1) )
+               .links( 
+                       ImmutableList.of(
+                               Link.create(Relation.SELF, Uris.uriBuilder("http://test1").build() ),
+                               Link.create(Relation.BOOKMARK, Uris.uriBuilder("http://test2").build() )
+                               ) ).build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/UserTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/UserTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/UserTest.java
new file mode 100644
index 0000000..9edd6f8
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/UserTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.openstack.trove.v1.domain;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import org.testng.annotations.Test;
+import com.google.common.collect.ImmutableSet;
+
+@Test(groups = "unit", testName = "UserTest")
+public class UserTest {
+   public void testUserForName() {
+      User user1 = forName("1");
+      User user2 = forName("2");
+      assertEquals(user1.getName(), "1");
+      assertEquals(user2.getName(), "2");
+      assertFalse(user1.equals(user2));
+   }
+   
+   /**
+    * Creates a dummy User when you need an User with just the userName.
+    */
+   public static User forName(String userName) {       
+       return User.builder()
+               .name(userName)
+               .password("password")
+               .databases( 
+                       ImmutableSet.of(
+                               "db1",
+                               "db2"
+                               ) ).build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/DatabaseApiExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/DatabaseApiExpectTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/DatabaseApiExpectTest.java
new file mode 100644
index 0000000..d422e60
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/DatabaseApiExpectTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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.openstack.trove.v1.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Set;
+
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.trove.v1.internal.BaseTroveApiExpectTest;
+import org.testng.annotations.Test;
+
+/**
+ * Tests DatabaseApi Guice wiring and parsing
+ *
+ * @author Zack Shoylev
+ */
+@Test(groups = "unit", testName = "DatabaseApiExpectTest")
+public class DatabaseApiExpectTest extends BaseTroveApiExpectTest {
+
+   public void testCreateDatabaseSimple() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/databases");
+      DatabaseApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint)
+            .method("POST")
+            .payload(payloadFromResourceWithContentType("/database_create_simple_request.json", MediaType.APPLICATION_JSON))
+            .build(),
+            HttpResponse.builder().statusCode(202).build() // response
+            ).getDatabaseApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      boolean result = api.create("testingdb");
+      assertTrue(result);
+   }
+
+   public void testCreateDatabaseSimpleFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/databases");
+      DatabaseApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint)
+            .method("POST")
+            .payload(payloadFromResourceWithContentType("/database_create_simple_request.json", MediaType.APPLICATION_JSON))
+            .build(),
+            HttpResponse.builder().statusCode(404).build() // response
+            ).getDatabaseApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      boolean result = api.create("testingdb");
+      assertFalse(result);
+   }
+
+   public void testCreateDatabase() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/databases");
+      DatabaseApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint)
+            .method("POST")
+            .payload(payloadFromResourceWithContentType("/database_create_request.json", MediaType.APPLICATION_JSON))
+            .build(),
+            HttpResponse.builder().statusCode(202).build() // response
+            ).getDatabaseApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      boolean result = api.create("testingdb", "utf8", "utf8_general_ci");
+      assertTrue(result);
+   }
+
+   public void testCreateDatabaseFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/databases");
+      DatabaseApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint)
+            .method("POST")
+            .payload(payloadFromResourceWithContentType("/database_create_request.json", MediaType.APPLICATION_JSON))
+            .build(),
+            HttpResponse.builder().statusCode(404).build() // response
+            ).getDatabaseApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      boolean result = api.create("testingdb", "utf8", "utf8_general_ci");
+      assertFalse(result);
+   }
+   
+   public void testDeleteDatabase() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/databases/db1");
+      DatabaseApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint) 
+            .method("DELETE")
+            .build(),
+            HttpResponse.builder().statusCode(202).build() // response
+            ).getDatabaseApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      boolean result = api.delete("db1");
+      assertTrue(result);
+   }
+   
+   public void testDeleteDatabaseFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/databases/db1");
+      DatabaseApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint) 
+            .method("DELETE")
+            .build(),
+            HttpResponse.builder().statusCode(404).build() // response
+            ).getDatabaseApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      boolean result = api.delete("db1");
+      assertFalse(result);
+   }
+   
+   public void testListDatabases() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/databases");
+      DatabaseApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/database_list.json")).build()
+      ).getDatabaseApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      List<String> databases = api.list().toList();
+      assertEquals(databases.size(), 5);
+      assertEquals(databases.iterator().next(), "anotherdb");
+   }
+   
+   public void testListDatabasesFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/databases");
+      DatabaseApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).payload(payloadFromResource("/database_list.json")).build()
+      ).getDatabaseApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      Set<String> databases = api.list().toSet();
+      assertTrue(databases.isEmpty());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/DatabaseApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/DatabaseApiLiveTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/DatabaseApiLiveTest.java
new file mode 100644
index 0000000..c60ee7c
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/DatabaseApiLiveTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.openstack.trove.v1.features;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jclouds.openstack.trove.v1.domain.Instance;
+import org.jclouds.openstack.trove.v1.internal.BaseTroveApiLiveTest;
+import org.jclouds.openstack.trove.v1.utils.TroveUtils;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+/**
+ * @author Zack Shoylev
+ */
+@Test(groups = "live", testName = "DatabaseApiLiveTest")
+public class DatabaseApiLiveTest extends BaseTroveApiLiveTest {
+
+   // zone to instance
+   private static Map<String,List<Instance>> instancesToDelete = Maps.newHashMap();
+   // not deleting databases. they will be deleted when instances are deleted
+
+   @Override
+   @BeforeClass(groups = { "integration", "live" })
+   public void setup() {
+      super.setup();
+      TroveUtils utils = new TroveUtils(api);
+      for (String zone : api.getConfiguredZones()) {
+         // create instances
+         List<Instance> instanceList = Lists.newArrayList();
+         Instance first = utils.getWorkingInstance(zone, "first_database_testing_" + zone, "1", 1);
+         Instance second = utils.getWorkingInstance(zone, "second_database_testing_" + zone, "1", 1);
+         instanceList.add(first);
+         instanceList.add(second);
+         instancesToDelete.put(zone, instanceList);
+
+         DatabaseApi databaseApiFirst = api.getDatabaseApiForZoneAndInstance(zone, first.getId());
+         DatabaseApi databaseApiSecond = api.getDatabaseApiForZoneAndInstance(zone, second.getId());
+         databaseApiFirst.create("livetest_db1");
+         databaseApiFirst.create("livetest_db2");
+         databaseApiSecond.create("livetest_db3");
+      }
+   }
+
+   @Override
+   @AfterClass(groups = { "integration", "live" })
+   public void tearDown(){
+      for (String zone : api.getConfiguredZones()) {
+         InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+         for(Instance instance : instancesToDelete.get(zone)){
+            if( !instanceApi.delete(instance.getId() ) )
+               throw new RuntimeException("Could not delete a database instance after tests!");
+         }
+      }
+      super.tearDown();
+   }
+
+   @Test
+   public void testListDatabases() {
+      for (String zone : api.getConfiguredZones()) {
+         InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+         assertTrue(instanceApi.list().size() >= 2);
+         for(Instance instance : instancesToDelete.get(zone)) {
+            DatabaseApi databaseApi = api.getDatabaseApiForZoneAndInstance(zone, instance.getId());
+            if(!instance.getName().contains("database_testing"))continue;
+            assertTrue(databaseApi.list().size() >=1);
+            for(String database : databaseApi.list()){
+               assertNotNull(database);      
+            }
+         }  
+      }   
+   }
+
+   @Test
+   public void testDeleteDatabases() {
+      for (String zone : api.getConfiguredZones()) {
+         InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+         assertTrue(instanceApi.list().size() >= 2);
+         for(Instance instance : instancesToDelete.get(zone)) {
+            DatabaseApi databaseApi = api.getDatabaseApiForZoneAndInstance(zone, instance.getId());
+            if(!instance.getName().contains("database_testing"))continue;
+            assertTrue(databaseApi.list().size() >=1);
+            for(String database : databaseApi.list()){
+               assertNotNull(database);
+               assertTrue(database.equals("livetest_db1") || database.equals("livetest_db2") || database.equals("livetest_db3") );
+               assertTrue(databaseApi.delete(database));
+               assertTrue(databaseApi.create(database));
+            }
+         }  
+      }   
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/FlavorApiExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/FlavorApiExpectTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/FlavorApiExpectTest.java
new file mode 100644
index 0000000..30c4b98
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/FlavorApiExpectTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.openstack.trove.v1.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.net.URI;
+import java.util.Set;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.trove.v1.TroveApi;
+import org.jclouds.openstack.trove.v1.domain.Flavor;
+import org.jclouds.openstack.trove.v1.internal.BaseTroveApiExpectTest;
+import org.testng.annotations.Test;
+
+/**
+ * Tests FlavorApi Guice wiring and parsing
+ *
+ * @author Zack Shoylev
+ */
+@Test(groups = "unit", testName = "FlavorApiExpectTest")
+public class FlavorApiExpectTest extends BaseTroveApiExpectTest {
+
+   public void testListFlavors() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/flavors");
+      FlavorApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/flavor_list.json")).build()
+      ).getFlavorApiForZone("RegionOne");
+
+      Set<? extends Flavor> flavors = api.list().toSet();
+      assertEquals(flavors.size(),6);
+      assertEquals(flavors.iterator().next().getRam(), 512);
+   }
+
+   public void testListFlavorsFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/flavors");
+      FlavorApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).build()
+      ).getFlavorApiForZone("RegionOne");
+
+      Set<? extends Flavor> flavors = api.list().toSet();
+      assertTrue(flavors.isEmpty());
+   }   
+
+   public void testGetFlavor() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/flavors/1");
+      FlavorApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/flavor_get.json")).build()
+      ).getFlavorApiForZone("RegionOne");
+
+      Flavor flavor = api.get(1);
+      assertEquals(flavor.getName(), "512MB Instance");
+      assertEquals(flavor.getId(), 1);
+      assertEquals(flavor.getRam(), 512);
+      assertEquals(flavor.getLinks().size(), 2);
+   }
+   
+   public void testGetFlavorByAccountId() {
+	      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/flavors/40806637803162");
+	      TroveApi redDwarfApi = requestsSendResponses(
+               keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess,
+               authenticatedGET().endpoint(endpoint).build(),
+               HttpResponse.builder().statusCode(200).payload(payloadFromResource("/flavor_list.json")).build() ); 
+	      FlavorApi api = redDwarfApi.getFlavorApiForZone("RegionOne");
+
+	      Set<? extends Flavor> flavors = api.list( redDwarfApi.getCurrentTenantId().get().getId() ).toSet();
+	      Flavor flavor = flavors.iterator().next();
+	      assertEquals(flavor.getName(), "512MB Instance");
+	      assertEquals(flavor.getId(), 1);
+	      assertEquals(flavor.getRam(), 512);
+	      assertEquals(flavor.getLinks().size(), 2);
+	   }
+
+   public void testGetFlavorFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/flavors/12312");
+      FlavorApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).build()
+      ).getFlavorApiForZone("RegionOne");
+
+      assertNull(api.get(12312));
+   }   
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/FlavorApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/FlavorApiLiveTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/FlavorApiLiveTest.java
new file mode 100644
index 0000000..7d0eebe
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/FlavorApiLiveTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.openstack.trove.v1.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+import org.jclouds.openstack.trove.v1.domain.Flavor;
+import org.jclouds.openstack.trove.v1.internal.BaseTroveApiLiveTest;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import com.google.common.collect.FluentIterable;
+
+/**
+ * @author Zack Shoylev
+ */
+@Test(groups = "live", testName = "FlavorApiLiveTest")
+public class FlavorApiLiveTest extends BaseTroveApiLiveTest {
+
+    @Override
+    @BeforeClass(groups = { "integration", "live" })
+    public void setup() {
+        super.setup();
+    }
+
+    private void checkFlavor(Flavor flavor) {
+        assertNotNull(flavor.getId(), "Id cannot be null for " + flavor);
+        assertNotNull(flavor.getName(), "Name cannot be null for " + flavor);
+    }
+
+    @Test
+    public void testListFlavorsByAccount() {
+        for (String zone : api.getConfiguredZones()) {
+            FlavorApi flavorApi = api.getFlavorApiForZone(zone);
+
+            FluentIterable<Flavor> response = flavorApi.list( api.getCurrentTenantId().get().getId() ); // tenant id, but referred to as account id. 
+            for (Flavor flavor : response) {
+                checkFlavor(flavor);
+            }  
+        }   
+    }
+
+    @Test
+    public void testListFlavorsByAccountWhenAccountIdNotFound() {
+        for (String zone : api.getConfiguredZones()) {
+            FlavorApi flavorApi = api.getFlavorApiForZone(zone);
+            assertTrue(flavorApi.list("9999").isEmpty());
+        }
+    }
+
+    @Test
+    public void testGetFlavor() {
+        for (String zone : api.getConfiguredZones()) {
+            FlavorApi flavorApi = api.getFlavorApiForZone(zone);           
+            for (Flavor flavor : flavorApi.list()) {
+                Flavor flavorFromGet = flavorApi.get(flavor.getId());
+                assertEquals(flavorFromGet.getId(), flavor.getId());
+                assertEquals(flavorFromGet.getRam(), flavor.getRam());
+                assertEquals(flavorFromGet.getName(), flavor.getName());
+                assertEquals(flavorFromGet.getLinks(), flavor.getLinks());
+            }
+        }
+    }
+
+    @Test
+    public void testGetFlavorWhenNotFound() {
+        for (String zone : api.getConfiguredZones()) {
+            FlavorApi flavorApi = api.getFlavorApiForZone(zone);
+            assertNull(flavorApi.get(9999));
+        }
+    }   
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/InstanceApiExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/InstanceApiExpectTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/InstanceApiExpectTest.java
new file mode 100644
index 0000000..369c469
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/InstanceApiExpectTest.java
@@ -0,0 +1,217 @@
+/*
+ * 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.openstack.trove.v1.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+import java.net.URI;
+import java.util.Set;
+import javax.ws.rs.core.MediaType;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.trove.v1.domain.Instance;
+import org.jclouds.openstack.trove.v1.internal.BaseTroveApiExpectTest;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+/**
+ * Tests InstanceApi Guice wiring and parsing
+ *
+ * @author Zack Shoylev
+ */
+@Test(groups = "unit", testName = "InstanceApiExpectTest")
+public class InstanceApiExpectTest extends BaseTroveApiExpectTest {
+    
+    public void testCreateInstance() {
+        URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances");
+        InstanceApi api = requestsSendResponses(
+                keystoneAuthWithUsernameAndPasswordAndTenantName,
+                responseWithKeystoneAccess,
+                authenticatedGET().endpoint(endpoint) // bad naming convention, you should not be able to change the method to POST
+                .method("POST")
+                .payload(payloadFromResourceWithContentType("/instance_create_request.json", MediaType.APPLICATION_JSON))
+                .build(),
+                HttpResponse.builder().statusCode(200).payload(payloadFromResource("/instance_create.json")).build() // response
+                ).getInstanceApiForZone("RegionOne");
+
+        Instance instance = api.create("1", 2, "json_rack_instance");
+        assertEquals(instance.getSize(),2);
+        assertEquals(instance.getName(), "json_rack_instance");  
+    }
+    
+    @Test(expectedExceptions = ResourceNotFoundException.class)
+    public void testCreateInstanceFail() {
+        URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances");
+        InstanceApi api = requestsSendResponses(
+                keystoneAuthWithUsernameAndPasswordAndTenantName,
+                responseWithKeystoneAccess,
+                authenticatedGET().endpoint(endpoint) // bad naming convention, you should not be able to change the method to POST
+                .method("POST")
+                .payload(payloadFromResourceWithContentType("/instance_create_request.json", MediaType.APPLICATION_JSON))
+                .build(),
+                HttpResponse.builder().statusCode(404).payload(payloadFromResource("/instance_create.json")).build() // response
+                ).getInstanceApiForZone("RegionOne");
+
+        api.create("1", 2, "json_rack_instance");
+    }
+    
+    public void testDeleteInstance() {
+        URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/098653ba-218b-47ce-936a-e0b749101f81");
+        InstanceApi api = requestsSendResponses(
+                keystoneAuthWithUsernameAndPasswordAndTenantName,
+                responseWithKeystoneAccess,
+                authenticatedGET().endpoint(endpoint).method("DELETE").build(),
+                HttpResponse.builder().statusCode(202).build() // response
+                ).getInstanceApiForZone("RegionOne");
+
+        assertTrue( api.delete("098653ba-218b-47ce-936a-e0b749101f81") );
+    }
+    
+    public void testDeleteInstanceFail() {
+        URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/098653ba-218b-47ce-936a-e0b749101f81");
+        InstanceApi api = requestsSendResponses(
+                keystoneAuthWithUsernameAndPasswordAndTenantName,
+                responseWithKeystoneAccess,
+                authenticatedGET().endpoint(endpoint).method("DELETE").build(),
+                HttpResponse.builder().statusCode(404).build() // response
+                ).getInstanceApiForZone("RegionOne");
+
+        assertTrue( !api.delete("098653ba-218b-47ce-936a-e0b749101f81") );
+    }
+
+   
+   public void testListInstances() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances");
+      InstanceApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/instance_list.json")).build()
+      ).getInstanceApiForZone("RegionOne");
+
+      Set<? extends Instance> instances = api.list().toSet();
+      assertEquals(instances.size(),2);
+      assertEquals(instances.iterator().next().getSize(), 2);
+   }
+
+   public void testListInstancesFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances");
+      InstanceApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).build()
+      ).getInstanceApiForZone("RegionOne");
+
+      Set<? extends Instance> instances = api.list().toSet();
+      assertTrue(instances.isEmpty());
+   }   
+
+   public void testGetInstance() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/44b277eb-39be-4921-be31-3d61b43651d7");
+      InstanceApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/instance_get.json")).build()
+      ).getInstanceApiForZone("RegionOne");
+
+      Instance instance = api.get("44b277eb-39be-4921-be31-3d61b43651d7");
+      assertEquals(instance.getName(), "json_rack_instance");
+      assertEquals(instance.getId(), "44b277eb-39be-4921-be31-3d61b43651d7");
+      assertEquals(instance.getLinks().size(), 2);
+      assertEquals(instance.getHostname(), "e09ad9a3f73309469cf1f43d11e79549caf9acf2.rackspaceclouddb.com");
+   }
+   
+   public void testGetInstanceFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/12312");
+      InstanceApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).build()
+      ).getInstanceApiForZone("RegionOne");
+
+      assertNull(api.get("12312"));
+   }  
+   
+   public void testEnableRootOnInstance() {
+       URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/44b277eb-39be-4921-be31-3d61b43651d7/root");
+       InstanceApi api = requestsSendResponses(
+             keystoneAuthWithUsernameAndPasswordAndTenantName,
+             responseWithKeystoneAccess,
+             authenticatedGET().method("POST").endpoint(endpoint).build(),
+             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/instance_root.json")).build()
+       ).getInstanceApiForZone("RegionOne");
+
+       String password = api.enableRoot("44b277eb-39be-4921-be31-3d61b43651d7");
+       assertEquals(password, "12345");
+    }
+   
+   public void testEnableRootOnInstanceFail() {
+       URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/44b277eb-39be-4921-be31-3d61b43651d7/root");
+       InstanceApi api = requestsSendResponses(
+             keystoneAuthWithUsernameAndPasswordAndTenantName,
+             responseWithKeystoneAccess,
+             authenticatedGET().method("POST").endpoint(endpoint).build(),
+             HttpResponse.builder().statusCode(404).payload(payloadFromResource("/instance_root.json")).build()
+       ).getInstanceApiForZone("RegionOne");
+
+       String password = api.enableRoot("44b277eb-39be-4921-be31-3d61b43651d7");
+       assertEquals(password, null);
+    }
+   
+   public void testIsRootInstance() {
+       URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/44b277eb-39be-4921-be31-3d61b43651d7/root");
+       InstanceApi api = requestsSendResponses(
+             keystoneAuthWithUsernameAndPasswordAndTenantName,
+             responseWithKeystoneAccess,
+             authenticatedGET().endpoint(endpoint).build(),
+             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/instance_is_rooted.json")).build()
+       ).getInstanceApiForZone("RegionOne");
+
+       boolean rooted = api.isRooted("44b277eb-39be-4921-be31-3d61b43651d7");
+       assertEquals(rooted, true);
+    }
+   
+   public void testIsRootInstanceFalse() {
+       URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/44b277eb-39be-4921-be31-3d61b43651d7/root");
+       InstanceApi api = requestsSendResponses(
+             keystoneAuthWithUsernameAndPasswordAndTenantName,
+             responseWithKeystoneAccess,
+             authenticatedGET().endpoint(endpoint).build(),
+             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/instance_is_rooted_false.json")).build()
+       ).getInstanceApiForZone("RegionOne");
+
+       Boolean rooted = api.isRooted("44b277eb-39be-4921-be31-3d61b43651d7");
+       assertEquals(rooted.booleanValue(), false);
+    }
+   
+   @Test(expectedExceptions = ResourceNotFoundException.class)  
+   public void testIsRootInstanceFail() {
+       URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/44b277eb-39be-4921-be31-3d61b43651d7/root");
+       InstanceApi api = requestsSendResponses(
+             keystoneAuthWithUsernameAndPasswordAndTenantName,
+             responseWithKeystoneAccess,
+             authenticatedGET().endpoint(endpoint).build(),
+             HttpResponse.builder().statusCode(404).payload(payloadFromResource("/instance_is_rooted.json")).build()
+       ).getInstanceApiForZone("RegionOne");
+
+       Boolean rooted = api.isRooted("44b277eb-39be-4921-be31-3d61b43651d7");
+       assertNull(rooted);
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/InstanceApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/InstanceApiLiveTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/InstanceApiLiveTest.java
new file mode 100644
index 0000000..6de832a
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/InstanceApiLiveTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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.openstack.trove.v1.features;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.jclouds.openstack.trove.v1.domain.Instance;
+import org.jclouds.openstack.trove.v1.internal.BaseTroveApiLiveTest;
+import org.jclouds.openstack.trove.v1.utils.TroveUtils;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+/**
+ * @author Zack Shoylev
+ */
+@Test(groups = "live", testName = "InstanceApiLiveTest")
+public class InstanceApiLiveTest extends BaseTroveApiLiveTest {
+
+    private static Map<String,List<Instance>> created = Maps.newHashMap();
+    
+    @Override
+    @BeforeClass(groups = { "integration", "live" })
+    public void setup() {
+        super.setup();
+        TroveUtils utils= new TroveUtils(api);
+        for (String zone : api.getConfiguredZones()) {
+            List<Instance> zoneList = Lists.newArrayList();
+            InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+            zoneList.add(utils.getWorkingInstance(zone, "first_instance_testing_" + zone, "1", 1));
+            Instance second = utils.getWorkingInstance(zone, "second_instance_testing_" + zone, "1", 1);
+            instanceApi.enableRoot(second.getId());
+            zoneList.add(second);            
+            created.put(zone, zoneList);
+        }
+    }
+    
+    @Override
+    @AfterClass(groups = { "integration", "live" })
+    public void tearDown(){
+        for (String zone : api.getConfiguredZones()) {
+            InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+            for(Instance instance : created.get(zone)){
+                if( !instanceApi.delete(instance.getId() ) )
+                    throw new RuntimeException("Could not delete a database instance after tests!");
+            }
+        }
+        super.tearDown();
+    }
+
+    private void checkInstance(Instance instance) {
+        assertNotNull(instance.getId(), "Id cannot be null for " + instance);
+        checkArgument(instance.getSize() > 0, "Size must not be 0");
+    }
+
+    @Test
+    public void testListInstances() {
+        for (String zone : api.getConfiguredZones()) {
+            InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+            FluentIterable<Instance> response = instanceApi.list(); 
+            assertFalse(response.isEmpty());
+            for (Instance instance : response) {
+                checkInstance(instance);
+            }  
+        }   
+    }    
+
+    @Test
+    public void testGetInstance() {
+        for (String zone : api.getConfiguredZones()) {
+            InstanceApi instanceApi = api.getInstanceApiForZone(zone);           
+            for (Instance instance : instanceApi.list()) {
+                Instance instanceFromGet = instanceApi.get(instance.getId());
+                assertNotNull(instanceFromGet.getHostname());
+                assertNull(instance.getHostname());
+                assertEquals(instanceFromGet.getId(), instance.getId());
+                assertEquals(instanceFromGet.getName(), instance.getName());
+                assertEquals(instanceFromGet.getStatus(), instance.getStatus());
+                assertEquals(instanceFromGet.getFlavor(), instance.getFlavor());
+                assertEquals(instanceFromGet.getSize(), instance.getSize());
+                assertEquals(instanceFromGet.getLinks(), instance.getLinks());
+            }
+        }
+    }
+
+    @Test
+    public void testGetInstanceWhenNotFound() {
+        for (String zone : api.getConfiguredZones()) {
+            InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+            assertNull(instanceApi.get("9999"));
+        }
+    }   
+    
+    @Test
+    public void testGetRootStatus() {
+        for (String zone : api.getConfiguredZones()) {
+            InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+            Iterator<Instance> iterator = instanceApi.list().iterator();
+            Instance first;
+            Instance second;
+            do {
+               first = iterator.next(); 
+            } while(!first.getName().contains("instance_testing"));
+            do {
+               second = iterator.next(); 
+            } while(!second.getName().contains("instance_testing"));
+            assertTrue(instanceApi.isRooted(first.getId()) || instanceApi.isRooted(second.getId()));
+        }
+    }
+}


[2/4] Moving trove to jclouds from jclouds-openstack-labs https://issues.apache.org/jira/browse/JCLOUDS-102

Posted by za...@apache.org.
http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/UserApiExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/UserApiExpectTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/UserApiExpectTest.java
new file mode 100644
index 0000000..b1f9208
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/UserApiExpectTest.java
@@ -0,0 +1,433 @@
+/*
+ * 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.openstack.trove.v1.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertFalse;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Set;
+
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.trove.v1.domain.User;
+import org.jclouds.openstack.trove.v1.internal.BaseTroveApiExpectTest;
+import org.testng.annotations.Test;
+import org.testng.collections.Lists;
+import org.testng.internal.annotations.Sets;
+
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.ImmutableSortedSet.Builder;
+
+/**
+ * Tests UserApi Guice wiring and parsing
+ *
+ * @author Zack Shoylev
+ */
+@Test(groups = "unit", testName = "UserApiExpectTest")
+public class UserApiExpectTest extends BaseTroveApiExpectTest {
+
+   public void testCreateUserSimple() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint) // bad naming convention, you should not be able to change the method to POST
+            .method("POST")
+            .payload(payloadFromResourceWithContentType("/user_create_simple_request.json", MediaType.APPLICATION_JSON))
+            .build(),
+            HttpResponse.builder().statusCode(202).build() // response
+            ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      boolean result = api.create("dbuser1", "password", "databaseA");
+      assertTrue(result);
+   }
+
+   public void testCreateUserSimpleFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint) // bad naming convention, you should not be able to change the method to POST
+            .method("POST")
+            .payload(payloadFromResourceWithContentType("/user_create_simple_request.json", MediaType.APPLICATION_JSON))
+            .build(),
+            HttpResponse.builder().statusCode(404).build() // response
+            ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      boolean result = api.create("dbuser1", "password", "databaseA");
+      assertFalse(result);
+   }
+   
+   public void testCreateUserSimpleWithHost() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint) // bad naming convention, you should not be able to change the method to POST
+            .method("POST")
+            .payload(payloadFromResourceWithContentType("/user_create_with_host_simple_request.json", MediaType.APPLICATION_JSON))
+            .build(),
+            HttpResponse.builder().statusCode(202).build() // response
+            ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      boolean result = api.create("dbuser1", "password", "192.168.64.64", "databaseA");
+      assertTrue(result);
+   }
+   
+   public void testCreateUserSimpleWithHostFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint) // bad naming convention, you should not be able to change the method to POST
+            .method("POST")
+            .payload(payloadFromResourceWithContentType("/user_create_with_host_simple_request.json", MediaType.APPLICATION_JSON))
+            .build(),
+            HttpResponse.builder().statusCode(404).build() // response
+            ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      boolean result = api.create("dbuser1", "password", "192.168.64.64", "databaseA");
+      assertFalse(result);
+   }
+
+   public void testCreateUser() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint) // bad naming convention, you should not be able to change the method to POST
+            .method("POST")
+            .payload(payloadFromResourceWithContentType("/user_create_request.json", MediaType.APPLICATION_JSON))
+            .build(),
+            HttpResponse.builder().statusCode(202).build() // response
+            ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      Set<String> databases1 = Sets.newHashSet();
+      databases1.add( "databaseA" );      
+      Builder<String> databases2builder = ImmutableSortedSet.<String>naturalOrder();
+      databases2builder.add( "databaseB" );
+      databases2builder.add( "databaseC" );
+      Set<String> databases2 = databases2builder.build();
+      Set<String> databases3 = Sets.newHashSet();
+      databases3.add( "databaseD" );
+      User user1 = User.builder().databases( databases1 ).name("dbuser1").password("password").build();
+      User user2 = User.builder().databases( databases2 ).name("dbuser2").password("password").build();
+      User user3 = User.builder().databases( databases3 ).name("dbuser3").password("password").host("192.168.64.64").build();
+      Set<User> users = Sets.newHashSet();
+      users.add(user1);
+      users.add(user2);
+      users.add(user3);
+      
+      boolean result = api.create(ImmutableSortedSet.<User>naturalOrder().addAll(users).build());
+      assertTrue(result);
+   }
+
+   public void testCreateUserFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint) // bad naming convention, you should not be able to change the method to POST
+            .method("POST")
+            .payload(payloadFromResourceWithContentType("/user_create_request.json", MediaType.APPLICATION_JSON))
+            .build(),
+            HttpResponse.builder().statusCode(404).build() // response
+            ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      Set<String> databases1 = Sets.newHashSet();
+      databases1.add( "databaseA" );
+      Builder<String> databases2builder = ImmutableSortedSet.<String>naturalOrder();
+      databases2builder.add( "databaseB" );
+      databases2builder.add( "databaseC" );
+      Set<String> databases2 = databases2builder.build();
+      Set<String> databases3 = Sets.newHashSet();
+      databases3.add( "databaseD" );
+      User user1 = User.builder().databases( databases1 ).name("dbuser1").password("password").build();
+      User user2 = User.builder().databases( databases2 ).name("dbuser2").password("password").build();
+      User user3 = User.builder().databases( databases3 ).name("dbuser3").password("password").host("192.168.64.64").build();
+      Set<User> users = Sets.newHashSet();
+      users.add(user1);
+      users.add(user2);
+      users.add(user3);
+      
+      boolean result = api.create( ImmutableSortedSet.<User>naturalOrder().addAll(users).build());
+      assertFalse(result);
+   }
+
+   public void testGrantUserSimple() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users/dbuser1/databases");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint) // bad naming convention, you should not be able to change the method to POST
+            .method("PUT")
+            .payload(payloadFromResourceWithContentType("/user_grant_simple_request.json", MediaType.APPLICATION_JSON))
+            .build(),
+            HttpResponse.builder().statusCode(202).build() // response
+            ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      boolean result = api.grant("dbuser1", "databaseZ");
+      assertTrue(result);
+   }
+
+   public void testGrantUserSimpleFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users/dbuser1/databases");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint) // bad naming convention, you should not be able to change the method to POST
+            .method("PUT")
+            .payload(payloadFromResourceWithContentType("/user_grant_simple_request.json", MediaType.APPLICATION_JSON))
+            .build(),
+            HttpResponse.builder().statusCode(404).build() // response
+            ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      boolean result = api.grant("dbuser1", "databaseZ");
+      assertFalse(result);
+   }
+
+   public void testGrantUser() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users/dbuser1/databases");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint) // bad naming convention, you should not be able to change the method to POST
+            .method("PUT")
+            .payload(payloadFromResourceWithContentType("/user_grant_request.json", MediaType.APPLICATION_JSON))
+            .build(),
+            HttpResponse.builder().statusCode(202).build() // response
+            ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      List<String> databases = Lists.newArrayList();
+      databases.add( "databaseC" );
+      databases.add( "databaseD" );
+      
+      boolean result = api.grant("dbuser1", databases);
+      assertTrue(result);
+   }
+
+   public void testGrantUserFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users/dbuser1/databases");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint) // bad naming convention, you should not be able to change the method to POST
+            .method("PUT")
+            .payload(payloadFromResourceWithContentType("/user_grant_request.json", MediaType.APPLICATION_JSON))
+            .build(),
+            HttpResponse.builder().statusCode(404).build() // response
+            ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      List<String> databases = Lists.newArrayList();
+      databases.add( "databaseC" );
+      databases.add( "databaseD" );
+      
+      boolean result = api.grant("dbuser1", databases);
+      assertFalse(result);
+   }
+   
+   public void testRevokeUser() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users/dbuser1/databases/databaseA");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint) // bad naming convention, you should not be able to change the method to POST
+            .method("DELETE")
+            .build(),
+            HttpResponse.builder().statusCode(202).build() // response
+            ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      Set<String> databases = Sets.newHashSet();
+      databases.add( "database" );
+      databases.add( "database" );
+      boolean result = api.revoke("dbuser1", "databaseA");
+      assertTrue(result);
+   }
+   
+   public void testRevokeUserFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users/dbuser1/databases/databaseA");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint) // bad naming convention, you should not be able to change the method to POST
+            .method("DELETE")
+            .build(),
+            HttpResponse.builder().statusCode(404).build() // response
+            ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      Set<String> databases = Sets.newHashSet();
+      databases.add( "database" );
+      databases.add( "database" );
+      boolean result = api.revoke("dbuser1", "databaseA");
+      assertFalse(result);
+   }
+   
+   public void testDeleteUser() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users/dbuser1");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint) // bad naming convention, you should not be able to change the method to POST
+            .method("DELETE")
+            .build(),
+            HttpResponse.builder().statusCode(202).build() // response
+            ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      Set<String> databases = Sets.newHashSet();
+      databases.add( "database" );
+      databases.add( "database" );
+      boolean result = api.delete("dbuser1");
+      assertTrue(result);
+   }
+   
+   public void testDeleteUserFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users/dbuser1");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint) // bad naming convention, you should not be able to change the method to POST
+            .method("DELETE")
+            .build(),
+            HttpResponse.builder().statusCode(404).build() // response
+            ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      Set<String> databases = Sets.newHashSet();
+      databases.add( "database" );
+      databases.add( "database" );
+      boolean result = api.delete("dbuser1");
+      assertFalse(result);
+   }
+   
+   public void testListUsers() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/trove_user_list.json")).build()
+      ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      Set<User> users = api.list().toSet();
+      assertEquals(users.size(), 4);
+      assertTrue(users.iterator().next().getDatabases().isEmpty());
+      assertEquals(users.iterator().next().getName(), "dbuser1");
+   }
+   
+   public void testListUsersFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).payload(payloadFromResource("/trove_user_list.json")).build()
+      ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      Set<User> users = api.list().toSet();
+      assertTrue(users.isEmpty());
+   }
+   
+   public void testUserGetDatabaseList() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users/dbuser1/databases");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/user_list_access.json")).build()
+      ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      List<String> databases = api.getDatabaseList("dbuser1").toList();
+      assertEquals(databases.size(), 2);
+      assertEquals(databases.iterator().next(), "databaseA");
+   }
+   
+   public void testUserGetDatabaseListFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users/dbuser1/databases");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).payload(payloadFromResource("/user_list_access.json")).build()
+      ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      Set<String> databases = api.getDatabaseList("dbuser1").toSet();
+      assertTrue(databases.isEmpty());
+   }
+   
+   public void testGetUser() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users/exampleuser");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/user_get.json")).build()
+      ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      User user = api.get("exampleuser");
+      assertEquals(user.getName(), "exampleuser");
+      assertEquals(user.getHost(), "%");
+      assertEquals(user.getDatabases().size(), 2);
+      assertEquals(user.getDatabases().iterator().next(), "databaseA");
+   }
+   
+   public void testGetUserFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users/exampleuser");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).payload(payloadFromResource("/user_get.json")).build()
+      ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      User user = api.get("exampleuser");
+      assertNull(user);
+   }
+   
+   public void testGetUserWithHostname() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users/example%2euser%40192%2e168%2e64%2e64");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/user_get_withhost.json")).build()
+      ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      User user = api.get("example.user", "192.168.64.64");
+      assertEquals(user.getName(), "example.user");
+      assertEquals(user.getHost(), "192.168.64.64");
+      assertEquals(user.getIdentifier(), "example.user@192.168.64.64");
+      assertEquals(user.getDatabases().size(), 2);
+      assertEquals(user.getDatabases().iterator().next(), "databaseA");
+   }
+   
+   public void testGetUserWithHostnameFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/users/example%2euser%40192%2e168%2e64%2e64");
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).payload(payloadFromResource("/user_get_withhost.json")).build()
+      ).getUserApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      User user = api.get("example.user", "192.168.64.64");
+      assertNull(user);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/UserApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/UserApiLiveTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/UserApiLiveTest.java
new file mode 100644
index 0000000..cd4a468
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/UserApiLiveTest.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.openstack.trove.v1.features;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+import org.jclouds.openstack.trove.v1.domain.Instance;
+import org.jclouds.openstack.trove.v1.domain.User;
+import org.jclouds.openstack.trove.v1.internal.BaseTroveApiLiveTest;
+import org.jclouds.openstack.trove.v1.utils.TroveUtils;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+/**
+ * @author Zack Shoylev
+ */
+@Test(groups = "live", testName = "UserApiLiveTest")
+public class UserApiLiveTest extends BaseTroveApiLiveTest {
+
+   // zone to instance
+   private static Map<String,List<Instance>> instancesToDelete = Maps.newHashMap();
+   // not deleting users. they will be deleted when instances are deleted
+
+   @Override
+   @BeforeClass(groups = { "integration", "live" })
+   public void setup() {
+      super.setup();
+      TroveUtils utils= new TroveUtils(api);
+      for (String zone : api.getConfiguredZones()) {
+         // create instances
+         List<Instance> instanceList = Lists.newArrayList();
+         Instance first = utils.getWorkingInstance(zone, "first_user_trove_live_testing_" + zone, "1", 1);
+         Instance second = utils.getWorkingInstance(zone, "second_user_trove_live_testing_" + zone, "1", 1);
+         instanceList.add(first);
+         instanceList.add(second);
+         instancesToDelete.put(zone, instanceList);
+         // create users
+         User user1 = User.builder()
+               .name("user1")
+               .password(UUID.randomUUID().toString())
+               .databases(ImmutableSet.of(
+                     "u1db1", 
+                     "u1db2")).build();
+         User user2 = User.builder()
+               .name("user2")
+               .password(UUID.randomUUID().toString())
+               .databases(ImmutableSet.of(
+                     "u2db1", 
+                     "u2db2")).build();
+         User user3 = User.builder()
+               .name("user3")
+               .password(UUID.randomUUID().toString())
+               .host("173.203.44.122")
+               .databases(ImmutableSet.of(
+                     "u3db1", 
+                     "u3db2")).build();
+         UserApi userApiFirst = api.getUserApiForZoneAndInstance(zone, first.getId());
+         UserApi userApiSecond = api.getUserApiForZoneAndInstance(zone, second.getId());
+         userApiFirst.create(ImmutableSet.of(user1, user2));
+         userApiSecond.create(ImmutableSet.of(user3));
+      }
+   }
+
+   @Override
+   @AfterClass(groups = { "integration", "live" })
+   public void tearDown(){
+      for (String zone : api.getConfiguredZones()) {
+         InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+         for(Instance instance : instancesToDelete.get(zone)){
+            if( !instanceApi.delete(instance.getId() ) )
+               throw new RuntimeException("Could not delete a database instance after tests!");
+         }
+      }
+      super.tearDown();
+   }
+
+   private void checkUser(User user) {
+      assertNotNull(user.getName(), "Name cannot be null for " + user);
+      assertNotNull(user.getHost(), "Host cannot be null (should be '%' if default) for " + user);
+      checkArgument(!user.getDatabases().isEmpty(), "Number of databases must not be 0");
+   }
+
+   @Test
+   public void testListUsers() {
+      for (String zone : api.getConfiguredZones()) {
+         InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+         assertTrue(instanceApi.list().size() >= 2);
+         for(Instance instance : instancesToDelete.get(zone)) {
+            UserApi userApi = api.getUserApiForZoneAndInstance(zone, instance.getId());
+            if(!instance.getName().contains("user_trove_live_testing"))continue;
+            assertTrue(userApi.list().size() >=1);
+            for(User user : userApi.list()){
+               checkUser(user);      
+            }
+         }  
+      }   
+   }    
+
+   @Test
+   public void testGetUser() {
+      for (String zone : api.getConfiguredZones()) {
+         InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+         assertTrue(instanceApi.list().size() >= 2);
+         for(Instance instance : instancesToDelete.get(zone)) {
+            UserApi userApi = api.getUserApiForZoneAndInstance(zone, instance.getId());
+            if(!instance.getName().contains("user_trove_live_testing"))continue;
+            assertTrue(userApi.list().size() >=1);
+            for(User user : userApi.list()){
+               User userFromGet = userApi.get(user.getIdentifier());
+               assertEquals(userFromGet.getName(), user.getName());
+               assertEquals(userFromGet.getHost(), user.getHost());
+               assertEquals(userFromGet.getIdentifier(), user.getIdentifier());
+               assertEquals(userFromGet.getDatabases(), user.getDatabases());
+               assertEquals(userFromGet, user);
+            }
+         }  
+      } 
+   }
+
+   @Test
+   public void testGetDatabaseListForUser() {
+      for (String zone : api.getConfiguredZones()) {
+         InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+         assertTrue(instanceApi.list().size() >= 2 );
+         for(Instance instance : instancesToDelete.get(zone)) {
+            UserApi userApi = api.getUserApiForZoneAndInstance(zone, instance.getId());
+            if(!instance.getName().contains("user_trove_live_testing"))continue;
+            assertTrue(userApi.list().size() >=1);
+            for(User user : userApi.list()){
+               assertFalse(userApi.getDatabaseList(user.getIdentifier()).isEmpty());
+            }
+         }  
+      } 
+   }
+
+   @Test
+   public void testGrantAndRevokeAcccessForUser() {
+      for (String zone : api.getConfiguredZones()) {
+         InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+         assertTrue(instanceApi.list().size() >= 2);
+         for(Instance instance : instancesToDelete.get(zone)) {
+            UserApi userApi = api.getUserApiForZoneAndInstance(zone, instance.getId());
+            if(!instance.getName().contains("user_trove_live_testing"))continue;
+            assertTrue(userApi.list().size() >=1);
+            for(User user : userApi.list()){
+               userApi.grant(user.getIdentifier(), "dbA");
+               userApi.grant(user.getIdentifier(), ImmutableList.of(
+                     "dbB", 
+                     "dbC"));
+
+               Set<String> databases = userApi.getDatabaseList(user.getIdentifier()).toSet();
+               assertTrue(databases.contains("dbA"));
+               assertTrue(databases.contains("dbB"));
+               assertTrue(databases.contains("dbC"));
+
+               userApi.revoke(user.getIdentifier(), "dbA");
+               userApi.revoke(user.getIdentifier(), "dbB");
+               userApi.revoke(user.getIdentifier(), "dbC");
+
+               databases = userApi.getDatabaseList(user.getIdentifier()).toSet();
+               assertFalse(databases.contains("dbA"));
+               assertFalse(databases.contains("dbB"));
+               assertFalse(databases.contains("dbC"));
+            }
+         }  
+      } 
+   }
+
+   @Test
+   public void testGetUserWhenNotFound() {
+      for (String zone : api.getConfiguredZones()) {
+         String instanceId = instancesToDelete.get(zone).iterator().next().getId();
+         UserApi userApi = api.getUserApiForZoneAndInstance(zone, instanceId);
+         assertNull(userApi.get("9999"));
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/internal/BaseTroveApiExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/internal/BaseTroveApiExpectTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/internal/BaseTroveApiExpectTest.java
new file mode 100644
index 0000000..b8c4216
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/internal/BaseTroveApiExpectTest.java
@@ -0,0 +1,27 @@
+/*
+ * 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.openstack.trove.v1.internal;
+
+import org.jclouds.openstack.trove.v1.TroveApi;
+
+/**
+ * Base class for writing Trove Rest Api Expect tests
+ * 
+ * @author Everett Toews
+ */
+public class BaseTroveApiExpectTest extends BaseTroveExpectTest<TroveApi> {
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/internal/BaseTroveApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/internal/BaseTroveApiLiveTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/internal/BaseTroveApiLiveTest.java
new file mode 100644
index 0000000..978f4ce
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/internal/BaseTroveApiLiveTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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.openstack.trove.v1.internal;
+
+import java.util.Properties;
+
+import org.jclouds.apis.BaseApiLiveTest;
+import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
+import org.jclouds.openstack.trove.v1.TroveApi;
+
+/**
+ * Tests behavior of TroveApi
+ * 
+ * @author Zack Shoylev
+ */
+public class BaseTroveApiLiveTest extends BaseApiLiveTest<TroveApi> {
+
+   public BaseTroveApiLiveTest() {
+      provider = "openstack-trove";
+   }
+
+   @Override
+   protected Properties setupProperties() {
+      Properties props = super.setupProperties();
+      setIfTestSystemPropertyPresent(props, KeystoneProperties.CREDENTIAL_TYPE);
+      setIfTestSystemPropertyPresent(props, KeystoneProperties.SERVICE_TYPE);
+      return props;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/internal/BaseTroveExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/internal/BaseTroveExpectTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/internal/BaseTroveExpectTest.java
new file mode 100644
index 0000000..b43db05
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/internal/BaseTroveExpectTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.openstack.trove.v1.internal;
+
+import javax.ws.rs.core.MediaType;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.keystone.v2_0.internal.KeystoneFixture;
+import org.jclouds.rest.internal.BaseRestApiExpectTest;
+
+/**
+ * Base class for writing Nova Expect tests
+ * 
+ * @author Adrian Cole
+ */
+public class BaseTroveExpectTest<T> extends BaseRestApiExpectTest<T> {
+   protected HttpRequest keystoneAuthWithUsernameAndPassword;
+   protected HttpRequest keystoneAuthWithUsernameAndPasswordAndTenantName;
+   protected HttpRequest keystoneAuthWithAccessKeyAndSecretKeyAndTenantName;
+   protected String authToken;
+   protected HttpResponse responseWithKeystoneAccess;
+   protected HttpRequest extensionsOfNovaRequest;
+   protected HttpResponse extensionsOfNovaResponse;
+   protected HttpResponse unmatchedExtensionsOfNovaResponse;
+   protected HttpRequest keystoneAuthWithAccessKeyAndSecretKeyAndTenantId;
+   protected String identityWithTenantId;
+
+   public BaseTroveExpectTest() {
+      provider = "openstack-trove";
+      keystoneAuthWithUsernameAndPassword = KeystoneFixture.INSTANCE.initialAuthWithUsernameAndPassword(identity,
+            credential);
+      keystoneAuthWithUsernameAndPasswordAndTenantName = KeystoneFixture.INSTANCE.initialAuthWithUsernameAndPasswordAndTenantName(identity,
+            credential);
+      keystoneAuthWithAccessKeyAndSecretKeyAndTenantName = KeystoneFixture.INSTANCE.initialAuthWithAccessKeyAndSecretKeyAndTenantName(identity,
+            credential);
+      keystoneAuthWithAccessKeyAndSecretKeyAndTenantId = KeystoneFixture.INSTANCE.initialAuthWithAccessKeyAndSecretKeyAndTenantId(identity,
+              credential);
+      
+      authToken = KeystoneFixture.INSTANCE.getAuthToken();
+      responseWithKeystoneAccess = KeystoneFixture.INSTANCE.responseWithAccess();
+      // now, createContext arg will need tenant prefix
+      identityWithTenantId = KeystoneFixture.INSTANCE.getTenantId() + ":" + identity;
+      identity = KeystoneFixture.INSTANCE.getTenantName() + ":" + identity;
+   }
+
+   @Override
+   protected HttpRequestComparisonType compareHttpRequestAsType(HttpRequest input) {
+      return HttpRequestComparisonType.JSON;
+   }
+   
+   protected HttpRequest.Builder<?> authenticatedGET() {
+      return HttpRequest.builder()
+                        .method("GET")
+                        .addHeader("Accept", MediaType.APPLICATION_JSON)
+                        .addHeader("X-Auth-Token", authToken);
+   }
+   
+   protected HttpRequest.Builder<?> authenticatedPOST() {
+      return HttpRequest.builder()
+                        .method("POST")
+                        .addHeader("Accept", MediaType.APPLICATION_JSON)
+                        .addHeader("X-Auth-Token", authToken);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/parse/ParseFlavorListTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/parse/ParseFlavorListTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/parse/ParseFlavorListTest.java
new file mode 100644
index 0000000..39361cf
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/parse/ParseFlavorListTest.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.openstack.trove.v1.parse;
+
+import java.util.Set;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.http.Uris;
+import org.jclouds.json.BaseSetParserTest;
+import org.jclouds.openstack.trove.v1.domain.Flavor;
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.openstack.v2_0.domain.Link.Relation;
+import org.jclouds.rest.annotations.SelectJson;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * 
+ * @author Zack Shoylev
+ */
+
+@Test(groups = "unit", testName = "ParseFlavorTest")
+public class ParseFlavorListTest extends BaseSetParserTest<Flavor> {
+
+   @Override
+   public String resource() {
+      return "/flavor_list.json";
+   }
+
+   @Override
+   @Consumes(MediaType.APPLICATION_JSON)
+   @SelectJson("flavors")
+   public Set<Flavor> expected() {
+      return ImmutableSet
+            .of(Flavor.builder()
+                  .id(1)
+                  .name("512MB Instance")
+                  .ram(512)
+                  .links(ImmutableList.of(
+                          Link.create(Relation.SELF, Uris.uriBuilder("https://localhost:8778/v1.0/811050/flavors/1").build() ),
+                          Link.create(Relation.BOOKMARK, Uris.uriBuilder("https://localhost:8778/flavors/1").build() )
+                          ))
+                  .build(),
+                  Flavor.builder()
+                  .id(2)
+                  .name("1GB Instance")
+                  .ram(1024)
+                  .links(ImmutableList.of(
+                          Link.create(Relation.SELF, Uris.uriBuilder("https://localhost:8778/v1.0/811050/flavors/2").build() ),
+                          Link.create(Relation.BOOKMARK, Uris.uriBuilder("https://localhost:8778/flavors/2").build() )
+                          ))
+                  .build(),
+                  Flavor.builder()
+                  .id(3)
+                  .name("2GB Instance")
+                  .ram(2048)
+                  .links(ImmutableList.of(
+                          Link.create(Relation.SELF, Uris.uriBuilder("https://localhost:8778/v1.0/811050/flavors/3").build() ),
+                          Link.create(Relation.BOOKMARK, Uris.uriBuilder("https://localhost:8778/flavors/3").build() )
+                          ))
+                  .build(),
+                  Flavor.builder()
+                  .id(4)
+                  .name("4GB Instance")
+                  .ram(4096)
+                  .links(ImmutableList.of(
+                          Link.create(Relation.SELF, Uris.uriBuilder("https://localhost:8778/v1.0/811050/flavors/4").build() ),
+                          Link.create(Relation.BOOKMARK, Uris.uriBuilder("https://localhost:8778/flavors/4").build() )
+                          ))
+                  .build(),
+                  Flavor.builder()
+                  .id(5)
+                  .name("8GB Instance")
+                  .ram(8192)
+                  .links(ImmutableList.of(
+                          Link.create(Relation.SELF, Uris.uriBuilder("https://localhost:8778/v1.0/811050/flavors/5").build() ),
+                          Link.create(Relation.BOOKMARK, Uris.uriBuilder("https://localhost:8778/flavors/5").build() )
+                          ))
+                  .build(),
+                  Flavor.builder()
+                  .id(6)
+                  .name("16GB Instance")
+                  .ram(16384)
+                  .links(ImmutableList.of(
+                          Link.create(Relation.SELF, Uris.uriBuilder("https://localhost:8778/v1.0/811050/flavors/6").build() ),
+                          Link.create(Relation.BOOKMARK, Uris.uriBuilder("https://localhost:8778/flavors/6").build() )
+                          ))
+                  .build());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/parse/ParseInstanceListTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/parse/ParseInstanceListTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/parse/ParseInstanceListTest.java
new file mode 100644
index 0000000..995404e
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/parse/ParseInstanceListTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.openstack.trove.v1.parse;
+
+import java.util.Set;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.http.Uris;
+import org.jclouds.json.BaseSetParserTest;
+import org.jclouds.openstack.trove.v1.domain.Flavor;
+import org.jclouds.openstack.trove.v1.domain.Instance;
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.openstack.v2_0.domain.Link.Relation;
+import org.jclouds.rest.annotations.SelectJson;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * 
+ * @author Zack Shoylev
+ */
+
+@Test(groups = "unit", testName = "ParseInstanceTest")
+public class ParseInstanceListTest extends BaseSetParserTest<Instance> {
+
+   @Override
+   public String resource() {
+      return "/instance_list.json";
+   }
+
+   /*
+    * The instance needs to be comparable for this test to work 
+    * */
+   @Override
+   @Consumes(MediaType.APPLICATION_JSON)
+   @SelectJson("instances")
+   public Set<Instance> expected() {
+      return ImmutableSet
+            .of(Instance.builder()
+                  .id("098653ba-218b-47ce-936a-e0b749101f81")
+                  .name("xml_rack_instance")
+                  .size(2)
+                  .flavor(
+                          Flavor.builder()
+                              .id(1)
+                              .links(ImmutableList.of(
+                                              Link.create(Relation.SELF, Uris.uriBuilder("https://ord.databases.api.rackspacecloud.com/v1.0/1234/flavors/1").build() ),
+                                              Link.create(Relation.BOOKMARK, Uris.uriBuilder("https://ord.databases.api.rackspacecloud.com/flavors/1").build())))
+                              .build()
+                         )
+                  .status(Instance.Status.ACTIVE)
+                  .links(ImmutableList.of(
+                          Link.create(Relation.SELF, Uris.uriBuilder("https://ord.databases.api.rackspacecloud.com/v1.0/1234/instances/098653ba-218b-47ce-936a-e0b749101f81").build() ),
+                          Link.create(Relation.BOOKMARK, Uris.uriBuilder("https://ord.databases.api.rackspacecloud.com/instances/098653ba-218b-47ce-936a-e0b749101f81").build() )
+                          ))
+                  .build(),
+                  Instance.builder()
+                  .id("44b277eb-39be-4921-be31-3d61b43651d7")
+                  .name("json_rack_instance")
+                  .size(2)
+                  .flavor(
+                          Flavor.builder()
+                              .id(1)
+                              .links(ImmutableList.of(
+                                              Link.create(Relation.SELF, Uris.uriBuilder("https://ord.databases.api.rackspacecloud.com/v1.0/1234/flavors/1").build() ),
+                                              Link.create(Relation.BOOKMARK, Uris.uriBuilder("https://ord.databases.api.rackspacecloud.com/flavors/1").build())))
+                              .build()
+                         )
+                  .status(Instance.Status.ACTIVE)
+                  .links(ImmutableList.of(
+                          Link.create(Relation.SELF, Uris.uriBuilder("https://ord.databases.api.rackspacecloud.com/v1.0/1234/instances/44b277eb-39be-4921-be31-3d61b43651d7").build() ),
+                          Link.create(Relation.BOOKMARK, Uris.uriBuilder("https://ord.databases.api.rackspacecloud.com/instances/44b277eb-39be-4921-be31-3d61b43651d7").build() )
+                          ))
+                  .build() 
+                  );
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/parse/ParseUserListTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/parse/ParseUserListTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/parse/ParseUserListTest.java
new file mode 100644
index 0000000..e62fbf4
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/parse/ParseUserListTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.openstack.trove.v1.parse;
+
+import java.util.Set;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+import org.jclouds.json.BaseSetParserTest;
+import org.jclouds.openstack.trove.v1.domain.User;
+import org.jclouds.rest.annotations.SelectJson;
+import org.testng.annotations.Test;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * 
+ * @author Zack Shoylev
+ */
+
+@Test(groups = "unit", testName = "ParseUserTest")
+public class ParseUserListTest extends BaseSetParserTest<User> {
+
+   @Override
+   public String resource() {
+      return "/trove_user_list.json";
+   }
+
+   /*
+    * The user needs to be comparable for this test to work 
+    * */
+   @Override
+   @Consumes(MediaType.APPLICATION_JSON)
+   @SelectJson("users")
+   public Set<User> expected() {
+      return ImmutableSet
+            .of(User.builder()
+                  .name("dbuser1")
+                  .host("%")
+                  .build(),
+                  User.builder()
+                  .name("dbuser2")
+                  .host("%")
+                  .databases( ImmutableSet.of( 
+                          "databaseB",
+                          "databaseC") )
+                  .build(),
+                  User.builder().name("dbuser3").host("%").build(),
+                  User.builder().name("demouser").host("%").databases(
+                          ImmutableSet.of("sampledb"))
+                          .build()
+                  );
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/utils/TroveUtilsExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/utils/TroveUtilsExpectTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/utils/TroveUtilsExpectTest.java
new file mode 100644
index 0000000..1170710
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/utils/TroveUtilsExpectTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.openstack.trove.v1.utils;
+
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+import java.util.List;
+
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.trove.v1.TroveApi;
+import org.jclouds.openstack.trove.v1.domain.Instance;
+import org.jclouds.openstack.trove.v1.internal.BaseTroveApiExpectTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Tests TroveUtils
+ *
+ * @author Zack Shoylev
+ */
+@Test(groups = "unit", testName = "InstanceApiExpectTest")
+public class TroveUtilsExpectTest extends BaseTroveApiExpectTest {
+    
+    public void testHelperCreateInstance() {
+        HttpRequest createInstance = authenticatedGET().endpoint(URI.create("http://172.16.0.1:8776/v1/3456/instances"))
+                                                       .method("POST")
+                                                       .payload(payloadFromResourceWithContentType("/instance_create_request.json", MediaType.APPLICATION_JSON))
+                                                       .build();
+        HttpResponse createInstanceSuccess = HttpResponse.builder().statusCode(200).payload(payloadFromResource("/instance_create.json")).build();
+        HttpResponse createInstanceFail = HttpResponse.builder().statusCode(404).payload(payloadFromResource("/instance_create.json")).build();
+        HttpRequest getInstance = authenticatedGET().endpoint(URI.create("http://172.16.0.1:8776/v1/3456/instances/44b277eb-39be-4921-be31-3d61b43651d7")).build();
+        HttpResponse badStatus = HttpResponse.builder().statusCode(200).payload(payloadFromResource("/instance_get_bad_instance.json")).build();
+        HttpResponse goodStatus = HttpResponse.builder().statusCode(200).payload(payloadFromResource("/instance_get.json")).build();
+        HttpResponse deletedStatus = HttpResponse.builder().statusCode(404).payload(payloadFromResource("/instance_get.json")).build();
+        HttpRequest deleteInstance = authenticatedGET().endpoint(URI.create("http://172.16.0.1:8776/v1/3456/instances/44b277eb-39be-4921-be31-3d61b43651d7")).method("DELETE").build();
+        HttpResponse deleteInstanceResponse = HttpResponse.builder().statusCode(202).build();
+
+        List<HttpRequest> requests = ImmutableList.of(  keystoneAuthWithUsernameAndPasswordAndTenantName, createInstance,     createInstance,     createInstance,        getInstance, deleteInstance,         getInstance,   createInstance,     createInstance,        getInstance);
+        List<HttpResponse> responses = ImmutableList.of(responseWithKeystoneAccess,                       createInstanceFail, createInstanceFail, createInstanceSuccess, badStatus,   deleteInstanceResponse, deletedStatus, createInstanceFail, createInstanceSuccess, goodStatus); 
+
+        TroveApi api = orderedRequestsSendResponses(requests, responses);
+
+        TroveUtils utils = new TroveUtils(api);
+        Instance instance = utils.getWorkingInstance("RegionOne", "json_rack_instance", "1", 2);
+        assertEquals(instance.getSize(),2);
+        assertEquals(instance.getName(), "json_rack_instance");  
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/access_rax_us.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/access_rax_us.json b/apis/openstack-trove/src/test/resources/access_rax_us.json
new file mode 100644
index 0000000..b90bebc
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/access_rax_us.json
@@ -0,0 +1,168 @@
+{
+    "access": {
+        "token": {
+            "id": "myToken",
+            "expires": "2012-09-30T17:15:32.000-05:00",
+            "tenant": {
+                "id": "717071",
+                "name": "717071"
+            }
+        },
+        "serviceCatalog": [
+            {
+                "endpoints": [
+                    {
+                        "tenantId": "717071",
+                        "publicURL": "https://dns.api.rackspacecloud.com/v1.0/717071"
+                    }
+                ],
+                "name": "cloudDNS",
+                "type": "rax:dns"
+            },
+            {
+                "endpoints": [
+                    {
+                        "tenantId": "717071",
+                        "publicURL": "https://monitoring.api.rackspacecloud.com/v1.0/717071"
+                    }
+                ],
+                "name": "cloudMonitoring",
+                "type": "rax:monitor"
+            },
+            {
+                "endpoints": [
+                    {
+                        "region": "DFW",
+                        "tenantId": "717071",
+                        "publicURL": "https://dfw.servers.api.rackspacecloud.com/v2/717071",
+                        "versionInfo": "https://dfw.servers.api.rackspacecloud.com/v2",
+                        "versionList": "https://dfw.servers.api.rackspacecloud.com/",
+                        "versionId": "2"
+                    },
+                    {
+                        "region": "ORD",
+                        "tenantId": "717071",
+                        "publicURL": "https://ord.servers.api.rackspacecloud.com/v2/717071",
+                        "versionInfo": "https://ord.servers.api.rackspacecloud.com/v2",
+                        "versionList": "https://ord.servers.api.rackspacecloud.com/",
+                        "versionId": "2"
+                    }
+                ],
+                "name": "cloudServersOpenStack",
+                "type": "compute"
+            },
+            {
+                "endpoints": [
+                    {
+                        "region": "ORD",
+                        "tenantId": "717071",
+                        "publicURL": "https://ord.loadbalancers.api.rackspacecloud.com/v1.0/717071"
+                    },
+                    {
+                        "region": "DFW",
+                        "tenantId": "717071",
+                        "publicURL": "https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/717071"
+                    }
+                ],
+                "name": "cloudLoadBalancers",
+                "type": "rax:load-balancer"
+            },
+            {
+                "endpoints": [
+                    {
+                        "region": "DFW",
+                        "tenantId": "717071",
+                        "publicURL": "https://dfw.databases.api.rackspacecloud.com/v1.0/717071"
+                    },
+                    {
+                        "region": "ORD",
+                        "tenantId": "717071",
+                        "publicURL": "https://ord.databases.api.rackspacecloud.com/v1.0/717071"
+                    },
+                    {
+                        "region": "SYD",
+                        "tenantId": "717071",
+                        "publicURL": "https://syd.databases.api.rackspacecloud.com/v1.0/717071"
+                    }
+                ],
+                "name": "cloudDatabases",
+                "type": "rax:database"
+            },
+            {
+                "endpoints": [
+                    {
+                        "region": "DFW",
+                        "tenantId": "MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9",
+                        "publicURL": "https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9",
+                        "internalURL": "https://snet-storage101.dfw1.clouddrive.com/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9"
+                    },
+                    {
+                        "region": "ORD",
+                        "tenantId": "MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9",
+                        "publicURL": "https://storage101.ord1.clouddrive.com/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9",
+                        "internalURL": "https://snet-storage101.ord1.clouddrive.com/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9"
+                    }
+                ],
+                "name": "cloudFiles",
+                "type": "object-store"
+            },
+            {
+                "endpoints": [
+                    {
+                        "region": "DFW",
+                        "tenantId": "MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9",
+                        "publicURL": "https://cdn1.clouddrive.com/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9"
+                    },
+                    {
+                        "region": "ORD",
+                        "tenantId": "MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9",
+                        "publicURL": "https://cdn2.clouddrive.com/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9"
+                    }
+                ],
+                "name": "cloudFilesCDN",
+                "type": "rax:object-cdn"
+            },
+            {
+                "endpoints": [
+                    {
+                        "tenantId": "717071",
+                        "publicURL": "https://servers.api.rackspacecloud.com/v1.0/717071",
+                        "versionInfo": "https://servers.api.rackspacecloud.com/v1.0",
+                        "versionList": "https://servers.api.rackspacecloud.com/",
+                        "versionId": "1.0"
+                    }
+                ],
+                "name": "cloudServers",
+                "type": "compute"
+            },
+            {
+                "endpoints": [
+                    {
+                         "publicURL": "https://ord.blockstorage.api.rackspacecloud.com/v1/717071",
+                         "tenantId": "717071",
+                         "region": "ORD"
+                    },
+                    {
+                        "region": "DFW",
+                        "tenantId": "717071",
+                        "publicURL": "https://dfw.blockstorage.api.rackspacecloud.com/v1/717071"
+                    }
+                ],
+                "name": "cloudBlockStorage",
+                "type": "volume"
+            }
+        ],
+        "user": {
+            "id": "224085",
+            "roles": [
+                {
+                    "id": "3",
+                    "description": "User Admin Role.",
+                    "name": "identity:user-admin"
+                }
+            ],
+            "name": "myUsername",
+            "RAX-AUTH:defaultRegion": "DFW"
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/database_create_request.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/database_create_request.json b/apis/openstack-trove/src/test/resources/database_create_request.json
new file mode 100644
index 0000000..e032a2d
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/database_create_request.json
@@ -0,0 +1,9 @@
+{
+    "databases": [
+        {    
+            "character_set": "utf8", 
+            "collate": "utf8_general_ci", 
+            "name": "testingdb"
+        } 
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/database_create_simple_request.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/database_create_simple_request.json b/apis/openstack-trove/src/test/resources/database_create_simple_request.json
new file mode 100644
index 0000000..6f9fd00
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/database_create_simple_request.json
@@ -0,0 +1,7 @@
+{
+    "databases": [
+        {   
+            "name": "testingdb"
+        } 
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/database_list.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/database_list.json b/apis/openstack-trove/src/test/resources/database_list.json
new file mode 100644
index 0000000..a895ddc
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/database_list.json
@@ -0,0 +1,19 @@
+{
+    "databases": [
+        {
+            "name": "anotherdb"
+        }, 
+        {
+            "name": "nextround"
+        }, 
+        {
+            "name": "oneMoreDB"
+        }, 
+        {
+            "name": "sampledb"
+        }, 
+        {
+            "name": "testingdb"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/flavor_get.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/flavor_get.json b/apis/openstack-trove/src/test/resources/flavor_get.json
new file mode 100644
index 0000000..9290fa7
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/flavor_get.json
@@ -0,0 +1,17 @@
+{
+    "flavor":{
+        "id":1,
+        "links":[
+            {
+                "href":"https://ord.databases.api.rackspacecloud.com/v1.0/1234/flavors/1",
+                "rel":"self"
+            },
+            {
+                "href":"https://ord.databases.api.rackspacecloud.com/flavors/1",
+                "rel":"bookmark"
+            }
+        ],
+        "name":"512MB Instance",
+        "ram":512
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/flavor_list.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/flavor_list.json b/apis/openstack-trove/src/test/resources/flavor_list.json
new file mode 100644
index 0000000..edc364c
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/flavor_list.json
@@ -0,0 +1,94 @@
+{
+    "flavors":[
+        {
+            "ram":512,
+            "id":1,
+            "links":[
+                {
+                    "href":"https://localhost:8778/v1.0/811050/flavors/1",
+                    "rel":"self"
+                },
+                {
+                    "href":"https://localhost:8778/flavors/1",
+                    "rel":"bookmark"
+                }
+            ],
+            "name":"512MB Instance"
+        },
+        {
+            "ram":1024,
+            "id":2,
+            "links":[
+                {
+                    "href":"https://localhost:8778/v1.0/811050/flavors/2",
+                    "rel":"self"
+                },
+                {
+                    "href":"https://localhost:8778/flavors/2",
+                    "rel":"bookmark"
+                }
+            ],
+            "name":"1GB Instance"
+        },
+        {
+            "ram":2048,
+            "id":3,
+            "links":[
+                {
+                    "href":"https://localhost:8778/v1.0/811050/flavors/3",
+                    "rel":"self"
+                },
+                {
+                    "href":"https://localhost:8778/flavors/3",
+                    "rel":"bookmark"
+                }
+            ],
+            "name":"2GB Instance"
+        },
+        {
+            "ram":4096,
+            "id":4,
+            "links":[
+                {
+                    "href":"https://localhost:8778/v1.0/811050/flavors/4",
+                    "rel":"self"
+                },
+                {
+                    "href":"https://localhost:8778/flavors/4",
+                    "rel":"bookmark"
+                }
+            ],
+            "name":"4GB Instance"
+        },
+        {
+            "ram":8192,
+            "id":5,
+            "links":[
+                {
+                    "href":"https://localhost:8778/v1.0/811050/flavors/5",
+                    "rel":"self"
+                },
+                {
+                    "href":"https://localhost:8778/flavors/5",
+                    "rel":"bookmark"
+                }
+            ],
+            "name":"8GB Instance"
+        },
+        {
+            "ram":16384,
+            "id":6,
+            "links":[
+                {
+                    "href":"https://localhost:8778/v1.0/811050/flavors/6",
+                    "rel":"self"
+                },
+                {
+                    "href":"https://localhost:8778/flavors/6",
+                    "rel":"bookmark"
+                }
+            ],
+            "name":"16GB Instance"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/instance_create.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/instance_create.json b/apis/openstack-trove/src/test/resources/instance_create.json
new file mode 100644
index 0000000..cfb4106
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/instance_create.json
@@ -0,0 +1,35 @@
+{
+    "instance": {
+        "created": "2013-03-18T19:09:17", 
+        "flavor": {
+            "id": "1", 
+            "links": [
+                {
+                    "href": "https://ord.databases.api.rackspacecloud.com/v1.0/1234/flavors/1", 
+                    "rel": "self"
+                }, 
+                {
+                    "href": "https://ord.databases.api.rackspacecloud.com/flavors/1", 
+                    "rel": "bookmark"
+                }
+            ]
+        }, 
+        "id": "44b277eb-39be-4921-be31-3d61b43651d7", 
+        "links": [
+            {
+                "href": "https://ord.databases.api.rackspacecloud.com/v1.0/1234/instances/44b277eb-39be-4921-be31-3d61b43651d7", 
+                "rel": "self"
+            }, 
+            {
+                "href": "https://ord.databases.api.rackspacecloud.com/instances/44b277eb-39be-4921-be31-3d61b43651d7", 
+                "rel": "bookmark"
+            }
+        ], 
+        "name": "json_rack_instance", 
+        "status": "BUILD", 
+        "updated": "2013-03-18T19:09:17", 
+        "volume": {
+            "size": 2
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/instance_create_request.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/instance_create_request.json b/apis/openstack-trove/src/test/resources/instance_create_request.json
new file mode 100644
index 0000000..a1031b9
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/instance_create_request.json
@@ -0,0 +1,9 @@
+{
+    "instance":{
+        "name":"json_rack_instance",
+        "volume":{
+            "size":2
+        },
+        "flavorRef":"1"
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/instance_get.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/instance_get.json b/apis/openstack-trove/src/test/resources/instance_get.json
new file mode 100644
index 0000000..baf8708
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/instance_get.json
@@ -0,0 +1,37 @@
+{
+    "instance": {
+        "created": "2013-03-18T19:09:17", 
+        "flavor": {
+            "id": "1", 
+            "links": [
+                {
+                    "href": "https://ord.databases.api.rackspacecloud.com/v1.0/1234/flavors/1", 
+                    "rel": "self"
+                }, 
+                {
+                    "href": "https://ord.databases.api.rackspacecloud.com/flavors/1", 
+                    "rel": "bookmark"
+                }
+            ]
+        }, 
+        "hostname": "e09ad9a3f73309469cf1f43d11e79549caf9acf2.rackspaceclouddb.com",
+        "id": "44b277eb-39be-4921-be31-3d61b43651d7", 
+        "links": [
+            {
+                "href": "https://ord.databases.api.rackspacecloud.com/v1.0/1234/instances/44b277eb-39be-4921-be31-3d61b43651d7", 
+                "rel": "self"
+            }, 
+            {
+                "href": "https://ord.databases.api.rackspacecloud.com/instances/44b277eb-39be-4921-be31-3d61b43651d7", 
+                "rel": "bookmark"
+            }
+        ], 
+        "name": "json_rack_instance", 
+        "status": "ACTIVE", 
+        "updated": "2013-03-18T19:09:17", 
+        "volume": {
+            "size": 2, 
+            "used": 0.16368598397821188
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/instance_get_bad_instance.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/instance_get_bad_instance.json b/apis/openstack-trove/src/test/resources/instance_get_bad_instance.json
new file mode 100644
index 0000000..99b8688
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/instance_get_bad_instance.json
@@ -0,0 +1,37 @@
+{
+    "instance": {
+        "created": "2013-03-18T19:09:17", 
+        "flavor": {
+            "id": "1", 
+            "links": [
+                {
+                    "href": "https://ord.databases.api.rackspacecloud.com/v1.0/1234/flavors/1", 
+                    "rel": "self"
+                }, 
+                {
+                    "href": "https://ord.databases.api.rackspacecloud.com/flavors/1", 
+                    "rel": "bookmark"
+                }
+            ]
+        }, 
+        "hostname": "e09ad9a3f73309469cf1f43d11e79549caf9acf2.rackspaceclouddb.com",
+        "id": "44b277eb-39be-4921-be31-3d61b43651d7", 
+        "links": [
+            {
+                "href": "https://ord.databases.api.rackspacecloud.com/v1.0/1234/instances/44b277eb-39be-4921-be31-3d61b43651d7", 
+                "rel": "self"
+            }, 
+            {
+                "href": "https://ord.databases.api.rackspacecloud.com/instances/44b277eb-39be-4921-be31-3d61b43651d7", 
+                "rel": "bookmark"
+            }
+        ], 
+        "name": "json_rack_instance", 
+        "status": "ERROR", 
+        "updated": "2013-03-18T19:09:17", 
+        "volume": {
+            "size": 2, 
+            "used": 0.16368598397821188
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/instance_is_rooted.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/instance_is_rooted.json b/apis/openstack-trove/src/test/resources/instance_is_rooted.json
new file mode 100644
index 0000000..f3990b4
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/instance_is_rooted.json
@@ -0,0 +1,3 @@
+{
+    "rootEnabled": true
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/instance_is_rooted_false.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/instance_is_rooted_false.json b/apis/openstack-trove/src/test/resources/instance_is_rooted_false.json
new file mode 100644
index 0000000..04e4e6d
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/instance_is_rooted_false.json
@@ -0,0 +1,3 @@
+{
+    "rootEnabled": false
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/instance_list.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/instance_list.json b/apis/openstack-trove/src/test/resources/instance_list.json
new file mode 100644
index 0000000..c1834a2
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/instance_list.json
@@ -0,0 +1,66 @@
+{
+    "instances": [
+        {
+            "flavor": {
+                "id": "1", 
+                "links": [
+                    {
+                        "href": "https://ord.databases.api.rackspacecloud.com/v1.0/1234/flavors/1", 
+                        "rel": "self"
+                    }, 
+                    {
+                        "href": "https://ord.databases.api.rackspacecloud.com/flavors/1", 
+                        "rel": "bookmark"
+                    }
+                ]
+            }, 
+            "id": "098653ba-218b-47ce-936a-e0b749101f81", 
+            "links": [
+                {
+                    "href": "https://ord.databases.api.rackspacecloud.com/v1.0/1234/instances/098653ba-218b-47ce-936a-e0b749101f81", 
+                    "rel": "self"
+                }, 
+                {
+                    "href": "https://ord.databases.api.rackspacecloud.com/instances/098653ba-218b-47ce-936a-e0b749101f81", 
+                    "rel": "bookmark"
+                }
+            ], 
+            "name": "xml_rack_instance", 
+            "status": "ACTIVE", 
+            "volume": {
+                "size": 2
+            }
+        }, 
+        {
+            "flavor": {
+                "id": "1", 
+                "links": [
+                    {
+                        "href": "https://ord.databases.api.rackspacecloud.com/v1.0/1234/flavors/1", 
+                        "rel": "self"
+                    }, 
+                    {
+                        "href": "https://ord.databases.api.rackspacecloud.com/flavors/1", 
+                        "rel": "bookmark"
+                    }
+                ]
+            }, 
+            "id": "44b277eb-39be-4921-be31-3d61b43651d7", 
+            "links": [
+                {
+                    "href": "https://ord.databases.api.rackspacecloud.com/v1.0/1234/instances/44b277eb-39be-4921-be31-3d61b43651d7", 
+                    "rel": "self"
+                }, 
+                {
+                    "href": "https://ord.databases.api.rackspacecloud.com/instances/44b277eb-39be-4921-be31-3d61b43651d7", 
+                    "rel": "bookmark"
+                }
+            ], 
+            "name": "json_rack_instance", 
+            "status": "ACTIVE", 
+            "volume": {
+                "size": 2
+            }
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/instance_root.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/instance_root.json b/apis/openstack-trove/src/test/resources/instance_root.json
new file mode 100644
index 0000000..e937b90
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/instance_root.json
@@ -0,0 +1,6 @@
+{
+    "user": {
+        "name": "root", 
+        "password": "12345"
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/logback-test.xml
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/logback-test.xml b/apis/openstack-trove/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..6559c23
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/logback-test.xml
@@ -0,0 +1,69 @@
+<?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="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="BLOBSTOREFILE" class="ch.qos.logback.core.FileAppender">
+        <file>target/test-data/jclouds-blobstore.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="WIREFILE" />
+    </logger>
+
+    <logger name="jclouds.headers">
+        <level value="DEBUG" />
+        <appender-ref ref="WIREFILE" />
+    </logger>
+
+    <logger name="jclouds.blobstore">
+        <level value="DEBUG" />
+        <appender-ref ref="BLOBSTOREFILE" />
+    </logger>
+
+</configuration>

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/logback.xml
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/logback.xml b/apis/openstack-trove/src/test/resources/logback.xml
new file mode 100644
index 0000000..6559c23
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/logback.xml
@@ -0,0 +1,69 @@
+<?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="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="BLOBSTOREFILE" class="ch.qos.logback.core.FileAppender">
+        <file>target/test-data/jclouds-blobstore.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="WIREFILE" />
+    </logger>
+
+    <logger name="jclouds.headers">
+        <level value="DEBUG" />
+        <appender-ref ref="WIREFILE" />
+    </logger>
+
+    <logger name="jclouds.blobstore">
+        <level value="DEBUG" />
+        <appender-ref ref="BLOBSTOREFILE" />
+    </logger>
+
+</configuration>

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/trove_user_list.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/trove_user_list.json b/apis/openstack-trove/src/test/resources/trove_user_list.json
new file mode 100644
index 0000000..546df43
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/trove_user_list.json
@@ -0,0 +1,35 @@
+{
+    "users": [
+        {
+            "databases": [],
+            "host": "%", 
+            "name": "dbuser1"
+        }, 
+        {
+            "databases": [
+                {
+                    "name": "databaseB"
+                }, 
+                {
+                    "name": "databaseC"
+                }
+            ],
+            "host": "%",
+            "name": "dbuser2"
+        }, 
+        {
+            "databases": [], 
+            "name": "dbuser3",
+            "host": "%"
+        }, 
+        {
+            "databases": [
+                {
+                    "name": "sampledb"
+                }
+            ],
+            "host": "%",
+            "name": "demouser"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/resources/user_create_request.json
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/resources/user_create_request.json b/apis/openstack-trove/src/test/resources/user_create_request.json
new file mode 100644
index 0000000..3837b8b
--- /dev/null
+++ b/apis/openstack-trove/src/test/resources/user_create_request.json
@@ -0,0 +1,35 @@
+{
+    "users":[
+        {
+            "databases":[
+                {
+                    "name":"databaseA"
+                }
+            ],
+            "name":"dbuser1",
+            "password":"password"
+        },
+        {
+            "databases":[
+                {
+                    "name":"databaseB"
+                },
+                {
+                    "name":"databaseC"
+                }
+            ],
+            "name":"dbuser2",
+            "password":"password"
+        },
+        {
+            "databases":[
+                {
+                    "name":"databaseD"
+                }
+            ],
+            "name":"dbuser3",
+            "host":"192.168.64.64",
+            "password":"password"
+        }
+    ]
+}