You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by jd...@apache.org on 2014/08/13 18:59:49 UTC

[10/12] Prefer Regions to Zones in OpenStack APIs

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ImageInRegionToImage.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ImageInRegionToImage.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ImageInRegionToImage.java
new file mode 100644
index 0000000..35a6787
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ImageInRegionToImage.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.compute.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.Map;
+
+import javax.inject.Inject;
+
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.ImageBuilder;
+import org.jclouds.compute.domain.OperatingSystem;
+import org.jclouds.domain.Location;
+import org.jclouds.openstack.nova.v2_0.domain.Image.Status;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.ImageInRegion;
+
+import com.google.common.base.Function;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Supplier;
+
+/**
+ * A function for transforming a nova-specific Image into a generic Image object.
+ */
+public class ImageInRegionToImage implements Function<ImageInRegion, Image> {
+   private final Map<Status, org.jclouds.compute.domain.Image.Status> toPortableImageStatus;
+   private final Function<org.jclouds.openstack.nova.v2_0.domain.Image, OperatingSystem> imageToOs;
+   private final Supplier<Map<String, Location>> locationIndex;
+
+   @Inject
+   public ImageInRegionToImage(Map<org.jclouds.openstack.nova.v2_0.domain.Image.Status, Image.Status> toPortableImageStatus,
+            Function<org.jclouds.openstack.nova.v2_0.domain.Image, OperatingSystem> imageToOs,
+            Supplier<Map<String, Location>> locationIndex) {
+      this.toPortableImageStatus = checkNotNull(toPortableImageStatus, "toPortableImageStatus");
+      this.imageToOs = checkNotNull(imageToOs, "imageToOs");
+      this.locationIndex = checkNotNull(locationIndex, "locationIndex");
+   }
+
+   @Override
+   public Image apply(ImageInRegion imageInRegion) {
+      Location location = locationIndex.get().get(imageInRegion.getRegion());
+      checkState(location != null, "location %s not in locationIndex: %s", imageInRegion.getRegion(), locationIndex.get());
+      org.jclouds.openstack.nova.v2_0.domain.Image image = imageInRegion.getImage();
+      return new ImageBuilder().id(imageInRegion.slashEncode()).providerId(image.getId()).name(image.getName())
+               .userMetadata(image.getMetadata()).operatingSystem(imageToOs.apply(image)).description(image.getName())
+               .location(location).status(toPortableImageStatus.get(image.getStatus())).build();
+   }
+
+   @Override
+   public String toString() {
+      return MoreObjects.toStringHelper(this).toString();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ImageInZoneToImage.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ImageInZoneToImage.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ImageInZoneToImage.java
deleted file mode 100644
index c2f6f6c..0000000
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ImageInZoneToImage.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.openstack.nova.v2_0.compute.functions;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-
-import java.util.Map;
-
-import javax.inject.Inject;
-
-import org.jclouds.compute.domain.Image;
-import org.jclouds.compute.domain.ImageBuilder;
-import org.jclouds.compute.domain.OperatingSystem;
-import org.jclouds.domain.Location;
-import org.jclouds.openstack.nova.v2_0.domain.Image.Status;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ImageInZone;
-
-import com.google.common.base.Function;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.Supplier;
-
-/**
- * A function for transforming a nova-specific Image into a generic Image object.
- */
-public class ImageInZoneToImage implements Function<ImageInZone, Image> {
-   private final Map<Status, org.jclouds.compute.domain.Image.Status> toPortableImageStatus;
-   private final Function<org.jclouds.openstack.nova.v2_0.domain.Image, OperatingSystem> imageToOs;
-   private final Supplier<Map<String, Location>> locationIndex;
-
-   @Inject
-   public ImageInZoneToImage(Map<org.jclouds.openstack.nova.v2_0.domain.Image.Status, Image.Status> toPortableImageStatus, 
-            Function<org.jclouds.openstack.nova.v2_0.domain.Image, OperatingSystem> imageToOs,
-            Supplier<Map<String, Location>> locationIndex) {
-      this.toPortableImageStatus = checkNotNull(toPortableImageStatus, "toPortableImageStatus");
-      this.imageToOs = checkNotNull(imageToOs, "imageToOs");
-      this.locationIndex = checkNotNull(locationIndex, "locationIndex");
-   }
-
-   @Override
-   public Image apply(ImageInZone imageInZone) {
-      Location location = locationIndex.get().get(imageInZone.getZone());
-      checkState(location != null, "location %s not in locationIndex: %s", imageInZone.getZone(), locationIndex.get());
-      org.jclouds.openstack.nova.v2_0.domain.Image image = imageInZone.getImage();
-      return new ImageBuilder().id(imageInZone.slashEncode()).providerId(image.getId()).name(image.getName())
-               .userMetadata(image.getMetadata()).operatingSystem(imageToOs.apply(image)).description(image.getName())
-               .location(location).status(toPortableImageStatus.get(image.getStatus())).build();
-   }
-   
-   @Override
-   public String toString() {
-      return MoreObjects.toStringHelper(this).toString();
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInRegionToSecurityGroup.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInRegionToSecurityGroup.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInRegionToSecurityGroup.java
new file mode 100644
index 0000000..08b4e2d
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInRegionToSecurityGroup.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.compute.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.Map;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.compute.domain.SecurityGroup;
+import org.jclouds.compute.domain.SecurityGroupBuilder;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.domain.Location;
+import org.jclouds.logging.Logger;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.SecurityGroupInRegion;
+
+import com.google.common.base.Function;
+import com.google.common.base.Supplier;
+import com.google.inject.Inject;
+
+
+/**
+ * A function for transforming a Nova-specific SecurityGroup into a generic
+ * SecurityGroup object.
+ */
+@Singleton
+public class NovaSecurityGroupInRegionToSecurityGroup implements Function<SecurityGroupInRegion, SecurityGroup> {
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
+
+   protected final Function<org.jclouds.openstack.nova.v2_0.domain.SecurityGroup, SecurityGroup> baseConverter;
+   protected final Supplier<Map<String, Location>> locationIndex;
+
+   @Inject
+   public NovaSecurityGroupInRegionToSecurityGroup(Function<org.jclouds.openstack.nova.v2_0.domain.SecurityGroup, SecurityGroup> baseConverter,
+                                                 Supplier<Map<String, Location>> locationIndex) {
+      this.baseConverter = checkNotNull(baseConverter, "baseConverter");
+      this.locationIndex = checkNotNull(locationIndex, "locationIndex");
+   }
+
+   @Override
+   public SecurityGroup apply(SecurityGroupInRegion group) {
+      SecurityGroupBuilder builder = SecurityGroupBuilder.fromSecurityGroup(baseConverter.apply(group.getSecurityGroup()));
+
+      Location region = locationIndex.get().get(group.getRegion());
+      checkState(region != null, "location %s not in locationIndex: %s", group.getRegion(), locationIndex.get());
+
+      builder.location(region);
+
+      builder.id(group.getRegion() + "/" + group.getSecurityGroup().getId());
+
+      return builder.build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInZoneToSecurityGroup.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInZoneToSecurityGroup.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInZoneToSecurityGroup.java
deleted file mode 100644
index 1991e77..0000000
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInZoneToSecurityGroup.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.openstack.nova.v2_0.compute.functions;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-
-import java.util.Map;
-
-import javax.annotation.Resource;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.jclouds.compute.domain.SecurityGroup;
-import org.jclouds.compute.domain.SecurityGroupBuilder;
-import org.jclouds.compute.reference.ComputeServiceConstants;
-import org.jclouds.domain.Location;
-import org.jclouds.logging.Logger;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.SecurityGroupInZone;
-
-import com.google.common.base.Function;
-import com.google.common.base.Supplier;
-import com.google.inject.Inject;
-
-
-/**
- * A function for transforming a Nova-specific SecurityGroup into a generic
- * SecurityGroup object.
- */
-@Singleton
-public class NovaSecurityGroupInZoneToSecurityGroup implements Function<SecurityGroupInZone, SecurityGroup> {
-   @Resource
-   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
-   protected Logger logger = Logger.NULL;
-
-   protected final Function<org.jclouds.openstack.nova.v2_0.domain.SecurityGroup, SecurityGroup> baseConverter;
-   protected final Supplier<Map<String, Location>> locationIndex;
-
-   @Inject
-   public NovaSecurityGroupInZoneToSecurityGroup(Function<org.jclouds.openstack.nova.v2_0.domain.SecurityGroup, SecurityGroup> baseConverter,
-                                                 Supplier<Map<String, Location>> locationIndex) {
-      this.baseConverter = checkNotNull(baseConverter, "baseConverter");
-      this.locationIndex = checkNotNull(locationIndex, "locationIndex");
-   }
-
-   @Override
-   public SecurityGroup apply(SecurityGroupInZone group) {
-      SecurityGroupBuilder builder = SecurityGroupBuilder.fromSecurityGroup(baseConverter.apply(group.getSecurityGroup()));
-
-      Location zone = locationIndex.get().get(group.getZone());
-      checkState(zone != null, "location %s not in locationIndex: %s", group.getZone(), locationIndex.get());
-
-      builder.location(zone);
-
-      builder.id(group.getZone() + "/" + group.getSecurityGroup().getId());
-
-      return builder.build();
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/OrphanedGroupsByRegionId.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/OrphanedGroupsByRegionId.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/OrphanedGroupsByRegionId.java
new file mode 100644
index 0000000..1a42952
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/OrphanedGroupsByRegionId.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.compute.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.transform;
+import static com.google.common.collect.Sets.filter;
+
+import java.util.Set;
+
+import javax.inject.Inject;
+
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.predicates.NodePredicates;
+import org.jclouds.domain.LocationScope;
+import org.jclouds.openstack.nova.v2_0.compute.predicates.AllNodesInGroupTerminated;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+
+public class OrphanedGroupsByRegionId implements Function<Set<? extends NodeMetadata>, Multimap<String, String>> {
+   private final Predicate<RegionAndName> allNodesInGroupTerminated;
+
+   @Inject
+   protected OrphanedGroupsByRegionId(ComputeService computeService) {
+      this(new AllNodesInGroupTerminated(checkNotNull(computeService, "computeService")));
+   }
+
+   @VisibleForTesting
+   OrphanedGroupsByRegionId(Predicate<RegionAndName> allNodesInGroupTerminated) {
+      this.allNodesInGroupTerminated = checkNotNull(allNodesInGroupTerminated, "allNodesInGroupTerminated");
+   }
+
+   public Multimap<String, String> apply(Set<? extends NodeMetadata> deadNodes) {
+      Iterable<? extends NodeMetadata> nodesWithGroup = filter(deadNodes, NodePredicates.hasGroup());
+      Set<RegionAndName> regionAndGroupNames = ImmutableSet.copyOf(filter(transform(nodesWithGroup,
+               new Function<NodeMetadata, RegionAndName>() {
+
+                  @Override
+                  public RegionAndName apply(NodeMetadata input) {
+                     String regionId = input.getLocation().getScope() == LocationScope.HOST ? input.getLocation()
+                              .getParent().getId() : input.getLocation().getId();
+                     return RegionAndName.fromRegionAndName(regionId, input.getGroup());
+                  }
+
+               }), allNodesInGroupTerminated));
+      Multimap<String, String> regionToRegionAndGroupNames = Multimaps.transformValues(Multimaps.index(regionAndGroupNames,
+               RegionAndName.REGION_FUNCTION), RegionAndName.NAME_FUNCTION);
+      return regionToRegionAndGroupNames;
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/OrphanedGroupsByZoneId.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/OrphanedGroupsByZoneId.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/OrphanedGroupsByZoneId.java
deleted file mode 100644
index f49330f..0000000
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/OrphanedGroupsByZoneId.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.openstack.nova.v2_0.compute.functions;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.filter;
-import static com.google.common.collect.Iterables.transform;
-import static com.google.common.collect.Sets.filter;
-
-import java.util.Set;
-
-import javax.inject.Inject;
-
-import org.jclouds.compute.ComputeService;
-import org.jclouds.compute.domain.NodeMetadata;
-import org.jclouds.compute.predicates.NodePredicates;
-import org.jclouds.domain.LocationScope;
-import org.jclouds.openstack.nova.v2_0.compute.predicates.AllNodesInGroupTerminated;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneAndName;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Multimaps;
-
-public class OrphanedGroupsByZoneId implements Function<Set<? extends NodeMetadata>, Multimap<String, String>> {
-   private final Predicate<ZoneAndName> allNodesInGroupTerminated;
-
-   @Inject
-   protected OrphanedGroupsByZoneId(ComputeService computeService) {
-      this(new AllNodesInGroupTerminated(checkNotNull(computeService, "computeService")));
-   }
-
-   @VisibleForTesting
-   OrphanedGroupsByZoneId(Predicate<ZoneAndName> allNodesInGroupTerminated) {
-      this.allNodesInGroupTerminated = checkNotNull(allNodesInGroupTerminated, "allNodesInGroupTerminated");
-   }
-
-   public Multimap<String, String> apply(Set<? extends NodeMetadata> deadNodes) {
-      Iterable<? extends NodeMetadata> nodesWithGroup = filter(deadNodes, NodePredicates.hasGroup());
-      Set<ZoneAndName> zoneAndGroupNames = ImmutableSet.copyOf(filter(transform(nodesWithGroup,
-               new Function<NodeMetadata, ZoneAndName>() {
-
-                  @Override
-                  public ZoneAndName apply(NodeMetadata input) {
-                     String zoneId = input.getLocation().getScope() == LocationScope.HOST ? input.getLocation()
-                              .getParent().getId() : input.getLocation().getId();
-                     return ZoneAndName.fromZoneAndName(zoneId, input.getGroup());
-                  }
-
-               }), allNodesInGroupTerminated));
-      Multimap<String, String> zoneToZoneAndGroupNames = Multimaps.transformValues(Multimaps.index(zoneAndGroupNames,
-               ZoneAndName.ZONE_FUNCTION), ZoneAndName.NAME_FUNCTION);
-      return zoneToZoneAndGroupNames;
-   }
-
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/RemoveFloatingIpFromNodeAndDeallocate.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/RemoveFloatingIpFromNodeAndDeallocate.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/RemoveFloatingIpFromNodeAndDeallocate.java
index cdbb0d9..94309c8 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/RemoveFloatingIpFromNodeAndDeallocate.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/RemoveFloatingIpFromNodeAndDeallocate.java
@@ -26,7 +26,7 @@ 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.FloatingIP;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneAndId;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndId;
 import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPApi;
 
 import com.google.common.base.Function;
@@ -36,25 +36,25 @@ import com.google.common.cache.LoadingCache;
 /**
  * A function for removing and deallocating an ip address from a node
  */
-public class RemoveFloatingIpFromNodeAndDeallocate implements Function<ZoneAndId, ZoneAndId> {
+public class RemoveFloatingIpFromNodeAndDeallocate implements Function<RegionAndId, RegionAndId> {
 
    @Resource
    @Named(ComputeServiceConstants.COMPUTE_LOGGER)
    protected Logger logger = Logger.NULL;
 
    private final NovaApi novaApi;
-   private final LoadingCache<ZoneAndId, Iterable<? extends FloatingIP>> floatingIpCache;
+   private final LoadingCache<RegionAndId, Iterable<? extends FloatingIP>> floatingIpCache;
 
    @Inject
    public RemoveFloatingIpFromNodeAndDeallocate(NovaApi novaApi,
-            @Named("FLOATINGIP") LoadingCache<ZoneAndId, Iterable<? extends FloatingIP>> floatingIpCache) {
+            @Named("FLOATINGIP") LoadingCache<RegionAndId, Iterable<? extends FloatingIP>> floatingIpCache) {
       this.novaApi = checkNotNull(novaApi, "novaApi");
       this.floatingIpCache = checkNotNull(floatingIpCache, "floatingIpCache");
    }
 
    @Override
-   public ZoneAndId apply(ZoneAndId id) {
-      FloatingIPApi floatingIpApi = novaApi.getFloatingIPExtensionForZone(id.getZone()).get();
+   public RegionAndId apply(RegionAndId id) {
+      FloatingIPApi floatingIpApi = novaApi.getFloatingIPApi(id.getRegion()).get();
       for (FloatingIP ip : floatingIpCache.getUnchecked(id)) {
          logger.debug(">> removing floatingIp(%s) from node(%s)", ip, id);
          floatingIpApi.removeFromServer(ip.getIp(), id.getId());

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/SecurityGroupRuleToIpPermission.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/SecurityGroupRuleToIpPermission.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/SecurityGroupRuleToIpPermission.java
index 46d4679..4f80b7b 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/SecurityGroupRuleToIpPermission.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/SecurityGroupRuleToIpPermission.java
@@ -32,8 +32,8 @@ 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.zonescoped.SecurityGroupInZone;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneAndName;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.SecurityGroupInRegion;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
@@ -50,16 +50,16 @@ public class SecurityGroupRuleToIpPermission implements Function<SecurityGroupRu
    @Resource
    @Named(ComputeServiceConstants.COMPUTE_LOGGER)
    protected Logger logger = Logger.NULL;
-   protected final Predicate<AtomicReference<ZoneAndName>> returnSecurityGroupExistsInZone;
+   protected final Predicate<AtomicReference<RegionAndName>> returnSecurityGroupExistsInRegion;
    protected final Supplier<Map<String, Location>> locationIndex;
-   LoadingCache<ZoneAndName, SecurityGroupInZone> groupMap;
+   LoadingCache<RegionAndName, SecurityGroupInRegion> groupMap;
 
    @Inject
-   public SecurityGroupRuleToIpPermission(@Named("SECURITYGROUP_PRESENT") Predicate<AtomicReference<ZoneAndName>> returnSecurityGroupExistsInZone,
+   public SecurityGroupRuleToIpPermission(@Named("SECURITYGROUP_PRESENT") Predicate<AtomicReference<RegionAndName>> returnSecurityGroupExistsInRegion,
                                           Supplier<Map<String, Location>> locationIndex,
-                                          LoadingCache<ZoneAndName, SecurityGroupInZone> groupMap) {
-      this.returnSecurityGroupExistsInZone = checkNotNull(returnSecurityGroupExistsInZone,
-              "returnSecurityGroupExistsInZone");
+                                          LoadingCache<RegionAndName, SecurityGroupInRegion> groupMap) {
+      this.returnSecurityGroupExistsInRegion = checkNotNull(returnSecurityGroupExistsInRegion,
+              "returnSecurityGroupExistsInRegion");
       this.locationIndex = checkNotNull(locationIndex, "locationIndex");
       this.groupMap = checkNotNull(groupMap, "groupMap");
    }
@@ -71,26 +71,26 @@ public class SecurityGroupRuleToIpPermission implements Function<SecurityGroupRu
       builder.fromPort(rule.getFromPort());
       builder.toPort(rule.getToPort());
       if (rule.getGroup() != null) {
-         String zone = getFirst(filter(locationIndex.get().keySet(), isSecurityGroupInZone(rule.getGroup().getName())),
+         String region = getFirst(filter(locationIndex.get().keySet(), isSecurityGroupInRegion(rule.getGroup().getName())),
                  null);
-         if (zone != null) {
-            SecurityGroupInZone group = groupMap.getUnchecked(ZoneAndName.fromZoneAndName(zone, rule.getGroup().getName()));
-            builder.groupId(zone + "/" + group.getSecurityGroup().getId());
+         if (region != null) {
+            SecurityGroupInRegion group = groupMap.getUnchecked(RegionAndName.fromRegionAndName(region, rule.getGroup().getName()));
+            builder.groupId(region + "/" + group.getSecurityGroup().getId());
          }
       }
       if (rule.getIpRange() != null)
          builder.cidrBlock(rule.getIpRange());
-      
+
       return builder.build();
    }
 
-   protected Predicate<String> isSecurityGroupInZone(final String groupName) {
+   protected Predicate<String> isSecurityGroupInRegion(final String groupName) {
       return new Predicate<String>() {
 
          @Override
-         public boolean apply(String zone) {
-            AtomicReference<ZoneAndName> securityGroupInZoneRef = Atomics.newReference(ZoneAndName.fromZoneAndName(zone, groupName));
-            return returnSecurityGroupExistsInZone.apply(securityGroupInZoneRef);
+         public boolean apply(String region) {
+            AtomicReference<RegionAndName> securityGroupInRegionRef = Atomics.newReference(RegionAndName.fromRegionAndName(region, groupName));
+            return returnSecurityGroupExistsInRegion.apply(securityGroupInRegionRef);
          }
       };
    }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInRegionToNodeMetadata.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInRegionToNodeMetadata.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInRegionToNodeMetadata.java
new file mode 100644
index 0000000..2134bb2
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInRegionToNodeMetadata.java
@@ -0,0 +1,207 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.compute.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Predicates.not;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.find;
+import static com.google.common.collect.Iterables.transform;
+import static com.google.common.collect.Sets.newHashSet;
+import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue;
+import static org.jclouds.compute.util.ComputeServiceUtils.groupFromMapOrName;
+import static org.jclouds.openstack.nova.v2_0.domain.Address.createV4;
+import static org.jclouds.openstack.nova.v2_0.domain.Address.createV6;
+
+import java.net.Inet4Address;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.jclouds.collect.Memoized;
+import org.jclouds.compute.domain.ComputeMetadata;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.NodeMetadataBuilder;
+import org.jclouds.compute.domain.OperatingSystem;
+import org.jclouds.compute.functions.GroupNamingConvention;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.domain.Location;
+import org.jclouds.domain.LocationBuilder;
+import org.jclouds.domain.LocationScope;
+import org.jclouds.logging.Logger;
+import org.jclouds.openstack.nova.v2_0.domain.Address;
+import org.jclouds.openstack.nova.v2_0.domain.Server;
+import org.jclouds.openstack.nova.v2_0.domain.Server.Status;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndId;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.ServerInRegion;
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.util.InetAddresses2;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.net.InetAddresses;
+
+/**
+ * A function for transforming a nova-specific Server into a generic
+ * NodeMetadata object.
+ */
+public class ServerInRegionToNodeMetadata implements Function<ServerInRegion, NodeMetadata> {
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
+
+   protected Map<Status, org.jclouds.compute.domain.NodeMetadata.Status> toPortableNodeStatus;
+   protected final Supplier<Map<String, Location>> locationIndex;
+   protected final Supplier<Set<? extends Image>> images;
+   protected final Supplier<Set<? extends Hardware>> hardwares;
+   protected final GroupNamingConvention nodeNamingConvention;
+
+   @Inject
+   public ServerInRegionToNodeMetadata(Map<Server.Status, NodeMetadata.Status> toPortableNodeStatus,
+            Supplier<Map<String, Location>> locationIndex, @Memoized Supplier<Set<? extends Image>> images,
+            @Memoized Supplier<Set<? extends Hardware>> hardwares, GroupNamingConvention.Factory namingConvention) {
+      this.toPortableNodeStatus = checkNotNull(toPortableNodeStatus, "toPortableNodeStatus");
+      this.nodeNamingConvention = checkNotNull(namingConvention, "namingConvention").createWithoutPrefix();
+      this.locationIndex = checkNotNull(locationIndex, "locationIndex");
+      this.images = checkNotNull(images, "images");
+      this.hardwares = checkNotNull(hardwares, "hardwares");
+   }
+
+   @Override
+   public NodeMetadata apply(ServerInRegion serverInRegion) {
+      Location region = locationIndex.get().get(serverInRegion.getRegion());
+      checkState(region != null, "location %s not in locationIndex: %s", serverInRegion.getRegion(), locationIndex.get());
+      Server from = serverInRegion.getServer();
+
+      NodeMetadataBuilder builder = new NodeMetadataBuilder();
+      builder.id(serverInRegion.slashEncode());
+      builder.providerId(from.getId());
+      builder.name(from.getName());
+      builder.hostname(from.getName());
+      builder.location(from.getHostId() != null ? new LocationBuilder().scope(LocationScope.HOST).id(from.getHostId())
+            .description(from.getHostId()).parent(region).build() : region);
+      builder.group(groupFromMapOrName(from.getMetadata(), from.getName(), nodeNamingConvention));
+      addMetadataAndParseTagsFromCommaDelimitedValue(builder, from.getMetadata());
+
+      if (from.getImage() != null) {
+         builder.imageId(RegionAndId.fromRegionAndId(serverInRegion.getRegion(), from.getImage().getId()).slashEncode());
+      }
+
+      builder.operatingSystem(findOperatingSystemForServerOrNull(serverInRegion));
+      builder.hardware(findHardwareForServerOrNull(serverInRegion));
+      builder.status(toPortableNodeStatus.get(from.getStatus()));
+
+      Set<Address> addresses = newHashSet(from.getAddresses().values());
+      if (from.getAccessIPv4() != null) {
+         addresses.add(createV4(from.getAccessIPv4()));
+      }
+      if (from.getAccessIPv6() != null) {
+         addresses.add(createV6(from.getAccessIPv6()));
+      }
+
+      builder.publicAddresses(
+            filter(
+                  transform(
+                        filter(addresses, not(isPrivateAddress)),
+                        AddressToStringTransformationFunction.INSTANCE),
+                  isInet4Address));
+
+      builder.privateAddresses(
+            filter(
+                  transform(
+                        filter(addresses, isPrivateAddress),
+                        AddressToStringTransformationFunction.INSTANCE),
+                  isInet4Address));
+
+      for (Link link : from.getLinks()) {
+         if (link.getRelation().equals(Link.Relation.SELF)) {
+            builder.uri(link.getHref());
+         }
+      }
+
+      return builder.build();
+   }
+
+   private static final Predicate<Address> isPrivateAddress = new Predicate<Address>() {
+      public boolean apply(Address in) {
+         return InetAddresses2.IsPrivateIPAddress.INSTANCE.apply(in.getAddr());
+      }
+   };
+
+   public static final Predicate<String> isInet4Address = new Predicate<String>() {
+      @Override
+      public boolean apply(String input) {
+         try {
+            // Note we can do this, as InetAddress is now on the white list
+            return InetAddresses.forString(input) instanceof Inet4Address;
+         } catch (IllegalArgumentException e) {
+            // could be a hostname
+            return true;
+         }
+      }
+
+   };
+
+   private enum AddressToStringTransformationFunction implements Function<Address, String> {
+      INSTANCE;
+      @Override
+      public String apply(Address address) {
+         return address.getAddr();
+      }
+   }
+
+   protected Hardware findHardwareForServerOrNull(ServerInRegion serverInRegion) {
+      return findObjectOfTypeForServerOrNull(hardwares.get(), "hardware", serverInRegion.getServer().getFlavor().getId(),
+            serverInRegion);
+   }
+
+   protected OperatingSystem findOperatingSystemForServerOrNull(ServerInRegion serverInRegion) {
+      if (serverInRegion.getServer().getImage() != null) {
+         Image image = findObjectOfTypeForServerOrNull(
+               images.get(), "image", serverInRegion.getServer().getImage().getId(), serverInRegion);
+
+         return (image != null) ? image.getOperatingSystem() : null;
+      } else {
+         return null;
+      }
+
+   }
+
+   public <T extends ComputeMetadata> T findObjectOfTypeForServerOrNull(Set<? extends T> supply, String type,
+         final String objectId, final RegionAndId serverInRegion) {
+      try {
+         return find(supply, new Predicate<T>() {
+            @Override
+            public boolean apply(T input) {
+               return input.getId().equals(RegionAndId.fromRegionAndId(serverInRegion.getRegion(), objectId).slashEncode());
+            }
+         });
+      } catch (NoSuchElementException e) {
+         logger.trace("could not find %s with id(%s) for server(%s)", type, objectId, serverInRegion);
+      }
+      return null;
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInZoneToNodeMetadata.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInZoneToNodeMetadata.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInZoneToNodeMetadata.java
deleted file mode 100644
index 57d66c2..0000000
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInZoneToNodeMetadata.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.openstack.nova.v2_0.compute.functions;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.base.Predicates.not;
-import static com.google.common.collect.Iterables.filter;
-import static com.google.common.collect.Iterables.find;
-import static com.google.common.collect.Iterables.transform;
-import static com.google.common.collect.Sets.newHashSet;
-import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue;
-import static org.jclouds.compute.util.ComputeServiceUtils.groupFromMapOrName;
-import static org.jclouds.openstack.nova.v2_0.domain.Address.createV4;
-import static org.jclouds.openstack.nova.v2_0.domain.Address.createV6;
-
-import java.net.Inet4Address;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
-
-import javax.annotation.Resource;
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.jclouds.collect.Memoized;
-import org.jclouds.compute.domain.ComputeMetadata;
-import org.jclouds.compute.domain.Hardware;
-import org.jclouds.compute.domain.Image;
-import org.jclouds.compute.domain.NodeMetadata;
-import org.jclouds.compute.domain.NodeMetadataBuilder;
-import org.jclouds.compute.domain.OperatingSystem;
-import org.jclouds.compute.functions.GroupNamingConvention;
-import org.jclouds.compute.reference.ComputeServiceConstants;
-import org.jclouds.domain.Location;
-import org.jclouds.domain.LocationBuilder;
-import org.jclouds.domain.LocationScope;
-import org.jclouds.logging.Logger;
-import org.jclouds.openstack.nova.v2_0.domain.Address;
-import org.jclouds.openstack.nova.v2_0.domain.Server;
-import org.jclouds.openstack.nova.v2_0.domain.Server.Status;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ServerInZone;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneAndId;
-import org.jclouds.openstack.v2_0.domain.Link;
-import org.jclouds.util.InetAddresses2;
-
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.base.Supplier;
-import com.google.common.net.InetAddresses;
-
-/**
- * A function for transforming a nova-specific Server into a generic
- * NodeMetadata object.
- */
-public class ServerInZoneToNodeMetadata implements Function<ServerInZone, NodeMetadata> {
-   @Resource
-   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
-   protected Logger logger = Logger.NULL;
-   
-   protected Map<Status, org.jclouds.compute.domain.NodeMetadata.Status> toPortableNodeStatus;
-   protected final Supplier<Map<String, Location>> locationIndex;
-   protected final Supplier<Set<? extends Image>> images;
-   protected final Supplier<Set<? extends Hardware>> hardwares;
-   protected final GroupNamingConvention nodeNamingConvention;
-
-   @Inject
-   public ServerInZoneToNodeMetadata(Map<Server.Status, NodeMetadata.Status> toPortableNodeStatus,
-            Supplier<Map<String, Location>> locationIndex, @Memoized Supplier<Set<? extends Image>> images,
-            @Memoized Supplier<Set<? extends Hardware>> hardwares, GroupNamingConvention.Factory namingConvention) {
-      this.toPortableNodeStatus = checkNotNull(toPortableNodeStatus, "toPortableNodeStatus");
-      this.nodeNamingConvention = checkNotNull(namingConvention, "namingConvention").createWithoutPrefix();
-      this.locationIndex = checkNotNull(locationIndex, "locationIndex");
-      this.images = checkNotNull(images, "images");
-      this.hardwares = checkNotNull(hardwares, "hardwares");
-   }
-
-   @Override
-   public NodeMetadata apply(ServerInZone serverInZone) {
-      Location zone = locationIndex.get().get(serverInZone.getZone());
-      checkState(zone != null, "location %s not in locationIndex: %s", serverInZone.getZone(), locationIndex.get());
-      Server from = serverInZone.getServer();
-
-      NodeMetadataBuilder builder = new NodeMetadataBuilder();
-      builder.id(serverInZone.slashEncode());
-      builder.providerId(from.getId());
-      builder.name(from.getName());
-      builder.hostname(from.getName());
-      builder.location(from.getHostId() != null ? new LocationBuilder().scope(LocationScope.HOST).id(from.getHostId())
-            .description(from.getHostId()).parent(zone).build() : zone);
-      builder.group(groupFromMapOrName(from.getMetadata(), from.getName(), nodeNamingConvention));
-      addMetadataAndParseTagsFromCommaDelimitedValue(builder, from.getMetadata());
-
-      if (from.getImage() != null) {
-         builder.imageId(ZoneAndId.fromZoneAndId(serverInZone.getZone(), from.getImage().getId()).slashEncode());
-      }
-
-      builder.operatingSystem(findOperatingSystemForServerOrNull(serverInZone));
-      builder.hardware(findHardwareForServerOrNull(serverInZone));
-      builder.status(toPortableNodeStatus.get(from.getStatus()));
-
-      Set<Address> addresses = newHashSet(from.getAddresses().values());
-      if (from.getAccessIPv4() != null) {
-         addresses.add(createV4(from.getAccessIPv4()));
-      }
-      if (from.getAccessIPv6() != null) {
-         addresses.add(createV6(from.getAccessIPv6()));
-      }
-
-      builder.publicAddresses(
-            filter(
-                  transform(
-                        filter(addresses, not(isPrivateAddress)),
-                        AddressToStringTransformationFunction.INSTANCE),
-                  isInet4Address));
-
-      builder.privateAddresses(
-            filter(
-                  transform(
-                        filter(addresses, isPrivateAddress),
-                        AddressToStringTransformationFunction.INSTANCE),
-                  isInet4Address));
-
-      for (Link link : from.getLinks()) {
-         if (link.getRelation().equals(Link.Relation.SELF)) {
-            builder.uri(link.getHref());
-         }
-      }
-      
-      return builder.build();
-   }
-   
-   private static final Predicate<Address> isPrivateAddress = new Predicate<Address>() {
-      public boolean apply(Address in) {
-         return InetAddresses2.IsPrivateIPAddress.INSTANCE.apply(in.getAddr());
-      }
-   };
-   
-   public static final Predicate<String> isInet4Address = new Predicate<String>() {
-      @Override
-      public boolean apply(String input) {
-         try {
-            // Note we can do this, as InetAddress is now on the white list
-            return InetAddresses.forString(input) instanceof Inet4Address;
-         } catch (IllegalArgumentException e) {
-            // could be a hostname
-            return true;
-         }
-      }
-
-   };
-
-   private enum AddressToStringTransformationFunction implements Function<Address, String> {
-      INSTANCE;
-      @Override
-      public String apply(Address address) {
-         return address.getAddr();
-      }
-   }
-
-   protected Hardware findHardwareForServerOrNull(ServerInZone serverInZone) {
-      return findObjectOfTypeForServerOrNull(hardwares.get(), "hardware", serverInZone.getServer().getFlavor().getId(),
-            serverInZone);
-   }
-
-   protected OperatingSystem findOperatingSystemForServerOrNull(ServerInZone serverInZone) {
-      if (serverInZone.getServer().getImage() != null) {
-         Image image = findObjectOfTypeForServerOrNull(
-               images.get(), "image", serverInZone.getServer().getImage().getId(), serverInZone);
-
-         return (image != null) ? image.getOperatingSystem() : null;
-      } else {
-         return null;
-      }
-
-   }
-
-   public <T extends ComputeMetadata> T findObjectOfTypeForServerOrNull(Set<? extends T> supply, String type,
-         final String objectId, final ZoneAndId serverInZone) {
-      try {
-         return find(supply, new Predicate<T>() {
-            @Override
-            public boolean apply(T input) {
-               return input.getId().equals(ZoneAndId.fromZoneAndId(serverInZone.getZone(), objectId).slashEncode());
-            }
-         });
-      } catch (NoSuchElementException e) {
-         logger.trace("could not find %s with id(%s) for server(%s)", type, objectId, serverInZone);
-      }
-      return null;
-   }
-
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/CreateUniqueKeyPair.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/CreateUniqueKeyPair.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/CreateUniqueKeyPair.java
index 71852dc..9d521c4 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/CreateUniqueKeyPair.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/CreateUniqueKeyPair.java
@@ -28,7 +28,7 @@ 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.KeyPair;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneAndName;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
 import org.jclouds.openstack.nova.v2_0.extensions.KeyPairApi;
 
 import com.google.common.base.Optional;
@@ -36,7 +36,7 @@ import com.google.common.cache.CacheLoader;
 import com.google.inject.Inject;
 
 @Singleton
-public class CreateUniqueKeyPair extends CacheLoader<ZoneAndName, KeyPair> {
+public class CreateUniqueKeyPair extends CacheLoader<RegionAndName, KeyPair> {
    @Resource
    @Named(ComputeServiceConstants.COMPUTE_LOGGER)
    protected Logger logger = Logger.NULL;
@@ -50,15 +50,15 @@ public class CreateUniqueKeyPair extends CacheLoader<ZoneAndName, KeyPair> {
    }
 
    @Override
-   public KeyPair load(ZoneAndName zoneAndName) {
-      String zoneId = checkNotNull(zoneAndName, "zoneAndName").getZone();
-      String prefix = zoneAndName.getName();
+   public KeyPair load(RegionAndName regionAndName) {
+      String regionId = checkNotNull(regionAndName, "regionAndName").getRegion();
+      String prefix = regionAndName.getName();
 
-      Optional<? extends KeyPairApi> api = novaApi.getKeyPairExtensionForZone(zoneId);
-      checkArgument(api.isPresent(), "Key pairs are required, but the extension is not available in zone %s!",
-            zoneId);
+      Optional<? extends KeyPairApi> api = novaApi.getKeyPairApi(regionId);
+      checkArgument(api.isPresent(), "Key pairs are required, but the extension is not available in region %s!",
+            regionId);
 
-      logger.debug(">> creating keyPair zone(%s) prefix(%s)", zoneId, prefix);
+      logger.debug(">> creating keyPair region(%s) prefix(%s)", regionId, prefix);
 
       KeyPair keyPair = null;
       while (keyPair == null) {

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/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 d072e37..23ee514 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
@@ -23,60 +23,60 @@ import java.util.concurrent.atomic.AtomicReference;
 import javax.inject.Inject;
 import javax.inject.Named;
 
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.SecurityGroupInZone;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneAndName;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneSecurityGroupNameAndPorts;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.SecurityGroupInRegion;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionSecurityGroupNameAndPorts;
 
 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<ZoneAndName, SecurityGroupInZone> {
+public class FindSecurityGroupOrCreate extends CacheLoader<RegionAndName, SecurityGroupInRegion> {
 
-   protected final Predicate<AtomicReference<ZoneAndName>> returnSecurityGroupExistsInZone;
-   protected final Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> groupCreator;
+   protected final Predicate<AtomicReference<RegionAndName>> returnSecurityGroupExistsInRegion;
+   protected final Function<RegionSecurityGroupNameAndPorts, SecurityGroupInRegion> groupCreator;
 
    @Inject
    public FindSecurityGroupOrCreate(
-            @Named("SECURITYGROUP_PRESENT") Predicate<AtomicReference<ZoneAndName>> returnSecurityGroupExistsInZone,
-            Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> groupCreator) {
-      this.returnSecurityGroupExistsInZone = checkNotNull(returnSecurityGroupExistsInZone,
-               "returnSecurityGroupExistsInZone");
+            @Named("SECURITYGROUP_PRESENT") Predicate<AtomicReference<RegionAndName>> returnSecurityGroupExistsInRegion,
+            Function<RegionSecurityGroupNameAndPorts, SecurityGroupInRegion> groupCreator) {
+      this.returnSecurityGroupExistsInRegion = checkNotNull(returnSecurityGroupExistsInRegion,
+               "returnSecurityGroupExistsInRegion");
       this.groupCreator = checkNotNull(groupCreator, "groupCreator");
    }
 
    @Override
-   public SecurityGroupInZone load(ZoneAndName in) {
-      AtomicReference<ZoneAndName> securityGroupInZoneRef = Atomics.newReference(checkNotNull(in,
-               "zoneSecurityGroupNameAndPorts"));
-      if (returnSecurityGroupExistsInZone.apply(securityGroupInZoneRef)) {
-         return returnExistingSecurityGroup(securityGroupInZoneRef);
+   public SecurityGroupInRegion load(RegionAndName in) {
+      AtomicReference<RegionAndName> securityGroupInRegionRef = Atomics.newReference(checkNotNull(in,
+               "regionSecurityGroupNameAndPorts"));
+      if (returnSecurityGroupExistsInRegion.apply(securityGroupInRegionRef)) {
+         return returnExistingSecurityGroup(securityGroupInRegionRef);
       } else {
          return createNewSecurityGroup(in);
       }
    }
 
-   private SecurityGroupInZone returnExistingSecurityGroup(AtomicReference<ZoneAndName> securityGroupInZoneRef) {
-      ZoneAndName securityGroupInZone = securityGroupInZoneRef.get();
-      checkState(securityGroupInZone instanceof SecurityGroupInZone,
+   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",
-               returnSecurityGroupExistsInZone);
-      return SecurityGroupInZone.class.cast(securityGroupInZone);
+               returnSecurityGroupExistsInRegion);
+      return SecurityGroupInRegion.class.cast(securityGroupInRegion);
    }
 
-   private SecurityGroupInZone createNewSecurityGroup(ZoneAndName in) {
+   private SecurityGroupInRegion createNewSecurityGroup(RegionAndName in) {
       checkState(
-               checkNotNull(in, "zoneSecurityGroupNameAndPorts") instanceof ZoneSecurityGroupNameAndPorts,
-               "programming error: when issuing get to this cacheloader, you need to pass an instance of ZoneSecurityGroupNameAndPorts, not %s",
+               checkNotNull(in, "regionSecurityGroupNameAndPorts") instanceof RegionSecurityGroupNameAndPorts,
+               "programming error: when issuing get to this cacheloader, you need to pass an instance of RegionSecurityGroupNameAndPorts, not %s",
                in);
-      ZoneSecurityGroupNameAndPorts zoneSecurityGroupNameAndPorts = ZoneSecurityGroupNameAndPorts.class.cast(in);
-      return groupCreator.apply(zoneSecurityGroupNameAndPorts);
+      RegionSecurityGroupNameAndPorts regionSecurityGroupNameAndPorts = RegionSecurityGroupNameAndPorts.class.cast(in);
+      return groupCreator.apply(regionSecurityGroupNameAndPorts);
    }
 
    @Override
    public String toString() {
-      return "returnExistingSecurityGroupInZoneOrCreateAsNeeded()";
+      return "returnExistingSecurityGroupInRegionOrCreateAsNeeded()";
    }
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/LoadFloatingIpsForInstance.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/LoadFloatingIpsForInstance.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/LoadFloatingIpsForInstance.java
index e4a9caa..1487a13 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/LoadFloatingIpsForInstance.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/LoadFloatingIpsForInstance.java
@@ -21,7 +21,7 @@ import javax.inject.Singleton;
 
 import org.jclouds.openstack.nova.v2_0.NovaApi;
 import org.jclouds.openstack.nova.v2_0.domain.FloatingIP;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneAndId;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndId;
 import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPApi;
 
 import com.google.common.base.Optional;
@@ -30,12 +30,12 @@ import com.google.common.cache.CacheLoader;
 import com.google.common.collect.ImmutableSet;
 
 /**
- * Each zone may or may not have the floating ip function present. In order to safely proceed, we
- * must allow the user to determine if a zone has floating ip services before attempting to use
+ * Each region may or may not have the floating ip function present. In order to safely proceed, we
+ * must allow the user to determine if a region has floating ip services before attempting to use
  * them.
  */
 @Singleton
-public class LoadFloatingIpsForInstance extends CacheLoader<ZoneAndId, Iterable<? extends FloatingIP>> {
+public class LoadFloatingIpsForInstance extends CacheLoader<RegionAndId, Iterable<? extends FloatingIP>> {
    private final NovaApi api;
 
    @Inject
@@ -44,9 +44,9 @@ public class LoadFloatingIpsForInstance extends CacheLoader<ZoneAndId, Iterable<
    }
 
    @Override
-   public Iterable<? extends FloatingIP> load(final ZoneAndId key) throws Exception {
-      String zone = key.getZone();
-      Optional<? extends FloatingIPApi> ipApiOptional = api.getFloatingIPExtensionForZone(zone);
+   public Iterable<? extends FloatingIP> load(final RegionAndId key) throws Exception {
+      String region = key.getRegion();
+      Optional<? extends FloatingIPApi> ipApiOptional = api.getFloatingIPApi(region);
       if (ipApiOptional.isPresent()) {
          return ipApiOptional.get().list().filter(
                   new Predicate<FloatingIP>() {

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/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 2778afc..519c0c0 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
@@ -196,10 +196,10 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
 
    /**
     * <h3>Note</h3>
-    * 
-    * This requires that {@link NovaApi#getExtensionForZone(String)} to return
+    *
+    * This requires that {@link NovaApi#getExtensionForRegion(String)} to return
     * {@link Optional#isPresent present}
-    * 
+    *
     * @return true if auto assignment of a floating ip to each vm is enabled
     */
    public boolean shouldAutoAssignFloatingIp() {
@@ -229,7 +229,7 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
    /**
     * <h3>Note</h3>
     *
-    * This requires that {@link NovaApi#getKeyPairExtensionForZone(String)} to return
+    * This requires that {@link NovaApi#getKeyPairExtensionApi(String)} to return
     * {@link Optional#isPresent present}
     *
     * @return true if auto generation of keypairs is enabled
@@ -241,7 +241,7 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
    /**
     * if unset, generate a default group prefixed with {@link jclouds#} according
     * to {@link #getInboundPorts()}
-    * 
+    *
     * @see org.jclouds.openstack.nova.v2_0.options.CreateServerOptions#getSecurityGroupNames
     * @deprecated Use {@link TemplateOptions#getGroups()} instead.
     */
@@ -301,14 +301,14 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
       }
 
       /**
-       * @see NovaTemplateOptions#shouldGenerateKeyPair() 
+       * @see NovaTemplateOptions#shouldGenerateKeyPair()
        */
       public static NovaTemplateOptions generateKeyPair(boolean enable) {
          return new NovaTemplateOptions().generateKeyPair(enable);
       }
 
       /**
-       * @see NovaTemplateOptions#getKeyPairName() 
+       * @see NovaTemplateOptions#getKeyPairName()
        */
       public static NovaTemplateOptions keyPairName(String keyPairName) {
          return new NovaTemplateOptions().keyPairName(keyPairName);
@@ -645,8 +645,8 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
    }
 
    /**
-    * OpenStack can be configured to write metadata to a special configuration drive that will be 
-    * attached to the instance when it boots. The instance can retrieve any information that would 
+    * OpenStack can be configured to write metadata to a special configuration drive that will be
+    * attached to the instance when it boots. The instance can retrieve any information that would
     * normally be available through the metadata service by mounting this disk and reading files from it.
     * To enable the config drive, set this parameter to "true".
     * This has to be enabled for user data cases.

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/predicates/AllNodesInGroupTerminated.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/predicates/AllNodesInGroupTerminated.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/predicates/AllNodesInGroupTerminated.java
index a4b63e9..6fb1d58 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/predicates/AllNodesInGroupTerminated.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/predicates/AllNodesInGroupTerminated.java
@@ -28,15 +28,15 @@ import javax.inject.Inject;
 
 import org.jclouds.compute.ComputeService;
 import org.jclouds.compute.domain.ComputeMetadata;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneAndName;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
 
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
 
-public class AllNodesInGroupTerminated implements Predicate<ZoneAndName> {
+public class AllNodesInGroupTerminated implements Predicate<RegionAndName> {
    private final ComputeService computeService;
 
-   
+
    //TODO: TESTME
    @Inject
    public AllNodesInGroupTerminated(ComputeService computeService) {
@@ -44,10 +44,10 @@ public class AllNodesInGroupTerminated implements Predicate<ZoneAndName> {
    }
 
    @Override
-   public boolean apply(ZoneAndName input) {
-      // new nodes can have the zone as their location, existing nodes, the parent is the
+   public boolean apply(RegionAndName input) {
+      // new nodes can have the region as their location, existing nodes, the parent is the
       // location
-      return all(computeService.listNodesDetailsMatching(Predicates.<ComputeMetadata> or(locationId(input.getZone()),
-               parentLocationId(input.getZone()))), and(inGroup(input.getName()), TERMINATED));
+      return all(computeService.listNodesDetailsMatching(Predicates.<ComputeMetadata> or(locationId(input.getRegion()),
+               parentLocationId(input.getRegion()))), and(inGroup(input.getName()), TERMINATED));
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/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 79bd021..9361999 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
@@ -45,9 +45,9 @@ import org.jclouds.openstack.nova.v2_0.compute.functions.AllocateAndAddFloatingI
 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.zonescoped.SecurityGroupInZone;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneAndName;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneSecurityGroupNameAndPorts;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.SecurityGroupInRegion;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionSecurityGroupNameAndPorts;
 
 import com.google.common.base.Function;
 import com.google.common.base.Throwables;
@@ -64,8 +64,8 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
          CreateNodesWithGroupEncodedIntoNameThenAddToSet {
 
    private final AllocateAndAddFloatingIpToNode createAndAddFloatingIpToNode;
-   private final LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupCache;
-   private final LoadingCache<ZoneAndName, KeyPair> keyPairCache;
+   private final LoadingCache<RegionAndName, SecurityGroupInRegion> securityGroupCache;
+   private final LoadingCache<RegionAndName, KeyPair> keyPairCache;
    private final NovaApi novaApi;
 
    @Inject
@@ -76,8 +76,8 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
             CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
             @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
             AllocateAndAddFloatingIpToNode createAndAddFloatingIpToNode,
-            LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupCache,
-            LoadingCache<ZoneAndName, KeyPair> keyPairCache, NovaApi novaApi) {
+            LoadingCache<RegionAndName, SecurityGroupInRegion> securityGroupCache,
+            LoadingCache<RegionAndName, KeyPair> keyPairCache, NovaApi novaApi) {
       super(addNodeWithTagStrategy, listNodesStrategy, namingConvention, userExecutor,
                customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
       this.securityGroupCache = checkNotNull(securityGroupCache, "securityGroupCache");
@@ -97,21 +97,21 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
 
       assert template.getOptions().equals(templateOptions) : "options didn't clone properly";
 
-      String zone = mutableTemplate.getLocation().getId();
+      String region = mutableTemplate.getLocation().getId();
 
       if (templateOptions.shouldAutoAssignFloatingIp()) {
-         checkArgument(novaApi.getFloatingIPExtensionForZone(zone).isPresent(),
+         checkArgument(novaApi.getFloatingIPApi(region).isPresent(),
                   "Floating IPs are required by options, but the extension is not available! options: %s",
                   templateOptions);
       }
 
-      boolean keyPairExtensionPresent = novaApi.getKeyPairExtensionForZone(zone).isPresent();
+      boolean keyPairExtensionPresent = novaApi.getKeyPairApi(region).isPresent();
       if (templateOptions.shouldGenerateKeyPair()) {
          checkArgument(keyPairExtensionPresent,
                   "Key Pairs are required by options, but the extension is not available! options: %s", templateOptions);
-         KeyPair keyPair = keyPairCache.getUnchecked(ZoneAndName.fromZoneAndName(zone, namingConvention.create()
+         KeyPair keyPair = keyPairCache.getUnchecked(RegionAndName.fromRegionAndName(region, namingConvention.create()
                   .sharedNameForGroup(group)));
-         keyPairCache.asMap().put(ZoneAndName.fromZoneAndName(zone, keyPair.getName()), keyPair);
+         keyPairCache.asMap().put(RegionAndName.fromRegionAndName(region, keyPair.getName()), keyPair);
          templateOptions.keyPairName(keyPair.getName());
       } else if (templateOptions.getKeyPairName() != null) {
          checkArgument(keyPairExtensionPresent,
@@ -120,11 +120,11 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
             String pem = templateOptions.getLoginPrivateKey();
             KeyPair keyPair = KeyPair.builder().name(templateOptions.getKeyPairName())
                      .fingerprint(fingerprintPrivateKey(pem)).privateKey(pem).build();
-            keyPairCache.asMap().put(ZoneAndName.fromZoneAndName(zone, keyPair.getName()), keyPair);
+            keyPairCache.asMap().put(RegionAndName.fromRegionAndName(region, keyPair.getName()), keyPair);
          }
       }
 
-      boolean securityGroupExtensionPresent = novaApi.getSecurityGroupExtensionForZone(zone).isPresent();
+      boolean securityGroupExtensionPresent = novaApi.getSecurityGroupApi(region).isPresent();
       List<Integer> inboundPorts = Ints.asList(templateOptions.getInboundPorts());
       if (!templateOptions.getGroups().isEmpty()) {
          checkArgument(securityGroupExtensionPresent,
@@ -134,7 +134,7 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
          if (templateOptions.getGroups().isEmpty() && !inboundPorts.isEmpty()) {
             String securityGroupName = namingConvention.create().sharedNameForGroup(group);
             try {
-               securityGroupCache.get(new ZoneSecurityGroupNameAndPorts(zone, securityGroupName, inboundPorts));
+               securityGroupCache.get(new RegionSecurityGroupNameAndPorts(region, securityGroupName, inboundPorts));
             } catch (ExecutionException e) {
                throw Throwables.propagate(e.getCause());
             }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaHttpApiModule.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaHttpApiModule.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaHttpApiModule.java
index d763406..0956c48 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaHttpApiModule.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaHttpApiModule.java
@@ -97,12 +97,12 @@ public class NovaHttpApiModule extends HttpApiModule<NovaApi> {
 
    @Provides
    @Singleton
-   public LoadingCache<String, Set<? extends Extension>> provideExtensionsByZone(final Provider<NovaApi> novaApi) {
+   public LoadingCache<String, Set<? extends Extension>> provideExtensionsByRegion(final Provider<NovaApi> novaApi) {
       return CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS)
             .build(new CacheLoader<String, Set<? extends Extension>>() {
                @Override
                public Set<? extends Extension> load(String key) throws Exception {
-                  return novaApi.get().getExtensionApiForZone(key).list();
+                  return novaApi.get().getExtensionApi(key).list();
                }
             });
    }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/HostAggregate.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/HostAggregate.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/HostAggregate.java
index 1c8673c..d5e75a3 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/HostAggregate.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/HostAggregate.java
@@ -36,16 +36,16 @@ import com.google.common.collect.ImmutableSet;
 
 /**
  * Aggregates can be manipulated using the Aggregate Extension to Nova (alias "OS-AGGREGATES")
- * 
+ *
  * @see org.jclouds.openstack.nova.v2_0.extensions.HostAggregateApi
 */
 public class HostAggregate {
 
-   public static Builder<?> builder() { 
+   public static Builder<?> builder() {
       return new ConcreteBuilder();
    }
-   
-   public Builder<?> toBuilder() { 
+
+   public Builder<?> toBuilder() {
       return new ConcreteBuilder().fromHostAggregate(this);
    }
 
@@ -60,8 +60,8 @@ public class HostAggregate {
       protected Date created;
       protected Date updated;
       protected Map<String, String> metadata = ImmutableMap.of();
-   
-      /** 
+
+      /**
        * @see HostAggregate#getId()
        */
       public T id(String id) {
@@ -69,7 +69,7 @@ public class HostAggregate {
          return self();
       }
 
-      /** 
+      /**
        * @see HostAggregate#getName()
        */
       public T name(String name) {
@@ -77,7 +77,7 @@ public class HostAggregate {
          return self();
       }
 
-      /** 
+      /**
        * @see HostAggregate#getAvailabilityZone()
        */
       public T availabilityZone(String availabilityZone) {
@@ -85,11 +85,11 @@ public class HostAggregate {
          return self();
       }
 
-      /** 
+      /**
        * @see HostAggregate#getHosts()
        */
       public T hosts(Set<String> hosts) {
-         this.hosts = ImmutableSet.copyOf(checkNotNull(hosts, "hosts"));      
+         this.hosts = ImmutableSet.copyOf(checkNotNull(hosts, "hosts"));
          return self();
       }
 
@@ -97,7 +97,7 @@ public class HostAggregate {
          return hosts(ImmutableSet.copyOf(in));
       }
 
-      /** 
+      /**
        * @see HostAggregate#getState()
        */
       public T state(String state) {
@@ -105,7 +105,7 @@ public class HostAggregate {
          return self();
       }
 
-      /** 
+      /**
        * @see HostAggregate#getCreated()
        */
       public T created(Date created) {
@@ -113,7 +113,7 @@ public class HostAggregate {
          return self();
       }
 
-      /** 
+      /**
        * @see HostAggregate#getUpdated()
        */
       public T updated(Date updated) {
@@ -121,18 +121,18 @@ public class HostAggregate {
          return self();
       }
 
-      /** 
+      /**
        * @see HostAggregate#getMetadata()
        */
       public T metadata(Map<String, String> metadata) {
-         this.metadata = ImmutableMap.copyOf(checkNotNull(metadata, "metadata"));     
+         this.metadata = ImmutableMap.copyOf(checkNotNull(metadata, "metadata"));
          return self();
       }
 
       public HostAggregate build() {
          return new HostAggregate(id, name, availabilityZone, hosts, state, created, updated, metadata);
       }
-      
+
       public T fromHostAggregate(HostAggregate in) {
          return this
                   .id(in.getId())
@@ -174,11 +174,11 @@ public class HostAggregate {
       this.id = checkNotNull(id, "id");
       this.name = checkNotNull(name, "name");
       this.availabilityZone = checkNotNull(availabilityZone, "availabilityZone");
-      this.hosts = hosts == null ? ImmutableSet.<String>of() : ImmutableSet.copyOf(hosts);      
+      this.hosts = hosts == null ? ImmutableSet.<String>of() : ImmutableSet.copyOf(hosts);
       this.state = checkNotNull(state, "state");
       this.created = checkNotNull(created, "created");
       this.updated = Optional.fromNullable(updated);
-      this.metadata = metadata == null ? ImmutableMap.<String, String>of() : ImmutableMap.copyOf(metadata);     
+      this.metadata = metadata == null ? ImmutableMap.<String, String>of() : ImmutableMap.copyOf(metadata);
    }
 
    public String getId() {
@@ -190,8 +190,6 @@ public class HostAggregate {
    }
 
    /**
-    * note: an "Availability Zone" is different from a Nova "Zone"
-    * 
     * @return the availability zone this aggregate is in
     */
    public String getAvailabilityZone() {
@@ -237,12 +235,12 @@ public class HostAggregate {
                && Objects.equal(this.updated, that.updated)
                && Objects.equal(this.metadata, that.metadata);
    }
-   
+
    protected ToStringHelper string() {
       return MoreObjects.toStringHelper(this)
             .add("id", id).add("name", name).add("availabilityZone", availabilityZone).add("hosts", hosts).add("state", state).add("created", created).add("updated", updated).add("metadata", metadata);
    }
-   
+
    @Override
    public String toString() {
       return string().toString();

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/AvailabilityZone.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/AvailabilityZone.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/AvailabilityZone.java
new file mode 100644
index 0000000..e59e4dd
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/AvailabilityZone.java
@@ -0,0 +1,69 @@
+/*
+ * 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 com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import com.google.gson.annotations.SerializedName;
+
+import java.beans.ConstructorProperties;
+
+public class AvailabilityZone {
+
+   @SerializedName("zoneName")
+   private final String name;
+   private final ZoneState state;
+
+   @ConstructorProperties({"zoneName" , "zoneState"})
+   protected AvailabilityZone(String name, ZoneState state) {
+      this.name = name;
+      this.state = state;
+   }
+
+   public String getName() {
+      return name;
+   }
+
+   public ZoneState getState() {
+      return state;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(name, state);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this != obj) return false;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      AvailabilityZone that = AvailabilityZone.class.cast(obj);
+      return Objects.equal(this.name, that.name) && Objects.equal(this.state, that.state);
+   }
+
+   protected MoreObjects.ToStringHelper string() {
+      return MoreObjects.toStringHelper(this)
+            .add("name", name)
+            .add("state", state);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/FlavorInRegion.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/FlavorInRegion.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/FlavorInRegion.java
new file mode 100644
index 0000000..5617673
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/FlavorInRegion.java
@@ -0,0 +1,43 @@
+/*
+ * 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 org.jclouds.openstack.nova.v2_0.domain.Flavor;
+
+public class FlavorInRegion extends RegionAndId {
+   protected final Flavor image;
+
+   public FlavorInRegion(Flavor image, String regionId) {
+      super(regionId, checkNotNull(image, "image").getId());
+      this.image = image;
+   }
+
+   public Flavor getFlavor() {
+      return image;
+   }
+
+   // superclass hashCode/equals are good enough, and help us use RegionAndId and FlavorInRegion
+   // interchangeably as Map keys
+
+   @Override
+   public String toString() {
+      return "[image=" + image + ", regionId=" + regionId + "]";
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/ImageInRegion.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/ImageInRegion.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/ImageInRegion.java
new file mode 100644
index 0000000..e1bf68e
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/ImageInRegion.java
@@ -0,0 +1,43 @@
+/*
+ * 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 org.jclouds.openstack.nova.v2_0.domain.Image;
+
+public class ImageInRegion extends RegionAndId {
+   protected final Image image;
+
+   public ImageInRegion(Image image, String regionId) {
+      super(regionId, checkNotNull(image, "image").getId());
+      this.image = image;
+   }
+
+   public Image getImage() {
+      return image;
+   }
+
+   // superclass hashCode/equals are good enough, and help us use RegionAndId and ImageInRegion
+   // interchangeably as Map keys
+
+   @Override
+   public String toString() {
+      return "[image=" + image + ", regionId=" + regionId + "]";
+   }
+
+}