You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by an...@apache.org on 2018/02/02 15:31:33 UTC
[2/2] jclouds git commit: [JCLOUDS-1377] add support for injectable
Neutron Context into Nova
[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
Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/09936b57
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/09936b57
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/09936b57
Branch: refs/heads/master
Commit: 09936b57fc90b5a3c7fe530358a2c6a757c32839
Parents: 2a56db0
Author: Andrea Turli <an...@gmail.com>
Authored: Wed Jan 17 11:46:55 2018 +0000
Committer: Andrea Turli <an...@gmail.com>
Committed: Fri Feb 2 16:26:22 2018 +0100
----------------------------------------------------------------------
apis/openstack-nova/pom.xml | 5 +
.../openstack/nova/v2_0/NovaApiMetadata.java | 2 +
.../v2_0/compute/NovaComputeServiceAdapter.java | 2 +-
.../config/NovaComputeServiceContextModule.java | 60 ++--
.../NeutronSecurityGroupExtension.java | 325 +++++++++++++++++++
.../extensions/NovaSecurityGroupExtension.java | 40 +--
.../compute/functions/CleanupResources.java | 34 +-
.../functions/CreateSecurityGroupIfNeeded.java | 138 ++++++--
.../NeutronSecurityGroupToSecurityGroup.java | 85 +++++
.../NovaSecurityGroupToSecurityGroup.java | 97 ++++++
.../loaders/FindSecurityGroupOrCreate.java | 35 +-
.../compute/options/NovaTemplateOptions.java | 1 +
...desWithGroupEncodedIntoNameThenAddToSet.java | 61 ++--
.../NeutronSecurityGroupInRegion.java | 80 +++++
.../openstack/nova/v2_0/features/ServerApi.java | 22 +-
.../NovaComputeServiceAdapterExpectTest.java | 14 +-
.../compute/NovaComputeServiceExpectTest.java | 6 +-
.../compute/NovaComputeServiceLiveTest.java | 21 +-
.../NeutronSecurityGroupExtensionLiveTest.java | 117 +++++++
.../NovaSecurityGroupExtensionExpectTest.java | 3 +-
.../NovaSecurityGroupExtensionLiveTest.java | 1 -
.../FindSecurityGroupInRegionOrCreateTest.java | 131 ++++++++
.../loaders/FindSecurityGroupOrCreateTest.java | 141 --------
.../nova/v2_0/features/ServerApiExpectTest.java | 33 ++
.../nova/v2_0/features/ServerApiLiveTest.java | 21 +-
.../CreateSecurityGroupIfNeededTest.java | 112 ++++++-
...eComputeServiceTypicalSecurityGroupTest.java | 24 +-
.../src/test/resources/image_list_detail.json | 27 ++
.../resources/image_list_detail_openstack.json | 27 ++
.../src/test/resources/logback-test.xml | 2 +-
.../BaseSecurityGroupExtensionLiveTest.java | 5 +-
31 files changed, 1322 insertions(+), 350 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jclouds/blob/09936b57/apis/openstack-nova/pom.xml
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/pom.xml b/apis/openstack-nova/pom.xml
index 85a9e28..8e90a0b 100644
--- a/apis/openstack-nova/pom.xml
+++ b/apis/openstack-nova/pom.xml
@@ -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>
http://git-wip-us.apache.org/repos/asf/jclouds/blob/09936b57/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaApiMetadata.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaApiMetadata.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaApiMetadata.java
index a330afa..2ee56a7 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaApiMetadata.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaApiMetadata.java
@@ -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;
}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/09936b57/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapter.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapter.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapter.java
index 02cfa2b..b2e18c8 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapter.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapter.java
@@ -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());
http://git-wip-us.apache.org/repos/asf/jclouds/blob/09936b57/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/config/NovaComputeServiceContextModule.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/config/NovaComputeServiceContextModule.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/config/NovaComputeServiceContextModule.java
index 700a39b..4402d47 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/config/NovaComputeServiceContextModule.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/config/NovaComputeServiceContextModule.java
@@ -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);
}
@@ -205,15 +234,6 @@ public class NovaComputeServiceContextModule extends
@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(
@Memoized Supplier<Set<? extends Location>> locations) {
return Suppliers.compose(new Function<Set<? extends Location>, Map<String, Location>>() {
http://git-wip-us.apache.org/repos/asf/jclouds/blob/09936b57/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NeutronSecurityGroupExtension.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NeutronSecurityGroupExtension.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NeutronSecurityGroupExtension.java
new file mode 100644
index 0000000..dae8af7
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NeutronSecurityGroupExtension.java
@@ -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);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/09936b57/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtension.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtension.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtension.java
index 4f992b9..153a406 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtension.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtension.java
@@ -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;
http://git-wip-us.apache.org/repos/asf/jclouds/blob/09936b57/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CleanupResources.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CleanupResources.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CleanupResources.java
index 9030395..5da0b87 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CleanupResources.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CleanupResources.java
@@ -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;
- @Inject
- public CleanupResources(NovaApi novaApi, RemoveFloatingIpFromNodeAndDeallocate removeFloatingIpFromNodeAndDeallocate,
- LoadingCache<RegionAndName, SecurityGroupInRegion> securityGroupMap) {
+ private final SecurityGroupExtension securityGroupExtension;
- this.novaApi = novaApi;
+ @Inject
+ 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
http://git-wip-us.apache.org/repos/asf/jclouds/blob/09936b57/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CreateSecurityGroupIfNeeded.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CreateSecurityGroupIfNeeded.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CreateSecurityGroupIfNeeded.java
index deea2e9..3faa490 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CreateSecurityGroupIfNeeded.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CreateSecurityGroupIfNeeded.java
@@ -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();
+ Location location = locationIndex.get().get(regionId);
+
logger.debug(">> creating securityGroup %s", regionSecurityGroupNameAndPorts);
- try {
- SecurityGroup securityGroup = api.get().createWithDescription(
- regionSecurityGroupNameAndPorts.getName(), regionSecurityGroupNameAndPorts.getName());
- logger.debug("<< created securityGroup(%s)", securityGroup);
- for (int port : regionSecurityGroupNameAndPorts.getPorts()) {
- authorizeGroupToItselfAndAllIPsToTCPPort(api.get(), securityGroup, port);
+ 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));
+ }
+ }
+ }
+
+ 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 new SecurityGroupInRegion(api.get().get(securityGroup.getId()), regionId, allGroups);
+ return securityGroup;
} 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);
+ 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 void authorizeGroupToItselfAndAllIPsToTCPPort(SecurityGroupApi securityGroupApi,
- SecurityGroup securityGroup, int port) {
+ 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");
+ 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);
-
}
+
}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/09936b57/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NeutronSecurityGroupToSecurityGroup.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NeutronSecurityGroupToSecurityGroup.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NeutronSecurityGroupToSecurityGroup.java
new file mode 100644
index 0000000..0a6ffbc
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NeutronSecurityGroupToSecurityGroup.java
@@ -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();
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/09936b57/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupToSecurityGroup.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupToSecurityGroup.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupToSecurityGroup.java
new file mode 100644
index 0000000..8739f60
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupToSecurityGroup.java
@@ -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();
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/09936b57/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/FindSecurityGroupOrCreate.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/FindSecurityGroupOrCreate.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/FindSecurityGroupOrCreate.java
index 1a980e5..274e4ef 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/FindSecurityGroupOrCreate.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/FindSecurityGroupOrCreate.java
@@ -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",
http://git-wip-us.apache.org/repos/asf/jclouds/blob/09936b57/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/options/NovaTemplateOptions.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/options/NovaTemplateOptions.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/options/NovaTemplateOptions.java
index 992302e..f9f4fb5 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/options/NovaTemplateOptions.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/options/NovaTemplateOptions.java
@@ -80,6 +80,7 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
eTo.configDrive(getConfigDrive());
eTo.novaNetworks(getNovaNetworks());
eTo.availabilityZone(getAvailabilityZone());
+ eTo.blockDeviceMappings(getBlockDeviceMappings());
}
}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/09936b57/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/strategy/ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/strategy/ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/strategy/ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.java
index 5f747e6..532643a 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/strategy/ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/strategy/ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.java
@@ -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,
http://git-wip-us.apache.org/repos/asf/jclouds/blob/09936b57/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/NeutronSecurityGroupInRegion.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/NeutronSecurityGroupInRegion.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/NeutronSecurityGroupInRegion.java
new file mode 100644
index 0000000..11e3f90
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/NeutronSecurityGroupInRegion.java
@@ -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();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/09936b57/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ServerApi.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ServerApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ServerApi.java
index 33bf09a..512f4a0 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ServerApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ServerApi.java
@@ -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);
+
}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/09936b57/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapterExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapterExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapterExpectTest.java
index 5528349..1317fc5 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapterExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapterExpectTest.java
@@ -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")