More attributes and domain objects for Rackspace Cloud Load Balancers.

This commit is contained in:
Everett Toews 2013-01-03 17:11:38 -06:00
parent f8f99b41b1
commit 6bc848c232
29 changed files with 2435 additions and 882 deletions

View File

@ -0,0 +1,153 @@
/**
* 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.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
/**
* The access list management feature allows fine-grained network access controls to be applied to the load balancer's
* virtual IP address. A single IP address, multiple IP addresses, or entire network subnets can be added as an access
* rule. Items that are configured with the ALLOW type will always take precedence over items with the DENY type. To
* reject traffic from all items except for those with the ALLOW type, add an access rules with an address of
* "0.0.0.0/0" and a DENY type.
*
* @author Everett Toews
*/
public class AccessRule {
private final int id;
private final Type type;
private final String address;
protected AccessRule(int id, Type type, String address) {
this.id = id;
this.type = checkNotNull(type, "type");
this.address = checkNotNull(address, "address");
}
public int getId() {
return this.id;
}
public Type getType() {
return this.type;
}
public String getAddress() {
return this.address;
}
@Override
public int hashCode() {
return Objects.hashCode(id);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
AccessRule that = AccessRule.class.cast(obj);
return Objects.equal(this.id, that.id);
}
protected ToStringHelper string() {
return Objects.toStringHelper(this)
.add("id", id).add("type", type).add("address", address);
}
@Override
public String toString() {
return string().toString();
}
public static enum Type {
/**
* Specifies items that will always take precedence over items with the DENY type.
*/
ALLOW,
/**
* Specifies items to which traffic can be denied.
*/
DENY,
UNRECOGNIZED;
public static Type fromValue(String type) {
try {
return valueOf(checkNotNull(type, "type"));
} catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
}
public static class Builder {
private int id;
private Type type;
private String address;
/**
* @see AccessRule#getId()
*/
public Builder id(int id) {
this.id = id;
return this;
}
/**
* @see Type
*/
public Builder type(Type type) {
this.type = type;
return this;
}
/**
* IP address for item to add to access list.
*/
public Builder address(String address) {
this.address = address;
return this;
}
public AccessRule build() {
return new AccessRule(id, type, address);
}
public Builder from(AccessRule in) {
return this
.id(in.getId())
.type(in.getType())
.address(in.getAddress());
}
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return new Builder().from(this);
}
}

View File

@ -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.domain;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
/**
* The connection throttling feature imposes limits on the number of connections per IP address to help mitigate
* malicious or abusive traffic to your applications. The attributes in the table that follows can be configured
* based on the traffic patterns for your sites.
*
* @author Everett Toews
*/
public class ConnectionThrottle {
private final int maxConnections;
private final int minConnections;
private final int maxConnectionRate;
private final int rateInterval;
protected ConnectionThrottle(int maxConnections, int minConnections, int maxConnectionRate, int rateInterval) {
this.maxConnections = maxConnections;
this.minConnections = minConnections;
this.maxConnectionRate = maxConnectionRate;
this.rateInterval = rateInterval;
}
public int getMaxConnections() {
return this.maxConnections;
}
public int getMinConnections() {
return this.minConnections;
}
public int getMaxConnectionRate() {
return this.maxConnectionRate;
}
public int getRateInterval() {
return this.rateInterval;
}
@Override
public int hashCode() {
return Objects.hashCode(maxConnections, minConnections, maxConnectionRate, rateInterval);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
ConnectionThrottle that = ConnectionThrottle.class.cast(obj);
return Objects.equal(this.maxConnections, that.maxConnections)
&& Objects.equal(this.minConnections, that.minConnections)
&& Objects.equal(this.maxConnectionRate, that.maxConnectionRate)
&& Objects.equal(this.rateInterval, that.rateInterval);
}
protected ToStringHelper string() {
return Objects.toStringHelper(this).add("maxConnections", maxConnections).add("minConnections", minConnections)
.add("maxConnectionRate", maxConnectionRate).add("rateInterval", rateInterval);
}
@Override
public String toString() {
return string().toString();
}
public static class Builder {
private int maxConnections;
private int minConnections;
private int maxConnectionRate;
private int rateInterval;
/**
* Maximum number of connections to allow for a single IP address. Setting a value of 0 will allow unlimited
* simultaneous connections; otherwise set a value between 1 and 100000.
*/
public Builder maxConnections(int maxConnections) {
this.maxConnections = maxConnections;
return this;
}
/**
* Allow at least this number of connections per IP address before applying throttling restrictions. Setting
* a value of 0 allows unlimited simultaneous connections; otherwise, set a value between 1 and 1000.
*/
public Builder minConnections(int minConnections) {
this.minConnections = minConnections;
return this;
}
/**
* Maximum number of connections allowed from a single IP address in the defined rateInterval. Setting a value
* of 0 allows an unlimited connection rate; otherwise, set a value between 1 and 100000.
*/
public Builder maxConnectionRate(int maxConnectionRate) {
this.maxConnectionRate = maxConnectionRate;
return this;
}
/**
* Frequency (in seconds) at which the maxConnectionRate is assessed. For example, a maxConnectionRate of 30
* with a rateInterval of 60 would allow a maximum of 30 connections per minute for a single IP address. This
* value must be between 1 and 3600.
*/
public Builder rateInterval(int rateInterval) {
this.rateInterval = rateInterval;
return this;
}
public ConnectionThrottle build() {
return new ConnectionThrottle(maxConnections, minConnections, maxConnectionRate, rateInterval);
}
public Builder from(ConnectionThrottle in) {
return this.maxConnections(in.getMaxConnections()).minConnections(in.getMinConnections())
.maxConnectionRate(in.getMaxConnectionRate()).rateInterval(in.getRateInterval());
}
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return new Builder().from(this);
}
}

View File

@ -0,0 +1,240 @@
/**
* 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.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
/**
* 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.
*
* @author Everett Toews
*/
public class HealthMonitor {
private final Type type;
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;
protected HealthMonitor(Type type, int delay, int timeout, int attemptsBeforeDeactivation, String bodyRegex,
String statusRegex, String path, 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;
}
public Type getType() {
return type;
}
public int getDelay() {
return delay;
}
public int getTimeout() {
return timeout;
}
public int getAttemptsBeforeDeactivation() {
return attemptsBeforeDeactivation;
}
public String getBodyRegex() {
return bodyRegex;
}
public String getStatusRegex() {
return statusRegex;
}
public String getPath() {
return path;
}
public String getHostHeader() {
return hostHeader;
}
@Override
public int hashCode() {
return Objects.hashCode(type, delay, timeout, attemptsBeforeDeactivation, bodyRegex, statusRegex, path,
hostHeader);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
HealthMonitor that = HealthMonitor.class.cast(obj);
return Objects.equal(this.type, that.type) && Objects.equal(this.delay, that.delay)
&& Objects.equal(this.timeout, that.timeout)
&& Objects.equal(this.attemptsBeforeDeactivation, that.attemptsBeforeDeactivation)
&& Objects.equal(this.bodyRegex, that.bodyRegex) && Objects.equal(this.statusRegex, that.statusRegex)
&& Objects.equal(this.path, that.path) && Objects.equal(this.hostHeader, that.hostHeader);
}
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);
}
@Override
public String toString() {
return string().toString();
}
/**
* Every health monitor has a type attribute to signify what kind of monitor it is.
*/
public static enum Type {
CONNECT, HTTP, HTTPS, UNRECOGNIZED;
public static Type fromValue(String type) {
try {
return valueOf(checkNotNull(type, "type"));
}
catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
}
public static class Builder {
private Type type;
private int delay;
private int timeout;
private int attemptsBeforeDeactivation;
private String bodyRegex;
private String statusRegex;
private String path;
private String hostHeader;
/**
* Type of the health monitor. Must be specified as CONNECT to monitor connections.
*/
public Builder type(Type type) {
this.type = type;
return this;
}
/**
* Required. The minimum number of seconds to wait before executing the health monitor.
* Must be a number between 1 and 3600.
*/
public Builder delay(int delay) {
this.delay = delay;
return this;
}
/**
* Required. Maximum number of seconds to wait for a connection to be established before timing out.
* Must be a number between 1 and 300.
*/
public Builder timeout(int timeout) {
this.timeout = timeout;
return this;
}
/**
* Required. Number of permissible monitor failures before removing a node from rotation.
* Must be a number between 1 and 10.
*/
public Builder attemptsBeforeDeactivation(int attemptsBeforeDeactivation) {
this.attemptsBeforeDeactivation = attemptsBeforeDeactivation;
return this;
}
/**
* Required (if using HTTP/S). A regular expression that will be used to evaluate the contents of the body of
* the response.
*/
public Builder bodyRegex(String bodyRegex) {
this.bodyRegex = bodyRegex;
return this;
}
/**
* Required (if using HTTP/S). A regular expression that will be used to evaluate the HTTP status code returned
* in the response.
*/
public Builder statusRegex(String statusRegex) {
this.statusRegex = statusRegex;
return this;
}
/**
* Required (if using HTTP/S). The HTTP path that will be used in the sample request.
*/
public Builder path(String path) {
this.path = path;
return this;
}
/**
* Optional (if using HTTP/S). The name of a host for which the health monitors will check.
*/
public Builder hostHeader(String hostHeader) {
this.hostHeader = hostHeader;
return this;
}
public HealthMonitor build() {
return new HealthMonitor(type, delay, timeout, attemptsBeforeDeactivation, bodyRegex, statusRegex, path,
hostHeader);
}
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());
}
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return new Builder().from(this);
}
}

View File

