refined domain objects related to security groups, implemented implicit security group lookup + creator

This commit is contained in:
Adrian Cole 2012-03-20 17:34:38 -07:00
parent 58ee8fa1a4
commit a2966b1555
21 changed files with 1058 additions and 126 deletions

View File

@ -21,6 +21,7 @@ package org.jclouds.openstack.nova.v1_1;
import static org.jclouds.Constants.PROPERTY_API_VERSION; import static org.jclouds.Constants.PROPERTY_API_VERSION;
import static org.jclouds.Constants.PROPERTY_ENDPOINT; import static org.jclouds.Constants.PROPERTY_ENDPOINT;
import static org.jclouds.openstack.nova.v1_1.reference.NovaConstants.PROPERTY_NOVA_AUTO_ALLOCATE_FLOATING_IPS; import static org.jclouds.openstack.nova.v1_1.reference.NovaConstants.PROPERTY_NOVA_AUTO_ALLOCATE_FLOATING_IPS;
import static org.jclouds.openstack.nova.v1_1.reference.NovaConstants.PROPERTY_NOVA_TIMEOUT_SECURITYGROUP_PRESENT;
import java.util.Properties; import java.util.Properties;
@ -43,6 +44,8 @@ public class NovaPropertiesBuilder extends PropertiesBuilder {
properties.setProperty(KeystoneProperties.VERSION, "2.0"); properties.setProperty(KeystoneProperties.VERSION, "2.0");
properties.setProperty(PROPERTY_API_VERSION, "1.1"); properties.setProperty(PROPERTY_API_VERSION, "1.1");
properties.setProperty(PROPERTY_NOVA_AUTO_ALLOCATE_FLOATING_IPS, "false"); properties.setProperty(PROPERTY_NOVA_AUTO_ALLOCATE_FLOATING_IPS, "false");
properties.setProperty(PROPERTY_NOVA_TIMEOUT_SECURITYGROUP_PRESENT, "500");
return properties; return properties;
} }

View File

