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/08/30 19:19:56 UTC

[2/3] Adds Otter (Rackspace Autoscale) to labs https://issues.apache.org/jira/browse/JCLOUDS-215

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/46f493ac/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/LaunchConfiguration.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/LaunchConfiguration.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/LaunchConfiguration.java
new file mode 100644
index 0000000..a6690ef
--- /dev/null
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/LaunchConfiguration.java
@@ -0,0 +1,341 @@
+/*
+ * 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.autoscale.v1.domain;
+
+import java.beans.ConstructorProperties;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+
+import org.jclouds.rackspace.autoscale.v1.features.GroupApi;
+
+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;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Autoscale LaunchConfiguration.
+ * 
+ * @see GroupApi#create(GroupConfiguration, LaunchConfiguration, List)
+ * @author Zack Shoylev
+ */
+public class LaunchConfiguration implements Comparable<LaunchConfiguration>{
+   private final ImmutableList<LoadBalancer> loadBalancers;
+   private final LaunchConfigurationType type;
+   private final ImmutableList<String> networks;
+   private final ImmutableList<Personality> personalities;
+
+   private final String serverName;
+   private final String serverImageRef;
+   private final String serverFlavorRef;
+   private final String serverDiskConfig;
+   private final ImmutableMap<String, String> serverMetadata;
+
+   @ConstructorProperties({
+      "loadBalancers", "type", "networks", "personalities", "serverName", "serverImageRef", "serverFlavorRef", "serverDiskConfig", "serverMetadata"
+   })
+   protected LaunchConfiguration(List<LoadBalancer> loadBalancers, LaunchConfigurationType type, List<String> networks, List<Personality> personalities, String serverName, String serverImageRef, String serverFlavorRef, String serverDiskConfig, Map<String, String> serverMetadata) {
+      this.loadBalancers = ImmutableList.copyOf(loadBalancers);
+      this.type = type;
+      this.networks = ImmutableList.copyOf(networks);
+      this.personalities = ImmutableList.copyOf(personalities);
+      this.serverName = serverName;
+      this.serverImageRef = serverImageRef;
+      this.serverFlavorRef = serverFlavorRef;
+      this.serverDiskConfig = serverDiskConfig;
+      this.serverMetadata = ImmutableMap.copyOf(serverMetadata);
+   }
+
+   /**
+    * @return the list of load balancers of this LaunchConfiguration.
+    * @see LaunchConfiguration.Builder#loadBalancers(List)
+    */
+   public List<LoadBalancer> getLoadBalancers() {
+      return this.loadBalancers;
+   }
+
+   /**
+    * @return the type for this LaunchConfiguration.
+    * @see LaunchConfigurationType
+    * @see LaunchConfiguration.Builder#type(LaunchConfigurationType)
+    */
+   public LaunchConfigurationType getType() {
+      return this.type;
+   }
+
+   /**
+    * @return the networks for this LaunchConfiguration.
+    * @see LaunchConfiguration#getNetworks()
+    * @see LaunchConfiguration.Builder#networks(List)
+    */
+   public List<String> getNetworks() {
+      return this.networks;
+   }
+
+   /**
+    * @return the personalities for this LaunchConfiguration.
+    * @see Personality
+    * @see LaunchConfiguration.Builder#personalities(List)
+    */
+   public List<Personality> getPersonalities() {
+      return this.personalities;
+   }
+
+   /**
+    * @return the server name for this LaunchConfiguration.
+    * @see LaunchConfiguration.Builder#serverName(String)
+    */
+   public String getServerName() {
+      return this.serverName;
+   }
+
+   /**
+    * @return the server image ref for this LaunchConfiguration.
+    * @see LaunchConfiguration.Builder#serverImageRef(String)
+    */
+   public String getServerImageRef() {
+      return this.serverImageRef;
+   }
+
+   /**
+    * @return the server flavor ref for this LaunchConfiguration.
+    * @see LaunchConfiguration.Builder#serverFlavorRef(String)
+    */
+   public String getServerFlavorRef() {
+      return this.serverFlavorRef;
+   }
+
+   /**
+    * @return the server disk config for this LaunchConfiguration, ex. "AUTO"
+    * @see LaunchConfiguration.Builder#serverDiskConfig(String)
+    */
+   public String getServerDiskConfig() {
+      return this.serverDiskConfig;
+   }
+
+   /**
+    * @return the server metadata for this LaunchConfiguration.
+    * @see LaunchConfiguration.Builder#serverMetadata(ImmutableMap)
+    */
+   public ImmutableMap<String, String> getServerMetadata() {
+      return this.serverMetadata;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(loadBalancers, type, networks, personalities, serverName, serverImageRef, serverFlavorRef, serverDiskConfig, serverMetadata);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      LaunchConfiguration that = LaunchConfiguration.class.cast(obj);
+      return Objects.equal(this.loadBalancers, that.loadBalancers) && 
+            Objects.equal(this.type, that.type) &&
+            Objects.equal(this.networks, that.networks) &&
+            Objects.equal(this.personalities, that.personalities) &&
+            Objects.equal(this.serverName, that.serverName) &&      
+            Objects.equal(this.serverImageRef, that.serverImageRef) &&
+            Objects.equal(this.serverFlavorRef, that.serverFlavorRef) &&
+            Objects.equal(this.serverDiskConfig, that.serverDiskConfig) &&
+            Objects.equal(this.serverMetadata, that.serverMetadata);
+   }
+
+   protected ToStringHelper string() {
+      return Objects.toStringHelper(this)
+            .add("loadBalancers", loadBalancers)
+            .add("type", type)
+            .add("networks", networks)
+            .add("personalities", personalities)
+            .add("serverName", serverName)
+            .add("serverImageRef", serverImageRef)
+            .add("serverFlavorRef", serverFlavorRef)
+            .add("serverDiskConfig", serverDiskConfig)
+            .add("serverMetadata", serverMetadata);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   public static Builder builder() { 
+      return new Builder();
+   }
+
+   public Builder toBuilder() { 
+      return new Builder().fromLaunchConfiguration(this);
+   }
+
+   public static class Builder {
+      protected List<LoadBalancer> loadBalancers;
+      protected LaunchConfigurationType type;
+      protected List<String> networks;
+      protected List<Personality> personalities;
+
+      protected String serverName;
+      protected String serverImageRef;
+      protected String serverFlavorRef;
+      protected String serverDiskConfig;
+      protected ImmutableMap<String, String> serverMetadata;
+
+      /** 
+       * @param loadBalancers The load balancers of this LaunchConfiguration.
+       * @return The builder object.
+       * @see LaunchConfiguration#getLoadBalancers()
+       */
+      public Builder loadBalancers(List<LoadBalancer> loadBalancers) {
+         this.loadBalancers = loadBalancers;
+         return this;
+      }
+
+      /** 
+       * @param type The type for this LaunchConfiguration.
+       * @return The builder object.
+       * @see LaunchConfiguration#getType()
+       */
+      public Builder type(LaunchConfigurationType type) {
+         this.type = type;
+         return this;
+      }
+
+      /** 
+       * @param networks The networks of this LaunchConfiguration.
+       * @return The builder object.
+       * @see LaunchConfiguration#getNetworks()
+       */
+      public Builder networks(List<String> networks) {
+         this.networks = networks;
+         return this;
+      }
+
+      /** 
+       * @param personalities The personalities of this LaunchConfiguration.
+       * @return The builder object.
+       * @see Personality
+       * @see LaunchConfiguration#getPersonalities()
+       */
+      public Builder personalities(List<Personality> personalities) {
+         this.personalities = personalities;
+         return this;
+      }
+
+      /** 
+       * @param serverName The serverName of this LaunchConfiguration.
+       * @return The builder object.
+       * @see LaunchConfiguration#getServerName()
+       */
+      public Builder serverName(String serverName) {
+         this.serverName = serverName;
+         return this;
+      }
+
+      /** 
+       * @param serverImageRef The serverImageRef of this LaunchConfiguration.
+       * @return The builder object.
+       * @see LaunchConfiguration#getServerImageRef()
+       */
+      public Builder serverImageRef(String serverImageRef) {
+         this.serverImageRef = serverImageRef;
+         return this;
+      }
+
+      /** 
+       * @param serverFlavorRef The serverFlavorRef of this LaunchConfiguration.
+       * @return The builder object.
+       * @see LaunchConfiguration#getServerFlavorRef()
+       */
+      public Builder serverFlavorRef(String serverFlavorRef) {
+         this.serverFlavorRef = serverFlavorRef;
+         return this;
+      }
+
+      /** 
+       * @param serverDiskConfig The serverDiskConfig of this LaunchConfiguration.
+       * @return The builder object.
+       * @see LaunchConfiguration#getServerDiskConfig()
+       */
+      public Builder serverDiskConfig(String serverDiskConfig) {
+         this.serverDiskConfig = serverDiskConfig;
+         return this;
+      }
+
+      /** 
+       * @param serverMetadata The serverMetadata of this LaunchConfiguration.
+       * @return The builder object.
+       * @see LaunchConfiguration#getServerMetadata()
+       */
+      public Builder serverMetadata(Map<String, String> serverMetadata) {
+         this.serverMetadata = ImmutableMap.copyOf(serverMetadata);
+         return this;
+      }
+
+      /**
+       * @return A new LaunchConfiguration object.
+       */
+      public LaunchConfiguration build() {
+         return new LaunchConfiguration(loadBalancers, type, networks, personalities, serverName, serverImageRef, serverFlavorRef, serverDiskConfig, serverMetadata);
+      }
+
+      public Builder fromLaunchConfiguration(LaunchConfiguration in) {
+         return this
+               .loadBalancers(in.getLoadBalancers())
+               .type(in.getType())
+               .networks(in.getNetworks())
+               .personalities(in.getPersonalities())
+               .serverName(in.getServerName())
+               .serverImageRef(in.getServerImageRef())
+               .serverFlavorRef(in.getServerFlavorRef())
+               .serverDiskConfig(in.getServerDiskConfig())
+               .serverMetadata(in.getServerMetadata());
+      }        
+   }
+
+   @Override
+   public int compareTo(LaunchConfiguration that) {
+      return this.getServerName().compareTo(that.getServerName());
+   }
+
+   /**
+    * Enumerates launch configuration types
+    */
+   public static enum LaunchConfigurationType {
+      LAUNCH_SERVER("launch_server");
+
+      private final String name;
+
+      private LaunchConfigurationType(String name) {
+         this.name = name;
+      }
+
+      public String toString() {
+         return name;
+      }
+
+      public static Optional<LaunchConfigurationType> getByValue(String value){
+         for (final LaunchConfigurationType element : EnumSet.allOf(LaunchConfigurationType.class)) {
+            if (element.toString().equals(value)) {
+               return Optional.of(element);
+            }
+         }
+         return Optional.absent();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/46f493ac/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/LoadBalancer.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/LoadBalancer.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/LoadBalancer.java
new file mode 100644
index 0000000..004bb97
--- /dev/null
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/LoadBalancer.java
@@ -0,0 +1,129 @@
+/*
+ * 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.autoscale.v1.domain;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.beans.ConstructorProperties;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Autoscale LoadBalancer. Part of the launch configuration.
+ * 
+ * @see LaunchConfiguration#getLoadBalancers()
+ * @author Zack Shoylev
+ */
+public class LoadBalancer { 
+   private final int port;
+   @SerializedName("loadBalancerId")
+   private final int id;
+
+   @ConstructorProperties({ "port", "loadBalancerId" })
+   protected LoadBalancer(int port, int id) {
+      checkArgument(port >= 0, "port should be non-negative");
+      this.port = port;
+      checkArgument(id >= 0, "id should be non-negative");
+      this.id = id;
+   }
+
+   /**
+    * @return the socket port number of this LoadBalancer.
+    * @see LoadBalancer.Builder#port(int)
+    */
+   public int getPort() {
+      return this.port;
+   }
+
+   /**
+    * @return the id for this LoadBalancer.
+    * @see LoadBalancer.Builder#id(int)
+    */
+   public int getId() {
+      return this.id;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(port, id);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null || getClass() != obj.getClass())
+         return false;
+      LoadBalancer that = LoadBalancer.class.cast(obj);
+      return Objects.equal(this.port, that.port) && Objects.equal(this.id, that.id);
+   }
+
+   protected ToStringHelper string() {
+      return Objects.toStringHelper(this).add("port", port).add("id", id);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return new Builder().fromLoadBalancer(this);
+   }
+
+   public static class Builder {
+      protected int port;
+      protected int id;
+
+      /**
+       * @param port The port of this LoadBalancer.
+       * @return The builder object.
+       * @see LoadBalancer#getPort()
+       */
+      public Builder port(int port) {
+         this.port = port;
+         return this;
+      }
+
+      /**
+       * @param id The id of this LoadBalancer.
+       * @return The builder object.
+       * @see LoadBalancer#getId()
+       */
+      public Builder id(int id) {
+         this.id = id;
+         return this;
+      }
+
+      /**
+       * @return A new LoadBalancer object.
+       */
+      public LoadBalancer build() {
+         return new LoadBalancer(port, id);
+      }
+
+      public Builder fromLoadBalancer(LoadBalancer in) {
+         return this.port(in.getPort()).id(in.getId());
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/46f493ac/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/Personality.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/Personality.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/Personality.java
new file mode 100644
index 0000000..4b2400f
--- /dev/null
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/Personality.java
@@ -0,0 +1,125 @@
+/*
+ * 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.autoscale.v1.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.beans.ConstructorProperties;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+
+/**
+ * Autoscale Personality. Part of the launch configuration.
+ * 
+ * @see LaunchConfiguration#getPersonalities()
+ * @author Zack Shoylev
+ */
+public class Personality {
+   private final String path;
+   private final String contents;
+
+   @ConstructorProperties({ "path", "contents" })
+   protected Personality(String path, String contents) {
+      this.path = checkNotNull(path, "path should not be null");
+      this.contents = checkNotNull(contents, "contents should not be null");
+   }
+
+   /**
+    * @return the path of this Personality.
+    * @see Personality.Builder#path(String)
+    */
+   public String getPath() {
+      return this.path;
+   }
+
+   /**
+    * @return the contents for this Personality.
+    * @see Personality.Builder#contents(String)
+    */
+   public String getContents() {
+      return this.contents;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(path, contents);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null || getClass() != obj.getClass())
+         return false;
+      Personality that = Personality.class.cast(obj);
+      return Objects.equal(this.path, that.path) && Objects.equal(this.contents, that.contents);
+   }
+
+   protected ToStringHelper string() {
+      return Objects.toStringHelper(this).add("path", path).add("contents", contents);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return new Builder().fromPersonality(this);
+   }
+
+   public static class Builder {
+      protected String path;
+      protected String contents;
+
+      /**
+       * @param path The path of this Personality.
+       * @return The builder object.
+       * @see Personality#getPath()
+       */
+      public Builder path(String path) {
+         this.path = path;
+         return this;
+      }
+
+      /**
+       * @param contents The contents of this Personality.
+       * @return The builder object.
+       * @see Personality#getContents()
+       */
+      public Builder contents(String contents) {
+         this.contents = contents;
+         return this;
+      }
+
+      /**
+       * @return A new Personality object.
+       */
+      public Personality build() {
+         return new Personality(path, contents);
+      }
+
+      public Builder fromPersonality(Personality in) {
+         return this.path(in.getPath()).contents(in.getContents());
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/46f493ac/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/ScalingPolicy.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/ScalingPolicy.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/ScalingPolicy.java
new file mode 100644
index 0000000..0cefb05
--- /dev/null
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/ScalingPolicy.java
@@ -0,0 +1,275 @@
+/*
+ * 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.autoscale.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.EnumSet;
+
+import org.jclouds.rackspace.autoscale.v1.features.GroupApi;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.Optional;
+
+/**
+ * Autoscale ScalingPolicy. This class is used for requests.
+ * 
+ * @see GroupApi#create(GroupConfiguration, LaunchConfiguration, java.util.List)
+ * @see Group#getScalingPolicies()
+ * @see ScalingPolicyResponse
+ * @author Zack Shoylev
+ */
+public class ScalingPolicy implements Comparable<ScalingPolicy>{
+   private final String name;
+   private final ScalingPolicyType type;
+   private final int cooldown;
+   private final int target;
+   private final ScalingPolicyTargetType targetType;
+
+   @ConstructorProperties({
+      "name", "type", "cooldown", "target", "targetType"
+   })
+   protected ScalingPolicy(String name, ScalingPolicyType type, int cooldown, int target, ScalingPolicyTargetType targetType) {
+
+      this.name = checkNotNull(name, "name required");
+      this.type = type;
+      checkArgument(cooldown >= 0, "cooldown should be non-negative");
+      this.cooldown = cooldown;
+      this.target = target;
+      this.targetType = targetType;
+   }
+
+   /**
+    * @return the name of this ScalingPolicy.
+    * @see ScalingPolicy.Builder#name(String)
+    */
+   public String getName() {
+      return this.name;
+   }   
+
+   /**
+    * @return the type for this ScalingPolicy.
+    * @see ScalingPolicyType
+    * @see ScalingPolicy.Builder#type(String)
+    */
+   public ScalingPolicyType getType() {
+      return this.type;
+   }
+
+   /**
+    * @return the cooldown for this ScalingPolicy.
+    * @see ScalingPolicy.Builder#cooldown(int)
+    */
+   public int getCooldown() {
+      return this.cooldown;
+   }
+
+   /**
+    * @return the target for this ScalingPolicy. This is a numeric value, but could represent a 0-100% for some target types. Scale-down policies might have negative values.
+    * 
+    * @see ScalingPolicy.Builder#target(int)
+    */
+   public int getTarget() {
+      return this.target;
+   }
+
+   /**
+    * @return the target type for this ScalingPolicy.
+    * @see ScalingPolicyTargetType
+    * @see ScalingPolicy.Builder#targetType(int)
+    */
+   public ScalingPolicyTargetType getTargetType() {
+      return this.targetType;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(name, type, cooldown, target, targetType);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      ScalingPolicy that = ScalingPolicy.class.cast(obj);
+      return Objects.equal(this.name, that.name) && 
+            Objects.equal(this.type, that.type) &&
+            Objects.equal(this.cooldown, that.cooldown) &&
+            Objects.equal(this.target, that.target) &&
+            Objects.equal(this.targetType, that.targetType);
+   }
+
+   protected ToStringHelper string() {
+      return Objects.toStringHelper(this)
+            .add("name", name)
+            .add("type", type)
+            .add("cooldown", cooldown)
+            .add("target", target)
+            .add("targetType", "targetType");
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   public static Builder builder() { 
+      return new Builder();
+   }
+
+   public Builder toBuilder() { 
+      return new Builder().fromScalingPolicy(this);
+   }
+
+   public static class Builder {
+      protected String name;
+      protected ScalingPolicyType type;
+      protected int cooldown;
+      protected int target;
+      protected ScalingPolicyTargetType targetType;
+
+      /** 
+       * @param name The name of this ScalingPolicy.
+       * @return The builder object.
+       * @see ScalingPolicy#getName()
+       */
+      public Builder name(String name) {
+         this.name = name;
+         return this;
+      }
+
+      /** 
+       * @param name The type for this ScalingPolicy.
+       * @return The builder object.
+       * @see ScalingPolicyType
+       * @see ScalingPolicy#getType()
+       */
+      public Builder type(ScalingPolicyType type) {
+         this.type = type;
+         return this;
+      }
+
+      /** 
+       * @param cooldown The cooldown of this ScalingPolicy.
+       * @return The builder object.
+       * @see ScalingPolicy#getCooldown()
+       */
+      public Builder cooldown(int cooldown) {
+         this.cooldown = cooldown;
+         return this;
+      }
+
+      /** 
+       * @param target The target of this ScalingPolicy.
+       * @return The builder object.
+       * @see ScalingPolicy#getTarget()
+       */
+      public Builder target(int target) {
+         this.target = target;
+         return this;
+      }
+
+      /** 
+       * @param target type The target type of this ScalingPolicy.
+       * @return The builder object.
+       * @see ScalingPolicyTargetType
+       * @see ScalingPolicy#getTargetType()
+       */
+      public Builder targetType(ScalingPolicyTargetType targetType) {
+         this.targetType = targetType;
+         return this;
+      }
+
+      /**
+       * @return A new ScalingPolicy object.
+       */
+      public ScalingPolicy build() {
+         return new ScalingPolicy(name, type, cooldown, target, targetType);
+      }
+
+      public Builder fromScalingPolicy(ScalingPolicy in) {
+         return this
+               .name(in.getName())
+               .type(in.getType())
+               .cooldown(in.getCooldown())
+               .target(in.getTarget())
+               .targetType(in.getTargetType());
+      }        
+   }
+
+   @Override
+   public int compareTo(ScalingPolicy that) {
+      return this.getName().compareTo(that.getName());
+   }
+
+   /**
+    * Enumerates different types of scaling policies
+    */
+   public static enum ScalingPolicyType {
+      WEBHOOK("webhook");
+
+      private final String name;
+
+      private ScalingPolicyType(String name) {
+         this.name = name;
+      }
+
+      public String toString() {
+         return name;
+      }
+
+      public static Optional<ScalingPolicyType> getByValue(String value){
+         for (final ScalingPolicyType element : EnumSet.allOf(ScalingPolicyType.class)) {
+            if (element.toString().equals(value)) {
+               return Optional.of(element);
+            }
+         }
+         return Optional.absent();
+      }
+   }
+
+   /**
+    * Enumerates different types of targets a policy might have
+    */
+   public static enum ScalingPolicyTargetType {
+      INCREMENTAL("change"),
+      DESIRED_CAPACITY("desiredCapacity"),
+      PERCENT_CHANGE("changePercent");
+
+      private final String name;
+
+      private ScalingPolicyTargetType(String name) {
+         this.name = name;
+      }
+
+      public String toString() {
+         return name;
+      }
+
+      public static Optional<ScalingPolicyTargetType> getByValue(String value){
+         for (final ScalingPolicyTargetType element : EnumSet.allOf(ScalingPolicyTargetType.class)) {
+            if (element.toString().equals(value)) {
+               return Optional.of(element);
+            }
+         }
+         return Optional.absent();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/46f493ac/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/ScalingPolicyResponse.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/ScalingPolicyResponse.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/ScalingPolicyResponse.java
new file mode 100644
index 0000000..c469719
--- /dev/null
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/ScalingPolicyResponse.java
@@ -0,0 +1,90 @@
+/*
+ * 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.autoscale.v1.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+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.collect.ImmutableList;
+
+/**
+ * Autoscale ScalingPolicyResponse. Extends ScalingPolicy with id and links.
+ * 
+ * @see Group#getScalingPolicies()
+ * @author Zack Shoylev
+ */
+public class ScalingPolicyResponse extends ScalingPolicy{
+   private final ImmutableList<Link> links;
+   private final String id;
+
+   @ConstructorProperties({
+      "name", "type", "cooldown", "target", "targetType", "links", "id"
+   })
+   public ScalingPolicyResponse(String name, ScalingPolicyType type, int cooldown, int target, ScalingPolicyTargetType targetType, List<Link> links, String id) {
+      super(name, type, cooldown, target, targetType);
+      this.id = checkNotNull(id, "id required");
+      this.links = ImmutableList.copyOf(checkNotNull(links, "links required"));
+   }
+
+   /**
+    * @return the unique id of this ScalingPolicy.
+    * @see ScalingPolicyResponse.Builder#id(String)
+    */
+   public String getId() {
+      return this.id;
+   }   
+
+   /**
+    * @return the links to this ScalingPolicy.
+    * @see ScalingPolicyResponse.Builder#links(String)
+    */
+   public ImmutableList<Link> getLinks() {
+      return this.links;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(super.hashCode(), links, id);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      ScalingPolicyResponse that = ScalingPolicyResponse.class.cast(obj);
+      return Objects.equal(this.id, that.id) && 
+            Objects.equal(this.links, that.links) &&
+            super.equals(obj);
+   }
+
+   protected ToStringHelper string() {
+      return super.string()
+            .add("links", links)
+            .add("id", id);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }   
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/46f493ac/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/features/GroupApi.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/features/GroupApi.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/features/GroupApi.java
new file mode 100644
index 0000000..f12b690
--- /dev/null
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/features/GroupApi.java
@@ -0,0 +1,159 @@
+/*
+ * 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.autoscale.v1.features;
+
+
+import java.util.List;
+
+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.FalseOnNotFoundOr404;
+import org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.rackspace.autoscale.v1.binders.BindCreateGroupToJson;
+import org.jclouds.rackspace.autoscale.v1.domain.Group;
+import org.jclouds.rackspace.autoscale.v1.domain.GroupConfiguration;
+import org.jclouds.rackspace.autoscale.v1.domain.GroupState;
+import org.jclouds.rackspace.autoscale.v1.domain.LaunchConfiguration;
+import org.jclouds.rackspace.autoscale.v1.domain.ScalingPolicy;
+import org.jclouds.rackspace.autoscale.v1.functions.ParseGroupResponse;
+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 com.google.common.collect.FluentIterable;
+
+/**
+ * The API for controlling scaling groups.
+ * A scaling group is a high-level autoscaling concept that encompasses a group configuration, a launch configuration, and a set of scaling policies.
+ * @author Zack Shoylev
+ */
+@RequestFilters(AuthenticateRequest.class)
+public interface GroupApi {
+
+   /**
+    * Create a scaling group.
+    * @param groupConfiguration The group configuration.
+    * @param launchConfiguration The launch configuration.
+    * @param scalingPolicies The list of scaling policies.
+    * @return Group The group created by this call.
+    * @see GroupConfiguration
+    * @see LaunchConfiguration
+    * @see ScalingPolicy
+    * @see Group
+    */
+   @Named("Group:create")
+   @POST
+   @Path("/groups")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(NullOnNotFoundOr404.class)
+   @MapBinder(BindCreateGroupToJson.class)
+   @ResponseParser(ParseGroupResponse.class)
+   Group create(@PayloadParam("groupConfiguration") GroupConfiguration groupConfiguration, 
+         @PayloadParam("launchConfiguration") LaunchConfiguration launchConfiguration,
+         @PayloadParam("scalingPolicies") List<ScalingPolicy> scalingPolicies);
+
+   /**
+    * This operation pauses the specified Autoscaling Group
+    *
+    * @param groupId The id for the specified Group.
+    * @return true if successful.
+    * @see GroupApi#resume(String)
+    */
+   @Named("Groups:pause/{groupId}")
+   @POST
+   @Path("/groups/{groupId}/pause")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(FalseOnNotFoundOr404.class)
+   boolean pause(@PathParam("groupId") String groupId);
+
+   /**
+    * This operation resumes the specified Autoscaling Group.
+    *
+    * @param groupId The id for the specified Group.
+    * @return true if successful.
+    * @see GroupApi#pause(String)
+    */
+   @Named("Groups:pause/{groupId}")
+   @POST
+   @Path("/groups/{groupId}/resume")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(FalseOnNotFoundOr404.class)
+   boolean resume(@PathParam("groupId") String groupId);
+
+   /**
+    * This operation deletes the specified Autoscaling Group
+    *
+    * @param groupId The id for the specified Group.
+    * @return true if successful.
+    */
+   @Named("Groups:delete/{id}")
+   @DELETE
+   @Path("/groups/{id}")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(FalseOnNotFoundOr404.class)
+   boolean delete(@PathParam("id") String groupId);
+
+   /**
+    * This operation gets group details for a group
+    * @param id The unique identifier of the scaling group.
+    * @return Group Full details for the scaling group.
+    */
+   @Named("Group:get/{id}")
+   @GET
+   @Path("/groups/{id}")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ResponseParser(ParseGroupResponse.class)
+   @Fallback(NullOnNotFoundOr404.class)
+   Group get(@PathParam("id") String id);
+
+   /**
+    * This operation gets the state of the Autoscaling Group. This is a slightly different set of information than the full details for a group.
+    * @param id The unique identifier of the scaling group.
+    * @return The state of the Group.
+    * @see GroupState
+    */
+   @Named("Group:state")
+   @GET
+   @Path("/groups/{id}/state")
+   @SelectJson("group")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(NullOnNotFoundOr404.class)
+   GroupState getState(@PathParam("id") String id);
+
+   /**
+    * This operation lists all autoscaling groups.
+    * @return A list of group states for all scaling groups.
+    * @see GroupState
+    */
+   @Named("Group:states")
+   @GET
+   @Path("/groups")
+   @SelectJson("groups")
+   @Consumes(MediaType.APPLICATION_JSON)
+   FluentIterable<GroupState> listGroupStates();
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/46f493ac/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/functions/ParseGroupResponse.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/functions/ParseGroupResponse.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/functions/ParseGroupResponse.java
new file mode 100644
index 0000000..5673a2c
--- /dev/null
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/functions/ParseGroupResponse.java
@@ -0,0 +1,151 @@
+/*
+ * 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.autoscale.v1.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.openstack.v2_0.domain.Link.Relation;
+import org.jclouds.rackspace.autoscale.v1.domain.Group;
+import org.jclouds.rackspace.autoscale.v1.domain.GroupConfiguration;
+import org.jclouds.rackspace.autoscale.v1.domain.LaunchConfiguration;
+import org.jclouds.rackspace.autoscale.v1.domain.LaunchConfiguration.LaunchConfigurationType;
+import org.jclouds.rackspace.autoscale.v1.domain.LoadBalancer;
+import org.jclouds.rackspace.autoscale.v1.domain.Personality;
+import org.jclouds.rackspace.autoscale.v1.domain.ScalingPolicy.ScalingPolicyTargetType;
+import org.jclouds.rackspace.autoscale.v1.domain.ScalingPolicy.ScalingPolicyType;
+import org.jclouds.rackspace.autoscale.v1.domain.ScalingPolicyResponse;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.inject.Inject;
+
+/**
+ * This parses the group response and decouples domain objects from the json object returned by the service.
+ * @author Zack Shoylev
+ */
+public class ParseGroupResponse implements Function<HttpResponse, Group> {
+
+   private final ParseJson<Map<String, Object>> json;
+
+   @Inject
+   ParseGroupResponse(ParseJson<Map<String, Object>> json) {
+      this.json = checkNotNull(json, "json");
+   }
+
+   /**
+    * Extracts the user password from the json response
+    */
+   @SuppressWarnings("unchecked")
+   public Group apply(HttpResponse from) {
+      Map<String, Object> result = json.apply(from);
+
+      Map<String, Object> group = (Map<String, Object>) result.get("group");
+      Map<String, Object> groupConfigurationMap = (Map<String, Object>) group.get("groupConfiguration");
+      Map<String, Object> launchConfigurationMap = (Map<String, Object>) group.get("launchConfiguration");
+      List<ScalingPolicyResponse> scalingPoliciesList = Lists.newArrayList();
+      Map<String, Object> args = (Map<String, Object>) launchConfigurationMap.get("args");
+      Map<String, Object> server = (Map<String, Object>) args.get("server");      
+
+      List<Personality> personalities = Lists.newArrayList();
+      List<String> networks = Lists.newArrayList();
+      for(Map<String,String> jsonPersonality : (List<Map<String,String>>) server.get("personality")) {
+         personalities.add(Personality.builder().path(jsonPersonality.get("path")).contents(jsonPersonality.get("contents")).build());
+      }
+
+      for(Map<String,String> jsonNetwork : (List<Map<String,String>>) server.get("networks")) {
+         networks.add(jsonNetwork.get("uuid"));
+      }
+
+      List<LoadBalancer> loadBalancers = Lists.newArrayList();
+      for(Map<String,Double> jsonLoadBalancer : (List<Map<String,Double>>) args.get("loadBalancers")) {
+         loadBalancers.add(
+               LoadBalancer.builder().id( ((Double)jsonLoadBalancer.get("loadBalancerId")).intValue() ).port( ((Double)jsonLoadBalancer.get("port")).intValue() ).build()
+               );
+      }
+
+      LaunchConfiguration launchConfiguration = LaunchConfiguration.builder()
+            .loadBalancers(loadBalancers)
+            .serverName((String) server.get("name"))
+            .serverImageRef((String) server.get("imageRef"))
+            .serverFlavorRef((String) server.get("flavorRef"))
+            .serverDiskConfig((String) server.get("OS-DCF:diskConfig"))
+            .serverMetadata((Map<String, String>) server.get("metadata"))
+            .personalities(personalities)
+            .networks(networks)
+            .type(LaunchConfigurationType.getByValue((String) launchConfigurationMap.get("type")).get())
+            .build();
+
+      GroupConfiguration groupConfiguration = GroupConfiguration.builder()
+            .cooldown(((Double) groupConfigurationMap.get("cooldown")).intValue())
+            .minEntities(((Double) groupConfigurationMap.get("minEntities")).intValue())
+            .maxEntities(((Double) groupConfigurationMap.get("maxEntities")).intValue())
+            .name((String) groupConfigurationMap.get("name"))
+            .metadata((Map<String, String>) groupConfigurationMap.get("metadata"))
+            .build();
+
+      for(Map<String, Object> scalingPolicyMap : (List<Map<String, Object>>) group.get("scalingPolicies")) {
+         ScalingPolicyTargetType targetType = null;
+         for(String key : scalingPolicyMap.keySet()) {
+            if(ScalingPolicyTargetType.getByValue(key).isPresent()) {
+               targetType = ScalingPolicyTargetType.getByValue(key).get();
+               break;
+            }  
+         }
+
+         List<Link> links = Lists.newArrayList();
+         for(Map<String, String> linkMap : (List<Map<String, String>>) scalingPolicyMap.get("links")) {
+            Link link = Link.builder().href(URI.create(linkMap.get("href"))).relation(Relation.fromValue(linkMap.get("rel"))).build();
+            links.add(link);
+         }
+
+         ScalingPolicyResponse scalingPolicyResponse = 
+               new ScalingPolicyResponse(
+                     (String)scalingPolicyMap.get("name"),
+                     ScalingPolicyType.getByValue((String)scalingPolicyMap.get("type")).get(),
+                     ((Double)scalingPolicyMap.get("cooldown")).intValue(),
+                     ((Double)scalingPolicyMap.get(targetType.toString())).intValue(),
+                     targetType,
+                     ImmutableList.copyOf(links),
+                     (String) scalingPolicyMap.get("id")
+                     );
+         scalingPoliciesList.add(scalingPolicyResponse);
+      }
+
+      List<Link> links = Lists.newArrayList();
+      for(Map<String, String> linkMap : (List<Map<String, String>>) group.get("links")) {
+         Link link = Link.builder().href(URI.create(linkMap.get("href"))).relation(Relation.fromValue(linkMap.get("rel"))).build();
+         links.add(link);
+      }
+
+      String groupId = (String) group.get("id");
+      return Group.builder()
+            .id(groupId)
+            .scalingPolicy(scalingPoliciesList)
+            .groupConfiguration(groupConfiguration)
+            .launchConfiguration(launchConfiguration)
+            .links(links)
+            .build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/46f493ac/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/handlers/AutoscaleErrorHandler.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/handlers/AutoscaleErrorHandler.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/handlers/AutoscaleErrorHandler.java
new file mode 100644
index 0000000..202b5de
--- /dev/null
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/handlers/AutoscaleErrorHandler.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.rackspace.autoscale.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 AutoscaleErrorHandler 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/incubator-jclouds-labs-openstack/blob/46f493ac/rackspace-autoscale/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/rackspace-autoscale/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
new file mode 100644
index 0000000..4ee5597
--- /dev/null
+++ b/rackspace-autoscale/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.rackspace.autoscale.v1.AutoscaleApiMetadata

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/46f493ac/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/features/GroupApiExpectTest.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/features/GroupApiExpectTest.java b/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/features/GroupApiExpectTest.java
new file mode 100644
index 0000000..b6f4e87
--- /dev/null
+++ b/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/features/GroupApiExpectTest.java
@@ -0,0 +1,357 @@
+/*
+ * 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.autoscale.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 static org.testng.Assert.assertFalse;
+
+import java.net.URI;
+import java.util.List;
+
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.rackspace.autoscale.v1.domain.Group;
+import org.jclouds.rackspace.autoscale.v1.domain.GroupConfiguration;
+import org.jclouds.rackspace.autoscale.v1.domain.GroupState;
+import org.jclouds.rackspace.autoscale.v1.domain.LaunchConfiguration;
+import org.jclouds.rackspace.autoscale.v1.domain.LaunchConfiguration.LaunchConfigurationType;
+import org.jclouds.rackspace.autoscale.v1.domain.LoadBalancer;
+import org.jclouds.rackspace.autoscale.v1.domain.Personality;
+import org.jclouds.rackspace.autoscale.v1.domain.ScalingPolicy;
+import org.jclouds.rackspace.autoscale.v1.domain.ScalingPolicy.ScalingPolicyTargetType;
+import org.jclouds.rackspace.autoscale.v1.domain.ScalingPolicy.ScalingPolicyType;
+import org.jclouds.rackspace.autoscale.v1.internal.BaseAutoscaleApiExpectTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
+/**
+ * Tests GroupApi Guice wiring and parsing
+ *
+ * @author Zack Shoylev
+ */
+@Test(groups = "unit", testName = "GroupApiExpectTest")
+public class GroupApiExpectTest extends BaseAutoscaleApiExpectTest {
+
+   public void testCreateGroup() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().method("POST").endpoint(endpoint).payload(payloadFromResourceWithContentType("/autoscale_groups_create_request.json", MediaType.APPLICATION_JSON)).build(),
+            HttpResponse.builder().statusCode(201).payload(payloadFromResource("/autoscale_groups_create_response.json")).build()
+            ).getGroupApiForZone("DFW");
+
+      GroupConfiguration groupConfiguration = GroupConfiguration.builder()
+            .maxEntities(10)
+            .cooldown(360)
+            .name("testscalinggroup198547")
+            .minEntities(0)
+            .metadata(ImmutableMap.of("gc_meta_key_2","gc_meta_value_2","gc_meta_key_1","gc_meta_value_1"))
+            .build();
+
+      LaunchConfiguration launchConfiguration = LaunchConfiguration.builder()
+            .loadBalancers(ImmutableList.of(LoadBalancer.builder().port(8080).id(9099).build()))
+            .serverName("autoscale_server")
+            .serverImageRef("0d589460-f177-4b0f-81c1-8ab8903ac7d8")
+            .serverFlavorRef("2")
+            .serverDiskConfig("AUTO")
+            .serverMetadata(ImmutableMap.of("build_config","core","meta_key_1","meta_value_1","meta_key_2","meta_value_2"))
+            .networks(ImmutableList.of("11111111-1111-1111-1111-111111111111","00000000-0000-0000-0000-000000000000"))
+            .personalities(ImmutableList.of(Personality.builder().path("/root/.csivh").contents("VGhpcyBpcyBhIHRlc3QgZmlsZS4=").build()))
+            .type(LaunchConfigurationType.LAUNCH_SERVER)
+            .build();
+
+      List<ScalingPolicy> scalingPolicies = Lists.newArrayList();
+
+      ScalingPolicy scalingPolicy = ScalingPolicy.builder()
+            .cooldown(0)
+            .type(ScalingPolicyType.WEBHOOK)
+            .name("scale up by 1")
+            .targetType(ScalingPolicyTargetType.INCREMENTAL)
+            .target(1)
+            .build();
+      scalingPolicies.add(scalingPolicy);
+
+      Group g = api.create(groupConfiguration, launchConfiguration, scalingPolicies);
+
+      assertNotNull(g);
+      assertEquals(g.getId(),"6791761b-821a-4d07-820d-0b2afc7dd7f6");
+      assertEquals(g.getLinks().size(), 1);
+      assertEquals(g.getLinks().get(0).getHref().toString(), "https://ord.autoscale.api.rackspacecloud.com/v1.0/829409/groups/6791761b-821a-4d07-820d-0b2afc7dd7f6/");
+      assertEquals(g.getLinks().get(0).getRelation(), Link.Relation.SELF);
+
+      assertEquals(g.getScalingPolicies().get(0).getId(), "dceb14ac-b2b3-4f06-aac9-a5b6cd5d40e1");
+      assertEquals(g.getScalingPolicies().get(0).getLinks().size(), 1);
+      assertEquals(g.getScalingPolicies().get(0).getLinks().get(0).getHref().toString(), "https://ord.autoscale.api.rackspacecloud.com/v1.0/829409/groups/6791761b-821a-4d07-820d-0b2afc7dd7f6/policies/dceb14ac-b2b3-4f06-aac9-a5b6cd5d40e1/");
+      assertEquals(g.getScalingPolicies().get(0).getLinks().get(0).getRelation(), Link.Relation.SELF);
+      assertEquals(g.getScalingPolicies().get(0).getCooldown(), 0);
+      assertEquals(g.getScalingPolicies().get(0).getTarget(), 1);
+      assertEquals(g.getScalingPolicies().get(0).getTargetType(), ScalingPolicyTargetType.INCREMENTAL);
+      assertEquals(g.getScalingPolicies().get(0).getType(), ScalingPolicyType.WEBHOOK);
+      assertEquals(g.getScalingPolicies().get(0).getName(), "scale up by 1");
+
+      assertEquals(g.getLaunchConfiguration().getLoadBalancers().size(), 1);
+      assertEquals(g.getLaunchConfiguration().getLoadBalancers().get(0).getId(), 9099);
+      assertEquals(g.getLaunchConfiguration().getLoadBalancers().get(0).getPort(), 8080);
+      assertEquals(g.getLaunchConfiguration().getServerName(), "autoscale_server");
+      assertEquals(g.getLaunchConfiguration().getServerImageRef(), "0d589460-f177-4b0f-81c1-8ab8903ac7d8");
+      assertEquals(g.getLaunchConfiguration().getServerFlavorRef(), "2");
+      assertEquals(g.getLaunchConfiguration().getServerDiskConfig(), "AUTO");
+      assertEquals(g.getLaunchConfiguration().getPersonalities().size(), 1);
+      assertEquals(g.getLaunchConfiguration().getPersonalities().get(0).getPath(), "/root/.csivh");
+      assertEquals(g.getLaunchConfiguration().getPersonalities().get(0).getContents(), "VGhpcyBpcyBhIHRlc3QgZmlsZS4=");
+      assertEquals(g.getLaunchConfiguration().getNetworks().size(), 2);
+      assertEquals(g.getLaunchConfiguration().getNetworks().get(0), "11111111-1111-1111-1111-111111111111");
+      assertEquals(g.getLaunchConfiguration().getNetworks().get(1), "00000000-0000-0000-0000-000000000000");
+      assertEquals(g.getLaunchConfiguration().getServerMetadata().size(), 3);
+      assertTrue(g.getLaunchConfiguration().getServerMetadata().containsKey("build_config"));
+      assertTrue(g.getLaunchConfiguration().getServerMetadata().containsValue("core"));
+      assertEquals(g.getLaunchConfiguration().getType(), LaunchConfigurationType.LAUNCH_SERVER);
+
+      assertEquals(g.getGroupConfiguration().getMaxEntities(), 10);
+      assertEquals(g.getGroupConfiguration().getCooldown(), 360);
+      assertEquals(g.getGroupConfiguration().getName(), "testscalinggroup198547");
+      assertEquals(g.getGroupConfiguration().getMinEntities(), 0);
+      assertEquals(g.getGroupConfiguration().getMetadata().size(), 2);
+      assertTrue(g.getGroupConfiguration().getMetadata().containsKey("gc_meta_key_2"));
+      assertTrue(g.getGroupConfiguration().getMetadata().containsValue("gc_meta_value_2"));
+   }
+
+   public void testCreateGroupFail() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().method("POST").endpoint(endpoint).payload(payloadFromResourceWithContentType("/autoscale_groups_create_request.json", MediaType.APPLICATION_JSON)).build(),
+            HttpResponse.builder().statusCode(404).payload(payloadFromResource("/autoscale_groups_create_response.json")).build()
+            ).getGroupApiForZone("DFW");
+
+      GroupConfiguration groupConfiguration = GroupConfiguration.builder()
+            .maxEntities(10)
+            .cooldown(360)
+            .name("testscalinggroup198547")
+            .minEntities(0)
+            .metadata(ImmutableMap.of("gc_meta_key_2","gc_meta_value_2","gc_meta_key_1","gc_meta_value_1"))
+            .build();
+
+      LaunchConfiguration launchConfiguration = LaunchConfiguration.builder()
+            .loadBalancers(ImmutableList.of(LoadBalancer.builder().port(8080).id(9099).build()))
+            .serverName("autoscale_server")
+            .serverImageRef("0d589460-f177-4b0f-81c1-8ab8903ac7d8")
+            .serverFlavorRef("2")
+            .serverDiskConfig("AUTO")
+            .serverMetadata(ImmutableMap.of("build_config","core","meta_key_1","meta_value_1","meta_key_2","meta_value_2"))
+            .networks(ImmutableList.of("11111111-1111-1111-1111-111111111111","00000000-0000-0000-0000-000000000000"))
+            .personalities(ImmutableList.of(Personality.builder().path("/root/.csivh").contents("VGhpcyBpcyBhIHRlc3QgZmlsZS4=").build()))
+            .type(LaunchConfigurationType.LAUNCH_SERVER)
+            .build();
+
+      List<ScalingPolicy> scalingPolicies = Lists.newArrayList();
+
+      ScalingPolicy scalingPolicy = ScalingPolicy.builder()
+            .cooldown(0)
+            .type(ScalingPolicyType.WEBHOOK)
+            .name("scale up by 1")
+            .targetType(ScalingPolicyTargetType.INCREMENTAL)
+            .target(1)
+            .build();
+      scalingPolicies.add(scalingPolicy);
+
+      Group g = api.create(groupConfiguration, launchConfiguration, scalingPolicies);
+
+      assertNull(g);
+   }
+
+   public void testListGroups() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/autoscale_groups_list_response.json")).build()
+            ).getGroupApiForZone("DFW");
+
+      FluentIterable<GroupState> groupStates = api.listGroupStates();
+      assertEquals(groupStates.size(),2);
+
+      assertEquals(groupStates.get(0).getGroupInstances().size(), 0);
+      assertEquals(groupStates.get(0).getActiveCapacity(), 0);
+      assertEquals(groupStates.get(0).getDesiredCapacity(), 0);
+      assertEquals(groupStates.get(0).getId(), "e41380ae-173c-4b40-848a-25c16d7fa83d");
+      assertEquals(groupStates.get(0).getLinks().size(), 1);
+      assertEquals(groupStates.get(0).getLinks().get(0).getHref().toString(), "https://dfw.autoscale.api.rackspacecloud.com/v1.0/676873/groups/e41380ae-173c-4b40-848a-25c16d7fa83d/");
+      assertEquals(groupStates.get(0).getLinks().get(0).getRelation(), Link.Relation.SELF);
+      assertEquals(groupStates.get(0).getPaused(), false);
+      assertEquals(groupStates.get(0).getPendingCapacity(), 0);
+   }
+
+   @Test(expectedExceptions = org.jclouds.rest.ResourceNotFoundException.class)
+   public void testListGroupsFail() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).build()
+            ).getGroupApiForZone("DFW");
+
+      FluentIterable<GroupState> groupStates = api.listGroupStates();
+      assertEquals(groupStates.size(), 0);
+   }
+
+   public void testGetGroup() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/1234567890");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/autoscale_groups_get_response.json")).build()
+            ).getGroupApiForZone("DFW");
+
+      Group g = api.get("1234567890");
+      assertEquals(g.getId(), "1234567890");
+      assertEquals(g.getScalingPolicies().size(), 3);
+   }
+
+   public void testGetGroupFail() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/1234567890");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).build()
+            ).getGroupApiForZone("DFW");
+
+      Group g = api.get("1234567890");
+      assertNull(g);
+   }
+
+   public void testDeleteGroup() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/1234567890");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).method("DELETE").build(),
+            HttpResponse.builder().statusCode(204).build()
+            ).getGroupApiForZone("DFW");
+
+      boolean success = api.delete("1234567890");
+      assertTrue(success);
+   }
+
+   public void testDeleteGroupFail() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/1234567890");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).method("DELETE").build(),
+            HttpResponse.builder().statusCode(404).build()
+            ).getGroupApiForZone("DFW");
+
+      boolean success = api.delete("1234567890");
+      assertFalse(success);
+   }
+
+   public void testGetGroupState() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/1234567890/state");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/autoscale_groups_state_response.json")).build()
+            ).getGroupApiForZone("DFW");
+
+      GroupState gs = api.getState("1234567890");
+      assertEquals(gs.getId(), "1234567890");
+      assertEquals(gs.getGroupInstances().size(), 2);
+      assertEquals(gs.getGroupInstances().get(0).getId(), "444444");
+   }
+
+   public void testGetGroupStateFail() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/1234567890/state");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).payload(payloadFromResource("/autoscale_groups_state_response.json")).build()
+            ).getGroupApiForZone("DFW");
+
+      GroupState gs = api.getState("1234567890");
+      assertNull(gs);
+   }
+
+   public void testPause() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/1234567890/pause");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).method("POST").build(),
+            HttpResponse.builder().statusCode(204).build()
+            ).getGroupApiForZone("DFW");
+
+      boolean success = api.pause("1234567890");
+      assertTrue(success);
+   }
+
+   public void testPauseFail() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/1234567890/pause");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).method("POST").build(),
+            HttpResponse.builder().statusCode(404).build()
+            ).getGroupApiForZone("DFW");
+
+      boolean success = api.pause("1234567890");
+      assertFalse(success);
+   }
+
+   public void testResume() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/1234567890/resume");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).method("POST").build(),
+            HttpResponse.builder().statusCode(204).build()
+            ).getGroupApiForZone("DFW");
+
+      boolean success = api.resume("1234567890");
+      assertTrue(success);
+   }
+
+   public void testResumeFail() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/1234567890/resume");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).method("POST").build(),
+            HttpResponse.builder().statusCode(404).build()
+            ).getGroupApiForZone("DFW");
+
+      boolean success = api.resume("1234567890");
+      assertFalse(success);
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/46f493ac/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/features/GroupApiLiveTest.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/features/GroupApiLiveTest.java b/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/features/GroupApiLiveTest.java
new file mode 100644
index 0000000..da6370b
--- /dev/null
+++ b/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/features/GroupApiLiveTest.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.rackspace.autoscale.v1.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.rackspace.autoscale.v1.domain.Group;
+import org.jclouds.rackspace.autoscale.v1.domain.GroupConfiguration;
+import org.jclouds.rackspace.autoscale.v1.domain.GroupState;
+import org.jclouds.rackspace.autoscale.v1.domain.LaunchConfiguration;
+import org.jclouds.rackspace.autoscale.v1.domain.LaunchConfiguration.LaunchConfigurationType;
+import org.jclouds.rackspace.autoscale.v1.domain.LoadBalancer;
+import org.jclouds.rackspace.autoscale.v1.domain.Personality;
+import org.jclouds.rackspace.autoscale.v1.domain.ScalingPolicy;
+import org.jclouds.rackspace.autoscale.v1.domain.ScalingPolicy.ScalingPolicyTargetType;
+import org.jclouds.rackspace.autoscale.v1.domain.ScalingPolicy.ScalingPolicyType;
+import org.jclouds.rackspace.autoscale.v1.internal.BaseAutoscaleApiLiveTest;
+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.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+/**
+ * Tests GroupApi Guice live test
+ * 
+ * @author Zack Shoylev
+ */
+@Test(groups = "unit", testName = "GroupApiLiveTest")
+public class GroupApiLiveTest extends BaseAutoscaleApiLiveTest {
+
+   private static Map<String, List<Group>> created = Maps.newHashMap();
+
+   @Override
+   @BeforeClass(groups = { "integration", "live" })
+   public void setup() {
+      super.setup();
+      for (String zone : api.getConfiguredZones()) {
+         List<Group> createdGroupList = Lists.newArrayList();
+         created.put(zone, createdGroupList);
+         GroupApi groupApi = api.getGroupApiForZone(zone);
+
+         GroupConfiguration groupConfiguration = GroupConfiguration.builder().maxEntities(10).cooldown(360)
+               .name("testscalinggroup198547").minEntities(0)
+               .metadata(ImmutableMap.of("gc_meta_key_2", "gc_meta_value_2", "gc_meta_key_1", "gc_meta_value_1"))
+               .build();
+
+         LaunchConfiguration launchConfiguration = LaunchConfiguration
+               .builder()
+               .loadBalancers(ImmutableList.of(LoadBalancer.builder().port(8080).id(9099).build()))
+               .serverName("autoscale_server")
+               .serverImageRef("0d589460-f177-4b0f-81c1-8ab8903ac7d8")
+               .serverFlavorRef("1")
+               .serverDiskConfig("AUTO")
+               .serverMetadata(
+                     ImmutableMap
+                     .of("build_config", "core", "meta_key_1", "meta_value_1", "meta_key_2", "meta_value_2"))
+                     .networks(
+                           ImmutableList.of("11111111-1111-1111-1111-111111111111", "00000000-0000-0000-0000-000000000000"))
+                           .personalities(
+                                 ImmutableList.of(Personality.builder().path("/root/.csivh")
+                                       .contents("VGhpcyBpcyBhIHRlc3QgZmlsZS4=").build()))
+                                       .type(LaunchConfigurationType.LAUNCH_SERVER).build();
+
+         List<ScalingPolicy> scalingPolicies = Lists.newArrayList();
+
+         ScalingPolicy scalingPolicy = ScalingPolicy.builder().cooldown(0).type(ScalingPolicyType.WEBHOOK)
+               .name("scale up by 1").targetType(ScalingPolicyTargetType.INCREMENTAL).target(1).build();
+         scalingPolicies.add(scalingPolicy);
+
+         Group g = groupApi.create(groupConfiguration, launchConfiguration, scalingPolicies);
+         createdGroupList.add(g);
+
+         assertNotNull(g);
+         assertNotNull(g.getId());
+         assertEquals(g.getLinks().size(), 1);
+         assertEquals(g.getLinks().get(0).getHref().toString(),
+               "https://" + zone.toLowerCase() + ".autoscale.api.rackspacecloud.com/v1.0/" + api.getCurrentTenantId().get().getId() + "/groups/" + g.getId() + "/");
+         assertEquals(g.getLinks().get(0).getRelation(), Link.Relation.SELF);
+
+         assertNotNull(g.getScalingPolicies().get(0).getId());
+         assertEquals(g.getScalingPolicies().get(0).getLinks().size(), 1);
+         assertEquals(
+               g.getScalingPolicies().get(0).getLinks().get(0).getHref().toString(),
+               "https://" + zone.toLowerCase() + ".autoscale.api.rackspacecloud.com/v1.0/" + api.getCurrentTenantId().get().getId() + "/groups/" + g.getId() + "/policies/" + g.getScalingPolicies().get(0).getId() +"/");
+         assertEquals(g.getScalingPolicies().get(0).getLinks().get(0).getRelation(), Link.Relation.SELF);
+         assertEquals(g.getScalingPolicies().get(0).getCooldown(), 0);
+         assertEquals(g.getScalingPolicies().get(0).getTarget(), 1);
+         assertEquals(g.getScalingPolicies().get(0).getTargetType(), ScalingPolicyTargetType.INCREMENTAL);
+         assertEquals(g.getScalingPolicies().get(0).getType(), ScalingPolicyType.WEBHOOK);
+         assertEquals(g.getScalingPolicies().get(0).getName(), "scale up by 1");
+
+         assertEquals(g.getLaunchConfiguration().getLoadBalancers().size(), 1);
+         assertEquals(g.getLaunchConfiguration().getLoadBalancers().get(0).getId(), 9099);
+         assertEquals(g.getLaunchConfiguration().getLoadBalancers().get(0).getPort(), 8080);
+         assertEquals(g.getLaunchConfiguration().getServerName(), "autoscale_server");
+         assertNotNull(g.getLaunchConfiguration().getServerImageRef());
+         assertEquals(g.getLaunchConfiguration().getServerFlavorRef(), "1");
+         assertEquals(g.getLaunchConfiguration().getServerDiskConfig(), "AUTO");
+         assertEquals(g.getLaunchConfiguration().getPersonalities().size(), 1);
+         assertEquals(g.getLaunchConfiguration().getPersonalities().get(0).getPath(), "/root/.csivh");
+         assertEquals(g.getLaunchConfiguration().getPersonalities().get(0).getContents(),
+               "VGhpcyBpcyBhIHRlc3QgZmlsZS4=");
+         assertEquals(g.getLaunchConfiguration().getNetworks().size(), 2);
+         assertEquals(g.getLaunchConfiguration().getNetworks().get(0), "11111111-1111-1111-1111-111111111111");
+         assertEquals(g.getLaunchConfiguration().getNetworks().get(1), "00000000-0000-0000-0000-000000000000");
+         assertEquals(g.getLaunchConfiguration().getServerMetadata().size(), 3);
+         assertTrue(g.getLaunchConfiguration().getServerMetadata().containsKey("build_config"));
+         assertTrue(g.getLaunchConfiguration().getServerMetadata().containsValue("core"));
+         assertEquals(g.getLaunchConfiguration().getType(), LaunchConfigurationType.LAUNCH_SERVER);
+
+         assertEquals(g.getGroupConfiguration().getMaxEntities(), 10);
+         assertEquals(g.getGroupConfiguration().getCooldown(), 360);
+         assertEquals(g.getGroupConfiguration().getName(), "testscalinggroup198547");
+         assertEquals(g.getGroupConfiguration().getMinEntities(), 0);
+         assertEquals(g.getGroupConfiguration().getMetadata().size(), 2);
+         assertTrue(g.getGroupConfiguration().getMetadata().containsKey("gc_meta_key_2"));
+         assertTrue(g.getGroupConfiguration().getMetadata().containsValue("gc_meta_value_2"));
+      }
+   }
+
+   @Test
+   public void testGetGroup() {
+      for (String zone : api.getConfiguredZones()) {
+         GroupApi groupApi = api.getGroupApiForZone(zone);
+         String groupId = created.get(zone).get(0).getId();
+         Group testGroup = groupApi.get(groupId);
+         assertEquals(testGroup.getId(), groupId);
+         assertEquals(testGroup.getGroupConfiguration().getCooldown(), 360);
+         assertEquals(testGroup.getLaunchConfiguration().getServerName(), "autoscale_server");
+         assertEquals(testGroup.getScalingPolicies().get(0).getName(), "scale up by 1");
+      }
+   }
+
+   @Test
+   public void testGetState() {
+      for (String zone : api.getConfiguredZones()) {
+         GroupApi groupApi = api.getGroupApiForZone(zone);
+         String groupId = created.get(zone).get(0).getId();
+         GroupState testGroup = groupApi.getState(groupId);
+         assertEquals(testGroup.getId(), groupId);
+      }
+   }
+
+   @Test
+   public void testListGroups() {
+      for (String zone : api.getConfiguredZones()) {
+         GroupApi groupApi = api.getGroupApiForZone(zone);
+         FluentIterable<GroupState> groupsList = groupApi.listGroupStates();
+         String groupId = created.get(zone).get(0).getId();
+         for( GroupState groupState : groupsList) {
+            if( groupId.equals(groupState.getId()) ) {
+               return;
+            }
+         }
+         fail("Could not find known groupID " + groupId);
+      }
+   }
+
+   /* TODO: uncomment when implemented
+   @Test
+   public void testPause() {
+      for (String zone : api.getConfiguredZones()) {
+         GroupApi groupApi = api.getGroupApiForZone(zone);
+         String groupId = created.get(zone).get(0).getId();
+         assertTrue(groupApi.pause(groupId));
+      }
+   }
+
+   @Test
+   public void testResume() {
+      for (String zone : api.getConfiguredZones()) {
+         GroupApi groupApi = api.getGroupApiForZone(zone);
+         String groupId = created.get(zone).get(0).getId();
+         assertTrue(groupApi.resume(groupId));
+      }
+   }
+    */
+
+   @Override
+   @AfterClass(groups = { "integration", "live" })
+   public void tearDown() {
+      for (String zone : api.getConfiguredZones()) {
+         GroupApi groupApi = api.getGroupApiForZone(zone);
+         for (Group group : created.get(zone)) {
+            if (!groupApi.delete(group.getId()))
+               throw new RuntimeException("Could not delete an autoscale group after tests!");
+         }
+      }
+      super.tearDown();
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/46f493ac/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/internal/BaseAutoscaleApiExpectTest.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/internal/BaseAutoscaleApiExpectTest.java b/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/internal/BaseAutoscaleApiExpectTest.java
new file mode 100644
index 0000000..4cf1527
--- /dev/null
+++ b/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/internal/BaseAutoscaleApiExpectTest.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.rackspace.autoscale.v1.internal;
+
+import org.jclouds.rackspace.autoscale.v1.AutoscaleApi;
+
+/**
+ * Base class for writing Autoscale Expect tests
+ * 
+ * @author Zack Shoylev
+ */
+public class BaseAutoscaleApiExpectTest extends BaseAutoscaleExpectTest<AutoscaleApi> {
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/46f493ac/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/internal/BaseAutoscaleApiLiveTest.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/internal/BaseAutoscaleApiLiveTest.java b/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/internal/BaseAutoscaleApiLiveTest.java
new file mode 100644
index 0000000..56f4ffa
--- /dev/null
+++ b/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/internal/BaseAutoscaleApiLiveTest.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.rackspace.autoscale.v1.internal;
+
+import java.util.Properties;
+
+import org.jclouds.apis.BaseApiLiveTest;
+import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
+import org.jclouds.rackspace.autoscale.v1.AutoscaleApi;
+
+/**
+ * Tests behavior of AutoscaleApi
+ * 
+ * @author Zack Shoylev
+ */
+public class BaseAutoscaleApiLiveTest extends BaseApiLiveTest<AutoscaleApi> {
+
+   public BaseAutoscaleApiLiveTest() {
+      provider = "rackspace-autoscale";
+   }
+
+   @Override
+   protected Properties setupProperties() {
+      Properties props = super.setupProperties();
+      setIfTestSystemPropertyPresent(props, KeystoneProperties.CREDENTIAL_TYPE);
+      setIfTestSystemPropertyPresent(props, KeystoneProperties.SERVICE_TYPE);
+      return props;
+   }
+}