@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Date; import java.util.Date;
import java.util.Map;
import java.util.Set; import java.util.Set;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
@ -33,138 +34,154 @@ import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
/** /**
*
* @author Adrian Cole * @author Adrian Cole
*/ */
public class LoadBalancer extends BaseLoadBalancer<Node, LoadBalancer> { public class LoadBalancer extends BaseLoadBalancer<Node, LoadBalancer> {
@SuppressWarnings("unchecked") private final String region;
public static Builder builder() { private final int id;
return new Builder(); private final Status status;
private final Set<VirtualIP> virtualIPs;
private final String clusterName;
private final Date created;
private final Date updated;
private final boolean contentCaching;
private final int nodeCount;
private final SSLTermination sslTermination;
private final SourceAddresses sourceAddresses;
public LoadBalancer(String region, int id, String name, String protocol, @Nullable Integer port, Set<Node> nodes,
@Nullable Integer timeout, @Nullable Boolean halfClosed, @Nullable Algorithm algorithm, Status status,
Set<VirtualIP> virtualIPs, @Nullable Map<String, SessionPersistenceType> sessionPersistenceType,
String clusterName, Date created, Date updated, @Nullable Map<String, Boolean> connectionLogging,
@Nullable ConnectionThrottle connectionThrottle, boolean contentCaching, int nodeCount,
@Nullable HealthMonitor healthMonitor, @Nullable SSLTermination sslTermination,
SourceAddresses sourceAddresses, @Nullable Set<AccessRule> accessRules,
@Nullable Set<Metadata> metadata) {
super(name, protocol, port, nodes, algorithm, timeout, halfClosed, sessionPersistenceType, connectionLogging,
connectionThrottle, healthMonitor, accessRules, metadata);
this.region = checkNotNull(region, "region");
checkArgument(id != -1, "id must be specified");
this.id = id;
this.status = checkNotNull(status, "status");
this.virtualIPs = ImmutableSet.copyOf(checkNotNull(virtualIPs, "virtualIPs"));
this.clusterName = clusterName;
this.created = checkNotNull(created, "created");
this.updated = checkNotNull(updated, "updated");
this.contentCaching = contentCaching;
this.nodeCount = nodeCount;
this.sslTermination = sslTermination;
this.sourceAddresses = sourceAddresses;
}
public String getRegion() {
return region;
}
public int getId() {
return id;
} }
/** /**
* {@inheritDoc} * @see Status
*/ */
@Override public Status getStatus() {
public Builder toBuilder() { return status;
return new Builder().from(this);
} }
public static class Builder extends BaseLoadBalancer.Builder<Node, LoadBalancer> { /**
private String region; * @see VirtualIP
private int id = -1; */
private Status status; public Set<VirtualIP> getVirtualIPs() {
private Set<VirtualIP> virtualIPs = ImmutableSet.<VirtualIP> of(); return virtualIPs;
private String sessionPersistenceType; }
private String clusterName;
private Date created;
private Date updated;
private boolean connectionLoggingEnabled;
private int nodeCount = 0;
public Builder region(String region) { /**
this.region = region; * Name of the cluster.
return this; */
} public String getClusterName() {
return clusterName;
}
public Builder id(int id) { /**
this.id = id; * When the load balancer was created.
return this; */
} public Date getCreated() {
return created;
}
public Builder status(Status status) { /**
this.status = status; * When the load balancer was updated.
return this; */
} public Date getUpdated() {
return updated;
}
public Builder algorithm(Algorithm algorithm) { /**
algorithm(algorithm.name()); * View the current content caching configuration.
return this; */
} public boolean isContentCaching() {
return contentCaching;
}
public Builder virtualIPs(Iterable<VirtualIP> virtualIPs) { /**
this.virtualIPs = ImmutableSet.<VirtualIP> copyOf(checkNotNull(virtualIPs, "virtualIPs")); * Broken out as a separate field because when LoadBalancers are returned from
return this; * {@link LoadBalancerApi#list()}, no Nodes are returned (so you can't rely on getNodes().size())
} * but a nodeCount is returned. When {@link LoadBalancerApi#get(int)} is called, nodes are
* returned by no nodeCount is returned.
*
* @return The number of Nodes in this LoadBalancer
*/
public int getNodeCount() {
return nodes.size() > 0 ? nodes.size() : nodeCount;
}
public Builder sessionPersistenceType(String sessionPersistenceType) { /**
this.sessionPersistenceType = sessionPersistenceType; * @see SSLTermination
return this; */
} @Nullable
public SSLTermination getSSLTermination() {
return sslTermination;
}
public Builder clusterName(String clusterName) { /**
this.clusterName = clusterName; * @see SourceAddresses
return this; */
} public SourceAddresses getSourceAddresses() {
return sourceAddresses;
}
public Builder created(Date created) { protected ToStringHelper string() {
this.created = created; return Objects.toStringHelper(this).omitNullValues().add("id", id).add("region", region).add("status", status)
return this; .add("name", name).add("protocol", protocol).add("port", port).add("nodeCount", getNodeCount())
} .add("nodes", nodes).add("timeout", timeout).add("algorithm", algorithm).add("halfClosed", halfClosed)
.add("clusterName", clusterName).add("created", created).add("updated", updated)
.add("contentCaching", contentCaching).add("sessionPersistenceType", getSessionPersistenceType())
.add("sslTermination", sslTermination).add("connectionLogging", isConnectionLogging())
.add("connectionThrottle", connectionThrottle).add("healthMonitor", healthMonitor)
.add("accessRules", accessList).add("metadata", getMetadata()).add("sourceAddresses", sourceAddresses)
.add("virtualIPs", virtualIPs);
}
public Builder updated(Date updated) { @Override
this.updated = updated; public String toString() {
return this; return string().toString();
} }
public Builder connectionLoggingEnabled(boolean connectionLoggingEnabled) { @Override
this.connectionLoggingEnabled = connectionLoggingEnabled; public int hashCode() {
return this; return Objects.hashCode(id, region);
} }
/** @Override
* @see LoadBalancer#getNodeCount() public boolean equals(Object obj) {
*/ if (this == obj)
public Builder nodeCount(int nodeCount) { return true;
this.nodeCount = nodeCount; if (obj == null || getClass() != obj.getClass())
return this; return false;
}
public LoadBalancer build() {
return new LoadBalancer(region, id, name, protocol, port, algorithm, status, virtualIPs, nodes,
sessionPersistenceType, clusterName, created, updated, connectionLoggingEnabled, nodeCount);
}
@Override
public Builder nodes(Iterable<Node> nodes) {
this.nodes = ImmutableSet.<Node> copyOf(checkNotNull(nodes, "nodes"));
return this;
}
@Override
public Builder node(Node nodes) {
this.nodes.add(checkNotNull(nodes, "nodes"));
return this;
}
@Override
public Builder algorithm(String algorithm) {
return Builder.class.cast(super.algorithm(algorithm));
}
@Override
public Builder from(LoadBalancer in) {
return Builder.class.cast(super.from(in)).id(in.getId()).status(in.getStatus()).virtualIPs(in.getVirtualIPs())
.clusterName(in.getClusterName()).created(in.getCreated()).updated(in.getUpdated())
.connectionLoggingEnabled(in.isConnectionLoggingEnabled()).nodeCount(in.getNodeCount());
}
@Override
public Builder name(String name) {
return Builder.class.cast(super.name(name));
}
@Override
public Builder port(Integer port) {
return Builder.class.cast(super.port(port));
}
@Override
public Builder protocol(String protocol) {
return Builder.class.cast(super.protocol(protocol));
}
LoadBalancer that = LoadBalancer.class.cast(obj);
return Objects.equal(this.id, that.id) && Objects.equal(this.region, that.region);
} }
/** /**
@ -216,168 +233,221 @@ public class LoadBalancer extends BaseLoadBalancer<Node, LoadBalancer> {
public static Status fromValue(String status) { public static Status fromValue(String status) {
try { try {
return valueOf(checkNotNull(status, "status")); return valueOf(checkNotNull(status, "status"));
} catch (IllegalArgumentException e) { }
catch (IllegalArgumentException e) {
return UNRECOGNIZED; return UNRECOGNIZED;
} }
} }
} }
/** public static class Builder extends BaseLoadBalancer.Builder<Node, LoadBalancer> {
* All load balancers utilize an algorithm that defines how traffic should be directed between private String region;
* back-end nodes. The default algorithm for newly created load balancers is RANDOM, which can be private int id = -1;
* overridden at creation time or changed after the load balancer has been initially provisioned. private Status status;
* The algorithm name is to be constant within a major revision of the load balancing API, though private Set<VirtualIP> virtualIPs = ImmutableSet.<VirtualIP> of();
* new algorithms may be created with a unique algorithm name within a given major revision of private String clusterName;
* the service API. private Date created;
*/ private Date updated;
public static enum Algorithm { private boolean contentCaching;
/** private int nodeCount = 0;
* The node with the lowest number of connections will receive requests. private SSLTermination sslTermination;
*/ private SourceAddresses sourceAddresses;
LEAST_CONNECTIONS,
/**
* Back-end servers are selected at random.
*/
RANDOM,
/**
* Connections are routed to each of the back-end servers in turn.
*/
ROUND_ROBIN,
/**
* Each request will be assigned to a node based on the number of concurrent connections to
* the node and its weight.
*/
WEIGHTED_LEAST_CONNECTIONS,
/**
* A round robin algorithm, but with different proportions of traffic being directed to the
* back-end nodes. Weights must be defined as part of the load balancer's node configuration.
*/
WEIGHTED_ROUND_ROBIN, UNRECOGNIZED;
public static Algorithm fromValue(String algorithm) { public Builder region(String region) {
try { this.region = region;
return valueOf(checkNotNull(algorithm, "algorithm")); return this;
} catch (IllegalArgumentException e) { }
return UNRECOGNIZED;
} public Builder id(int id) {
this.id = id;
return this;
}
public Builder status(Status status) {
this.status = status;
return this;
}
public Builder virtualIPs(Iterable<VirtualIP> virtualIPs) {
this.virtualIPs = ImmutableSet.<VirtualIP> copyOf(checkNotNull(virtualIPs, "virtualIPs"));
return this;
}
public Builder clusterName(String clusterName) {
this.clusterName = clusterName;
return this;
}
public Builder created(Date created) {
this.created = created;
return this;
}
public Builder updated(Date updated) {
this.updated = updated;
return this;
}
public Builder contentCaching(boolean contentCaching) {
this.contentCaching = contentCaching;
return this;
}
/**
* @see LoadBalancer#getNodeCount()
*/
public Builder nodeCount(int nodeCount) {
this.nodeCount = nodeCount;
return this;
}
public Builder sslTermination(@Nullable SSLTermination sslTermination) {
this.sslTermination = sslTermination;
return this;
}
public Builder sourceAddresses(@Nullable SourceAddresses sourceAddresses) {
this.sourceAddresses = sourceAddresses;
return this;
}
public LoadBalancer build() {
return new LoadBalancer(region, id, name, protocol, port, nodes, timeout, halfClosed, algorithm, status,
virtualIPs, sessionPersistence, clusterName, created, updated, connectionLogging, connectionThrottle,
contentCaching, nodeCount, healthMonitor, sslTermination, sourceAddresses, accessRules, metadata);
}
/**
* {@inheritDoc}
*/
@Override
public Builder nodes(Iterable<Node> nodes) {
this.nodes = ImmutableSet.<Node> copyOf(checkNotNull(nodes, "nodes"));
return this;
}
/**
* {@inheritDoc}
*/
@Override
public Builder node(Node nodes) {
this.nodes.add(checkNotNull(nodes, "nodes"));
return this;
}
/**
* {@inheritDoc}
*/
@Override
public Builder algorithm(Algorithm algorithm) {
return Builder.class.cast(super.algorithm(algorithm));
}
/**
* {@inheritDoc}
*/
@Override
public Builder name(String name) {
return Builder.class.cast(super.name(name));
}
/**
* {@inheritDoc}
*/
@Override
public Builder port(Integer port) {
return Builder.class.cast(super.port(port));
}
/**
* {@inheritDoc}
*/
@Override
public Builder protocol(String protocol) {
return Builder.class.cast(super.protocol(protocol));
}
/**
* {@inheritDoc}
*/
@Override
public Builder timeout(@Nullable Integer timeout) {
return Builder.class.cast(super.timeout(timeout));
}
/**
* {@inheritDoc}
*/
@Override
public Builder halfClosed(@Nullable Boolean halfClosed) {
return Builder.class.cast(super.halfClosed(halfClosed));
}
/**
* {@inheritDoc}
*/
@Override
public Builder sessionPersistenceType(@Nullable SessionPersistenceType sessionPersistenceType) {
return Builder.class.cast(super.sessionPersistenceType(sessionPersistenceType));
}
/**
* {@inheritDoc}
*/
@Override
public Builder connectionLogging(@Nullable Boolean connectionLogging) {
return Builder.class.cast(super.connectionLogging(connectionLogging));
}
/**
* {@inheritDoc}
*/
@Override
public Builder connectionThrottle(@Nullable ConnectionThrottle connectionThrottle) {
return Builder.class.cast(super.connectionThrottle(connectionThrottle));
}
/**
* {@inheritDoc}
*/
@Override
public Builder healthMonitor(@Nullable HealthMonitor healthMonitor) {
return Builder.class.cast(super.healthMonitor(healthMonitor));
}
/**
* {@inheritDoc}
*/
@Override
public Builder accessRules(@Nullable Set<AccessRule> accessRules) {
return Builder.class.cast(super.accessRules(accessRules));
}
/**
* {@inheritDoc}
*/
@Override
public Builder metadata(@Nullable Set<Metadata> metadata) {
return Builder.class.cast(super.metadata(metadata));
}
@Override
public Builder from(LoadBalancer in) {
return Builder.class.cast(super.from(in)).region(in.getRegion()).id(in.getId()).status(in.getStatus())
.virtualIPs(in.getVirtualIPs()).clusterName(in.getClusterName()).created(in.getCreated())
.updated(in.getUpdated()).contentCaching(in.isContentCaching()).nodeCount(in.getNodeCount())
.sslTermination(in.getSSLTermination()).sourceAddresses(in.getSourceAddresses());
} }
} }
public static Algorithm[] WEIGHTED_ALGORITHMS = { Algorithm.WEIGHTED_LEAST_CONNECTIONS, @SuppressWarnings("unchecked")
Algorithm.WEIGHTED_ROUND_ROBIN }; public static Builder builder() {
return new Builder();
private final String region;
private final int id;
private final Status status;
private final Algorithm algorithm;
private final Set<VirtualIP> virtualIPs;
private final String sessionPersistenceType;
private final String clusterName;
private final Date created;
private final Date updated;
private final boolean connectionLoggingEnabled;
private int nodeCount = 0;
public LoadBalancer(String region, int id, String name, String protocol, Integer port, @Nullable String algorithm,
Status status, Iterable<VirtualIP> virtualIPs, Iterable<Node> nodes, String sessionPersistenceType,
String clusterName, Date created, Date updated, boolean connectionLoggingEnabled, Integer nodeCount) {
super(name, protocol, port, algorithm, nodes);
this.region = checkNotNull(region, "region");
checkArgument(id != -1, "id must be specified");
this.id = id;
this.status = checkNotNull(status, "status");
this.algorithm = algorithm != null ? Algorithm.fromValue(algorithm) : null;
this.virtualIPs = ImmutableSet.copyOf(checkNotNull(virtualIPs, "virtualIPs"));
this.sessionPersistenceType = sessionPersistenceType;
this.clusterName = clusterName;
this.created = checkNotNull(created, "created");
this.updated = checkNotNull(updated, "updated");
this.connectionLoggingEnabled = connectionLoggingEnabled;
this.nodeCount = nodeCount;
}
public String getRegion() {
return region;
}
public int getId() {
return id;
}
public Status getStatus() {
return status;
}
/**
*
* @return algorithm, which may be null if the load balancer is deleted
*/
@Nullable
public Algorithm getTypedAlgorithm() {
return algorithm;
}
public Set<VirtualIP> getVirtualIPs() {
return virtualIPs;
}
public String getClusterName() {
return clusterName;
}
public String getSessionPersistenceType() {
return sessionPersistenceType;
}
public Date getCreated() {
return created;
}
public Date getUpdated() {
return updated;
}
public boolean isConnectionLoggingEnabled() {
return connectionLoggingEnabled;
}
/**
* Broken out as a separate field because when LoadBalancers are returned from
* {@link LoadBalancerApi#list()}, no Nodes are returned (so you can't rely on getNodes().size())
* but a nodeCount is returned. When {@link LoadBalancerApi#get(int)} is called, nodes are
* returned by no nodeCount is returned.
*
* @return The number of Nodes in this LoadBalancer
*/
public int getNodeCount() {
return nodes.size() > 0 ? nodes.size() : nodeCount;
}
protected ToStringHelper string() {
return Objects.toStringHelper(this).omitNullValues()
.add("id", id).add("region", region).add("name", name).add("protocol", protocol).add("port", port)
.add("algorithm", algorithm).add("status", status).add("virtualIPs", virtualIPs).add("nodeCount", getNodeCount())
.add("nodes", nodes).add("sessionPersistenceType", sessionPersistenceType).add("created", created)
.add("updated", updated).add("clusterName", clusterName).add("connectionLoggingEnabled", connectionLoggingEnabled);
}
@Override
public String toString() {
return string().toString();
} }
@Override @Override
public int hashCode() { public Builder toBuilder() {
return Objects.hashCode(id, region); return new Builder().from(this);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
LoadBalancer that = LoadBalancer.class.cast(obj);
return Objects.equal(this.id, that.id) && Objects.equal(this.region, that.region);
} }
} }

View File

