[JCLOUDS-1377] add support for injectable Neutron Context into Nova

- fix NovaComputeServiceExpectTest
- fix NovaComputeServiceExpectTest
- fix CreateSecurityGroupIfNeededTest
- fix FindSecurityGroupInRegionOrCreateTest
- fix checkstyle
- fix removal from security group cache
- fix listSecurityGroupsForNode
- change both Nova and Neutron listSecurityGroupsForNode to use NovaApi.listSecurityGroupForServer
This commit is contained in:
andreaturli 2018-01-17 11:46:55 +00:00
parent 2a56db0957
commit 09936b57fc
30 changed files with 1224 additions and 252 deletions

View File

@ -53,6 +53,11 @@
<artifactId>openstack-keystone</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jclouds.api</groupId>
<artifactId>openstack-neutron</artifactId>
<version>${project.version}</version>
</dependency>
<!-- for the extension namespaces -->
<dependency>
<groupId>com.google.inject.extensions</groupId>

View File

@ -17,6 +17,7 @@
package org.jclouds.openstack.nova.v2_0;
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE;
import static org.jclouds.openstack.keystone.config.KeystoneProperties.CREDENTIAL_TYPE;
import static org.jclouds.openstack.keystone.config.KeystoneProperties.KEYSTONE_VERSION;
import static org.jclouds.openstack.keystone.config.KeystoneProperties.SERVICE_TYPE;
@ -78,6 +79,7 @@ public class NovaApiMetadata extends BaseHttpApiMetadata<NovaApi> {
// before expiry by default. We choose a value less than the latter
// since the former persists between jclouds invocations.
properties.setProperty(PROPERTY_SESSION_INTERVAL, 30 * 60 + "");
properties.put(TEMPLATE, "osFamily=UBUNTU,os64Bit=true,osVersionMatches=16.*");
return properties;
}

View File

@ -140,7 +140,7 @@ public class NovaComputeServiceAdapter implements
logger.warn(message);
String tagString = metadataAndTagsAsCommaDelimitedValue.get("jclouds_tags");
Set<String> tags = Sets.newHashSet(Splitter.on(',').split(tagString));
cleanupResources.removeSecurityGroupCreatedByJcloudsAndInvalidateCache(regionId, tags);
cleanupResources.removeSecurityGroupCreatedByJcloudsAndInvalidateCache(tags);
throw new IllegalStateException(message);
}
logger.trace("<< server(%s)", lightweightServer.getId());

View File