@ -20,6 +20,8 @@ package org.jclouds.openstack.nova.v1_1.compute.config;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -40,18 +42,26 @@ import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.compute.NovaComputeServiceAdapter; import org.jclouds.openstack.nova.v1_1.compute.NovaComputeServiceAdapter;
import org.jclouds.openstack.nova.v1_1.compute.domain.FlavorInZone; import org.jclouds.openstack.nova.v1_1.compute.domain.FlavorInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ImageInZone; import org.jclouds.openstack.nova.v1_1.compute.domain.ImageInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ServerInZone; import org.jclouds.openstack.nova.v1_1.compute.domain.ServerInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneAndId; import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneAndId;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneAndName;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneSecurityGroupNameAndPorts;
import org.jclouds.openstack.nova.v1_1.compute.functions.CreateSecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.compute.functions.FlavorInZoneToHardware; import org.jclouds.openstack.nova.v1_1.compute.functions.FlavorInZoneToHardware;
import org.jclouds.openstack.nova.v1_1.compute.functions.ImageInZoneToImage; import org.jclouds.openstack.nova.v1_1.compute.functions.ImageInZoneToImage;
import org.jclouds.openstack.nova.v1_1.compute.functions.NovaImageToOperatingSystem; import org.jclouds.openstack.nova.v1_1.compute.functions.NovaImageToOperatingSystem;
import org.jclouds.openstack.nova.v1_1.compute.functions.ServerInZoneToNodeMetadata; import org.jclouds.openstack.nova.v1_1.compute.functions.ServerInZoneToNodeMetadata;
import org.jclouds.openstack.nova.v1_1.compute.loaders.CreateOrUpdateSecurityGroupAsNeeded;
import org.jclouds.openstack.nova.v1_1.compute.loaders.LoadFloatingIpsForInstance; import org.jclouds.openstack.nova.v1_1.compute.loaders.LoadFloatingIpsForInstance;
import org.jclouds.openstack.nova.v1_1.compute.options.NovaTemplateOptions; import org.jclouds.openstack.nova.v1_1.compute.options.NovaTemplateOptions;
import org.jclouds.openstack.nova.v1_1.compute.strategy.ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet; import org.jclouds.openstack.nova.v1_1.compute.strategy.ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet;
import org.jclouds.openstack.nova.v1_1.predicates.FindSecurityGroupWithNameAndReturnTrue;
import org.jclouds.openstack.nova.v1_1.reference.NovaConstants; import org.jclouds.openstack.nova.v1_1.reference.NovaConstants;
import org.jclouds.predicates.RetryablePredicate;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
@ -103,6 +113,12 @@ public class NovaComputeServiceContextModule
bind(new TypeLiteral<CacheLoader<ZoneAndId, Iterable<String>>>() { bind(new TypeLiteral<CacheLoader<ZoneAndId, Iterable<String>>>() {
}).annotatedWith(Names.named("FLOATINGIP")).to(LoadFloatingIpsForInstance.class); }).annotatedWith(Names.named("FLOATINGIP")).to(LoadFloatingIpsForInstance.class);
bind(new TypeLiteral<Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone>>() {
}).to(CreateSecurityGroupInZone.class);
bind(new TypeLiteral<CacheLoader<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone>>() {
}).to(CreateOrUpdateSecurityGroupAsNeeded.class);
bind(CreateNodesWithGroupEncodedIntoNameThenAddToSet.class).to( bind(CreateNodesWithGroupEncodedIntoNameThenAddToSet.class).to(
ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.class); ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.class);
@ -123,6 +139,22 @@ public class NovaComputeServiceContextModule
return CacheBuilder.newBuilder().build(in); return CacheBuilder.newBuilder().build(in);
} }
@Provides
@Singleton
protected LoadingCache<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> securityGroupMap(
CacheLoader<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> in) {
return CacheBuilder.newBuilder().build(in);
}
@Provides
@Singleton
@Named("SECURITY")
protected Predicate<AtomicReference<ZoneAndName>> securityGroupEventualConsistencyDelay(
FindSecurityGroupWithNameAndReturnTrue in,
@Named(NovaConstants.PROPERTY_NOVA_TIMEOUT_SECURITYGROUP_PRESENT) long msDelay) {
return new RetryablePredicate<AtomicReference<ZoneAndName>>(in, msDelay, 100l, TimeUnit.MILLISECONDS);
}
@Provides @Provides
@Singleton @Singleton
protected Supplier<Map<String, Location>> createLocationIndexedById( protected Supplier<Map<String, Location>> createLocationIndexedById(

View File

@ -0,0 +1,48 @@
/**
* 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.openstack.nova.v1_1.compute.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.openstack.nova.v1_1.domain.SecurityGroup;
/**
* @author Adrian Cole
*/
public class SecurityGroupInZone extends ZoneAndName {
protected final SecurityGroup securityGroup;
public SecurityGroupInZone(SecurityGroup securityGroup, String zoneId) {
super(zoneId, checkNotNull(securityGroup, "securityGroup").getName());
this.securityGroup = securityGroup;
}
public SecurityGroup getServer() {
return securityGroup;
}
// superclass hashCode/equals are good enough, and help us use ZoneAndName and ServerInZone
// interchangeably as Map keys
@Override
public String toString() {
return "[securityGroup=" + securityGroup + ", zoneId=" + zoneId + "]";
}
}

View File

@ -0,0 +1,93 @@
/**
* 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.openstack.nova.v1_1.compute.domain;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Objects;
import com.google.common.base.Splitter;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.Iterables;
/**
* Helpful when looking for resources by zone and name
*
* @author Adrian Cole
*/
public class ZoneAndName {
public static ZoneAndName fromSlashEncoded(String name) {
Iterable<String> parts = Splitter.on('/').split(checkNotNull(name, "name"));
checkArgument(Iterables.size(parts) == 2, "name must be in format zoneId/name");
return new ZoneAndName(Iterables.get(parts, 0), Iterables.get(parts, 1));
}
public static ZoneAndName fromZoneAndName(String zoneId, String name) {
return new ZoneAndName(zoneId, name);
}
private static String slashEncodeZoneAndName(String zoneId, String name) {
return checkNotNull(zoneId, "zoneId") + "/" + checkNotNull(name, "name");
}
public String slashEncode() {
return slashEncodeZoneAndName(zoneId, name);
}
protected final String zoneId;
protected final String name;
protected ZoneAndName(String zoneId, String name) {
this.zoneId = checkNotNull(zoneId, "zoneId");
this.name = checkNotNull(name, "name");
}
public String getZone() {
return zoneId;
}
public String getName() {
return name;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
ZoneAndName that = ZoneAndName.class.cast(o);
return equal(this.zoneId, that.zoneId) && equal(this.name, that.name);
}
@Override
public int hashCode() {
return Objects.hashCode(zoneId, name);
}
@Override
public String toString() {
return string().toString();
}
protected ToStringHelper string() {
return Objects.toStringHelper("").add("zoneId", zoneId).add("name", name);
}
}

View File

@ -0,0 +1,64 @@
/**
* 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.openstack.nova.v1_1.compute.domain;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.ImmutableList;
/**
* @author Adrian Cole
*/
public class ZoneSecurityGroupNameAndPorts extends ZoneAndName {
protected final List<Integer> ports;
public ZoneSecurityGroupNameAndPorts(String zoneId, String name, List<Integer> ports) {
super(zoneId, name);
this.ports = ImmutableList.<Integer> copyOf(checkNotNull(ports, "ports"));
}
public List<Integer> getPorts() {
return ports;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
ZoneSecurityGroupNameAndPorts that = ZoneSecurityGroupNameAndPorts.class.cast(o);
return super.equals(that) && equal(this.ports, that.ports);
}
@Override
public int hashCode() {
return Objects.hashCode(super.hashCode(), ports);
}
@Override
public ToStringHelper string() {
return super.string().add("ports", ports);
}
}

View File

@ -0,0 +1,89 @@
/**
* 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.openstack.nova.v1_1.compute.functions;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.compute.domain.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneSecurityGroupNameAndPorts;
import org.jclouds.openstack.nova.v1_1.domain.Ingress;
import org.jclouds.openstack.nova.v1_1.domain.IpProtocol;
import org.jclouds.openstack.nova.v1_1.domain.SecurityGroup;
import org.jclouds.openstack.nova.v1_1.extensions.SecurityGroupClient;
import com.google.common.base.Function;
import com.google.common.base.Optional;
/**
*
* @author Adrian Cole
*/
@Singleton
public class CreateSecurityGroupInZone implements Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
protected final NovaClient novaClient;
@Inject
public CreateSecurityGroupInZone(NovaClient novaClient) {
this.novaClient = checkNotNull(novaClient, "novaClient");
}
@Override
public SecurityGroupInZone apply(ZoneSecurityGroupNameAndPorts zoneSecurityGroupNameAndPorts) {
checkNotNull(zoneSecurityGroupNameAndPorts, "zoneSecurityGroupNameAndPorts");
String zoneId = zoneSecurityGroupNameAndPorts.getZone();
Optional<SecurityGroupClient> client = novaClient.getSecurityGroupExtensionForZone(zoneId);
checkArgument(client.isPresent(), "Security groups are required, but the extension is not available!");
logger.debug(">> creating securityGroup %s", zoneSecurityGroupNameAndPorts);
SecurityGroup securityGroup = client.get().createSecurityGroupWithNameAndDescription(
zoneSecurityGroupNameAndPorts.getName(), zoneSecurityGroupNameAndPorts.getName());
logger.debug("<< created securityGroup(%s)", securityGroup);
for (int port : zoneSecurityGroupNameAndPorts.getPorts()) {
authorizeGroupToItselfAndAllIPsToTCPPort(client.get(), securityGroup, port);
}
return new SecurityGroupInZone(client.get().getSecurityGroup(securityGroup.getId()), zoneId);
}
private void authorizeGroupToItselfAndAllIPsToTCPPort(SecurityGroupClient securityGroupClient,
SecurityGroup securityGroup, int port) {
logger.debug(">> authorizing securityGroup(%s) permission to port %d", securityGroup, port);
logger.trace(">> authorizing securityGroup(%s) permission to itself on port %d", securityGroup, port);
securityGroupClient.createSecurityGroupRuleAllowingSecurityGroupId(securityGroup.getId(), Ingress.builder()
.ipProtocol(IpProtocol.TCP).fromPort(port).toPort(port).build(), securityGroup.getId());
logger.trace(">> authorizing securityGroup(%s) permission to 0.0.0.0/0 on port %d", securityGroup, port);
securityGroupClient.createSecurityGroupRuleAllowingCidrBlock(securityGroup.getId(), Ingress.builder().ipProtocol(
IpProtocol.TCP).fromPort(port).toPort(port).build(), "0.0.0.0/0");
logger.debug("<< authorized securityGroup(%s) permission to port %d", securityGroup, port);
}
}

View File

@ -0,0 +1,83 @@
/**
* 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.openstack.nova.v1_1.compute.loaders;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import org.jclouds.openstack.nova.v1_1.compute.domain.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneAndName;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneSecurityGroupNameAndPorts;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.cache.CacheLoader;
/**
*
* @author Adrian Cole
*/
@Singleton
public class CreateOrUpdateSecurityGroupAsNeeded extends
CacheLoader<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
protected final Predicate<AtomicReference<ZoneAndName>> securityGroupEventualConsistencyDelay;
protected final Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> groupCreator;
@Inject
public CreateOrUpdateSecurityGroupAsNeeded(
@Named("SECURITY") Predicate<AtomicReference<ZoneAndName>> securityGroupEventualConsistencyDelay,
Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> groupCreator) {
this.securityGroupEventualConsistencyDelay = checkNotNull(securityGroupEventualConsistencyDelay,
"securityGroupEventualConsistencyDelay");
this.groupCreator = checkNotNull(groupCreator, "groupCreator");
}
@Override
public SecurityGroupInZone load(ZoneSecurityGroupNameAndPorts zoneSecurityGroupNameAndPorts) {
checkNotNull(zoneSecurityGroupNameAndPorts, "zoneSecurityGroupNameAndPorts");
AtomicReference<ZoneAndName> securityGroupInZoneRef = new AtomicReference<ZoneAndName>(
zoneSecurityGroupNameAndPorts);
if (securityGroupEventualConsistencyDelay.apply(securityGroupInZoneRef)) {
ZoneAndName securityGroupInZone = securityGroupInZoneRef.get();
checkState(
securityGroupInZone instanceof SecurityGroupInZone,
"programming error: predicate %s should update the atomic reference to the actual security group found",
securityGroupEventualConsistencyDelay);
// TODO: check ports are actually present!
return SecurityGroupInZone.class.cast(securityGroupInZone);
} else {
return groupCreator.apply(zoneSecurityGroupNameAndPorts);
}
}
}