@ -19,22 +19,24 @@
package org.jclouds.rackspace.cloudloadbalancers.domain; package org.jclouds.rackspace.cloudloadbalancers.domain;
import org.jclouds.rackspace.cloudloadbalancers.domain.internal.BaseLoadBalancer; import org.jclouds.rackspace.cloudloadbalancers.domain.internal.BaseLoadBalancer;
import org.jclouds.rackspace.cloudloadbalancers.domain.internal.BaseLoadBalancer.Algorithm;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Objects.ToStringHelper;
/** /**
* Used to update Load Balancers.
* *
* @author Adrian Cole * @author Adrian Cole
* @see <a href=
* "http://docs.rackspacecloud.com/loadbalancers/api/v1.0/clb-devguide/content/ch04s01s02.html"
* />
*/ */
public class LoadBalancerAttributes { public class LoadBalancerAttributes {
protected String name; protected String name;
protected String protocol; protected String protocol;
protected Integer port; protected Integer port;
protected String algorithm; protected Algorithm algorithm;
protected Integer timeout;
protected Boolean halfClosed;
public LoadBalancerAttributes name(String name) { public LoadBalancerAttributes name(String name) {
this.name = name; this.name = name;
@ -46,43 +48,31 @@ public class LoadBalancerAttributes {
return this; return this;
} }
public LoadBalancerAttributes port(int port) { public LoadBalancerAttributes port(Integer port) {
this.port = port; this.port = port;
return this; return this;
} }
public LoadBalancerAttributes algorithm(String algorithm) { public LoadBalancerAttributes algorithm(Algorithm algorithm) {
this.algorithm = algorithm; this.algorithm = algorithm;
return this; return this;
} }
public static <T extends BaseLoadBalancer<?, T>> LoadBalancerAttributes fromLoadBalancer(T lb) { public LoadBalancerAttributes timeout(Integer timeout) {
return Builder.name(lb.getName()).port(lb.getPort()).protocol(lb.getProtocol()).algorithm(lb.getAlgorithm()); this.timeout = timeout;
return this;
} }
public static class Builder { public LoadBalancerAttributes halfClosed(Boolean halfClosed) {
public static LoadBalancerAttributes name(String name) { this.halfClosed = halfClosed;
return new LoadBalancerAttributes().name(name); return this;
}
public static LoadBalancerAttributes protocol(String protocol) {
return new LoadBalancerAttributes().protocol(protocol);
}
public static LoadBalancerAttributes port(int port) {
return new LoadBalancerAttributes().port(port);
}
public static LoadBalancerAttributes algorithm(String algorithm) {
return new LoadBalancerAttributes().algorithm(algorithm);
}
} }
protected ToStringHelper string() { protected ToStringHelper string() {
return Objects.toStringHelper(this).omitNullValues() return Objects.toStringHelper(this).omitNullValues().add("name", name).add("algorithm", algorithm)
.add("name", name).add("algorithm", algorithm).add("port", port).add("protocol", protocol); .add("port", port).add("protocol", protocol).add("timeout", timeout).add("halfClosed", halfClosed);
} }
@Override @Override
public String toString() { public String toString() {
return string().toString(); return string().toString();
@ -90,18 +80,68 @@ public class LoadBalancerAttributes {
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hashCode(name, algorithm, port, protocol); return Objects.hashCode(name, algorithm, port, protocol, timeout, halfClosed);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) return true; if (this == obj)
if (obj == null || getClass() != obj.getClass()) return false; return true;
if (obj == null || getClass() != obj.getClass())
return false;
LoadBalancerAttributes that = LoadBalancerAttributes.class.cast(obj); LoadBalancerAttributes that = LoadBalancerAttributes.class.cast(obj);
return Objects.equal(this.name, that.name) return Objects.equal(this.name, that.name) && Objects.equal(this.algorithm, that.algorithm)
&& Objects.equal(this.algorithm, that.algorithm) && Objects.equal(this.port, that.port) && Objects.equal(this.protocol, that.protocol)
&& Objects.equal(this.port, that.port) && Objects.equal(this.timeout, that.timeout) && Objects.equal(this.halfClosed, that.halfClosed);
&& Objects.equal(this.protocol, that.protocol); }
public static class Builder {
/**
* @see BaseLoadBalancer.Builder#name(String)
*/
public static LoadBalancerAttributes name(String name) {
return new LoadBalancerAttributes().name(name);
}
/**
* @see BaseLoadBalancer.Builder#protocol(String)
*/
public static LoadBalancerAttributes protocol(String protocol) {
return new LoadBalancerAttributes().protocol(protocol);
}
/**
* @see BaseLoadBalancer.Builder#port(Integer)
*/
public static LoadBalancerAttributes port(Integer port) {
return new LoadBalancerAttributes().port(port);
}
/**
* @see BaseLoadBalancer.Builder#algorithm(Algorithm)
*/
public static LoadBalancerAttributes algorithm(Algorithm algorithm) {
return new LoadBalancerAttributes().algorithm(algorithm);
}
/**
* @see BaseLoadBalancer.Builder#timeout(Integer)
*/
public static LoadBalancerAttributes timeout(Integer timeout) {
return new LoadBalancerAttributes().timeout(timeout);
}
/**
* @see BaseLoadBalancer.Builder#halfClosed(Boolean)
*/
public static LoadBalancerAttributes halfClosed(Boolean halfClosed) {
return new LoadBalancerAttributes().halfClosed(halfClosed);
}
}
public static <T extends BaseLoadBalancer<?, T>> LoadBalancerAttributes fromLoadBalancer(T lb) {
return Builder.name(lb.getName()).port(lb.getPort()).protocol(lb.getProtocol()).algorithm(lb.getAlgorithm())
.timeout(lb.getTimeout()).halfClosed(lb.isHalfClosed());
} }
} }

View File

@ -21,43 +21,77 @@ package org.jclouds.rackspace.cloudloadbalancers.domain;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.rackspace.cloudloadbalancers.domain.internal.BaseLoadBalancer; import org.jclouds.rackspace.cloudloadbalancers.domain.internal.BaseLoadBalancer;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
/** /**
* Used to create Load Balancers.
* *
* @author Adrian Cole * @author Adrian Cole
* @see <a href=
* "http://docs.rackspacecloud.com/loadbalancers/api/v1.0/clb-devguide/content/ch04s01s02.html"
* />
*/ */
public class LoadBalancerRequest extends BaseLoadBalancer<NodeRequest, LoadBalancerRequest> { public class LoadBalancerRequest extends BaseLoadBalancer<NodeRequest, LoadBalancerRequest> {
@SuppressWarnings("unchecked") private final Set<Map<String, String>> virtualIps;
public static Builder builder() {
return new Builder(); public LoadBalancerRequest(String name, String protocol, @Nullable Integer port, Set<NodeRequest> nodes,
@Nullable Algorithm algorithm, @Nullable Integer timeout, @Nullable Boolean halfClosed,
@Nullable Map<String, SessionPersistenceType> sessionPersistenceType,
@Nullable Map<String, Boolean> connectionLogging, @Nullable ConnectionThrottle connectionThrottle,
@Nullable HealthMonitor healthMonitor, @Nullable Set<AccessRule> accessRules,
@Nullable Set<Metadata> metadata, VirtualIP.Type virtualIPType, Integer virtualIPId) {
this(name, protocol, port, nodes, algorithm, timeout, halfClosed, sessionPersistenceType, connectionLogging,
connectionThrottle, healthMonitor, accessRules, metadata, getVirtualIPsFromOptions(virtualIPType,
virtualIPId));
}
public LoadBalancerRequest(String name, String protocol, @Nullable Integer port, Set<NodeRequest> nodes,
@Nullable Algorithm algorithm, @Nullable Integer timeout, @Nullable Boolean halfClosed,
@Nullable Map<String, SessionPersistenceType> sessionPersistenceType,
@Nullable Map<String, Boolean> connectionLogging, @Nullable ConnectionThrottle connectionThrottle,
@Nullable HealthMonitor healthMonitor, @Nullable Set<AccessRule> accessRules,
@Nullable Set<Metadata> metadata, Set<Map<String, String>> virtualIPsFromOptions) {
super(name, protocol, port, nodes, algorithm, timeout, halfClosed, sessionPersistenceType, connectionLogging,
connectionThrottle, healthMonitor, accessRules, metadata);
this.virtualIps = checkNotNull(virtualIPsFromOptions, "virtualIPsFromOptions");
}
static Set<Map<String, String>> getVirtualIPsFromOptions(VirtualIP.Type virtualIPType, Integer virtualIPId) {
checkArgument(virtualIPType == null || virtualIPId == null,
"virtualIPType and virtualIPId cannot both be specified");
if (virtualIPType != null)
return ImmutableSet.<Map<String, String>> of(ImmutableMap.of("type", virtualIPType.name()));
else if (virtualIPId != null)
return ImmutableSet.<Map<String, String>> of(ImmutableMap.of("id", virtualIPId.toString()));
else
throw new IllegalArgumentException("virtualIPType or virtualIPId must be specified");
}
protected ToStringHelper string() {
return Objects.toStringHelper(this).omitNullValues().add("name", name).add("protocol", protocol)
.add("port", port).add("nodes", nodes).add("timeout", timeout).add("algorithm", algorithm)
.add("timeout", timeout).add("sessionPersistenceType", getSessionPersistenceType())
.add("connectionLogging", isConnectionLogging()).add("connectionThrottle", connectionThrottle)
.add("healthMonitor", healthMonitor).add("accessRules", accessList).add("metadata", metadata)
.add("virtualIps", virtualIps);
} }
/**
* {@inheritDoc}
*/
@Override @Override
public Builder toBuilder() { public String toString() {
return new Builder().from(this); return string().toString();
} }
public static class Builder extends BaseLoadBalancer.Builder<NodeRequest, LoadBalancerRequest> { public static class Builder extends BaseLoadBalancer.Builder<NodeRequest, LoadBalancerRequest> {
private VirtualIP.Type virtualIPType; private VirtualIP.Type virtualIPType;
private Integer virtualIPId; private Integer virtualIPId;
private List<Map<String, String>> virtualIps; private Set<Map<String, String>> virtualIps;
public Builder virtualIPId(Integer virtualIPId) { public Builder virtualIPId(Integer virtualIPId) {
this.virtualIPId = virtualIPId; this.virtualIPId = virtualIPId;
@ -69,49 +103,77 @@ public class LoadBalancerRequest extends BaseLoadBalancer<NodeRequest, LoadBalan
return this; return this;
} }
public LoadBalancerRequest build() { private Builder virtualIPs(Set<Map<String, String>> virtualIPs) {
return virtualIps == null this.virtualIps = virtualIPs;
? new LoadBalancerRequest(name, protocol, port, algorithm, nodes, virtualIPType, virtualIPId) return this;
: new LoadBalancerRequest(name, protocol, port, algorithm, nodes, virtualIps);
} }
public LoadBalancerRequest build() {
if (virtualIps == null) {
return new LoadBalancerRequest(name, protocol, port, nodes, algorithm, timeout, halfClosed,
sessionPersistence, connectionLogging, connectionThrottle, healthMonitor, accessRules, metadata,
virtualIPType, virtualIPId);
}
else {
return new LoadBalancerRequest(name, protocol, port, nodes, algorithm, timeout, halfClosed,
sessionPersistence, connectionLogging, connectionThrottle, healthMonitor, accessRules, metadata,
virtualIps);
}
}
/**
* {@inheritDoc}
*/
@Override @Override
public Builder nodes(Iterable<NodeRequest> nodes) { public Builder nodes(Iterable<NodeRequest> nodes) {
this.nodes = ImmutableSet.<NodeRequest> copyOf(checkNotNull(nodes, "nodes")); this.nodes = ImmutableSet.<NodeRequest> copyOf(checkNotNull(nodes, "nodes"));
return this; return this;
} }
/**
* {@inheritDoc}
*/
@Override @Override
public Builder node(NodeRequest nodes) { public Builder node(NodeRequest nodes) {
this.nodes.add(checkNotNull(nodes, "nodes")); this.nodes.add(checkNotNull(nodes, "nodes"));
return this; return this;
} }
private Builder virtualIPs(List<Map<String, String>> virtualIPs) { /**
this.virtualIps = virtualIPs; * {@inheritDoc}
return this; */
}
@Override @Override
public Builder algorithm(String algorithm) { public Builder algorithm(Algorithm algorithm) {
return Builder.class.cast(super.algorithm(algorithm)); return Builder.class.cast(super.algorithm(algorithm));
} }
/**
* {@inheritDoc}
*/
@Override @Override
public Builder from(LoadBalancerRequest in) { public Builder from(LoadBalancerRequest in) {
return Builder.class.cast(super.from(in)).virtualIPs(in.virtualIps); return Builder.class.cast(super.from(in)).virtualIPs(in.virtualIps);
} }
/**
* {@inheritDoc}
*/
@Override @Override
public Builder name(String name) { public Builder name(String name) {
return Builder.class.cast(super.name(name)); return Builder.class.cast(super.name(name));
} }
/**
* {@inheritDoc}
*/
@Override @Override
public Builder port(Integer port) { public Builder port(Integer port) {
return Builder.class.cast(super.port(port)); return Builder.class.cast(super.port(port));
} }
/**
* {@inheritDoc}
*/
@Override @Override
public Builder protocol(String protocol) { public Builder protocol(String protocol) {
return Builder.class.cast(super.protocol(protocol)); return Builder.class.cast(super.protocol(protocol));
@ -119,38 +181,13 @@ public class LoadBalancerRequest extends BaseLoadBalancer<NodeRequest, LoadBalan
} }
private final List<Map<String, String>> virtualIps; @SuppressWarnings("unchecked")
public static Builder builder() {
public LoadBalancerRequest(String name, String protocol, int port, String algorithm, Iterable<NodeRequest> nodes, return new Builder();
VirtualIP.Type virtualIPType, Integer virtualIPId) {
this(name, protocol, port, algorithm, nodes, getVirtualIPsFromOptions(virtualIPType, virtualIPId));
} }
private LoadBalancerRequest(String name, String protocol, int port, String algorithm, Iterable<NodeRequest> nodes,
List<Map<String, String>> virtualIPsFromOptions) {
super(name, protocol, port, algorithm, nodes);
this.virtualIps = checkNotNull(virtualIPsFromOptions, "virtualIPsFromOptions");
}
static List<Map<String, String>> getVirtualIPsFromOptions(VirtualIP.Type virtualIPType, Integer virtualIPId) {
checkArgument(virtualIPType == null || virtualIPId == null,
"virtualIPType and virtualIPId cannot both be specified");
if (virtualIPType != null)
return ImmutableList.<Map<String, String>> of(ImmutableMap.of("type", virtualIPType.name()));
else if (virtualIPId != null)
return ImmutableList.<Map<String, String>> of(ImmutableMap.of("id", virtualIPId.toString()));
else
throw new IllegalArgumentException("virtualIPType or virtualIPId must be specified");
}
protected ToStringHelper string() {
return Objects.toStringHelper(this).omitNullValues()
.add("name", name).add("algorithm", algorithm).add("nodes", nodes).add("port", port)
.add("protocol", protocol).add("virtualIps", virtualIps);
}
@Override @Override
public String toString() { public Builder toBuilder() {
return string().toString(); return new Builder().from(this);
} }
} }

View File

@ -0,0 +1,111 @@
/**
* 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.domain;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
/**
* @author Everett Toews
*/
public class Metadata {
private int id;
private String key;
private String value;
private Metadata(Integer id, String key, String value) {
this.id = id;
this.key = key;
this.value = value;
}
public int getId() {
return id;
}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
@Override
public int hashCode() {
return Objects.hashCode(id);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Metadata that = Metadata.class.cast(obj);
return Objects.equal(this.id, that.id);
}
protected ToStringHelper string() {
return Objects.toStringHelper(this).omitNullValues()
.add("id", id).add("key", key).add("value", value);
}
@Override
public String toString() {
return string().toString();
}
public static class Builder {
private Integer id;
private String key;
private String value;
public Builder id(Integer id) {
this.id = id;
return this;
}
public Builder key(String key) {
this.key = key;
return this;
}
public Builder value(String value) {
this.value = value;
return this;
}
public Metadata build() {
return new Metadata(id, key, value);
}
public Builder from(Metadata in) {
return id(in.getId()).key(in.getKey()).value(in.getValue());
}
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return new Builder().from(this);
}
}

View File

@ -51,73 +51,58 @@ import com.google.common.base.Objects.ToStringHelper;
* nodes. * nodes.
* *
* @author Adrian Cole * @author Adrian Cole
* @see <a href=
* "http://docs.rackspacecloud.com/loadbalancers/api/v1.0/clb-devguide/content/ch04s02.html" />
*/ */
public class Node extends BaseNode<Node> { public class Node extends BaseNode<Node> {
@SuppressWarnings("unchecked") private int id;
public static Builder builder() { private Status status;
return new Builder();
// for serialization only
Node() {
} }
/** public Node(int id, String address, int port, Condition condition, Type type, Status status, Integer weight) {
* {@inheritDoc} super(address, port, condition, type, weight);
*/ checkArgument(id != -1, "id must be specified");
this.id = id;
this.status = checkNotNull(status, "status");
}
public int getId() {
return id;
}
public Status getStatus() {
return status;
}
protected ToStringHelper string() {
return Objects.toStringHelper(this).omitNullValues()
.add("id", id).add("address", address).add("port", port).add("condition", condition)
.add("type", type).add("weight", weight).add("status", status);
}
@Override @Override
public Builder toBuilder() { public String toString() {
return new Builder().from(this); return string().toString();
} }
public static class Builder extends BaseNode.Builder<Node> { @Override
private int id = -1; public int hashCode() {
private Status status; return Objects.hashCode(id);
}
public Builder id(int id) { @Override
this.id = id; public boolean equals(Object obj) {
return this; if (this == obj) return true;
} if (obj == null || getClass() != obj.getClass()) return false;
public Builder status(Status status) {
this.status = status;
return this;
}
@Override
public Node build() {
return new Node(id, address, port, condition, status, weight);
}
@Override
public Builder address(String address) {
return Builder.class.cast(super.address(address));
}
@Override
public Builder condition(Condition condition) {
return Builder.class.cast(super.condition(condition));
}
@Override
public Builder from(Node in) {
return Builder.class.cast(super.from(in)).id(in.getId()).status(in.getStatus());
}
@Override
public Builder port(int port) {
return Builder.class.cast(super.port(port));
}
@Override
public Builder weight(Integer weight) {
return Builder.class.cast(super.weight(weight));
}
Node that = Node.class.cast(obj);
return Objects.equal(this.id, that.id);
} }
/** /**
* The status is determined by the passive or active health monitors. * The status is determined by the passive or active health monitors.
*
*/ */
public static enum Status { public static enum Status {
/** /**
@ -146,54 +131,82 @@ public class Node extends BaseNode<Node> {
return UNRECOGNIZED; return UNRECOGNIZED;
} }
} }
} }
private int id; public static class Builder extends BaseNode.Builder<Node> {
private Status status; private int id = -1;
private Status status;
// for serialization only public Builder id(int id) {
Node() { this.id = id;
return this;
}
/**
* @see Status
*/
public Builder status(Status status) {
this.status = status;
return this;
}
@Override
public Node build() {
return new Node(id, address, port, condition, type, status, weight);
}
/**
* {@inheritDoc}
*/
@Override
public Builder address(String address) {
return Builder.class.cast(super.address(address));
}
/**
* {@inheritDoc}
*/
@Override
public Builder condition(Condition condition) {
return Builder.class.cast(super.condition(condition));
}
/**
* {@inheritDoc}
*/
@Override
public Builder type(Type type) {
return Builder.class.cast(super.type(type));
}
/**
* {@inheritDoc}
*/
@Override
public Builder port(int port) {
return Builder.class.cast(super.port(port));
}
/**
* {@inheritDoc}
*/
@Override
public Builder weight(Integer weight) {
return Builder.class.cast(super.weight(weight));
}
@Override
public Builder from(Node in) {
return Builder.class.cast(super.from(in)).id(in.getId()).status(in.getStatus());
}
} }
public Node(int id, String address, int port, Condition condition, Status status, Integer weight) { @SuppressWarnings("unchecked")
super(address, port, condition, weight); public static Builder builder() {
checkArgument(id != -1, "id must be specified"); return new Builder();
this.id = id;
this.status = checkNotNull(status, "status");
}
public int getId() {
return id;
}
public Status getStatus() {
return status;
}
protected ToStringHelper string() {
return Objects.toStringHelper(this).omitNullValues()
.add("address", address).add("port", port).add("condition", condition)
.add("weight", weight).add("status", status);
}
@Override
public String toString() {
return string().toString();
} }
@Override @Override
public int hashCode() { public Builder toBuilder() {
return Objects.hashCode(id); return new Builder().from(this);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Node that = Node.class.cast(obj);
return Objects.equal(this.id, that.id);
} }
} }

View File

@ -20,48 +20,40 @@ package org.jclouds.rackspace.cloudloadbalancers.domain;
import org.jclouds.rackspace.cloudloadbalancers.domain.internal.BaseNode; import org.jclouds.rackspace.cloudloadbalancers.domain.internal.BaseNode;
import org.jclouds.rackspace.cloudloadbalancers.domain.internal.BaseNode.Condition; import org.jclouds.rackspace.cloudloadbalancers.domain.internal.BaseNode.Condition;
import org.jclouds.rackspace.cloudloadbalancers.domain.internal.BaseNode.Type;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Objects.ToStringHelper;
/** /**
* Used to update Nodes.
* *
* @author Dan Lo Bianco * @author Dan Lo Bianco
* @see <a href=
* "http://docs.rackspace.com/loadbalancers/api/v1.0/clb-devguide/content/Modify_Nodes-d1e2503.html"
* />
*/ */
public class NodeAttributes { public class NodeAttributes {
protected String condition;
protected Condition condition;
protected Type type;
protected Integer weight; protected Integer weight;
public NodeAttributes condition(String condition) { public NodeAttributes condition(Condition condition) {
this.condition = condition; this.condition = condition;
return this; return this;
} }
public NodeAttributes weight(int weight) { public NodeAttributes type(Type type) {
this.type = type;
return this;
}
public NodeAttributes weight(Integer weight) {
this.weight = weight; this.weight = weight;
return this; return this;
} }
public static <T extends BaseNode<T>> NodeAttributes fromNode(T n) {
return Builder.condition(n.getCondition()).weight(n.getWeight());
}
public static class Builder {
public static NodeAttributes condition(Condition condition) {
return new NodeAttributes().condition(condition.name());
}
public static NodeAttributes weight(int weight) {
return new NodeAttributes().weight(weight);
}
}
protected ToStringHelper string() { protected ToStringHelper string() {
return Objects.toStringHelper(this).omitNullValues() return Objects.toStringHelper(this).omitNullValues()
.add("condition", condition).add("weight", weight); .add("condition", condition).add("type", type).add("weight", weight);
} }
@Override @Override
@ -71,7 +63,7 @@ public class NodeAttributes {
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hashCode(condition, weight); return Objects.hashCode(condition, type, weight);
} }
@Override @Override
@ -81,6 +73,34 @@ public class NodeAttributes {
NodeAttributes that = NodeAttributes.class.cast(obj); NodeAttributes that = NodeAttributes.class.cast(obj);
return Objects.equal(this.condition, that.condition) return Objects.equal(this.condition, that.condition)
&& Objects.equal(this.type, that.type)
&& Objects.equal(this.weight, that.weight); && Objects.equal(this.weight, that.weight);
} }
public static class Builder {
/**
* @see BaseNode.Builder#condition(Condition)
*/
public static NodeAttributes condition(Condition condition) {
return new NodeAttributes().condition(condition);
}
/**
* @see BaseNode.Builder#type(Type)
*/
public static NodeAttributes type(Type type) {
return new NodeAttributes().type(type);
}
/**
* @see BaseNode.Builder#weight(Integer)
*/
public static NodeAttributes weight(Integer weight) {
return new NodeAttributes().weight(weight);
}
}
public static <T extends BaseNode<T>> NodeAttributes fromNode(T n) {
return Builder.condition(n.getCondition()).type(n.getType()).weight(n.getWeight());
}
} }

