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:47 UTC

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

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtensionExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtensionExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtensionExpectTest.java
index 775490a..9795aa9 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtensionExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaSecurityGroupExtensionExpectTest.java
@@ -47,7 +47,7 @@ import com.google.common.collect.Sets;
 @Test(groups = "unit", testName = "NovaSecurityGroupExtensionExpectTest")
 public class NovaSecurityGroupExtensionExpectTest extends BaseNovaComputeServiceExpectTest {
 
-   protected String zone = "az-1.region-a.geo-1";
+   protected String region = "az-1.region-a.geo-1";
    protected HttpRequest list = HttpRequest.builder().method("GET").endpoint(
            URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/3456/os-security-groups")).headers(
            ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
@@ -59,7 +59,7 @@ public class NovaSecurityGroupExtensionExpectTest extends BaseNovaComputeService
    @Override
    protected Properties setupProperties() {
       Properties overrides = super.setupProperties();
-      overrides.setProperty("jclouds.zones", zone);
+      overrides.setProperty("jclouds.regions", region);
       return overrides;
    }
 
@@ -95,9 +95,9 @@ public class NovaSecurityGroupExtensionExpectTest extends BaseNovaComputeService
       SecurityGroupExtension extension = requestsSendResponses(requestResponseMap.build()).getSecurityGroupExtension().get();
 
       Set<SecurityGroup> groups = extension.listSecurityGroupsInLocation(new LocationBuilder()
-              .scope(LocationScope.ZONE)
-              .id(zone)
-              .description("zone")
+              .scope(LocationScope.REGION)
+              .id(region)
+              .description("region")
               .build());
       assertEquals(groups.size(), 1);
    }
@@ -129,7 +129,7 @@ public class NovaSecurityGroupExtensionExpectTest extends BaseNovaComputeService
 
       SecurityGroupExtension extension = requestsSendResponses(requestResponseMap.build()).getSecurityGroupExtension().get();
 
-      Set<SecurityGroup> groups = extension.listSecurityGroupsForNode(zone + "/8d0a6ca5-8849-4b3d-b86e-f24c92490ebb");
+      Set<SecurityGroup> groups = extension.listSecurityGroupsForNode(region + "/8d0a6ca5-8849-4b3d-b86e-f24c92490ebb");
       assertEquals(groups.size(), 1);
    }
 
@@ -150,8 +150,8 @@ public class NovaSecurityGroupExtensionExpectTest extends BaseNovaComputeService
 
       SecurityGroupExtension extension = requestsSendResponses(requestResponseMap.build()).getSecurityGroupExtension().get();
 
-      SecurityGroup group = extension.getSecurityGroupById(zone + "/160");
-      assertEquals(group.getId(), zone + "/160");
+      SecurityGroup group = extension.getSecurityGroupById(region + "/160");
+      assertEquals(group.getId(), region + "/160");
    }
 
    public void testCreateSecurityGroup() {
@@ -193,11 +193,11 @@ public class NovaSecurityGroupExtensionExpectTest extends BaseNovaComputeService
       SecurityGroupExtension extension = requestsSendResponses(requestResponseMap.build()).getSecurityGroupExtension().get();
 
       SecurityGroup group = extension.createSecurityGroup("test", new LocationBuilder()
-              .scope(LocationScope.ZONE)
-              .id(zone)
-              .description("zone")
+              .scope(LocationScope.REGION)
+              .id(region)
+              .description("region")
               .build());
-      assertEquals(group.getId(), zone + "/160");
+      assertEquals(group.getId(), region + "/160");
    }
 
    public void testRemoveSecurityGroup() {
@@ -225,7 +225,7 @@ public class NovaSecurityGroupExtensionExpectTest extends BaseNovaComputeService
 
       SecurityGroupExtension extension = requestsSendResponses(requestResponseMap.build()).getSecurityGroupExtension().get();
 
-      assertTrue(extension.removeSecurityGroup(zone + "/160"), "Expected removal of securitygroup to be successful");
+      assertTrue(extension.removeSecurityGroup(region + "/160"), "Expected removal of securitygroup to be successful");
    }
 
    public void testAddIpPermissionCidrFromIpPermission() {
@@ -269,7 +269,7 @@ public class NovaSecurityGroupExtensionExpectTest extends BaseNovaComputeService
 
       IpPermission perm = builder.build();
 
-      SecurityGroup origGroup = extension.getSecurityGroupById(zone + "/160");
+      SecurityGroup origGroup = extension.getSecurityGroupById(region + "/160");
 
       assertNotNull(origGroup);
       SecurityGroup newGroup = extension.addIpPermission(perm, origGroup);
@@ -309,7 +309,7 @@ public class NovaSecurityGroupExtensionExpectTest extends BaseNovaComputeService
               ImmutableList.of(responseWithKeystoneAccess, extensionsOfNovaResponse, getSecurityGroupNoRulesResponse,
                       createRuleResponse, getSecurityGroupResponse, listResponse, listResponse)).getSecurityGroupExtension().get();
 
-      SecurityGroup origGroup = extension.getSecurityGroupById(zone + "/160");
+      SecurityGroup origGroup = extension.getSecurityGroupById(region + "/160");
 
       assertNotNull(origGroup);
       SecurityGroup newGroup = extension.addIpPermission(IpProtocol.TCP,
@@ -364,7 +364,7 @@ public class NovaSecurityGroupExtensionExpectTest extends BaseNovaComputeService
 
       IpPermission perm = builder.build();
 
-      SecurityGroup origGroup = extension.getSecurityGroupById(zone + "/160");
+      SecurityGroup origGroup = extension.getSecurityGroupById(region + "/160");
 
       assertNotNull(origGroup);
       SecurityGroup newGroup = extension.addIpPermission(perm, origGroup);
@@ -404,7 +404,7 @@ public class NovaSecurityGroupExtensionExpectTest extends BaseNovaComputeService
               ImmutableList.of(responseWithKeystoneAccess, extensionsOfNovaResponse, getSecurityGroupNoRulesResponse,
                       createRuleResponse, getSecurityGroupResponse, listResponse, listResponse)).getSecurityGroupExtension().get();
 
