Merge pull request #1179 from rackspace/rax-clb-access-list

The access list API for Rackspace Cloud Load Balancers.
This commit is contained in:
Adrian Cole 2013-01-16 10:03:16 -08:00
commit 184ff81f3d
19 changed files with 628 additions and 132 deletions

View File

@ -25,6 +25,7 @@ import javax.ws.rs.PathParam;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.Zone;
import org.jclouds.location.functions.ZoneToEndpoint;
import org.jclouds.rackspace.cloudloadbalancers.features.AccessRuleApi;
import org.jclouds.rackspace.cloudloadbalancers.features.LoadBalancerApi;
import org.jclouds.rackspace.cloudloadbalancers.features.NodeApi;
import org.jclouds.rest.annotations.Delegate;
@ -62,4 +63,11 @@ public interface CloudLoadBalancersApi {
NodeApi getNodeApiForZoneAndLoadBalancer(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone, @PathParam("lbId") int lbId);
/**
* Provides synchronous access to Access Rule features.
*/
@Delegate
@Path("/loadbalancers/{lbId}")
AccessRuleApi getAccessRuleApiForZoneAndLoadBalancer(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone, @PathParam("lbId") int lbId);
}

View File

@ -48,7 +48,8 @@ import com.google.inject.Module;
*/
public class CloudLoadBalancersApiMetadata extends BaseRestApiMetadata {
public static final TypeToken<RestContext<CloudLoadBalancersApi, CloudLoadBalancersAsyncApi>> CONTEXT_TOKEN = new TypeToken<RestContext<CloudLoadBalancersApi, CloudLoadBalancersAsyncApi>>() {
public static final TypeToken<RestContext<CloudLoadBalancersApi, CloudLoadBalancersAsyncApi>> CONTEXT_TOKEN =
new TypeToken<RestContext<CloudLoadBalancersApi, CloudLoadBalancersAsyncApi>>() {
private static final long serialVersionUID = 1L;
};

View File

@ -26,6 +26,7 @@ import javax.ws.rs.PathParam;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.Zone;
import org.jclouds.location.functions.ZoneToEndpoint;
import org.jclouds.rackspace.cloudloadbalancers.features.AccessRuleApi;
import org.jclouds.rackspace.cloudloadbalancers.features.LoadBalancerAsyncApi;
import org.jclouds.rackspace.cloudloadbalancers.features.NodeAsyncApi;
import org.jclouds.rest.annotations.Delegate;
@ -63,4 +64,11 @@ public interface CloudLoadBalancersAsyncApi {
NodeAsyncApi getNodeApiForZoneAndLoadBalancer(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone, @PathParam("lbId") int lbId);
/**
* Provides synchronous access to Access Rule features.
*/
@Delegate
@Path("/loadbalancers/{lbId}")
AccessRuleApi getAccessRuleApiForZoneAndLoadBalancer(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone, @PathParam("lbId") int lbId);
}

View File

@ -28,6 +28,8 @@ import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
import org.jclouds.rackspace.cloudloadbalancers.CloudLoadBalancersAsyncApi;
import org.jclouds.rackspace.cloudloadbalancers.CloudLoadBalancersApi;
import org.jclouds.rackspace.cloudloadbalancers.features.AccessRuleApi;
import org.jclouds.rackspace.cloudloadbalancers.features.AccessRuleAsyncApi;
import org.jclouds.rackspace.cloudloadbalancers.features.LoadBalancerAsyncApi;
import org.jclouds.rackspace.cloudloadbalancers.features.LoadBalancerApi;
import org.jclouds.rackspace.cloudloadbalancers.features.NodeAsyncApi;
@ -52,6 +54,7 @@ public class CloudLoadBalancersRestClientModule extends
public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()
.put(LoadBalancerApi.class, LoadBalancerAsyncApi.class)
.put(NodeApi.class, NodeAsyncApi.class)
.put(AccessRuleApi.class, AccessRuleAsyncApi.class)
.build();
public CloudLoadBalancersRestClientModule() {

View File

@ -24,41 +24,49 @@ 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
* The access rule 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
* rule. Rules that are configured with the ALLOW type will always take precedence over rules with the DENY type. To
* reject traffic from all rules 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;
/**
* Use this method to easily construct {@link Type#ALLOW} rules for the address.
*/
public static AccessRule allow(String address) {
return new AccessRule(address, Type.ALLOW);
}
/**
* Use this method to easily construct {@link Type#DENY} rules for the address.
*/
public static AccessRule deny(String address) {
return new AccessRule(address, Type.DENY);
}
protected AccessRule(int id, Type type, String address) {
this.id = id;
this.type = checkNotNull(type, "type");
public AccessRule(String address, Type type) {
this.address = checkNotNull(address, "address");
}
public int getId() {
return this.id;
}
public Type getType() {
return this.type;
this.type = checkNotNull(type, "type");
}
public String getAddress() {
return this.address;
}
public Type getType() {
return this.type;
}
@Override
public int hashCode() {
return Objects.hashCode(id);
return Objects.hashCode(address);
}
@Override
@ -67,12 +75,12 @@ public class AccessRule {
if (obj == null || getClass() != obj.getClass()) return false;
AccessRule that = AccessRule.class.cast(obj);
return Objects.equal(this.id, that.id);
return Objects.equal(this.address, that.address);
}
protected ToStringHelper string() {
return Objects.toStringHelper(this)
.add("id", id).add("type", type).add("address", address);
return Objects.toStringHelper(this).omitNullValues()
.add("address", address).add("type", type);
}
@Override
@ -82,12 +90,12 @@ public class AccessRule {
public static enum Type {
/**
* Specifies items that will always take precedence over items with the DENY type.
* Specifies rules that will always take precedence over rules with the DENY type.
*/
ALLOW,
/**
* Specifies items to which traffic can be denied.
* Specifies rules to which traffic can be denied.
*/
DENY,
@ -101,53 +109,4 @@ public class AccessRule {
}
}
}
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,65 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.rackspace.cloudloadbalancers.domain;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
/**
* The same as {@link AccessRule} but this will have an id as assigned by the Cloud Load Balancers service.
*
* @author Everett Toews
*/
public class AccessRuleWithId extends AccessRule {
private final int id;
public AccessRuleWithId(int id, String address, Type type) {
super(address, type);
this.id = id;
}
public int getId() {
return this.id;
}
@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;
AccessRuleWithId that = AccessRuleWithId.class.cast(obj);
return Objects.equal(this.id, that.id);
}
protected ToStringHelper string() {
return Objects.toStringHelper(this).omitNullValues()
.add("id", id).add("address", getAddress()).add("type", getType());
}
@Override
public String toString() {
return string().toString();
}
}

View File

@ -49,6 +49,7 @@ public class LoadBalancer extends BaseLoadBalancer<Node, LoadBalancer> {
private final int nodeCount;
private final SSLTermination sslTermination;
private final SourceAddresses sourceAddresses;
private final Set<AccessRuleWithId> accessRules;
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,
@ -56,10 +57,10 @@ public class LoadBalancer extends BaseLoadBalancer<Node, LoadBalancer> {
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,
SourceAddresses sourceAddresses, Set<AccessRuleWithId> accessRules,
@Nullable Set<Metadata> metadata) {
super(name, protocol, port, nodes, algorithm, timeout, halfClosed, sessionPersistenceType, connectionLogging,
connectionThrottle, healthMonitor, accessRules, metadata);
connectionThrottle, healthMonitor, metadata);
this.region = checkNotNull(region, "region");
checkArgument(id != -1, "id must be specified");
this.id = id;
@ -72,6 +73,7 @@ public class LoadBalancer extends BaseLoadBalancer<Node, LoadBalancer> {
this.nodeCount = nodeCount;
this.sslTermination = sslTermination;
this.sourceAddresses = sourceAddresses;
this.accessRules = accessRules == null ? ImmutableSet.<AccessRuleWithId> of() : ImmutableSet.copyOf(accessRules);
}
public String getRegion() {
@ -151,6 +153,10 @@ public class LoadBalancer extends BaseLoadBalancer<Node, LoadBalancer> {
return sourceAddresses;
}
public Set<AccessRuleWithId> getAccessRules() {
return accessRules;
}
protected ToStringHelper string() {
return Objects.toStringHelper(this).omitNullValues().add("id", id).add("region", region).add("status", status)
.add("name", name).add("protocol", protocol).add("port", port).add("nodeCount", getNodeCount())
@ -159,7 +165,7 @@ public class LoadBalancer extends BaseLoadBalancer<Node, LoadBalancer> {
.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("accessRules", accessRules).add("metadata", getMetadata()).add("sourceAddresses", sourceAddresses)
.add("virtualIPs", virtualIPs);
}
@ -253,6 +259,7 @@ public class LoadBalancer extends BaseLoadBalancer<Node, LoadBalancer> {
private int nodeCount = 0;
private SSLTermination sslTermination;
private SourceAddresses sourceAddresses;
private Set<AccessRuleWithId> accessRules;
public Builder region(String region) {
this.region = region;
@ -302,16 +309,22 @@ public class LoadBalancer extends BaseLoadBalancer<Node, LoadBalancer> {
return this;
}
public Builder sslTermination(@Nullable SSLTermination sslTermination) {
this.sslTermination = sslTermination;
public Builder sslTermination(SSLTermination sslTermination) {
this.sslTermination = checkNotNull(sslTermination, "sslTermination");
return this;
}
public Builder sourceAddresses(@Nullable SourceAddresses sourceAddresses) {
this.sourceAddresses = sourceAddresses;
public Builder sourceAddresses(SourceAddresses sourceAddresses) {
this.sourceAddresses = checkNotNull(sourceAddresses, "sourceAddresses");
return this;
}
public Builder accessRules(Iterable<AccessRuleWithId> accessRules) {
this.accessRules = ImmutableSet.copyOf(checkNotNull(accessRules, "accessRules"));
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,
@ -416,14 +429,6 @@ public class LoadBalancer extends BaseLoadBalancer<Node, LoadBalancer> {
return Builder.class.cast(super.healthMonitor(healthMonitor));
}
/**
* {@inheritDoc}
*/
@Override
public Builder accessRules(@Nullable Set<AccessRule> accessRules) {
return Builder.class.cast(super.accessRules(accessRules));
}
/**
* {@inheritDoc}
*/

View File

@ -40,6 +40,7 @@ import com.google.common.collect.ImmutableSet;
public class LoadBalancerRequest extends BaseLoadBalancer<NodeRequest, LoadBalancerRequest> {
private final Set<Map<String, String>> virtualIps;
private final Set<AccessRule> accessRules;
public LoadBalancerRequest(String name, String protocol, @Nullable Integer port, Set<NodeRequest> nodes,
@Nullable Algorithm algorithm, @Nullable Integer timeout, @Nullable Boolean halfClosed,
@ -48,8 +49,8 @@ public class LoadBalancerRequest extends BaseLoadBalancer<NodeRequest, LoadBalan
@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));
connectionThrottle, healthMonitor, accessRules, metadata,
getVirtualIPsFromOptions(virtualIPType, virtualIPId));
}
public LoadBalancerRequest(String name, String protocol, @Nullable Integer port, Set<NodeRequest> nodes,
@ -59,8 +60,9 @@ public class LoadBalancerRequest extends BaseLoadBalancer<NodeRequest, LoadBalan
@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);
connectionThrottle, healthMonitor, metadata);
this.virtualIps = checkNotNull(virtualIPsFromOptions, "virtualIPsFromOptions");
this.accessRules = accessRules;
}
static Set<Map<String, String>> getVirtualIPsFromOptions(VirtualIP.Type virtualIPType, Integer virtualIPId) {
@ -79,7 +81,7 @@ public class LoadBalancerRequest extends BaseLoadBalancer<NodeRequest, LoadBalan
.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("healthMonitor", healthMonitor).add("accessRules", accessRules).add("metadata", metadata)
.add("virtualIps", virtualIps);
}
@ -92,22 +94,43 @@ public class LoadBalancerRequest extends BaseLoadBalancer<NodeRequest, LoadBalan
private VirtualIP.Type virtualIPType;
private Integer virtualIPId;
private Set<Map<String, String>> virtualIps;
private Set<AccessRule> accessRules;
/**
* @see VirtualIP
*/
public Builder virtualIPId(Integer virtualIPId) {
this.virtualIPId = virtualIPId;
return this;
}
/**
* @see VirtualIP
*/
public Builder virtualIPType(VirtualIP.Type virtualIPType) {
this.virtualIPType = virtualIPType;
return this;
}
/**
* @see VirtualIP
*/
private Builder virtualIPs(Set<Map<String, String>> virtualIPs) {
this.virtualIps = virtualIPs;
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 accessRules(Iterable<AccessRule> accessRules) {
this.accessRules = ImmutableSet.<AccessRule> copyOf(checkNotNull(accessRules, "accessRules"));
return this;
}
public LoadBalancerRequest build() {
if (virtualIps == null) {
return new LoadBalancerRequest(name, protocol, port, nodes, algorithm, timeout, halfClosed,
@ -147,14 +170,6 @@ public class LoadBalancerRequest extends BaseLoadBalancer<NodeRequest, LoadBalan
return Builder.class.cast(super.algorithm(algorithm));
}
/**
* {@inheritDoc}
*/
@Override
public Builder from(LoadBalancerRequest in) {
return Builder.class.cast(super.from(in)).virtualIPs(in.virtualIps);
}
/**
* {@inheritDoc}
*/
@ -179,6 +194,13 @@ public class LoadBalancerRequest extends BaseLoadBalancer<NodeRequest, LoadBalan
return Builder.class.cast(super.protocol(protocol));
}
/**
* {@inheritDoc}
*/
@Override
public Builder from(LoadBalancerRequest in) {
return Builder.class.cast(super.from(in)).virtualIPs(in.virtualIps);
}
}
@SuppressWarnings("unchecked")

View File

@ -25,7 +25,6 @@ import java.util.Set;
import java.util.SortedSet;
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;
@ -62,7 +61,6 @@ public class BaseLoadBalancer<N extends BaseNode<N>, T extends BaseLoadBalancer<
protected Map<String, Boolean> connectionLogging;
protected ConnectionThrottle connectionThrottle;
protected HealthMonitor healthMonitor;
protected Set<AccessRule> accessList;
protected Set<Metadata> metadata;
// for serialization only
@ -73,8 +71,7 @@ public class BaseLoadBalancer<N extends BaseNode<N>, T extends BaseLoadBalancer<
@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) {
@Nullable HealthMonitor healthMonitor, @Nullable Set<Metadata> metadata) {
this.name = checkNotNull(name, "name");
this.protocol = protocol;// null on deleted LB
this.port = port;// null on deleted LB
@ -86,7 +83,6 @@ public class BaseLoadBalancer<N extends BaseNode<N>, T extends BaseLoadBalancer<
this.connectionLogging = connectionLogging;
this.connectionThrottle = connectionThrottle;
this.healthMonitor = healthMonitor;
this.accessList = accessRules;
this.metadata = metadata;
}
@ -171,14 +167,6 @@ public class BaseLoadBalancer<N extends BaseNode<N>, T extends BaseLoadBalancer<
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.
*/
@ -192,7 +180,7 @@ public class BaseLoadBalancer<N extends BaseNode<N>, T extends BaseLoadBalancer<
.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);
.add("healthMonitor", healthMonitor).add("metadata", metadata);
}
@Override
@ -300,7 +288,6 @@ public class BaseLoadBalancer<N extends BaseNode<N>, T extends BaseLoadBalancer<
protected Map<String, Boolean> connectionLogging;
protected ConnectionThrottle connectionThrottle;
protected HealthMonitor healthMonitor;
protected Set<AccessRule> accessRules;
protected Set<Metadata> metadata;
/**
@ -427,17 +414,6 @@ public class BaseLoadBalancer<N extends BaseNode<N>, T extends BaseLoadBalancer<
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.
*/
@ -448,7 +424,7 @@ public class BaseLoadBalancer<N extends BaseNode<N>, T extends BaseLoadBalancer<
public BaseLoadBalancer<N, T> build() {
return new BaseLoadBalancer<N, T>(name, protocol, port, nodes, algorithm, timeout, halfClosed,
sessionPersistence, connectionLogging, connectionThrottle, healthMonitor, accessRules, metadata);
sessionPersistence, connectionLogging, connectionThrottle, healthMonitor, metadata);
}
public Builder<N, T> from(T baseLB) {
@ -456,8 +432,7 @@ public class BaseLoadBalancer<N extends BaseNode<N>, T extends BaseLoadBalancer<
.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());
.healthMonitor(baseLB.getHealthMonitor()).metadata(baseLB.getMetadata());
}
}

View File

@ -0,0 +1,62 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.rackspace.cloudloadbalancers.features;
import org.jclouds.rackspace.cloudloadbalancers.domain.AccessRule;
import org.jclouds.rackspace.cloudloadbalancers.domain.AccessRuleWithId;
/**
* The access list management feature allows fine-grained network access controls to be applied to the load balancer's
* virtual IP address.
* <p/>
*
* @see AccessRuleAsyncApi
* @author Everett Toews
*/
public interface AccessRuleApi {
/**
* Create a new access list or append to an existing access list.
*
* When creating an access list, one or more AccessRules are required. If a populated access list already exists
* for the load balancer, it will be appended to with subsequent creates. One access list may include up to 100
* AccessRules. A single address or subnet definition is considered unique and cannot be duplicated between rules
* in an access list.
*/
void create(Iterable<AccessRule> accessList);
/**
* List the AccessRules
*/
Iterable<AccessRuleWithId> list();
/**
* Remove an access rule from the access list.
*/
void remove(int id);
/**
* Batch delete the access rules given the specified ids.
*/
void remove(Iterable<Integer> ids);
/**
* Remove the entire access list.
*/
void removeAll();
}

View File

@ -0,0 +1,98 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.rackspace.cloudloadbalancers.features;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
import org.jclouds.rackspace.cloudloadbalancers.domain.AccessRule;
import org.jclouds.rackspace.cloudloadbalancers.domain.AccessRuleWithId;
import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson;
import org.jclouds.rest.annotations.WrapWith;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides asynchronous access to Rackspace Cloud Load Balancers via their REST API.
* <p/>
*
* @see AccessRuleApi
* @author Everett Toews
*/
@RequestFilters(AuthenticateRequest.class)
public interface AccessRuleAsyncApi {
/**
* @see AccessRuleApi#create(Iterable)
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Fallback(NullOnNotFoundOr404.class)
@Path("/accesslist")
ListenableFuture<Void> create(@WrapWith("accessList") Iterable<AccessRule> accessList);
/**
* @see AccessRuleApi#list()
*/
@GET
@Consumes(MediaType.APPLICATION_JSON)
@Fallback(EmptyPagedIterableOnNotFoundOr404.class)
@SelectJson("accessList")
@Path("/accesslist")
ListenableFuture<Iterable<AccessRuleWithId>> list();
/**
* @see AccessRuleApi#remove(int)
*/
@DELETE
@Fallback(VoidOnNotFoundOr404.class)
@Path("/accesslist/{id}")
@Consumes("*/*")
ListenableFuture<Void> remove(@PathParam("id") int id);
/**
* @see AccessRuleApi#remove(Iterable)
*/
@DELETE
@Fallback(VoidOnNotFoundOr404.class)
@Path("/accesslist")
@Consumes("*/*")
ListenableFuture<Void> remove(@QueryParam("id") Iterable<Integer> ids);
/**
* @see AccessRuleApi#removeAll()
*/
@DELETE
@Fallback(VoidOnNotFoundOr404.class)
@Path("/accesslist")
@Consumes("*/*")
ListenableFuture<Void> removeAll();
}

View File

@ -22,10 +22,12 @@ import javax.annotation.Resource;
import javax.inject.Inject;
import org.jclouds.logging.Logger;
import org.jclouds.rackspace.cloudloadbalancers.domain.AccessRuleWithId;
import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer;
import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer.Builder;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.inject.assistedinject.Assisted;
@ -56,7 +58,7 @@ public class ConvertLB implements Function<LB, LoadBalancer> {
.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);
.metadata(lb.getMetadata()).virtualIPs(lb.virtualIps);
if (lb.cluster.size() == 1)
builder.clusterName(Iterables.get(lb.cluster.values(), 0));
@ -70,6 +72,10 @@ public class ConvertLB implements Function<LB, LoadBalancer> {
builder.sslTermination(lb.sslTermination);
if (lb.sourceAddresses != null)
builder.sourceAddresses(lb.sourceAddresses);
if (lb.accessList == null)
builder.accessRules(ImmutableSet.<AccessRuleWithId> of());
else
builder.accessRules(lb.accessList);
return builder.build();
}

View File

@ -23,6 +23,7 @@ import java.util.Map;
import java.util.Set;
import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer.Status;
import org.jclouds.rackspace.cloudloadbalancers.domain.AccessRuleWithId;
import org.jclouds.rackspace.cloudloadbalancers.domain.Node;
import org.jclouds.rackspace.cloudloadbalancers.domain.SSLTermination;
import org.jclouds.rackspace.cloudloadbalancers.domain.SourceAddresses;
@ -47,6 +48,7 @@ class LB extends BaseLoadBalancer<Node, LB> {
Map<String, Boolean> contentCaching = Maps.newLinkedHashMap();
SSLTermination sslTermination;
SourceAddresses sourceAddresses;
Set<AccessRuleWithId> accessList;
@Override
public int hashCode() {

View File

@ -0,0 +1,116 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.rackspace.cloudloadbalancers.features;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.List;
import javax.ws.rs.core.MediaType;
import org.jclouds.http.HttpResponse;
import org.jclouds.rackspace.cloudloadbalancers.CloudLoadBalancersApi;
import org.jclouds.rackspace.cloudloadbalancers.domain.AccessRule;
import org.jclouds.rackspace.cloudloadbalancers.domain.AccessRuleWithId;
import org.jclouds.rackspace.cloudloadbalancers.internal.BaseCloudLoadBalancerApiExpectTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
/**
* @author Everett Toews
*/
@Test(groups = "unit")
public class AccessRuleApiExpectTest extends BaseCloudLoadBalancerApiExpectTest<CloudLoadBalancersApi> {
public void testListAccessList() {
URI endpoint = URI.create("https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/123123/loadbalancers/2000/accesslist");
AccessRuleApi api = requestsSendResponses(
rackspaceAuthWithUsernameAndApiKey,
responseWithAccess,
authenticatedGET().endpoint(endpoint).build(),
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/accesslist-list.json")).build()
).getAccessRuleApiForZoneAndLoadBalancer("DFW", 2000);
Iterable<AccessRuleWithId> accessList = api.list();
assertEquals(accessList, getAccessList());
}
public void testCreateAccessList() {
URI endpoint = URI.create("https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/123123/loadbalancers/2000/accesslist");
AccessRuleApi api = requestsSendResponses(
rackspaceAuthWithUsernameAndApiKey,
responseWithAccess,
authenticatedGET().method("POST").endpoint(endpoint).payload(payloadFromResource("/accesslist-create.json")).build(),
HttpResponse.builder().statusCode(200).build()
).getAccessRuleApiForZoneAndLoadBalancer("DFW", 2000);
AccessRule accessRule1 = AccessRule.deny("206.160.163.21");
AccessRule accessRule2 = AccessRule.deny("206.160.165.11");
AccessRule accessRule3 = AccessRule.deny("206.160.163.22");
List<AccessRule> accessList = ImmutableList.<AccessRule> of(accessRule1, accessRule2, accessRule3);
api.create(accessList);
}
public void testRemoveSingleAccessRule() {
URI endpoint = URI.create("https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/123123/loadbalancers/2000/accesslist/23");
AccessRuleApi api = requestsSendResponses(
rackspaceAuthWithUsernameAndApiKey,
responseWithAccess,
authenticatedGET().method("DELETE").endpoint(endpoint).replaceHeader("Accept", MediaType.WILDCARD).build(),
HttpResponse.builder().statusCode(200).build()
).getAccessRuleApiForZoneAndLoadBalancer("DFW", 2000);
api.remove(23);
}
public void testRemoveManyAccessRules() {
URI endpoint = URI.create("https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/123123/loadbalancers/2000/accesslist?id=23&id=24");
AccessRuleApi api = requestsSendResponses(
rackspaceAuthWithUsernameAndApiKey,
responseWithAccess,
authenticatedGET().method("DELETE").endpoint(endpoint).replaceHeader("Accept", MediaType.WILDCARD).build(),
HttpResponse.builder().statusCode(200).build()
).getAccessRuleApiForZoneAndLoadBalancer("DFW", 2000);
List<Integer> accessRuleIds = ImmutableList.<Integer> of(23, 24);
api.remove(accessRuleIds);
}
public void testRemoveAllAccessRules() {
URI endpoint = URI.create("https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/123123/loadbalancers/2000/accesslist");
AccessRuleApi api = requestsSendResponses(
rackspaceAuthWithUsernameAndApiKey,
responseWithAccess,
authenticatedGET().method("DELETE").endpoint(endpoint).replaceHeader("Accept", MediaType.WILDCARD).build(),
HttpResponse.builder().statusCode(200).build()
).getAccessRuleApiForZoneAndLoadBalancer("DFW", 2000);
api.removeAll();
}
private Iterable<AccessRule> getAccessList() {
AccessRule accessRule1 = new AccessRuleWithId(23, "206.160.163.21", AccessRule.Type.DENY);
AccessRule accessRule2 = new AccessRuleWithId(24, "206.160.165.11", AccessRule.Type.DENY);
AccessRule accessRule3 = new AccessRuleWithId(25, "206.160.163.22", AccessRule.Type.DENY);
return ImmutableList.<AccessRule> of(accessRule1, accessRule2, accessRule3);
}
}

View File

@ -0,0 +1,145 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.rackspace.cloudloadbalancers.features;
import static org.jclouds.rackspace.cloudloadbalancers.predicates.LoadBalancerPredicates.awaitAvailable;
import static org.jclouds.rackspace.cloudloadbalancers.predicates.LoadBalancerPredicates.awaitDeleted;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jclouds.rackspace.cloudloadbalancers.domain.AccessRule;
import org.jclouds.rackspace.cloudloadbalancers.domain.AccessRuleWithId;
import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer;
import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancerRequest;
import org.jclouds.rackspace.cloudloadbalancers.domain.NodeRequest;
import org.jclouds.rackspace.cloudloadbalancers.domain.VirtualIP.Type;
import org.jclouds.rackspace.cloudloadbalancers.internal.BaseCloudLoadBalancersApiLiveTest;
import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
/**
* @author Everett Toews
*/
@Test(groups = "live", singleThreaded = true, testName = "AccessListApiLiveTest")
public class AccessRuleApiLiveTest extends BaseCloudLoadBalancersApiLiveTest {
private LoadBalancer lb;
private String zone;
private AccessRule accessRule1;
private AccessRule accessRule2;
private AccessRule accessRule3;
private AccessRule accessRule4;
private Map<String, AccessRule> accessRules;
@Override
@BeforeGroups(groups = { "live" })
public void setupContext() {
super.setupContext();
accessRule1 = AccessRule.deny("206.160.163.21");
accessRule2 = AccessRule.deny("206.160.165.11");
accessRule3 = AccessRule.deny("206.160.163.22");
accessRule4 = AccessRule.deny("206.160.168.22");
accessRules = new HashMap<String, AccessRule>();
accessRules.put(accessRule1.getAddress(), accessRule1);
accessRules.put(accessRule2.getAddress(), accessRule2);
accessRules.put(accessRule3.getAddress(), accessRule3);
accessRules.put(accessRule4.getAddress(), accessRule4);
}
public void testCreateLoadBalancer() {
NodeRequest nodeRequest = NodeRequest.builder().address("192.168.1.1").port(8080).build();
LoadBalancerRequest lbRequest = LoadBalancerRequest.builder()
.name(prefix+"-jclouds").protocol("HTTP").port(80).virtualIPType(Type.PUBLIC).node(nodeRequest).build();
zone = Iterables.getFirst(clbApi.getConfiguredZones(), null);
lb = clbApi.getLoadBalancerApiForZone(zone).create(lbRequest);
assertTrue(awaitAvailable(clbApi.getLoadBalancerApiForZone(zone)).apply(lb));
}
@Test(dependsOnMethods = "testCreateLoadBalancer")
public void testCreateAccessList() throws Exception {
clbApi.getAccessRuleApiForZoneAndLoadBalancer(zone, lb.getId()).create(accessRules.values());
assertTrue(awaitAvailable(clbApi.getLoadBalancerApiForZone(zone)).apply(lb));
assertExpectedAccessRules(accessRules);
}
@Test(dependsOnMethods = "testCreateAccessList")
public void testRemoveSingleAccessRule() throws Exception {
Iterable<AccessRuleWithId> actualAccessList = clbApi.getAccessRuleApiForZoneAndLoadBalancer(zone, lb.getId()).list();
AccessRuleWithId removedAccessRule = Iterables.getFirst(actualAccessList, null);
accessRules.remove(removedAccessRule.getAddress());
clbApi.getAccessRuleApiForZoneAndLoadBalancer(zone, lb.getId()).remove(removedAccessRule.getId());
assertTrue(awaitAvailable(clbApi.getLoadBalancerApiForZone(zone)).apply(lb));
assertExpectedAccessRules(accessRules);
}
@Test(dependsOnMethods = "testRemoveSingleAccessRule")
public void testRemoveManyAccessRules() throws Exception {
Iterable<AccessRuleWithId> actualAccessList = clbApi.getAccessRuleApiForZoneAndLoadBalancer(zone, lb.getId()).list();
AccessRuleWithId removedAccessRule1 = Iterables.getFirst(actualAccessList, null);
AccessRuleWithId removedAccessRule2 = Iterables.getLast(actualAccessList);
List<Integer> removedAccessRuleIds = ImmutableList.<Integer> of(removedAccessRule1.getId(), removedAccessRule2.getId());
accessRules.remove(removedAccessRule1.getAddress());
accessRules.remove(removedAccessRule2.getAddress());
clbApi.getAccessRuleApiForZoneAndLoadBalancer(zone, lb.getId()).remove(removedAccessRuleIds);
assertTrue(awaitAvailable(clbApi.getLoadBalancerApiForZone(zone)).apply(lb));
assertExpectedAccessRules(accessRules);
}
@Test(dependsOnMethods = "testRemoveManyAccessRules")
public void testRemoveAllAccessRules() throws Exception {
clbApi.getAccessRuleApiForZoneAndLoadBalancer(zone, lb.getId()).removeAll();
assertTrue(awaitAvailable(clbApi.getLoadBalancerApiForZone(zone)).apply(lb));
assertExpectedAccessRules(new HashMap<String, AccessRule>());
}
private void assertExpectedAccessRules(Map<String, AccessRule> expectedAccessList) {
Iterable<AccessRuleWithId> actualAccessList = clbApi.getAccessRuleApiForZoneAndLoadBalancer(zone, lb.getId()).list();
for (AccessRule actualAccessRule: actualAccessList) {
assertEquals(expectedAccessList.containsKey(actualAccessRule.getAddress()), true,
"The AccessRule " + actualAccessRule + " was not found in " + expectedAccessList);
}
}
@Override
@AfterGroups(groups = "live")
protected void tearDownContext() {
assertTrue(awaitAvailable(clbApi.getLoadBalancerApiForZone(zone)).apply(lb));
clbApi.getLoadBalancerApiForZone(zone).remove(lb.getId());
assertTrue(awaitDeleted(clbApi.getLoadBalancerApiForZone(zone)).apply(lb));
super.tearDownContext();
}
}

View File

@ -58,7 +58,7 @@ public class LoadBalancerApiExpectTest extends BaseCloudLoadBalancerApiExpectTes
assertEquals(loadBalancers, testLoadBalancers());
}
public void testGetLoadBalancer() {
public void testGetLoadBalancer() throws Exception {
URI endpoint = URI.create("https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/123123/loadbalancers/2000");
LoadBalancerApi api = requestsSendResponses(
rackspaceAuthWithUsernameAndApiKey,
@ -71,7 +71,7 @@ public class LoadBalancerApiExpectTest extends BaseCloudLoadBalancerApiExpectTes
assertEquals(loadBalancer, testLoadBalancer());
}
public void testCreateLoadBalancer() {
public void testCreateLoadBalancer() throws Exception {
URI endpoint = URI.create("https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/123123/loadbalancers");
LoadBalancerApi api = requestsSendResponses(
rackspaceAuthWithUsernameAndApiKey,

View File

@ -22,6 +22,7 @@ import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.http.HttpResponse;
import org.jclouds.json.BaseItemParserTest;
import org.jclouds.rackspace.cloudloadbalancers.domain.AccessRule;
import org.jclouds.rackspace.cloudloadbalancers.domain.AccessRuleWithId;
import org.jclouds.rackspace.cloudloadbalancers.domain.ConnectionThrottle;
import org.jclouds.rackspace.cloudloadbalancers.domain.HealthMonitor;
import org.jclouds.rackspace.cloudloadbalancers.domain.HealthMonitor.Type;
@ -75,8 +76,8 @@ public class ParseLoadBalancerTest extends BaseItemParserTest<LoadBalancer> {
.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()))
new AccessRuleWithId(22215, "1.2.3.4/32", AccessRule.Type.DENY),
new AccessRuleWithId(22217, "12.0.0.0/8", AccessRule.Type.ALLOW)))
.virtualIPs(ImmutableSet.of(
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()))

View File

@ -0,0 +1 @@
{"accessList":[{"address":"206.160.163.21","type":"DENY"},{"address":"206.160.165.11","type":"DENY"},{"address":"206.160.163.22","type":"DENY"}]}

View File

@ -0,0 +1,19 @@
{
"accessList": [
{
"address": "206.160.163.21",
"id": 23,
"type": "DENY"
},
{
"address": "206.160.165.11",
"id": 24,
"type": "DENY"
},
{
"address": "206.160.163.22",
"id": 25,
"type": "DENY"
}
]
}