View File

@ -48,70 +48,20 @@ import com.google.common.base.Objects.ToStringHelper;
* nodes. * nodes.
* *
* @author Adrian Cole * @author Adrian Cole
* @see <a href=
* "http://docs.rackspacecloud.com/loadbalancers/api/v1.0/clb-devguide/content/ch04s02.html" />
*/ */
public class NodeRequest extends BaseNode<NodeRequest> { public class NodeRequest extends BaseNode<NodeRequest> {
@SuppressWarnings("unchecked")
public static Builder builder() {
return new Builder();
}
/**
* {@inheritDoc}
*/
@Override
public Builder toBuilder() {
return new Builder().from(this);
}
public static class Builder extends BaseNode.Builder<NodeRequest> {
@Override
public NodeRequest build() {
return new NodeRequest(address, port, condition, weight);
}
@Override
public Builder address(String address) {
return Builder.class.cast(super.address(address));
}
@Override
public Builder condition(Condition condition) {
return Builder.class.cast(super.condition(condition));
}
@Override
public Builder from(NodeRequest in) {
return Builder.class.cast(super.from(in));
}
@Override
public Builder port(int port) {
return Builder.class.cast(super.port(port));
}
@Override
public Builder weight(Integer weight) {
return Builder.class.cast(super.weight(weight));
}
}
// for serialization only // for serialization only
NodeRequest() { NodeRequest() {
} }
public NodeRequest(String address, int port, Condition condition, Integer weight) { public NodeRequest(String address, int port, Condition condition, Type type, Integer weight) {
super(address, port, condition, weight); super(address, port, condition, type, weight);
} }
protected ToStringHelper string() { protected ToStringHelper string() {
return Objects.toStringHelper(this).omitNullValues() return Objects.toStringHelper(this).omitNullValues()
.add("address", address).add("port", port).add("condition", condition).add("weight", weight); .add("address", address).add("port", port).add("condition", condition).add("type", type).add("weight", weight);
} }
@Override @Override
@ -133,4 +83,69 @@ public class NodeRequest extends BaseNode<NodeRequest> {
return Objects.equal(this.address, that.address) return Objects.equal(this.address, that.address)
&& Objects.equal(this.port, that.port); && Objects.equal(this.port, that.port);
} }
public static class Builder extends BaseNode.Builder<NodeRequest> {
@Override
public NodeRequest build() {
return new NodeRequest(address, port, condition, type, weight);
}
/**
* {@inheritDoc}
*/
@Override
public Builder address(String address) {
return Builder.class.cast(super.address(address));
}
/**
* {@inheritDoc}
*/
@Override
public Builder condition(Condition condition) {
return Builder.class.cast(super.condition(condition));
}
/**
* {@inheritDoc}
*/
@Override
public Builder type(Type type) {
return Builder.class.cast(super.type(type));
}
/**
* {@inheritDoc}
*/
@Override
public Builder port(int port) {
return Builder.class.cast(super.port(port));
}
/**
* {@inheritDoc}
*/
@Override
public Builder weight(Integer weight) {
return Builder.class.cast(super.weight(weight));
}
@Override
public Builder from(NodeRequest in) {
return Builder.class.cast(super.from(in));
}
}
@SuppressWarnings("unchecked")
public static Builder builder() {
return new Builder();
}
/**
* {@inheritDoc}
*/
@Override
public Builder toBuilder() {
return new Builder().from(this);
}
} }

View File