@ -17,21 +17,22 @@
package org.jclouds.openstack.nova.v2_0.compute.config;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING;
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED;
import static org.jclouds.openstack.nova.v2_0.config.NovaProperties.AUTO_ALLOCATE_FLOATING_IPS;
import static org.jclouds.openstack.nova.v2_0.config.NovaProperties.AUTO_GENERATE_KEYPAIRS;
import static org.jclouds.openstack.nova.v2_0.config.NovaProperties.TIMEOUT_SECURITYGROUP_PRESENT;
import static org.jclouds.util.Predicates2.retry;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Named;
import javax.inject.Singleton;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import org.jclouds.Context;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceAdapter;
@ -53,6 +54,7 @@ import org.jclouds.functions.IdentityFunction;
import org.jclouds.openstack.nova.v2_0.NovaApi;
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.NeutronSecurityGroupExtension;
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.CleanupResources;
@ -60,7 +62,9 @@ import org.jclouds.openstack.nova.v2_0.compute.functions.CreateSecurityGroupIfNe
import org.jclouds.openstack.nova.v2_0.compute.functions.FlavorInRegionToHardware;
import org.jclouds.openstack.nova.v2_0.compute.functions.ImageInRegionToImage;
import org.jclouds.openstack.nova.v2_0.compute.functions.ImageToOperatingSystem;
import org.jclouds.openstack.nova.v2_0.compute.functions.NeutronSecurityGroupToSecurityGroup;
import org.jclouds.openstack.nova.v2_0.compute.functions.NovaSecurityGroupInRegionToSecurityGroup;
import org.jclouds.openstack.nova.v2_0.compute.functions.NovaSecurityGroupToSecurityGroup;
import org.jclouds.openstack.nova.v2_0.compute.functions.OrphanedGroupsByRegionId;
import org.jclouds.openstack.nova.v2_0.compute.functions.ServerInRegionToNodeMetadata;
import org.jclouds.openstack.nova.v2_0.compute.loaders.FindSecurityGroupOrCreate;
@ -77,7 +81,6 @@ import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionSecurityGroupNameAndPorts;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.SecurityGroupInRegion;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.ServerInRegion;
import org.jclouds.openstack.nova.v2_0.predicates.FindSecurityGroupWithNameAndReturnTrue;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
@ -137,10 +140,10 @@ public class NovaComputeServiceContextModule extends
bind(new TypeLiteral<CacheLoader<RegionAndId, Iterable<? extends FloatingIP>>>() {
}).annotatedWith(Names.named("FLOATINGIP")).to(LoadFloatingIpsForInstance.class);
bind(new TypeLiteral<Function<RegionSecurityGroupNameAndPorts, SecurityGroupInRegion>>() {
bind(new TypeLiteral<Function<RegionSecurityGroupNameAndPorts, SecurityGroup>>() {
}).to(CreateSecurityGroupIfNeeded.class);
bind(new TypeLiteral<CacheLoader<RegionAndName, SecurityGroupInRegion>>() {
bind(new TypeLiteral<CacheLoader<RegionAndName, SecurityGroup>>() {
}).to(FindSecurityGroupOrCreate.class);
bind(CreateNodesWithGroupEncodedIntoNameThenAddToSet.class).to(
@ -149,11 +152,37 @@ public class NovaComputeServiceContextModule extends
bind(new TypeLiteral<ImageExtension>() {
}).to(NovaImageExtension.class);
bind(new TypeLiteral<SecurityGroupExtension>() {
}).to(NovaSecurityGroupExtension.class);
bind(new TypeLiteral<Function<NodeMetadata, Boolean>>() {
}).to(CleanupResources.class);
install(new FactoryModuleBuilder().build(NeutronSecurityGroupToSecurityGroup.Factory.class));
install(new FactoryModuleBuilder().build(NovaSecurityGroupToSecurityGroup.Factory.class));
bind(new TypeLiteral<SecurityGroupExtension>() {
}).toProvider(SecurityGroupExtensionProvider.class);
}
@Singleton
public static class SecurityGroupExtensionProvider implements Provider<SecurityGroupExtension> {
@Inject(optional = true)
@Named("openstack-neutron")
protected Supplier<Context> neutronApiContextSupplier;
private final NeutronSecurityGroupExtension neutronSecurityGroupExtension;
private final NovaSecurityGroupExtension novaSecurityGroupExtension;
@Inject
SecurityGroupExtensionProvider(NeutronSecurityGroupExtension neutronSecurityGroupExtension,
NovaSecurityGroupExtension novaSecurityGroupExtension) {
this.neutronSecurityGroupExtension = neutronSecurityGroupExtension;
this.novaSecurityGroupExtension = novaSecurityGroupExtension;
}
@Override
public SecurityGroupExtension get() {
return neutronApiContextSupplier != null ? neutronSecurityGroupExtension : novaSecurityGroupExtension;
}
}
@Override
@ -192,8 +221,8 @@ public class NovaComputeServiceContextModule extends
@Provides
@Singleton
protected final LoadingCache<RegionAndName, SecurityGroupInRegion> securityGroupMap(
CacheLoader<RegionAndName, SecurityGroupInRegion> in) {
protected final LoadingCache<RegionAndName, SecurityGroup> securityGroupMap(
CacheLoader<RegionAndName, SecurityGroup> in) {
return CacheBuilder.newBuilder().build(in);
}
@ -203,15 +232,6 @@ public class NovaComputeServiceContextModule extends
OsFamily.UBUNTU, LoginCredentials.builder().user("ubuntu").build());
}
@Provides
@Singleton
@Named("SECURITYGROUP_PRESENT")
protected final Predicate<AtomicReference<RegionAndName>> securityGroupEventualConsistencyDelay(
FindSecurityGroupWithNameAndReturnTrue in,
@Named(TIMEOUT_SECURITYGROUP_PRESENT) long msDelay) {
return retry(in, msDelay, 100L, MILLISECONDS);
}
@Provides
@Singleton
protected final Supplier<Map<String, Location>> createLocationIndexedById(

View File

@ -0,0 +1,325 @@
/*
* 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.notNull;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import javax.inject.Named;
import org.jclouds.Context;
import org.jclouds.compute.domain.SecurityGroup;
import org.jclouds.compute.extensions.SecurityGroupExtension;
import org.jclouds.compute.functions.GroupNamingConvention;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.Location;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.Region;
import org.jclouds.logging.Logger;
import org.jclouds.net.domain.IpPermission;
import org.jclouds.net.domain.IpProtocol;
import org.jclouds.openstack.neutron.v2.NeutronApi;
import org.jclouds.openstack.neutron.v2.domain.Rule;
import org.jclouds.openstack.neutron.v2.domain.RuleDirection;
import org.jclouds.openstack.neutron.v2.domain.RuleEthertype;
import org.jclouds.openstack.neutron.v2.domain.RuleProtocol;
import org.jclouds.openstack.neutron.v2.features.SecurityGroupApi;
import org.jclouds.openstack.nova.v2_0.NovaApi;
import org.jclouds.openstack.nova.v2_0.compute.functions.NeutronSecurityGroupToSecurityGroup;
import org.jclouds.openstack.nova.v2_0.compute.functions.NovaSecurityGroupToSecurityGroup;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndId;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionSecurityGroupNameAndPorts;
import org.jclouds.rest.ApiContext;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
/**
* An extension to compute service to allow for the manipulation of {@link org.jclouds.compute.domain.SecurityGroup}s. Implementation
* is optional by providers.
*/
public class NeutronSecurityGroupExtension implements SecurityGroupExtension {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final NovaApi api;
private final Supplier<Set<String>> regionIds;
private final GroupNamingConvention.Factory namingConvention;
private final LoadingCache<RegionAndName, SecurityGroup> groupCreator;
private final Supplier<Map<String, Location>> locationIndex;
private final NeutronSecurityGroupToSecurityGroup.Factory neutronSecurityGroupToSecurityGroup;
private final NovaSecurityGroupToSecurityGroup.Factory novaSecurityGroupToSecurityGroup;
@Inject(optional = true)
@Named("openstack-neutron")
private Supplier<Context> neutronContextSupplier;
@Inject
NeutronSecurityGroupExtension(NovaApi api,
@Region Supplier<Set<String>> regionIds,
GroupNamingConvention.Factory namingConvention, LoadingCache<RegionAndName, SecurityGroup> groupCreator,
Supplier<Map<String, Location>> locationIndex,
NeutronSecurityGroupToSecurityGroup.Factory neutronSecurityGroupToSecurityGroup,
NovaSecurityGroupToSecurityGroup.Factory novaSecurityGroupToSecurityGroup) {
this.api = api;
this.regionIds = checkNotNull(regionIds, "regionIds");
this.namingConvention = checkNotNull(namingConvention, "namingConvention");
this.groupCreator = groupCreator;
this.locationIndex = locationIndex;
this.neutronSecurityGroupToSecurityGroup = neutronSecurityGroupToSecurityGroup;
this.novaSecurityGroupToSecurityGroup = novaSecurityGroupToSecurityGroup;
}
@Override
public SecurityGroup createSecurityGroup(String name, Location location) {
String region = location.getId();
if (region == null) {
return null;
}
logger.debug(">> creating security group %s in %s...", name, location);
String markerGroup = namingConvention.create().sharedNameForGroup(name);
RegionSecurityGroupNameAndPorts regionAndName = new RegionSecurityGroupNameAndPorts(region, markerGroup, ImmutableSet.<Integer> of());
return groupCreator.getUnchecked(regionAndName);
}
@Override
public Set<SecurityGroup> listSecurityGroups() {
Set<SecurityGroup> securityGroups = Sets.newHashSet();
for (String regionId : regionIds.get()) {
Location location = locationIndex.get().get(regionId);
securityGroups.addAll(listSecurityGroupsInLocation(location));
}
return ImmutableSet.copyOf(securityGroups);
}
@Override
public Set<SecurityGroup> listSecurityGroupsInLocation(final Location location) {
String region = location.getId();
if (region == null) {
return ImmutableSet.of();
}
return getSecurityGroupApi(region).listSecurityGroups().concat().transform(neutronSecurityGroupToSecurityGroup.create(location)).toSet();
}
@Override
public Set<SecurityGroup> listSecurityGroupsForNode(String id) {
RegionAndId regionAndId = RegionAndId.fromSlashEncoded(checkNotNull(id, "id"));
String region = regionAndId.getRegion();
Location location = locationIndex.get().get(region);
Set<org.jclouds.openstack.nova.v2_0.domain.SecurityGroup> allGroups = api.getServerApi(region).listSecurityGroupForServer(regionAndId.getId());
return ImmutableSet.copyOf(transform(filter(allGroups, notNull()), novaSecurityGroupToSecurityGroup.create(location)));
}
@Override
public SecurityGroup getSecurityGroupById(String id) {
RegionAndId regionAndId = RegionAndId.fromSlashEncoded(checkNotNull(id, "id"));
String region = regionAndId.getRegion();
String groupId = regionAndId.getId();
SecurityGroupApi securityGroupApi = getSecurityGroupApi(region);
Location location = locationIndex.get().get(region);
return neutronSecurityGroupToSecurityGroup.create(location).apply(securityGroupApi.getSecurityGroup(groupId));
}
@Override
public boolean removeSecurityGroup(String id) {
checkNotNull(id, "id");
RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id);
String region = regionAndId.getRegion();
String groupId = regionAndId.getId();
SecurityGroupApi securityGroupApi = getSecurityGroupApi(region);
// Would be nice to delete the group and invalidate the cache atomically - i.e. use a mutex.
// Will make sure that a create operation in parallel won't see inconsistent state.
boolean deleted = securityGroupApi.deleteSecurityGroup(groupId);
for (SecurityGroup cachedSg : groupCreator.asMap().values()) {
if (id.equals(cachedSg.getId())) {
String groupName = cachedSg.getName();
groupCreator.invalidate(new RegionSecurityGroupNameAndPorts(region, groupName, ImmutableSet.<Integer>of()));
break;
}
}
return deleted;
}
@Override
public SecurityGroup addIpPermission(IpPermission ipPermission, SecurityGroup group) {
String region = group.getLocation().getId();
RegionAndId groupRegionAndId = RegionAndId.fromSlashEncoded(group.getId());
String id = groupRegionAndId.getId();
SecurityGroupApi securityGroupApi = getSecurityGroupApi(region);
if (!ipPermission.getCidrBlocks().isEmpty()) {
for (String cidr : ipPermission.getCidrBlocks()) {
securityGroupApi.create(Rule.CreateRule.createBuilder(RuleDirection.INGRESS, group.getProviderId())
.protocol(RuleProtocol.fromValue(ipPermission.getIpProtocol().name()))
.ethertype(RuleEthertype.IPV4)
.portRangeMin(ipPermission.getFromPort())
.portRangeMax(ipPermission.getToPort())
.remoteIpPrefix(cidr)
.build());
}
}
if (!ipPermission.getGroupIds().isEmpty()) {
for (String regionAndGroupRaw : ipPermission.getGroupIds()) {
RegionAndId regionAndId = RegionAndId.fromSlashEncoded(regionAndGroupRaw);
String groupId = regionAndId.getId();
securityGroupApi.create(Rule.CreateRule.createBuilder(RuleDirection.INGRESS, groupId)
.protocol(RuleProtocol.fromValue(ipPermission.getIpProtocol().name()))
.ethertype(RuleEthertype.IPV4)
.portRangeMin(ipPermission.getFromPort())
.portRangeMax(ipPermission.getToPort())
.remoteGroupId(groupId)
.build());
}
}
return getSecurityGroupById(RegionAndId.fromRegionAndId(region, id).slashEncode());
}
@Override
public SecurityGroup addIpPermission(IpProtocol protocol, int startPort, int endPort,
Multimap<String, String> tenantIdGroupNamePairs,
Iterable<String> ipRanges,
Iterable<String> groupIds, SecurityGroup group) {
IpPermission.Builder permBuilder = IpPermission.builder();
permBuilder.ipProtocol(protocol);
permBuilder.fromPort(startPort);
permBuilder.toPort(endPort);
permBuilder.tenantIdGroupNamePairs(tenantIdGroupNamePairs);
permBuilder.cidrBlocks(ipRanges);
permBuilder.groupIds(groupIds);
return addIpPermission(permBuilder.build(), group);
}
@Override
public SecurityGroup removeIpPermission(final IpPermission ipPermission, SecurityGroup group) {
String region = group.getLocation().getId();
RegionAndId groupRegionAndId = RegionAndId.fromSlashEncoded(group.getId());
String id = groupRegionAndId.getId();
SecurityGroupApi securityGroupApi = getSecurityGroupApi(region);
org.jclouds.openstack.neutron.v2.domain.SecurityGroup securityGroup = securityGroupApi.getSecurityGroup(id);
if (!ipPermission.getCidrBlocks().isEmpty()) {
for (final String cidr : ipPermission.getCidrBlocks()) {
for (Rule rule : filter(securityGroup.getRules(),
new Predicate<Rule>() {
@Override
public boolean apply(@Nullable Rule input) {
return input.getRemoteIpPrefix() != null && input.getRemoteIpPrefix().equals(cidr) &&
input.getProtocol() != null && input.getProtocol().name().equals(ipPermission.getIpProtocol().name()) &&
input.getPortRangeMin() != null && input.getPortRangeMin() == ipPermission.getFromPort() &&
input.getPortRangeMax() != null && input.getPortRangeMax() == ipPermission.getToPort();
}
})) {
securityGroupApi.deleteRule(rule.getId());
}
}
}
if (!ipPermission.getGroupIds().isEmpty()) {
for (final String groupId : ipPermission.getGroupIds()) {
for (Rule rule : filter(securityGroup.getRules(),
new Predicate<Rule>() {
@Override
public boolean apply(@Nullable Rule input) {
return input.getRemoteGroupId() != null && input.getRemoteGroupId().equals(groupId) &&
input.getProtocol() != null && input.getProtocol().name().equals(ipPermission.getIpProtocol().name()) &&
input.getPortRangeMin() != null && input.getPortRangeMin() == ipPermission.getFromPort() &&
input.getPortRangeMax() != null && input.getPortRangeMax() == ipPermission.getToPort();
}
})) {
securityGroupApi.deleteRule(rule.getId());
}
}
}
return getSecurityGroupById(RegionAndId.fromRegionAndId(region, id).slashEncode());
}
@Override
public SecurityGroup removeIpPermission(IpProtocol protocol, int startPort, int endPort,
Multimap<String, String> tenantIdGroupNamePairs,
Iterable<String> ipRanges,
Iterable<String> groupIds, SecurityGroup group) {
IpPermission.Builder permBuilder = IpPermission.builder();
permBuilder.ipProtocol(protocol);
permBuilder.fromPort(startPort);
permBuilder.toPort(endPort);
permBuilder.tenantIdGroupNamePairs(tenantIdGroupNamePairs);
permBuilder.cidrBlocks(ipRanges);
permBuilder.groupIds(groupIds);
return removeIpPermission(permBuilder.build(), group);
}
@Override
public boolean supportsTenantIdGroupNamePairs() {
return false;
}
@Override
public boolean supportsTenantIdGroupIdPairs() {
return false;
}
@Override
public boolean supportsGroupIds() {
return true;
}
@Override
public boolean supportsPortRangesForGroups() {
return false;
}
@Override
public boolean supportsExclusionCidrBlocks() {
return false;
}
private SecurityGroupApi getSecurityGroupApi(String region) {
return ((ApiContext<NeutronApi>) neutronContextSupplier.get()).getApi().getSecurityGroupApi(region);
}
}

View File

@ -16,14 +16,12 @@
*/
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;
@ -32,9 +30,9 @@ import static org.jclouds.openstack.nova.v2_0.predicates.SecurityGroupPredicates
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import com.google.inject.Inject;
import org.jclouds.Constants;
import org.jclouds.compute.domain.SecurityGroup;
import org.jclouds.compute.extensions.SecurityGroupExtension;
@ -46,13 +44,11 @@ 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.regionscoped.RegionAndId;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionSecurityGroupNameAndPorts;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.SecurityGroupInRegion;
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;
@ -73,7 +69,7 @@ public class NovaSecurityGroupExtension implements SecurityGroupExtension {
protected final ListeningExecutorService userExecutor;
protected final Supplier<Set<String>> regionIds;
protected final Function<SecurityGroupInRegion, SecurityGroup> groupConverter;
protected final LoadingCache<RegionAndName, SecurityGroupInRegion> groupCreator;
protected final LoadingCache<RegionAndName, SecurityGroup> groupCreator;
protected final GroupNamingConvention.Factory namingConvention;
@Inject
@ -81,7 +77,7 @@ public class NovaSecurityGroupExtension implements SecurityGroupExtension {
@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
@Region Supplier<Set<String>> regionIds,
Function<SecurityGroupInRegion, SecurityGroup> groupConverter,
LoadingCache<RegionAndName, SecurityGroupInRegion> groupCreator,
LoadingCache<RegionAndName, SecurityGroup> groupCreator,
GroupNamingConvention.Factory namingConvention) {
this.api = checkNotNull(api, "api");
@ -121,25 +117,9 @@ public class NovaSecurityGroupExtension implements SecurityGroupExtension {
public Set<SecurityGroup> listSecurityGroupsForNode(String id) {
RegionAndId regionAndId = RegionAndId.fromSlashEncoded(checkNotNull(id, "id"));
String region = regionAndId.getRegion();
String instanceId = regionAndId.getId();
Optional<? extends ServerWithSecurityGroupsApi> serverApi = api.getServerWithSecurityGroupsApi(region);
Optional<? extends SecurityGroupApi> sgApi = api.getSecurityGroupApi(region);
if (!serverApi.isPresent() || !sgApi.isPresent()) {
return ImmutableSet.of();
}
ServerWithSecurityGroups instance = serverApi.get().get(instanceId);
if (instance == null) {
return ImmutableSet.of();
}
Set<String> groupNames = instance.getSecurityGroupNames();
final FluentIterable<org.jclouds.openstack.nova.v2_0.domain.SecurityGroup> allGroups = sgApi.get().list();
Set<? extends SecurityGroupInRegion> rawGroups =
allGroups.filter(nameIn(groupNames)).transform(groupToGroupInRegion(allGroups, region)).toSet();
Set<org.jclouds.openstack.nova.v2_0.domain.SecurityGroup> allGroups = api.getServerApi(region).listSecurityGroupForServer(regionAndId.getId());
Set<? extends SecurityGroupInRegion> rawGroups =
FluentIterable.from(allGroups).transform(groupToGroupInRegion(allGroups, region)).toSet();
return ImmutableSet.copyOf(transform(filter(rawGroups, notNull()), groupConverter));
}
@ -174,8 +154,8 @@ public class NovaSecurityGroupExtension implements SecurityGroupExtension {
String markerGroup = namingConvention.create().sharedNameForGroup(name);
RegionSecurityGroupNameAndPorts regionAndName = new RegionSecurityGroupNameAndPorts(region, markerGroup, ImmutableSet.<Integer> of());
SecurityGroupInRegion rawGroup = groupCreator.getUnchecked(regionAndName);
return groupConverter.apply(rawGroup);
SecurityGroup rawGroup = groupCreator.getUnchecked(regionAndName);
return rawGroup;
}
@Override
@ -196,8 +176,8 @@ public class NovaSecurityGroupExtension implements SecurityGroupExtension {
boolean deleted = sgApi.get().delete(groupId);
for (SecurityGroupInRegion cachedSg : groupCreator.asMap().values()) {
if (groupId.equals(cachedSg.getSecurityGroup().getId())) {
for (SecurityGroup cachedSg : groupCreator.asMap().values()) {
if (id.equals(cachedSg.getId())) {
String groupName = cachedSg.getName();
groupCreator.invalidate(new RegionSecurityGroupNameAndPorts(region, groupName, ImmutableSet.<Integer>of()));
break;

View File

@ -27,13 +27,12 @@ import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.SecurityGroup;
import org.jclouds.compute.extensions.SecurityGroupExtension;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import org.jclouds.openstack.nova.v2_0.NovaApi;
import org.jclouds.openstack.nova.v2_0.domain.SecurityGroup;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndId;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.SecurityGroupInRegion;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
@ -47,38 +46,29 @@ public class CleanupResources implements Function<NodeMetadata, Boolean> {
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
protected final NovaApi novaApi;
protected final RemoveFloatingIpFromNodeAndDeallocate removeFloatingIpFromNodeAndDeallocate;
protected final LoadingCache<RegionAndName, SecurityGroupInRegion> securityGroupMap;
protected final LoadingCache<RegionAndName, SecurityGroup> securityGroupMap;
private final SecurityGroupExtension securityGroupExtension;
@Inject
public CleanupResources(NovaApi novaApi, RemoveFloatingIpFromNodeAndDeallocate removeFloatingIpFromNodeAndDeallocate,
LoadingCache<RegionAndName, SecurityGroupInRegion> securityGroupMap) {
this.novaApi = novaApi;
public CleanupResources(RemoveFloatingIpFromNodeAndDeallocate removeFloatingIpFromNodeAndDeallocate,
LoadingCache<RegionAndName, SecurityGroup> securityGroupMap, SecurityGroupExtension securityGroupExtension) {
this.removeFloatingIpFromNodeAndDeallocate = removeFloatingIpFromNodeAndDeallocate;
this.securityGroupMap = checkNotNull(securityGroupMap, "securityGroupMap");
this.securityGroupExtension = securityGroupExtension;
}
@Override
public Boolean apply(NodeMetadata node) {
final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(node.getId());
removeFloatingIpFromNodeifAny(regionAndId);
return removeSecurityGroupCreatedByJcloudsAndInvalidateCache(regionAndId.getRegion(), node.getTags());
return removeSecurityGroupCreatedByJcloudsAndInvalidateCache(node.getTags());
}
public boolean removeSecurityGroupCreatedByJcloudsAndInvalidateCache(String regionId, Set<String> tags) {
public boolean removeSecurityGroupCreatedByJcloudsAndInvalidateCache(Set<String> tags) {
String securityGroupIdCreatedByJclouds = getSecurityGroupIdCreatedByJclouds(tags);
if (securityGroupIdCreatedByJclouds != null) {
SecurityGroup securityGroup = novaApi.getSecurityGroupApi(regionId).get().get(securityGroupIdCreatedByJclouds);
RegionAndName regionAndName = RegionAndName.fromRegionAndName(regionId, securityGroup.getName());
logger.debug(">> deleting securityGroup(%s)", regionAndName);
novaApi.getSecurityGroupApi(regionId).get().delete(securityGroupIdCreatedByJclouds);
securityGroupMap.invalidate(regionAndName);
logger.debug("<< deleted securityGroup(%s)", regionAndName);
return true;
}
return false;
return securityGroupExtension.removeSecurityGroup(securityGroupIdCreatedByJclouds);
}
private void removeFloatingIpFromNodeifAny(RegionAndId regionAndId) {
@ -88,7 +78,7 @@ public class CleanupResources implements Function<NodeMetadata, Boolean> {
logger.warn(e, "<< error removing and deallocating ip from node(%s): %s", regionAndId, e.getMessage());
}
}
private String getSecurityGroupIdCreatedByJclouds(Set<String> tags) {
return FluentIterable.from(tags).filter(new Predicate<String>() {
@Override

View File

@ -17,73 +17,153 @@
package org.jclouds.openstack.nova.v2_0.compute.functions;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.find;
import static org.jclouds.openstack.nova.v2_0.predicates.SecurityGroupPredicates.nameEquals;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import com.google.common.annotations.VisibleForTesting;
import org.jclouds.Context;
import org.jclouds.compute.domain.SecurityGroup;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.Location;
import org.jclouds.logging.Logger;
import org.jclouds.net.domain.IpProtocol;
import org.jclouds.openstack.neutron.v2.NeutronApi;
import org.jclouds.openstack.neutron.v2.domain.Rule;
import org.jclouds.openstack.neutron.v2.domain.RuleDirection;
import org.jclouds.openstack.neutron.v2.domain.RuleProtocol;
import org.jclouds.openstack.neutron.v2.features.SecurityGroupApi;
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.SecurityGroup;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndId;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionSecurityGroupNameAndPorts;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.SecurityGroupInRegion;
import org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupApi;
import org.jclouds.rest.ApiContext;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.FluentIterable;
import com.google.inject.Inject;
@Singleton
public class CreateSecurityGroupIfNeeded implements Function<RegionSecurityGroupNameAndPorts, SecurityGroupInRegion> {
public class CreateSecurityGroupIfNeeded implements Function<RegionSecurityGroupNameAndPorts, SecurityGroup> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
protected final NovaApi novaApi;
private final Supplier<Map<String, Location>> locationIndex;
private final Function<SecurityGroupInRegion, SecurityGroup> securityGroupInRegionSecurityGroupFunction;
private final NeutronSecurityGroupToSecurityGroup.Factory neutronSecurityGroupToSecurityGroup;
@Inject(optional = true)
@Named("openstack-neutron")
Supplier<Context> neutronContextSupplier;
@Inject
public CreateSecurityGroupIfNeeded(NovaApi novaApi) {
this.novaApi = checkNotNull(novaApi, "novaApi");
@VisibleForTesting
public CreateSecurityGroupIfNeeded(NovaApi novaApi, Supplier<Map<String, Location>> locationIndex,
Function<SecurityGroupInRegion, SecurityGroup> securityGroupInRegionSecurityGroupFunction,
NeutronSecurityGroupToSecurityGroup.Factory neutronSecurityGroupToSecurityGroup) {
this.novaApi = novaApi;
this.locationIndex = locationIndex;
this.securityGroupInRegionSecurityGroupFunction = securityGroupInRegionSecurityGroupFunction;
this.neutronSecurityGroupToSecurityGroup = neutronSecurityGroupToSecurityGroup;
}
@Override
public SecurityGroupInRegion apply(RegionSecurityGroupNameAndPorts regionSecurityGroupNameAndPorts) {
checkNotNull(regionSecurityGroupNameAndPorts, "regionSecurityGroupNameAndPorts");
public SecurityGroup apply(final RegionSecurityGroupNameAndPorts regionSecurityGroupNameAndPorts) {
String regionId = regionSecurityGroupNameAndPorts.getRegion();
Optional<? extends SecurityGroupApi> api = novaApi.getSecurityGroupApi(regionId);
checkArgument(api.isPresent(), "Security groups are required, but the extension is not available in region %s!", regionId);
final FluentIterable<SecurityGroup> allGroups = api.get().list();
logger.debug(">> creating securityGroup %s", regionSecurityGroupNameAndPorts);
try {
SecurityGroup securityGroup = api.get().createWithDescription(
regionSecurityGroupNameAndPorts.getName(), regionSecurityGroupNameAndPorts.getName());
Location location = locationIndex.get().get(regionId);
logger.debug("<< created securityGroup(%s)", securityGroup);
for (int port : regionSecurityGroupNameAndPorts.getPorts()) {
authorizeGroupToItselfAndAllIPsToTCPPort(api.get(), securityGroup, port);
logger.debug(">> creating securityGroup %s", regionSecurityGroupNameAndPorts);
SecurityGroupApi securityGroupApi = getNeutronSecurityGroupApi(regionId);
if (securityGroupApi != null) {
org.jclouds.openstack.neutron.v2.domain.SecurityGroup group = securityGroupApi
.create(org.jclouds.openstack.neutron.v2.domain.SecurityGroup.CreateSecurityGroup.createBuilder()
.name(regionSecurityGroupNameAndPorts.getName()).description("security group created by jclouds")
.build());
return createSecurityGroupFrom(group, location, regionSecurityGroupNameAndPorts.getPorts());
} else {
// try to use Nova
Optional<? extends org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupApi> api = novaApi
.getSecurityGroupApi(regionId);
checkArgument(api.isPresent(),
"Security groups are required, but the extension is not available in region %s!", regionId);
final FluentIterable<org.jclouds.openstack.nova.v2_0.domain.SecurityGroup> allGroups = api.get().list();
logger.debug(">> creating securityGroup %s", regionSecurityGroupNameAndPorts);
try {
org.jclouds.openstack.nova.v2_0.domain.SecurityGroup novaSecurityGroup = api.get().createWithDescription(
regionSecurityGroupNameAndPorts.getName(), regionSecurityGroupNameAndPorts.getName());
logger.debug("<< created securityGroup(%s)", novaSecurityGroup);
for (int port : regionSecurityGroupNameAndPorts.getPorts()) {
authorizeGroupToItselfAndAllIPsToTCPPort(api.get(), novaSecurityGroup, port);
}
return securityGroupInRegionSecurityGroupFunction
.apply(new SecurityGroupInRegion(api.get().get(novaSecurityGroup.getId()), regionId, allGroups));
} catch (IllegalStateException e) {
logger.trace("<< trying to find securityGroup(%s): %s", regionSecurityGroupNameAndPorts, e.getMessage());
org.jclouds.openstack.nova.v2_0.domain.SecurityGroup group = find(allGroups,
nameEquals(regionSecurityGroupNameAndPorts.getName()));
logger.debug("<< reused securityGroup(%s)", group.getId());
return securityGroupInRegionSecurityGroupFunction
.apply(new SecurityGroupInRegion(group, regionId, allGroups));
}
return new SecurityGroupInRegion(api.get().get(securityGroup.getId()), regionId, allGroups);
} catch (IllegalStateException e) {
logger.trace("<< trying to find securityGroup(%s): %s", regionSecurityGroupNameAndPorts, e.getMessage());
SecurityGroup group = find(allGroups, nameEquals(regionSecurityGroupNameAndPorts.getName()));
logger.debug("<< reused securityGroup(%s)", group.getId());
return new SecurityGroupInRegion(group, regionId, allGroups);
}
}
private void authorizeGroupToItselfAndAllIPsToTCPPort(SecurityGroupApi securityGroupApi,
SecurityGroup securityGroup, int port) {
logger.debug(">> authorizing securityGroup(%s) permission to 0.0.0.0/0 on port %d", securityGroup, port);
securityGroupApi.createRuleAllowingCidrBlock(securityGroup.getId(), Ingress.builder().ipProtocol(
IpProtocol.TCP).fromPort(port).toPort(port).build(), "0.0.0.0/0");
logger.debug("<< authorized securityGroup(%s) permission to 0.0.0.0/0 on port %d", securityGroup, port);
private SecurityGroup createSecurityGroupFrom(final org.jclouds.openstack.neutron.v2.domain.SecurityGroup group,
Location location, Set<Integer> ports) {
SecurityGroup securityGroup = neutronSecurityGroupToSecurityGroup.create(location).apply(group);
logger.debug("<< created securityGroup(%s)", securityGroup);
SecurityGroupApi securityGroupApi = getNeutronSecurityGroupApi(location.getId());
try {
for (int inboundPort : ports) {
logger.debug(">> authorizing securityGroup(%s) permission to 0.0.0.0/0 on port %d", securityGroup, inboundPort);
securityGroupApi.create(
Rule.CreateRule.createBuilder(RuleDirection.INGRESS, RegionAndId.fromSlashEncoded(securityGroup.getId()).getId()).protocol(RuleProtocol.TCP)
.portRangeMin(inboundPort).portRangeMax(inboundPort).remoteIpPrefix("0.0.0.0/0").build());
logger.debug("<< authorized securityGroup(%s) permission to 0.0.0.0/0 on port %d", securityGroup, inboundPort);
}
return securityGroup;
} catch (IllegalStateException e) {
logger.trace("<< trying to find securityGroup(%s): %s", group, e.getMessage());
return securityGroupApi.listSecurityGroups().concat()
.filter(new Predicate<org.jclouds.openstack.neutron.v2.domain.SecurityGroup>() {
@Override
public boolean apply(@Nullable org.jclouds.openstack.neutron.v2.domain.SecurityGroup input) {
return input.getName().equals(group.getName());
}
}).transform(neutronSecurityGroupToSecurityGroup.create(location)).first().orNull();
}
}
private SecurityGroupApi getNeutronSecurityGroupApi(String region) {
if (neutronContextSupplier == null)
return null;
return ((ApiContext<NeutronApi>) neutronContextSupplier.get()).getApi().getSecurityGroupApi(region);
}
private void authorizeGroupToItselfAndAllIPsToTCPPort(
org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupApi securityGroupApi,
org.jclouds.openstack.nova.v2_0.domain.SecurityGroup securityGroup, int port) {
logger.debug(">> authorizing securityGroup(%s) permission to 0.0.0.0/0 on port %d", securityGroup, port);
securityGroupApi.createRuleAllowingCidrBlock(securityGroup.getId(),
Ingress.builder().ipProtocol(IpProtocol.TCP).fromPort(port).toPort(port).build(), "0.0.0.0/0");
logger.debug("<< authorized securityGroup(%s) permission to 0.0.0.0/0 on port %d", securityGroup, port);
}
}

View File

@ -0,0 +1,85 @@
/*
* 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 com.google.common.base.Function;
import com.google.common.base.Predicates;
import com.google.inject.assistedinject.Assisted;
import org.jclouds.compute.domain.SecurityGroup;
import org.jclouds.compute.domain.SecurityGroupBuilder;
import org.jclouds.domain.Location;
import org.jclouds.net.domain.IpPermission;
import org.jclouds.net.domain.IpProtocol;
import org.jclouds.openstack.neutron.v2.domain.Rule;
import org.jclouds.openstack.neutron.v2.domain.RuleDirection;
import javax.annotation.Nullable;
import javax.inject.Inject;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
public class NeutronSecurityGroupToSecurityGroup implements Function<org.jclouds.openstack.neutron.v2.domain.SecurityGroup, SecurityGroup> {
public interface Factory {
NeutronSecurityGroupToSecurityGroup create(Location location);
}
private final Location location;
@Inject
public NeutronSecurityGroupToSecurityGroup(@Assisted Location location) {
this.location = location;
}
@Override
public SecurityGroup apply(@Nullable org.jclouds.openstack.neutron.v2.domain.SecurityGroup group) {
SecurityGroupBuilder builder = new SecurityGroupBuilder();
builder.providerId(group.getId());
builder.ownerId(group.getTenantId());
builder.name(group.getName());
final String regionId = location.getId();
builder.location(location);
builder.id(regionId + "/" + group.getId());
if (group.getRules() != null) {
builder.ipPermissions(filter(transform(group.getRules(), new Function<Rule, IpPermission>() {
@Override
public IpPermission apply(Rule from) {
if (from.getDirection() == RuleDirection.EGRESS) return null;
IpPermission.Builder builder = IpPermission.builder();
if (from.getProtocol() != null) {
builder.ipProtocol(IpProtocol.fromValue(from.getProtocol().name()));
} else {
builder.ipProtocol(IpProtocol.TCP);
}
if (from.getPortRangeMin() != null) builder.fromPort(from.getPortRangeMin());
if (from.getPortRangeMax() != null) builder.toPort(from.getPortRangeMax());
if (from.getRemoteGroupId() != null) {
builder.groupId(regionId + "/" + from.getRemoteGroupId());
} else if (from.getRemoteIpPrefix() != null){
builder.cidrBlock(from.getRemoteIpPrefix());
}
return builder.build();
}
}), Predicates.notNull()));
}
return builder.build();
}
}

View File

@ -0,0 +1,97 @@
/*
* 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.filter;
import static com.google.common.collect.Iterables.transform;
import javax.annotation.Nullable;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
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.net.domain.IpPermission;
import org.jclouds.openstack.nova.v2_0.domain.SecurityGroupRule;
import org.jclouds.openstack.nova.v2_0.domain.TenantIdAndName;
import com.google.common.base.Function;
import com.google.common.base.Predicates;
import com.google.inject.assistedinject.Assisted;
/**
* A function for transforming a Nova-specific SecurityGroup into a generic
* SecurityGroup object.
*/
public class NovaSecurityGroupToSecurityGroup
implements Function<org.jclouds.openstack.nova.v2_0.domain.SecurityGroup, SecurityGroup> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
public interface Factory {
NovaSecurityGroupToSecurityGroup create(Location location);
}
private final Location location;
@Inject
public NovaSecurityGroupToSecurityGroup(@Assisted Location location) {
this.location = location;
}
@Override
public SecurityGroup apply(@Nullable org.jclouds.openstack.nova.v2_0.domain.SecurityGroup group) {
SecurityGroupBuilder builder = new SecurityGroupBuilder();
builder.providerId(group.getId());
builder.ownerId(group.getTenantId());
builder.name(group.getName());
final String regionId = location.getId();
builder.location(location);
builder.id(regionId + "/" + group.getId());
if (group.getRules() != null) {
builder.ipPermissions(filter(transform(group.getRules(), new Function<SecurityGroupRule, IpPermission>() {
@Override
public IpPermission apply(SecurityGroupRule input) {
return securityGroupRuleToIpPermission(input);
}
}), Predicates.notNull()));
}
return builder.build();
}
private IpPermission securityGroupRuleToIpPermission(SecurityGroupRule rule) {
IpPermission.Builder builder = IpPermission.builder();
builder.ipProtocol(rule.getIpProtocol());
builder.fromPort(rule.getFromPort());
builder.toPort(rule.getToPort());
final TenantIdAndName ruleGroup = rule.getGroup();
if (ruleGroup != null) {
builder.groupId(location.getId() + "/" + ruleGroup.getTenantId());
}
if (rule.getIpRange() != null) {
builder.cidrBlock(rule.getIpRange());
}
return builder.build();
}
}

View File

@ -19,54 +19,31 @@ package org.jclouds.openstack.nova.v2_0.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.inject.Inject;
import javax.inject.Named;
import org.jclouds.compute.domain.SecurityGroup;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionSecurityGroupNameAndPorts;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.SecurityGroupInRegion;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.cache.CacheLoader;
import com.google.common.util.concurrent.Atomics;
public class FindSecurityGroupOrCreate extends CacheLoader<RegionAndName, SecurityGroupInRegion> {
public class FindSecurityGroupOrCreate extends CacheLoader<RegionAndName, SecurityGroup> {
protected final Predicate<AtomicReference<RegionAndName>> returnSecurityGroupExistsInRegion;
protected final Function<RegionSecurityGroupNameAndPorts, SecurityGroupInRegion> groupCreator;
protected final Function<RegionSecurityGroupNameAndPorts, SecurityGroup> groupCreator;
@Inject
public FindSecurityGroupOrCreate(
@Named("SECURITYGROUP_PRESENT") Predicate<AtomicReference<RegionAndName>> returnSecurityGroupExistsInRegion,
Function<RegionSecurityGroupNameAndPorts, SecurityGroupInRegion> groupCreator) {
this.returnSecurityGroupExistsInRegion = checkNotNull(returnSecurityGroupExistsInRegion,
"returnSecurityGroupExistsInRegion");
Function<RegionSecurityGroupNameAndPorts, SecurityGroup> groupCreator) {
this.groupCreator = checkNotNull(groupCreator, "groupCreator");
}
@Override
public SecurityGroupInRegion load(RegionAndName in) {
AtomicReference<RegionAndName> securityGroupInRegionRef = Atomics.newReference(checkNotNull(in,
"regionSecurityGroupNameAndPorts"));
if (returnSecurityGroupExistsInRegion.apply(securityGroupInRegionRef)) {
return returnExistingSecurityGroup(securityGroupInRegionRef);
} else {
public SecurityGroup load(RegionAndName in) {
return createNewSecurityGroup(in);
}
}
private SecurityGroupInRegion returnExistingSecurityGroup(AtomicReference<RegionAndName> securityGroupInRegionRef) {
RegionAndName securityGroupInRegion = securityGroupInRegionRef.get();
checkState(securityGroupInRegion instanceof SecurityGroupInRegion,
"programming error: predicate %s should update the atomic reference to the actual security group found",
returnSecurityGroupExistsInRegion);
return SecurityGroupInRegion.class.cast(securityGroupInRegion);
}
private SecurityGroupInRegion createNewSecurityGroup(RegionAndName in) {
private SecurityGroup createNewSecurityGroup(RegionAndName in) {
checkState(
checkNotNull(in, "regionSecurityGroupNameAndPorts") instanceof RegionSecurityGroupNameAndPorts,
"programming error: when issuing get to this cacheloader, you need to pass an instance of RegionSecurityGroupNameAndPorts, not %s",

View File

@ -80,6 +80,7 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
eTo.configDrive(getConfigDrive());
eTo.novaNetworks(getNovaNetworks());
eTo.availabilityZone(getAvailabilityZone());
eTo.blockDeviceMappings(getBlockDeviceMappings());
}
}

View File

@ -23,7 +23,6 @@ import static com.google.common.base.Preconditions.checkState;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject;
@ -33,25 +32,25 @@ import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.SecurityGroup;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.extensions.SecurityGroupExtension;
import org.jclouds.compute.functions.GroupNamingConvention;
import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName;
import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.nova.v2_0.NovaApi;
import org.jclouds.openstack.nova.v2_0.compute.functions.AllocateAndAddFloatingIpToNode;
import org.jclouds.openstack.nova.v2_0.compute.options.NodeAndNovaTemplateOptions;
import org.jclouds.openstack.nova.v2_0.compute.options.NovaTemplateOptions;
import org.jclouds.openstack.nova.v2_0.domain.KeyPair;
import org.jclouds.openstack.nova.v2_0.domain.SecurityGroup;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionSecurityGroupNameAndPorts;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.SecurityGroupInRegion;
import com.google.common.base.Function;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
@ -70,8 +69,9 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
public static final String JCLOUDS_SG_PREFIX = "jclouds_sg";
private final AllocateAndAddFloatingIpToNode createAndAddFloatingIpToNode;
protected final LoadingCache<RegionAndName, SecurityGroupInRegion> securityGroupCache;
protected final NovaApi novaApi;
private final LoadingCache<RegionAndName, SecurityGroup> securityGroupCache;
private final NovaApi novaApi;
private final SecurityGroupExtension securityGroupExtension;
@Inject
protected ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet(
@ -81,13 +81,16 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
AllocateAndAddFloatingIpToNode createAndAddFloatingIpToNode,
LoadingCache<RegionAndName, SecurityGroupInRegion> securityGroupCache, NovaApi novaApi) {
LoadingCache<RegionAndName, SecurityGroup> securityGroupCache,
NovaApi novaApi,
SecurityGroupExtension securityGroupExtension) {
super(addNodeWithTagStrategy, listNodesStrategy, namingConvention, userExecutor,
customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
this.securityGroupCache = checkNotNull(securityGroupCache, "securityGroupCache");
this.createAndAddFloatingIpToNode = checkNotNull(createAndAddFloatingIpToNode,
"createAndAddFloatingIpToNode");
this.novaApi = checkNotNull(novaApi, "novaApi");
this.securityGroupExtension = securityGroupExtension;
}
@Override
@ -106,14 +109,8 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
checkArgument(novaApi.getKeyPairApi(region).isPresent(),
"Key Pairs are required by options, but the extension is not available! options: %s", templateOptions);
}
final List<Integer> inboundPorts = Ints.asList(templateOptions.getInboundPorts());
if (!templateOptions.getGroups().isEmpty() || !inboundPorts.isEmpty()) {
checkArgument(novaApi.getSecurityGroupApi(region).isPresent(),
"Security groups are required by options, but the extension is not available! options: %s",
templateOptions);
}
KeyPair keyPair = null;
if (templateOptions.shouldGenerateKeyPair()) {
keyPair = generateKeyPair(region, namingConvention.create().sharedNameForGroup(group));
@ -132,29 +129,29 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
ImmutableList.Builder<String> tagsBuilder = ImmutableList.builder();
if (!templateOptions.getGroups().isEmpty()) {
Set<String> securityGroupNames = novaApi.getSecurityGroupApi(region).get().list()
.transform(new Function<SecurityGroup, String>() {
@Override
public String apply(SecurityGroup input) {
return input.getName();
}
})
.toSet();
Iterable<String> securityGroupNames = Iterables.transform(securityGroupExtension.listSecurityGroups(), new Function<org.jclouds.compute.domain.SecurityGroup, String>() {
@Override
public String apply(@Nullable org.jclouds.compute.domain.SecurityGroup input) {
return input.getName();
}
});
for (String securityGroupName : templateOptions.getGroups()) {
checkState(securityGroupNames.contains(securityGroupName), "Cannot find security group with name " + securityGroupName + ". \nSecurity groups available are: \n" + Iterables.toString(securityGroupNames)); // {
checkState(Iterables.contains(securityGroupNames, securityGroupName), "Cannot find security group with name " + securityGroupName + ". \nSecurity groups available are: \n" + Iterables.toString(securityGroupNames)); // {
}
}
else if (!inboundPorts.isEmpty()) {
SecurityGroupInRegion securityGroupInRegion;
} else if (!inboundPorts.isEmpty()) {
String securityGroupName = namingConvention.create().sharedNameForGroup(group);
try {
securityGroupInRegion = securityGroupCache.get(new RegionSecurityGroupNameAndPorts(region, securityGroupName, inboundPorts));
} catch (ExecutionException e) {
throw Throwables.propagate(e.getCause());
// populate the security group cache with existing security groups
for (SecurityGroup existingSecurityGroup : securityGroupExtension.listSecurityGroupsInLocation(template.getLocation())) {
securityGroupCache.put(new RegionSecurityGroupNameAndPorts(region, existingSecurityGroup.getName(), inboundPorts), existingSecurityGroup);
}
templateOptions.securityGroups(securityGroupName);
tagsBuilder.add(String.format("%s-%s", JCLOUDS_SG_PREFIX, securityGroupInRegion.getSecurityGroup().getId()));
SecurityGroup securityGroup = securityGroupCache.getUnchecked(new RegionSecurityGroupNameAndPorts(region, securityGroupName, inboundPorts));
templateOptions.securityGroups(securityGroup.getName());
tagsBuilder.add(String.format("%s-%s", JCLOUDS_SG_PREFIX, securityGroup.getId()));
}
templateOptions.tags(tagsBuilder.build());
Map<?, ListenableFuture<Void>> responses = super.execute(group, count, template, goodNodes, badNodes,

View File

@ -0,0 +1,80 @@
/*
* 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.domain.regionscoped;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collection;
import java.util.Map;
import org.jclouds.openstack.neutron.v2.domain.SecurityGroup;
import org.jclouds.openstack.nova.v2_0.domain.TenantIdAndName;
import com.google.common.base.MoreObjects.ToStringHelper;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
public class NeutronSecurityGroupInRegion extends RegionAndName {
protected final SecurityGroup securityGroup;
protected final Multimap<TenantIdAndName, SecurityGroup> groupsByName;
public NeutronSecurityGroupInRegion(SecurityGroup securityGroup, String regionId, Iterable<SecurityGroup> allGroupsInRegion) {
super(regionId, checkNotNull(securityGroup, "securityGroup").getName());
this.securityGroup = securityGroup;
this.groupsByName = HashMultimap.create();
for (SecurityGroup groupInRegion : allGroupsInRegion) {
final TenantIdAndName tenantIdAndName = TenantIdAndName.builder()
.tenantId(groupInRegion.getTenantId())
.name(groupInRegion.getName())
.build();
this.groupsByName.put(tenantIdAndName, groupInRegion);
}
}
public SecurityGroup getSecurityGroup() {
return securityGroup;
}
/**
* Returns a map of group {@link TenantIdAndName}s to groups.
*
* The returned value is a collection, to take into account the possibility that certain clouds
* may permit duplicate group names.
*
* @return The map of names to (collections of) groups.
*/
public Map<TenantIdAndName, Collection<SecurityGroup>> getGroupsByName() {
return groupsByName.asMap();
}
// superclass hashCode/equals are good enough, and help us use RegionAndName and SecurityGroupInRegion
// interchangeably as Map keys
@Override
protected ToStringHelper string() {
return super.string()
.add("securityGroup", securityGroup)
.add("groupsByName", groupsByName);
}
@Override
public String toString() {
return string().toString();
}
}

View File

@ -19,6 +19,7 @@ package org.jclouds.openstack.nova.v2_0.features;
import com.google.common.base.Optional;
import java.util.Map;
import java.util.Set;
import javax.inject.Named;
import javax.ws.rs.Consumes;
@ -31,6 +32,7 @@ import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.jclouds.Fallbacks;
import org.jclouds.Fallbacks.AbsentOn403Or404Or500;
import org.jclouds.Fallbacks.EmptyMapOnNotFoundOr404;
import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404;
@ -40,6 +42,7 @@ import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
import org.jclouds.collect.PagedIterable;
import org.jclouds.fallbacks.MapHttp4xxCodesToExceptions;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.nova.v2_0.domain.SecurityGroup;
import org.jclouds.openstack.v2_0.domain.PaginatedCollection;
import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v2_0.KeystoneFallbacks.EmptyPaginatedCollectionOnNotFoundOr404;
@ -362,8 +365,8 @@ public interface ServerApi {
*
* @param id
* id of the image
* @param metadata
* a Map containing the metadata
* @param key
* a key containing the metadata
* @return the value or null if not present
*/
@Named("server:getMetadata")
@ -428,4 +431,19 @@ public interface ServerApi {
@ResponseParser(ParseDiagnostics.class)
@Fallback(AbsentOn403Or404Or500.class)
Optional<Map<String, String>> getDiagnostics(@PathParam("id") String id);
/**
* Lists Security Groups for a server.
* @param id
* id of the server
* @return a list of security groups attached to the server
*/
@Named("server:getSecurityGroups")
@GET
@Path("/{id}/os-security-groups")
@SelectJson("security_groups")
@Fallback(Fallbacks.EmptySetOnNotFoundOr404.class)
Set<SecurityGroup> listSecurityGroupForServer(@PathParam("id") String id);
}

View File

@ -66,7 +66,7 @@ public class NovaComputeServiceAdapterExpectTest extends BaseNovaComputeServiceC
.addHeader("Accept", "application/json")
.addHeader("X-Auth-Token", authToken)
.payload(payloadFromStringWithContentType(
"{\"server\":{\"name\":\"test-e92\",\"imageRef\":\"1241\",\"flavorRef\":\"100\",\"networks\": [{\"uuid\": \"4ebd35cf-bfe7-4d93-b0d8-eb468ce2245a\"}]}}", "application/json"))
"{\"server\":{\"name\":\"test-e92\",\"imageRef\":\"2235\",\"flavorRef\":\"100\",\"networks\":[{\"uuid\":\"4ebd35cf-bfe7-4d93-b0d8-eb468ce2245a\"}]}}", "application/json"))
.build();
HttpResponse createServerResponse = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
@ -101,7 +101,7 @@ public class NovaComputeServiceAdapterExpectTest extends BaseNovaComputeServiceC
.addHeader("Accept", "application/json")
.addHeader("X-Auth-Token", authToken)
.payload(payloadFromStringWithContentType(
"{\"server\":{\"name\":\"test-e92\",\"imageRef\":\"1241\",\"flavorRef\":\"100\",\"OS-DCF:diskConfig\":\"AUTO\"}}", "application/json"))
"{\"server\":{\"name\":\"test-e92\",\"imageRef\":\"2235\",\"flavorRef\":\"100\",\"OS-DCF:diskConfig\":\"AUTO\"}}", "application/json"))
.build();
HttpResponse createServerResponse = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
@ -136,7 +136,7 @@ public class NovaComputeServiceAdapterExpectTest extends BaseNovaComputeServiceC
.addHeader("Accept", "application/json")
.addHeader("X-Auth-Token", authToken)
.payload(payloadFromStringWithContentType(
"{\"server\":{\"name\":\"test-e92\",\"imageRef\":\"1241\",\"flavorRef\":\"100\",\"config_drive\":\"true\"}}", "application/json"))
"{\"server\":{\"name\":\"test-e92\",\"imageRef\":\"2235\",\"flavorRef\":\"100\",\"config_drive\":\"true\"}}", "application/json"))
.build();
HttpResponse createServerResponse = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
@ -170,7 +170,7 @@ public class NovaComputeServiceAdapterExpectTest extends BaseNovaComputeServiceC
.addHeader("Accept", "application/json")
.addHeader("X-Auth-Token", authToken)
.payload(payloadFromStringWithContentType(
"{\"server\":{\"name\":\"test-e92\",\"imageRef\":\"1241\",\"flavorRef\":\"100\",\"networks\":[{\"uuid\":\"12345\", \"port\":\"67890\", \"fixed_ip\":\"192.168.0.1\"},{\"uuid\":\"54321\", \"port\":\"09876\", \"fixed_ip\":\"192.168.0.2\"},{\"uuid\":\"non-nova-uuid\"}]}}", "application/json"))
"{\"server\":{\"name\":\"test-e92\",\"imageRef\":\"2235\",\"flavorRef\":\"100\",\"networks\":[{\"uuid\":\"12345\",\"port\":\"67890\",\"fixed_ip\":\"192.168.0.1\"},{\"uuid\":\"54321\",\"port\":\"09876\",\"fixed_ip\":\"192.168.0.2\"},{\"uuid\":\"non-nova-uuid\"}]}}", "application/json"))
.build();
HttpResponse createServerResponse = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
@ -217,7 +217,7 @@ public class NovaComputeServiceAdapterExpectTest extends BaseNovaComputeServiceC
.addHeader("Accept", "application/json")
.addHeader("X-Auth-Token", authToken)
.payload(payloadFromStringWithContentType(
"{\"server\":{\"name\":\"test-e92\",\"imageRef\":\"1241\",\"flavorRef\":\"100\",\"security_groups\":[{\"name\":\"group1\"}, {\"name\":\"group2\"}]}}", "application/json"))
"{\"server\":{\"name\":\"test-e92\",\"imageRef\":\"2235\",\"flavorRef\":\"100\",\"security_groups\":[{\"name\":\"group1\"},{\"name\":\"group2\"}]}}", "application/json"))
.build();
HttpResponse createServerResponse = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
@ -258,7 +258,7 @@ public class NovaComputeServiceAdapterExpectTest extends BaseNovaComputeServiceC
.addHeader("Accept", "application/json")
.addHeader("X-Auth-Token", authToken)
.payload(payloadFromStringWithContentType(
"{\"server\":{\"name\":\"test-e92\",\"imageRef\":\"1241\",\"flavorRef\":\"100\",\"key_name\":\"foo\"}}", "application/json"))
"{\"server\":{\"name\":\"test-e92\",\"imageRef\":\"2235\",\"flavorRef\":\"100\",\"key_name\":\"foo\"}}", "application/json"))
.build();
@ -301,7 +301,7 @@ public class NovaComputeServiceAdapterExpectTest extends BaseNovaComputeServiceC
.addHeader("Accept", "application/json")
.addHeader("X-Auth-Token", authToken)
.payload(payloadFromStringWithContentType(
"{\"server\":{\"name\":\"test-e92\",\"imageRef\":\"1241\",\"flavorRef\":\"100\"}}", "application/json"))
"{\"server\":{\"name\":\"test-e92\",\"imageRef\":\"2235\",\"flavorRef\":\"100\"}}", "application/json"))
.build();
HttpResponse createServerResponse = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")

View File

@ -225,7 +225,7 @@ public class NovaComputeServiceExpectTest extends BaseNovaComputeServiceExpectTe
.addHeader("X-Auth-Token", authToken)
.payload(
payloadFromStringWithContentType(
"{\"server\":{\"name\":\"test-1\",\"imageRef\":\"14\",\"flavorRef\":\"1\",\"metadata\":{\"jclouds_tags\":\"jclouds_sg-2769\"},\"key_name\":\"jclouds-test-0\",\"security_groups\":[{\"name\":\"jclouds-test\"}]}}",
"{\"server\":{\"name\":\"test-1\",\"imageRef\":\"2235\",\"flavorRef\":\"1\",\"metadata\":{\"jclouds_tags\":\"jclouds_sg-RegionOne/2769\"},\"key_name\":\"jclouds-test-0\",\"security_groups\":[{\"name\":\"jclouds-test\"}]}}",
"application/json")).build();
HttpResponse createdServer = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
@ -280,7 +280,7 @@ public class NovaComputeServiceExpectTest extends BaseNovaComputeServiceExpectTe
.addHeader("X-Auth-Token", authToken)
.payload(
payloadFromStringWithContentType(
"{\"server\":{\"name\":\"test-0\",\"imageRef\":\"14\",\"flavorRef\":\"1\",\"metadata\":{\"jclouds_tags\":\"jclouds_sg-2769\"},\"key_name\":\"testkeypair\",\"security_groups\":[{\"name\":\"jclouds-test\"}]}}",
"{\"server\":{\"name\":\"test-0\",\"imageRef\":\"2235\",\"flavorRef\":\"1\",\"metadata\":{\"jclouds_tags\":\"jclouds_sg-RegionOne/2769\"},\"key_name\":\"testkeypair\",\"security_groups\":[{\"name\":\"jclouds-test\"}]}}",
"application/json")).build();
HttpResponse createdServer = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
@ -349,7 +349,7 @@ public class NovaComputeServiceExpectTest extends BaseNovaComputeServiceExpectTe
.addHeader("X-Auth-Token", authToken)
.payload(
payloadFromStringWithContentType(
"{\"server\":{\"name\":\"test-0\",\"imageRef\":\"14\",\"flavorRef\":\"1\",\"key_name\":\"testkeypair\",\"security_groups\":[{\"name\":\"name1\"}]}}",
"{\"server\":{\"name\":\"test-0\",\"imageRef\":\"2235\",\"flavorRef\":\"1\",\"key_name\":\"testkeypair\",\"security_groups\":[{\"name\":\"name1\"}]}}",
"application/json")).build();
HttpResponse createdServer = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")

View File

@ -21,12 +21,15 @@ import static java.util.logging.Logger.getAnonymousLogger;
import java.util.Properties;
import org.jclouds.compute.internal.BaseComputeServiceLiveTest;
import org.jclouds.logging.config.LoggingModule;
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
import org.jclouds.openstack.keystone.config.KeystoneProperties;
import org.jclouds.openstack.nova.v2_0.config.NovaProperties;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
@Test(groups = "live", singleThreaded = true, testName = "NovaComputeServiceLiveTest")
@ -40,7 +43,17 @@ public class NovaComputeServiceLiveTest extends BaseComputeServiceLiveTest {
protected Module getSshModule() {
return new SshjSshClientModule();
}
@Override
protected LoggingModule getLoggingModule() {
return new SLF4JLoggingModule();
}
@Override
protected Iterable<Module> setupModules() {
return ImmutableSet.of(getLoggingModule(), credentialStoreModule, getSshModule());
}
@Override
public void testOptionToNotBlock() {
// start call is blocking anyway.
@ -49,12 +62,14 @@ public class NovaComputeServiceLiveTest extends BaseComputeServiceLiveTest {
@Test(enabled = true, dependsOnMethods = "testReboot")
public void testSuspendResume() throws Exception {
try {
// may fail because of lack of AdminActions extension or non-admin user, so log and continue
// may fail because of lack of AdminActions extension or non-admin user, so log
// and continue
super.testSuspendResume();
} catch (AuthorizationException e) {
getAnonymousLogger().info("testSuspendResume() threw, probably due to lack of privileges: " + e.getMessage());
} catch (UnsupportedOperationException e) {
getAnonymousLogger().info("testSuspendResume() threw, probably due to unavailable AdminActions extension: " + e.getMessage());
getAnonymousLogger().info(
"testSuspendResume() threw, probably due to unavailable AdminActions extension: " + e.getMessage());
}
}

View File

@ -0,0 +1,117 @@
/*
* 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 java.util.Properties;
import java.util.concurrent.ExecutionException;
import javax.annotation.Resource;
import javax.inject.Named;
import com.google.common.base.Optional;
import org.jclouds.Context;
import org.jclouds.ContextBuilder;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.domain.SecurityGroup;
import org.jclouds.compute.extensions.SecurityGroupExtension;
import org.jclouds.compute.extensions.internal.BaseSecurityGroupExtensionLiveTest;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.config.ContextLinking;
import org.jclouds.logging.Logger;
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
import org.jclouds.openstack.neutron.v2.NeutronApi;
import org.jclouds.rest.ApiContext;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.TypeToken;
import com.google.inject.Module;
import static org.testng.Assert.assertTrue;
/**
* Live test for openstack-neutron {@link SecurityGroupExtension} implementation.
*/
@Test(groups = "live", singleThreaded = true, testName = "NeutronSecurityGroupExtensionLiveTest")
public class NeutronSecurityGroupExtensionLiveTest extends BaseSecurityGroupExtensionLiveTest {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.CONSOLE;
private Context neutronApiContext;
public NeutronSecurityGroupExtensionLiveTest() {
provider = "openstack-nova";
Properties overrides = setupProperties();
neutronApiContext = ContextBuilder.newBuilder("openstack-neutron")
.endpoint(setIfTestSystemPropertyPresent(overrides,
"openstack-nova.endpoint"))
.credentials(setIfTestSystemPropertyPresent(overrides,
"openstack-nova.identity"),
setIfTestSystemPropertyPresent(overrides, "openstack-nova.credential"))
.modules(ImmutableSet.<Module>of(
new SshjSshClientModule(),
new SLF4JLoggingModule())
)
.build(new TypeToken<ApiContext<NeutronApi>>() {});
}
@Test(groups = { "integration", "live" }, singleThreaded = true)
public void testListSecurityGroups() throws RunNodesException, InterruptedException, ExecutionException {
skipIfSecurityGroupsNotSupported();
ComputeService computeService = view.getComputeService();
Optional<SecurityGroupExtension> securityGroupExtension = computeService.getSecurityGroupExtension();
assertTrue(securityGroupExtension.isPresent(), "security extension was not present");
for (SecurityGroup securityGroup : securityGroupExtension.get().listSecurityGroups()) {
logger.info(securityGroup.toString());
}
}
@Test(groups = { "integration", "live" }, singleThreaded = true)
public void testListSecurityGroupsForNode() throws RunNodesException, InterruptedException, ExecutionException {
skipIfSecurityGroupsNotSupported();
ComputeService computeService = view.getComputeService();
Optional<SecurityGroupExtension> securityGroupExtension = computeService.getSecurityGroupExtension();
assertTrue(securityGroupExtension.isPresent(), "security extension was not present");
for (SecurityGroup securityGroup : securityGroupExtension.get().listSecurityGroupsForNode("uk-1/97374b9f-c706-4c4a-ae5a-48b6d2e58db9")) {
logger.info(securityGroup.toString());
}
}
@AfterClass
@Override
protected void tearDownContext() {
super.tearDownContext();
}
@Override
protected Iterable<Module> setupModules() {
return ImmutableSet.<Module> of(ContextLinking.linkContext(neutronApiContext), getLoggingModule(), credentialStoreModule, getSshModule());
}
}

View File

@ -113,14 +113,13 @@ public class NovaSecurityGroupExtensionExpectTest extends BaseNovaComputeService
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/v2/3456/os-security-groups")).headers(
URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/3456/servers/8d0a6ca5-8849-4b3d-b86e-f24c92490ebb/os-security-groups")).headers(
ImmutableMultimap.<String, String> 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<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
requestResponseMap.put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess);
requestResponseMap.put(extensionsOfNovaRequest, extensionsOfNovaResponse);

View File

@ -46,7 +46,6 @@ import com.google.common.collect.Iterables;
@Test(groups = "live", singleThreaded = true, testName = "NovaSecurityGroupExtensionLiveTest")
public class NovaSecurityGroupExtensionLiveTest extends BaseSecurityGroupExtensionLiveTest {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.CONSOLE;

View File

@ -17,11 +17,13 @@
package org.jclouds.openstack.nova.v2_0.compute.loaders;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.fail;
import java.util.concurrent.atomic.AtomicReference;
import org.jclouds.compute.domain.SecurityGroup;
import org.jclouds.compute.domain.SecurityGroupBuilder;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionSecurityGroupNameAndPorts;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.SecurityGroupInRegion;
@ -29,111 +31,99 @@ import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@Test(groups = "unit", singleThreaded = true, testName = "FindSecurityGroupOrCreateTest")
public class FindSecurityGroupOrCreateTest {
@Test(groups = "unit", singleThreaded = true, testName = "FindSecurityGroupInRegionOrCreateTest")
public class FindSecurityGroupInRegionOrCreateTest {
@Test
public void testWhenNotFoundCreatesANewSecurityGroup() throws Exception {
Predicate<AtomicReference<RegionAndName>> returnSecurityGroupExistsInRegion = Predicates.alwaysFalse();
SecurityGroupInRegion securityGroupInRegion = createMock(SecurityGroupInRegion.class);
SecurityGroup securityGroup = createMock(SecurityGroup.class);
RegionSecurityGroupNameAndPorts input = new RegionSecurityGroupNameAndPorts("region", "groupName", ImmutableSet
.<Integer> of(22, 8080));
Function<RegionSecurityGroupNameAndPorts, SecurityGroupInRegion> groupCreator = Functions.forMap(ImmutableMap
.<RegionSecurityGroupNameAndPorts, SecurityGroupInRegion> of(input, securityGroupInRegion));
Function<RegionSecurityGroupNameAndPorts, SecurityGroup> groupCreator = Functions.forMap(ImmutableMap
.of(input, securityGroup));
FindSecurityGroupOrCreate parser = new FindSecurityGroupOrCreate(
returnSecurityGroupExistsInRegion, groupCreator);
FindSecurityGroupOrCreate parser = new FindSecurityGroupOrCreate(groupCreator);
assertEquals(parser.load(input), securityGroupInRegion);
assertEquals(parser.load(input), securityGroup);
}
@Test
@Test(enabled = false) // TODO does it apply now?
public void testWhenFoundReturnsSecurityGroupFromAtomicReferenceValueUpdatedDuringPredicateCheck() throws Exception {
SecurityGroup expected = new SecurityGroupBuilder().id("region/id").name("name").build();
final SecurityGroupInRegion securityGroupInRegion = createMock(SecurityGroupInRegion.class);
final org.jclouds.openstack.nova.v2_0.domain.SecurityGroup novaSecurityGroup = createMock(org.jclouds.openstack.nova.v2_0.domain.SecurityGroup.class);
Predicate<AtomicReference<RegionAndName>> returnSecurityGroupExistsInRegion = new Predicate<AtomicReference<RegionAndName>>() {
@Override
public boolean apply(AtomicReference<RegionAndName> input) {
input.set(securityGroupInRegion);
return true;
}
expect(novaSecurityGroup.getId()).andReturn("id").anyTimes();
expect(novaSecurityGroup.getName()).andReturn("name");
replay(novaSecurityGroup);
};
expect(securityGroupInRegion.getRegion()).andReturn("region");
expect(securityGroupInRegion.getSecurityGroup()).andReturn(novaSecurityGroup).anyTimes();
replay(securityGroupInRegion);
RegionAndName input = RegionAndName.fromRegionAndName("region", "groupName");
Function<RegionSecurityGroupNameAndPorts, SecurityGroupInRegion> groupCreator = new Function<RegionSecurityGroupNameAndPorts, SecurityGroupInRegion>() {
Function<RegionSecurityGroupNameAndPorts, SecurityGroup> groupCreator = new Function<RegionSecurityGroupNameAndPorts, SecurityGroup>() {
@Override
public SecurityGroupInRegion apply(RegionSecurityGroupNameAndPorts input) {
public SecurityGroup apply(RegionSecurityGroupNameAndPorts input) {
fail();
return null;
}
};
FindSecurityGroupOrCreate parser = new FindSecurityGroupOrCreate(
returnSecurityGroupExistsInRegion, groupCreator);
FindSecurityGroupOrCreate parser = new FindSecurityGroupOrCreate(groupCreator);
assertEquals(parser.load(input), securityGroupInRegion);
assertEquals(parser.load(input), expected);
}
@Test(expectedExceptions = IllegalStateException.class)
@Test(expectedExceptions = IllegalStateException.class, enabled = false) // TODO does it apply now?
public void testWhenFoundPredicateMustUpdateAtomicReference() throws Exception {
Predicate<AtomicReference<RegionAndName>> returnSecurityGroupExistsInRegion = Predicates.alwaysTrue();
RegionAndName input = RegionAndName.fromRegionAndName("region", "groupName");
Function<RegionSecurityGroupNameAndPorts, SecurityGroupInRegion> groupCreator = new Function<RegionSecurityGroupNameAndPorts, SecurityGroupInRegion>() {
Function<RegionSecurityGroupNameAndPorts, SecurityGroup> groupCreator = new Function<RegionSecurityGroupNameAndPorts, SecurityGroup>() {
@Override
public SecurityGroupInRegion apply(RegionSecurityGroupNameAndPorts input) {
public SecurityGroup apply(RegionSecurityGroupNameAndPorts input) {
fail();
return null;
}
};
FindSecurityGroupOrCreate parser = new FindSecurityGroupOrCreate(
returnSecurityGroupExistsInRegion, groupCreator);
FindSecurityGroupOrCreate parser = new FindSecurityGroupOrCreate(groupCreator);
parser.load(input);
}
@Test(expectedExceptions = IllegalStateException.class)
public void testWhenNotFoundInputMustBeRegionSecurityGroupNameAndPorts() throws Exception {
Predicate<AtomicReference<RegionAndName>> returnSecurityGroupExistsInRegion = Predicates.alwaysFalse();
RegionAndName input = RegionAndName.fromRegionAndName("region", "groupName");
Function<RegionSecurityGroupNameAndPorts, SecurityGroupInRegion> groupCreator = new Function<RegionSecurityGroupNameAndPorts, SecurityGroupInRegion>() {
Function<RegionSecurityGroupNameAndPorts, SecurityGroup> groupCreator = new Function<RegionSecurityGroupNameAndPorts, SecurityGroup>() {
@Override
public SecurityGroupInRegion apply(RegionSecurityGroupNameAndPorts input) {
public SecurityGroup apply(RegionSecurityGroupNameAndPorts input) {
fail();
return null;
}
};
FindSecurityGroupOrCreate parser = new FindSecurityGroupOrCreate(
returnSecurityGroupExistsInRegion, groupCreator);
FindSecurityGroupOrCreate parser = new FindSecurityGroupOrCreate(groupCreator);
parser.load(input);

View File

@ -19,6 +19,7 @@ package org.jclouds.openstack.nova.v2_0.features;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import com.google.common.collect.Iterables;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.nova.v2_0.NovaApi;
@ -30,6 +31,7 @@ import org.jclouds.openstack.nova.v2_0.options.RebuildServerOptions;
import org.jclouds.openstack.nova.v2_0.parse.ParseCreatedServerTest;
import org.jclouds.openstack.nova.v2_0.parse.ParseMetadataListTest;
import org.jclouds.openstack.nova.v2_0.parse.ParseMetadataUpdateTest;
import org.jclouds.openstack.nova.v2_0.parse.ParseSecurityGroupListTest;
import org.jclouds.openstack.nova.v2_0.parse.ParseServerDetailsStatesTest;
import org.jclouds.openstack.nova.v2_0.parse.ParseServerDiagnostics;
import org.jclouds.openstack.nova.v2_0.parse.ParseServerListTest;
@ -498,4 +500,35 @@ public class ServerApiExpectTest extends BaseNovaApiExpectTest {
HttpResponse.builder().statusCode(statusCode).build()).getServerApi("az-1.region-a.geo-1").getDiagnostics(serverId).isPresent());
}
}
public void testListSecurityGroupsForServerWhenResponseIs200() throws Exception {
String serverId = "123";
HttpRequest getDiagnostics = HttpRequest.builder()
.method("GET")
.addHeader("Accept", "application/json")
.endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/3456/servers/" + serverId + "/os-security-groups")
.addHeader("X-Auth-Token", authToken)
.build();
HttpResponse serverDiagnosticsResponse = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
.payload(payloadFromResourceWithContentType("/securitygroup_list.json", "application/json; charset=UTF-8")).build();
NovaApi apiWithNewServer = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
responseWithKeystoneAccess, getDiagnostics, serverDiagnosticsResponse);
assertEquals(Iterables.toString(apiWithNewServer.getServerApi("az-1.region-a.geo-1").listSecurityGroupForServer(serverId)),
Iterables.toString(new ParseSecurityGroupListTest().expected()));
}
public void testListSecurityGroupsForServerWhenResponseIs404() throws Exception {
String serverId = "123";
HttpRequest getSecurityGroups = HttpRequest.builder()
.method("GET")
.addHeader("Accept", "application/json")
.endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/3456/servers/" + serverId + "/os-security-groups")
.addHeader("X-Auth-Token", authToken)
.build();
assertTrue(requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess, getSecurityGroups,
HttpResponse.builder().statusCode(404).build()).getServerApi("az-1.region-a.geo-1").listSecurityGroupForServer(serverId).isEmpty());
}
}

View File

@ -24,6 +24,7 @@ import static org.testng.Assert.assertTrue;
import org.jclouds.http.HttpResponseException;
import org.jclouds.openstack.nova.v2_0.domain.BlockDeviceMapping;
import org.jclouds.openstack.nova.v2_0.domain.Network;
import org.jclouds.openstack.nova.v2_0.domain.SecurityGroup;
import org.jclouds.openstack.nova.v2_0.domain.Server;
import org.jclouds.openstack.nova.v2_0.domain.ServerCreated;
import org.jclouds.openstack.nova.v2_0.extensions.AvailabilityZoneApi;
@ -88,7 +89,7 @@ public class ServerApiLiveTest extends BaseNovaApiLiveTest {
for (String regionId : regions) {
ServerApi serverApi = api.getServerApi(regionId);
Optional<? extends AvailabilityZoneApi> availabilityZoneApi = api.getAvailabilityZoneApi(regionId);
availabilityZone = availabilityZoneApi.isPresent() ? Iterables.getLast(availabilityZoneApi.get().list()).getName() : "nova";
availabilityZone = availabilityZoneApi.isPresent() ? Iterables.get(availabilityZoneApi.get().list(), 0).getName() : "nova";
try {
serverId = createServer(regionId, availabilityZone).getId();
Server server = serverApi.get(serverId);
@ -226,6 +227,18 @@ public class ServerApiLiveTest extends BaseNovaApiLiveTest {
}
}
@Test(description = "GET /v${apiVersion}/servers/{id}/os-security-groups")
public void testListSecurityGroupForServer() throws Exception {
for (String regionId : regions) {
ServerApi serverApi = api.getServerApi(regionId);
for (Resource server : serverApi.list().concat()) {
for (SecurityGroup securityGroup : serverApi.listSecurityGroupForServer(server.getId())) {
checkSecurityGroup(securityGroup);
}
}
}
}
private Server createServer(String regionId, String availabilityZoneId) {
ServerApi serverApi = api.getServerApi(regionId);
@ -250,4 +263,10 @@ public class ServerApiLiveTest extends BaseNovaApiLiveTest {
checkResource(server);
assertNotNull(server.getFlavor());
}
private void checkSecurityGroup(SecurityGroup securityGroup) {
assertNotNull(securityGroup.getId());
assertNotNull(securityGroup.getName());
assertNotNull(securityGroup.getRules());
}
}

View File

@ -19,16 +19,28 @@ package org.jclouds.openstack.nova.v2_0.functions;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.Map;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.inject.Injector;
import org.jclouds.compute.domain.SecurityGroupBuilder;
import org.jclouds.domain.Location;
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.NovaApi;
import org.jclouds.openstack.nova.v2_0.compute.functions.CreateSecurityGroupIfNeeded;
import org.jclouds.openstack.nova.v2_0.domain.SecurityGroup;
import org.jclouds.openstack.nova.v2_0.compute.functions.NeutronSecurityGroupToSecurityGroup;
import org.jclouds.openstack.nova.v2_0.compute.functions.NovaSecurityGroupInRegionToSecurityGroup;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionSecurityGroupNameAndPorts;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.SecurityGroupInRegion;
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiExpectTest;
import org.jclouds.openstack.nova.v2_0.parse.ParseComputeServiceTypicalSecurityGroupTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
@ -48,6 +60,18 @@ public class CreateSecurityGroupIfNeededTest extends BaseNovaApiExpectTest {
"{\"security_group\":{\"name\":\"jclouds_mygroup\",\"description\":\"jclouds_mygroup\"}}",
"application/json")).build();
Location provider = new LocationBuilder().scope(LocationScope.PROVIDER).id("openstack-nova").description(
"openstack-nova").build();
Location region = new LocationBuilder().id("az-1.region-a.geo-1").description("az-1.region-a.geo-1").scope(
LocationScope.REGION).parent(provider).build();
Supplier<Map<String, Location>> locationIndex = Suppliers.<Map<String, Location>> ofInstance(ImmutableMap
.<String, Location> of("az-1.region-a.geo-1", region));
Function<SecurityGroupInRegion, org.jclouds.compute.domain.SecurityGroup> securityGroupInRegionSecurityGroupFunction = new NovaSecurityGroupInRegionToSecurityGroup(locationIndex);
Injector injector = createInjector(Functions.forMap(ImmutableMap.<HttpRequest, HttpResponse>of()), createModule(), setupProperties());
NeutronSecurityGroupToSecurityGroup.Factory factory = injector.getInstance(NeutronSecurityGroupToSecurityGroup.Factory.class);
private final int groupId = 2769;
public void testCreateNewGroup() throws Exception {
@ -126,13 +150,46 @@ public class CreateSecurityGroupIfNeededTest extends BaseNovaApiExpectTest {
NovaApi apiCanCreateSecurityGroup = requestsSendResponses(builder.build());
CreateSecurityGroupIfNeeded fn = new CreateSecurityGroupIfNeeded(apiCanCreateSecurityGroup);
CreateSecurityGroupIfNeeded fn = new CreateSecurityGroupIfNeeded(apiCanCreateSecurityGroup, locationIndex, securityGroupInRegionSecurityGroupFunction, factory);
// we can find it
final SecurityGroup expected = new ParseComputeServiceTypicalSecurityGroupTest().expected();
org.jclouds.compute.domain.SecurityGroup expected = new SecurityGroupBuilder()
.id("az-1.region-a.geo-1/2769")
.providerId("2769")
.name("jclouds_mygroup")
.location(locationIndex.get().get("az-1.region-a.geo-1"))
.ipPermissions(ImmutableList.of(
IpPermission.builder()
.ipProtocol(IpProtocol.TCP)
.fromPort(22)
.toPort(22)
.cidrBlock("0.0.0.0/0")
.build(),
IpPermission.builder()
.ipProtocol(IpProtocol.TCP)
.fromPort(22)
.toPort(22)
.groupIds(ImmutableList.of("az-1.region-a.geo-1/2769"))
.build(),
IpPermission.builder()
.ipProtocol(IpProtocol.TCP)
.fromPort(8080)
.toPort(8080)
.cidrBlock("0.0.0.0/0")
.build(),
IpPermission.builder()
.ipProtocol(IpProtocol.TCP)
.fromPort(8080)
.toPort(8080)
.groupIds(ImmutableList.of("az-1.region-a.geo-1/2769"))
.build()
)
)
.build();
assertEquals(
fn.apply(new RegionSecurityGroupNameAndPorts("az-1.region-a.geo-1", "jclouds_mygroup", ImmutableSet.of(22, 8080))).toString(),
new SecurityGroupInRegion(expected, "az-1.region-a.geo-1", ImmutableList.of(expected)).toString());
fn.apply(new RegionSecurityGroupNameAndPorts("az-1.region-a.geo-1", "jclouds_mygroup", ImmutableSet.of(22, 8080))).toString(),
expected.toString().trim());
}
@ -163,12 +220,45 @@ public class CreateSecurityGroupIfNeededTest extends BaseNovaApiExpectTest {
NovaApi apiWhenSecurityGroupsExist = requestsSendResponses(builder.build());
CreateSecurityGroupIfNeeded fn = new CreateSecurityGroupIfNeeded(apiWhenSecurityGroupsExist);
CreateSecurityGroupIfNeeded fn = new CreateSecurityGroupIfNeeded(apiWhenSecurityGroupsExist, locationIndex, securityGroupInRegionSecurityGroupFunction, factory);
// we can find it
final SecurityGroup expected = new ParseComputeServiceTypicalSecurityGroupTest().expected();
org.jclouds.compute.domain.SecurityGroup expected = new SecurityGroupBuilder()
.id("az-1.region-a.geo-1/2769")
.providerId("2769")
.name("jclouds_mygroup")
.location(locationIndex.get().get("az-1.region-a.geo-1"))
.ipPermissions(ImmutableList.of(
IpPermission.builder()
.ipProtocol(IpProtocol.TCP)
.fromPort(22)
.toPort(22)
.cidrBlock("0.0.0.0/0")
.build(),
IpPermission.builder()
.ipProtocol(IpProtocol.TCP)
.fromPort(22)
.toPort(22)
.groupIds(ImmutableList.of("az-1.region-a.geo-1/2769"))
.build(),
IpPermission.builder()
.ipProtocol(IpProtocol.TCP)
.fromPort(8080)
.toPort(8080)
.cidrBlock("0.0.0.0/0")
.build(),
IpPermission.builder()
.ipProtocol(IpProtocol.TCP)
.fromPort(8080)
.toPort(8080)
.groupIds(ImmutableList.of("az-1.region-a.geo-1/2769"))
.build()
)
)
.build();
assertEquals(
fn.apply(new RegionSecurityGroupNameAndPorts("az-1.region-a.geo-1", "jclouds_mygroup", ImmutableSet.of(22, 8080))).toString(),
new SecurityGroupInRegion(expected, "az-1.region-a.geo-1", ImmutableList.of(expected)).toString());
fn.apply(new RegionSecurityGroupNameAndPorts("az-1.region-a.geo-1", "jclouds_mygroup", ImmutableSet.of(22, 8080))).toString(),
expected.toString().trim()
);
}
}

View File

@ -49,23 +49,21 @@ public class ParseComputeServiceTypicalSecurityGroupTest extends BaseItemParserT
public SecurityGroup expected() {
Set<SecurityGroupRule> securityGroupRules = ImmutableSet.of(
SecurityGroupRule.builder().fromPort(22)
.ipProtocol(IpProtocol.TCP).toPort(22).parentGroupId("2769")
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(TenantIdAndName.builder().tenantId("37936628937291").name("jclouds_mygroup").build())
.ipProtocol(IpProtocol.TCP).toPort(22).parentGroupId("2769")
.id("10332").build(),
SecurityGroupRule.builder().fromPort(8080)
.ipProtocol(IpProtocol.TCP).toPort(8080).parentGroupId("2769")
SecurityGroupRule.builder().fromPort(22)
.group(TenantIdAndName.builder().tenantId("37936628937291").name("jclouds_mygroup").build())
.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(TenantIdAndName.builder().tenantId("37936628937291").name("jclouds_mygroup").build())
.ipProtocol(IpProtocol.TCP).toPort(8080).parentGroupId("2769")
.id("10334").build()
);
SecurityGroupRule.builder().fromPort(8080)
.group(TenantIdAndName.builder().tenantId("37936628937291").name("jclouds_mygroup").build())
.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();
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

@ -416,6 +416,33 @@
"project_id": "None"
}
},
{
"status": "ACTIVE",
"updated": "2012-03-12T07:49:23Z",
"name": "Ubuntu Lucid 16.04 LTS Server 64-bit (Kernel)",
"links": [
{
"href": "https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/37936628937291/images/1235",
"rel": "self"
},
{
"href": "https://az-1.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/images/1235",
"rel": "bookmark"
}
],
"created": "2011-12-21T11:39:58Z",
"progress": 100,
"id": "2235",
"metadata": {
"image_location": "local",
"image_state": "available",
"min_ram": 0,
"min_disk": 0,
"architecture": "amd64",
"owner": null,
"project_id": "None"
}
},
{
"status": "ACTIVE",
"updated": "2012-03-12T07:49:05Z",

View File

@ -71,6 +71,33 @@
"owner": "1"
}
},
{
"status": "ACTIVE",
"updated": "2012-03-12T07:49:23Z",
"name": "Ubuntu Lucid 16.04 LTS Server 64-bit (Kernel)",
"links": [
{
"href": "https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/37936628937291/images/1235",
"rel": "self"
},
{
"href": "https://az-1.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/images/1235",
"rel": "bookmark"
}
],
"created": "2011-12-21T11:39:58Z",
"progress": 100,
"id": "2235",
"metadata": {
"image_location": "local",
"image_state": "available",
"min_ram": 0,
"min_disk": 0,
"architecture": "amd64",
"owner": null,
"project_id": "None"
}
},
{
"status": "ACTIVE",
"updated": "2012-02-02T19:10:33Z",

View File

@ -13,7 +13,7 @@
</encoder>
</appender>
<appender name="COMPUTEFILE" class="ch.qos.logback.core.FileAppender">
<file>target/jclouds-compute.log</file>
<file>target/test-data/jclouds-compute.log</file>
<encoder>
<Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
</encoder>

View File

@ -406,17 +406,18 @@ public abstract class BaseSecurityGroupExtensionLiveTest extends BaseComputeServ
@Test(groups = {"integration", "live"}, singleThreaded = true)
public void testSecurityGroupCacheInvalidatedWhenDeletedExternally() throws Exception {
String testSecurityGroupName = secGroupNameToDelete + "-externally";
ComputeService computeService = view.getComputeService();
Optional<SecurityGroupExtension> securityGroupExtension = computeService.getSecurityGroupExtension();
assertTrue(securityGroupExtension.isPresent(), "security extension was not present");
final SecurityGroupExtension security = securityGroupExtension.get();
final SecurityGroup seedGroup = security.createSecurityGroup(secGroupNameToDelete, getNodeTemplate().getLocation());
final SecurityGroup seedGroup = security.createSecurityGroup(testSecurityGroupName, getNodeTemplate().getLocation());
deleteSecurityGroupFromAnotherView(seedGroup);
boolean deleted = security.removeSecurityGroup(seedGroup.getId());
assertFalse(deleted, "SG deleted externally so should've failed deletion");
final SecurityGroup recreatedGroup = security.createSecurityGroup(secGroupNameToDelete, getNodeTemplate().getLocation());
final SecurityGroup recreatedGroup = security.createSecurityGroup(testSecurityGroupName, getNodeTemplate().getLocation());
// Makes sure the security group exists and is re-created and is not just returned from cache
security.addIpPermission(IpPermission.builder()