View File

@ -24,6 +24,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.Beta; import com.google.common.annotations.Beta;
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.gson.annotations.SerializedName;
/** /**
* Ingress access to a destination protocol on particular ports * Ingress access to a destination protocol on particular ports
@ -37,9 +38,9 @@ public class Ingress {
} }
public static class Builder { public static class Builder {
private IpProtocol ipProtocol; protected IpProtocol ipProtocol;
private int fromPort; protected int fromPort;
private int toPort; protected int toPort;
/** /**
* *
@ -73,9 +74,12 @@ public class Ingress {
} }
} }
private final IpProtocol ipProtocol; @SerializedName(value = "ip_protocol")
private final int fromPort; protected final IpProtocol ipProtocol;
private final int toPort; @SerializedName(value = "from_port")
protected final int fromPort;
@SerializedName(value = "to_port")
protected final int toPort;
protected Ingress(IpProtocol ipProtocol, int fromPort, int toPort) { protected Ingress(IpProtocol ipProtocol, int fromPort, int toPort) {
this.fromPort = fromPort; this.fromPort = fromPort;

View File

@ -19,16 +19,18 @@
package org.jclouds.openstack.nova.v1_1.domain; package org.jclouds.openstack.nova.v1_1.domain;
import static com.google.common.base.Objects.toStringHelper; import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map; import org.jclouds.javax.annotation.Nullable;
import com.google.common.collect.ForwardingObject;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
/** /**
* Defines a security group rule * Defines a security group rule
* *
*/ */
public class SecurityGroupRule implements Comparable<SecurityGroupRule> { public class SecurityGroupRule extends Ingress {
public static Builder builder() { public static Builder builder() {
return new Builder(); return new Builder();
@ -38,125 +40,113 @@ public class SecurityGroupRule implements Comparable<SecurityGroupRule> {
return builder().fromSecurityGroupRule(this); return builder().fromSecurityGroupRule(this);
} }
public static class Builder { public static class Builder extends Ingress.Builder {
private String id; private String id;
private int fromPort;
private Map<String, String> group;
// tcp/udp/icmp - move to enum
private IpProtocol ipProtocol;
private int toPort;
private String parentGroupId; private String parentGroupId;
private TenantIdAndName group;
private Map<String, String> ipRange; private String ipRange;
public Builder id(String id) { public Builder id(String id) {
this.id = id; this.id = id;
return this; return this;
} }
public Builder fromPort(int fromPort) { public Builder group(TenantIdAndName group) {
this.fromPort = fromPort;
return this;
}
public Builder group(Map<String, String> group) {
this.group = group; this.group = group;
return this; return this;
} }
public Builder ipProtocol(IpProtocol ipProtocol) {
this.ipProtocol = ipProtocol;
return this;
}
public Builder toPort(int toPort) {
this.toPort = toPort;
return this;
}
public Builder parentGroupId(String parentGroupId) { public Builder parentGroupId(String parentGroupId) {
this.parentGroupId = parentGroupId; this.parentGroupId = parentGroupId;
return this; return this;
} }
public Builder ipRange(Map<String, String> ipRange) { public Builder ipRange(String ipRange) {
this.ipRange = ipRange; this.ipRange = ipRange;
return this; return this;
} }
@Override
public SecurityGroupRule build() { public SecurityGroupRule build() {
return new SecurityGroupRule(id, fromPort, group, ipProtocol, toPort, parentGroupId, ipRange); return new SecurityGroupRule(ipProtocol, fromPort, toPort, id, parentGroupId, group, ipRange);
} }
public Builder fromSecurityGroupRule(SecurityGroupRule in) { public Builder fromSecurityGroupRule(SecurityGroupRule in) {
return id(in.getId()).fromPort(in.getFromPort()).group(in.getGroup()).ipProtocol(in.getIpProtocol()) return id(in.getId()).fromPort(in.getFromPort()).group(in.getGroup()).ipProtocol(in.getIpProtocol()).toPort(
.toPort(in.getToPort()).parentGroupId(in.getParentGroupId()).ipRange(in.getIpRange()); in.getToPort()).parentGroupId(in.getParentGroupId()).ipRange(in.getIpRange());
}
@Override
public Builder ipProtocol(IpProtocol ipProtocol) {
super.ipProtocol(ipProtocol);
return this;
}
@Override
public Builder fromPort(int fromPort) {
super.fromPort(fromPort);
return this;
}
@Override
public Builder toPort(int toPort) {
super.toPort(toPort);
return this;
}
}
protected final String id;
protected final TenantIdAndName group;
@SerializedName(value = "parent_group_id")
protected final String parentGroupId;
// type to get around unnecessary structure
private static class Cidr extends ForwardingObject {
private String cidr;
private Cidr(String cidr) {
this.cidr = cidr;
}
@Override
protected Object delegate() {
return cidr;
} }
} }
protected String id;
@SerializedName(value = "from_port")
protected int fromPort;
protected Map<String, String> group;
@SerializedName(value = "ip_protocol")
// tcp/udp/icmp
protected IpProtocol ipProtocol;
@SerializedName(value = "to_port")
protected int toPort;
@SerializedName(value = "parent_group_id")
protected String parentGroupId;
@SerializedName(value = "ip_range") @SerializedName(value = "ip_range")
protected Map<String, String> ipRange; protected final Cidr ipRange;
protected SecurityGroupRule(String id, int fromPort, Map<String, String> group, IpProtocol ipProtocol, int toPort, protected SecurityGroupRule(IpProtocol ipProtocol, int fromPort, int toPort, String id, String parentGroupId,
String parentGroupId, Map<String, String> ipRange) { @Nullable TenantIdAndName group, @Nullable String ipRange) {
this.id = id; super(ipProtocol, fromPort, toPort);
this.fromPort = fromPort; this.parentGroupId = checkNotNull(parentGroupId, "parentGroupId");
this.id = checkNotNull(id, "id");
this.group = group; this.group = group;
this.ipProtocol = ipProtocol; this.ipRange = ipRange != null ? new Cidr(ipRange) : null;
this.toPort = toPort;
this.parentGroupId = parentGroupId;
this.ipRange = ipRange;
}
public String getId() {
return this.id;
}
public int getFromPort() {
return this.fromPort;
}
public Map<String, String> getGroup() {
return this.group;
}
public IpProtocol getIpProtocol() {
return this.ipProtocol;
}
public int getToPort() {
return this.toPort;
} }
public String getParentGroupId() { public String getParentGroupId() {
return this.parentGroupId; return this.parentGroupId;
} }
public Map<String, String> getIpRange() { public String getId() {
return this.ipRange; return this.id;
} }
@Override @Nullable
public int compareTo(SecurityGroupRule o) { public TenantIdAndName getGroup() {
return this.id.compareTo(o.getId()); if (this.group == null || this.group.getName() == null)
return null;
return this.group;
}
@Nullable
public String getIpRange() {
return this.ipRange == null ? null : ipRange.cidr;
} }
@Override @Override
@ -213,9 +203,9 @@ public class SecurityGroupRule implements Comparable<SecurityGroupRule> {
@Override @Override
public String toString() { public String toString() {
return toStringHelper("").add("id", id).add("fromPort", fromPort).add("group", group) return toStringHelper("").add("id", id).add("fromPort", fromPort).add("group", getGroup()).add("ipProtocol",
.add("ipProtocol", ipProtocol).add("toPort", toPort).add("parentGroupId", parentGroupId) ipProtocol).add("toPort", toPort).add("parentGroupId", parentGroupId).add("ipRange", getIpRange())
.add("ipRange", ipRange).toString(); .toString();
} }
} }

View File

@ -0,0 +1,74 @@
/**
* 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.openstack.nova.v1_1.domain;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
import com.google.gson.annotations.SerializedName;
/**
*
* @author Adrian Cole
*/
public class TenantIdAndName {
@SerializedName("tenant_id")
protected final String tenantId;
protected final String name;
public TenantIdAndName(String tenantId, String name) {
this.tenantId = checkNotNull(tenantId, "tenantId");
this.name = checkNotNull(name, "name");
}
public String getTenantId() {
return tenantId;
}
public String getName() {
return name;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
TenantIdAndName that = TenantIdAndName.class.cast(o);
return equal(this.tenantId, that.tenantId) && equal(this.name, that.name);
}
@Override
public int hashCode() {
return Objects.hashCode(tenantId, name);
}
@Override
public String toString() {
return string().toString();
}
protected ToStringHelper string() {
return Objects.toStringHelper("").add("tenantId", tenantId).add("name", name);
}
}

View File

@ -72,15 +72,15 @@ public interface SecurityGroupClient {
* *
* @return a new Security Group Rule * @return a new Security Group Rule
*/ */
SecurityGroupRule createSecurityGroupRuleAllowingCidrBlock(String parent_group_id, Ingress ip_protocol, String cidr); SecurityGroupRule createSecurityGroupRuleAllowingCidrBlock(String parentGroup, Ingress ingress, String sourceCidr);
/** /**
* Create a Security Group Rule. * Create a Security Group Rule.
* *
* @return a new Security Group Rule * @return a new Security Group Rule
*/ */
SecurityGroupRule createSecurityGroupRuleAllowingSecurityGroupId(String group_id, Ingress ip_protocol, SecurityGroupRule createSecurityGroupRuleAllowingSecurityGroupId(String parentGroup, Ingress ingress,
String parent_group_id); String sourceCidr);
/** /**
* Delete a Security Group Rule. * Delete a Security Group Rule.

View File

@ -0,0 +1,86 @@
/**
* 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.openstack.nova.v1_1.predicates;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Resource;
import javax.inject.Singleton;
import org.jclouds.logging.Logger;
import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.compute.domain.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneAndName;
import org.jclouds.openstack.nova.v1_1.domain.SecurityGroup;
import org.jclouds.openstack.nova.v1_1.extensions.SecurityGroupClient;
import org.jclouds.rest.ResourceNotFoundException;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.inject.Inject;
/**
* AtomicReference is so that we can return the securityGroup that matched.
*
* @author Adrian Cole
*/
@Singleton
public class FindSecurityGroupWithNameAndReturnTrue implements Predicate<AtomicReference<ZoneAndName>> {
private final NovaClient novaClient;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public FindSecurityGroupWithNameAndReturnTrue(NovaClient novaClient) {
this.novaClient = checkNotNull(novaClient, "novaClient");
}
public boolean apply(AtomicReference<ZoneAndName> securityGroupInZoneRef) {
checkNotNull(securityGroupInZoneRef, "securityGroupRef");
final ZoneAndName securityGroupInZone = checkNotNull(securityGroupInZoneRef.get(), "securityGroupInZone");
Optional<SecurityGroupClient> client = novaClient.getSecurityGroupExtensionForZone(securityGroupInZone.getZone());
checkArgument(client.isPresent(), "Security groups are required, but the extension is not available!");
logger.trace("looking for security group %s", securityGroupInZone.slashEncode());
try {
SecurityGroup returnVal = Iterables.find(client.get().listSecurityGroups(), new Predicate<SecurityGroup>() {
@Override
public boolean apply(SecurityGroup input) {
return input.getName().equals(securityGroupInZone.getName());
}
});
securityGroupInZoneRef.set(new SecurityGroupInZone(returnVal, securityGroupInZone.getZone()));
return true;
} catch (ResourceNotFoundException e) {
return false;
} catch (NoSuchElementException e) {
return false;
}
}
}

View File

@ -24,6 +24,12 @@ package org.jclouds.openstack.nova.v1_1.reference;
* @author Adam Lowe * @author Adam Lowe
*/ */
public class NovaConstants { public class NovaConstants {
/**
* Eventual consistency delay for retrieving a security group after it is created (in ms)
*/
public static final String PROPERTY_NOVA_TIMEOUT_SECURITYGROUP_PRESENT = "jclouds.openstack-nova.timeout.securitygroup-present";
/** /**
* Whenever a node is created, automatically allocate and assign a floating ip address, also * Whenever a node is created, automatically allocate and assign a floating ip address, also
* deallocate when the node is destroyed. * deallocate when the node is destroyed.

View File

@ -36,7 +36,6 @@ import org.jclouds.openstack.nova.v1_1.parse.ParseSecurityGroupListTest;
import org.jclouds.openstack.nova.v1_1.parse.ParseSecurityGroupTest; import org.jclouds.openstack.nova.v1_1.parse.ParseSecurityGroupTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
@ -233,8 +232,8 @@ public class SecurityGroupClientExpectTest extends BaseNovaClientExpectTest {
} }
private SecurityGroupRule createSecurityGroupRuleExpected() { private SecurityGroupRule createSecurityGroupRuleExpected() {
return SecurityGroupRule.builder().fromPort(80).group(ImmutableMap.<String, String> of()).id("218").ipProtocol( return SecurityGroupRule.builder().fromPort(80).id("218").ipProtocol(
IpProtocol.TCP).ipRange(ImmutableMap.of("cidr", "0.0.0.0/0")).parentGroupId("161").toPort(8080).build(); IpProtocol.TCP).ipRange("0.0.0.0/0").parentGroupId("161").toPort(8080).build();
} }
} }

View File

@ -29,6 +29,8 @@ import org.jclouds.openstack.nova.v1_1.domain.SecurityGroupRule;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientLiveTest; import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientLiveTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
/** /**
* Tests behavior of {@code SecurityGroupClient} * Tests behavior of {@code SecurityGroupClient}
* *
@ -73,20 +75,20 @@ public class SecurityGroupClientLiveTest extends BaseNovaClientLiveTest {
SecurityGroup securityGroup = null; SecurityGroup securityGroup = null;
try { try {
securityGroup = client securityGroup = client.createSecurityGroupWithNameAndDescription(SECURITY_GROUP_NAME, "test security group");
.createSecurityGroupWithNameAndDescription(SECURITY_GROUP_NAME, "test security group");
assertNotNull(securityGroup); assertNotNull(securityGroup);
SecurityGroupRule rule = client.createSecurityGroupRuleAllowingCidrBlock(securityGroup.getId(), Ingress for (int port : ImmutableSet.of(22, 8080)) {
.builder().ipProtocol(IpProtocol.TCP).fromPort(443).toPort(443).build(), "0.0.0.0/0"); SecurityGroupRule rule = client.createSecurityGroupRuleAllowingCidrBlock(securityGroup.getId(), Ingress
assertNotNull(rule); .builder().ipProtocol(IpProtocol.TCP).fromPort(port).toPort(port).build(), "0.0.0.0/0");
assertNotNull(rule);
SecurityGroupRule rule2 = client.createSecurityGroupRuleAllowingSecurityGroupId(securityGroup.getId(), SecurityGroupRule rule2 = client.createSecurityGroupRuleAllowingSecurityGroupId(securityGroup.getId(),
Ingress.builder().ipProtocol(IpProtocol.TCP).fromPort(443).toPort(443).build(), securityGroup Ingress.builder().ipProtocol(IpProtocol.TCP).fromPort(port).toPort(port).build(), securityGroup
.getId()); .getId());
assertNotNull(rule2);
assertNotNull(rule2);
}
securityGroup = client.getSecurityGroup(securityGroup.getId()); securityGroup = client.getSecurityGroup(securityGroup.getId());
} finally { } finally {

View File

@ -0,0 +1,134 @@
/**
* 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.openstack.nova.v1_1.functions;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.compute.domain.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneSecurityGroupNameAndPorts;
import org.jclouds.openstack.nova.v1_1.compute.functions.CreateSecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientExpectTest;
import org.jclouds.openstack.nova.v1_1.parse.ParseComputeServiceTypicalSecurityGroupTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableMap.Builder;
/**
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "CreateSecurityGroupInZoneExpectTest")
public class CreateSecurityGroupInZoneExpectTest extends BaseNovaClientExpectTest {
public void testUpdateReferenceWhenSecurityGroupListContainsGroupName() throws Exception {
Builder<HttpRequest, HttpResponse> builder = ImmutableMap.<HttpRequest, HttpResponse>builder();
builder.put(keystoneAuthWithAccessKeyAndSecretKey, responseWithKeystoneAccess);
builder.put(extensionsOfNovaRequest, extensionsOfNovaResponse);
HttpRequest createSecurityGroup = HttpRequest.builder().method("POST").endpoint(
URI.create("https://compute.north.host/v1.1/3456/os-security-groups")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build())
.payload(
payloadFromStringWithContentType(
"{\"security_group\":{\"name\":\"jclouds#mygroup\",\"description\":\"jclouds#mygroup\"}}",
"application/json")).build();
int groupId = 2769;
HttpResponse createSecurityGroupResponse = HttpResponse.builder().statusCode(200)
.payload(
payloadFromStringWithContentType(
String.format("{\"security_group\": {\"rules\": [], \"tenant_id\": \"37936628937291\", \"id\": %s, \"name\": \"jclouds#mygroup\", \"description\": \"jclouds#mygroup\"}}", groupId),
"application/json; charset=UTF-8")).build();
builder.put(createSecurityGroup, createSecurityGroupResponse);
int ruleId = 10331;
for (int port : ImmutableList.of(22,8080)){
HttpRequest createCidrRule = HttpRequest.builder().method("POST").endpoint(
URI.create("https://compute.north.host/v1.1/3456/os-security-group-rules")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build())
.payload(
payloadFromStringWithContentType(
String.format("{\"security_group_rule\":{\"parent_group_id\":\"%s\",\"cidr\":\"0.0.0.0/0\",\"ip_protocol\":\"tcp\",\"from_port\":\"%d\",\"to_port\":\"%d\"}}",
groupId, port, port), "application/json")).build();
HttpResponse createCidrRuleResponse = HttpResponse.builder().statusCode(200)
.payload(
payloadFromStringWithContentType(
String.format("{\"security_group_rule\": {\"from_port\": %d, \"group\": {}, \"ip_protocol\": \"tcp\", \"to_port\": %d, \"parent_group_id\": %d, \"ip_range\": {\"cidr\": \"0.0.0.0/0\"}, \"id\": %d}}",
port, port, groupId, ruleId++), "application/json; charset=UTF-8")).build();
builder.put(createCidrRule, createCidrRuleResponse);
HttpRequest createSelfRule = HttpRequest.builder().method("POST").endpoint(
URI.create("https://compute.north.host/v1.1/3456/os-security-group-rules")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build())
.payload(
payloadFromStringWithContentType(
String.format("{\"security_group_rule\":{\"group_id\":\"%d\",\"parent_group_id\":\"%d\",\"ip_protocol\":\"tcp\",\"from_port\":\"%d\",\"to_port\":\"%d\"}}",
groupId, groupId, port, port), "application/json")).build();
// note server responds with group name in the rule!!
HttpResponse createSelfRuleResponse = HttpResponse.builder().statusCode(200)
.payload(
payloadFromStringWithContentType(
String.format("{\"security_group_rule\": {\"from_port\": %d, \"group\": {\"tenant_id\": \"37936628937291\", \"name\": \"jclouds#mygroup\"}, \"ip_protocol\": \"tcp\", \"to_port\": %d, \"parent_group_id\": %d, \"ip_range\": {}, \"id\": %d}}",
port, port, groupId, ruleId++), "application/json; charset=UTF-8")).build();
builder.put(createSelfRule, createSelfRuleResponse);
}
HttpRequest getSecurityGroup = HttpRequest.builder().method("GET").endpoint(
URI.create("https://compute.north.host/v1.1/3456/os-security-groups/"+groupId)).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build();
HttpResponse getSecurityGroupResponse = HttpResponse.builder().statusCode(200).payload(
payloadFromResource("/securitygroup_details_computeservice_typical.json")).build();
builder.put(getSecurityGroup, getSecurityGroupResponse);
NovaClient clientWhenSecurityGroupsExist = requestsSendResponses(builder.build());
CreateSecurityGroupInZone fn = new CreateSecurityGroupInZone(clientWhenSecurityGroupsExist);
// we can find it
assertEquals(fn.apply(
new ZoneSecurityGroupNameAndPorts("az-1.region-a.geo-1", "jclouds#mygroup", ImmutableList.of(22, 8080)))
.toString(), new SecurityGroupInZone(new ParseComputeServiceTypicalSecurityGroupTest().expected(),
"az-1.region-a.geo-1").toString());
}
}

View File

@ -0,0 +1,103 @@
/**
* 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.openstack.nova.v1_1.functions;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import java.net.URI;
import java.util.concurrent.atomic.AtomicReference;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.compute.domain.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneAndName;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientExpectTest;
import org.jclouds.openstack.nova.v1_1.parse.ParseSecurityGroupListTest;
import org.jclouds.openstack.nova.v1_1.predicates.FindSecurityGroupWithNameAndReturnTrue;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Iterables;
/**
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "FindSecurityGroupWithNameAndReturnTrueExpectTest")
public class FindSecurityGroupWithNameAndReturnTrueExpectTest extends BaseNovaClientExpectTest {
public void testUpdateReferenceWhenSecurityGroupListContainsGroupName() throws Exception {
HttpRequest listSecurityGroups = HttpRequest.builder().method("GET").endpoint(
URI.create("https://compute.north.host/v1.1/3456/os-security-groups")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build();
HttpResponse listSecurityGroupsResponse = HttpResponse.builder().statusCode(200).payload(
payloadFromResource("/securitygroup_list.json")).build();
NovaClient clientWhenSecurityGroupsExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, listSecurityGroups,
listSecurityGroupsResponse);
FindSecurityGroupWithNameAndReturnTrue predicate = new FindSecurityGroupWithNameAndReturnTrue(
clientWhenSecurityGroupsExist);
AtomicReference<ZoneAndName> securityGroupInZoneRef = new AtomicReference<ZoneAndName>(ZoneAndName
.fromZoneAndName("az-1.region-a.geo-1", "name1"));
// we can find it
assertTrue(predicate.apply(securityGroupInZoneRef));
// the reference is now up to date, and includes the actual group found.
assertEquals(securityGroupInZoneRef.get().toString(), new SecurityGroupInZone(Iterables
.getOnlyElement(new ParseSecurityGroupListTest().expected()), "az-1.region-a.geo-1").toString());
}
public void testDoesNotUpdateReferenceWhenSecurityGroupListMissingGroupName() throws Exception {
HttpRequest listSecurityGroups = HttpRequest.builder().method("GET").endpoint(
URI.create("https://compute.north.host/v1.1/3456/os-security-groups")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build();
HttpResponse listSecurityGroupsResponse = HttpResponse.builder().statusCode(200).payload(
payloadFromResource("/securitygroup_list.json")).build();
NovaClient clientWhenSecurityGroupsExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, listSecurityGroups,
listSecurityGroupsResponse);
FindSecurityGroupWithNameAndReturnTrue predicate = new FindSecurityGroupWithNameAndReturnTrue(
clientWhenSecurityGroupsExist);
ZoneAndName zoneAndGroup = ZoneAndName.fromZoneAndName("az-1.region-a.geo-1", "name2");
AtomicReference<ZoneAndName> securityGroupInZoneRef = new AtomicReference<ZoneAndName>(zoneAndGroup);
// we cannot find it
assertFalse(predicate.apply(securityGroupInZoneRef));
// the reference is the same
assertEquals(securityGroupInZoneRef.get(), zoneAndGroup);
}
}

View File

@ -0,0 +1,78 @@
/**
* 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.openstack.nova.v1_1.parse;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.json.BaseItemParserTest;
import org.jclouds.json.config.GsonModule;
import org.jclouds.openstack.nova.v1_1.config.NovaParserModule;
import org.jclouds.openstack.nova.v1_1.domain.IpProtocol;
import org.jclouds.openstack.nova.v1_1.domain.SecurityGroup;
import org.jclouds.openstack.nova.v1_1.domain.SecurityGroupRule;
import org.jclouds.openstack.nova.v1_1.domain.TenantIdAndName;
import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ParseSecurityGroupTest")
public class ParseComputeServiceTypicalSecurityGroupTest extends BaseItemParserTest<SecurityGroup> {
@Override
public String resource() {
return "/securitygroup_details_computeservice_typical.json";
}
@Override
@SelectJson("security_group")
@Consumes(MediaType.APPLICATION_JSON)
public SecurityGroup expected() {
Set<SecurityGroupRule> securityGroupRules = ImmutableSet.<SecurityGroupRule> of(
SecurityGroupRule.builder().fromPort(22)
.ipProtocol(IpProtocol.TCP).toPort(22).parentGroupId("2769")
.ipRange("0.0.0.0/0").id("10331").build(),
SecurityGroupRule.builder().fromPort(22).group(new TenantIdAndName("37936628937291", "jclouds#mygroup"))
.ipProtocol(IpProtocol.TCP).toPort(22).parentGroupId("2769")
.id("10332").build(),
SecurityGroupRule.builder().fromPort(8080)
.ipProtocol(IpProtocol.TCP).toPort(8080).parentGroupId("2769")
.ipRange("0.0.0.0/0").id("10333").build(),
SecurityGroupRule.builder().fromPort(8080).group(new TenantIdAndName("37936628937291", "jclouds#mygroup"))
.ipProtocol(IpProtocol.TCP).toPort(8080).parentGroupId("2769")
.id("10334").build()
);
return SecurityGroup.builder().description("jclouds#mygroup").id("2769").tenantId("37936628937291").rules(securityGroupRules)
.name("jclouds#mygroup").build();
}
protected Injector injector() {
return Guice.createInjector(new NovaParserModule(), new GsonModule());
}
}

View File

@ -18,8 +18,6 @@
*/ */
package org.jclouds.openstack.nova.v1_1.parse; package org.jclouds.openstack.nova.v1_1.parse;
import java.util.HashMap;
import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
@ -34,7 +32,6 @@ import org.jclouds.openstack.nova.v1_1.domain.SecurityGroupRule;
import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
@ -56,17 +53,15 @@ public class ParseSecurityGroupListTest extends BaseSetParserTest<SecurityGroup>
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Set<SecurityGroup> expected() { public Set<SecurityGroup> expected() {
Map<String, String> anyCidr = ImmutableMap.<String, String> of("cidr", "0.0.0.0/0");
Set<SecurityGroupRule> securityGroupRules = ImmutableSet.<SecurityGroupRule> of( Set<SecurityGroupRule> securityGroupRules = ImmutableSet.<SecurityGroupRule> of(
SecurityGroupRule.builder().fromPort(22).group(new HashMap<String, String>()) SecurityGroupRule.builder().fromPort(22)
.ipProtocol(IpProtocol.TCP).toPort(22).parentGroupId("3").ipRange(anyCidr) .ipProtocol(IpProtocol.TCP).toPort(22).parentGroupId("3").ipRange("0.0.0.0/0")
.id("107").build(), .id("107").build(),
SecurityGroupRule.builder().fromPort(7600).group(new HashMap<String, String>()) SecurityGroupRule.builder().fromPort(7600)
.ipProtocol(IpProtocol.TCP).toPort(7600).parentGroupId("3").ipRange(anyCidr) .ipProtocol(IpProtocol.TCP).toPort(7600).parentGroupId("3").ipRange("0.0.0.0/0")
.id("118").build(), .id("118").build(),
SecurityGroupRule.builder().fromPort(8084).group(new HashMap<String, String>()) SecurityGroupRule.builder().fromPort(8084)
.ipProtocol(IpProtocol.TCP).toPort(8084).parentGroupId("3").ipRange(anyCidr) .ipProtocol(IpProtocol.TCP).toPort(8084).parentGroupId("3").ipRange("0.0.0.0/0")
.id("119").build()); .id("119").build());
return ImmutableSet.of(SecurityGroup.builder().description("description1").id("1").tenantId("tenant1") return ImmutableSet.of(SecurityGroup.builder().description("description1").id("1").tenantId("tenant1")

View File

@ -18,7 +18,6 @@
*/ */
package org.jclouds.openstack.nova.v1_1.parse; package org.jclouds.openstack.nova.v1_1.parse;
import java.util.HashMap;
import java.util.Set; import java.util.Set;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
@ -30,10 +29,10 @@ import org.jclouds.openstack.nova.v1_1.config.NovaParserModule;
import org.jclouds.openstack.nova.v1_1.domain.IpProtocol; import org.jclouds.openstack.nova.v1_1.domain.IpProtocol;
import org.jclouds.openstack.nova.v1_1.domain.SecurityGroup; import org.jclouds.openstack.nova.v1_1.domain.SecurityGroup;
import org.jclouds.openstack.nova.v1_1.domain.SecurityGroupRule; import org.jclouds.openstack.nova.v1_1.domain.SecurityGroupRule;
import org.jclouds.openstack.nova.v1_1.domain.TenantIdAndName;
import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
@ -44,7 +43,6 @@ import com.google.inject.Injector;
*/ */
@Test(groups = "unit", testName = "ParseSecurityGroupTest") @Test(groups = "unit", testName = "ParseSecurityGroupTest")
public class ParseSecurityGroupTest extends BaseItemParserTest<SecurityGroup> { public class ParseSecurityGroupTest extends BaseItemParserTest<SecurityGroup> {
@Override @Override
public String resource() { public String resource() {
return "/securitygroup_details.json"; return "/securitygroup_details.json";
@ -56,12 +54,12 @@ public class ParseSecurityGroupTest extends BaseItemParserTest<SecurityGroup> {
public SecurityGroup expected() { public SecurityGroup expected() {
Set<SecurityGroupRule> securityGroupRules = ImmutableSet.<SecurityGroupRule> of( Set<SecurityGroupRule> securityGroupRules = ImmutableSet.<SecurityGroupRule> of(
SecurityGroupRule.builder().fromPort(22).group(new HashMap<String, String>()) SecurityGroupRule.builder().fromPort(22)
.ipProtocol(IpProtocol.TCP).toPort(22).parentGroupId("28") .ipProtocol(IpProtocol.TCP).toPort(22).parentGroupId("28")
.ipRange(ImmutableMap.of("cidr", "10.2.6.0/24")).id("108").build(), .ipRange("10.2.6.0/24").id("108").build(),
SecurityGroupRule.builder().fromPort(22).group(ImmutableMap.of("tenant_id", "admin", "name", "11111")) SecurityGroupRule.builder().fromPort(22).group(new TenantIdAndName("admin", "11111"))
.ipProtocol(IpProtocol.TCP).toPort(22).parentGroupId("28") .ipProtocol(IpProtocol.TCP).toPort(22).parentGroupId("28")
.ipRange(new HashMap<String, String>()).id("109").build()); .id("109").build());
return SecurityGroup.builder().description("description0").id("0").tenantId("tenant0").rules(securityGroupRules) return SecurityGroup.builder().description("description0").id("0").tenantId("tenant0").rules(securityGroupRules)
.name("name0").build(); .name("name0").build();

View File

@ -0,0 +1,51 @@
{
"security_group": {
"rules": [{
"from_port": 22,
"group": {},
"ip_protocol": "tcp",
"to_port": 22,
"parent_group_id": 2769,
"ip_range": {
"cidr": "0.0.0.0/0"
},
"id": 10331
}, {
"from_port": 22,
"group": {
"tenant_id": "37936628937291",
"name": "jclouds#mygroup"
},
"ip_protocol": "tcp",
"to_port": 22,
"parent_group_id": 2769,
"ip_range": {},
"id": 10332
}, {
"from_port": 8080,
"group": {},
"ip_protocol": "tcp",
"to_port": 8080,
"parent_group_id": 2769,
"ip_range": {
"cidr": "0.0.0.0/0"
},
"id": 10333
}, {
"from_port": 8080,
"group": {
"tenant_id": "37936628937291",
"name": "jclouds#mygroup"
},
"ip_protocol": "tcp",
"to_port": 8080,
"parent_group_id": 2769,
"ip_range": {},
"id": 10334
}],
"tenant_id": "37936628937291",
"id": 2769,
"name": "jclouds#mygroup",
"description": "jclouds#mygroup"
}
}