From f4b64fd00df41fc89d3d033a1109b6f3a431ee98 Mon Sep 17 00:00:00 2001 From: Everett Toews Date: Mon, 21 Jan 2013 15:48:13 -0600 Subject: [PATCH] The Health Monitor API for Rackspace Cloud Load Balancers. --- .../CloudLoadBalancersApi.java | 9 ++ .../CloudLoadBalancersAsyncApi.java | 13 +- .../CloudLoadBalancersRestClientModule.java | 3 + .../domain/HealthMonitor.java | 74 ++++++--- .../features/HealthMonitorApi.java | 54 +++++++ .../features/HealthMonitorAsyncApi.java | 82 ++++++++++ .../functions/ParseHealthMonitor.java | 65 ++++++++ .../features/ConnectionApiExpectTest.java | 16 +- .../features/HealthMonitorApiExpectTest.java | 150 ++++++++++++++++++ .../features/HealthMonitorApiLiveTest.java | 88 ++++++++++ .../connectionthrottle-get-deleted.json | 4 + .../test/resources/healthmonitor-create.json | 1 + .../resources/healthmonitor-get-deleted.json | 4 + .../src/test/resources/healthmonitor-get.json | 8 + 14 files changed, 546 insertions(+), 25 deletions(-) create mode 100644 apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/features/HealthMonitorApi.java create mode 100644 apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/features/HealthMonitorAsyncApi.java create mode 100644 apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/functions/ParseHealthMonitor.java create mode 100644 apis/rackspace-cloudloadbalancers/src/test/java/org/jclouds/rackspace/cloudloadbalancers/features/HealthMonitorApiExpectTest.java create mode 100644 apis/rackspace-cloudloadbalancers/src/test/java/org/jclouds/rackspace/cloudloadbalancers/features/HealthMonitorApiLiveTest.java create mode 100644 apis/rackspace-cloudloadbalancers/src/test/resources/connectionthrottle-get-deleted.json create mode 100644 apis/rackspace-cloudloadbalancers/src/test/resources/healthmonitor-create.json create mode 100644 apis/rackspace-cloudloadbalancers/src/test/resources/healthmonitor-get-deleted.json create mode 100644 apis/rackspace-cloudloadbalancers/src/test/resources/healthmonitor-get.json diff --git a/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/CloudLoadBalancersApi.java b/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/CloudLoadBalancersApi.java index 45e117e9ef..77c55b23b1 100644 --- a/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/CloudLoadBalancersApi.java +++ b/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/CloudLoadBalancersApi.java @@ -27,6 +27,7 @@ import org.jclouds.location.Zone; import org.jclouds.location.functions.ZoneToEndpoint; import org.jclouds.rackspace.cloudloadbalancers.features.AccessRuleApi; import org.jclouds.rackspace.cloudloadbalancers.features.ConnectionApi; +import org.jclouds.rackspace.cloudloadbalancers.features.HealthMonitorApi; import org.jclouds.rackspace.cloudloadbalancers.features.LoadBalancerApi; import org.jclouds.rackspace.cloudloadbalancers.features.NodeApi; import org.jclouds.rackspace.cloudloadbalancers.features.VirtualIPApi; @@ -88,4 +89,12 @@ public interface CloudLoadBalancersApi { @Path("/loadbalancers/{lbId}") ConnectionApi getConnectionApiForZoneAndLoadBalancer( @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone, @PathParam("lbId") int lbId); + + /** + * Provides synchronous access to Health Monitor features. + */ + @Delegate + @Path("/loadbalancers/{lbId}") + HealthMonitorApi getHealthMonitorApiForZoneAndLoadBalancer( + @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone, @PathParam("lbId") int lbId); } diff --git a/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/CloudLoadBalancersAsyncApi.java b/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/CloudLoadBalancersAsyncApi.java index 33db013de1..454dea7dfd 100644 --- a/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/CloudLoadBalancersAsyncApi.java +++ b/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/CloudLoadBalancersAsyncApi.java @@ -27,7 +27,8 @@ import org.jclouds.javax.annotation.Nullable; import org.jclouds.location.Zone; import org.jclouds.location.functions.ZoneToEndpoint; import org.jclouds.rackspace.cloudloadbalancers.features.AccessRuleAsyncApi; -import org.jclouds.rackspace.cloudloadbalancers.features.ConnectionApi; +import org.jclouds.rackspace.cloudloadbalancers.features.ConnectionAsyncApi; +import org.jclouds.rackspace.cloudloadbalancers.features.HealthMonitorAsyncApi; import org.jclouds.rackspace.cloudloadbalancers.features.LoadBalancerAsyncApi; import org.jclouds.rackspace.cloudloadbalancers.features.NodeAsyncApi; import org.jclouds.rackspace.cloudloadbalancers.features.VirtualIPAsyncApi; @@ -87,6 +88,14 @@ public interface CloudLoadBalancersAsyncApi { */ @Delegate @Path("/loadbalancers/{lbId}") - ConnectionApi getConnectionApiForZoneAndLoadBalancer( + ConnectionAsyncApi getConnectionApiForZoneAndLoadBalancer( + @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone, @PathParam("lbId") int lbId); + + /** + * Provides synchronous access to Health Monitor features. + */ + @Delegate + @Path("/loadbalancers/{lbId}") + HealthMonitorAsyncApi getHealthMonitorApiForZoneAndLoadBalancer( @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone, @PathParam("lbId") int lbId); } diff --git a/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/config/CloudLoadBalancersRestClientModule.java b/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/config/CloudLoadBalancersRestClientModule.java index 435de2bc12..a1ed967403 100644 --- a/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/config/CloudLoadBalancersRestClientModule.java +++ b/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/config/CloudLoadBalancersRestClientModule.java @@ -32,6 +32,8 @@ import org.jclouds.rackspace.cloudloadbalancers.features.AccessRuleApi; import org.jclouds.rackspace.cloudloadbalancers.features.AccessRuleAsyncApi; import org.jclouds.rackspace.cloudloadbalancers.features.ConnectionApi; import org.jclouds.rackspace.cloudloadbalancers.features.ConnectionAsyncApi; +import org.jclouds.rackspace.cloudloadbalancers.features.HealthMonitorApi; +import org.jclouds.rackspace.cloudloadbalancers.features.HealthMonitorAsyncApi; import org.jclouds.rackspace.cloudloadbalancers.features.LoadBalancerAsyncApi; import org.jclouds.rackspace.cloudloadbalancers.features.LoadBalancerApi; import org.jclouds.rackspace.cloudloadbalancers.features.NodeAsyncApi; @@ -61,6 +63,7 @@ public class CloudLoadBalancersRestClientModule extends .put(AccessRuleApi.class, AccessRuleAsyncApi.class) .put(VirtualIPApi.class, VirtualIPAsyncApi.class) .put(ConnectionApi.class, ConnectionAsyncApi.class) + .put(HealthMonitorApi.class, HealthMonitorAsyncApi.class) .build(); public CloudLoadBalancersRestClientModule() { diff --git a/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/domain/HealthMonitor.java b/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/domain/HealthMonitor.java index cd1e159dc4..8da0c3287c 100644 --- a/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/domain/HealthMonitor.java +++ b/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/domain/HealthMonitor.java @@ -20,8 +20,13 @@ package org.jclouds.rackspace.cloudloadbalancers.domain; import static com.google.common.base.Preconditions.checkNotNull; +import java.beans.ConstructorProperties; + +import org.jclouds.javax.annotation.Nullable; + import com.google.common.base.Objects; import com.google.common.base.Objects.ToStringHelper; +import com.google.common.base.Optional; /** * The load balancing service includes a health monitoring operation which periodically checks your back-end nodes to @@ -29,11 +34,11 @@ import com.google.common.base.Objects.ToStringHelper; * monitor determines that the node is functional. In addition to being performed periodically, the health check also * is performed against every node that is added to ensure that the node is operating properly before allowing it to * service traffic. Only one health monitor is allowed to be enabled on a load balancer at a time. - * + *

* As part of your strategy for monitoring connections, you should consider defining secondary nodes that provide * failover for effectively routing traffic in case the primary node fails. This is an additional feature that will * ensure you remain up in case your primary node fails. - * + *

* @author Everett Toews */ public class HealthMonitor { @@ -42,21 +47,31 @@ public class HealthMonitor { private final int delay; private final int timeout; private final int attemptsBeforeDeactivation; - private final String bodyRegex; - private final String statusRegex; - private final String path; - private final String hostHeader; + private final Optional bodyRegex; + private final Optional statusRegex; + private final Optional path; + private final Optional hostHeader; - protected HealthMonitor(Type type, int delay, int timeout, int attemptsBeforeDeactivation, String bodyRegex, - String statusRegex, String path, String hostHeader) { + @ConstructorProperties({ + "type", "delay", "timeout", "attemptsBeforeDeactivation", "bodyRegex", "statusRegex", "path", "hostHeader" + }) + protected HealthMonitor(Type type, int delay, int timeout, int attemptsBeforeDeactivation, + @Nullable String bodyRegex, @Nullable String statusRegex, @Nullable String path, + @Nullable String hostHeader) { this.type = checkNotNull(type, "type"); this.delay = delay; this.timeout = timeout; this.attemptsBeforeDeactivation = attemptsBeforeDeactivation; - this.bodyRegex = bodyRegex; - this.statusRegex = statusRegex; - this.path = path; - this.hostHeader = hostHeader; + this.bodyRegex = Optional.fromNullable(bodyRegex); + this.statusRegex = Optional.fromNullable(statusRegex); + this.path = Optional.fromNullable(path); + this.hostHeader = Optional.fromNullable(hostHeader); + + if (!isValid()) + if (type.equals(Type.CONNECT)) + throw new IllegalArgumentException("Only delay, timeout, and attemptsBeforeDeactivation must be set."); + else + throw new IllegalArgumentException("At least delay, timeout, attemptsBeforeDeactivation, and path must be set."); } public Type getType() { @@ -75,25 +90,38 @@ public class HealthMonitor { return attemptsBeforeDeactivation; } - public String getBodyRegex() { + public Optional getBodyRegex() { return bodyRegex; } - public String getStatusRegex() { + public Optional getStatusRegex() { return statusRegex; } - public String getPath() { + public Optional getPath() { return path; } - public String getHostHeader() { + public Optional getHostHeader() { return hostHeader; } + + /** + * @return true if this HealthMonitor is valid, false otherwise + */ + public boolean isValid() { + boolean required = delay != 0 && timeout != 0 && attemptsBeforeDeactivation != 0; + + if (type.equals(Type.CONNECT)) + return required && !path.isPresent() && !statusRegex.isPresent() + && !bodyRegex.isPresent() && !hostHeader.isPresent(); + else + return required && path.isPresent(); + } @Override public int hashCode() { - return Objects.hashCode(type, delay, timeout, attemptsBeforeDeactivation, bodyRegex, statusRegex, path, + return Objects.hashCode(type, delay, timeout, attemptsBeforeDeactivation, bodyRegex, statusRegex, path, hostHeader); } @@ -113,9 +141,10 @@ public class HealthMonitor { } protected ToStringHelper string() { - return Objects.toStringHelper(this).add("type", type).add("delay", delay).add("timeout", timeout) - .add("attemptsBeforeDeactivation", attemptsBeforeDeactivation).add("bodyRegex", bodyRegex) - .add("statusRegex", statusRegex).add("path", path).add("hostHeader", hostHeader); + return Objects.toStringHelper(this).omitNullValues().add("type", type).add("delay", delay) + .add("timeout", timeout).add("attemptsBeforeDeactivation", attemptsBeforeDeactivation) + .add("bodyRegex", bodyRegex).add("statusRegex", statusRegex).add("path", path) + .add("hostHeader", hostHeader); } @Override @@ -225,8 +254,9 @@ public class HealthMonitor { public Builder from(HealthMonitor in) { return this.type(in.getType()).delay(in.getDelay()).timeout(in.getTimeout()) - .attemptsBeforeDeactivation(in.getAttemptsBeforeDeactivation()).bodyRegex(in.getBodyRegex()) - .statusRegex(in.getStatusRegex()).path(in.getPath()).hostHeader(in.getHostHeader()); + .attemptsBeforeDeactivation(in.getAttemptsBeforeDeactivation()).bodyRegex(in.getBodyRegex().orNull()) + .statusRegex(in.getStatusRegex().orNull()).path(in.getPath().orNull()) + .hostHeader(in.getHostHeader().orNull()); } } diff --git a/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/features/HealthMonitorApi.java b/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/features/HealthMonitorApi.java new file mode 100644 index 0000000000..c6cc266a81 --- /dev/null +++ b/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/features/HealthMonitorApi.java @@ -0,0 +1,54 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.cloudloadbalancers.features; + +import org.jclouds.rackspace.cloudloadbalancers.domain.HealthMonitor; + +/** + * The load balancing service includes a health monitoring operation which periodically checks your back-end nodes to + * ensure they are responding correctly. If a node is not responding, it is removed from rotation until the health + * monitor determines that the node is functional. In addition to being performed periodically, the health check also + * is performed against every node that is added to ensure that the node is operating properly before allowing it to + * service traffic. Only one health monitor is allowed to be enabled on a load balancer at a time. + *

+ * As part of your strategy for monitoring connections, you should consider defining secondary nodes that provide + * failover for effectively routing traffic in case the primary node fails. This is an additional feature that will + * ensure you remain up in case your primary node fails. + *

+ * @see HealthMonitorAsyncApi + * @author Everett Toews + */ +public interface HealthMonitorApi { + /** + * Create or update a health monitor. + */ + void createOrUpdate(HealthMonitor healthMonitor); + + /** + * Get health monitor. + */ + HealthMonitor get(); + + /** + * Remove health monitor. + * + * @return true on a successful removal, false if the connection throttle was not found + */ + boolean remove(); +} \ No newline at end of file diff --git a/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/features/HealthMonitorAsyncApi.java b/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/features/HealthMonitorAsyncApi.java new file mode 100644 index 0000000000..59ba880702 --- /dev/null +++ b/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/features/HealthMonitorAsyncApi.java @@ -0,0 +1,82 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.cloudloadbalancers.features; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.FalseOnNotFoundOr422; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.Fallbacks.VoidOnNotFoundOr404; +import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest; +import org.jclouds.rackspace.cloudloadbalancers.domain.HealthMonitor; +import org.jclouds.rackspace.cloudloadbalancers.functions.ParseHealthMonitor; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.WrapWith; + +import com.google.common.util.concurrent.ListenableFuture; + +/** + * Provides asynchronous access to Rackspace Cloud Load Balancers via their REST API. + *

+ * + * @see HealthMonitorApi + * @author Everett Toews + */ +@RequestFilters(AuthenticateRequest.class) +public interface HealthMonitorAsyncApi { + + /** + * @see HealthMonitorApi#createOrUpdate(HealthMonitor) + */ + @Named("healthmonitor:create") + @PUT + @Consumes(MediaType.APPLICATION_JSON) + @Fallback(VoidOnNotFoundOr404.class) + @Path("/healthmonitor") + ListenableFuture createOrUpdate(@WrapWith("healthMonitor") HealthMonitor healthMonitor); + + /** + * @see HealthMonitorApi#get() + */ + @Named("healthmonitor:get") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @ResponseParser(ParseHealthMonitor.class) + @Fallback(NullOnNotFoundOr404.class) + @Path("/healthmonitor") + ListenableFuture get(); + + /** + * @see HealthMonitorApi#remove() + */ + @Named("healthmonitor:remove") + @DELETE + @Fallback(FalseOnNotFoundOr422.class) + @Path("/healthmonitor") + @Consumes("*/*") + ListenableFuture remove(); +} diff --git a/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/functions/ParseHealthMonitor.java b/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/functions/ParseHealthMonitor.java new file mode 100644 index 0000000000..0b9b5e03a3 --- /dev/null +++ b/apis/rackspace-cloudloadbalancers/src/main/java/org/jclouds/rackspace/cloudloadbalancers/functions/ParseHealthMonitor.java @@ -0,0 +1,65 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.cloudloadbalancers.functions; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Map; + +import javax.inject.Inject; + +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.rackspace.cloudloadbalancers.domain.HealthMonitor; +import org.jclouds.rest.InvocationContext; + +import com.google.common.base.Function; +import com.google.common.collect.Iterables; + +/** + * @author Everett Toews + */ +public class ParseHealthMonitor implements + Function, InvocationContext { + + private final ParseJson> json; + + @Inject + ParseHealthMonitor(ParseJson> json) { + this.json = checkNotNull(json, "json"); + } + + @Override + public HealthMonitor apply(HttpResponse response) { + Map map = json.apply(response); + + if (map == null || map.size() == 0) + return null; + + HealthMonitor healthMonitor = Iterables.get(map.values(), 0); + + return healthMonitor.isValid() ? healthMonitor : null; + } + + @Override + public ParseHealthMonitor setContext(HttpRequest request) { + return this; + } +} diff --git a/apis/rackspace-cloudloadbalancers/src/test/java/org/jclouds/rackspace/cloudloadbalancers/features/ConnectionApiExpectTest.java b/apis/rackspace-cloudloadbalancers/src/test/java/org/jclouds/rackspace/cloudloadbalancers/features/ConnectionApiExpectTest.java index 3ad8630065..77bc3a3bd4 100644 --- a/apis/rackspace-cloudloadbalancers/src/test/java/org/jclouds/rackspace/cloudloadbalancers/features/ConnectionApiExpectTest.java +++ b/apis/rackspace-cloudloadbalancers/src/test/java/org/jclouds/rackspace/cloudloadbalancers/features/ConnectionApiExpectTest.java @@ -20,6 +20,7 @@ package org.jclouds.rackspace.cloudloadbalancers.features; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertNull; import java.net.URI; @@ -49,6 +50,19 @@ public class ConnectionApiExpectTest extends BaseCloudLoadBalancerApiExpectTest< assertEquals(connectionThrottle, getConnectionThrottle()); } + public void testGetDeletedConnectionThrottle() { + URI endpoint = URI.create("https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/123123/loadbalancers/2000/connectionthrottle"); + ConnectionApi api = requestsSendResponses( + rackspaceAuthWithUsernameAndApiKey, + responseWithAccess, + authenticatedGET().endpoint(endpoint).build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/connectionthrottle-get-deleted.json")).build() + ).getConnectionApiForZoneAndLoadBalancer("DFW", 2000); + + ConnectionThrottle connectionThrottle = api.getConnectionThrottle(); + assertNull(connectionThrottle); + } + public void testCreateConnectionThrottle() { URI endpoint = URI.create("https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/123123/loadbalancers/2000/connectionthrottle"); ConnectionApi api = requestsSendResponses( @@ -70,7 +84,7 @@ public class ConnectionApiExpectTest extends BaseCloudLoadBalancerApiExpectTest< ConnectionThrottle.builder().build(); } - public void testRemoveSingleVirtualIP() { + public void testRemoveConnectionThrottle() { URI endpoint = URI.create("https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/123123/loadbalancers/2000/connectionthrottle"); ConnectionApi api = requestsSendResponses( rackspaceAuthWithUsernameAndApiKey, diff --git a/apis/rackspace-cloudloadbalancers/src/test/java/org/jclouds/rackspace/cloudloadbalancers/features/HealthMonitorApiExpectTest.java b/apis/rackspace-cloudloadbalancers/src/test/java/org/jclouds/rackspace/cloudloadbalancers/features/HealthMonitorApiExpectTest.java new file mode 100644 index 0000000000..8fa869bc87 --- /dev/null +++ b/apis/rackspace-cloudloadbalancers/src/test/java/org/jclouds/rackspace/cloudloadbalancers/features/HealthMonitorApiExpectTest.java @@ -0,0 +1,150 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.cloudloadbalancers.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertNull; + +import java.net.URI; + +import javax.ws.rs.core.MediaType; + +import org.jclouds.http.HttpResponse; +import org.jclouds.rackspace.cloudloadbalancers.CloudLoadBalancersApi; +import org.jclouds.rackspace.cloudloadbalancers.domain.HealthMonitor; +import org.jclouds.rackspace.cloudloadbalancers.internal.BaseCloudLoadBalancerApiExpectTest; +import org.testng.annotations.Test; + +/** + * @author Everett Toews + */ +@Test(groups = "unit") +public class HealthMonitorApiExpectTest extends BaseCloudLoadBalancerApiExpectTest { + public void testGetHealthMonitor() { + URI endpoint = URI.create("https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/123123/loadbalancers/2000/healthmonitor"); + HealthMonitorApi api = requestsSendResponses( + rackspaceAuthWithUsernameAndApiKey, + responseWithAccess, + authenticatedGET().endpoint(endpoint).build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/healthmonitor-get.json")).build() + ).getHealthMonitorApiForZoneAndLoadBalancer("DFW", 2000); + + HealthMonitor healthMonitor = api.get(); + assertEquals(healthMonitor, getConnectHealthMonitor()); + } + + public void testGetDeletedHealthMonitor() { + URI endpoint = URI.create("https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/123123/loadbalancers/2000/healthmonitor"); + HealthMonitorApi api = requestsSendResponses( + rackspaceAuthWithUsernameAndApiKey, + responseWithAccess, + authenticatedGET().endpoint(endpoint).build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/healthmonitor-get-deleted.json")).build() + ).getHealthMonitorApiForZoneAndLoadBalancer("DFW", 2000); + + HealthMonitor healthMonitor = api.get(); + assertNull(healthMonitor); + } + + public void testCreateHealthMonitor() { + URI endpoint = URI.create("https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/123123/loadbalancers/2000/healthmonitor"); + HealthMonitorApi api = requestsSendResponses( + rackspaceAuthWithUsernameAndApiKey, + responseWithAccess, + authenticatedGET().method("PUT").endpoint(endpoint).payload(payloadFromResource("/healthmonitor-create.json")).build(), + HttpResponse.builder().statusCode(200).build() + ).getHealthMonitorApiForZoneAndLoadBalancer("DFW", 2000); + + api.createOrUpdate(getConnectHealthMonitor()); + } + + public void testRemoveHealthMonitor() { + URI endpoint = URI.create("https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/123123/loadbalancers/2000/healthmonitor"); + HealthMonitorApi api = requestsSendResponses( + rackspaceAuthWithUsernameAndApiKey, + responseWithAccess, + authenticatedGET().method("DELETE").endpoint(endpoint).replaceHeader("Accept", MediaType.WILDCARD).build(), + HttpResponse.builder().statusCode(200).build() + ).getHealthMonitorApiForZoneAndLoadBalancer("DFW", 2000); + + assertTrue(api.remove()); + } + + public void testValidConnectHealthMonitor() { + assertTrue(getConnectHealthMonitor().isValid()); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testInvalidConnectHealthMonitorWithoutRequirements() { + HealthMonitor.builder().type(HealthMonitor.Type.CONNECT).build(); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testInvalidConnectHealthMonitorWithUnrequired() { + HealthMonitor.builder() + .type(HealthMonitor.Type.CONNECT) + .delay(3599) + .timeout(30) + .attemptsBeforeDeactivation(2) + .path("/foobar") + .build(); + } + + public void testValidHTTPHealthMonitor() { + assertTrue(getHTTPHealthMonitor().isValid()); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testInvalidHTTPHealthMonitorWithoutRequirements() { + HealthMonitor.builder().type(HealthMonitor.Type.HTTP).build(); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testInvalidHTTPHealthMonitorWithUnrequired() { + HealthMonitor.builder() + .type(HealthMonitor.Type.HTTP) + .delay(3599) + .path("/foobar") + .build(); + } + + public static HealthMonitor getConnectHealthMonitor() { + HealthMonitor healthMonitor = HealthMonitor.builder() + .type(HealthMonitor.Type.CONNECT) + .delay(3599) + .timeout(30) + .attemptsBeforeDeactivation(2) + .build(); + + return healthMonitor; + } + + public static HealthMonitor getHTTPHealthMonitor() { + HealthMonitor healthMonitor = HealthMonitor.builder() + .type(HealthMonitor.Type.HTTP) + .delay(3599) + .timeout(30) + .attemptsBeforeDeactivation(2) + .path("/foobar") + .build(); + + return healthMonitor; + } +} diff --git a/apis/rackspace-cloudloadbalancers/src/test/java/org/jclouds/rackspace/cloudloadbalancers/features/HealthMonitorApiLiveTest.java b/apis/rackspace-cloudloadbalancers/src/test/java/org/jclouds/rackspace/cloudloadbalancers/features/HealthMonitorApiLiveTest.java new file mode 100644 index 0000000000..eeac6f0e17 --- /dev/null +++ b/apis/rackspace-cloudloadbalancers/src/test/java/org/jclouds/rackspace/cloudloadbalancers/features/HealthMonitorApiLiveTest.java @@ -0,0 +1,88 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.cloudloadbalancers.features; + +import static org.jclouds.rackspace.cloudloadbalancers.predicates.LoadBalancerPredicates.awaitAvailable; +import static org.jclouds.rackspace.cloudloadbalancers.predicates.LoadBalancerPredicates.awaitDeleted; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +import org.jclouds.rackspace.cloudloadbalancers.domain.HealthMonitor; +import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer; +import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancerRequest; +import org.jclouds.rackspace.cloudloadbalancers.domain.NodeRequest; +import org.jclouds.rackspace.cloudloadbalancers.domain.VirtualIP.Type; +import org.jclouds.rackspace.cloudloadbalancers.internal.BaseCloudLoadBalancersApiLiveTest; +import org.testng.annotations.AfterGroups; +import org.testng.annotations.Test; + +import com.google.common.collect.Iterables; + +/** + * @author Everett Toews + */ +@Test(groups = "live", singleThreaded = true, testName = "HealthMonitorApiLiveTest") +public class HealthMonitorApiLiveTest extends BaseCloudLoadBalancersApiLiveTest { + private LoadBalancer lb; + private String zone; + + public void testCreateLoadBalancer() { + NodeRequest nodeRequest = NodeRequest.builder().address("192.168.1.1").port(8080).build(); + LoadBalancerRequest lbRequest = LoadBalancerRequest.builder() + .name(prefix+"-jclouds").protocol("HTTP").port(80).virtualIPType(Type.PUBLIC).node(nodeRequest).build(); + + zone = Iterables.getFirst(clbApi.getConfiguredZones(), null); + lb = clbApi.getLoadBalancerApiForZone(zone).create(lbRequest); + + assertTrue(awaitAvailable(clbApi.getLoadBalancerApiForZone(zone)).apply(lb)); + } + + @Test(dependsOnMethods = "testCreateLoadBalancer") + public void testCreateAndGetConnectionThrottling() throws Exception { + clbApi.getHealthMonitorApiForZoneAndLoadBalancer(zone, lb.getId()).createOrUpdate( + HealthMonitorApiExpectTest.getConnectHealthMonitor()); + assertTrue(awaitAvailable(clbApi.getLoadBalancerApiForZone(zone)).apply(lb)); + + HealthMonitor healthMonitor = + clbApi.getHealthMonitorApiForZoneAndLoadBalancer(zone, lb.getId()).get(); + + assertEquals(healthMonitor, HealthMonitorApiExpectTest.getConnectHealthMonitor()); + } + + @Test(dependsOnMethods = "testCreateAndGetConnectionThrottling") + public void testRemoveAndGetHealthMonitor() throws Exception { + assertTrue(clbApi.getHealthMonitorApiForZoneAndLoadBalancer(zone, lb.getId()).remove()); + assertTrue(awaitAvailable(clbApi.getLoadBalancerApiForZone(zone)).apply(lb)); + + HealthMonitor healthMonitor = + clbApi.getHealthMonitorApiForZoneAndLoadBalancer(zone, lb.getId()).get(); + + assertNull(healthMonitor); + } + + @Override + @AfterGroups(groups = "live") + protected void tearDownContext() { + assertTrue(awaitAvailable(clbApi.getLoadBalancerApiForZone(zone)).apply(lb)); + clbApi.getLoadBalancerApiForZone(zone).remove(lb.getId()); + assertTrue(awaitDeleted(clbApi.getLoadBalancerApiForZone(zone)).apply(lb)); + super.tearDownContext(); + } +} diff --git a/apis/rackspace-cloudloadbalancers/src/test/resources/connectionthrottle-get-deleted.json b/apis/rackspace-cloudloadbalancers/src/test/resources/connectionthrottle-get-deleted.json new file mode 100644 index 0000000000..ba49c2e12d --- /dev/null +++ b/apis/rackspace-cloudloadbalancers/src/test/resources/connectionthrottle-get-deleted.json @@ -0,0 +1,4 @@ +{ + "connectionThrottle": { + } +} \ No newline at end of file diff --git a/apis/rackspace-cloudloadbalancers/src/test/resources/healthmonitor-create.json b/apis/rackspace-cloudloadbalancers/src/test/resources/healthmonitor-create.json new file mode 100644 index 0000000000..48951e916d --- /dev/null +++ b/apis/rackspace-cloudloadbalancers/src/test/resources/healthmonitor-create.json @@ -0,0 +1 @@ +{"healthMonitor":{"type":"CONNECT","delay":3599,"timeout":30,"attemptsBeforeDeactivation":2}} \ No newline at end of file diff --git a/apis/rackspace-cloudloadbalancers/src/test/resources/healthmonitor-get-deleted.json b/apis/rackspace-cloudloadbalancers/src/test/resources/healthmonitor-get-deleted.json new file mode 100644 index 0000000000..c84694ae7b --- /dev/null +++ b/apis/rackspace-cloudloadbalancers/src/test/resources/healthmonitor-get-deleted.json @@ -0,0 +1,4 @@ +{ + "healthMonitor": { + } +} \ No newline at end of file diff --git a/apis/rackspace-cloudloadbalancers/src/test/resources/healthmonitor-get.json b/apis/rackspace-cloudloadbalancers/src/test/resources/healthmonitor-get.json new file mode 100644 index 0000000000..5fd3f5bd68 --- /dev/null +++ b/apis/rackspace-cloudloadbalancers/src/test/resources/healthmonitor-get.json @@ -0,0 +1,8 @@ +{ + "healthMonitor": { + "type": "CONNECT", + "delay": 3599, + "timeout": 30, + "attemptsBeforeDeactivation": 2 + } +} \ No newline at end of file