@ -0,0 +1,152 @@
/**
* 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.domain;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
/**
* The SSL Termination feature allows a load balancer user to terminate SSL traffic at the load balancer layer versus
* at the web server layer. A user may choose to configure SSL Termination using a key and an SSL certificate or an
* (Intermediate) SSL certificate.
* <p/>
* When SSL Termination is configured on a load balancer, a secure shadow server is created that listens only for
* secure traffic on a user-specified port. This shadow server is only visible to and manageable by the system.
* Existing or updated attributes on a load balancer with SSL Termination will also apply to its shadow server.
* For example, if Connection Logging is enabled on an SSL load balancer, it will also be enabled on the shadow server
* and Cloud Files logs will contain log files for both.
* <p/>
* Notes
* <ol>
* <li>SSL Termination may only be configured on load balancers with non-secure protocols. For example, SSL Termination
* can be applied to an HTTP load balancer, but not to an HTTPS load balancer.</li>
* <li>SSL-terminated load balancers decrypt the traffic at the traffic manager and pass unencrypted traffic to the
* back-end node. Because of this, the customer's back-end nodes don't know what protocol the client requested.
* Therefore the X-Forwarded-Proto (XFP) header has been added for identifying the originating protocol of an HTTP
* request as "http" or "https" depending on what protocol the client requested.</li>
* <li>Not every service will return certificates in the proper order. Please verify that your chain of certificates
* matches that of walking up the chain from the domain to the CA root.</li>
* </ol>
*
* Warning
* <ol>
* <li>If SSL is enabled on a load balancer that is configured with nodes that are NOT in the same datacenter, then
* decrypted traffic will be sent in clear text over the public internet to the external node(s) and will no longer
* be secure.</li>
* </ol>
* @author Everett Toews
*/
public class SSLTermination {
private final boolean enabled;
private final boolean secureTrafficOnly;
private final int securePort;
protected SSLTermination(boolean enabled, boolean secureTrafficOnly, int securePort) {
this.enabled = enabled;
this.secureTrafficOnly = secureTrafficOnly;
this.securePort = securePort;
}
public boolean getEnabled() {
return this.enabled;
}
public boolean getSecureTrafficOnly() {
return this.secureTrafficOnly;
}
public int getSecurePort() {
return this.securePort;
}
@Override
public int hashCode() {
return Objects.hashCode(enabled, secureTrafficOnly, securePort);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
SSLTermination that = SSLTermination.class.cast(obj);
return Objects.equal(this.enabled, that.enabled) && Objects.equal(this.secureTrafficOnly, that.secureTrafficOnly)
&& Objects.equal(this.securePort, that.securePort);
}
protected ToStringHelper string() {
return Objects.toStringHelper(this).add("enabled", enabled).add("secureTrafficOnly", secureTrafficOnly)
.add("securePort", securePort);
}
@Override
public String toString() {
return string().toString();
}
public static class Builder {
private boolean enabled;
private boolean secureTrafficOnly;
private int securePort;
/**
* @see SSLTermination#getEnabled()
*/
public Builder enabled(boolean enabled) {
this.enabled = enabled;
return this;
}
/**
* @see SSLTermination#getSecureTrafficOnly()
*/
public Builder secureTrafficOnly(boolean secureTrafficOnly) {
this.secureTrafficOnly = secureTrafficOnly;
return this;
}
/**
* @see SSLTermination#getSecurePort()
*/
public Builder securePort(int securePort) {
this.securePort = securePort;
return this;
}
public SSLTermination build() {
return new SSLTermination(enabled, secureTrafficOnly, securePort);
}
public Builder from(SSLTermination in) {
return this.enabled(in.getEnabled()).secureTrafficOnly(in.getSecureTrafficOnly())
.securePort(in.getSecurePort());
}
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return new Builder().from(this);
}
}

View File

@ -0,0 +1,127 @@
/*
* 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.domain;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
/**
* The load balancer source IP addresses are useful for customers who are automating the deployment of infrastructure
* and need to determine the IP addresses of requests coming from our load balancers for the purpose of creating more
* robust firewall rules.
*
* @author Everett Toews
*/
public class SourceAddresses {
private final String ipv6Public;
private final String ipv4Public;
private final String ipv4Servicenet;
protected SourceAddresses(String ipv6Public, String ipv4Public, String ipv4Servicenet) {
this.ipv6Public = ipv6Public;
this.ipv4Public = ipv4Public;
this.ipv4Servicenet = ipv4Servicenet;
}
public String getIPV6Public() {
return this.ipv6Public;
}
public String getIPV4Public() {
return this.ipv4Public;
}
public String getIPV4Servicenet() {
return this.ipv4Servicenet;
}
@Override
public int hashCode() {
return Objects.hashCode(ipv6Public, ipv4Public, ipv4Servicenet);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
SourceAddresses that = SourceAddresses.class.cast(obj);
return Objects.equal(this.ipv6Public, that.ipv6Public) && Objects.equal(this.ipv4Public, that.ipv4Public)
&& Objects.equal(this.ipv4Servicenet, that.ipv4Servicenet);
}
protected ToStringHelper string() {
return Objects.toStringHelper(this).add("ipv6Public", ipv6Public).add("ipv4Public", ipv4Public)
.add("ipv4Servicenet", ipv4Servicenet);
}
@Override
public String toString() {
return string().toString();
}
public static class Builder {
private String ipv6Public;
private String ipv4Public;
private String ipv4Servicenet;
/**
* @see SourceAddresses#getIPV6Public()
*/
public Builder ipv6Public(String ipv6Public) {
this.ipv6Public = ipv6Public;
return this;
}
/**
* @see SourceAddresses#getIPV4Public()
*/
public Builder ipv4Public(String ipv4Public) {
this.ipv4Public = ipv4Public;
return this;
}
/**
* @see SourceAddresses#getIPV4Servicenet()
*/
public Builder ipv4Servicenet(String ipv4Servicenet) {
this.ipv4Servicenet = ipv4Servicenet;
return this;
}
public SourceAddresses build() {
return new SourceAddresses(ipv6Public, ipv4Public, ipv4Servicenet);
}
public Builder from(SourceAddresses in) {
return this.ipv6Public(in.getIPV6Public()).ipv4Public(in.getIPV4Public())
.ipv4Servicenet(in.getIPV4Servicenet());
}
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return new Builder().from(this);
}
}

View File