-      SecurityGroup origGroup = extension.getSecurityGroupById(zone + "/160");
+      SecurityGroup origGroup = extension.getSecurityGroupById(region + "/160");
 
       assertNotNull(origGroup);
       SecurityGroup newGroup = extension.addIpPermission(IpProtocol.TCP,

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/AllocateAndAddFloatingIpToNodeExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/AllocateAndAddFloatingIpToNodeExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/AllocateAndAddFloatingIpToNodeExpectTest.java
index 28cc533..af20d85 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/AllocateAndAddFloatingIpToNodeExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/AllocateAndAddFloatingIpToNodeExpectTest.java
@@ -48,10 +48,10 @@ import com.google.common.util.concurrent.Atomics;
 public class AllocateAndAddFloatingIpToNodeExpectTest extends BaseNovaComputeServiceExpectTest {
    final Location provider = new LocationBuilder().scope(LocationScope.PROVIDER).id("openstack-nova").description(
             "openstack-nova").build();
-   final Location zone = new LocationBuilder().id("az-1.region-a.geo-1").description("az-1.region-a.geo-1").scope(
-            LocationScope.ZONE).parent(provider).build();
+   final Location region = new LocationBuilder().id("az-1.region-a.geo-1").description("az-1.region-a.geo-1").scope(
+            LocationScope.REGION).parent(provider).build();
    final Location host = new LocationBuilder().scope(LocationScope.HOST).id("hostId").description("hostId")
-            .parent(zone).build();
+            .parent(region).build();
    final NodeMetadata node = new NodeMetadataBuilder().id("az-1.region-a.geo-1/71592").providerId("71592").location(
             host).name("Server 71592").status(Status.RUNNING).privateAddresses(ImmutableSet.of("10.4.27.237"))
             .credentials(LoginCredentials.builder().password("foo").build()).build();

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/FlavorInRegionToHardwareTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/FlavorInRegionToHardwareTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/FlavorInRegionToHardwareTest.java
new file mode 100644
index 0000000..7445c9a
--- /dev/null
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/FlavorInRegionToHardwareTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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 org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+
+import java.util.Map;
+import java.util.UUID;
+
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.domain.Location;
+import org.jclouds.domain.LocationBuilder;
+import org.jclouds.domain.LocationScope;
+import org.jclouds.openstack.nova.v2_0.domain.Flavor;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.FlavorInRegion;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Tests the function used to transform Flavor objects into Hardware objects
+ */
+@Test(testName = "FlavorInRegionToHardwareTest")
+public class FlavorInRegionToHardwareTest {
+   Location provider = new LocationBuilder().scope(LocationScope.PROVIDER).id("openstack-nova").description(
+            "openstack-nova").build();
+   Location region = new LocationBuilder().id("az-1.region-a.geo-1").description("az-1.region-a.geo-1").scope(
+            LocationScope.REGION).parent(provider).build();
+   Supplier<Map<String, Location>> locationIndex = Suppliers.<Map<String, Location>> ofInstance(ImmutableMap
+            .<String, Location> of("az-1.region-a.geo-1", region));
+
+   @Test
+   public void testConversionWhereLocationFound() {
+
+      UUID id = UUID.randomUUID();
+
+      FlavorInRegion flavorInRegionToConvert = new FlavorInRegion(Flavor.builder().id(id.toString())
+               .name("Test Flavor " + id).ram(262144).disk(10000).vcpus(16).build(), "az-1.region-a.geo-1");
+
+      Hardware converted = new FlavorInRegionToHardware(locationIndex).apply(flavorInRegionToConvert);
+
+      Flavor flavorToConvert = flavorInRegionToConvert.getFlavor();
+      assertEquals(converted.getName(), flavorToConvert.getName());
+      assertEquals(converted.getId(), flavorInRegionToConvert.slashEncode());
+      assertEquals(converted.getProviderId(), flavorToConvert.getId());
+      assertEquals(converted.getLocation(), locationIndex.get().get("az-1.region-a.geo-1"));
+
+      assertEquals(converted.getRam(), flavorToConvert.getRam());
+
+      assertNotNull(converted.getProcessors());
+      assertFalse(converted.getProcessors().isEmpty());
+      assertEquals(converted.getProcessors().iterator().next().getCores(), (double) flavorToConvert.getVcpus());
+
+      assertNotNull(converted.getVolumes());
+      assertFalse(converted.getVolumes().isEmpty());
+      assertEquals(converted.getVolumes().iterator().next().getSize(), Float.valueOf(flavorToConvert.getDisk()));
+
+   }
+
+   @Test(expectedExceptions = IllegalStateException.class)
+   public void testConversionWhereLocationNotFound() {
+
+      UUID id = UUID.randomUUID();
+
+      FlavorInRegion flavorInRegionToConvert = new FlavorInRegion(Flavor.builder().id(id.toString())
+               .name("Test Flavor " + id).ram(262144).disk(10000).vcpus(16).build(), "South");
+      new FlavorInRegionToHardware(locationIndex).apply(flavorInRegionToConvert);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/FlavorInZoneToHardwareTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/FlavorInZoneToHardwareTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/FlavorInZoneToHardwareTest.java
deleted file mode 100644
index 6e0e001..0000000
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/FlavorInZoneToHardwareTest.java
+++ /dev/null
@@ -1,88 +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 org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNotNull;
-
-import java.util.Map;
-import java.util.UUID;
-
-import org.jclouds.compute.domain.Hardware;
-import org.jclouds.domain.Location;
-import org.jclouds.domain.LocationBuilder;
-import org.jclouds.domain.LocationScope;
-import org.jclouds.openstack.nova.v2_0.domain.Flavor;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.FlavorInZone;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.ImmutableMap;
-
-/**
- * Tests the function used to transform Flavor objects into Hardware objects
- */
-@Test(testName = "FlavorInZoneToHardwareTest")
-public class FlavorInZoneToHardwareTest {
-   Location provider = new LocationBuilder().scope(LocationScope.PROVIDER).id("openstack-nova").description(
-            "openstack-nova").build();
-   Location zone = new LocationBuilder().id("az-1.region-a.geo-1").description("az-1.region-a.geo-1").scope(
-            LocationScope.ZONE).parent(provider).build();
-   Supplier<Map<String, Location>> locationIndex = Suppliers.<Map<String, Location>> ofInstance(ImmutableMap
-            .<String, Location> of("az-1.region-a.geo-1", zone));
-
-   @Test
-   public void testConversionWhereLocationFound() {
-
-      UUID id = UUID.randomUUID();
-
-      FlavorInZone flavorInZoneToConvert = new FlavorInZone(Flavor.builder().id(id.toString())
-               .name("Test Flavor " + id).ram(262144).disk(10000).vcpus(16).build(), "az-1.region-a.geo-1");
-
-      Hardware converted = new FlavorInZoneToHardware(locationIndex).apply(flavorInZoneToConvert);
-
-      Flavor flavorToConvert = flavorInZoneToConvert.getFlavor();
-      assertEquals(converted.getName(), flavorToConvert.getName());
-      assertEquals(converted.getId(), flavorInZoneToConvert.slashEncode());
-      assertEquals(converted.getProviderId(), flavorToConvert.getId());
-      assertEquals(converted.getLocation(), locationIndex.get().get("az-1.region-a.geo-1"));
-
-      assertEquals(converted.getRam(), flavorToConvert.getRam());
-
-      assertNotNull(converted.getProcessors());
-      assertFalse(converted.getProcessors().isEmpty());
-      assertEquals(converted.getProcessors().iterator().next().getCores(), (double) flavorToConvert.getVcpus());
-
-      assertNotNull(converted.getVolumes());
-      assertFalse(converted.getVolumes().isEmpty());
-      assertEquals(converted.getVolumes().iterator().next().getSize(), Float.valueOf(flavorToConvert.getDisk()));
-
-   }
-
-   @Test(expectedExceptions = IllegalStateException.class)
-   public void testConversionWhereLocationNotFound() {
-
-      UUID id = UUID.randomUUID();
-
-      FlavorInZone flavorInZoneToConvert = new FlavorInZone(Flavor.builder().id(id.toString())
-               .name("Test Flavor " + id).ram(262144).disk(10000).vcpus(16).build(), "South");
-      new FlavorInZoneToHardware(locationIndex).apply(flavorInZoneToConvert);
-   }
-
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/ImageInRegionToImageTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/ImageInRegionToImageTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/ImageInRegionToImageTest.java
new file mode 100644
index 0000000..b767929
--- /dev/null
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/ImageInRegionToImageTest.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.compute.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Map;
+import java.util.UUID;
+
+import org.jclouds.compute.domain.OperatingSystem;
+import org.jclouds.compute.domain.OsFamily;
+import org.jclouds.domain.Location;
+import org.jclouds.domain.LocationBuilder;
+import org.jclouds.domain.LocationScope;
+import org.jclouds.openstack.nova.v2_0.compute.config.NovaComputeServiceContextModule;
+import org.jclouds.openstack.nova.v2_0.domain.Image;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.ImageInRegion;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Tests the function that transforms nova-specific images to generic images.
+ */
+@Test(testName = "ImageInRegionToHardwareTest")
+public class ImageInRegionToImageTest {
+
+   Location provider = new LocationBuilder().scope(LocationScope.PROVIDER).id("openstack-nova").description(
+            "openstack-nova").build();
+   Location region = new LocationBuilder().id("az-1.region-a.geo-1").description("az-1.region-a.geo-1").scope(
+            LocationScope.REGION).parent(provider).build();
+   Supplier<Map<String, Location>> locationIndex = Suppliers.<Map<String, Location>> ofInstance(ImmutableMap
+            .<String, Location> of("az-1.region-a.geo-1", region));
+
+   @Test
+   public void testConversionWhereLocationFound() {
+      UUID id = UUID.randomUUID();
+      Image novaImageToConvert = Image.builder().id(id.toString()).name("Test Image " + id).status(Image.Status.DELETED).build();
+      OperatingSystem operatingSystem = new OperatingSystem(OsFamily.UBUNTU, "My Test OS", "My Test Version", "x86",
+               "My Test OS", true);
+      ImageInRegionToImage converter = new ImageInRegionToImage(NovaComputeServiceContextModule.toPortableImageStatus,
+               constant(operatingSystem), locationIndex);
+
+      ImageInRegion novaImageInRegionToConvert = new ImageInRegion(novaImageToConvert, "az-1.region-a.geo-1");
+
+      org.jclouds.compute.domain.Image convertedImage = converter.apply(novaImageInRegionToConvert);
+
+      assertEquals(convertedImage.getId(), novaImageInRegionToConvert.slashEncode());
+      assertEquals(convertedImage.getProviderId(), novaImageToConvert.getId());
+      assertEquals(convertedImage.getLocation(), locationIndex.get().get("az-1.region-a.geo-1"));
+
+      assertEquals(convertedImage.getName(), novaImageToConvert.getName());
+      assertEquals(convertedImage.getStatus(), org.jclouds.compute.domain.Image.Status.DELETED);
+      assertEquals(convertedImage.getOperatingSystem(), operatingSystem);
+   }
+
+   @Test(expectedExceptions = IllegalStateException.class)
+   public void testConversionWhereLocationNotFound() {
+      UUID id = UUID.randomUUID();
+      Image novaImageToConvert = Image.builder().id(id.toString()).name("Test Image " + id).build();
+      OperatingSystem operatingSystem = new OperatingSystem(OsFamily.UBUNTU, "My Test OS", "My Test Version", "x86",
+               "My Test OS", true);
+      ImageInRegionToImage converter = new ImageInRegionToImage(NovaComputeServiceContextModule.toPortableImageStatus,
+               constant(operatingSystem), locationIndex);
+
+      ImageInRegion novaImageInRegionToConvert = new ImageInRegion(novaImageToConvert, "South");
+
+      converter.apply(novaImageInRegionToConvert);
+   }
+
+   @SuppressWarnings("unchecked")
+   private static Function<Image, OperatingSystem> constant(OperatingSystem operatingSystem) {
+      return Function.class.cast(Functions.constant(operatingSystem));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/ImageInZoneToImageTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/ImageInZoneToImageTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/ImageInZoneToImageTest.java
deleted file mode 100644
index 9872242..0000000
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/ImageInZoneToImageTest.java
+++ /dev/null
@@ -1,93 +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 org.testng.Assert.assertEquals;
-
-import java.util.Map;
-import java.util.UUID;
-
-import org.jclouds.compute.domain.OperatingSystem;
-import org.jclouds.compute.domain.OsFamily;
-import org.jclouds.domain.Location;
-import org.jclouds.domain.LocationBuilder;
-import org.jclouds.domain.LocationScope;
-import org.jclouds.openstack.nova.v2_0.compute.config.NovaComputeServiceContextModule;
-import org.jclouds.openstack.nova.v2_0.domain.Image;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ImageInZone;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.ImmutableMap;
-
-/**
- * Tests the function that transforms nova-specific images to generic images.
- */
-@Test(testName = "ImageInZoneToHardwareTest")
-public class ImageInZoneToImageTest {
-
-   Location provider = new LocationBuilder().scope(LocationScope.PROVIDER).id("openstack-nova").description(
-            "openstack-nova").build();
-   Location zone = new LocationBuilder().id("az-1.region-a.geo-1").description("az-1.region-a.geo-1").scope(
-            LocationScope.ZONE).parent(provider).build();
-   Supplier<Map<String, Location>> locationIndex = Suppliers.<Map<String, Location>> ofInstance(ImmutableMap
-            .<String, Location> of("az-1.region-a.geo-1", zone));
-   
-   @Test
-   public void testConversionWhereLocationFound() {
-      UUID id = UUID.randomUUID();
-      Image novaImageToConvert = Image.builder().id(id.toString()).name("Test Image " + id).status(Image.Status.DELETED).build();
-      OperatingSystem operatingSystem = new OperatingSystem(OsFamily.UBUNTU, "My Test OS", "My Test Version", "x86",
-               "My Test OS", true);
-      ImageInZoneToImage converter = new ImageInZoneToImage(NovaComputeServiceContextModule.toPortableImageStatus,
-               constant(operatingSystem), locationIndex);
-
-      ImageInZone novaImageInZoneToConvert = new ImageInZone(novaImageToConvert, "az-1.region-a.geo-1");
-
-      org.jclouds.compute.domain.Image convertedImage = converter.apply(novaImageInZoneToConvert);
-
-      assertEquals(convertedImage.getId(), novaImageInZoneToConvert.slashEncode());
-      assertEquals(convertedImage.getProviderId(), novaImageToConvert.getId());
-      assertEquals(convertedImage.getLocation(), locationIndex.get().get("az-1.region-a.geo-1"));
-
-      assertEquals(convertedImage.getName(), novaImageToConvert.getName());
-      assertEquals(convertedImage.getStatus(), org.jclouds.compute.domain.Image.Status.DELETED);
-      assertEquals(convertedImage.getOperatingSystem(), operatingSystem);
-   }
-
-   @Test(expectedExceptions = IllegalStateException.class)
-   public void testConversionWhereLocationNotFound() {
-      UUID id = UUID.randomUUID();
-      Image novaImageToConvert = Image.builder().id(id.toString()).name("Test Image " + id).build();
-      OperatingSystem operatingSystem = new OperatingSystem(OsFamily.UBUNTU, "My Test OS", "My Test Version", "x86",
-               "My Test OS", true);
-      ImageInZoneToImage converter = new ImageInZoneToImage(NovaComputeServiceContextModule.toPortableImageStatus,
-               constant(operatingSystem), locationIndex);
-
-      ImageInZone novaImageInZoneToConvert = new ImageInZone(novaImageToConvert, "South");
-
-      converter.apply(novaImageInZoneToConvert);
-   }
-
-   @SuppressWarnings("unchecked")
-   private static Function<Image, OperatingSystem> constant(OperatingSystem operatingSystem) {
-      return Function.class.cast(Functions.constant(operatingSystem));
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInRegionToSecurityGroupTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInRegionToSecurityGroupTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInRegionToSecurityGroupTest.java
new file mode 100644
index 0000000..969b3f4
--- /dev/null
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInRegionToSecurityGroupTest.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.compute.functions;
+
+import static com.google.common.collect.Iterables.transform;
+import static org.jclouds.openstack.nova.v2_0.compute.functions.NovaSecurityGroupToSecurityGroupTest.securityGroupWithCidr;
+import static org.jclouds.openstack.nova.v2_0.compute.functions.NovaSecurityGroupToSecurityGroupTest.securityGroupWithGroup;
+import static org.testng.Assert.assertEquals;
+
+import java.util.Map;
+
+import org.jclouds.compute.domain.SecurityGroup;
+import org.jclouds.domain.Location;
+import org.jclouds.domain.LocationBuilder;
+import org.jclouds.domain.LocationScope;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.SecurityGroupInRegion;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+@Test(groups = "unit", testName = "NovaSecurityGroupInRegionToSecurityGroupTest")
+public class NovaSecurityGroupInRegionToSecurityGroupTest {
+
+   Location provider = new LocationBuilder().scope(LocationScope.PROVIDER).id("openstack-nova")
+           .description("openstack-nova").build();
+   Location region = new LocationBuilder().id("az-1.region-a.geo-1").description("az-1.region-a.geo-1")
+           .scope(LocationScope.REGION).parent(provider).build();
+   Supplier<Map<String, Location>> locationIndex = Suppliers.<Map<String, Location>> ofInstance(ImmutableMap
+           .<String, Location>of("az-1.region-a.geo-1", region));
+
+
+   @Test
+   public void testApplyWithGroup() {
+      NovaSecurityGroupInRegionToSecurityGroup parser = createGroupParser();
+
+      SecurityGroupInRegion origGroup = new SecurityGroupInRegion(securityGroupWithGroup(), region.getId());
+
+      SecurityGroup newGroup = parser.apply(origGroup);
+
+      assertEquals(newGroup.getId(), origGroup.getRegion() + "/" + origGroup.getSecurityGroup().getId());
+      assertEquals(newGroup.getProviderId(), origGroup.getSecurityGroup().getId());
+      assertEquals(newGroup.getName(), origGroup.getSecurityGroup().getName());
+      assertEquals(newGroup.getOwnerId(), origGroup.getSecurityGroup().getTenantId());
+      assertEquals(newGroup.getIpPermissions(), ImmutableSet.copyOf(transform(origGroup.getSecurityGroup().getRules(),
+              NovaSecurityGroupToSecurityGroupTest.ruleConverter)));
+      assertEquals(newGroup.getLocation().getId(), origGroup.getRegion());
+   }
+
+   @Test
+   public void testApplyWithCidr() {
+
+      NovaSecurityGroupInRegionToSecurityGroup parser = createGroupParser();
+
+      SecurityGroupInRegion origGroup = new SecurityGroupInRegion(securityGroupWithCidr(), region.getId());
+
+      SecurityGroup newGroup = parser.apply(origGroup);
+
+      assertEquals(newGroup.getId(), origGroup.getRegion() + "/" + origGroup.getSecurityGroup().getId());
+      assertEquals(newGroup.getProviderId(), origGroup.getSecurityGroup().getId());
+      assertEquals(newGroup.getName(), origGroup.getSecurityGroup().getName());
+      assertEquals(newGroup.getOwnerId(), origGroup.getSecurityGroup().getTenantId());
+      assertEquals(newGroup.getIpPermissions(), ImmutableSet.copyOf(transform(origGroup.getSecurityGroup().getRules(),
+              NovaSecurityGroupToSecurityGroupTest.ruleConverter)));
+      assertEquals(newGroup.getLocation().getId(), origGroup.getRegion());
+   }
+
+   private NovaSecurityGroupInRegionToSecurityGroup createGroupParser() {
+      NovaSecurityGroupToSecurityGroup baseParser = new NovaSecurityGroupToSecurityGroup(NovaSecurityGroupToSecurityGroupTest.ruleConverter);
+
+      NovaSecurityGroupInRegionToSecurityGroup parser = new NovaSecurityGroupInRegionToSecurityGroup(baseParser, locationIndex);
+
+      return parser;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInZoneToSecurityGroupTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInZoneToSecurityGroupTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInZoneToSecurityGroupTest.java
deleted file mode 100644
index dceba6c..0000000
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupInZoneToSecurityGroupTest.java
+++ /dev/null
@@ -1,91 +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.collect.Iterables.transform;
-import static org.jclouds.openstack.nova.v2_0.compute.functions.NovaSecurityGroupToSecurityGroupTest.securityGroupWithCidr;
-import static org.jclouds.openstack.nova.v2_0.compute.functions.NovaSecurityGroupToSecurityGroupTest.securityGroupWithGroup;
-import static org.testng.Assert.assertEquals;
-
-import java.util.Map;
-
-import org.jclouds.compute.domain.SecurityGroup;
-import org.jclouds.domain.Location;
-import org.jclouds.domain.LocationBuilder;
-import org.jclouds.domain.LocationScope;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.SecurityGroupInZone;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-
-@Test(groups = "unit", testName = "NovaSecurityGroupInZoneToSecurityGroupTest")
-public class NovaSecurityGroupInZoneToSecurityGroupTest {
-
-   Location provider = new LocationBuilder().scope(LocationScope.PROVIDER).id("openstack-nova")
-           .description("openstack-nova").build();
-   Location zone = new LocationBuilder().id("az-1.region-a.geo-1").description("az-1.region-a.geo-1")
-           .scope(LocationScope.ZONE).parent(provider).build();
-   Supplier<Map<String, Location>> locationIndex = Suppliers.<Map<String, Location>> ofInstance(ImmutableMap
-           .<String, Location>of("az-1.region-a.geo-1", zone));
-
-
-   @Test
-   public void testApplyWithGroup() {
-      NovaSecurityGroupInZoneToSecurityGroup parser = createGroupParser();
-
-      SecurityGroupInZone origGroup = new SecurityGroupInZone(securityGroupWithGroup(), zone.getId());
-
-      SecurityGroup newGroup = parser.apply(origGroup);
-
-      assertEquals(newGroup.getId(), origGroup.getZone() + "/" + origGroup.getSecurityGroup().getId());
-      assertEquals(newGroup.getProviderId(), origGroup.getSecurityGroup().getId());
-      assertEquals(newGroup.getName(), origGroup.getSecurityGroup().getName());
-      assertEquals(newGroup.getOwnerId(), origGroup.getSecurityGroup().getTenantId());
-      assertEquals(newGroup.getIpPermissions(), ImmutableSet.copyOf(transform(origGroup.getSecurityGroup().getRules(),
-              NovaSecurityGroupToSecurityGroupTest.ruleConverter)));
-      assertEquals(newGroup.getLocation().getId(), origGroup.getZone());
-   }
-
-   @Test
-   public void testApplyWithCidr() {
-
-      NovaSecurityGroupInZoneToSecurityGroup parser = createGroupParser();
-
-      SecurityGroupInZone origGroup = new SecurityGroupInZone(securityGroupWithCidr(), zone.getId());
-
-      SecurityGroup newGroup = parser.apply(origGroup);
-
-      assertEquals(newGroup.getId(), origGroup.getZone() + "/" + origGroup.getSecurityGroup().getId());
-      assertEquals(newGroup.getProviderId(), origGroup.getSecurityGroup().getId());
-      assertEquals(newGroup.getName(), origGroup.getSecurityGroup().getName());
-      assertEquals(newGroup.getOwnerId(), origGroup.getSecurityGroup().getTenantId());
-      assertEquals(newGroup.getIpPermissions(), ImmutableSet.copyOf(transform(origGroup.getSecurityGroup().getRules(),
-              NovaSecurityGroupToSecurityGroupTest.ruleConverter)));
-      assertEquals(newGroup.getLocation().getId(), origGroup.getZone());
-   }
-
-   private NovaSecurityGroupInZoneToSecurityGroup createGroupParser() {
-      NovaSecurityGroupToSecurityGroup baseParser = new NovaSecurityGroupToSecurityGroup(NovaSecurityGroupToSecurityGroupTest.ruleConverter);
-
-      NovaSecurityGroupInZoneToSecurityGroup parser = new NovaSecurityGroupInZoneToSecurityGroup(baseParser, locationIndex);
-
-      return parser;
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupToSecurityGroupTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupToSecurityGroupTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupToSecurityGroupTest.java
index 1a964b6..5edc44d 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupToSecurityGroupTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/NovaSecurityGroupToSecurityGroupTest.java
@@ -29,8 +29,8 @@ import org.jclouds.domain.LocationScope;
 import org.jclouds.net.domain.IpProtocol;
 import org.jclouds.openstack.nova.v2_0.domain.SecurityGroupRule;
 import org.jclouds.openstack.nova.v2_0.domain.TenantIdAndName;
-import org.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.RegionAndName;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.SecurityGroupInRegion;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Functions;
@@ -49,23 +49,23 @@ public class NovaSecurityGroupToSecurityGroupTest {
 
    private static final Location provider = new LocationBuilder().scope(LocationScope.PROVIDER).id("openstack-nova")
            .description("openstack-nova").build();
-   private static final Location zone = new LocationBuilder().id("az-1.region-a.geo-1").description("az-1.region-a.geo-1")
-           .scope(LocationScope.ZONE).parent(provider).build();
+   private static final Location region = new LocationBuilder().id("az-1.region-a.geo-1").description("az-1.region-a.geo-1")
+           .scope(LocationScope.REGION).parent(provider).build();
    private static final Supplier<Map<String, Location>> locationIndex = Suppliers.<Map<String, Location>> ofInstance(ImmutableMap
-           .<String, Location>of("az-1.region-a.geo-1", zone));
+           .<String, Location>of("az-1.region-a.geo-1", region));
 
 
-   private static final Predicate<AtomicReference<ZoneAndName>> returnSecurityGroupExistsInZone = Predicates.alwaysTrue();
+   private static final Predicate<AtomicReference<RegionAndName>> returnSecurityGroupExistsInRegion = Predicates.alwaysTrue();
 
-   private static final Map<ZoneAndName, SecurityGroupInZone> groupMap = ImmutableMap.of(
-           ZoneAndName.fromZoneAndName("az-1.region-a.geo-1", "some-group"), new SecurityGroupInZone(securityGroupWithGroup(), "az-1.region-a.geo-1"),
-           ZoneAndName.fromZoneAndName("az-1.region-a.geo-1", "some-other-group"), new SecurityGroupInZone(securityGroupWithCidr(), "az-1.region-a.geo-1"));
+   private static final Map<RegionAndName, SecurityGroupInRegion> groupMap = ImmutableMap.of(
+           RegionAndName.fromRegionAndName("az-1.region-a.geo-1", "some-group"), new SecurityGroupInRegion(securityGroupWithGroup(), "az-1.region-a.geo-1"),
+           RegionAndName.fromRegionAndName("az-1.region-a.geo-1", "some-other-group"), new SecurityGroupInRegion(securityGroupWithCidr(), "az-1.region-a.geo-1"));
 
    // weird compilation error means have to declare extra generics for call to build() - see https://bugs.eclipse.org/bugs/show_bug.cgi?id=365818
-   private static final Supplier <LoadingCache<ZoneAndName, SecurityGroupInZone>> groupCache = Suppliers.<LoadingCache<ZoneAndName, SecurityGroupInZone>> ofInstance(
-           CacheBuilder.newBuilder().<ZoneAndName, SecurityGroupInZone>build(CacheLoader.from(Functions.forMap(groupMap))));
+   private static final Supplier <LoadingCache<RegionAndName, SecurityGroupInRegion>> groupCache = Suppliers.<LoadingCache<RegionAndName, SecurityGroupInRegion>> ofInstance(
+           CacheBuilder.newBuilder().<RegionAndName, SecurityGroupInRegion>build(CacheLoader.from(Functions.forMap(groupMap))));
 
-   public static final SecurityGroupRuleToIpPermission ruleConverter = new SecurityGroupRuleToIpPermission(returnSecurityGroupExistsInZone, locationIndex,
+   public static final SecurityGroupRuleToIpPermission ruleConverter = new SecurityGroupRuleToIpPermission(returnSecurityGroupExistsInRegion, locationIndex,
            groupCache.get());
 
    public static org.jclouds.openstack.nova.v2_0.domain.SecurityGroup securityGroupWithGroup() {

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/OrphanedGroupsByRegionIdTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/OrphanedGroupsByRegionIdTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/OrphanedGroupsByRegionIdTest.java
new file mode 100644
index 0000000..27b976d
--- /dev/null
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/OrphanedGroupsByRegionIdTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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 org.testng.Assert.assertEquals;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.functions.GroupNamingConvention;
+import org.jclouds.domain.Location;
+import org.jclouds.domain.LocationBuilder;
+import org.jclouds.domain.LocationScope;
+import org.jclouds.openstack.nova.v2_0.compute.config.NovaComputeServiceContextModule;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.ServerInRegion;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
+import org.jclouds.openstack.nova.v2_0.parse.ParseServerTest;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicates;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Guice;
+
+@Test(testName = "OrphanedGroupsByRegionIdTest")
+public class OrphanedGroupsByRegionIdTest {
+
+   Location provider = new LocationBuilder().scope(LocationScope.PROVIDER).id("openstack-nova").description(
+            "openstack-nova").build();
+   Location region = new LocationBuilder().id("az-1.region-a.geo-1").description("az-1.region-a.geo-1").scope(
+            LocationScope.REGION).parent(provider).build();
+   Supplier<Map<String, Location>> locationIndex = Suppliers.<Map<String, Location>> ofInstance(ImmutableMap
+            .<String, Location> of("az-1.region-a.geo-1", region));
+
+   GroupNamingConvention.Factory namingConvention = Guice.createInjector().getInstance(GroupNamingConvention.Factory.class);
+
+   @Test
+   public void testWhenComputeServiceSaysAllNodesAreDeadBothGroupsAreReturned() {
+
+      ServerInRegion withoutHost = new ServerInRegion(new ServerInRegionToNodeMetadataTest().expectedServer(), "az-1.region-a.geo-1");
+      ServerInRegion withHost = new ServerInRegion(new ParseServerTest().expected(), "az-1.region-a.geo-1");
+
+      ServerInRegionToNodeMetadata converter = new ServerInRegionToNodeMetadata(
+               NovaComputeServiceContextModule.toPortableNodeStatus, locationIndex, Suppliers
+               .<Set<? extends Image>> ofInstance(ImmutableSet.<Image> of()), Suppliers
+               .<Set<? extends Hardware>> ofInstance(ImmutableSet.<Hardware> of()), namingConvention);
+
+      Set<? extends NodeMetadata> set = ImmutableSet.of(converter.apply(withHost), converter.apply(withoutHost));
+
+      assertEquals(new OrphanedGroupsByRegionId(Predicates.<RegionAndName> alwaysTrue()).apply(set), ImmutableMultimap
+               .<String, String> builder().putAll("az-1.region-a.geo-1", "sample", "test").build());
+   }
+
+   @Test
+   public void testWhenComputeServiceSaysAllNodesAreDeadNoGroupsAreReturned() {
+
+      ServerInRegion withoutHost = new ServerInRegion(new ServerInRegionToNodeMetadataTest().expectedServer(), "az-1.region-a.geo-1");
+      ServerInRegion withHost = new ServerInRegion(new ParseServerTest().expected(), "az-1.region-a.geo-1");
+
+      ServerInRegionToNodeMetadata converter = new ServerInRegionToNodeMetadata(
+               NovaComputeServiceContextModule.toPortableNodeStatus, locationIndex, Suppliers
+                        .<Set<? extends Image>> ofInstance(ImmutableSet.<Image> of()), Suppliers
+                        .<Set<? extends Hardware>> ofInstance(ImmutableSet.<Hardware> of()), namingConvention);
+
+      Set<? extends NodeMetadata> set = ImmutableSet.of(converter.apply(withHost), converter.apply(withoutHost));
+
+      assertEquals(new OrphanedGroupsByRegionId(Predicates.<RegionAndName> alwaysFalse()).apply(set), ImmutableMultimap
+               .<String, String> of());
+
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/OrphanedGroupsByZoneIdTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/OrphanedGroupsByZoneIdTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/OrphanedGroupsByZoneIdTest.java
deleted file mode 100644
index b6ae064..0000000
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/OrphanedGroupsByZoneIdTest.java
+++ /dev/null
@@ -1,91 +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 org.testng.Assert.assertEquals;
-
-import java.util.Map;
-import java.util.Set;
-
-import org.jclouds.compute.domain.Hardware;
-import org.jclouds.compute.domain.Image;
-import org.jclouds.compute.domain.NodeMetadata;
-import org.jclouds.compute.functions.GroupNamingConvention;
-import org.jclouds.domain.Location;
-import org.jclouds.domain.LocationBuilder;
-import org.jclouds.domain.LocationScope;
-import org.jclouds.openstack.nova.v2_0.compute.config.NovaComputeServiceContextModule;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ServerInZone;
-import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneAndName;
-import org.jclouds.openstack.nova.v2_0.parse.ParseServerTest;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Predicates;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.ImmutableSet;
-import com.google.inject.Guice;
-
-@Test(testName = "OrphanedGroupsByZoneIdTest")
-public class OrphanedGroupsByZoneIdTest {
-
-   Location provider = new LocationBuilder().scope(LocationScope.PROVIDER).id("openstack-nova").description(
-            "openstack-nova").build();
-   Location zone = new LocationBuilder().id("az-1.region-a.geo-1").description("az-1.region-a.geo-1").scope(
-            LocationScope.ZONE).parent(provider).build();
-   Supplier<Map<String, Location>> locationIndex = Suppliers.<Map<String, Location>> ofInstance(ImmutableMap
-            .<String, Location> of("az-1.region-a.geo-1", zone));
-
-   GroupNamingConvention.Factory namingConvention = Guice.createInjector().getInstance(GroupNamingConvention.Factory.class);
-   
-   @Test
-   public void testWhenComputeServiceSaysAllNodesAreDeadBothGroupsAreReturned() {
-
-      ServerInZone withoutHost = new ServerInZone(new ServerInZoneToNodeMetadataTest().expectedServer(), "az-1.region-a.geo-1");
-      ServerInZone withHost = new ServerInZone(new ParseServerTest().expected(), "az-1.region-a.geo-1");
-      
-      ServerInZoneToNodeMetadata converter = new ServerInZoneToNodeMetadata(
-               NovaComputeServiceContextModule.toPortableNodeStatus, locationIndex, Suppliers
-               .<Set<? extends Image>> ofInstance(ImmutableSet.<Image> of()), Suppliers
-               .<Set<? extends Hardware>> ofInstance(ImmutableSet.<Hardware> of()), namingConvention);
-
-      Set<? extends NodeMetadata> set = ImmutableSet.of(converter.apply(withHost), converter.apply(withoutHost));
-
-      assertEquals(new OrphanedGroupsByZoneId(Predicates.<ZoneAndName> alwaysTrue()).apply(set), ImmutableMultimap
-               .<String, String> builder().putAll("az-1.region-a.geo-1", "sample", "test").build());
-   }
-
-   @Test
-   public void testWhenComputeServiceSaysAllNodesAreDeadNoGroupsAreReturned() {
-
-      ServerInZone withoutHost = new ServerInZone(new ServerInZoneToNodeMetadataTest().expectedServer(), "az-1.region-a.geo-1");
-      ServerInZone withHost = new ServerInZone(new ParseServerTest().expected(), "az-1.region-a.geo-1");
-
-      ServerInZoneToNodeMetadata converter = new ServerInZoneToNodeMetadata(
-               NovaComputeServiceContextModule.toPortableNodeStatus, locationIndex, Suppliers
-                        .<Set<? extends Image>> ofInstance(ImmutableSet.<Image> of()), Suppliers
-                        .<Set<? extends Hardware>> ofInstance(ImmutableSet.<Hardware> of()), namingConvention);
-
-      Set<? extends NodeMetadata> set = ImmutableSet.of(converter.apply(withHost), converter.apply(withoutHost));
-
-      assertEquals(new OrphanedGroupsByZoneId(Predicates.<ZoneAndName> alwaysFalse()).apply(set), ImmutableMultimap
-               .<String, String> of());
-
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/744cd5d7/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInRegionToNodeMetadataTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInRegionToNodeMetadataTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInRegionToNodeMetadataTest.java
new file mode 100644
index 0000000..e602f54
--- /dev/null
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/ServerInRegionToNodeMetadataTest.java
@@ -0,0 +1,341 @@
+/*
+ * 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 org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.Set;
+
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.HardwareBuilder;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.ImageBuilder;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.OperatingSystem;
+import org.jclouds.compute.domain.OsFamily;
+import org.jclouds.compute.functions.GroupNamingConvention;
+import org.jclouds.date.internal.SimpleDateFormatDateService;
+import org.jclouds.domain.Location;
+import org.jclouds.domain.LocationBuilder;
+import org.jclouds.domain.LocationScope;
+import org.jclouds.openstack.nova.v2_0.compute.config.NovaComputeServiceContextModule;
+import org.jclouds.openstack.nova.v2_0.domain.Server;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.ServerInRegion;
+import org.jclouds.openstack.nova.v2_0.parse.ParseServerTest;
+import org.jclouds.openstack.nova.v2_0.parse.ParseServerWithoutImageTest;
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.openstack.v2_0.domain.Resource;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Guice;
+
+/**
+ * Tests for the function for transforming a nova specific Server into a generic
+ * NodeMetadata object.
+ */
+@Test(testName = "ServerInRegionToNodeMetadataTest")
+public class ServerInRegionToNodeMetadataTest {
+
+   Location provider = new LocationBuilder().scope(LocationScope.PROVIDER).id("openstack-nova")
+         .description("openstack-nova").build();
+   Location region = new LocationBuilder().id("az-1.region-a.geo-1").description("az-1.region-a.geo-1")
+         .scope(LocationScope.REGION).parent(provider).build();
+   Supplier<Map<String, Location>> locationIndex = Suppliers.<Map<String, Location>> ofInstance(ImmutableMap
+         .<String, Location> of("az-1.region-a.geo-1", region));
+
+   GroupNamingConvention.Factory namingConvention = Guice.createInjector().getInstance(GroupNamingConvention.Factory.class);
+
+   @Test
+   public void testWhenNoHardwareOrImageMatchServerScopedIdsImageIdIsStillSet() {
+
+      Hardware existingHardware = new HardwareBuilder().id("az-1.region-a.geo-1/FOOOOOOOO").providerId("FOOOOOOOO")
+            .location(region).build();
+      Image existingImage = new ImageBuilder().id("az-1.region-a.geo-1/FOOOOOOOO")
+            .operatingSystem(OperatingSystem.builder().family(OsFamily.LINUX).description("foobuntu").build())
+            .providerId("FOOOOOOOO").description("foobuntu").location(region).status(Image.Status.AVAILABLE).build();
+
+      checkHardwareAndImageStatus(null, existingHardware, "az-1.region-a.geo-1/52415800-8b69-11e0-9b19-734f6f006e54",
+            null, existingImage);
+   }
+
+   @Test
+   public void testWhenNoHardwareAndImageMatchServerScopedIdsHardwareOperatingSystemAndImageIdAreSet() {
+
+      Hardware existingHardware = new HardwareBuilder().id("az-1.region-a.geo-1/52415800-8b69-11e0-9b19-734f216543fd")
+            .providerId("52415800-8b69-11e0-9b19-734f216543fd").location(region).build();
+      Image existingImage = new ImageBuilder().id("az-1.region-a.geo-1/52415800-8b69-11e0-9b19-734f6f006e54")
+            .operatingSystem(OperatingSystem.builder().family(OsFamily.LINUX).description("foobuntu").build())
+            .providerId("52415800-8b69-11e0-9b19-734f6f006e54").description("foobuntu").status(Image.Status.AVAILABLE)
+            .location(region).build();
+
+      checkHardwareAndImageStatus(existingHardware, existingHardware, existingImage.getId(),
+            existingImage.getOperatingSystem(), existingImage);
+   }
+
+   @Test
+   public void testNullAccessIPs() {
+      Hardware existingHardware = new HardwareBuilder().id("az-1.region-a.geo-1/52415800-8b69-11e0-9b19-734f216543fd")
+            .providerId("52415800-8b69-11e0-9b19-734f216543fd").location(region).build();
+      Image existingImage = new ImageBuilder().id("az-1.region-a.geo-1/52415800-8b69-11e0-9b19-734f6f006e54")
+            .operatingSystem(OperatingSystem.builder().family(OsFamily.LINUX).description("foobuntu").build())
+            .providerId("52415800-8b69-11e0-9b19-734f6f006e54").description("foobuntu").status(Image.Status.AVAILABLE)
+            .location(region).build();
+
+      Set<Image> images = existingImage == null ? ImmutableSet.<Image> of() : ImmutableSet.of(existingImage);
+      Set<Hardware> hardwares = existingHardware == null ? ImmutableSet.<Hardware> of() : ImmutableSet
+            .of(existingHardware);
+      Server serverToConvert = new ParseServerTest().expected().toBuilder()
+            .accessIPv4(null)
+            .accessIPv6(null)
+            .build();
+
+      ServerInRegion serverInRegionToConvert = new ServerInRegion(serverToConvert, "az-1.region-a.geo-1");
+
+      ServerInRegionToNodeMetadata converter = new ServerInRegionToNodeMetadata(
+            NovaComputeServiceContextModule.toPortableNodeStatus, locationIndex, Suppliers
+            .<Set<? extends Image>> ofInstance(images), Suppliers
+            .<Set<? extends Hardware>> ofInstance(hardwares), namingConvention);
+
+      NodeMetadata convertedNodeMetadata = converter.apply(serverInRegionToConvert);
+
+      assertNotNull(convertedNodeMetadata.getPrivateAddresses());
+      assertEquals(convertedNodeMetadata.getPrivateAddresses(), ImmutableSet.of("10.176.42.16"));
+
+      assertNotNull(convertedNodeMetadata.getPublicAddresses());
+      // note jclouds doesn't yet support ipv6 b/c not tested yet
+      assertEquals(convertedNodeMetadata.getPublicAddresses(), ImmutableSet.of("67.23.10.132", "67.23.10.131"));
+   }
+
+   @Test
+   public void testDuplicateAccessIPs() {
+      Hardware existingHardware = new HardwareBuilder().id("az-1.region-a.geo-1/52415800-8b69-11e0-9b19-734f216543fd")
+            .providerId("52415800-8b69-11e0-9b19-734f216543fd").location(region).build();
+      Image existingImage = new ImageBuilder().id("az-1.region-a.geo-1/52415800-8b69-11e0-9b19-734f6f006e54")
+            .operatingSystem(OperatingSystem.builder().family(OsFamily.LINUX).description("foobuntu").build())
+            .providerId("52415800-8b69-11e0-9b19-734f6f006e54").description("foobuntu").status(Image.Status.AVAILABLE)
+            .location(region).build();
+
+      Set<Image> images = existingImage == null ? ImmutableSet.<Image> of() : ImmutableSet.of(existingImage);
+      Set<Hardware> hardwares = existingHardware == null ? ImmutableSet.<Hardware> of() : ImmutableSet
+            .of(existingHardware);
+      Server serverToConvert = new ParseServerTest().expected().toBuilder()
+            .accessIPv4("67.23.10.132")
+            .accessIPv6("::babe:67.23.10.132")
+            .build();
+
+      ServerInRegion serverInRegionToConvert = new ServerInRegion(serverToConvert, "az-1.region-a.geo-1");
+
+      ServerInRegionToNodeMetadata converter = new ServerInRegionToNodeMetadata(
+            NovaComputeServiceContextModule.toPortableNodeStatus, locationIndex, Suppliers
+            .<Set<? extends Image>> ofInstance(images), Suppliers
+            .<Set<? extends Hardware>> ofInstance(hardwares), namingConvention);
+
+      NodeMetadata convertedNodeMetadata = converter.apply(serverInRegionToConvert);
+
+      assertNotNull(convertedNodeMetadata.getPrivateAddresses());
+      assertEquals(convertedNodeMetadata.getPrivateAddresses(), ImmutableSet.of("10.176.42.16"));
+
+      assertNotNull(convertedNodeMetadata.getPublicAddresses());
+      // note jclouds doesn't yet support ipv6 b/c not tested yet
+      assertEquals(convertedNodeMetadata.getPublicAddresses(), ImmutableSet.of("67.23.10.132", "67.23.10.131"));
+   }
+
+   @Test
+   public void testAlternateAccessIPs() {
+      Hardware existingHardware = new HardwareBuilder().id("az-1.region-a.geo-1/52415800-8b69-11e0-9b19-734f216543fd")
+            .providerId("52415800-8b69-11e0-9b19-734f216543fd").location(region).build();
+      Image existingImage = new ImageBuilder().id("az-1.region-a.geo-1/52415800-8b69-11e0-9b19-734f6f006e54")
+            .operatingSystem(OperatingSystem.builder().family(OsFamily.LINUX).description("foobuntu").build())
+            .providerId("52415800-8b69-11e0-9b19-734f6f006e54").description("foobuntu").status(Image.Status.AVAILABLE)
+            .location(region).build();
+
+      Set<Image> images = existingImage == null ? ImmutableSet.<Image> of() : ImmutableSet.of(existingImage);
+      Set<Hardware> hardwares = existingHardware == null ? ImmutableSet.<Hardware> of() : ImmutableSet
+            .of(existingHardware);
+      Server serverToConvert = new ParseServerTest().expected().toBuilder()
+            .accessIPv4("76.32.1.231")
+            .accessIPv6("::babe:76.32.1.231")
+            .build();
+
+      ServerInRegion serverInRegionToConvert = new ServerInRegion(serverToConvert, "az-1.region-a.geo-1");
+
+      ServerInRegionToNodeMetadata converter = new ServerInRegionToNodeMetadata(
+            NovaComputeServiceContextModule.toPortableNodeStatus, locationIndex, Suppliers
+            .<Set<? extends Image>> ofInstance(images), Suppliers
+            .<Set<? extends Hardware>> ofInstance(hardwares), namingConvention);
+
+      NodeMetadata convertedNodeMetadata = converter.apply(serverInRegionToConvert);
+
+      assertNotNull(convertedNodeMetadata.getPrivateAddresses());
+      assertEquals(convertedNodeMetadata.getPrivateAddresses(), ImmutableSet.of("10.176.42.16"));
+
+      assertNotNull(convertedNodeMetadata.getPublicAddresses());
+      // note jclouds doesn't yet support ipv6 b/c not tested yet
+      assertEquals(convertedNodeMetadata.getPublicAddresses(), ImmutableSet.of("67.23.10.132", "67.23.10.131", "76.32.1.231"));
+   }
+
+   @Test
+   public void testPortableNodeStatusNotNull() {
+      for (Server.Status serverStatus : Server.Status.values()) {
+         assertNotNull(NovaComputeServiceContextModule.toPortableNodeStatus.get(serverStatus));
+      }
+   }
+
+   @Test
+   public void testServerWithoutImage() {
+      Hardware existingHardware = new HardwareBuilder().id("az-1.region-a.geo-1/52415800-8b69-11e0-9b19-734f216543fd")
+            .providerId("52415800-8b69-11e0-9b19-734f216543fd").location(region).build();
+      Image existingImage = new ImageBuilder().id("az-1.region-a.geo-1/52415800-8b69-11e0-9b19-734f6f006e54")
+            .operatingSystem(OperatingSystem.builder().family(OsFamily.LINUX).description("foobuntu").build())
+            .providerId("52415800-8b69-11e0-9b19-734f6f006e54").description("foobuntu").status(Image.Status.AVAILABLE)
+            .location(region).build();
+
+      Server serverToConvert = new ParseServerWithoutImageTest().expected();
+      ServerInRegion serverInRegionToConvert = new ServerInRegion(serverToConvert, "az-1.region-a.geo-1");
+
+      ServerInRegionToNodeMetadata converter = new ServerInRegionToNodeMetadata(
+            NovaComputeServiceContextModule.toPortableNodeStatus, locationIndex,
+            Suppliers.<Set<? extends Image>> ofInstance(ImmutableSet.of(existingImage)),
+            Suppliers.<Set<? extends Hardware>> ofInstance(ImmutableSet.of(existingHardware)),
+            namingConvention);
+
+      NodeMetadata convertedNodeMetadata = converter.apply(serverInRegionToConvert);
+
+      assertNull(convertedNodeMetadata.getImageId());
+   }
+
+   // TODO: clean up this syntax
+   private void checkHardwareAndImageStatus(Hardware expectedHardware, Hardware existingHardware,
+         String expectedImageId, OperatingSystem expectedOs, Image existingImage) {
+
+      Set<Image> images = existingImage == null ? ImmutableSet.<Image> of() : ImmutableSet.of(existingImage);
+      Set<Hardware> hardwares = existingHardware == null ? ImmutableSet.<Hardware> of() : ImmutableSet
+            .of(existingHardware);
+      Server serverToConvert = new ParseServerTest().expected();
+
+      ServerInRegion serverInRegionToConvert = new ServerInRegion(serverToConvert, "az-1.region-a.geo-1");
+
+      ServerInRegionToNodeMetadata converter = new ServerInRegionToNodeMetadata(
+               NovaComputeServiceContextModule.toPortableNodeStatus, locationIndex, Suppliers
+                        .<Set<? extends Image>> ofInstance(images), Suppliers
+                        .<Set<? extends Hardware>> ofInstance(hardwares), namingConvention);
+
+      NodeMetadata convertedNodeMetadata = converter.apply(serverInRegionToConvert);
+
+      assertEquals(serverInRegionToConvert.slashEncode(), convertedNodeMetadata.getId());
+      assertEquals(serverToConvert.getId(), convertedNodeMetadata.getProviderId());
+
+      assertEquals(convertedNodeMetadata.getLocation().getScope(), LocationScope.HOST);
+      assertEquals(convertedNodeMetadata.getLocation().getId(), "e4d909c290d0fb1ca068ffaddf22cbd0");
+
+      assertEquals(convertedNodeMetadata.getLocation().getParent(), locationIndex.get().get("az-1.region-a.geo-1"));
+
+      assertEquals(serverToConvert.getName(), convertedNodeMetadata.getName());
+      assertEquals(convertedNodeMetadata.getGroup(), "sample");
+
+      assertEquals(convertedNodeMetadata.getImageId(), expectedImageId);
+      assertEquals(convertedNodeMetadata.getOperatingSystem(), expectedOs);
+
+      assertEquals(convertedNodeMetadata.getHardware(), expectedHardware);
+
+      assertEquals(NovaComputeServiceContextModule.toPortableNodeStatus.get(serverToConvert.getStatus()),
+               convertedNodeMetadata.getStatus());
+
+      assertNotNull(convertedNodeMetadata.getPrivateAddresses());
+      assertEquals(convertedNodeMetadata.getPrivateAddresses(), ImmutableSet.of("10.176.42.16"));
+
+      assertNotNull(convertedNodeMetadata.getPublicAddresses());
+      // note jclouds doesn't yet support ipv6 b/c not tested yet
+      assertEquals(convertedNodeMetadata.getPublicAddresses(), ImmutableSet.of("67.23.10.132", "67.23.10.131"));
+
+      assertNotNull(convertedNodeMetadata.getUserMetadata());
+      assertEquals(convertedNodeMetadata.getUserMetadata(),
+            ImmutableMap.<String, String> of("Server Label", "Web Head 1", "Image Version", "2.1"));
+
+      URI expectedURI = URI.create("http://servers.api.openstack.org/v2/1234/servers/71752");
+      assertEquals(convertedNodeMetadata.getUri(), expectedURI);
+   }
+
+   @Test
+   public void testNewServerWithoutHostIdSetsRegionAsLocation() {
+
+      Set<Image> images = ImmutableSet.<Image> of();
+      Set<Hardware> hardwares = ImmutableSet.<Hardware> of();
+
+      Server serverToConvert = expectedServer();
+
+      ServerInRegion serverInRegionToConvert = new ServerInRegion(serverToConvert, "az-1.region-a.geo-1");
+
+      ServerInRegionToNodeMetadata converter = new ServerInRegionToNodeMetadata(
+               NovaComputeServiceContextModule.toPortableNodeStatus, locationIndex, Suppliers
+                        .<Set<? extends Image>> ofInstance(images), Suppliers
+                        .<Set<? extends Hardware>> ofInstance(hardwares), namingConvention);
+
+      NodeMetadata convertedNodeMetadata = converter.apply(serverInRegionToConvert);
+
+      assertEquals(serverInRegionToConvert.slashEncode(), convertedNodeMetadata.getId());
+      assertEquals(serverToConvert.getId(), convertedNodeMetadata.getProviderId());
+
+      assertEquals(convertedNodeMetadata.getLocation(), region);
+
+      URI expectedURI = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/37936628937291/servers/71752");
+      assertEquals(convertedNodeMetadata.getUri(), expectedURI);
+   }
+
+   public Server expectedServer() {
+      return Server
+            .builder()
+            .id("71752")
+            .uuid("47491020-6a78-4f63-9475-23195ac4515c")
+            .tenantId("37936628937291")
+            .userId("54297837463082")
+            .name("test-e92")
+            .updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-03-19T06:21:13Z"))
+            .created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-03-19T06:21:13Z"))
+            .status(Server.Status.BUILD)
+            .image(
+                  Resource
+                        .builder()
+                        .id("1241")
+                        .links(
+                              Link.create(
+                                    Link.Relation.BOOKMARK,
+                                    URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/images/1241")))
+                        .build())
+            .flavor(
+                  Resource
+                        .builder()
+                        .id("100")
+                        .links(
+                              Link.create(
+                                    Link.Relation.BOOKMARK,
+                                    URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/flavors/100")))
+                        .build())
+            .links(
+                  Link.create(Link.Relation.SELF, URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/37936628937291/servers/71752")),
+                  Link.create(Link.Relation.BOOKMARK, URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/servers/71752"))).build();
+
+   }
+}