diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/LoadBalancerRule.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/LoadBalancerRule.java index 042d281017..5b9f1420ab 100644 --- a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/LoadBalancerRule.java +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/LoadBalancerRule.java @@ -21,6 +21,7 @@ package org.jclouds.cloudstack.domain; import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.base.CaseFormat; import com.google.gson.annotations.SerializedName; /** @@ -28,6 +29,22 @@ import com.google.gson.annotations.SerializedName; * @author Adrian Cole */ public class LoadBalancerRule implements Comparable { + public static enum State { + ADD, ACTIVE, UNRECOGNIZED; + @Override + public String toString() { + return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()); + } + + public static State fromValue(String state) { + try { + return valueOf(CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, checkNotNull(state, "state"))); + } catch (IllegalArgumentException e) { + return UNRECOGNIZED; + } + } + + } public static enum Algorithm { SOURCE, ROUNDROBIN, LEASTCONN, UNRECOGNIZED; @@ -62,7 +79,7 @@ public class LoadBalancerRule implements Comparable { private String publicIP; private long publicIPId; private int publicPort; - private String state; + private State state; public Builder id(long id) { this.id = id; @@ -119,7 +136,7 @@ public class LoadBalancerRule implements Comparable { return this; } - public Builder state(String state) { + public Builder state(State state) { this.state = state; return this; } @@ -146,7 +163,7 @@ public class LoadBalancerRule implements Comparable { private long publicIPId; @SerializedName("publicport") private int publicPort; - private String state; + private State state; // for deserializer LoadBalancerRule() { @@ -154,7 +171,7 @@ public class LoadBalancerRule implements Comparable { } public LoadBalancerRule(long id, String account, Algorithm algorithm, String description, String domain, - long domainId, String name, int privatePort, String publicIP, long publicIPId, int publicPort, String state) { + long domainId, String name, int privatePort, String publicIP, long publicIPId, int publicPort, State state) { this.id = id; this.account = account; this.algorithm = algorithm; @@ -249,7 +266,7 @@ public class LoadBalancerRule implements Comparable { /** * @return the state of the rule */ - public String getState() { + public State getState() { return state; } diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/AddressClient.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/AddressClient.java index bc04b9d8af..6eb0e0011c 100644 --- a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/AddressClient.java +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/AddressClient.java @@ -71,5 +71,6 @@ public interface AddressClient { * @param id * the id of the public ip address to disassociate */ + @Timeout(duration = 120, timeUnit = TimeUnit.SECONDS) void disassociateIPAddress(long id); } diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/LoadBalancerAsyncClient.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/LoadBalancerAsyncClient.java index 29a212dc72..511ee15003 100644 --- a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/LoadBalancerAsyncClient.java +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/LoadBalancerAsyncClient.java @@ -31,7 +31,9 @@ import org.jclouds.cloudstack.domain.VirtualMachine; import org.jclouds.cloudstack.domain.LoadBalancerRule.Algorithm; import org.jclouds.cloudstack.filters.QuerySigner; import org.jclouds.cloudstack.options.ListLoadBalancerRulesOptions; +import org.jclouds.functions.JoinOnComma; import org.jclouds.rest.annotations.ExceptionParser; +import org.jclouds.rest.annotations.ParamParser; import org.jclouds.rest.annotations.QueryParams; import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.Unwrap; @@ -62,6 +64,16 @@ public interface LoadBalancerAsyncClient { @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) ListenableFuture> listLoadBalancerRules(ListLoadBalancerRulesOptions... options); + /** + * @see LoadBalancerClient#getLoadBalancerRule + */ + @GET + @QueryParams(keys = "command", values = "listLoadBalancerRules") + @Unwrap(depth = 3, edgeCollection = Set.class) + @Consumes(MediaType.APPLICATION_JSON) + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + ListenableFuture getLoadBalancerRule(@QueryParam("id") long id); + /** * @see LoadBalancerClient#createLoadBalancerRuleForPublicIp */ @@ -83,6 +95,50 @@ public interface LoadBalancerAsyncClient { @ExceptionParser(ReturnNullOnNotFoundOr404.class) ListenableFuture deleteLoadBalancerRule(@QueryParam("id") long id); + /** + * @see LoadBalancerClient#assignVirtualMachinesToLoadBalancerRule(long,Iterable) + */ + @GET + @QueryParams(keys = "command", values = "assignToLoadBalancerRule") + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + @Unwrap(depth = 2) + @Consumes(MediaType.APPLICATION_JSON) + ListenableFuture assignVirtualMachinesToLoadBalancerRule(@QueryParam("id") long id, + @QueryParam("virtualmachineids") @ParamParser(JoinOnComma.class) Iterable virtualMachineIds); + + /** + * @see LoadBalancerClient#assignVirtualMachinesToLoadBalancerRule(long,long[]) + */ + @GET + @QueryParams(keys = "command", values = "assignToLoadBalancerRule") + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + @Unwrap(depth = 2) + @Consumes(MediaType.APPLICATION_JSON) + ListenableFuture assignVirtualMachinesToLoadBalancerRule(@QueryParam("id") long id, + @QueryParam("virtualmachineids") @ParamParser(JoinOnComma.class) long... virtualMachineIds); + + /** + * @see LoadBalancerClient#removeVirtualMachinesFromLoadBalancerRule(long,Iterable) + */ + @GET + @QueryParams(keys = "command", values = "removeFromLoadBalancerRule") + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + @Unwrap(depth = 2) + @Consumes(MediaType.APPLICATION_JSON) + ListenableFuture removeVirtualMachinesFromLoadBalancerRule(@QueryParam("id") long id, + @QueryParam("virtualmachineids") @ParamParser(JoinOnComma.class) Iterable virtualMachineIds); + + /** + * @see LoadBalancerClient#removeVirtualMachinesFromLoadBalancerRule(long,long[]) + */ + @GET + @QueryParams(keys = "command", values = "removeFromLoadBalancerRule") + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + @Unwrap(depth = 2) + @Consumes(MediaType.APPLICATION_JSON) + ListenableFuture removeVirtualMachinesFromLoadBalancerRule(@QueryParam("id") long id, + @QueryParam("virtualmachineids") @ParamParser(JoinOnComma.class) long... virtualMachineIds); + /** * @see LoadBalancerClient#listVirtualMachinesAssignedToLoadBalancerRule */ diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/LoadBalancerClient.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/LoadBalancerClient.java index fb357e203b..5e0d0f6b60 100644 --- a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/LoadBalancerClient.java +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/LoadBalancerClient.java @@ -47,6 +47,15 @@ public interface LoadBalancerClient { */ Set listLoadBalancerRules(ListLoadBalancerRulesOptions... options); + /** + * get a specific LoadBalancerRule by id + * + * @param id + * LoadBalancerRule to get + * @return LoadBalancerRule or null if not found + */ + LoadBalancerRule getLoadBalancerRule(long id); + /** * Creates a load balancer rule. * @@ -85,4 +94,51 @@ public interface LoadBalancerClient { */ Set listVirtualMachinesAssignedToLoadBalancerRule(long id); + /** + * Assigns virtual machine or a list of virtual machines to a load balancer rule. + * + * @param id + * the ID of the load balancer rule + * @param virtualMachineIds + * the list of IDs of the virtual machine that are being assigned to the load balancer + * rule + * @return job id related to the operation + */ + long assignVirtualMachinesToLoadBalancerRule(long id, Iterable virtualMachineIds); + + /** + * Assigns virtual machine or a list of virtual machines to a load balancer rule. + * + * @param id + * the ID of the load balancer rule + * @param virtualMachineIds + * the list of IDs of the virtual machine that are being assigned to the load balancer + * rule + * @return job id related to the operation + */ + long assignVirtualMachinesToLoadBalancerRule(long id, long... virtualMachineIds); + + /** + * Removes a virtual machine or a list of virtual machines from a load balancer rule. + * + * @param id + * the ID of the load balancer rule + * @param virtualMachineIds + * the list of IDs of the virtual machine that are being removed from the load balancer + * rule + * @return job id related to the operation + */ + long removeVirtualMachinesFromLoadBalancerRule(long id, Iterable virtualMachineIds); + + /** + * Removes a virtual machine or a list of virtual machines from a load balancer rule. + * + * @param id + * the ID of the load balancer rule + * @param virtualMachineIds + * the list of IDs of the virtual machine that are being removed from the load balancer + * rule + * @return job id related to the operation + */ + long removeVirtualMachinesFromLoadBalancerRule(long id, long... virtualMachineIds); } diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/predicates/LoadBalancerRuleActive.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/predicates/LoadBalancerRuleActive.java new file mode 100644 index 0000000000..2d1f247cf2 --- /dev/null +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/predicates/LoadBalancerRuleActive.java @@ -0,0 +1,66 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.jclouds.cloudstack.predicates; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.cloudstack.CloudStackClient; +import org.jclouds.cloudstack.domain.LoadBalancerRule; +import org.jclouds.cloudstack.domain.LoadBalancerRule.State; +import org.jclouds.logging.Logger; + +import com.google.common.base.Predicate; + +/** + * + * Tests to see if a LoadBalancerRule is active + * + * @author Adrian Cole + */ +@Singleton +public class LoadBalancerRuleActive implements Predicate { + + private final CloudStackClient client; + + @Resource + protected Logger logger = Logger.NULL; + + @Inject + public LoadBalancerRuleActive(CloudStackClient client) { + this.client = client; + } + + public boolean apply(LoadBalancerRule rule) { + logger.trace("looking for state on rule %s", checkNotNull(rule, "rule")); + rule = refresh(rule); + if (rule == null) + return false; + logger.trace("%s: looking for rule state %s: currently: %s", rule.getId(), State.ACTIVE, rule.getState()); + return rule.getState() == State.ACTIVE; + } + + private LoadBalancerRule refresh(LoadBalancerRule rule) { + return client.getLoadBalancerClient().getLoadBalancerRule(rule.getId()); + } +} diff --git a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/LoadBalancerClientLiveTest.java b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/LoadBalancerClientLiveTest.java index 164e1cbe6a..771136b78c 100644 --- a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/LoadBalancerClientLiveTest.java +++ b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/LoadBalancerClientLiveTest.java @@ -24,11 +24,16 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import java.util.Set; +import java.util.concurrent.TimeUnit; import org.jclouds.cloudstack.domain.LoadBalancerRule; import org.jclouds.cloudstack.domain.PublicIPAddress; import org.jclouds.cloudstack.domain.VirtualMachine; import org.jclouds.cloudstack.domain.LoadBalancerRule.Algorithm; +import org.jclouds.cloudstack.domain.LoadBalancerRule.State; +import org.jclouds.cloudstack.predicates.LoadBalancerRuleActive; +import org.jclouds.net.IPSocket; +import org.jclouds.predicates.RetryablePredicate; import org.testng.annotations.AfterGroups; import org.testng.annotations.BeforeGroups; import org.testng.annotations.Test; @@ -45,10 +50,13 @@ public class LoadBalancerClientLiveTest extends BaseCloudStackClientLiveTest { private PublicIPAddress ip = null; private VirtualMachine vm; private LoadBalancerRule rule; + private RetryablePredicate loadBalancerRuleActive; @BeforeGroups(groups = "live") public void setupClient() { super.setupClient(); + loadBalancerRuleActive = new RetryablePredicate(new LoadBalancerRuleActive(client), 600, 5, + TimeUnit.SECONDS); prefix += "rule"; ip = AddressClientLiveTest.createPublicIPAddress(client, jobComplete); vm = VirtualMachineClientLiveTest.createVirtualMachine(client, jobComplete, virtualMachineRunning); @@ -62,19 +70,30 @@ public class LoadBalancerClientLiveTest extends BaseCloudStackClientLiveTest { assertEquals(rule.getPrivatePort(), 22); assertEquals(rule.getAlgorithm(), Algorithm.LEASTCONN); assertEquals(rule.getName(), prefix); + assertEquals(rule.getState(), State.ADD); assertEquals(client.getLoadBalancerClient().listVirtualMachinesAssignedToLoadBalancerRule(rule.getId()).size(), 0); checkRule(rule); - // IPSocket socket = new IPSocket(ip.getIPAddress(), 22); - // socketTester.apply(socket); - // SshClient client = sshFactory.create(socket, new Credentials("root", "password")); - // try { - // client.connect(); - // ExecResponse exec = client.exec("echo hello"); - // assertEquals(exec.getOutput().trim(), "hello"); - // } finally { - // if (client != null) - // client.disconnect(); - // } + + } + + @Test(dependsOnMethods = "testCreateLoadBalancerRule") + public void testAssignToLoadBalancerRule() throws Exception { + assert jobComplete.apply(client.getLoadBalancerClient().assignVirtualMachinesToLoadBalancerRule(rule.getId(), + vm.getId())); + assertEquals(client.getLoadBalancerClient().listVirtualMachinesAssignedToLoadBalancerRule(rule.getId()).size(), 1); + assert loadBalancerRuleActive.apply(rule) : rule; + IPSocket socket = new IPSocket(ip.getIPAddress(), 22); + assert socketTester.apply(socket) : vm; + } + + @Test(dependsOnMethods = "testAssignToLoadBalancerRule") + public void testRemoveFromLoadBalancerRule() throws Exception { + assert jobComplete.apply(client.getLoadBalancerClient().removeVirtualMachinesFromLoadBalancerRule(rule.getId(), + vm.getId())); + assertEquals(client.getLoadBalancerClient().listVirtualMachinesAssignedToLoadBalancerRule(rule.getId()).size(), 0); + assertEquals(rule.getState(), State.ADD); + IPSocket socket = new IPSocket(ip.getIPAddress(), 22); + assert !socketTester.apply(socket); } @AfterGroups(groups = "live") @@ -82,12 +101,12 @@ public class LoadBalancerClientLiveTest extends BaseCloudStackClientLiveTest { if (rule != null) { assert jobComplete.apply(client.getLoadBalancerClient().deleteLoadBalancerRule(rule.getId())); } - if (ip != null) { - client.getAddressClient().disassociateIPAddress(ip.getId()); - } if (vm != null) { assert jobComplete.apply(client.getVirtualMachineClient().destroyVirtualMachine(vm.getId())); } + if (ip != null) { + client.getAddressClient().disassociateIPAddress(ip.getId()); + } super.tearDown(); }