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/11/01 16:14:39 UTC

[1/2] JCLOUDS-215 - Adds Group configuration, Group launch, Scaling policy functionality

Updated Branches:
  refs/heads/master e3c8147e2 -> 1c871e12e


http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/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
index da6370b..7f095e1 100644
--- 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
@@ -18,6 +18,7 @@ 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.fail;
 
@@ -47,11 +48,11 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
 /**
- * Tests GroupApi Guice live test
+ * Group live test
  * 
  * @author Zack Shoylev
  */
-@Test(groups = "unit", testName = "GroupApiLiveTest")
+@Test(groups = "unit", testName = "GroupApiLiveTest", singleThreaded = true)
 public class GroupApiLiveTest extends BaseAutoscaleApiLiveTest {
 
    private static Map<String, List<Group>> created = Maps.newHashMap();
@@ -74,8 +75,9 @@ public class GroupApiLiveTest extends BaseAutoscaleApiLiveTest {
                .builder()
                .loadBalancers(ImmutableList.of(LoadBalancer.builder().port(8080).id(9099).build()))
                .serverName("autoscale_server")
-               .serverImageRef("0d589460-f177-4b0f-81c1-8ab8903ac7d8")
-               .serverFlavorRef("1")
+               .serverImageRef("57b8a366-ab2c-454b-939f-215303a4431f")
+               //.serverImageRef("0d589460-f177-4b0f-81c1-8ab8903ac7d8")
+               .serverFlavorRef("2")
                .serverDiskConfig("AUTO")
                .serverMetadata(
                      ImmutableMap
@@ -90,7 +92,7 @@ public class GroupApiLiveTest extends BaseAutoscaleApiLiveTest {
          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();
+               .name("scale up by 1").targetType(ScalingPolicyTargetType.INCREMENTAL).target("1").build();
          scalingPolicies.add(scalingPolicy);
 
          Group g = groupApi.create(groupConfiguration, launchConfiguration, scalingPolicies);
@@ -110,7 +112,7 @@ public class GroupApiLiveTest extends BaseAutoscaleApiLiveTest {
                "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).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");
@@ -120,7 +122,7 @@ public class GroupApiLiveTest extends BaseAutoscaleApiLiveTest {
          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().getServerFlavorRef(), "2");
          assertEquals(g.getLaunchConfiguration().getServerDiskConfig(), "AUTO");
          assertEquals(g.getLaunchConfiguration().getPersonalities().size(), 1);
          assertEquals(g.getLaunchConfiguration().getPersonalities().get(0).getPath(), "/root/.csivh");
@@ -163,7 +165,7 @@ public class GroupApiLiveTest extends BaseAutoscaleApiLiveTest {
          GroupApi groupApi = api.getGroupApiForZone(zone);
          String groupId = created.get(zone).get(0).getId();
          GroupState testGroup = groupApi.getState(groupId);
-         assertEquals(testGroup.getId(), groupId);
+         assertNull(testGroup.getId()); // The id recently changed to not be included when getting state.
       }
    }
 
@@ -202,6 +204,74 @@ public class GroupApiLiveTest extends BaseAutoscaleApiLiveTest {
    }
     */
 
+   @Test
+   public void testGetGroupConfiguration() {
+      for (String zone : api.getConfiguredZones()) {
+         GroupApi groupApi = api.getGroupApiForZone(zone);
+         String groupId = created.get(zone).get(0).getId();
+         GroupConfiguration testGroupConfiguration = groupApi.getGroupConfiguration(groupId);
+         assertEquals(testGroupConfiguration.getCooldown(), 360);
+         assertEquals(testGroupConfiguration.getMaxEntities(), 10);
+         assertEquals(testGroupConfiguration.getMinEntities(), 0);
+      }
+   }
+
+   @Test
+   public void testGetGroupLaunchConfiguration() {
+      for (String zone : api.getConfiguredZones()) {
+         GroupApi groupApi = api.getGroupApiForZone(zone);
+         String groupId = created.get(zone).get(0).getId();
+         LaunchConfiguration testLaunchConfiguration = groupApi.getLaunchConfiguration(groupId);
+         assertEquals(testLaunchConfiguration.getLoadBalancers().get(0).getPort(), 8080);
+         assertEquals(testLaunchConfiguration.getType(), LaunchConfigurationType.LAUNCH_SERVER);
+         assertEquals(testLaunchConfiguration.getServerFlavorRef(), "2");
+      }
+   }
+
+   @Test
+   public void testUpdateLaunchConfiguration() {
+      for (String zone : api.getConfiguredZones()) {
+         GroupApi groupApi = api.getGroupApiForZone(zone);
+         String groupId = created.get(zone).get(0).getId();
+
+         LaunchConfiguration launchConfiguration = LaunchConfiguration
+               .builder()
+               .loadBalancers(ImmutableList.of(LoadBalancer.builder().port(8080).id(9099).build()))
+               .serverName("autoscale_server")
+               .serverImageRef("57b8a366-ab2c-454b-939f-215303a4431f")
+               .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();
+
+         boolean result = groupApi.updateLaunchConfiguration(groupId, launchConfiguration);
+         assertEquals(result, true);
+      }
+   }
+
+   @Test
+   public void testUpdateGroupConfiguration() {
+      for (String zone : api.getConfiguredZones()) {
+         GroupApi groupApi = api.getGroupApiForZone(zone);
+         String groupId = created.get(zone).get(0).getId();
+
+         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();
+
+         boolean result = groupApi.updateGroupConfiguration(groupId, groupConfiguration);
+         assertEquals(result, true);
+      }
+   }
+
    @Override
    @AfterClass(groups = { "integration", "live" })
    public void tearDown() {

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/features/ScalingPolicyApiExpectTest.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/features/ScalingPolicyApiExpectTest.java b/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/features/ScalingPolicyApiExpectTest.java
new file mode 100644
index 0000000..8bb310c
--- /dev/null
+++ b/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/features/ScalingPolicyApiExpectTest.java
@@ -0,0 +1,265 @@
+/*
+ * 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.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.net.URI;
+import java.util.List;
+
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.http.HttpResponse;
+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.domain.ScalingPolicyResponse;
+import org.jclouds.rackspace.autoscale.v1.internal.BaseAutoscaleApiExpectTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Lists;
+
+/**
+ * Tests Scaling Policy Api Guice wiring and parsing
+ *
+ * @author Zack Shoylev
+ */
+@Test(groups = "unit", testName = "GroupApiExpectTest")
+public class ScalingPolicyApiExpectTest extends BaseAutoscaleApiExpectTest {
+
+   public void testCreateScalingPolicy() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/groupId1/policies");
+      PolicyApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().method("POST").endpoint(endpoint).payload(payloadFromResourceWithContentType("/autoscale_policy_create_request.json", MediaType.APPLICATION_JSON)).build(),
+            HttpResponse.builder().statusCode(201).payload(payloadFromResource("/autoscale_policy_create_response.json")).build()
+            ).getPolicyApiForGroupInZone("groupId1", "DFW");      
+
+      List<ScalingPolicy> scalingPolicies = Lists.newArrayList();
+
+      ScalingPolicy scalingPolicy = ScalingPolicy.builder()
+            .cooldown(1800)
+            .type(ScalingPolicyType.WEBHOOK)
+            .name("scale up by one server")
+            .targetType(ScalingPolicyTargetType.INCREMENTAL)
+            .target("1")
+            .build();
+      scalingPolicies.add(scalingPolicy);
+
+      FluentIterable<ScalingPolicyResponse> scalingPolicyResponse = api.create(scalingPolicies);
+
+      assertNotNull(scalingPolicyResponse);
+      assertEquals(scalingPolicyResponse.size(), 1);
+      assertEquals(scalingPolicyResponse.get(0).getCooldown(), 1800);
+      assertEquals(scalingPolicyResponse.get(0).getId(), "dceb14ac-b2b3-4f06-aac9-a5b6cd5d40e1");
+      assertEquals(scalingPolicyResponse.get(0).getName(), "scale up by one server");
+      assertEquals(scalingPolicyResponse.get(0).getTarget(), "1");
+      assertEquals(scalingPolicyResponse.get(0).getLinks().size(), 1);
+   }
+
+   public void testCreateScalingPolicyFail() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/groupId1/policies");
+      PolicyApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().method("POST").endpoint(endpoint).payload(payloadFromResourceWithContentType("/autoscale_policy_create_request.json", MediaType.APPLICATION_JSON)).build(),
+            HttpResponse.builder().statusCode(404).payload(payloadFromResource("/autoscale_policy_create_response.json")).build()
+            ).getPolicyApiForGroupInZone("groupId1", "DFW");      
+
+      List<ScalingPolicy> scalingPolicies = Lists.newArrayList();
+
+      ScalingPolicy scalingPolicy = ScalingPolicy.builder()
+            .cooldown(1800)
+            .type(ScalingPolicyType.WEBHOOK)
+            .name("scale up by one server")
+            .targetType(ScalingPolicyTargetType.INCREMENTAL)
+            .target("1")
+            .build();
+      scalingPolicies.add(scalingPolicy);
+
+      FluentIterable<ScalingPolicyResponse> scalingPolicyResponse = api.create(scalingPolicies);
+
+      assertTrue(scalingPolicyResponse.size() == 0);
+   }
+
+   public void testListScalingPolicies() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/groupId1/policies");
+      PolicyApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().method("GET").endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(201).payload(payloadFromResource("/autoscale_policy_list_response.json")).build()
+            ).getPolicyApiForGroupInZone("groupId1", "DFW");
+
+      FluentIterable<ScalingPolicyResponse> scalingPolicyResponse = api.list();
+
+      assertNotNull(scalingPolicyResponse);
+      assertEquals(scalingPolicyResponse.size(), 2);
+      assertEquals(scalingPolicyResponse.get(0).getCooldown(), 150);
+      assertEquals(scalingPolicyResponse.get(0).getId(), "policyId1");
+      assertEquals(scalingPolicyResponse.get(0).getName(), "scale up by one server");
+      assertEquals(scalingPolicyResponse.get(0).getTarget(), "1");
+      assertEquals(scalingPolicyResponse.get(0).getLinks().size(), 1);
+   }
+
+   public void testListScalingPoliciesFail() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/groupId1/policies");
+      PolicyApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().method("GET").endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).payload(payloadFromResource("/autoscale_policy_list_response.json")).build()
+            ).getPolicyApiForGroupInZone("groupId1", "DFW");
+
+      FluentIterable<ScalingPolicyResponse> scalingPolicyResponse = api.list();
+
+      assertEquals(scalingPolicyResponse.size(), 0);
+   }
+
+   public void testGetScalingPolicies() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/groupId1/policies/policyId");
+      PolicyApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().method("GET").endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(201).payload(payloadFromResource("/autoscale_policy_get_response.json")).build()
+            ).getPolicyApiForGroupInZone("groupId1", "DFW");
+
+      ScalingPolicyResponse scalingPolicyResponse = api.get("policyId");
+
+      assertNotNull(scalingPolicyResponse);
+      assertEquals(scalingPolicyResponse.getCooldown(), 150);
+      assertEquals(scalingPolicyResponse.getId(), "policyId");
+      assertEquals(scalingPolicyResponse.getName(), "scale up by one server");
+      assertEquals(scalingPolicyResponse.getTarget(), "1");
+      assertEquals(scalingPolicyResponse.getLinks().size(), 1);
+   }
+
+   public void testGetScalingPoliciesFail() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/groupId1/policies/policyId");
+      PolicyApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().method("GET").endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).payload(payloadFromResource("/autoscale_policy_get_response.json")).build()
+            ).getPolicyApiForGroupInZone("groupId1", "DFW");
+
+      ScalingPolicyResponse scalingPolicyResponse = api.get("policyId");
+
+      assertNull(scalingPolicyResponse);
+   }
+
+   public void testUpdateScalingPolicy() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/groupId1/policies/policyId");
+      PolicyApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().method("PUT").endpoint(endpoint).payload(payloadFromResourceWithContentType("/autoscale_policy_update_request.json", MediaType.APPLICATION_JSON)).build(),
+            HttpResponse.builder().statusCode(201).build()
+            ).getPolicyApiForGroupInZone("groupId1", "DFW");
+
+      ScalingPolicy scalingPolicy = ScalingPolicy.builder()
+            .cooldown(6)
+            .type(ScalingPolicyType.WEBHOOK)
+            .name("scale down by 5 percent")
+            .targetType(ScalingPolicyTargetType.PERCENT_CHANGE)
+            .target("-5")
+            .build();
+
+      boolean result = api.update("policyId", scalingPolicy);
+      assertTrue(result);
+   }
+
+   public void testUpdateScalingPolicyFail() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/groupId1/policies/policyId");
+      PolicyApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().method("PUT").endpoint(endpoint).payload(payloadFromResourceWithContentType("/autoscale_policy_update_request.json", MediaType.APPLICATION_JSON)).build(),
+            HttpResponse.builder().statusCode(404).build()
+            ).getPolicyApiForGroupInZone("groupId1", "DFW");      
+
+      ScalingPolicy scalingPolicy = ScalingPolicy.builder()
+            .cooldown(6)
+            .type(ScalingPolicyType.WEBHOOK)
+            .name("scale down by 5 percent")
+            .targetType(ScalingPolicyTargetType.PERCENT_CHANGE)
+            .target("-5")
+            .build();
+
+      boolean result = api.update("policyId", scalingPolicy);
+      assertFalse(result);
+   }
+
+   public void testDeleteScalingPolicy() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/groupId1/policies/policyId");
+      PolicyApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().method("DELETE").endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(201).build()
+            ).getPolicyApiForGroupInZone("groupId1", "DFW");      
+
+      boolean result = api.delete("policyId");
+      assertTrue(result);
+   }
+
+   public void testDeleteScalingPolicyFail() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/groupId1/policies/policyId");
+      PolicyApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().method("DELETE").endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).build()
+            ).getPolicyApiForGroupInZone("groupId1", "DFW");      
+
+      boolean result = api.delete("policyId");
+      assertFalse(result);
+   }
+
+   public void testExecuteScalingPolicy() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/groupId1/policies/policyId/execute");
+      PolicyApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().method("POST").endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(201).build()
+            ).getPolicyApiForGroupInZone("groupId1", "DFW");      
+
+      boolean result = api.execute("policyId");
+      assertTrue(result);
+   }
+
+   public void testExecuteScalingPolicyFail() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/groupId1/policies/policyId/execute");
+      PolicyApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().method("POST").endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).build()
+            ).getPolicyApiForGroupInZone("groupId1", "DFW");      
+
+      boolean result = api.execute("policyId");
+      assertFalse(result);
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/features/ScalingPolicyApiLiveTest.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/features/ScalingPolicyApiLiveTest.java b/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/features/ScalingPolicyApiLiveTest.java
new file mode 100644
index 0000000..ab2e257
--- /dev/null
+++ b/rackspace-autoscale/src/test/java/org/jclouds/rackspace/autoscale/v1/features/ScalingPolicyApiLiveTest.java
@@ -0,0 +1,338 @@
+/*
+ * 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 java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+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.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.domain.ScalingPolicyResponse;
+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;
+import com.google.common.util.concurrent.Uninterruptibles;
+
+/**
+ * Scaling Policy live test
+ * 
+ * @author Zack Shoylev
+ */
+@Test(groups = "unit", testName = "ScalingPolicyApiLiveTest", singleThreaded = true)
+public class ScalingPolicyApiLiveTest 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("c52a0ca6-c1f2-4cd1-b7d6-afbcd1ebda22")
+               .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 = 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(), "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"));
+      }
+   }
+
+   @Test
+   public void testCreatePolicy() {
+      for (String zone : api.getConfiguredZones()) {
+
+         PolicyApi policyApi = api.getPolicyApiForGroupInZone(created.get(zone).get(0).getId(), zone);
+
+         List<ScalingPolicy> scalingPolicies = Lists.newArrayList();
+
+         ScalingPolicy scalingPolicy = ScalingPolicy.builder()
+               .cooldown(1800)
+               .type(ScalingPolicyType.WEBHOOK)
+               .name("scale up by one server")
+               .targetType(ScalingPolicyTargetType.INCREMENTAL)
+               .target("1")
+               .build();
+         scalingPolicies.add(scalingPolicy);
+
+         FluentIterable<ScalingPolicyResponse> scalingPolicyResponse = policyApi.create(scalingPolicies);
+         assertNotNull(scalingPolicyResponse.iterator().next().getId());
+         assertEquals(scalingPolicyResponse.iterator().next().getCooldown(), 1800);
+         assertEquals(scalingPolicyResponse.iterator().next().getTarget(), "1");
+      }
+   }
+
+   @Test
+   public void testListPolicy() {
+      for (String zone : api.getConfiguredZones()) {
+
+         PolicyApi policyApi = api.getPolicyApiForGroupInZone(created.get(zone).get(0).getId(), zone);
+
+         FluentIterable<ScalingPolicyResponse> scalingPolicyResponse = policyApi.list();
+         assertNotNull(scalingPolicyResponse.iterator().next().getId());
+      }
+   }
+
+   @Test
+   public void testGetPolicy() {
+      for (String zone : api.getConfiguredZones()) {
+
+         PolicyApi policyApi = api.getPolicyApiForGroupInZone(created.get(zone).get(0).getId(), zone);
+
+         assertNotNull(policyApi);
+         ScalingPolicyResponse listResponse = policyApi.list().iterator().next();
+         ScalingPolicyResponse getResponse = policyApi.get(listResponse.getId());
+         assertEquals(listResponse.getId(), getResponse.getId());
+         assertEquals(listResponse.getName(), getResponse.getName());
+         assertEquals(listResponse.getCooldown(), getResponse.getCooldown());
+         assertEquals(listResponse.getLinks(), getResponse.getLinks());
+         assertEquals(listResponse.getTarget(), getResponse.getTarget());
+         assertEquals(listResponse.getTargetType(), getResponse.getTargetType());
+         assertEquals(listResponse.getType(), getResponse.getType());
+      }
+   }
+
+   @Test
+   public void testUpdatePolicy() {
+      for (String zone : api.getConfiguredZones()) {
+
+         PolicyApi policyApi = api.getPolicyApiForGroupInZone(created.get(zone).get(0).getId(), zone);
+
+         List<ScalingPolicy> scalingPolicies = Lists.newArrayList();
+
+         ScalingPolicy scalingPolicy = ScalingPolicy.builder()
+               .cooldown(1800)
+               .type(ScalingPolicyType.WEBHOOK)
+               .name("scale up by one server")
+               .targetType(ScalingPolicyTargetType.INCREMENTAL)
+               .target("1")
+               .build();
+         scalingPolicies.add(scalingPolicy);
+
+         ScalingPolicy updated = ScalingPolicy.builder()
+               .cooldown(2000)
+               .type(ScalingPolicyType.WEBHOOK)
+               .name("scale up by 2 PERCENT server")
+               .targetType(ScalingPolicyTargetType.PERCENT_CHANGE)
+               .target("2")
+               .build();
+
+
+         FluentIterable<ScalingPolicyResponse> scalingPolicyResponse = policyApi.create(scalingPolicies);
+         String policyId = scalingPolicyResponse.iterator().next().getId();
+         assertNotNull(policyId);
+
+         boolean result = policyApi.update(policyId, updated);
+         assertTrue(result);
+
+         ScalingPolicyResponse updatedResponse = policyApi.get(policyId);
+
+         assertNotNull(updatedResponse.getId());
+         assertEquals(updatedResponse.getCooldown(), 2000);
+         assertEquals(updatedResponse.getTarget(), "2");
+         assertEquals(updatedResponse.getTargetType(), ScalingPolicyTargetType.PERCENT_CHANGE);
+         assertEquals(updatedResponse.getType(), ScalingPolicyType.WEBHOOK);
+         assertEquals(updatedResponse.getName(), "scale up by 2 PERCENT server");
+      }
+   }
+
+   @Test
+   public void testDeletePolicy() {
+      for (String zone : api.getConfiguredZones()) {
+
+         PolicyApi policyApi = api.getPolicyApiForGroupInZone(created.get(zone).get(0).getId(), zone);
+
+         List<ScalingPolicy> scalingPolicies = Lists.newArrayList();
+
+         ScalingPolicy scalingPolicy = ScalingPolicy.builder()
+               .cooldown(1800)
+               .type(ScalingPolicyType.WEBHOOK)
+               .name("scale up by one server")
+               .targetType(ScalingPolicyTargetType.INCREMENTAL)
+               .target("1")
+               .build();
+         scalingPolicies.add(scalingPolicy);         
+
+         FluentIterable<ScalingPolicyResponse> scalingPolicyResponse = policyApi.create(scalingPolicies);
+         String policyId = scalingPolicyResponse.iterator().next().getId();
+         assertNotNull(policyId);
+
+         boolean result = policyApi.delete(policyId);
+         assertTrue(result);
+      }
+   }
+
+   @Test
+   public void testExecutePolicy() {
+      for (String zone : api.getConfiguredZones()) {
+
+         PolicyApi policyApi = api.getPolicyApiForGroupInZone(created.get(zone).get(0).getId(), zone);
+
+         List<ScalingPolicy> scalingPolicies = Lists.newArrayList();
+
+         ScalingPolicy scalingPolicy = ScalingPolicy.builder()
+               .cooldown(1800)
+               .type(ScalingPolicyType.WEBHOOK)
+               .name("scale up by 0 server")
+               .targetType(ScalingPolicyTargetType.INCREMENTAL)
+               .target("1")
+               .build();
+         scalingPolicies.add(scalingPolicy);         
+
+         FluentIterable<ScalingPolicyResponse> scalingPolicyResponse = policyApi.create(scalingPolicies);
+         String policyId = scalingPolicyResponse.iterator().next().getId();
+         assertNotNull(policyId);
+
+         boolean result = policyApi.execute(policyId);
+         assertTrue(result);
+      }
+   }   
+
+   @Override
+   @AfterClass(groups = { "integration", "live" })
+   public void tearDown() {
+      for (String zone : api.getConfiguredZones()) {
+         GroupApi groupApi = api.getGroupApiForZone(zone);
+         for (Group group : created.get(zone)) {
+            PolicyApi policyApi = api.getPolicyApiForGroupInZone(group.getId(), zone);
+            if(policyApi == null)continue;
+            for(ScalingPolicyResponse sgr : policyApi.list()) {
+               if(!policyApi.delete(sgr.getId())) {
+                  System.out.println("Could not delete an autoscale policy after tests!");
+               }
+            }
+
+            List<ScalingPolicy> scalingPolicies = Lists.newArrayList();
+
+            ScalingPolicy scalingPolicy = ScalingPolicy.builder()
+                  .cooldown(1)
+                  .type(ScalingPolicyType.WEBHOOK)
+                  .name("0 machines")
+                  .targetType(ScalingPolicyTargetType.DESIRED_CAPACITY)
+                  .target("0")
+                  .build();
+            scalingPolicies.add(scalingPolicy);
+
+            FluentIterable<ScalingPolicyResponse> scalingPolicyResponse = policyApi.create(scalingPolicies);
+            String policyId = scalingPolicyResponse.iterator().next().getId();
+
+            Uninterruptibles.sleepUninterruptibly(3, TimeUnit.SECONDS);
+
+            policyApi.execute(policyId);
+
+            Uninterruptibles.sleepUninterruptibly(3, TimeUnit.SECONDS);
+
+            if (!groupApi.delete(group.getId()))
+               System.out.println("Could not delete an autoscale group after tests!");
+         }
+      }
+      super.tearDown();
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/test/resources/autoscale_groups_configuration_get_response.json
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/test/resources/autoscale_groups_configuration_get_response.json b/rackspace-autoscale/src/test/resources/autoscale_groups_configuration_get_response.json
new file mode 100644
index 0000000..d8799c3
--- /dev/null
+++ b/rackspace-autoscale/src/test/resources/autoscale_groups_configuration_get_response.json
@@ -0,0 +1,12 @@
+{
+    "groupConfiguration": {
+        "name": "workers",
+        "cooldown": 60,
+        "minEntities": 5,
+        "maxEntities": 100,
+        "metadata": {
+            "firstkey": "this is a string",
+            "secondkey": "1"
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/test/resources/autoscale_groups_launch_configuration_get_response.json
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/test/resources/autoscale_groups_launch_configuration_get_response.json b/rackspace-autoscale/src/test/resources/autoscale_groups_launch_configuration_get_response.json
new file mode 100644
index 0000000..c80e6ea
--- /dev/null
+++ b/rackspace-autoscale/src/test/resources/autoscale_groups_launch_configuration_get_response.json
@@ -0,0 +1,33 @@
+{
+    "launchConfiguration": {
+            "type": "launch_server",
+            "args": {
+                "server": {
+                    "flavorRef": "3",
+                    "name": "webhead",
+                    "imageRef": "0d589460-f177-4b0f-81c1-8ab8903ac7d8",
+                    "OS-DCF:diskConfig": "AUTO",
+                    "metadata": {
+                        "mykey": "myvalue"
+                    },
+                    "personality": [
+                        {
+                            "path": "/root/.ssh/authorized_keys",
+                            "contents": "ssh-rsa AAAAB3Nza...LiPk== user@example.net"
+                        }
+                    ],
+                    "networks": [
+                        {
+                            "uuid": "11111111-1111-1111-1111-111111111111"
+                        }
+                    ]
+                },
+                "loadBalancers": [
+                    {
+                        "loadBalancerId": 2200,
+                        "port": 8081
+                    }
+                ]
+            }
+        }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/test/resources/autoscale_groups_update_configuration_request.json
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/test/resources/autoscale_groups_update_configuration_request.json b/rackspace-autoscale/src/test/resources/autoscale_groups_update_configuration_request.json
new file mode 100644
index 0000000..70704cd
--- /dev/null
+++ b/rackspace-autoscale/src/test/resources/autoscale_groups_update_configuration_request.json
@@ -0,0 +1,10 @@
+{
+    "name": "workers",
+    "cooldown": 60,
+    "minEntities": 5,
+    "maxEntities": 100,
+    "metadata": {
+        "firstkey": "this is a string",
+        "secondkey": "1"
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/test/resources/autoscale_groups_update_launch_configuration_request.json
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/test/resources/autoscale_groups_update_launch_configuration_request.json b/rackspace-autoscale/src/test/resources/autoscale_groups_update_launch_configuration_request.json
new file mode 100644
index 0000000..9ab0d78
--- /dev/null
+++ b/rackspace-autoscale/src/test/resources/autoscale_groups_update_launch_configuration_request.json
@@ -0,0 +1,36 @@
+{
+    "args":{
+        "loadBalancers":[
+            {
+                "port":8080,
+                "loadBalancerId":9099
+            }
+        ],
+        "server":{
+            "name":"autoscale_server",
+            "imageRef":"0d589460-f177-4b0f-81c1-8ab8903ac7d8",
+            "flavorRef":"2",
+            "OS-DCF:diskConfig":"AUTO",
+            "metadata":{
+                "build_config":"core",
+                "meta_key_1":"meta_value_1",
+                "meta_key_2":"meta_value_2"
+            },
+            "networks":[
+                {
+                    "uuid":"11111111-1111-1111-1111-111111111111"
+                },
+                {
+                    "uuid":"00000000-0000-0000-0000-000000000000"
+                }
+            ],
+            "personality":[
+                {
+                    "path":"/root/.csivh",
+                    "contents":"VGhpcyBpcyBhIHRlc3QgZmlsZS4="
+                }
+            ]
+        }
+    },
+    "type":"launch_server"
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/test/resources/autoscale_policy_create_request.json
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/test/resources/autoscale_policy_create_request.json b/rackspace-autoscale/src/test/resources/autoscale_policy_create_request.json
new file mode 100644
index 0000000..b0918a8
--- /dev/null
+++ b/rackspace-autoscale/src/test/resources/autoscale_policy_create_request.json
@@ -0,0 +1,8 @@
+[  
+   {
+    "name": "scale up by one server",
+    "change": 1,
+    "cooldown": 1800,
+    "type": "webhook"
+  }
+]

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/test/resources/autoscale_policy_create_response.json
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/test/resources/autoscale_policy_create_response.json b/rackspace-autoscale/src/test/resources/autoscale_policy_create_response.json
new file mode 100644
index 0000000..62d333c
--- /dev/null
+++ b/rackspace-autoscale/src/test/resources/autoscale_policy_create_response.json
@@ -0,0 +1,18 @@
+{
+"policies":
+[
+  {
+    "cooldown": 1800,
+    "type": "webhook",
+    "name": "scale up by one server",
+    "change": 1,
+    "links": [
+          {
+            "href": "https://ord.autoscale.api.rackspacecloud.com/v1.0/829409/groups/6791761b-821a-4d07-820d-0b2afc7dd7f6/policies/dceb14ac-b2b3-4f06-aac9-a5b6cd5d40e1/",
+            "rel": "self"
+          }
+        ],
+    "id": "dceb14ac-b2b3-4f06-aac9-a5b6cd5d40e1"
+  }
+]
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/test/resources/autoscale_policy_get_response.json
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/test/resources/autoscale_policy_get_response.json b/rackspace-autoscale/src/test/resources/autoscale_policy_get_response.json
new file mode 100644
index 0000000..aa241b4
--- /dev/null
+++ b/rackspace-autoscale/src/test/resources/autoscale_policy_get_response.json
@@ -0,0 +1,15 @@
+{
+    "policy": {
+        "id": "policyId",
+        "links": [
+            {
+                "href": "urlRoot/v1.0/010101/groups/groupId/policy/policyId",
+                "rel": "self"
+            }
+        ],
+        "name": "scale up by one server",
+        "change": 1,
+        "cooldown": 150,
+        "type": "webhook"
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/test/resources/autoscale_policy_list_response.json
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/test/resources/autoscale_policy_list_response.json b/rackspace-autoscale/src/test/resources/autoscale_policy_list_response.json
new file mode 100644
index 0000000..843370c
--- /dev/null
+++ b/rackspace-autoscale/src/test/resources/autoscale_policy_list_response.json
@@ -0,0 +1,30 @@
+{
+    "policies": [
+        {
+            "id":"policyId1",
+            "name": "scale up by one server",
+            "change": 1,
+            "cooldown": 150,
+            "type": "webhook",
+            "links": [
+                {
+                    "href": "urlRoot/v1.0/010101/groups/groupId1/policy/policyId1",
+                    "rel": "self"
+                }
+            ]
+        },
+        {
+            "id": "policyId2",
+            "name": "scale up ten percent",
+            "changePercent": 10,
+            "cooldown": 150,
+            "type": "webhook",
+            "links": [
+                {
+                    "href": "urlRoot/v1.0/010101/groups/groupId1/policy/policyId2",
+                    "rel": "self"
+                }
+            ]
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/test/resources/autoscale_policy_update_request.json
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/test/resources/autoscale_policy_update_request.json b/rackspace-autoscale/src/test/resources/autoscale_policy_update_request.json
new file mode 100644
index 0000000..e0438bd
--- /dev/null
+++ b/rackspace-autoscale/src/test/resources/autoscale_policy_update_request.json
@@ -0,0 +1,6 @@
+{
+    "name": "scale down by 5 percent",
+    "changePercent": -5,
+    "cooldown": 6,
+    "type": "webhook"
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/test/resources/autoscale_webhook_get_response.json
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/test/resources/autoscale_webhook_get_response.json b/rackspace-autoscale/src/test/resources/autoscale_webhook_get_response.json
new file mode 100644
index 0000000..fa1d859
--- /dev/null
+++ b/rackspace-autoscale/src/test/resources/autoscale_webhook_get_response.json
@@ -0,0 +1,17 @@
+{
+    "webhook": {
+        "id":"{webhookId}",
+        "name": "webhook name",
+        "metadata": {},
+        "links": [
+            {
+                "href": ".../{groupId1}/policies/{policyId1}/webhooks/{webhookId}/",
+                "rel": "self"
+            },
+            {
+                "href": ".../execute/1/{capabilityHash2}",
+                "rel": "capability"
+            }
+        ]
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/test/resources/autoscale_webhook_update_request.json
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/test/resources/autoscale_webhook_update_request.json b/rackspace-autoscale/src/test/resources/autoscale_webhook_update_request.json
new file mode 100644
index 0000000..5b74d4d
--- /dev/null
+++ b/rackspace-autoscale/src/test/resources/autoscale_webhook_update_request.json
@@ -0,0 +1,6 @@
+{
+    "name": "alice",
+    "metadata": {
+        "notes": "this is for Alice"
+    }
+}


[2/2] git commit: JCLOUDS-215 - Adds Group configuration, Group launch, Scaling policy functionality

Posted by za...@apache.org.
JCLOUDS-215 - Adds Group configuration, Group launch, Scaling policy functionality


Project: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/commit/1c871e12
Tree: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/tree/1c871e12
Diff: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/diff/1c871e12

Branch: refs/heads/master
Commit: 1c871e12e4bd3ea4bd5d208189f63e892eaf23aa
Parents: e3c8147
Author: Zack Shoylev <za...@rackspace.com>
Authored: Tue Oct 1 23:57:34 2013 -0500
Committer: Zack Shoylev <za...@rackspace.com>
Committed: Fri Nov 1 10:10:37 2013 -0500

----------------------------------------------------------------------
 .../us/v1/AutoscaleUSProviderMetadata.java      |   1 -
 .../features/AutoscaleUSGroupApiLiveTest.java   |   2 +-
 .../AutoscaleUSScalingPolicyApiLiveTest.java    |  32 ++
 .../rackspace/autoscale/v1/AutoscaleApi.java    |  12 +
 .../v1/binders/BindCreateGroupToJson.java       |  48 +--
 .../binders/BindLaunchConfigurationToJson.java  |  50 +++
 .../v1/binders/BindScalingPoliciesToJson.java   |  50 +++
 .../v1/binders/BindScalingPolicyToJson.java     |  52 +++
 .../BindToGroupConfigurationRequestPayload.java |  64 ++++
 .../v1/config/AutoscaleHttpApiModule.java       |   8 +-
 .../autoscale/v1/domain/GroupState.java         |  12 +-
 .../autoscale/v1/domain/LoadBalancer.java       |   2 +-
 .../autoscale/v1/domain/ScalingPolicy.java      |  10 +-
 .../v1/domain/ScalingPolicyResponse.java        |   2 +-
 .../autoscale/v1/features/GroupApi.java         |  61 +++-
 .../autoscale/v1/features/PolicyApi.java        | 135 ++++++++
 .../ParseGroupLaunchConfigurationResponse.java  |  94 ++++++
 .../v1/functions/ParseGroupResponse.java        |  39 ++-
 .../functions/ParseScalingPoliciesResponse.java |  95 ++++++
 .../functions/ParseScalingPolicyResponse.java   |  90 +++++
 .../autoscale/v1/internal/ParseHelper.java      | 102 ++++++
 .../v1/features/GroupApiExpectTest.java         | 164 ++++++++-
 .../autoscale/v1/features/GroupApiLiveTest.java |  86 ++++-
 .../v1/features/ScalingPolicyApiExpectTest.java | 265 +++++++++++++++
 .../v1/features/ScalingPolicyApiLiveTest.java   | 338 +++++++++++++++++++
 ...scale_groups_configuration_get_response.json |  12 +
 ...roups_launch_configuration_get_response.json |  33 ++
 ...ale_groups_update_configuration_request.json |  10 +
 ...ups_update_launch_configuration_request.json |  36 ++
 .../autoscale_policy_create_request.json        |   8 +
 .../autoscale_policy_create_response.json       |  18 +
 .../autoscale_policy_get_response.json          |  15 +
 .../autoscale_policy_list_response.json         |  30 ++
 .../autoscale_policy_update_request.json        |   6 +
 .../autoscale_webhook_get_response.json         |  17 +
 .../autoscale_webhook_update_request.json       |   6 +
 36 files changed, 1918 insertions(+), 87 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale-us/src/main/java/org/jclouds/rackspace/autoscale/us/v1/AutoscaleUSProviderMetadata.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale-us/src/main/java/org/jclouds/rackspace/autoscale/us/v1/AutoscaleUSProviderMetadata.java b/rackspace-autoscale-us/src/main/java/org/jclouds/rackspace/autoscale/us/v1/AutoscaleUSProviderMetadata.java
index f680c25..c7844ea 100644
--- a/rackspace-autoscale-us/src/main/java/org/jclouds/rackspace/autoscale/us/v1/AutoscaleUSProviderMetadata.java
+++ b/rackspace-autoscale-us/src/main/java/org/jclouds/rackspace/autoscale/us/v1/AutoscaleUSProviderMetadata.java
@@ -25,7 +25,6 @@ import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERV
 import java.net.URI;
 import java.util.Properties;
 
-import org.jclouds.apis.ApiMetadata;
 import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.ZoneModule;
 import org.jclouds.providers.ProviderMetadata;
 import org.jclouds.providers.internal.BaseProviderMetadata;

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale-us/src/test/java/org/jclouds/rackspace/autoscale/us/v1/features/AutoscaleUSGroupApiLiveTest.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale-us/src/test/java/org/jclouds/rackspace/autoscale/us/v1/features/AutoscaleUSGroupApiLiveTest.java b/rackspace-autoscale-us/src/test/java/org/jclouds/rackspace/autoscale/us/v1/features/AutoscaleUSGroupApiLiveTest.java
index 08ac5fb..3c3b7f0 100644
--- a/rackspace-autoscale-us/src/test/java/org/jclouds/rackspace/autoscale/us/v1/features/AutoscaleUSGroupApiLiveTest.java
+++ b/rackspace-autoscale-us/src/test/java/org/jclouds/rackspace/autoscale/us/v1/features/AutoscaleUSGroupApiLiveTest.java
@@ -24,7 +24,7 @@ import org.testng.annotations.Test;
  *
  * @author Zack Shoylev
  */
-@Test(groups = "unit", testName = "AutoscaleUSGroupApiLiveTest")
+@Test(groups = "unit", testName = "AutoscaleUSGroupApiLiveTest", singleThreaded = true)
 public class AutoscaleUSGroupApiLiveTest extends GroupApiLiveTest {
    public AutoscaleUSGroupApiLiveTest() {
       provider = "rackspace-autoscale-us";

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale-us/src/test/java/org/jclouds/rackspace/autoscale/us/v1/features/AutoscaleUSScalingPolicyApiLiveTest.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale-us/src/test/java/org/jclouds/rackspace/autoscale/us/v1/features/AutoscaleUSScalingPolicyApiLiveTest.java b/rackspace-autoscale-us/src/test/java/org/jclouds/rackspace/autoscale/us/v1/features/AutoscaleUSScalingPolicyApiLiveTest.java
new file mode 100644
index 0000000..12c9d26
--- /dev/null
+++ b/rackspace-autoscale-us/src/test/java/org/jclouds/rackspace/autoscale/us/v1/features/AutoscaleUSScalingPolicyApiLiveTest.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.autoscale.us.v1.features;
+
+import org.jclouds.rackspace.autoscale.v1.features.ScalingPolicyApiLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ * Tests GroupApi Guice wiring and parsing
+ *
+ * @author Zack Shoylev
+ */
+@Test(groups = "unit", testName = "AutoscaleUSGroupApiLiveTest", singleThreaded = true)
+public class AutoscaleUSScalingPolicyApiLiveTest extends ScalingPolicyApiLiveTest {
+   public AutoscaleUSScalingPolicyApiLiveTest() {
+      provider = "rackspace-autoscale-us";
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/AutoscaleApi.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/AutoscaleApi.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/AutoscaleApi.java
index 4563a3f..1ae148d 100644
--- a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/AutoscaleApi.java
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/AutoscaleApi.java
@@ -19,11 +19,15 @@ package org.jclouds.rackspace.autoscale.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.rackspace.autoscale.v1.features.GroupApi;
+import org.jclouds.rackspace.autoscale.v1.features.PolicyApi;
 import org.jclouds.rest.annotations.Delegate;
 import org.jclouds.rest.annotations.EndpointParam;
 
@@ -54,6 +58,14 @@ public interface AutoscaleApi extends Closeable{
    GroupApi getGroupApiForZone(@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
 
    /**
+    * Provides access to all policy features for scaling Groups.
+    */
+   @Delegate
+   @Path("/groups/{groupId}")
+   PolicyApi getPolicyApiForGroupInZone(@PathParam("groupId") String groupId, 
+         @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
+
+   /**
     * Provides the Tenant.
     */
    @Provides 

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindCreateGroupToJson.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindCreateGroupToJson.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindCreateGroupToJson.java
index 8e06f95..1a51d39 100644
--- a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindCreateGroupToJson.java
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindCreateGroupToJson.java
@@ -16,18 +16,16 @@
  */
 package org.jclouds.rackspace.autoscale.v1.binders;
 
-import java.util.List;
 import java.util.Map;
+
 import org.jclouds.http.HttpRequest;
 import org.jclouds.rackspace.autoscale.v1.domain.GroupConfiguration;
-import org.jclouds.rackspace.autoscale.v1.domain.LaunchConfiguration;
-import org.jclouds.rackspace.autoscale.v1.domain.ScalingPolicy;
+import org.jclouds.rackspace.autoscale.v1.internal.ParseHelper;
 import org.jclouds.rest.MapBinder;
 import org.jclouds.rest.binders.BindToJsonPayload;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
 import com.google.inject.Inject;
 
 /**
@@ -43,46 +41,12 @@ public class BindCreateGroupToJson implements MapBinder {
       this.jsonBinder = jsonBinder;
    }
 
-   @SuppressWarnings("unchecked")
    @Override    
    public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
-      List<ScalingPolicy> scalingPoliciesRequest = (List<ScalingPolicy>) postParams.get("scalingPolicies");
-      LaunchConfiguration launchConfigurationRequest = (LaunchConfiguration) postParams.get("launchConfiguration");
 
+      ImmutableMap<String, Object> launchConfigurationMap = ParseHelper.buildLaunchConfigurationRequestMap(postParams);
       GroupConfiguration groupConfiguration = (GroupConfiguration) postParams.get("groupConfiguration");
-
-      Map<String, Object> launchConfigurationMap = Maps.newHashMap();
-      List<Map<String, Object>> scalingPoliciesList = Lists.newArrayList();
-      Map<String, Object> args = Maps.newHashMap();
-      launchConfigurationMap.put("args", args);
-      launchConfigurationMap.put("type", launchConfigurationRequest.getType().toString());
-
-      args.put("loadBalancers", launchConfigurationRequest.getLoadBalancers());
-      Map<String, Object> server = Maps.newHashMap();
-      args.put("server", server);
-      server.put("name", launchConfigurationRequest.getServerName());
-      server.put("imageRef", launchConfigurationRequest.getServerImageRef());
-      server.put("flavorRef", launchConfigurationRequest.getServerFlavorRef());
-      server.put("OS-DCF:diskConfig", launchConfigurationRequest.getServerDiskConfig());
-      server.put("metadata", launchConfigurationRequest.getServerMetadata());
-      List<Map<String, String>> networks = Lists.newArrayList();
-      server.put("networks", networks);
-      for(String networkId : launchConfigurationRequest.getNetworks()) {
-         Map<String, String> network = Maps.newHashMap();
-         network.put("uuid", networkId);
-         networks.add(network);
-      }
-      server.put("personality", launchConfigurationRequest.getPersonalities());
-
-      for(ScalingPolicy scalingPolicy : scalingPoliciesRequest) {
-         Map<String,Object> scalingPolicyMap = Maps.newHashMap();
-         scalingPoliciesList.add(scalingPolicyMap);
-         scalingPolicyMap.put("cooldown", scalingPolicy.getCooldown());
-         scalingPolicyMap.put("type", scalingPolicy.getType().toString());
-         scalingPolicyMap.put("name", scalingPolicy.getName());
-         // A couple of different scaling policies are supported, such as percent or number based, or targeting specific numbers of instances
-         scalingPolicyMap.put(scalingPolicy.getTargetType().toString(), scalingPolicy.getTarget());
-      }
+      ImmutableList<Map<String, Object>> scalingPoliciesList = ParseHelper.buildScalingPoliciesRequestList(postParams);
 
       return jsonBinder.bindToRequest(request, ImmutableMap.of(
             "launchConfiguration", launchConfigurationMap, 
@@ -92,6 +56,6 @@ public class BindCreateGroupToJson implements MapBinder {
 
    @Override
    public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
-      throw new IllegalStateException("CreateInstance is a POST operation");
+      throw new IllegalStateException("Create scaling group is a POST operation");
    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindLaunchConfigurationToJson.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindLaunchConfigurationToJson.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindLaunchConfigurationToJson.java
new file mode 100644
index 0000000..86be582
--- /dev/null
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindLaunchConfigurationToJson.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.rackspace.autoscale.v1.binders;
+
+import java.util.Map;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rackspace.autoscale.v1.internal.ParseHelper;
+import org.jclouds.rest.MapBinder;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import com.google.inject.Inject;
+
+/**
+ * Decouple building the json object from the domain objects structure by using the binder
+ * @author Zack Shoylev
+ */
+public class BindLaunchConfigurationToJson implements MapBinder {
+
+   private final BindToJsonPayload jsonBinder;
+
+   @Inject
+   private BindLaunchConfigurationToJson(BindToJsonPayload jsonBinder) {
+      this.jsonBinder = jsonBinder;
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
+      return jsonBinder.bindToRequest(request, ParseHelper.buildLaunchConfigurationRequestMap(postParams));
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
+      throw new IllegalStateException("Update launch configuration is a POST operation");
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindScalingPoliciesToJson.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindScalingPoliciesToJson.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindScalingPoliciesToJson.java
new file mode 100644
index 0000000..4ba1308
--- /dev/null
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindScalingPoliciesToJson.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.rackspace.autoscale.v1.binders;
+
+import java.util.Map;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rackspace.autoscale.v1.internal.ParseHelper;
+import org.jclouds.rest.MapBinder;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import com.google.inject.Inject;
+
+/**
+ * Decouple building the json object from the domain objects structure by using the binder
+ * @author Zack Shoylev
+ */
+public class BindScalingPoliciesToJson implements MapBinder {
+
+   private final BindToJsonPayload jsonBinder;
+
+   @Inject
+   private BindScalingPoliciesToJson(BindToJsonPayload jsonBinder) {
+      this.jsonBinder = jsonBinder;
+   }
+
+   @Override    
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
+      return jsonBinder.bindToRequest(request, ParseHelper.buildScalingPoliciesRequestList(postParams));
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
+      throw new IllegalStateException("Create Policies is a POST operation");
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindScalingPolicyToJson.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindScalingPolicyToJson.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindScalingPolicyToJson.java
new file mode 100644
index 0000000..ec77508
--- /dev/null
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindScalingPolicyToJson.java
@@ -0,0 +1,52 @@
+/*
+ * 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.binders;
+
+import java.util.Map;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rackspace.autoscale.v1.domain.ScalingPolicy;
+import org.jclouds.rackspace.autoscale.v1.internal.ParseHelper;
+import org.jclouds.rest.MapBinder;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import com.google.inject.Inject;
+
+/**
+ * Decouple building the json object from the domain objects structure by using the binder
+ * @author Zack Shoylev
+ */
+public class BindScalingPolicyToJson implements MapBinder {
+
+   private final BindToJsonPayload jsonBinder;
+
+   @Inject
+   private BindScalingPolicyToJson(BindToJsonPayload jsonBinder) {
+      this.jsonBinder = jsonBinder;
+   }
+
+   @Override    
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
+      ScalingPolicy scalingPolicy = (ScalingPolicy) postParams.get("scalingPolicy");
+      return jsonBinder.bindToRequest(request, ParseHelper.buildScalingPolicyMap(scalingPolicy));
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
+      throw new IllegalStateException("Update policy is a POST operation");
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindToGroupConfigurationRequestPayload.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindToGroupConfigurationRequestPayload.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindToGroupConfigurationRequestPayload.java
new file mode 100644
index 0000000..af0ddf6
--- /dev/null
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/binders/BindToGroupConfigurationRequestPayload.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.autoscale.v1.binders;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+
+import javax.inject.Inject;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.json.Json;
+import org.jclouds.rackspace.autoscale.v1.domain.GroupConfiguration;
+import org.jclouds.rest.MapBinder;
+
+import com.google.common.collect.Maps;
+
+/**
+ * 
+ * @author Zack Shoylev
+ */
+public class BindToGroupConfigurationRequestPayload implements MapBinder {
+
+   protected final Json jsonBinder;
+
+   @Inject
+   public BindToGroupConfigurationRequestPayload(Json jsonBinder) {
+      this.jsonBinder = checkNotNull(jsonBinder, "jsonBinder");
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
+      GroupConfiguration gc = (GroupConfiguration) postParams.get("groupConfiguration");
+      Map<String, Object> gcMap = Maps.newHashMap();
+      gcMap.put("name", gc.getName());
+      gcMap.put("cooldown", gc.getCooldown());
+      gcMap.put("minEntities", gc.getMinEntities());
+      gcMap.put("maxEntities", gc.getMaxEntities());
+      gcMap.put("metadata", gc.getMetadata());
+
+      request.setPayload(jsonBinder.toJson(gcMap));
+      request.getPayload().getContentMetadata().setContentType("application/json");
+      return request;
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
+      throw new IllegalStateException("Illegal unwrap operation");
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/config/AutoscaleHttpApiModule.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/config/AutoscaleHttpApiModule.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/config/AutoscaleHttpApiModule.java
index 9311287..1be469f 100644
--- a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/config/AutoscaleHttpApiModule.java
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/config/AutoscaleHttpApiModule.java
@@ -46,12 +46,12 @@ import com.google.inject.Provides;
  */
 @ConfiguresHttpApi
 public class AutoscaleHttpApiModule extends HttpApiModule<AutoscaleApi> {
-   
+
    @Override
    protected void configure() {
       super.configure();
    }
-   
+
    @Provides
    @Singleton
    public Multimap<URI, URI> aliases() {
@@ -64,12 +64,12 @@ public class AutoscaleHttpApiModule extends HttpApiModule<AutoscaleApi> {
       bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(AutoscaleErrorHandler.class);
       bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(AutoscaleErrorHandler.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){

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/GroupState.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/GroupState.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/GroupState.java
index 5b26e34..33af167 100644
--- a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/GroupState.java
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/domain/GroupState.java
@@ -50,12 +50,20 @@ public class GroupState implements Comparable<GroupState> {
    protected GroupState(String id, List<Link> links, int activeCapacity, int pendingCapacity,
          int desiredCapacity, boolean paused, List<GroupInstance> groupInstances) {
       this.id = id;
-      this.links = ImmutableList.copyOf(links);
+      if (links == null) {
+         this.links = ImmutableList.of();
+      } else {
+         this.links = ImmutableList.copyOf(links);
+      }
       this.activeCapacity = activeCapacity;
       this.pendingCapacity = pendingCapacity;
       this.desiredCapacity = desiredCapacity;
       this.paused = paused;
-      this.groupInstances = ImmutableList.copyOf(groupInstances);
+      if (groupInstances == null) {
+         this.groupInstances = ImmutableList.of();
+      } else {
+         this.groupInstances = ImmutableList.copyOf(groupInstances);
+      }
    }
 
    /**

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/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
index 004bb97..eb8eaa6 100644
--- 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
@@ -30,7 +30,7 @@ import com.google.gson.annotations.SerializedName;
  * @see LaunchConfiguration#getLoadBalancers()
  * @author Zack Shoylev
  */
-public class LoadBalancer { 
+public class LoadBalancer {
    private final int port;
    @SerializedName("loadBalancerId")
    private final int id;

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/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
index 0cefb05..3ecaa97 100644
--- 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
@@ -40,13 +40,13 @@ public class ScalingPolicy implements Comparable<ScalingPolicy>{
    private final String name;
    private final ScalingPolicyType type;
    private final int cooldown;
-   private final int target;
+   private final String target;
    private final ScalingPolicyTargetType targetType;
 
    @ConstructorProperties({
       "name", "type", "cooldown", "target", "targetType"
    })
-   protected ScalingPolicy(String name, ScalingPolicyType type, int cooldown, int target, ScalingPolicyTargetType targetType) {
+   protected ScalingPolicy(String name, ScalingPolicyType type, int cooldown, String target, ScalingPolicyTargetType targetType) {
 
       this.name = checkNotNull(name, "name required");
       this.type = type;
@@ -86,7 +86,7 @@ public class ScalingPolicy implements Comparable<ScalingPolicy>{
     * 
     * @see ScalingPolicy.Builder#target(int)
     */
-   public int getTarget() {
+   public String getTarget() {
       return this.target;
    }
 
@@ -142,7 +142,7 @@ public class ScalingPolicy implements Comparable<ScalingPolicy>{
       protected String name;
       protected ScalingPolicyType type;
       protected int cooldown;
-      protected int target;
+      protected String target;
       protected ScalingPolicyTargetType targetType;
 
       /** 
@@ -181,7 +181,7 @@ public class ScalingPolicy implements Comparable<ScalingPolicy>{
        * @return The builder object.
        * @see ScalingPolicy#getTarget()
        */
-      public Builder target(int target) {
+      public Builder target(String target) {
          this.target = target;
          return this;
       }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/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
index c469719..eb1249e 100644
--- 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
@@ -40,7 +40,7 @@ public class ScalingPolicyResponse extends ScalingPolicy{
    @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) {
+   public ScalingPolicyResponse(String name, ScalingPolicyType type, int cooldown, String 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"));

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/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
index f12b690..abad72f 100644
--- 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
@@ -16,7 +16,6 @@
  */
 package org.jclouds.rackspace.autoscale.v1.features;
 
-
 import java.util.List;
 
 import javax.inject.Named;
@@ -24,6 +23,7 @@ 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;
@@ -32,11 +32,14 @@ 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.binders.BindLaunchConfigurationToJson;
+import org.jclouds.rackspace.autoscale.v1.binders.BindToGroupConfigurationRequestPayload;
 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.ParseGroupLaunchConfigurationResponse;
 import org.jclouds.rackspace.autoscale.v1.functions.ParseGroupResponse;
 import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.MapBinder;
@@ -98,7 +101,7 @@ public interface GroupApi {
     * @return true if successful.
     * @see GroupApi#pause(String)
     */
-   @Named("Groups:pause/{groupId}")
+   @Named("Groups:resume/{groupId}")
    @POST
    @Path("/groups/{groupId}/resume")
    @Consumes(MediaType.APPLICATION_JSON)
@@ -156,4 +159,58 @@ public interface GroupApi {
    @SelectJson("groups")
    @Consumes(MediaType.APPLICATION_JSON)
    FluentIterable<GroupState> listGroupStates();
+   
+   /**
+    * This operation gets the configuration for the scaling group.
+    * @return The group configuration for the scaling group.
+    * @see GroupConfiguration
+    */
+   @Named("Group:configuration")
+   @GET
+   @Path("/groups/{groupId}/config")
+   @SelectJson("groupConfiguration")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(NullOnNotFoundOr404.class)
+   GroupConfiguration getGroupConfiguration(@PathParam("groupId") String id);
+   
+   /**
+    * This operation updates the configuration for the scaling group.
+    * @return true if successful.
+    * @see GroupConfiguration
+    */
+   @Named("Group:updateConfiguration")
+   @PUT
+   @Path("/groups/{groupId}/config")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(FalseOnNotFoundOr404.class)
+   @MapBinder(BindToGroupConfigurationRequestPayload.class)
+   boolean updateGroupConfiguration(@PathParam("groupId") String id,
+         @PayloadParam("groupConfiguration") GroupConfiguration groupConfiguration);
+   
+   /**
+    * This operation gets the launch configuration for the scaling group.
+    * @return The launch configuration for the scaling group.
+    * @see LaunchConfiguration
+    */
+   @Named("Group:launchConfiguration")
+   @GET
+   @Path("/groups/{groupId}/launch")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(NullOnNotFoundOr404.class)
+   @ResponseParser(ParseGroupLaunchConfigurationResponse.class)
+   LaunchConfiguration getLaunchConfiguration(@PathParam("groupId") String id);
+   
+   /**
+    * This operation updates the launch configuration for the scaling group.
+    * @return true if successful.
+    * @see LaunchConfiguration
+    */
+   @Named("Group:updateLaunchConfiguration")
+   @PUT
+   @Path("/groups/{groupId}/launch")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(FalseOnNotFoundOr404.class)
+   @MapBinder(BindLaunchConfigurationToJson.class)
+   boolean updateLaunchConfiguration(@PathParam("groupId") String id, 
+         @PayloadParam("launchConfiguration") LaunchConfiguration launchConfiguration);
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/features/PolicyApi.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/features/PolicyApi.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/features/PolicyApi.java
new file mode 100644
index 0000000..fdfc0e2
--- /dev/null
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/features/PolicyApi.java
@@ -0,0 +1,135 @@
+/*
+ * 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.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.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.rackspace.autoscale.v1.binders.BindScalingPoliciesToJson;
+import org.jclouds.rackspace.autoscale.v1.binders.BindScalingPolicyToJson;
+import org.jclouds.rackspace.autoscale.v1.domain.ScalingPolicy;
+import org.jclouds.rackspace.autoscale.v1.domain.ScalingPolicyResponse;
+import org.jclouds.rackspace.autoscale.v1.functions.ParseScalingPoliciesResponse;
+import org.jclouds.rackspace.autoscale.v1.functions.ParseScalingPolicyResponse;
+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 com.google.common.collect.FluentIterable;
+
+/**
+ * The API for controlling the configuration of 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 PolicyApi {
+   /**
+    * Create a scaling policy.
+    * @param scalingPolicies The list of scaling policies.
+    * @return List of the created scaling policies
+    * @see ScalingPolicy
+    * @see ScalingPolicyResponse
+    */
+   @Named("Policy:create")
+   @POST
+   @Path("/policies")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(EmptyFluentIterableOnNotFoundOr404.class)
+   @MapBinder(BindScalingPoliciesToJson.class)
+   @ResponseParser(ParseScalingPoliciesResponse.class)
+   FluentIterable<ScalingPolicyResponse> create(@PayloadParam("scalingPolicies") List<ScalingPolicy> scalingPolicies);
+
+   /**
+    * This operation lists all scaling policies.
+    * @return A list of scaling policy responses.
+    * @see ScalingPolicyResponse
+    */
+   @Named("Policy:list")
+   @GET
+   @Path("/policies")
+   @ResponseParser(ParseScalingPoliciesResponse.class)
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(EmptyFluentIterableOnNotFoundOr404.class)
+   FluentIterable<ScalingPolicyResponse> list();
+
+   /**
+    * This operation returns the details for a single scaling policy.
+    * @return Existing scaling policy details
+    * @see ScalingPolicyResponse
+    */
+   @Named("Policy:get")
+   @GET
+   @Path("/policies/{scalingPolicyId}")
+   @ResponseParser(ParseScalingPolicyResponse.class)
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(NullOnNotFoundOr404.class)
+   ScalingPolicyResponse get(@PathParam("scalingPolicyId") String scalingPolicyId);
+
+   /**
+    * This operation updates a specific scaling policy.
+    * @return true if successful.
+    * @see ScalingPolicy
+    */
+   @Named("Policy:update")
+   @PUT
+   @Path("/policies/{scalingPolicyId}")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @MapBinder(BindScalingPolicyToJson.class)
+   @Fallback(FalseOnNotFoundOr404.class)
+   boolean update(@PathParam("scalingPolicyId") String scalingPolicyId, @PayloadParam("scalingPolicy") ScalingPolicy scalingPolicy);
+
+   /**
+    * This operation deletes a specific scaling policy.
+    * @return true if successful.
+    * @see ScalingPolicy
+    */
+   @Named("Policy:delete")
+   @DELETE
+   @Path("/policies/{scalingPolicyId}")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(FalseOnNotFoundOr404.class)
+   boolean delete(@PathParam("scalingPolicyId") String scalingPolicyId);
+
+   /**
+    * This operation executes a specific scaling policy.
+    * @return true if successful.
+    * @see ScalingPolicy
+    */
+   @Named("Policy:execute")
+   @POST
+   @Path("/policies/{scalingPolicyId}/execute")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(FalseOnNotFoundOr404.class)
+   boolean execute(@PathParam("scalingPolicyId") String scalingPolicyId);
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/functions/ParseGroupLaunchConfigurationResponse.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/functions/ParseGroupLaunchConfigurationResponse.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/functions/ParseGroupLaunchConfigurationResponse.java
new file mode 100644
index 0000000..0d8bfe4
--- /dev/null
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/functions/ParseGroupLaunchConfigurationResponse.java
@@ -0,0 +1,94 @@
+/*
+ * 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.util.List;
+import java.util.Map;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseJson;
+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 com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+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 ParseGroupLaunchConfigurationResponse implements Function<HttpResponse, LaunchConfiguration> {
+
+   private final ParseJson<Map<String, Object>> json;
+
+   @Inject
+   ParseGroupLaunchConfigurationResponse(ParseJson<Map<String, Object>> json) {
+      this.json = checkNotNull(json, "json");
+   }
+
+   /**
+    * Parses the launch configuration from the response
+    */
+   @SuppressWarnings("unchecked")
+   public LaunchConfiguration apply(HttpResponse from) {
+      // This needs to be refactored when the service is in a more final state and changing less often
+      // A lot of the complexity is expected to go away
+
+      Map<String, Object> result = json.apply(from);
+
+      Map<String, Object> launchConfigurationMap = (Map<String, Object>) result.get("launchConfiguration");
+      Map<String, Object> args = (Map<String, Object>) launchConfigurationMap.get("args");
+      Map<String, Object> server = (Map<String, Object>) args.get("server");      
+
+      ImmutableList.Builder<Personality> personalities = ImmutableList.builder();
+      ImmutableList.Builder<String> networks = ImmutableList.builder();
+      
+      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"));
+      }
+
+      ImmutableList.Builder<LoadBalancer> loadBalancers = ImmutableList.builder();
+      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.build())
+            .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.build())
+            .networks(networks.build())
+            .type(LaunchConfigurationType.getByValue((String) launchConfigurationMap.get("type")).get())
+            .build();
+
+      return launchConfiguration;
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/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
index 5673a2c..79e29a7 100644
--- 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
@@ -38,7 +38,7 @@ 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.common.math.DoubleMath;
 import com.google.inject.Inject;
 
 /**
@@ -55,21 +55,24 @@ public class ParseGroupResponse implements Function<HttpResponse, Group> {
    }
 
    /**
-    * Extracts the user password from the json response
+    * Parses the Group from the response
     */
    @SuppressWarnings("unchecked")
    public Group apply(HttpResponse from) {
+      // This needs to be refactored when the service is in a more final state and changing less often
+      // A lot of the complexity is expected to go away
+
       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();
+      ImmutableList.Builder<ScalingPolicyResponse> scalingPoliciesList = ImmutableList.builder();
       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();
+      ImmutableList.Builder<Personality> personalities = ImmutableList.builder();
+      ImmutableList.Builder<String> networks = ImmutableList.builder();
       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());
       }
@@ -78,7 +81,7 @@ public class ParseGroupResponse implements Function<HttpResponse, Group> {
          networks.add(jsonNetwork.get("uuid"));
       }
 
-      List<LoadBalancer> loadBalancers = Lists.newArrayList();
+      ImmutableList.Builder<LoadBalancer> loadBalancers = ImmutableList.builder();
       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()
@@ -86,14 +89,14 @@ public class ParseGroupResponse implements Function<HttpResponse, Group> {
       }
 
       LaunchConfiguration launchConfiguration = LaunchConfiguration.builder()
-            .loadBalancers(loadBalancers)
+            .loadBalancers(loadBalancers.build())
             .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)
+            .personalities(personalities.build())
+            .networks(networks.build())
             .type(LaunchConfigurationType.getByValue((String) launchConfigurationMap.get("type")).get())
             .build();
 
@@ -114,26 +117,28 @@ public class ParseGroupResponse implements Function<HttpResponse, Group> {
             }  
          }
 
-         List<Link> links = Lists.newArrayList();
+         ImmutableList.Builder<Link> links = ImmutableList.builder();
          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);
          }
 
+         Double d = (Double)scalingPolicyMap.get(targetType.toString()); // GSON only knows double now
+
          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")
+                     DoubleMath.isMathematicalInteger(d) ? Integer.toString(d.intValue()) : Double.toString(d), 
+                           targetType,
+                           ImmutableList.copyOf(links.build()),
+                           (String) scalingPolicyMap.get("id")
                      );
          scalingPoliciesList.add(scalingPolicyResponse);
       }
 
-      List<Link> links = Lists.newArrayList();
+      ImmutableList.Builder<Link> links = ImmutableList.builder();
       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);
@@ -142,10 +147,10 @@ public class ParseGroupResponse implements Function<HttpResponse, Group> {
       String groupId = (String) group.get("id");
       return Group.builder()
             .id(groupId)
-            .scalingPolicy(scalingPoliciesList)
+            .scalingPolicy(scalingPoliciesList.build())
             .groupConfiguration(groupConfiguration)
             .launchConfiguration(launchConfiguration)
-            .links(links)
+            .links(links.build())
             .build();
    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/functions/ParseScalingPoliciesResponse.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/functions/ParseScalingPoliciesResponse.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/functions/ParseScalingPoliciesResponse.java
new file mode 100644
index 0000000..e02160c
--- /dev/null
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/functions/ParseScalingPoliciesResponse.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.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.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.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.math.DoubleMath;
+import com.google.inject.Inject;
+
+/**
+ * This parses the scaling policy response and decouples domain objects from the json object returned by the service.
+ * @author Zack Shoylev
+ */
+public class ParseScalingPoliciesResponse implements Function<HttpResponse, FluentIterable<ScalingPolicyResponse>> {
+
+   private final ParseJson<Map<String, List<Map<String, Object>>>> json;
+
+   @Inject
+   ParseScalingPoliciesResponse(ParseJson<Map<String, List<Map<String, Object>>>> json) {
+      this.json = checkNotNull(json, "json");
+   }
+
+   /**
+    * Parse a list of scaling policy responses
+    */
+   @SuppressWarnings("unchecked")
+   public FluentIterable<ScalingPolicyResponse> apply(HttpResponse from) {
+      // This needs to be refactored when the service is in a more final state and changing less often
+      // A lot of the complexity is expected to go away
+
+      Map<String, List<Map<String, Object>>> singleMap = (Map<String, List<Map<String, Object>>>) json.apply(from);
+      List<Map<String, Object>> result = singleMap.get("policies");
+      ImmutableList.Builder<ScalingPolicyResponse> scalingPoliciesList = ImmutableList.builder();
+
+      for(Map<String, Object> scalingPolicyMap : result) {
+         ScalingPolicyTargetType targetType = null;
+         for(String key : scalingPolicyMap.keySet()) {
+            if(ScalingPolicyTargetType.getByValue(key).isPresent()) {
+               targetType = ScalingPolicyTargetType.getByValue(key).get();
+               break;
+            }  
+         }
+
+         ImmutableList.Builder<Link> links = ImmutableList.builder();
+         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);
+         }
+
+         Double d = (Double)scalingPolicyMap.get(targetType.toString()); // GSON only knows double now
+         ScalingPolicyResponse scalingPolicyResponse = 
+               new ScalingPolicyResponse(
+                     (String)scalingPolicyMap.get("name"),
+                     ScalingPolicyType.getByValue((String)scalingPolicyMap.get("type")).get(),
+                     ((Double)scalingPolicyMap.get("cooldown")).intValue(),
+                     DoubleMath.isMathematicalInteger(d) ? Integer.toString(d.intValue()) : Double.toString(d),
+                           targetType,
+                           ImmutableList.copyOf(links.build()),
+                           (String) scalingPolicyMap.get("id")
+                     );
+         scalingPoliciesList.add(scalingPolicyResponse);
+      }
+
+      return FluentIterable.from(scalingPoliciesList.build());
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/functions/ParseScalingPolicyResponse.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/functions/ParseScalingPolicyResponse.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/functions/ParseScalingPolicyResponse.java
new file mode 100644
index 0000000..968254d
--- /dev/null
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/functions/ParseScalingPolicyResponse.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.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.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.math.DoubleMath;
+import com.google.inject.Inject;
+
+/**
+ * This parses the scaling policy response and decouples domain objects from the json object returned by the service.
+ * @author Zack Shoylev
+ */
+public class ParseScalingPolicyResponse implements Function<HttpResponse, ScalingPolicyResponse> {
+
+   private final ParseJson<Map<String, Object>> json;
+
+   @Inject
+   ParseScalingPolicyResponse(ParseJson<Map<String, Object>> json) {
+      this.json = checkNotNull(json, "json");
+   }
+
+   /**
+    * Parse a single scaling policy response
+    */
+   @SuppressWarnings("unchecked")
+   public ScalingPolicyResponse apply(HttpResponse from) {
+      // This needs to be refactored when the service is in a more final state and changing less often
+      // A lot of the complexity is expected to go away
+
+      Map<String, Object> singleMap = json.apply(from);
+      Map<String, Object> scalingPolicyMap = (Map<String, Object>) singleMap.get("policy");
+
+      ScalingPolicyTargetType targetType = null;
+      for(String key : scalingPolicyMap.keySet()) {
+         if(ScalingPolicyTargetType.getByValue(key).isPresent()) {
+            targetType = ScalingPolicyTargetType.getByValue(key).get();
+            break;
+         }  
+      }
+
+      ImmutableList.Builder<Link> links = ImmutableList.builder();
+      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);
+      }
+
+      Double d = (Double)scalingPolicyMap.get(targetType.toString()); // GSON only knows double now
+      ScalingPolicyResponse scalingPolicyResponse =
+            new ScalingPolicyResponse(
+                  (String)scalingPolicyMap.get("name"),
+                  ScalingPolicyType.getByValue((String)scalingPolicyMap.get("type")).get(),
+                  ((Double)scalingPolicyMap.get("cooldown")).intValue(),
+                  DoubleMath.isMathematicalInteger(d) ? Integer.toString(d.intValue()) : Double.toString(d),
+                        targetType,
+                        ImmutableList.copyOf(links.build()),
+                        (String) scalingPolicyMap.get("id")
+                  );
+
+      return scalingPolicyResponse;
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/internal/ParseHelper.java
----------------------------------------------------------------------
diff --git a/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/internal/ParseHelper.java b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/internal/ParseHelper.java
new file mode 100644
index 0000000..9e00579
--- /dev/null
+++ b/rackspace-autoscale/src/main/java/org/jclouds/rackspace/autoscale/v1/internal/ParseHelper.java
@@ -0,0 +1,102 @@
+/*
+ * 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.List;
+import java.util.Map;
+
+import org.jclouds.rackspace.autoscale.v1.domain.LaunchConfiguration;
+import org.jclouds.rackspace.autoscale.v1.domain.ScalingPolicy;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.google.common.primitives.Floats;
+import com.google.common.primitives.Ints;
+
+/**
+ * @author Zack Shoylev
+ * 
+ * Helper methods for parsing autoscale JSON
+ */
+public class ParseHelper {
+   public static ImmutableMap<String, Object> buildLaunchConfigurationRequestMap(Map<String, Object> postParams) {
+      LaunchConfiguration launchConfigurationRequest = (LaunchConfiguration) postParams.get("launchConfiguration");
+
+      ImmutableMap.Builder<String, Object> launchConfigurationMapBuilder = ImmutableMap.builder();
+      ImmutableMap.Builder<String, Object> argsBuilder = ImmutableMap.builder();
+      ImmutableMap.Builder<String, Object> serverBuilder = ImmutableMap.builder();
+      ImmutableList.Builder<Map<String, String>> networksBuilder = ImmutableList.builder();
+
+      for (String networkId : launchConfigurationRequest.getNetworks()) {
+         Map<String, String> network = Maps.newHashMap();
+         network.put("uuid", networkId);
+         networksBuilder.add(network);
+      }
+
+      serverBuilder.put("name", launchConfigurationRequest.getServerName());
+      serverBuilder.put("imageRef", launchConfigurationRequest.getServerImageRef());
+      serverBuilder.put("flavorRef", launchConfigurationRequest.getServerFlavorRef());
+      serverBuilder.put("OS-DCF:diskConfig", launchConfigurationRequest.getServerDiskConfig());
+      serverBuilder.put("metadata", launchConfigurationRequest.getServerMetadata());
+      serverBuilder.put("personality", launchConfigurationRequest.getPersonalities());
+      serverBuilder.put("networks", networksBuilder.build());
+
+      argsBuilder.put("loadBalancers", launchConfigurationRequest.getLoadBalancers());
+      argsBuilder.put("server", serverBuilder.build());
+
+      launchConfigurationMapBuilder.put("type", launchConfigurationRequest.getType().toString());
+      launchConfigurationMapBuilder.put("args", argsBuilder.build());
+
+      return launchConfigurationMapBuilder.build();
+   }
+
+   @SuppressWarnings("unchecked")
+   public static ImmutableList<Map<String, Object>> buildScalingPoliciesRequestList(Map<String, Object> postParams) {
+      List<ScalingPolicy> scalingPoliciesRequest = (List<ScalingPolicy>) postParams.get("scalingPolicies");
+      ImmutableList.Builder<Map<String, Object>> scalingPoliciesListBuilder = ImmutableList.builder();
+
+      for (ScalingPolicy scalingPolicy : scalingPoliciesRequest) {
+         scalingPoliciesListBuilder.add(buildScalingPolicyMap(scalingPolicy));
+      }
+      return scalingPoliciesListBuilder.build();
+   }
+   
+   public static ImmutableMap<String, Object> buildScalingPolicyMap(ScalingPolicy scalingPolicy) {
+      ImmutableMap.Builder<String, Object> scalingPolicyMapBuilder = ImmutableMap.builder();
+      scalingPolicyMapBuilder.put("cooldown", scalingPolicy.getCooldown());
+      scalingPolicyMapBuilder.put("type", scalingPolicy.getType().toString());
+      scalingPolicyMapBuilder.put("name", scalingPolicy.getName());
+      // A couple of different scaling policies are supported, such as percent or number based, or targeting specific numbers of instances
+      String targetString = scalingPolicy.getTarget();
+      Integer targetInt = Ints.tryParse(targetString);
+      // Notes:
+      // 1. Refactor when autoscale is complete and service is released to dry this code.
+      // 2. Refactor to use simpler code for the number parsing. Polymorphism or a facade might work.
+      // 3. Potentially remove or rework the enum code.
+      Float targetFloat;
+      if (targetInt != null) {
+         scalingPolicyMapBuilder.put(scalingPolicy.getTargetType().toString(), targetInt);
+      } else if ((targetFloat = Floats.tryParse(targetString)) != null) {
+         scalingPolicyMapBuilder.put(scalingPolicy.getTargetType().toString(), targetFloat);
+      } else {
+         scalingPolicyMapBuilder.put(scalingPolicy.getTargetType().toString(), targetString);
+      }
+
+      return scalingPolicyMapBuilder.build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/1c871e12/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
index b6f4e87..8e5ad0a 100644
--- 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
@@ -91,7 +91,7 @@ public class GroupApiExpectTest extends BaseAutoscaleApiExpectTest {
             .type(ScalingPolicyType.WEBHOOK)
             .name("scale up by 1")
             .targetType(ScalingPolicyTargetType.INCREMENTAL)
-            .target(1)
+            .target("1")
             .build();
       scalingPolicies.add(scalingPolicy);
 
@@ -108,7 +108,7 @@ public class GroupApiExpectTest extends BaseAutoscaleApiExpectTest {
       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).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");
@@ -176,7 +176,7 @@ public class GroupApiExpectTest extends BaseAutoscaleApiExpectTest {
             .type(ScalingPolicyType.WEBHOOK)
             .name("scale up by 1")
             .targetType(ScalingPolicyTargetType.INCREMENTAL)
-            .target(1)
+            .target("1")
             .build();
       scalingPolicies.add(scalingPolicy);
 
@@ -354,4 +354,162 @@ public class GroupApiExpectTest extends BaseAutoscaleApiExpectTest {
       boolean success = api.resume("1234567890");
       assertFalse(success);
    }
+
+   public void testGetGroupConfiguration() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/1234567890/config");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/autoscale_groups_configuration_get_response.json")).build())
+            .getGroupApiForZone("DFW");
+
+      GroupConfiguration gc = api.getGroupConfiguration("1234567890");
+      assertEquals(gc.getCooldown(), 60);
+      assertEquals(gc.getMaxEntities(), 100);
+   }
+
+   public void testGetGroupConfigurationFail() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/1234567890/config");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404)
+            .payload(payloadFromResource("/autoscale_groups_configuration_get_response.json")).build())
+            .getGroupApiForZone("DFW");
+
+      GroupConfiguration gc = api.getGroupConfiguration("1234567890");
+      assertEquals(gc, null);
+   }
+
+   public void testGetLaunchConfiguration() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/1234567890/launch");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/autoscale_groups_launch_configuration_get_response.json")).build())
+            .getGroupApiForZone("DFW");
+
+      LaunchConfiguration lc = api.getLaunchConfiguration("1234567890");
+      assertEquals(lc.getServerName(), "webhead");
+      assertEquals(lc.getType(), LaunchConfigurationType.LAUNCH_SERVER);
+   }
+
+   public void testGetLaunchConfigurationFail() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/1234567890/launch");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404)
+            .payload(payloadFromResource("/autoscale_groups_launch_configuration_get_response.json")).build())
+            .getGroupApiForZone("DFW");
+
+      LaunchConfiguration lc = api.getLaunchConfiguration("1234567890");
+      assertEquals(lc, null);
+   }
+
+   public void testUpdateGroupConfiguration() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/1234567890/config");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().method("PUT").endpoint(endpoint)
+            .payload(payloadFromResourceWithContentType("/autoscale_groups_update_configuration_request.json", MediaType.APPLICATION_JSON)).build(),
+            HttpResponse.builder().statusCode(200)
+            .build())
+            .getGroupApiForZone("DFW");
+
+      GroupConfiguration gc = GroupConfiguration.builder()
+            .name("workers")
+            .cooldown(60)
+            .minEntities(5)
+            .maxEntities(100)
+            .metadata(ImmutableMap.of("firstkey", "this is a string", "secondkey", "1"))
+            .build();
+
+      boolean result = api.updateGroupConfiguration("1234567890", gc);
+      assertEquals(result, true);
+   }
+
+   public void testUpdateGroupConfigurationFail() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/1234567890/config");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().method("PUT").endpoint(endpoint)
+            .payload(payloadFromResourceWithContentType("/autoscale_groups_update_configuration_request.json", MediaType.APPLICATION_JSON)).build(),
+            HttpResponse.builder().statusCode(404)
+            .build())
+            .getGroupApiForZone("DFW");
+
+      GroupConfiguration gc = GroupConfiguration.builder()
+            .name("workers")
+            .cooldown(60)
+            .minEntities(5)
+            .maxEntities(100)
+            .metadata(ImmutableMap.of("firstkey", "this is a string", "secondkey", "1"))
+            .build();
+
+      boolean result = api.updateGroupConfiguration("1234567890", gc);
+      assertFalse(result);
+   }
+
+   public void testUpdateGroupLaunchConfiguration() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/1234567890/launch");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().method("PUT").endpoint(endpoint)
+            .payload(payloadFromResourceWithContentType("/autoscale_groups_update_launch_configuration_request.json", MediaType.APPLICATION_JSON)).build(),
+            HttpResponse.builder().statusCode(200)
+            .build())
+            .getGroupApiForZone("DFW");
+
+      LaunchConfiguration lc = 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();
+
+      boolean result = api.updateLaunchConfiguration("1234567890", lc);
+      assertEquals(result, true);
+   }
+
+   public void testUpdateGroupLaunchConfigurationFail() {
+      URI endpoint = URI.create("https://dfw.autoscale.api.rackspacecloud.com/v1.0/888888/groups/1234567890/launch");
+      GroupApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().method("PUT").endpoint(endpoint)
+            .payload(payloadFromResourceWithContentType("/autoscale_groups_update_launch_configuration_request.json", MediaType.APPLICATION_JSON)).build(),
+            HttpResponse.builder().statusCode(404)
+            .build())
+            .getGroupApiForZone("DFW");
+
+      LaunchConfiguration lc = 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();
+
+      boolean result = api.updateLaunchConfiguration("1234567890", lc);
+      assertFalse(result);
+   }
 }