@ -30,96 +30,18 @@ import com.google.common.base.Objects.ToStringHelper;
* only within the region in which the load balancer resides. * only within the region in which the load balancer resides.
* *
* @author Adrian Cole * @author Adrian Cole
* @see <a href=
* "http://docs.rackspacecloud.com/loadbalancers/api/v1.0/clb-devguide/content/ch04s03s01.html"
* />
*/ */
public class VirtualIP implements Comparable<VirtualIP> { public class VirtualIP implements Comparable<VirtualIP> {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private int id = -1;
private String address;
private Type type;
private IPVersion ipVersion = IPVersion.IPV4;
public Builder id(int id) {
this.id = id;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
public Builder type(Type type) {
this.type = type;
return this;
}
public Builder ipVersion(IPVersion ipVersion) {
this.ipVersion = ipVersion;
return this;
}
public VirtualIP build() {
return new VirtualIP(id, address, type, ipVersion);
}
}
/**
* Virtual IP Types
*/
public static enum Type {
/**
* An address that is routable on the public Internet.
*/
PUBLIC,
/**
* An address that is routable only on ServiceNet.
*/
SERVICENET, UNRECOGNIZED;
public static Type fromValue(String type) {
try {
return valueOf(checkNotNull(type, "type"));
} catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
}
/**
* Virtual IP Versions
*/
public static enum IPVersion {
IPV4, IPV6, UNRECOGNIZED;
public static IPVersion fromValue(String ipVersion) {
try {
return valueOf(checkNotNull(ipVersion, "ipVersion"));
} catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
}
// for serialization only
VirtualIP() {
}
private int id; private int id;
private String address; private String address;
private Type type; private Type type;
private IPVersion ipVersion; private IPVersion ipVersion;
// for serialization only
VirtualIP() {
}
public VirtualIP(int id, String address, Type type, IPVersion ipVersion) { public VirtualIP(int id, String address, Type type, IPVersion ipVersion) {
checkArgument(id != -1, "id must be specified"); checkArgument(id != -1, "id must be specified");
this.id = id; this.id = id;
@ -172,4 +94,79 @@ public class VirtualIP implements Comparable<VirtualIP> {
VirtualIP that = VirtualIP.class.cast(obj); VirtualIP that = VirtualIP.class.cast(obj);
return Objects.equal(this.id, that.id); return Objects.equal(this.id, that.id);
} }
/**
* Virtual IP Types
*/
public static enum Type {
/**
* An address that is routable on the public Internet.
*/
PUBLIC,
/**
* An address that is routable only on ServiceNet.
*/
SERVICENET, UNRECOGNIZED;
public static Type fromValue(String type) {
try {
return valueOf(checkNotNull(type, "type"));
} catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
}
/**
* Virtual IP Versions
*/
public static enum IPVersion {
IPV4, IPV6, UNRECOGNIZED;
public static IPVersion fromValue(String ipVersion) {
try {
return valueOf(checkNotNull(ipVersion, "ipVersion"));
} catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
}
public static class Builder {
private int id = -1;
private String address;
private Type type;
private IPVersion ipVersion = IPVersion.IPV4;
public Builder id(int id) {
this.id = id;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
public Builder type(Type type) {
this.type = type;
return this;
}
public Builder ipVersion(IPVersion ipVersion) {
this.ipVersion = ipVersion;
return this;
}
public VirtualIP build() {
return new VirtualIP(id, address, type, ipVersion);
}
}
public static Builder builder() {
return new Builder();
}
} }

View File

@ -20,104 +20,74 @@ package org.jclouds.rackspace.cloudloadbalancers.domain.internal;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
import org.jclouds.rackspace.cloudloadbalancers.domain.AccessRule;
import org.jclouds.rackspace.cloudloadbalancers.domain.ConnectionThrottle;
import org.jclouds.rackspace.cloudloadbalancers.domain.HealthMonitor;
import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer; import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer;
import org.jclouds.rackspace.cloudloadbalancers.domain.Metadata;
import org.jclouds.rackspace.cloudloadbalancers.features.LoadBalancerApi;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
* @see <a href=
* "http://docs.rackspacecloud.com/loadbalancers/api/v1.0/clb-devguide/content/ch04s01s02.html"
* />
*/ */
public class BaseLoadBalancer<N extends BaseNode<N>, T extends BaseLoadBalancer<N, T>> implements public class BaseLoadBalancer<N extends BaseNode<N>, T extends BaseLoadBalancer<N, T>> implements
Comparable<BaseLoadBalancer<N, T>> { Comparable<BaseLoadBalancer<N, T>> {
public static <N extends BaseNode<N>, T extends BaseLoadBalancer<N, T>> Builder<N, T> builder() { private static final String ENABLED = "enabled";
return new Builder<N, T>(); private static final String PERSISTENCE_TYPE = "persistenceType";
} public static Algorithm[] WEIGHTED_ALGORITHMS = { Algorithm.WEIGHTED_LEAST_CONNECTIONS,
Algorithm.WEIGHTED_ROUND_ROBIN };
@SuppressWarnings("unchecked")
public Builder<N, T> toBuilder() {
return new Builder<N, T>().from((T) this);
}
public static class Builder<N extends BaseNode<N>, T extends BaseLoadBalancer<N, T>> {
protected String name;
protected String protocol;
protected Integer port;
protected String algorithm;
protected Set<N> nodes = Sets.newLinkedHashSet();
public Builder<N, T> name(String name) {
this.name = name;
return this;
}
public Builder<N, T> protocol(String protocol) {
this.protocol = protocol;
return this;
}
public Builder<N, T> port(Integer port) {
this.port = port;
return this;
}
public Builder<N, T> algorithm(String algorithm) {
this.algorithm = algorithm;
return this;
}
public Builder<N, T> nodes(Iterable<N> nodes) {
this.nodes = ImmutableSet.<N> copyOf(checkNotNull(nodes, "nodes"));
return this;
}
@SuppressWarnings("unchecked")
public Builder<N, T> node(N node) {
this.nodes.add((N) checkNotNull(nodes, "nodes"));
return this;
}
public BaseLoadBalancer<N, T> build() {
return new BaseLoadBalancer<N, T>(name, protocol, port, algorithm, nodes);
}
public Builder<N, T> from(T baseLoadBalancer) {
return name(baseLoadBalancer.getName()).port(baseLoadBalancer.getPort()).protocol(
baseLoadBalancer.getProtocol()).algorithm(baseLoadBalancer.getAlgorithm()).nodes(
baseLoadBalancer.getNodes());
}
}
// for serialization only
protected BaseLoadBalancer() {
}
protected String name; protected String name;
protected String protocol; protected String protocol;
protected Integer port; protected Integer port;
protected String algorithm; protected SortedSet<N> nodes = ImmutableSortedSet.of(); // so tests will come out consistently
// so tests will come out consistently protected Algorithm algorithm;
protected SortedSet<N> nodes = ImmutableSortedSet.of(); protected Integer timeout;
protected Boolean halfClosed;
protected Map<String, SessionPersistenceType> sessionPersistence;
protected Map<String, Boolean> connectionLogging;
protected ConnectionThrottle connectionThrottle;
protected HealthMonitor healthMonitor;
protected Set<AccessRule> accessList;
protected Set<Metadata> metadata;
public BaseLoadBalancer(String name, String protocol, Integer port, @Nullable String algorithm, Iterable<N> nodes) { // for serialization only
protected BaseLoadBalancer() {
}
public BaseLoadBalancer(String name, @Nullable String protocol, @Nullable Integer port, Iterable<N> nodes,
@Nullable Algorithm algorithm, @Nullable Integer timeout, @Nullable Boolean halfClosed,
@Nullable Map<String, SessionPersistenceType> sessionPersistence,
@Nullable Map<String, Boolean> connectionLogging, @Nullable ConnectionThrottle connectionThrottle,
@Nullable HealthMonitor healthMonitor, @Nullable Set<AccessRule> accessRules,
@Nullable Set<Metadata> metadata) {
this.name = checkNotNull(name, "name"); this.name = checkNotNull(name, "name");
this.protocol = protocol;// null on deleted LB this.protocol = protocol;// null on deleted LB
this.port = port;// null on deleted LB this.port = port;// null on deleted LB
this.algorithm = algorithm;// null on deleted LB
this.nodes = ImmutableSortedSet.copyOf(checkNotNull(nodes, "nodes")); this.nodes = ImmutableSortedSet.copyOf(checkNotNull(nodes, "nodes"));
this.algorithm = algorithm;// null on deleted LB
this.timeout = timeout;
this.halfClosed = halfClosed;
this.sessionPersistence = sessionPersistence;
this.connectionLogging = connectionLogging;
this.connectionThrottle = connectionThrottle;
this.healthMonitor = healthMonitor;
this.accessList = accessRules;
this.metadata = metadata;
} }
@Override @Override
@ -129,33 +99,102 @@ public class BaseLoadBalancer<N extends BaseNode<N>, T extends BaseLoadBalancer<
return name; return name;
} }
/**
* @return protocol, which may be null if the load balancer is deleted.
*/
@Nullable
public String getProtocol() { public String getProtocol() {
return protocol; return protocol;
} }
public Integer getPort() {
return port;
}
/** /**
* * @return port, which may be null if port has not been set.
* @return algorithm, which may be null if the load balancer is deleted
*/ */
@Nullable @Nullable
public String getAlgorithm() { public Integer getPort() {
return algorithm; return port;
} }
public Set<N> getNodes() { public Set<N> getNodes() {
return nodes; return nodes;
} }
protected ToStringHelper string() { /**
return Objects.toStringHelper(this).omitNullValues() * @return algorithm, which may be null if the load balancer is deleted.
.add("name", name).add("protocol", protocol).add("port", port) */
.add("algorithm", algorithm).add("nodes", nodes); @Nullable
public Algorithm getAlgorithm() {
return algorithm;
} }
/**
* @return timeout, which may be null if no timeout has been set.
*/
@Nullable
public Integer getTimeout() {
return timeout;
}
/**
* @return halfClosed, which may be null if halfClosed has not been set.
*/
@Nullable
public Boolean isHalfClosed() {
return halfClosed;
}
/**
* @return sessionPersistenceType, which may be null if sessionPersistenceType has not been set.
*/
@Nullable
public SessionPersistenceType getSessionPersistenceType() {
return sessionPersistence == null ? null : sessionPersistence.get(PERSISTENCE_TYPE);
}
public boolean isConnectionLogging() {
return connectionLogging == null ? false : connectionLogging.get(ENABLED);
}
/**
* @return connectionThrottle, which may be null if connectionThrottle has not been set.
*/
@Nullable
public ConnectionThrottle getConnectionThrottle() {
return connectionThrottle;
}
/**
* @return healthMonitor, which may be null if healthMonitor has not been set.
*/
@Nullable
public HealthMonitor getHealthMonitor() {
return healthMonitor;
}
/**
* @return accessRules, which may be null if accessRules has not been set.
*/
@Nullable
public Set<AccessRule> getAccessRules() {
return accessList;
}
/**
* @return metadata, which may be null if metadata has not been set.
*/
@Nullable
public Set<Metadata> getMetadata() {
return metadata;
}
protected ToStringHelper string() {
return Objects.toStringHelper(this).omitNullValues().add("name", name).add("protocol", protocol)
.add("port", port).add("nodes", nodes).add("timeout", timeout).add("algorithm", algorithm)
.add("timeout", timeout).add("sessionPersistenceType", getSessionPersistenceType())
.add("connectionLogging", connectionLogging).add("connectionThrottle", connectionThrottle)
.add("healthMonitor", healthMonitor).add("accessRules", accessList).add("metadata", metadata);
}
@Override @Override
public String toString() { public String toString() {
return string().toString(); return string().toString();
@ -168,10 +207,266 @@ public class BaseLoadBalancer<N extends BaseNode<N>, T extends BaseLoadBalancer<
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) return true; if (this == obj)
if (obj == null || getClass() != obj.getClass()) return false; return true;
if (obj == null || getClass() != obj.getClass())
return false;
LoadBalancer that = LoadBalancer.class.cast(obj); LoadBalancer that = LoadBalancer.class.cast(obj);
return Objects.equal(this.name, that.name); return Objects.equal(this.name, that.name);
} }
/**
* All load balancers utilize an algorithm that defines how traffic should be directed between
* back-end nodes. The default algorithm for newly created load balancers is RANDOM, which can be
* overridden at creation time or changed after the load balancer has been initially provisioned.
* The algorithm name is to be constant within a major revision of the load balancing API, though
* new algorithms may be created with a unique algorithm name within a given major revision of
* the service API.
*/
public static enum Algorithm {
/**
* The node with the lowest number of connections will receive requests.
*/
LEAST_CONNECTIONS,
/**
* Back-end servers are selected at random.
*/
RANDOM,
/**
* Connections are routed to each of the back-end servers in turn.
*/
ROUND_ROBIN,
/**
* Each request will be assigned to a node based on the number of concurrent connections to
* the node and its weight.
*/
WEIGHTED_LEAST_CONNECTIONS,
/**
* A round robin algorithm, but with different proportions of traffic being directed to the
* back-end nodes. Weights must be defined as part of the load balancer's node configuration.
*/
WEIGHTED_ROUND_ROBIN, UNRECOGNIZED;
public static Algorithm fromValue(String algorithm) {
try {
return valueOf(checkNotNull(algorithm, "algorithm"));
}
catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
}
/**
* Session persistence is a feature of the load balancing service that forces multiple requests from clients to be
* directed to the same node. This is common with many web applications that do not inherently share application
* state between back-end servers.
*/
public static enum SessionPersistenceType {
/**
* A session persistence mechanism that inserts an HTTP cookie and is used to determine the destination back-end
* node. This is supported for HTTP load balancing only.
*/
HTTP_COOKIE,
/**
* A session persistence mechanism that will keep track of the source IP address that is mapped and is able to
* determine the destination back-end node. This is supported for HTTPS pass-through and non-HTTP load balancing
* only.
*/
SOURCE_IP,
UNRECOGNIZED;
public static SessionPersistenceType fromValue(String sessionPersistenceType) {
try {
return valueOf(checkNotNull(sessionPersistenceType, "sessionPersistenceType"));
}
catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
}
public static class Builder<N extends BaseNode<N>, T extends BaseLoadBalancer<N, T>> {
protected String name;
protected String protocol;
protected Integer port;
protected Set<N> nodes = Sets.newLinkedHashSet();
protected Algorithm algorithm;
protected Integer timeout;
protected Boolean halfClosed;
protected Map<String, SessionPersistenceType> sessionPersistence;
protected Map<String, Boolean> connectionLogging;
protected ConnectionThrottle connectionThrottle;
protected HealthMonitor healthMonitor;
protected Set<AccessRule> accessRules;
protected Set<Metadata> metadata;
/**
* Required. Name of the load balancer to create. The name must be 128 characters or less in length, and all
* UTF-8 characters are valid.
*/
public Builder<N, T> name(String name) {
this.name = checkNotNull(name, "name");
return this;
}
/**
* Required. Protocol of the service which is being load balanced.
*
* @see LoadBalancerApi#listProtocols()
*/
public Builder<N, T> protocol(String protocol) {
this.protocol = protocol;
return this;
}
/**
* Required if the protocol being used is not in LoadBalancerApi#listProtocols() or the protocol is in
* LoadBalancerApi#listProtocols() but port=0. Port number for the service you are load balancing.
*/
public Builder<N, T> port(@Nullable Integer port) {
this.port = port;
return this;
}
/**
* Required. Nodes to be added to the load balancer.
*/
public Builder<N, T> nodes(Iterable<N> nodes) {
this.nodes = ImmutableSet.<N> copyOf(checkNotNull(nodes, "nodes"));
return this;
}
@SuppressWarnings("unchecked")
public Builder<N, T> node(N node) {
this.nodes.add((N) checkNotNull(nodes, "nodes"));
return this;
}
/**
* Algorithm that defines how traffic should be directed between back-end nodes.
*
* @see Algorithm
*/
public Builder<N, T> algorithm(@Nullable Algorithm algorithm) {
this.algorithm = algorithm;
return this;
}
/**
* The timeout value for the load balancer and communications with its nodes. Defaults to 30 seconds with
* a maximum of 120 seconds.
*/
public Builder<N, T> timeout(@Nullable Integer timeout) {
this.timeout = timeout;
return this;
}
/**
* Enable or Disable Half-Closed support for the load balancer. Half-Closed support provides the ability
* for one end of the connection to terminate its output, while still receiving data from the other end.
* Only available for TCP/TCP_CLIENT_FIRST protocols.
*/
public Builder<N, T> halfClosed(@Nullable Boolean halfClosed) {
this.halfClosed = halfClosed;
return this;
}
/**
* Specifies whether multiple requests from clients are directed to the same node.
*
* @see SessionPersistenceType
*/
public Builder<N, T> sessionPersistenceType(@Nullable SessionPersistenceType sessionPersistenceType) {
if (sessionPersistenceType != null) {
this.sessionPersistence = Maps.newHashMap();
this.sessionPersistence.put(PERSISTENCE_TYPE, sessionPersistenceType);
}
else {
this.sessionPersistence = null;
}
return this;
}
/**
* Current connection logging configuration.
*/
public Builder<N, T> connectionLogging(@Nullable Boolean connectionLogging) {
if (connectionLogging != null) {
this.connectionLogging = Maps.newHashMap();
this.connectionLogging.put(ENABLED, connectionLogging);
}
else {
this.connectionLogging = null;
}
return this;
}
/**
* Specifies limits on the number of connections per IP address to help mitigate malicious or abusive
* traffic to your applications.
*
* @see ConnectionThrottle
*/
public Builder<N, T> connectionThrottle(@Nullable ConnectionThrottle connectionThrottle) {
this.connectionThrottle = connectionThrottle;
return this;
}
/**
* The type of health monitor check to perform to ensure that the service is performing properly.
*
* @see HealthMonitor
*/
public Builder<N, T> healthMonitor(@Nullable HealthMonitor healthMonitor) {
this.healthMonitor = healthMonitor;
return this;
}
/**
* The access list management feature allows fine-grained network access controls to be applied to the load
* balancer's virtual IP address.
*
* @see AccessRule
*/
public Builder<N, T> accessRules(@Nullable Set<AccessRule> accessRules) {
this.accessRules = accessRules;
return this;
}
/**
* Information (metadata) that can be associated with each load balancer for the client's personal use.
*/
public Builder<N, T> metadata(@Nullable Set<Metadata> metadata) {
this.metadata = metadata;
return this;
}
public BaseLoadBalancer<N, T> build() {
return new BaseLoadBalancer<N, T>(name, protocol, port, nodes, algorithm, timeout, halfClosed,
sessionPersistence, connectionLogging, connectionThrottle, healthMonitor, accessRules, metadata);
}
public Builder<N, T> from(T baseLB) {
return name(baseLB.getName()).protocol(baseLB.getProtocol()).port(baseLB.getPort())
.algorithm(baseLB.getAlgorithm()).timeout(baseLB.getTimeout()).halfClosed(baseLB.isHalfClosed())
.nodes(baseLB.getNodes()).sessionPersistenceType(baseLB.getSessionPersistenceType())
.connectionLogging(baseLB.isConnectionLogging()).connectionThrottle(baseLB.getConnectionThrottle())
.healthMonitor(baseLB.getHealthMonitor()).accessRules(baseLB.getAccessRules())
.metadata(baseLB.getMetadata());
}
}
public static <N extends BaseNode<N>, T extends BaseLoadBalancer<N, T>> Builder<N, T> builder() {
return new Builder<N, T>();
}
@SuppressWarnings("unchecked")
public Builder<N, T> toBuilder() {
return new Builder<N, T>().from((T) this);
}
} }

View File

@ -21,6 +21,8 @@ package org.jclouds.rackspace.cloudloadbalancers.domain.internal;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.rackspace.cloudloadbalancers.domain.internal.BaseLoadBalancer.Algorithm;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Objects.ToStringHelper;
@ -49,53 +51,81 @@ import com.google.common.base.Objects.ToStringHelper;
* nodes. * nodes.
* *
* @author Adrian Cole * @author Adrian Cole
* @see <a href=
* "http://docs.rackspacecloud.com/loadbalancers/api/v1.0/clb-devguide/content/ch04s02.html" />
*/ */
public class BaseNode<T extends BaseNode<T>> implements Comparable<BaseNode<T>> { public class BaseNode<T extends BaseNode<T>> implements Comparable<BaseNode<T>> {
public static <T extends BaseNode<T>> Builder<T> builder() { protected String address;
return new Builder<T>(); protected int port;
protected Condition condition;
protected Type type;
protected Integer weight;
// for serialization only
protected BaseNode() {
} }
@SuppressWarnings("unchecked") public BaseNode(String address, int port, Condition condition, Type type, Integer weight) {
public Builder<T> toBuilder() { this.address = checkNotNull(address, "address");
return new Builder<T>().from((T) this); checkArgument(port != -1, "port must be specified");
this.port = port;
this.condition = checkNotNull(condition, "condition");
this.type = type;
this.weight = weight;
} }
public static class Builder<T extends BaseNode<T>> { public String getAddress() {
protected String address; return address;
protected int port = -1; }
protected Condition condition = Condition.ENABLED;
protected Integer weight;
public Builder<T> address(String address) { public int getPort() {
this.address = address; return port;
return this; }
}
public Builder<T> port(int port) { public Condition getCondition() {
this.port = port; return condition;
return this; }
}
public Builder<T> condition(Condition condition) { public Type getType() {
this.condition = condition; return type;
return this; }
}
public Builder<T> weight(Integer weight) { /**
this.weight = weight; * the maximum weight of a node is 100.
return this; */
} public Integer getWeight() {
return weight;
}
public BaseNode<T> build() { @Override
return new BaseNode<T>(address, port, condition, weight); public int compareTo(BaseNode<T> arg0) {
} return address.compareTo(arg0.address);
}
public Builder<T> from(T in) { protected ToStringHelper string() {
return address(in.getAddress()).port(in.getPort()).condition(in.getCondition()).weight(in.getWeight()); return Objects.toStringHelper(this).omitNullValues().add("address", address).add("port", port)
} .add("condition", condition).add("type", type).add("weight", weight);
}
@Override
public String toString() {
return string().toString();
}
@Override
public int hashCode() {
return Objects.hashCode(address, port, condition);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
BaseNode<?> that = BaseNode.class.cast(obj);
return Objects.equal(this.address, that.address) && Objects.equal(this.port, that.port)
&& Objects.equal(this.condition, that.condition);
} }
/** /**
@ -122,78 +152,112 @@ public class BaseNode<T extends BaseNode<T>> implements Comparable<BaseNode<T>>
public static Condition fromValue(String condition) { public static Condition fromValue(String condition) {
try { try {
return valueOf(checkNotNull(condition, "condition")); return valueOf(checkNotNull(condition, "condition"));
} catch (IllegalArgumentException e) { }
catch (IllegalArgumentException e) {
return UNRECOGNIZED; return UNRECOGNIZED;
} }
} }
} }
protected String address;
protected int port;
protected Condition condition;
protected Integer weight;
// for serialization only
protected BaseNode() {
}
public BaseNode(String address, int port, Condition condition, Integer weight) {
this.address = checkNotNull(address, "address");
checkArgument(port != -1, "port must be specified");
this.port = port;
this.condition = checkNotNull(condition, "condition");
this.weight = weight;
}
public String getAddress() {
return address;
}
public int getPort() {
return port;
}
public Condition getCondition() {
return condition;
}
/** /**
* the maximum weight of a node is 100. * Type of node.
*/ */
public Integer getWeight() { public static enum Type {
return weight; /**
* Nodes defined as PRIMARY are in the normal rotation to receive traffic from the load balancer.
*/
PRIMARY,
/**
* Nodes defined as SECONDARY are only in the rotation to receive traffic from the load balancer when all the
* primary nodes fail. This provides a failover feature that automatically routes traffic to the secondary node
* in the event that the primary node is disabled or in a failing state. Note that active health monitoring must
* be enabled on the load balancer to enable the failover feature to the secondary node.
*/
SECONDARY,
UNRECOGNIZED;
public static Type fromValue(String type) {
try {
return valueOf(checkNotNull(type, "type"));
}
catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
} }
@Override public static class Builder<T extends BaseNode<T>> {
public int compareTo(BaseNode<T> arg0) { protected String address;
return address.compareTo(arg0.address); protected int port = -1;
protected Condition condition = Condition.ENABLED;
protected Type type;
protected Integer weight;
/**
* Required. IP address or domain name for the node.
*/
public Builder<T> address(String address) {
this.address = address;
return this;
}
/**
* Required. Port number for the service you are load balancing.
*/
public Builder<T> port(int port) {
this.port = port;
return this;
}
/**
* Required. Condition for the node, which determines its role within the load balancer.
*
* @see Condition
*/
public Builder<T> condition(Condition condition) {
this.condition = condition;
return this;
}
/**
* Type of node to add.
*
* @see Type
*/
public Builder<T> type(Type type) {
this.type = type;
return this;
}
/**
* Weight of node to add. If the {@link Algorithm#WEIGHTED_ROUND_ROBIN} load balancer algorithm mode is
* selected, then the user should assign the relevant weight to the node using the weight attribute for
* the node. Must be an integer from 1 to 100.
*/
public Builder<T> weight(Integer weight) {
this.weight = weight;
return this;
}
public BaseNode<T> build() {
return new BaseNode<T>(address, port, condition, type, weight);
}
public Builder<T> from(T in) {
return address(in.getAddress()).port(in.getPort()).condition(in.getCondition()).type(in.getType())
.weight(in.getWeight());
}
} }
protected ToStringHelper string() { public static <T extends BaseNode<T>> Builder<T> builder() {
return Objects.toStringHelper(this).omitNullValues() return new Builder<T>();
.add("address", address).add("port", port).add("condition", condition).add("weight", weight);
}
@Override
public String toString() {
return string().toString();
} }
@Override @SuppressWarnings("unchecked")
public int hashCode() { public Builder<T> toBuilder() {
return Objects.hashCode(address, port, condition); return new Builder<T>().from((T) this);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
BaseNode<?> that = BaseNode.class.cast(obj);
return Objects.equal(this.address, that.address)
&& Objects.equal(this.port, that.port)
&& Objects.equal(this.condition, that.condition);
} }
} }

View File

@ -51,21 +51,29 @@ public class ConvertLB implements Function<LB, LoadBalancer> {
@Override @Override
public LoadBalancer apply(LB lb) { public LoadBalancer apply(LB lb) {
try { try {
Builder builder = LoadBalancer.builder().region(region).name(lb.getName()).port(lb.getPort()) Builder builder = LoadBalancer.builder().id(lb.id).region(region).status(lb.status).name(lb.getName())
.protocol(lb.getProtocol()).algorithm(lb.getAlgorithm()).nodes(lb.getNodes()).id(lb.id) .protocol(lb.getProtocol()).port(lb.getPort()).nodeCount(lb.nodeCount).nodes(lb.getNodes())
.status(lb.status).virtualIPs(lb.virtualIps).nodeCount(lb.nodeCount); .timeout(lb.getTimeout()).algorithm(lb.getAlgorithm()).halfClosed(lb.isHalfClosed())
.sessionPersistenceType(lb.getSessionPersistenceType()).connectionLogging(lb.isConnectionLogging())
.connectionThrottle(lb.getConnectionThrottle()).healthMonitor(lb.getHealthMonitor())
.accessRules(lb.getAccessRules()).metadata(lb.getMetadata()).virtualIPs(lb.virtualIps);
if (lb.cluster.size() == 1) if (lb.cluster.size() == 1)
builder.clusterName(Iterables.get(lb.cluster.values(), 0)); builder.clusterName(Iterables.get(lb.cluster.values(), 0));
if (lb.sessionPersistence.size() == 1)
builder.sessionPersistenceType(Iterables.get(lb.sessionPersistence.values(), 0));
if (lb.created.size() == 1) if (lb.created.size() == 1)
builder.created(Iterables.get(lb.created.values(), 0)); builder.created(Iterables.get(lb.created.values(), 0));
if (lb.updated.size() == 1) if (lb.updated.size() == 1)
builder.updated(Iterables.get(lb.updated.values(), 0)); builder.updated(Iterables.get(lb.updated.values(), 0));
if (lb.connectionLogging.size() == 1) if (lb.contentCaching.size() == 1)
builder.connectionLoggingEnabled(Iterables.get(lb.connectionLogging.values(), 0)); builder.contentCaching(Iterables.get(lb.contentCaching.values(), 0));
if (lb.sslTermination != null)
builder.sslTermination(lb.sslTermination);
if (lb.sourceAddresses != null)
builder.sourceAddresses(lb.sourceAddresses);
return builder.build(); return builder.build();
} catch (NullPointerException e) { }
catch (NullPointerException e) {
logger.warn(e, "nullpointer found parsing %s", lb); logger.warn(e, "nullpointer found parsing %s", lb);
throw e; throw e;
} }

View File

@ -22,9 +22,11 @@ import java.util.Date;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.jclouds.rackspace.cloudloadbalancers.domain.Node;
import org.jclouds.rackspace.cloudloadbalancers.domain.VirtualIP;
import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer.Status; import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer.Status;
import org.jclouds.rackspace.cloudloadbalancers.domain.Node;
import org.jclouds.rackspace.cloudloadbalancers.domain.SSLTermination;
import org.jclouds.rackspace.cloudloadbalancers.domain.SourceAddresses;
import org.jclouds.rackspace.cloudloadbalancers.domain.VirtualIP;
import org.jclouds.rackspace.cloudloadbalancers.domain.internal.BaseLoadBalancer; import org.jclouds.rackspace.cloudloadbalancers.domain.internal.BaseLoadBalancer;
import com.google.common.base.Objects; import com.google.common.base.Objects;
@ -33,17 +35,18 @@ import com.google.common.collect.Sets;
/** /**
* Only here as the datatype for cloudloadbalancers is awkward. * Only here as the datatype for cloudloadbalancers is awkward.
**/ */
class LB extends BaseLoadBalancer<Node, LB> { class LB extends BaseLoadBalancer<Node, LB> {
int id; int id;
int nodeCount; int nodeCount;
Status status; Status status;
Set<VirtualIP> virtualIps = Sets.newLinkedHashSet(); Set<VirtualIP> virtualIps = Sets.newLinkedHashSet();
Map<String, String> sessionPersistence = Maps.newLinkedHashMap();
Map<String, String> cluster = Maps.newLinkedHashMap(); Map<String, String> cluster = Maps.newLinkedHashMap();
Map<String, Date> created = Maps.newLinkedHashMap(); Map<String, Date> created = Maps.newLinkedHashMap();
Map<String, Date> updated = Maps.newLinkedHashMap(); Map<String, Date> updated = Maps.newLinkedHashMap();
Map<String, Boolean> connectionLogging = Maps.newLinkedHashMap(); Map<String, Boolean> contentCaching = Maps.newLinkedHashMap();
SSLTermination sslTermination;
SourceAddresses sourceAddresses;
@Override @Override
public int hashCode() { public int hashCode() {

View File

@ -102,7 +102,7 @@ public class LoadBalancerApiExpectTest extends BaseCloudLoadBalancerApiExpectTes
.name("sample-loadbalancer") .name("sample-loadbalancer")
.protocol("HTTP") .protocol("HTTP")
.port(80) .port(80)
.algorithm(LoadBalancer.Algorithm.RANDOM.name()) .algorithm(LoadBalancer.Algorithm.RANDOM)
.virtualIPType(VirtualIP.Type.PUBLIC) .virtualIPType(VirtualIP.Type.PUBLIC)
.nodes(nodeRequests) .nodes(nodeRequests)
.build(); .build();
@ -125,7 +125,7 @@ public class LoadBalancerApiExpectTest extends BaseCloudLoadBalancerApiExpectTes
.name("foo") .name("foo")
.protocol("HTTPS") .protocol("HTTPS")
.port(443) .port(443)
.algorithm(LoadBalancer.Algorithm.RANDOM.name()); .algorithm(LoadBalancer.Algorithm.RANDOM);
api.update(2000, lbAttrs); api.update(2000, lbAttrs);
} }

View File

@ -151,7 +151,7 @@ public class LoadBalancerApiLiveTest extends BaseCloudLoadBalancersApiLiveTest {
assertEquals(lb.getRegion(), region); assertEquals(lb.getRegion(), region);
assertEquals(lb.getName(), name); assertEquals(lb.getName(), name);
assertEquals(lb.getProtocol(), "HTTP"); assertEquals(lb.getProtocol(), "HTTP");
assertEquals(lb.getPort(), Integer.valueOf(80)); assertEquals(lb.getPort(), new Integer(80));
assertEquals(Iterables.get(lb.getVirtualIPs(), 0).getType(), Type.PUBLIC); assertEquals(Iterables.get(lb.getVirtualIPs(), 0).getType(), Type.PUBLIC);
} }

View File

@ -91,6 +91,7 @@ public class NodeApiExpectTest extends BaseCloudLoadBalancerApiExpectTest<CloudL
NodeRequest nodeRequest2 = NodeRequest.builder() NodeRequest nodeRequest2 = NodeRequest.builder()
.address("10.1.1.2") .address("10.1.1.2")
.condition(NodeRequest.Condition.ENABLED) .condition(NodeRequest.Condition.ENABLED)
.type(Node.Type.SECONDARY)
.port(80) .port(80)
.weight(8) .weight(8)
.build(); .build();
@ -119,6 +120,7 @@ public class NodeApiExpectTest extends BaseCloudLoadBalancerApiExpectTest<CloudL
NodeAttributes nodeAttributes = NodeAttributes.Builder NodeAttributes nodeAttributes = NodeAttributes.Builder
.condition(NodeRequest.Condition.DISABLED) .condition(NodeRequest.Condition.DISABLED)
.type(NodeRequest.Type.SECONDARY)
.weight(20); .weight(20);
api.update(410, nodeAttributes); api.update(410, nodeAttributes);
@ -156,6 +158,7 @@ public class NodeApiExpectTest extends BaseCloudLoadBalancerApiExpectTest<CloudL
.address("10.1.1.1") .address("10.1.1.1")
.port(80) .port(80)
.condition(Node.Condition.ENABLED) .condition(Node.Condition.ENABLED)
.type(Node.Type.PRIMARY)
.status(Node.Status.ONLINE) .status(Node.Status.ONLINE)
.weight(3) .weight(3)
.build(); .build();
@ -165,6 +168,7 @@ public class NodeApiExpectTest extends BaseCloudLoadBalancerApiExpectTest<CloudL
.address("10.1.1.2") .address("10.1.1.2")
.port(80) .port(80)
.condition(Node.Condition.ENABLED) .condition(Node.Condition.ENABLED)
.type(Node.Type.SECONDARY)
.status(Node.Status.ONLINE) .status(Node.Status.ONLINE)
.weight(8) .weight(8)
.build(); .build();
@ -174,6 +178,7 @@ public class NodeApiExpectTest extends BaseCloudLoadBalancerApiExpectTest<CloudL
.address("10.1.1.3") .address("10.1.1.3")
.port(80) .port(80)
.condition(Node.Condition.DISABLED) .condition(Node.Condition.DISABLED)
.type(Node.Type.PRIMARY)
.status(Node.Status.ONLINE) .status(Node.Status.ONLINE)
.weight(12) .weight(12)
.build(); .build();
@ -187,6 +192,7 @@ public class NodeApiExpectTest extends BaseCloudLoadBalancerApiExpectTest<CloudL
.address("10.1.1.1") .address("10.1.1.1")
.port(80) .port(80)
.condition(Node.Condition.ENABLED) .condition(Node.Condition.ENABLED)
.type(Node.Type.PRIMARY)
.status(Node.Status.ONLINE) .status(Node.Status.ONLINE)
.weight(12) .weight(12)
.build(); .build();

View File

@ -114,7 +114,7 @@ public class NodeApiLiveTest extends BaseCloudLoadBalancersApiLiveTest {
assert n.getAddress() != null : n; assert n.getAddress() != null : n;
assert n.getPort() != -1 : n; assert n.getPort() != -1 : n;
assert n.getStatus() != null : n; assert n.getStatus() != null : n;
assert !Arrays.asList(LoadBalancer.WEIGHTED_ALGORITHMS).contains(lb.getTypedAlgorithm()) assert !Arrays.asList(LoadBalancer.WEIGHTED_ALGORITHMS).contains(lb.getAlgorithm())
|| n.getWeight() != null : n; || n.getWeight() != null : n;
Node getDetails = clbApi.getNodeApiForZoneAndLoadBalancer(lb.getRegion(), lb.getId()).get(n.getId()); Node getDetails = clbApi.getNodeApiForZoneAndLoadBalancer(lb.getRegion(), lb.getId()).get(n.getId());
@ -125,7 +125,7 @@ public class NodeApiLiveTest extends BaseCloudLoadBalancersApiLiveTest {
assertEquals(getDetails.getAddress(), n.getAddress()); assertEquals(getDetails.getAddress(), n.getAddress());
assertEquals(getDetails.getPort(), n.getPort()); assertEquals(getDetails.getPort(), n.getPort());
assertEquals(getDetails.getStatus(), n.getStatus()); assertEquals(getDetails.getStatus(), n.getStatus());
if (Arrays.asList(LoadBalancer.WEIGHTED_ALGORITHMS).contains(lb.getTypedAlgorithm())) { if (Arrays.asList(LoadBalancer.WEIGHTED_ALGORITHMS).contains(lb.getAlgorithm())) {
assertEquals(getDetails.getWeight(), n.getWeight()); assertEquals(getDetails.getWeight(), n.getWeight());
} }
} catch (AssertionError e) { } catch (AssertionError e) {

View File

@ -21,13 +21,20 @@ package org.jclouds.rackspace.cloudloadbalancers.functions;
import org.jclouds.date.internal.SimpleDateFormatDateService; import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.json.BaseItemParserTest; import org.jclouds.json.BaseItemParserTest;
import org.jclouds.rackspace.cloudloadbalancers.domain.AccessRule;
import org.jclouds.rackspace.cloudloadbalancers.domain.ConnectionThrottle;
import org.jclouds.rackspace.cloudloadbalancers.domain.HealthMonitor;
import org.jclouds.rackspace.cloudloadbalancers.domain.HealthMonitor.Type;
import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer; import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer;
import org.jclouds.rackspace.cloudloadbalancers.domain.Node;
import org.jclouds.rackspace.cloudloadbalancers.domain.VirtualIP;
import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer.Status; import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer.Status;
import org.jclouds.rackspace.cloudloadbalancers.domain.Metadata;
import org.jclouds.rackspace.cloudloadbalancers.domain.Node;
import org.jclouds.rackspace.cloudloadbalancers.domain.SSLTermination;
import org.jclouds.rackspace.cloudloadbalancers.domain.SourceAddresses;
import org.jclouds.rackspace.cloudloadbalancers.domain.VirtualIP;
import org.jclouds.rackspace.cloudloadbalancers.domain.VirtualIP.IPVersion; import org.jclouds.rackspace.cloudloadbalancers.domain.VirtualIP.IPVersion;
import org.jclouds.rackspace.cloudloadbalancers.functions.ConvertLB; import org.jclouds.rackspace.cloudloadbalancers.domain.internal.BaseLoadBalancer.Algorithm;
import org.jclouds.rackspace.cloudloadbalancers.functions.ParseLoadBalancer; import org.jclouds.rackspace.cloudloadbalancers.domain.internal.BaseLoadBalancer.SessionPersistenceType;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -57,19 +64,32 @@ public class ParseLoadBalancerTest extends BaseItemParserTest<LoadBalancer> {
.name("sample-loadbalancer") .name("sample-loadbalancer")
.protocol("HTTP") .protocol("HTTP")
.port(80) .port(80)
.algorithm("RANDOM") .algorithm(Algorithm.RANDOM)
.status(Status.ACTIVE) .status(Status.ACTIVE)
.connectionLoggingEnabled(true) .connectionLogging(true)
.contentCaching(true)
.nodeCount(2) .nodeCount(2)
.halfClosed(false)
.healthMonitor(HealthMonitor.builder().type(Type.CONNECT).delay(10).timeout(5).attemptsBeforeDeactivation(2).build())
.sslTermination(SSLTermination.builder().enabled(true).secureTrafficOnly(false).securePort(443).build())
.sourceAddresses(SourceAddresses.builder().ipv6Public("2001:4800:7901::5/64").ipv4Public("174.143.139.137").ipv4Servicenet("10.183.250.137").build())
.connectionThrottle(ConnectionThrottle.builder().maxConnections(100).minConnections(10).maxConnectionRate(50).rateInterval(60).build())
.accessRules(ImmutableSet.of(
AccessRule.builder().id(22215).type(AccessRule.Type.DENY).address("1.2.3.4/32").build(),
AccessRule.builder().id(22217).type(AccessRule.Type.ALLOW).address("12.0.0.0/8").build()))
.virtualIPs(ImmutableSet.of( .virtualIPs(ImmutableSet.of(
VirtualIP.builder().id(1000).address("206.10.10.210").type(VirtualIP.Type.PUBLIC).ipVersion(IPVersion.IPV4).build())) VirtualIP.builder().id(1000).address("206.10.10.210").type(VirtualIP.Type.PUBLIC).ipVersion(IPVersion.IPV4).build(),
VirtualIP.builder().id(1001).address("2001:4800:7901:0000:9a32:3c2a:0000:0001").type(VirtualIP.Type.PUBLIC).ipVersion(IPVersion.IPV6).build()))
.nodes(ImmutableSet.of( .nodes(ImmutableSet.of(
Node.builder().id(1041).address("10.1.1.1").port(80).condition(Node.Condition.ENABLED).status(Node.Status.ONLINE).build(), Node.builder().id(1041).address("10.1.1.1").port(80).condition(Node.Condition.ENABLED).status(Node.Status.ONLINE).build(),
Node.builder().id(1411).address("10.1.1.2").port(80).condition(Node.Condition.ENABLED).status(Node.Status.ONLINE).build())) Node.builder().id(1411).address("10.1.1.2").port(80).condition(Node.Condition.ENABLED).status(Node.Status.ONLINE).build()))
.sessionPersistenceType("HTTP_COOKIE") .sessionPersistenceType(SessionPersistenceType.HTTP_COOKIE)
.clusterName("c1.dfw1") .clusterName("c1.dfw1")
.created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2010-11-30T03:23:42Z")) .created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2010-11-30T03:23:42Z"))
.updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2010-11-30T03:23:44Z")).build(); .updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2010-11-30T03:23:44Z"))
.metadata(ImmutableSet.<Metadata> of(
Metadata.builder().id(1).key("color").value("red").build(),
Metadata.builder().id(2).key("label").value("web-load-balancer").build())).build();
} }
// add factory binding as this is not default // add factory binding as this is not default

View File

@ -27,6 +27,7 @@ import org.jclouds.http.HttpResponse;
import org.jclouds.json.BaseIterableWithMarkerParserTest; import org.jclouds.json.BaseIterableWithMarkerParserTest;
import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer; import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer;
import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer.Status; import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer.Status;
import org.jclouds.rackspace.cloudloadbalancers.domain.internal.BaseLoadBalancer.Algorithm;
import org.jclouds.rackspace.cloudloadbalancers.domain.VirtualIP; import org.jclouds.rackspace.cloudloadbalancers.domain.VirtualIP;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -52,7 +53,7 @@ public class ParseLoadBalancersTest extends BaseIterableWithMarkerParserTest<Loa
.id(71) .id(71)
.protocol("HTTP") .protocol("HTTP")
.port(80) .port(80)
.algorithm("RANDOM") .algorithm(Algorithm.RANDOM)
.status(Status.ACTIVE) .status(Status.ACTIVE)
.nodeCount(1) .nodeCount(1)
.virtualIPs(ImmutableSet.of( .virtualIPs(ImmutableSet.of(
@ -67,7 +68,7 @@ public class ParseLoadBalancersTest extends BaseIterableWithMarkerParserTest<Loa
.id(166) .id(166)
.protocol("HTTP") .protocol("HTTP")
.port(80) .port(80)
.algorithm("RANDOM") .algorithm(Algorithm.RANDOM)
.status(Status.ACTIVE) .status(Status.ACTIVE)
.nodeCount(1) .nodeCount(1)
.virtualIPs(ImmutableSet.of( .virtualIPs(ImmutableSet.of(

View File

@ -1,25 +1 @@
{ {"loadBalancer":{"virtualIps":[{"type":"PUBLIC"}],"name":"sample-loadbalancer","protocol":"HTTP","port":80,"algorithm":"RANDOM","nodes":[{"address":"10.1.1.1","port":80,"condition":"ENABLED"},{"address":"10.1.1.2","port":80,"condition":"ENABLED"}]}}
"loadBalancer": {
"virtualIps": [
{
"type": "PUBLIC"
}
],
"name": "sample-loadbalancer",
"protocol": "HTTP",
"port": 80,
"algorithm": "RANDOM",
"nodes": [
{
"address": "10.1.1.1",
"port": 80,
"condition": "ENABLED"
},
{
"address": "10.1.1.2",
"port": 80,
"condition": "ENABLED"
}
]
}
}

View File

@ -1,55 +1,105 @@
{ {
"loadBalancer":{ "loadBalancer": {
"id": 2000, "id": 2000,
"name":"sample-loadbalancer", "name": "sample-loadbalancer",
"protocol":"HTTP", "protocol": "HTTP",
"port": 80, "port": 80,
"algorithm":"RANDOM", "algorithm": "RANDOM",
"status":"ACTIVE", "status": "ACTIVE",
"connectionLogging":{ "cluster": {
"enabled":"true" "name": "c1.dfw1"
}, },
"virtualIps":[ "nodes": [
{
"id": 1000,
"address":"206.10.10.210",
"type":"PUBLIC",
"ipVersion":"IPV4"
}
],
"nodes":[
{ {
"id": 1041, "id": 1041,
"address":"10.1.1.1", "address": "10.1.1.1",
"port": 80, "port": 80,
"condition":"ENABLED", "condition": "ENABLED",
"status":"ONLINE" "status": "ONLINE"
}, },
{ {
"id": 1411, "id": 1411,
"address":"10.1.1.2", "address": "10.1.1.2",
"port": 80, "port": 80,
"condition":"ENABLED", "condition": "ENABLED",
"status":"ONLINE" "status": "ONLINE"
} }
], ],
"sessionPersistence":{ "created": {
"persistenceType":"HTTP_COOKIE" "time": "2010-11-30T03:23:42Z"
}, },
"connectionThrottle":{ "healthMonitor": {
"type": "CONNECT",
"delay": 10,
"timeout": 5,
"attemptsBeforeDeactivation": 2
},
"sslTermination": {
"enabled": true,
"secureTrafficOnly": false,
"securePort": 443
},
"sessionPersistence": {
"persistenceType": "HTTP_COOKIE"
},
"virtualIps": [
{
"id": 1000,
"address": "206.10.10.210",
"type": "PUBLIC",
"ipVersion": "IPV4"
},
{
"id": 1001,
"address": "2001:4800:7901:0000:9a32:3c2a:0000:0001",
"type": "PUBLIC",
"ipVersion": "IPV6"
}
],
"sourceAddresses": {
"ipv6Public": "2001:4800:7901::5/64",
"ipv4Servicenet": "10.183.250.137",
"ipv4Public": "174.143.139.137"
},
"updated": {
"time": "2010-11-30T03:23:44Z"
},
"halfClosed": false,
"accessList": [
{
"address": "1.2.3.4/32",
"id": 22215,
"type": "DENY"
},
{
"address": "12.0.0.0/8",
"id": 22217,
"type": "ALLOW"
}
],
"connectionThrottle": {
"minConnections": 10, "minConnections": 10,
"maxConnections": 100, "maxConnections": 100,
"maxConnectionRate": 50, "maxConnectionRate": 50,
"rateInterval": 60 "rateInterval": 60
}, },
"cluster":{ "connectionLogging": {
"name":"c1.dfw1" "enabled": true
}, },
"created":{ "contentCaching": {
"time":"2010-11-30T03:23:42Z" "enabled": true
}, },
"updated":{ "metadata": [
"time":"2010-11-30T03:23:44Z" {
} "id": 1,
"key": "color",
"value": "red"
},
{
"id": 2,
"key": "label",
"value": "web-load-balancer"
}
]
} }
} }

View File

@ -1,8 +1 @@
{ {"loadBalancer":{"name":"foo","protocol":"HTTPS","port":443,"algorithm":"RANDOM"}}
"loadBalancer": {
"name": "foo",
"protocol": "HTTPS",
"port": 443,
"algorithm": "RANDOM"
}
}

View File

@ -1,11 +1,23 @@
{"node": { {
"id":410, "node": {
"address":"10.1.1.1", "id": 410,
"port":80, "address": "10.1.1.1",
"condition":"ENABLED", "port": 80,
"status":"ONLINE", "condition": "ENABLED",
"weight":12, "status": "ONLINE",
"type":"PRIMARY", "weight": 12,
"metadata":[] "type": "PRIMARY",
"metadata": [
{
"id": 1,
"key": "color",
"value": "red"
},
{
"id": 2,
"key": "label",
"value": "web-load-balancer"
}
]
} }
} }

View File

@ -1 +1 @@
{"node":{"condition":"DISABLED","weight":20}} {"node":{"condition":"DISABLED","type":"SECONDARY","weight":20}}

View File

@ -1 +1 @@
{"nodes":[{"address":"10.1.1.1","port":80,"condition":"ENABLED","weight":3},{"address":"10.1.1.2","port":80,"condition":"ENABLED","weight":8},{"address":"10.1.1.3","port":80,"condition":"DISABLED","weight":12}]} {"nodes":[{"address":"10.1.1.1","port":80,"condition":"ENABLED","weight":3},{"address":"10.1.1.2","port":80,"condition":"ENABLED","type":"SECONDARY","weight":8},{"address":"10.1.1.3","port":80,"condition":"DISABLED","weight":12}]}