From 389ba6c94a44b3e1331dfa4be5f159f6e5e33bae Mon Sep 17 00:00:00 2001 From: Andrew Bayer Date: Fri, 13 Sep 2013 10:31:02 -0700 Subject: [PATCH] JCLOUDS-267. Add SecurityGroupExtension support for Nova. --- .../NovaComputeServiceContextModule.java | 16 +- .../NovaSecurityGroupExtension.java | 422 +++++++++++++++++ ...ovaSecurityGroupInZoneToSecurityGroup.java | 73 +++ .../NovaSecurityGroupToSecurityGroup.java | 13 +- .../loaders/FindSecurityGroupOrCreate.java | 3 +- .../zonescoped/SecurityGroupInZone.java | 2 +- .../v2_0/extensions/SecurityGroupApi.java | 2 +- .../predicates/SecurityGroupPredicates.java | 139 +++++- .../NovaSecurityGroupExtensionExpectTest.java | 423 ++++++++++++++++++ .../NovaSecurityGroupExtensionLiveTest.java | 35 ++ ...ecurityGroupInZoneToSecurityGroupTest.java | 93 ++++ .../NovaSecurityGroupToSecurityGroupTest.java | 89 ++-- .../SecurityGroupPredicatesTest.java | 93 +++- .../securitygroup_details_extension.json | 34 ++ ...curitygroup_details_extension_norules.json | 10 + .../securitygroup_list_extension.json | 51 +++ .../securitygrouprule_created_cidr.json | 13 + .../securitygrouprule_created_group.json | 14 + ...server_with_security_groups_extension.json | 1 + 19 files changed, 1467 insertions(+), 59 deletions(-) create mode 100644 apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtension.java create mode 100644 apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInZoneToSecurityGroup.java create mode 100644 apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtensionExpectTest.java create mode 100644 apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtensionLiveTest.java create mode 100644 apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInZoneToSecurityGroupTest.java create mode 100644 apis/openstack-nova/src/test/resources/securitygroup_details_extension.json create mode 100644 apis/openstack-nova/src/test/resources/securitygroup_details_extension_norules.json create mode 100644 apis/openstack-nova/src/test/resources/securitygroup_list_extension.json create mode 100644 apis/openstack-nova/src/test/resources/securitygrouprule_created_cidr.json create mode 100644 apis/openstack-nova/src/test/resources/securitygrouprule_created_group.json create mode 100644 apis/openstack-nova/src/test/resources/server_with_security_groups_extension.json diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/config/NovaComputeServiceContextModule.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/config/NovaComputeServiceContextModule.java index 57a341dd8b..311d4abf24 100644 --- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/config/NovaComputeServiceContextModule.java +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/config/NovaComputeServiceContextModule.java @@ -40,6 +40,7 @@ import org.jclouds.compute.domain.OperatingSystem; import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.SecurityGroup; import org.jclouds.compute.extensions.ImageExtension; +import org.jclouds.compute.extensions.SecurityGroupExtension; import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet; import org.jclouds.domain.Location; @@ -49,10 +50,12 @@ import org.jclouds.net.domain.IpPermission; import org.jclouds.openstack.nova.v2_0.compute.NovaComputeService; import org.jclouds.openstack.nova.v2_0.compute.NovaComputeServiceAdapter; import org.jclouds.openstack.nova.v2_0.compute.extensions.NovaImageExtension; +import org.jclouds.openstack.nova.v2_0.compute.extensions.NovaSecurityGroupExtension; import org.jclouds.openstack.nova.v2_0.compute.functions.CreateSecurityGroupIfNeeded; import org.jclouds.openstack.nova.v2_0.compute.functions.FlavorInZoneToHardware; import org.jclouds.openstack.nova.v2_0.compute.functions.ImageInZoneToImage; import org.jclouds.openstack.nova.v2_0.compute.functions.ImageToOperatingSystem; +import org.jclouds.openstack.nova.v2_0.compute.functions.NovaSecurityGroupInZoneToSecurityGroup; import org.jclouds.openstack.nova.v2_0.compute.functions.NovaSecurityGroupToSecurityGroup; import org.jclouds.openstack.nova.v2_0.compute.functions.OrphanedGroupsByZoneId; import org.jclouds.openstack.nova.v2_0.compute.functions.SecurityGroupRuleToIpPermission; @@ -119,6 +122,9 @@ public class NovaComputeServiceContextModule extends bind(new TypeLiteral>() { }).to(NovaSecurityGroupToSecurityGroup.class); + bind(new TypeLiteral>() { + }).to(NovaSecurityGroupInZoneToSecurityGroup.class); + bind(new TypeLiteral, Multimap>>() { }).to(OrphanedGroupsByZoneId.class); @@ -153,6 +159,9 @@ public class NovaComputeServiceContextModule extends bind(new TypeLiteral() { }).to(NovaImageExtension.class); + + bind(new TypeLiteral() { + }).to(NovaSecurityGroupExtension.class); } @Override @@ -187,7 +196,7 @@ public class NovaComputeServiceContextModule extends @Provides @Singleton - @Named(TIMEOUT_SECURITYGROUP_PRESENT) + @Named("SECURITYGROUP_PRESENT") protected Predicate> securityGroupEventualConsistencyDelay( FindSecurityGroupWithNameAndReturnTrue in, @Named(TIMEOUT_SECURITYGROUP_PRESENT) long msDelay) { @@ -269,4 +278,9 @@ public class NovaComputeServiceContextModule extends protected Optional provideImageExtension(Injector i) { return Optional.of(i.getInstance(ImageExtension.class)); } + + @Override + protected Optional provideSecurityGroupExtension(Injector i) { + return Optional.of(i.getInstance(SecurityGroupExtension.class)); + } } diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtension.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtension.java new file mode 100644 index 0000000000..416e3a9647 --- /dev/null +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtension.java @@ -0,0 +1,422 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.v2_0.compute.extensions; + + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Predicates.and; +import static com.google.common.base.Predicates.notNull; +import static com.google.common.collect.Iterables.concat; +import static com.google.common.collect.Iterables.filter; +import static com.google.common.collect.Iterables.transform; +import static org.jclouds.openstack.nova.v2_0.predicates.SecurityGroupPredicates.nameIn; +import static org.jclouds.openstack.nova.v2_0.predicates.SecurityGroupPredicates.ruleCidr; +import static org.jclouds.openstack.nova.v2_0.predicates.SecurityGroupPredicates.ruleEndPort; +import static org.jclouds.openstack.nova.v2_0.predicates.SecurityGroupPredicates.ruleGroup; +import static org.jclouds.openstack.nova.v2_0.predicates.SecurityGroupPredicates.ruleProtocol; +import static org.jclouds.openstack.nova.v2_0.predicates.SecurityGroupPredicates.ruleStartPort; + +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.jclouds.Constants; +import org.jclouds.compute.domain.SecurityGroup; +import org.jclouds.compute.extensions.SecurityGroupExtension; +import org.jclouds.compute.functions.GroupNamingConvention; +import org.jclouds.domain.Location; +import org.jclouds.location.Zone; +import org.jclouds.net.domain.IpPermission; +import org.jclouds.net.domain.IpProtocol; +import org.jclouds.openstack.nova.v2_0.NovaApi; +import org.jclouds.openstack.nova.v2_0.domain.Ingress; +import org.jclouds.openstack.nova.v2_0.domain.SecurityGroupRule; +import org.jclouds.openstack.nova.v2_0.domain.ServerWithSecurityGroups; +import org.jclouds.openstack.nova.v2_0.domain.zonescoped.SecurityGroupInZone; +import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneAndId; +import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneAndName; +import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneSecurityGroupNameAndPorts; +import org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupApi; +import org.jclouds.openstack.nova.v2_0.extensions.ServerWithSecurityGroupsApi; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Supplier; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Multimap; +import com.google.common.util.concurrent.ListeningExecutorService; + +/** + * An extension to compute service to allow for the manipulation of {@link org.jclouds.compute.domain.SecurityGroup}s. Implementation + * is optional by providers. + * + * @author Andrew Bayer + */ +public class NovaSecurityGroupExtension implements SecurityGroupExtension { + + protected final NovaApi api; + protected final ListeningExecutorService userExecutor; + protected final Supplier> zoneIds; + protected final Function groupConverter; + protected final LoadingCache groupCreator; + protected final GroupNamingConvention.Factory namingConvention; + + @Inject + public NovaSecurityGroupExtension(NovaApi api, + @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, + @Zone Supplier> zoneIds, + Function groupConverter, + LoadingCache groupCreator, + GroupNamingConvention.Factory namingConvention) { + + this.api = checkNotNull(api, "api"); + this.userExecutor = checkNotNull(userExecutor, "userExecutor"); + this.zoneIds = checkNotNull(zoneIds, "zoneIds"); + this.groupConverter = checkNotNull(groupConverter, "groupConverter"); + this.groupCreator = checkNotNull(groupCreator, "groupCreator"); + this.namingConvention = checkNotNull(namingConvention, "namingConvention"); + } + + @Override + public Set listSecurityGroups() { + Iterable rawGroups = pollSecurityGroups(); + Iterable groups = transform(filter(rawGroups, notNull()), + groupConverter); + return ImmutableSet.copyOf(groups); + } + + + @Override + public Set listSecurityGroupsInLocation(final Location location) { + String zone = location.getId(); + if (zone == null) { + return ImmutableSet.of(); + } + return listSecurityGroupsInLocation(zone); + } + + public Set listSecurityGroupsInLocation(String zone) { + Iterable rawGroups = pollSecurityGroupsByZone(zone); + Iterable groups = transform(filter(rawGroups, notNull()), + groupConverter); + return ImmutableSet.copyOf(groups); + } + + @Override + public Set listSecurityGroupsForNode(String id) { + ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(checkNotNull(id, "id")); + String zone = zoneAndId.getZone(); + String instanceId = zoneAndId.getId(); + + Optional serverApi = api.getServerWithSecurityGroupsExtensionForZone(zone); + Optional sgApi = api.getSecurityGroupExtensionForZone(zone); + + if (!serverApi.isPresent() || !sgApi.isPresent()) { + return ImmutableSet.of(); + } + + ServerWithSecurityGroups instance = serverApi.get().get(instanceId); + if (instance == null) { + return ImmutableSet.of(); + } + + Set groupNames = instance.getSecurityGroupNames(); + Set rawGroups = + sgApi.get().list().filter(nameIn(groupNames)).transform(groupToGroupInZone(zone)).toSet(); + + return ImmutableSet.copyOf(transform(filter(rawGroups, notNull()), groupConverter)); + } + + @Override + public SecurityGroup getSecurityGroupById(String id) { + ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(checkNotNull(id, "id")); + String zone = zoneAndId.getZone(); + String groupId = zoneAndId.getId(); + + Optional sgApi = api.getSecurityGroupExtensionForZone(zone); + + if (!sgApi.isPresent()) { + return null; + } + + SecurityGroupInZone rawGroup = new SecurityGroupInZone(sgApi.get().get(groupId), zone); + + return groupConverter.apply(rawGroup); + } + + @Override + public SecurityGroup createSecurityGroup(String name, Location location) { + String zone = location.getId(); + if (zone == null) { + return null; + } + return createSecurityGroup(name, zone); + } + + public SecurityGroup createSecurityGroup(String name, String zone) { + String markerGroup = namingConvention.create().sharedNameForGroup(name); + ZoneSecurityGroupNameAndPorts zoneAndName = new ZoneSecurityGroupNameAndPorts(zone, markerGroup, ImmutableSet. of()); + + SecurityGroupInZone rawGroup = groupCreator.apply(zoneAndName); + return groupConverter.apply(rawGroup); + } + + @Override + public boolean removeSecurityGroup(String id) { + checkNotNull(id, "id"); + ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(id); + String zone = zoneAndId.getZone(); + String groupId = zoneAndId.getId(); + + Optional sgApi = api.getSecurityGroupExtensionForZone(zone); + + if (!sgApi.isPresent()) { + return false; + } + + if (sgApi.get().get(groupId) == null) { + return false; + } + + sgApi.get().delete(groupId); + // TODO: test this clear happens + groupCreator.invalidate(new ZoneSecurityGroupNameAndPorts(zone, groupId, ImmutableSet. of())); + return true; + } + + @Override + public SecurityGroup addIpPermission(IpPermission ipPermission, SecurityGroup group) { + String zone = group.getLocation().getId(); + String id = group.getId(); + + Optional sgApi = api.getSecurityGroupExtensionForZone(zone); + + if (!sgApi.isPresent()) { + return null; + } + + if (ipPermission.getCidrBlocks().size() > 0) { + for (String cidr : ipPermission.getCidrBlocks()) { + sgApi.get().createRuleAllowingCidrBlock(id, + Ingress.builder() + .ipProtocol(ipPermission.getIpProtocol()) + .fromPort(ipPermission.getFromPort()) + .toPort(ipPermission.getToPort()) + .build(), + cidr); + } + } + + if (ipPermission.getGroupIds().size() > 0) { + for (String zoneAndGroupRaw : ipPermission.getGroupIds()) { + ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(zoneAndGroupRaw); + String groupId = zoneAndId.getId(); + sgApi.get().createRuleAllowingSecurityGroupId(id, + Ingress.builder() + .ipProtocol(ipPermission.getIpProtocol()) + .fromPort(ipPermission.getFromPort()) + .toPort(ipPermission.getToPort()) + .build(), + groupId); + } + } + + return getSecurityGroupById(ZoneAndId.fromZoneAndId(zone, id).slashEncode()); + } + + @Override + public SecurityGroup addIpPermission(IpProtocol protocol, int startPort, int endPort, + Multimap tenantIdGroupNamePairs, + Iterable ipRanges, + Iterable groupIds, SecurityGroup group) { + String zone = group.getLocation().getId(); + String id = group.getId(); + + Optional sgApi = api.getSecurityGroupExtensionForZone(zone); + + if (!sgApi.isPresent()) { + return null; + } + + if (Iterables.size(ipRanges) > 0) { + for (String cidr : ipRanges) { + sgApi.get().createRuleAllowingCidrBlock(id, + Ingress.builder() + .ipProtocol(protocol) + .fromPort(startPort) + .toPort(endPort) + .build(), + cidr); + } + } + + if (Iterables.size(groupIds) > 0) { + for (String zoneAndGroupRaw : groupIds) { + ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(zoneAndGroupRaw); + String groupId = zoneAndId.getId(); + sgApi.get().createRuleAllowingSecurityGroupId(id, + Ingress.builder() + .ipProtocol(protocol) + .fromPort(startPort) + .toPort(endPort) + .build(), + groupId); + } + } + + return getSecurityGroupById(ZoneAndId.fromZoneAndId(zone, id).slashEncode()); + } + + @Override + public SecurityGroup removeIpPermission(IpPermission ipPermission, SecurityGroup group) { + String zone = group.getLocation().getId(); + String id = group.getId(); + + Optional sgApi = api.getSecurityGroupExtensionForZone(zone); + + if (!sgApi.isPresent()) { + return null; + } + + org.jclouds.openstack.nova.v2_0.domain.SecurityGroup securityGroup = sgApi.get().get(id); + + if (ipPermission.getCidrBlocks().size() > 0) { + for (String cidr : ipPermission.getCidrBlocks()) { + for (SecurityGroupRule rule : filter(securityGroup.getRules(), + and(ruleCidr(cidr), ruleProtocol(ipPermission.getIpProtocol()), + ruleStartPort(ipPermission.getFromPort()), + ruleEndPort(ipPermission.getToPort())))) { + sgApi.get().deleteRule(rule.getId()); + } + } + } + + if (ipPermission.getGroupIds().size() > 0) { + for (String groupId : ipPermission.getGroupIds()) { + for (SecurityGroupRule rule : filter(securityGroup.getRules(), + and(ruleGroup(groupId), ruleProtocol(ipPermission.getIpProtocol()), + ruleStartPort(ipPermission.getFromPort()), + ruleEndPort(ipPermission.getToPort())))) { + sgApi.get().deleteRule(rule.getId()); + } + + } + } + + return getSecurityGroupById(ZoneAndId.fromZoneAndId(zone, id).slashEncode()); + } + + @Override + public SecurityGroup removeIpPermission(IpProtocol protocol, int startPort, int endPort, + Multimap tenantIdGroupNamePairs, + Iterable ipRanges, + Iterable groupIds, SecurityGroup group) { + String zone = group.getLocation().getId(); + String id = group.getId(); + + Optional sgApi = api.getSecurityGroupExtensionForZone(zone); + + if (!sgApi.isPresent()) { + return null; + } + + org.jclouds.openstack.nova.v2_0.domain.SecurityGroup securityGroup = sgApi.get().get(id); + + if (Iterables.size(ipRanges) > 0) { + for (String cidr : ipRanges) { + for (SecurityGroupRule rule : filter(securityGroup.getRules(), + and(ruleCidr(cidr), + ruleProtocol(protocol), + ruleStartPort(startPort), + ruleEndPort(endPort)))) { + sgApi.get().deleteRule(rule.getId()); + } + } + } + + if (Iterables.size(groupIds) > 0) { + for (String groupId : groupIds) { + for (SecurityGroupRule rule : filter(securityGroup.getRules(), + and(ruleGroup(groupId), + ruleProtocol(protocol), + ruleStartPort(startPort), + ruleEndPort(endPort)))) { + sgApi.get().deleteRule(rule.getId()); + } + } + } + + return getSecurityGroupById(ZoneAndId.fromZoneAndId(zone, id).slashEncode()); + } + + @Override + public boolean supportsTenantIdGroupNamePairs() { + return false; + } + + @Override + public boolean supportsGroupIds() { + return true; + } + + @Override + public boolean supportsPortRangesForGroups() { + return false; + } + + protected Iterable pollSecurityGroups() { + Iterable> groups + = transform(zoneIds.get(), allSecurityGroupsInZone()); + + return concat(groups); + } + + + protected Iterable pollSecurityGroupsByZone(String zone) { + return allSecurityGroupsInZone().apply(zone); + } + + protected Function> allSecurityGroupsInZone() { + return new Function>() { + + @Override + public Set apply(final String from) { + Optional sgApi = api.getSecurityGroupExtensionForZone(from); + + if (!sgApi.isPresent()) { + return ImmutableSet.of(); + } + + + return sgApi.get().list().transform(groupToGroupInZone(from)).toSet(); + } + + }; + } + + protected Function groupToGroupInZone(final String zone) { + return new Function() { + @Override + public SecurityGroupInZone apply(org.jclouds.openstack.nova.v2_0.domain.SecurityGroup group) { + return new SecurityGroupInZone(group, zone); + } + }; + } +} diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInZoneToSecurityGroup.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInZoneToSecurityGroup.java new file mode 100644 index 0000000000..124cd6552e --- /dev/null +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInZoneToSecurityGroup.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.v2_0.compute.functions; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import java.util.Map; + +import javax.annotation.Resource; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.compute.domain.SecurityGroup; +import org.jclouds.compute.domain.SecurityGroupBuilder; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.domain.Location; +import org.jclouds.logging.Logger; +import org.jclouds.openstack.nova.v2_0.domain.zonescoped.SecurityGroupInZone; + +import com.google.common.base.Function; +import com.google.common.base.Supplier; +import com.google.inject.Inject; + + +/** + * A function for transforming a Nova-specific SecurityGroup into a generic + * SecurityGroup object. + * + * @author Andrew Bayer + */ +@Singleton +public class NovaSecurityGroupInZoneToSecurityGroup implements Function { + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + protected final Function baseConverter; + protected final Supplier> locationIndex; + + @Inject + public NovaSecurityGroupInZoneToSecurityGroup(Function baseConverter, + Supplier> locationIndex) { + this.baseConverter = checkNotNull(baseConverter, "baseConverter"); + this.locationIndex = checkNotNull(locationIndex, "locationIndex"); + } + + @Override + public SecurityGroup apply(SecurityGroupInZone group) { + SecurityGroupBuilder builder = SecurityGroupBuilder.fromSecurityGroup(baseConverter.apply(group.getSecurityGroup())); + + Location zone = locationIndex.get().get(group.getZone()); + checkState(zone != null, "location %s not in locationIndex: %s", group.getZone(), locationIndex.get()); + + builder.location(zone); + + return builder.build(); + } +} diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupToSecurityGroup.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupToSecurityGroup.java index 3b70ae7551..d39f849182 100644 --- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupToSecurityGroup.java +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupToSecurityGroup.java @@ -16,12 +16,8 @@ */ package org.jclouds.openstack.nova.v2_0.compute.functions; -import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.Iterables.transform; -import java.util.NoSuchElementException; -import java.util.Set; - import javax.annotation.Resource; import javax.inject.Named; import javax.inject.Singleton; @@ -34,9 +30,6 @@ import org.jclouds.net.domain.IpPermission; import org.jclouds.openstack.nova.v2_0.domain.SecurityGroupRule; import com.google.common.base.Function; -import com.google.common.base.Predicate; -import com.google.common.base.Supplier; -import com.google.common.collect.Iterables; import com.google.inject.Inject; @@ -67,8 +60,10 @@ public class NovaSecurityGroupToSecurityGroup implements Function> returnSecurityGroupExistsInZone, + @Named("SECURITYGROUP_PRESENT") Predicate> returnSecurityGroupExistsInZone, Function groupCreator) { this.returnSecurityGroupExistsInZone = checkNotNull(returnSecurityGroupExistsInZone, "returnSecurityGroupExistsInZone"); diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/zonescoped/SecurityGroupInZone.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/zonescoped/SecurityGroupInZone.java index dd892a25d3..28e2b0f3d3 100644 --- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/zonescoped/SecurityGroupInZone.java +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/zonescoped/SecurityGroupInZone.java @@ -31,7 +31,7 @@ public class SecurityGroupInZone extends ZoneAndName { this.securityGroup = securityGroup; } - public SecurityGroup getServer() { + public SecurityGroup getSecurityGroup() { return securityGroup; } diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupApi.java index 9e8d26094e..867ccd3807 100644 --- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupApi.java +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupApi.java @@ -77,7 +77,7 @@ public interface SecurityGroupApi { * @return a new Security Group Rule */ SecurityGroupRule createRuleAllowingSecurityGroupId(String parentGroup, Ingress ingress, - String sourceCidr); + String groupId); /** * Delete a Security Group Rule. diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/predicates/SecurityGroupPredicates.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/predicates/SecurityGroupPredicates.java index 108618fa7f..412e37f48e 100644 --- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/predicates/SecurityGroupPredicates.java +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/predicates/SecurityGroupPredicates.java @@ -18,9 +18,14 @@ package org.jclouds.openstack.nova.v2_0.predicates; import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Set; + +import org.jclouds.net.domain.IpProtocol; import org.jclouds.openstack.nova.v2_0.domain.SecurityGroup; +import org.jclouds.openstack.nova.v2_0.domain.SecurityGroupRule; import com.google.common.base.Predicate; +import com.google.common.base.Predicates; /** * Predicates handy when working with SecurityGroups @@ -32,7 +37,7 @@ public class SecurityGroupPredicates { /** * matches name of the given security group - * + * * @param name * @return predicate that matches name */ @@ -52,6 +57,28 @@ public class SecurityGroupPredicates { }; } + /** + * matches name of the given security group against a list + * + * @param names + * @return predicate that matches one of the names + */ + public static Predicate nameIn(final Set names) { + checkNotNull(names, "names must be defined"); + + return new Predicate() { + @Override + public boolean apply(SecurityGroup ext) { + return Predicates.in(names).apply(ext.getName()); + } + + @Override + public String toString() { + return "nameIn(" + names + ")"; + } + }; + } + /** * matches name of the given security group * @@ -73,4 +100,114 @@ public class SecurityGroupPredicates { } }; } + + /** + * matches a security group rule by its cidr + * + * @param cidr + * @return predicate that matches cidr + */ + public static Predicate ruleCidr(final String cidr) { + checkNotNull(cidr, "cidr must be defined"); + + return new Predicate() { + @Override + public boolean apply(SecurityGroupRule ext) { + return cidr.equals(ext.getIpRange()); + } + + @Override + public String toString() { + return "cidr(" + cidr + ")"; + } + }; + } + + /** + * matches a security group rule by the security group it allows + * + * @param groupName + * @return predicate that matches group + */ + public static Predicate ruleGroup(final String groupName) { + checkNotNull(groupName, "groupName must be defined"); + + return new Predicate() { + @Override + public boolean apply(SecurityGroupRule ext) { + return ext.getGroup() != null && groupName.equals(ext.getGroup().getName()); + } + + @Override + public String toString() { + return "ruleGroup(" + groupName + ")"; + } + }; + } + + /** + * matches a security group rule by the protocol + * + * @param protocol + * @return predicate that matches protocol + */ + public static Predicate ruleProtocol(final IpProtocol protocol) { + checkNotNull(protocol, "protocol must be defined"); + + return new Predicate() { + @Override + public boolean apply(SecurityGroupRule ext) { + return protocol.equals(ext.getIpProtocol()); + } + + @Override + public String toString() { + return "ruleProtocol(" + protocol + ")"; + } + }; + } + + /** + * matches a security group rule by the start port + * + * @param startPort + * @return predicate that matches startPort + */ + public static Predicate ruleStartPort(final int startPort) { + checkNotNull(startPort, "startPort must be defined"); + + return new Predicate() { + @Override + public boolean apply(SecurityGroupRule ext) { + return startPort == ext.getFromPort(); + } + + @Override + public String toString() { + return "ruleStartPort(" + startPort + ")"; + } + }; + } + + /** + * matches a security group rule by the end port + * + * @param endPort + * @return predicate that matches endPort + */ + public static Predicate ruleEndPort(final int endPort) { + checkNotNull(endPort, "endPort must be defined"); + + return new Predicate() { + @Override + public boolean apply(SecurityGroupRule ext) { + return endPort == ext.getToPort(); + } + + @Override + public String toString() { + return "ruleEndPort(" + endPort + ")"; + } + }; + } } diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtensionExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtensionExpectTest.java new file mode 100644 index 0000000000..b80351ef89 --- /dev/null +++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtensionExpectTest.java @@ -0,0 +1,423 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.v2_0.compute.extensions; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.net.URI; +import java.util.Properties; +import java.util.Set; + +import org.jclouds.compute.domain.SecurityGroup; +import org.jclouds.compute.extensions.SecurityGroupExtension; +import org.jclouds.domain.LocationBuilder; +import org.jclouds.domain.LocationScope; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.net.domain.IpPermission; +import org.jclouds.net.domain.IpProtocol; +import org.jclouds.openstack.nova.v2_0.internal.BaseNovaComputeServiceExpectTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMap.Builder; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; + +/** + * + * @author Andrew Bayer + */ +@Test(groups = "unit", testName = "NovaSecurityGroupExtensionExpectTest") +public class NovaSecurityGroupExtensionExpectTest extends BaseNovaComputeServiceExpectTest { + + protected String zone = "az-1.region-a.geo-1"; + + @Override + protected Properties setupProperties() { + Properties overrides = super.setupProperties(); + overrides.setProperty("jclouds.zones", zone); + return overrides; + } + + public void testListSecurityGroups() { + HttpRequest list = HttpRequest.builder().method("GET").endpoint( + URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups")).headers( + ImmutableMultimap. builder().put("Accept", "application/json").put("X-Auth-Token", + authToken).build()).build(); + + HttpResponse listResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygroup_list.json")).build(); + + + Builder requestResponseMap = ImmutableMap. builder(); + requestResponseMap.put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess); + requestResponseMap.put(extensionsOfNovaRequest, extensionsOfNovaResponse); + requestResponseMap.put(list, listResponse).build(); + + SecurityGroupExtension extension = requestsSendResponses(requestResponseMap.build()).getSecurityGroupExtension().get(); + + Set groups = extension.listSecurityGroups(); + assertEquals(groups.size(), 1); + } + + public void testListSecurityGroupsInLocation() { + HttpRequest list = HttpRequest.builder().method("GET").endpoint( + URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups")).headers( + ImmutableMultimap. builder().put("Accept", "application/json").put("X-Auth-Token", + authToken).build()).build(); + + HttpResponse listResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygroup_list.json")).build(); + + + Builder requestResponseMap = ImmutableMap. builder(); + requestResponseMap.put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess); + requestResponseMap.put(extensionsOfNovaRequest, extensionsOfNovaResponse); + requestResponseMap.put(list, listResponse).build(); + + SecurityGroupExtension extension = requestsSendResponses(requestResponseMap.build()).getSecurityGroupExtension().get(); + + Set groups = extension.listSecurityGroupsInLocation(new LocationBuilder() + .scope(LocationScope.ZONE) + .id(zone) + .description("zone") + .build()); + assertEquals(groups.size(), 1); + } + + public void testListSecurityGroupsForNode() { + HttpRequest serverReq = HttpRequest.builder().method("GET").endpoint( + URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-create-server-ext/8d0a6ca5-8849-4b3d-b86e-f24c92490ebb")) + .headers( + ImmutableMultimap. builder().put("Accept", "application/json").put("X-Auth-Token", + authToken).build()).build(); + + HttpResponse serverResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/server_with_security_groups_extension.json")).build(); + + HttpRequest list = HttpRequest.builder().method("GET").endpoint( + URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups")).headers( + ImmutableMultimap. builder().put("Accept", "application/json").put("X-Auth-Token", + authToken).build()).build(); + + HttpResponse listResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygroup_list.json")).build(); + + + Builder requestResponseMap = ImmutableMap. builder(); + requestResponseMap.put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess); + requestResponseMap.put(extensionsOfNovaRequest, extensionsOfNovaResponse); + requestResponseMap.put(serverReq, serverResponse); + requestResponseMap.put(list, listResponse).build(); + + SecurityGroupExtension extension = requestsSendResponses(requestResponseMap.build()).getSecurityGroupExtension().get(); + + Set groups = extension.listSecurityGroupsForNode(zone + "/8d0a6ca5-8849-4b3d-b86e-f24c92490ebb"); + assertEquals(groups.size(), 1); + } + + public void testGetSecurityGroupById() { + HttpRequest getSecurityGroup = HttpRequest.builder().method("GET").endpoint( + URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups/160")).headers( + ImmutableMultimap. builder().put("Accept", "application/json").put("X-Auth-Token", + authToken).build()).build(); + + HttpResponse getSecurityGroupResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygroup_details_extension.json")).build(); + + Builder requestResponseMap = ImmutableMap. builder(); + requestResponseMap.put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess); + requestResponseMap.put(extensionsOfNovaRequest, extensionsOfNovaResponse); + requestResponseMap.put(getSecurityGroup, getSecurityGroupResponse).build(); + + SecurityGroupExtension extension = requestsSendResponses(requestResponseMap.build()).getSecurityGroupExtension().get(); + + SecurityGroup group = extension.getSecurityGroupById(zone + "/160"); + assertEquals(group.getId(), "160"); + } + + public void testCreateSecurityGroup() { + HttpRequest create = HttpRequest.builder().method("POST").endpoint( + URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups")).headers( + ImmutableMultimap. builder().put("Accept", "application/json").put("X-Auth-Token", + authToken).build()) + .payload( + payloadFromStringWithContentType( + "{\"security_group\":{\"name\":\"jclouds-test\",\"description\":\"jclouds-test\"}}", + "application/json")).build(); + + HttpResponse createResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygroup_created.json")).build(); + + HttpRequest list = HttpRequest.builder().method("GET").endpoint( + URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups")).headers( + ImmutableMultimap.builder().put("Accept", "application/json").put("X-Auth-Token", + authToken).build()).build(); + + HttpResponse listResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygroup_list_extension.json")).build(); + + Builder requestResponseMap = ImmutableMap. builder(); + requestResponseMap.put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess); + requestResponseMap.put(extensionsOfNovaRequest, extensionsOfNovaResponse); + requestResponseMap.put(create, createResponse); + requestResponseMap.put(list, listResponse).build(); + + SecurityGroupExtension extension = requestsSendResponses(requestResponseMap.build()).getSecurityGroupExtension().get(); + + SecurityGroup group = extension.createSecurityGroup("test", new LocationBuilder() + .scope(LocationScope.ZONE) + .id(zone) + .description("zone") + .build()); + assertEquals(group.getId(), "160"); + } + + public void testRemoveSecurityGroup() { + HttpRequest delete = HttpRequest.builder().method("DELETE").endpoint( + URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups/160")) + .headers( + ImmutableMultimap.builder().put("Accept", "application/json") + .put("X-Auth-Token", authToken).build()).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(202).build(); + + HttpRequest getSecurityGroup = HttpRequest.builder().method("GET").endpoint( + URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups/160")).headers( + ImmutableMultimap. builder().put("Accept", "application/json").put("X-Auth-Token", + authToken).build()).build(); + + HttpResponse getSecurityGroupResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygroup_details_extension.json")).build(); + + Builder requestResponseMap = ImmutableMap. builder(); + requestResponseMap.put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess); + requestResponseMap.put(extensionsOfNovaRequest, extensionsOfNovaResponse); + requestResponseMap.put(getSecurityGroup, getSecurityGroupResponse); + requestResponseMap.put(delete, deleteResponse).build(); + + SecurityGroupExtension extension = requestsSendResponses(requestResponseMap.build()).getSecurityGroupExtension().get(); + + assertTrue(extension.removeSecurityGroup(zone + "/160"), "Expected removal of securitygroup to be successful"); + } + + public void testAddIpPermissionCidrFromIpPermission() { + HttpRequest createRule = HttpRequest + .builder() + .method("POST") + .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-group-rules") + .addHeader("Accept", "application/json") + .addHeader("X-Auth-Token", authToken) + .payload( + payloadFromStringWithContentType( + "{\"security_group_rule\":{\"parent_group_id\":\"160\",\"cidr\":\"10.2.6.0/24\",\"ip_protocol\":\"tcp\",\"from_port\":\"22\",\"to_port\":\"22\"}}", + "application/json")).build(); + + HttpResponse createRuleResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygrouprule_created_cidr.json")).build(); + + HttpRequest getSecurityGroup = HttpRequest.builder().method("GET").endpoint( + URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups/160")).headers( + ImmutableMultimap. builder().put("Accept", "application/json").put("X-Auth-Token", + authToken).build()).build(); + + HttpResponse getSecurityGroupNoRulesResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygroup_details_extension_norules.json")).build(); + + HttpResponse getSecurityGroupResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygroup_details_extension.json")).build(); + + + SecurityGroupExtension extension = orderedRequestsSendResponses(ImmutableList.of(keystoneAuthWithUsernameAndPasswordAndTenantName, + extensionsOfNovaRequest, getSecurityGroup, createRule, getSecurityGroup), + ImmutableList.of(responseWithKeystoneAccess, extensionsOfNovaResponse, getSecurityGroupNoRulesResponse, + createRuleResponse, getSecurityGroupResponse)).getSecurityGroupExtension().get(); + + IpPermission.Builder builder = IpPermission.builder(); + + builder.ipProtocol(IpProtocol.TCP); + builder.fromPort(22); + builder.toPort(22); + builder.cidrBlock("10.2.6.0/24"); + + IpPermission perm = builder.build(); + + SecurityGroup origGroup = extension.getSecurityGroupById(zone + "/160"); + + assertNotNull(origGroup); + SecurityGroup newGroup = extension.addIpPermission(perm, origGroup); + + assertNotNull(newGroup); + } + + public void testAddIpPermissionCidrFromParams() { + HttpRequest createRule = HttpRequest + .builder() + .method("POST") + .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-group-rules") + .addHeader("Accept", "application/json") + .addHeader("X-Auth-Token", authToken) + .payload( + payloadFromStringWithContentType( + "{\"security_group_rule\":{\"parent_group_id\":\"160\",\"cidr\":\"10.2.6.0/24\",\"ip_protocol\":\"tcp\",\"from_port\":\"22\",\"to_port\":\"22\"}}", + "application/json")).build(); + + HttpResponse createRuleResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygrouprule_created_cidr.json")).build(); + + HttpRequest getSecurityGroup = HttpRequest.builder().method("GET").endpoint( + URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups/160")).headers( + ImmutableMultimap. builder().put("Accept", "application/json").put("X-Auth-Token", + authToken).build()).build(); + + HttpResponse getSecurityGroupNoRulesResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygroup_details_extension_norules.json")).build(); + + HttpResponse getSecurityGroupResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygroup_details_extension.json")).build(); + + + SecurityGroupExtension extension = orderedRequestsSendResponses(ImmutableList.of(keystoneAuthWithUsernameAndPasswordAndTenantName, + extensionsOfNovaRequest, getSecurityGroup, createRule, getSecurityGroup), + ImmutableList.of(responseWithKeystoneAccess, extensionsOfNovaResponse, getSecurityGroupNoRulesResponse, + createRuleResponse, getSecurityGroupResponse)).getSecurityGroupExtension().get(); + + SecurityGroup origGroup = extension.getSecurityGroupById(zone + "/160"); + + assertNotNull(origGroup); + SecurityGroup newGroup = extension.addIpPermission(IpProtocol.TCP, + 22, + 22, + emptyMultimap(), + ImmutableSet.of("10.2.6.0/24"), + emptyStringSet(), + origGroup); + + assertNotNull(newGroup); + } + + public void testAddIpPermissionGroupFromIpPermission() { + HttpRequest createRule = HttpRequest + .builder() + .method("POST") + .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-group-rules") + .addHeader("Accept", "application/json") + .addHeader("X-Auth-Token", authToken) + .payload( + payloadFromStringWithContentType( + "{\"security_group_rule\":{\"group_id\":\"11111\",\"parent_group_id\":\"160\",\"ip_protocol\":\"tcp\",\"from_port\":\"22\",\"to_port\":\"22\"}}", + "application/json")).build(); + + HttpResponse createRuleResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygrouprule_created_group.json")).build(); + + HttpRequest getSecurityGroup = HttpRequest.builder().method("GET").endpoint( + URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups/160")).headers( + ImmutableMultimap. builder().put("Accept", "application/json").put("X-Auth-Token", + authToken).build()).build(); + + HttpResponse getSecurityGroupNoRulesResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygroup_details_extension_norules.json")).build(); + + HttpResponse getSecurityGroupResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygroup_details_extension.json")).build(); + + + SecurityGroupExtension extension = orderedRequestsSendResponses(ImmutableList.of(keystoneAuthWithUsernameAndPasswordAndTenantName, + extensionsOfNovaRequest, getSecurityGroup, createRule, getSecurityGroup), + ImmutableList.of(responseWithKeystoneAccess, extensionsOfNovaResponse, getSecurityGroupNoRulesResponse, + createRuleResponse, getSecurityGroupResponse)).getSecurityGroupExtension().get(); + + IpPermission.Builder builder = IpPermission.builder(); + + builder.ipProtocol(IpProtocol.TCP); + builder.fromPort(22); + builder.toPort(22); + builder.groupId("admin/11111"); + + IpPermission perm = builder.build(); + + SecurityGroup origGroup = extension.getSecurityGroupById(zone + "/160"); + + assertNotNull(origGroup); + SecurityGroup newGroup = extension.addIpPermission(perm, origGroup); + + assertNotNull(newGroup); + } + + public void testAddIpPermissionGroupFromParams() { + HttpRequest createRule = HttpRequest + .builder() + .method("POST") + .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-group-rules") + .addHeader("Accept", "application/json") + .addHeader("X-Auth-Token", authToken) + .payload( + payloadFromStringWithContentType( + "{\"security_group_rule\":{\"group_id\":\"11111\",\"parent_group_id\":\"160\",\"ip_protocol\":\"tcp\",\"from_port\":\"22\",\"to_port\":\"22\"}}", + "application/json")).build(); + + HttpResponse createRuleResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygrouprule_created_group.json")).build(); + + HttpRequest getSecurityGroup = HttpRequest.builder().method("GET").endpoint( + URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups/160")).headers( + ImmutableMultimap. builder().put("Accept", "application/json").put("X-Auth-Token", + authToken).build()).build(); + + HttpResponse getSecurityGroupNoRulesResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygroup_details_extension_norules.json")).build(); + + HttpResponse getSecurityGroupResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/securitygroup_details_extension.json")).build(); + + + SecurityGroupExtension extension = orderedRequestsSendResponses(ImmutableList.of(keystoneAuthWithUsernameAndPasswordAndTenantName, + extensionsOfNovaRequest, getSecurityGroup, createRule, getSecurityGroup), + ImmutableList.of(responseWithKeystoneAccess, extensionsOfNovaResponse, getSecurityGroupNoRulesResponse, + createRuleResponse, getSecurityGroupResponse)).getSecurityGroupExtension().get(); + + SecurityGroup origGroup = extension.getSecurityGroupById(zone + "/160"); + + assertNotNull(origGroup); + SecurityGroup newGroup = extension.addIpPermission(IpProtocol.TCP, + 22, + 22, + emptyMultimap(), + emptyStringSet(), + ImmutableSet.of("admin/11111"), + origGroup); + + assertNotNull(newGroup); + } + + private Multimap emptyMultimap() { + return LinkedHashMultimap.create(); + } + + private Set emptyStringSet() { + return Sets.newLinkedHashSet(); + } + +} diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtensionLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtensionLiveTest.java new file mode 100644 index 0000000000..4a7dbed215 --- /dev/null +++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtensionLiveTest.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.v2_0.compute.extensions; + +import org.jclouds.compute.extensions.internal.BaseSecurityGroupExtensionLiveTest; +import org.testng.annotations.Test; + +/** + * Live test for openstack-nova {@link org.jclouds.compute.extensions.SecurityGroupExtension} implementation. + * + * @author Andrew Bayer + * + */ +@Test(groups = "live", singleThreaded = true, testName = "NovaSecurityGroupExtensionLiveTest") +public class NovaSecurityGroupExtensionLiveTest extends BaseSecurityGroupExtensionLiveTest { + + public NovaSecurityGroupExtensionLiveTest() { + provider = "openstack-nova"; + } + +} diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInZoneToSecurityGroupTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInZoneToSecurityGroupTest.java new file mode 100644 index 0000000000..7c588ad1a9 --- /dev/null +++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInZoneToSecurityGroupTest.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.v2_0.compute.functions; + +import static com.google.common.collect.Iterables.transform; +import static org.jclouds.openstack.nova.v2_0.compute.functions.NovaSecurityGroupToSecurityGroupTest.securityGroupWithCidr; +import static org.jclouds.openstack.nova.v2_0.compute.functions.NovaSecurityGroupToSecurityGroupTest.securityGroupWithGroup; +import static org.testng.Assert.assertEquals; + +import java.util.Map; + +import org.jclouds.compute.domain.SecurityGroup; +import org.jclouds.domain.Location; +import org.jclouds.domain.LocationBuilder; +import org.jclouds.domain.LocationScope; +import org.jclouds.openstack.nova.v2_0.domain.zonescoped.SecurityGroupInZone; +import org.testng.annotations.Test; + +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +/** + * @author Andrew Bayer + */ +@Test(groups = "unit", testName = "NovaSecurityGroupInZoneToSecurityGroupTest") +public class NovaSecurityGroupInZoneToSecurityGroupTest { + + private static final SecurityGroupRuleToIpPermission ruleConverter = new SecurityGroupRuleToIpPermission(); + Location provider = new LocationBuilder().scope(LocationScope.PROVIDER).id("openstack-nova") + .description("openstack-nova").build(); + Location zone = new LocationBuilder().id("az-1.region-a.geo-1").description("az-1.region-a.geo-1") + .scope(LocationScope.ZONE).parent(provider).build(); + Supplier> locationIndex = Suppliers.> ofInstance(ImmutableMap + .of("az-1.region-a.geo-1", zone)); + + + @Test + public void testApplyWithGroup() { + NovaSecurityGroupInZoneToSecurityGroup parser = createGroupParser(); + + SecurityGroupInZone origGroup = new SecurityGroupInZone(securityGroupWithGroup(), zone.getId()); + + SecurityGroup newGroup = parser.apply(origGroup); + + assertEquals(newGroup.getId(), origGroup.getSecurityGroup().getId()); + assertEquals(newGroup.getProviderId(), origGroup.getSecurityGroup().getId()); + assertEquals(newGroup.getName(), origGroup.getSecurityGroup().getName()); + assertEquals(newGroup.getOwnerId(), origGroup.getSecurityGroup().getTenantId()); + assertEquals(newGroup.getIpPermissions(), ImmutableSet.copyOf(transform(origGroup.getSecurityGroup().getRules(), ruleConverter))); + assertEquals(newGroup.getLocation().getId(), origGroup.getZone()); + } + + @Test + public void testApplyWithCidr() { + + NovaSecurityGroupInZoneToSecurityGroup parser = createGroupParser(); + + SecurityGroupInZone origGroup = new SecurityGroupInZone(securityGroupWithCidr(), zone.getId()); + + SecurityGroup newGroup = parser.apply(origGroup); + + assertEquals(newGroup.getId(), origGroup.getSecurityGroup().getId()); + assertEquals(newGroup.getProviderId(), origGroup.getSecurityGroup().getId()); + assertEquals(newGroup.getName(), origGroup.getSecurityGroup().getName()); + assertEquals(newGroup.getOwnerId(), origGroup.getSecurityGroup().getTenantId()); + assertEquals(newGroup.getIpPermissions(), ImmutableSet.copyOf(transform(origGroup.getSecurityGroup().getRules(), ruleConverter))); + assertEquals(newGroup.getLocation().getId(), origGroup.getZone()); + } + + private NovaSecurityGroupInZoneToSecurityGroup createGroupParser() { + NovaSecurityGroupToSecurityGroup baseParser = new NovaSecurityGroupToSecurityGroup(ruleConverter); + + NovaSecurityGroupInZoneToSecurityGroup parser = new NovaSecurityGroupInZoneToSecurityGroup(baseParser, locationIndex); + + return parser; + } +} diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupToSecurityGroupTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupToSecurityGroupTest.java index 8db1e1510f..16d01d3f67 100644 --- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupToSecurityGroupTest.java +++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupToSecurityGroupTest.java @@ -18,19 +18,13 @@ package org.jclouds.openstack.nova.v2_0.compute.functions; import static com.google.common.collect.Iterables.transform; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - -import java.util.Set; import org.jclouds.compute.domain.SecurityGroup; -import org.jclouds.compute.reference.ComputeServiceConstants; -import org.jclouds.net.domain.IpPermission; import org.jclouds.net.domain.IpProtocol; import org.jclouds.openstack.nova.v2_0.domain.SecurityGroupRule; import org.jclouds.openstack.nova.v2_0.domain.TenantIdAndName; import org.testng.annotations.Test; -import com.google.common.base.Supplier; import com.google.common.collect.ImmutableSet; /** @@ -40,32 +34,59 @@ import com.google.common.collect.ImmutableSet; public class NovaSecurityGroupToSecurityGroupTest { private static final SecurityGroupRuleToIpPermission ruleConverter = new SecurityGroupRuleToIpPermission(); - - @Test - public void testApplyWithGroup() { + + public static org.jclouds.openstack.nova.v2_0.domain.SecurityGroup securityGroupWithGroup() { TenantIdAndName group = TenantIdAndName.builder().tenantId("tenant").name("name").build(); - + SecurityGroupRule ruleToConvert = SecurityGroupRule.builder() - .id("some-id") - .ipProtocol(IpProtocol.TCP) - .fromPort(10) - .toPort(20) - .group(group) - .parentGroupId("some-other-id") - .build(); + .id("some-id") + .ipProtocol(IpProtocol.TCP) + .fromPort(10) + .toPort(20) + .group(group) + .parentGroupId("some-other-id") + .build(); org.jclouds.openstack.nova.v2_0.domain.SecurityGroup origGroup = org.jclouds.openstack.nova.v2_0.domain.SecurityGroup.builder() - .tenantId("tenant") - .id("some-id") - .name("some-group") - .description("some-description") - .rules(ruleToConvert) - .build(); + .tenantId("tenant") + .id("some-id") + .name("some-group") + .description("some-description") + .rules(ruleToConvert) + .build(); + return origGroup; + } + + public static org.jclouds.openstack.nova.v2_0.domain.SecurityGroup securityGroupWithCidr() { + SecurityGroupRule ruleToConvert = SecurityGroupRule.builder() + .id("some-id") + .ipProtocol(IpProtocol.TCP) + .fromPort(10) + .toPort(20) + .ipRange("0.0.0.0/0") + .parentGroupId("some-other-id") + .build(); + + org.jclouds.openstack.nova.v2_0.domain.SecurityGroup origGroup = org.jclouds.openstack.nova.v2_0.domain.SecurityGroup.builder() + .tenantId("tenant") + .id("some-id") + .name("some-group") + .description("some-description") + .rules(ruleToConvert) + .build(); + + return origGroup; + } + + @Test + public void testApplyWithGroup() { NovaSecurityGroupToSecurityGroup parser = createGroupParser(); + org.jclouds.openstack.nova.v2_0.domain.SecurityGroup origGroup = securityGroupWithGroup(); + SecurityGroup newGroup = parser.apply(origGroup); - + assertEquals(newGroup.getId(), origGroup.getId()); assertEquals(newGroup.getProviderId(), origGroup.getId()); assertEquals(newGroup.getName(), origGroup.getName()); @@ -75,27 +96,13 @@ public class NovaSecurityGroupToSecurityGroupTest { @Test public void testApplyWithCidr() { - SecurityGroupRule ruleToConvert = SecurityGroupRule.builder() - .id("some-id") - .ipProtocol(IpProtocol.TCP) - .fromPort(10) - .toPort(20) - .ipRange("0.0.0.0/0") - .parentGroupId("some-other-id") - .build(); - - org.jclouds.openstack.nova.v2_0.domain.SecurityGroup origGroup = org.jclouds.openstack.nova.v2_0.domain.SecurityGroup.builder() - .tenantId("tenant") - .id("some-id") - .name("some-group") - .description("some-description") - .rules(ruleToConvert) - .build(); NovaSecurityGroupToSecurityGroup parser = createGroupParser(); + org.jclouds.openstack.nova.v2_0.domain.SecurityGroup origGroup = securityGroupWithCidr(); + SecurityGroup group = parser.apply(origGroup); - + assertEquals(group.getId(), origGroup.getId()); assertEquals(group.getProviderId(), origGroup.getId()); assertEquals(group.getName(), origGroup.getName()); diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/predicates/SecurityGroupPredicatesTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/predicates/SecurityGroupPredicatesTest.java index 521d7d57c2..26e5ce2790 100644 --- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/predicates/SecurityGroupPredicatesTest.java +++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/predicates/SecurityGroupPredicatesTest.java @@ -17,10 +17,22 @@ package org.jclouds.openstack.nova.v2_0.predicates; import static org.jclouds.openstack.nova.v2_0.predicates.SecurityGroupPredicates.nameEquals; +import static org.jclouds.openstack.nova.v2_0.predicates.SecurityGroupPredicates.nameIn; +import static org.jclouds.openstack.nova.v2_0.predicates.SecurityGroupPredicates.ruleCidr; +import static org.jclouds.openstack.nova.v2_0.predicates.SecurityGroupPredicates.ruleEndPort; +import static org.jclouds.openstack.nova.v2_0.predicates.SecurityGroupPredicates.ruleGroup; +import static org.jclouds.openstack.nova.v2_0.predicates.SecurityGroupPredicates.ruleProtocol; +import static org.jclouds.openstack.nova.v2_0.predicates.SecurityGroupPredicates.ruleStartPort; +import static org.testng.Assert.assertTrue; +import org.jclouds.net.domain.IpProtocol; import org.jclouds.openstack.nova.v2_0.domain.SecurityGroup; +import org.jclouds.openstack.nova.v2_0.domain.SecurityGroupRule; +import org.jclouds.openstack.nova.v2_0.domain.TenantIdAndName; import org.testng.annotations.Test; +import com.google.common.collect.ImmutableSet; + /** * * @author Adrian Cole @@ -28,15 +40,90 @@ import org.testng.annotations.Test; @Test(groups = "unit", testName = "SecurityGroupPredicatesTest") public class SecurityGroupPredicatesTest { SecurityGroup ref = SecurityGroup.builder().id("12345").name("jclouds").description("description").build(); + SecurityGroupRule ruleRef = SecurityGroupRule.builder().id("6789").parentGroupId("12345").ipRange("0.0.0.0/0") + .fromPort(10).toPort(20).ipProtocol(IpProtocol.TCP) + .group(TenantIdAndName.builder().tenantId("11111111").name("abcd").build()) + .build(); - @Test public void testnameEqualsWhenEqual() { - assert nameEquals("jclouds").apply(ref); + assertTrue(nameEquals("jclouds").apply(ref), "expected 'jclouds' as the name of " + ref); } @Test public void testnameEqualsWhenNotEqual() { - assert !nameEquals("foo").apply(ref); + assertTrue(!nameEquals("foo").apply(ref), "expected 'foo' not to be the name of " + ref); } + @Test + public void testNameInWhenIn() { + assertTrue(nameIn(ImmutableSet.of("jclouds", "pants")).apply(ref), + "expected the name of " + ref + " to be one of 'jclouds' or 'pants'"); + } + + @Test + public void testNameInWhenNotIn() { + assertTrue(!nameIn(ImmutableSet.of("foo", "pants")).apply(ref), + "expected the name of " + ref + " to not be either of 'foo' or 'pants'"); + + } + + @Test + public void testRuleCidrWhenEqual() { + assertTrue(ruleCidr("0.0.0.0/0").apply(ruleRef), + "expected the CIDR to be '0.0.0.0/0' for " + ruleRef); + } + + @Test + public void testRuleCidrWhenNotEqual() { + assertTrue(!ruleCidr("1.1.1.1/0").apply(ruleRef), + "expected the CIDR to not be '1.1.1.1/0' for " + ruleRef); + } + + @Test + public void testRuleGroupWhenEqual() { + assertTrue(ruleGroup("abcd").apply(ruleRef), + "expected the group to be equal to 'abcd' for " + ruleRef); + } + + @Test + public void testRuleGroupWhenNotEqual() { + assertTrue(!ruleGroup("pants").apply(ruleRef), + "expected the group to not be equal to 'pants' for " + ruleRef); + } + + @Test + public void testRuleProtocolWhenEqual() { + assertTrue(ruleProtocol(IpProtocol.TCP).apply(ruleRef), + "expected TCP for " + ruleRef); + } + + @Test + public void testRuleProtocolWhenNotEqual() { + assertTrue(!ruleProtocol(IpProtocol.UDP).apply(ruleRef), + "expected not UDP for " + ruleRef); + } + + @Test + public void testRuleStartPortWhenEqual() { + assertTrue(ruleStartPort(10).apply(ruleRef), + "expected start port 10 for " + ruleRef); + } + + @Test + public void testRuleStartPortWhenNotEqual() { + assertTrue(!ruleStartPort(50).apply(ruleRef), + "expected start port not to be 50 for " + ruleRef); + } + + @Test + public void testRuleEndPortWhenEqual() { + assertTrue(ruleEndPort(20).apply(ruleRef), + "expected end port 20 for " + ruleRef); + } + + @Test + public void testRuleEndPortWhenNotEqual() { + assertTrue(!ruleEndPort(50).apply(ruleRef), + "expected end port not to be 50 for " + ruleRef); + } } diff --git a/apis/openstack-nova/src/test/resources/securitygroup_details_extension.json b/apis/openstack-nova/src/test/resources/securitygroup_details_extension.json new file mode 100644 index 0000000000..a64429643b --- /dev/null +++ b/apis/openstack-nova/src/test/resources/securitygroup_details_extension.json @@ -0,0 +1,34 @@ +{ + "security_group": + { + "rules": [ + { + "from_port": 22, + "group": {}, + "ip_protocol": "tcp", + "to_port": 22, + "parent_group_id": 160, + "ip_range": { + "cidr": "10.2.6.0/24" + }, + "id": 108 + }, + { + "from_port": 22, + "group": { + "tenant_id": "admin", + "name": "11111" + }, + "ip_protocol": "tcp", + "to_port": 22, + "parent_group_id": 160, + "ip_range": {}, + "id": 109 + } + ], + "tenant_id": "tenant0", + "id": 160, + "name": "name0", + "description": "description0" + } +} \ No newline at end of file diff --git a/apis/openstack-nova/src/test/resources/securitygroup_details_extension_norules.json b/apis/openstack-nova/src/test/resources/securitygroup_details_extension_norules.json new file mode 100644 index 0000000000..27aca88759 --- /dev/null +++ b/apis/openstack-nova/src/test/resources/securitygroup_details_extension_norules.json @@ -0,0 +1,10 @@ +{ + "security_group": + { + "rules": [], + "tenant_id": "tenant0", + "id": 160, + "name": "name0", + "description": "description0" + } +} \ No newline at end of file diff --git a/apis/openstack-nova/src/test/resources/securitygroup_list_extension.json b/apis/openstack-nova/src/test/resources/securitygroup_list_extension.json new file mode 100644 index 0000000000..14866e3f91 --- /dev/null +++ b/apis/openstack-nova/src/test/resources/securitygroup_list_extension.json @@ -0,0 +1,51 @@ +{ + "security_groups":[ + { + "rules":[ + { + "from_port":22, + "group":{ + + }, + "ip_protocol":"tcp", + "to_port":22, + "parent_group_id":3, + "ip_range":{ + "cidr":"0.0.0.0/0" + }, + "id":107 + }, + { + "from_port":7600, + "group":{ + + }, + "ip_protocol":"tcp", + "to_port":7600, + "parent_group_id":3, + "ip_range":{ + "cidr":"0.0.0.0/0" + }, + "id":118 + }, + { + "from_port":8084, + "group":{ + + }, + "ip_protocol":"tcp", + "to_port":8084, + "parent_group_id":3, + "ip_range":{ + "cidr":"0.0.0.0/0" + }, + "id":119 + } + ], + "tenant_id":"dev_16767499955063", + "id":160, + "name":"jclouds-test", + "description":"jclouds-test" + } + ] +} \ No newline at end of file diff --git a/apis/openstack-nova/src/test/resources/securitygrouprule_created_cidr.json b/apis/openstack-nova/src/test/resources/securitygrouprule_created_cidr.json new file mode 100644 index 0000000000..cc91ac70a5 --- /dev/null +++ b/apis/openstack-nova/src/test/resources/securitygrouprule_created_cidr.json @@ -0,0 +1,13 @@ +{ + "security_group_rule": { + "from_port": 22, + "group": {}, + "ip_protocol": "tcp", + "to_port": 22, + "parent_group_id": 160, + "ip_range": { + "cidr": "10.2.6.0/24" + }, + "id": 108 + } +} \ No newline at end of file diff --git a/apis/openstack-nova/src/test/resources/securitygrouprule_created_group.json b/apis/openstack-nova/src/test/resources/securitygrouprule_created_group.json new file mode 100644 index 0000000000..ff17bcdc0d --- /dev/null +++ b/apis/openstack-nova/src/test/resources/securitygrouprule_created_group.json @@ -0,0 +1,14 @@ +{ + "security_group_rule": { + "from_port": 22, + "group": { + "tenant_id": "admin", + "name": "11111" + }, + "ip_protocol": "tcp", + "to_port": 22, + "parent_group_id": 160, + "ip_range": {}, + "id": 109 + } +} \ No newline at end of file diff --git a/apis/openstack-nova/src/test/resources/server_with_security_groups_extension.json b/apis/openstack-nova/src/test/resources/server_with_security_groups_extension.json new file mode 100644 index 0000000000..7a3c4b2adc --- /dev/null +++ b/apis/openstack-nova/src/test/resources/server_with_security_groups_extension.json @@ -0,0 +1 @@ +{"server": {"status": "ACTIVE", "updated": "2012-05-04T12:15:01Z", "hostId": "02c7c81e36024d2bfdb473cb762900138bc07777922479d3d4f8f690", "user_id": "1e8a56719e0d4ab4b7edb85c77f7290f", "name": "test", "links": [{"href": "http://172.16.89.148:8774/v2/4287930c796741aa898425f40832cb3c/servers/8d0a6ca5-8849-4b3d-b86e-f24c92490ebb", "rel": "self"}, {"href": "http://172.16.89.148:8774/4287930c796741aa898425f40832cb3c/servers/8d0a6ca5-8849-4b3d-b86e-f24c92490ebb", "rel": "bookmark"}], "created": "2012-05-04T12:14:57Z", "tenant_id": "4287930c796741aa898425f40832cb3c", "image": {"id": "ea17cc36-f7c9-40cd-b6bf-a952b74870f2", "links": [{"href": "http://172.16.89.148:8774/4287930c796741aa898425f40832cb3c/images/ea17cc36-f7c9-40cd-b6bf-a952b74870f2", "rel": "bookmark"}]}, "addresses": {"private": [{"version": 4, "addr": "10.0.0.8"}]}, "accessIPv4": "", "accessIPv6": "", "key_name": "", "progress": 0, "flavor": {"id": "1", "links": [{"href": "http://172.16.89.148:8774/4287930c796741aa898425f40832cb3c/flavors/1", "rel": "bookmark"}]}, "config_drive": "", "id": "8d0a6ca5-8849-4b3d-b86e-f24c92490ebb", "security_groups": [{"name": "name1"}], "metadata": {}}} \ No newline at end of file