You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2016/02/01 18:47:05 UTC

[47/50] brooklyn-library git commit: geo-dns: update member list of entity.hostname changes

geo-dns: update member list of entity.hostname changes

- Useful for some private subnet examples, where the hostname/url
  gets transformed.
- Transforms tests from groovy to Java.


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-library/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-library/commit/8d1b5d2b
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-library/tree/8d1b5d2b
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-library/diff/8d1b5d2b

Branch: refs/heads/0.5.0
Commit: 8d1b5d2b8e40a882f9f396ae9f4673ee1a30150b
Parents: 387cc27
Author: Aled Sage <al...@gmail.com>
Authored: Wed Apr 17 14:38:04 2013 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Thu Apr 25 11:18:21 2013 +0100

----------------------------------------------------------------------
 .../entity/dns/AbstractGeoDnsServiceImpl.java   |  78 +++++----
 .../entity/dns/AbstractGeoDnsServiceTest.groovy | 152 -----------------
 .../entity/dns/AbstractGeoDnsServiceTest.java   | 166 +++++++++++++++++++
 .../geoscaling/GeoscalingIntegrationTest.groovy |  67 --------
 .../geoscaling/GeoscalingIntegrationTest.java   |  86 ++++++++++
 5 files changed, 301 insertions(+), 248 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/8d1b5d2b/software/webapp/src/main/java/brooklyn/entity/dns/AbstractGeoDnsServiceImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/dns/AbstractGeoDnsServiceImpl.java b/software/webapp/src/main/java/brooklyn/entity/dns/AbstractGeoDnsServiceImpl.java
index 55be2c0..959c277 100644
--- a/software/webapp/src/main/java/brooklyn/entity/dns/AbstractGeoDnsServiceImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/dns/AbstractGeoDnsServiceImpl.java
@@ -3,6 +3,7 @@ package brooklyn.entity.dns;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.net.InetAddress;
+import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.Collection;
 import java.util.Collections;
@@ -154,8 +155,8 @@ public abstract class AbstractGeoDnsServiceImpl extends AbstractEntity implement
             boolean changed = false;
             Set<Entity> previousOnes = MutableSet.copyOf(targetHosts.keySet());
             for (Entity e: pool) {
-                if (previousOnes.remove(e)) continue;
-                changed |= addTargetHost(e, false);
+                previousOnes.remove(e);
+                changed |= addTargetHost(e);
             }
             //anything left in previousOnes is no longer applicable
             for (Entity e: previousOnes) {
@@ -171,44 +172,39 @@ public abstract class AbstractGeoDnsServiceImpl extends AbstractEntity implement
         }
     }
     
-    /** returns if host is added */
-    protected boolean addTargetHost(Entity e, boolean doUpdate) {
-        if (targetHosts.containsKey(e)) {
-            log.warn("GeoDns ignoring already-added entity {}", e);
-            return false;
-        }
-        //add it if it is valid
+    /**
+     * Adds this host, if it is absent or if its hostname has changed.
+     *  
+     * @return true if host is added or changed
+     */
+    protected boolean addTargetHost(Entity e) {
         try {
-            String hostname = e.getAttribute(Attributes.HOSTNAME);
-            String url = e.getAttribute(WebAppService.ROOT_URL);
-            if (url!=null) {
-                URL u = new URL(url);
-                if (hostname==null) {
-                    if (!entitiesWithoutGeoInfo.contains(e))  //don't log repeatedly
-                        log.warn("GeoDns using URL {} to redirect to {} (HOSTNAME attribute is preferred, but not available)", url, e);
-                    hostname = u.getHost(); 
-                }
-                if (u.getPort() > 0 && u.getPort() != 80 && u.getPort() != 443) {
-                    if (!entitiesWithoutGeoInfo.contains(e))  //don't log repeatedly
-                        log.warn("GeoDns detected non-standard port in URL {} for {}; forwarding may not work", url, e);
-                }
-            }
-            if (hostname==null) {
+            HostGeoInfo oldGeo = targetHosts.get(e);
+            String hostname = inferHostname(e);
+            HostGeoInfo geoH = (hostname == null) ? null : HostGeoInfo.fromIpAddress(InetAddress.getByName(hostname));
+
+            if (hostname == null) {
                 if (entitiesWithoutGeoInfo.add(e)) {
                     log.debug("GeoDns ignoring {}, will continue scanning (no hostname or URL available)", e);
                 }
                 return false;
             }
-            HostGeoInfo geoH = HostGeoInfo.fromIpAddress(InetAddress.getByName(hostname));
+            
             if (geoH == null) {
                 if (entitiesWithoutGeoInfo.add(e)) {
                     log.warn("GeoDns ignoring {} (no geography info available for {})", e, hostname);
                 }
                 return false;
             }
+            
+            // If we already knew about it, and it hasn't changed, then nothing to do
+            if (oldGeo != null && geoH.getAddress().equals(oldGeo.getAddress())) {
+                return false;
+            }
+            
+            // Check if location has lat/lon explicitly set; use geo-dns but warn if dramatically different
             HostGeoInfo geoE = HostGeoInfo.fromEntity(e);
-            if (geoE!=null) {
-                //geo info set for both; prefer H, but warn if they differ dramatially
+            if (geoE != null) {
                 if ((Math.abs(geoH.latitude-geoE.latitude)>3) ||
                         (Math.abs(geoH.longitude-geoE.longitude)>3) ) {
                     log.warn("GeoDns mismatch, {} is in {} but hosts URL in {}", new Object[] {e, geoE, geoH});
@@ -216,10 +212,10 @@ public abstract class AbstractGeoDnsServiceImpl extends AbstractEntity implement
             }
             
             entitiesWithoutGeoInfo.remove(e);
-            log.info("GeoDns adding "+e+" at "+geoH+(url!=null ? " (downstream listening on "+url+")" : ""));
+            log.info("GeoDns adding "+e+" at "+geoH+(oldGeo != null ? " (previously "+oldGeo+")" : ""));
             targetHosts.put(e, geoH);
-            if (doUpdate) update();
             return true;
+
         } catch (Exception ee) {
             log.warn("GeoDns ignoring {} (error analysing location, {}", e, ee);
             return false;
@@ -250,4 +246,28 @@ public abstract class AbstractGeoDnsServiceImpl extends AbstractEntity implement
         setAttribute(TARGETS, entityIdToUrl);
     }
     
+    protected String inferHostname(Entity entity) {
+        String hostname = entity.getAttribute(Attributes.HOSTNAME);
+        String url = entity.getAttribute(WebAppService.ROOT_URL);
+        if (url!=null) {
+            try {
+                URL u = new URL(url);
+                
+                if (hostname==null) {
+                    if (!entitiesWithoutGeoInfo.contains(entity))  //don't log repeatedly
+                        log.warn("GeoDns using URL {} to redirect to {} (HOSTNAME attribute is preferred, but not available)", url, entity);
+                    hostname = u.getHost(); 
+                }
+                
+                if (u.getPort() > 0 && u.getPort() != 80 && u.getPort() != 443) {
+                    if (!entitiesWithoutGeoInfo.contains(entity))  //don't log repeatedly
+                        log.warn("GeoDns detected non-standard port in URL {} for {}; forwarding may not work", url, entity);
+                }
+                
+            } catch (MalformedURLException e) {
+                LOG.warn("Invalid URL {} for entity {} in {}", new Object[] {url, entity, this});
+            }
+        }
+        return hostname;
+    }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/8d1b5d2b/software/webapp/src/test/java/brooklyn/entity/dns/AbstractGeoDnsServiceTest.groovy
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/brooklyn/entity/dns/AbstractGeoDnsServiceTest.groovy b/software/webapp/src/test/java/brooklyn/entity/dns/AbstractGeoDnsServiceTest.groovy
deleted file mode 100644
index bba6b3b..0000000
--- a/software/webapp/src/test/java/brooklyn/entity/dns/AbstractGeoDnsServiceTest.groovy
+++ /dev/null
@@ -1,152 +0,0 @@
-package brooklyn.entity.dns;
-
-import static java.util.concurrent.TimeUnit.*
-import static org.testng.Assert.*
-
-import java.util.concurrent.TimeUnit
-
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.testng.annotations.AfterMethod
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.Test
-
-import brooklyn.entity.Entity
-import brooklyn.entity.basic.ApplicationBuilder
-import brooklyn.entity.basic.DynamicGroup
-import brooklyn.entity.basic.Entities
-import brooklyn.entity.group.DynamicFabric
-import brooklyn.entity.proxying.EntitySpecs
-import brooklyn.location.Location
-import brooklyn.location.basic.SimulatedLocation
-import brooklyn.location.basic.SshMachineLocation
-import brooklyn.location.geo.HostGeoInfo
-import brooklyn.test.entity.TestApplication
-import brooklyn.test.entity.TestEntity
-import brooklyn.test.entity.TestEntityImpl
-import brooklyn.util.internal.Repeater
-import brooklyn.util.internal.TimeExtras
-
-import com.google.common.base.Predicates
-import com.google.common.collect.Iterables
-
-public class AbstractGeoDnsServiceTest {
-    public static final Logger log = LoggerFactory.getLogger(AbstractGeoDnsServiceTest.class);
-    static { TimeExtras.init() }
-
-    private static final String WEST_IP = "208.95.232.123";
-    private static final String EAST_IP = "216.150.144.82";
-    private static final double WEST_LATITUDE = 37.43472, WEST_LONGITUDE = -121.89500;
-    private static final double EAST_LATITUDE = 41.10361, EAST_LONGITUDE = -73.79583;
-    
-    private static final Location WEST_PARENT = new SimulatedLocation(
-        name: "West parent", latitude: WEST_LATITUDE, longitude: WEST_LONGITUDE);
-    private static final Location WEST_CHILD = new SshMachineLocation(
-        name: "West child", address: WEST_IP, parentLocation: WEST_PARENT); 
-    private static final Location WEST_CHILD_WITH_LOCATION = new SshMachineLocation(
-        name: "West child with location", address: WEST_IP, parentLocation: WEST_PARENT,
-        latitude: WEST_LATITUDE, longitude: WEST_LONGITUDE); 
-    
-    private static final Location EAST_PARENT = new SimulatedLocation(
-        name: "East parent", latitude: EAST_LATITUDE, longitude: EAST_LONGITUDE);
-    private static final Location EAST_CHILD = new SshMachineLocation(
-        name: "East child", address: EAST_IP, parentLocation: EAST_PARENT); 
-    private static final Location EAST_CHILD_WITH_LOCATION = new SshMachineLocation(
-        name: "East child with location", address: EAST_IP, parentLocation: EAST_PARENT,
-        latitude: EAST_LATITUDE, longitude: EAST_LONGITUDE); 
-    
-    private TestApplication app;
-    private DynamicFabric fabric;
-    private DynamicGroup testEntities;
-    private GeoDnsTestService geoDns;
-    
-
-    @BeforeMethod(alwaysRun=true)
-    public void setup() {
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
-        fabric = app.createAndManageChild(EntitySpecs.spec(DynamicFabric.class)
-            .configure("factory", { properties -> new TestEntityImpl(properties) }));
-        
-        testEntities = app.createAndManageChild(EntitySpecs.spec(DynamicGroup.class)
-            .configure(DynamicGroup.ENTITY_FILTER, Predicates.instanceOf(TestEntity.class)));
-        geoDns = new GeoDnsTestService(app, polPeriod:10);
-        geoDns.setTargetEntityProvider(testEntities);
-        Entities.startManagement(geoDns);
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void shutdown() {
-        if (app != null) Entities.destroy(app);
-    }
-
-    
-    @Test
-    public void testGeoInfoOnLocation() {
-        app.start( [ WEST_CHILD_WITH_LOCATION, EAST_CHILD_WITH_LOCATION ] );
-        
-        waitForTargetHosts(geoDns);
-        assertTrue(geoDns.targetHostsByName.containsKey("West child with location"), "targets="+geoDns.targetHostsByName);
-        assertTrue(geoDns.targetHostsByName.containsKey("East child with location"), "targets="+geoDns.targetHostsByName);
-    }
-    
-    @Test
-    public void testGeoInfoOnParentLocation() {
-        app.start( [ WEST_CHILD, EAST_CHILD ] );
-        
-        waitForTargetHosts(geoDns);
-        assertTrue(geoDns.targetHostsByName.containsKey("West child"), "targets="+geoDns.targetHostsByName);
-        assertTrue(geoDns.targetHostsByName.containsKey("East child"), "targets="+geoDns.targetHostsByName);
-    }
-    
-    //TODO
-//    @Test
-//    public void testMissingGeoInfo() {
-//    }
-//    
-//    @Test
-//    public void testEmptyGroup() {
-//    }
-    
-    private static void waitForTargetHosts(GeoDnsTestService service) {
-        new Repeater("Wait for target hosts")
-            .repeat()
-            .every(500 * MILLISECONDS)
-            .until { service.targetHostsByName.size() == 2 }
-            .limitIterationsTo(20)
-            .run();
-    }
-    
-    
-    private static class GeoDnsTestService extends AbstractGeoDnsServiceImpl {
-        public Map<String, HostGeoInfo> targetHostsByName = new LinkedHashMap<String, HostGeoInfo>();
-        
-        public GeoDnsTestService(properties=[:], Entity parent) {
-            super(properties, parent);
-        }
-        
-        protected boolean addTargetHost(Entity e, boolean doUpdate) {
-            //ignore geo lookup, override parent menu
-            log.info("TestService adding target host $e");
-            Location l = Iterables.getOnlyElement(e.locations);
-            HostGeoInfo geoInfo = new HostGeoInfo("127.0.0.1", l.name, 
-                l.findLocationProperty("latitude"), l.findLocationProperty("longitude"));
-            targetHosts.put(e, geoInfo);
-            if (doUpdate) update();
-            return true;
-        }
-        
-        @Override
-        protected void reconfigureService(Collection<HostGeoInfo> targetHosts) {
-            targetHostsByName.clear();
-            for (HostGeoInfo host : targetHosts) {
-                if (host != null) targetHostsByName.put(host.displayName, host);
-            }
-        }
-
-        @Override
-        public String getHostname() {
-            return "localhost";
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/8d1b5d2b/software/webapp/src/test/java/brooklyn/entity/dns/AbstractGeoDnsServiceTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/brooklyn/entity/dns/AbstractGeoDnsServiceTest.java b/software/webapp/src/test/java/brooklyn/entity/dns/AbstractGeoDnsServiceTest.java
new file mode 100644
index 0000000..b365a6a
--- /dev/null
+++ b/software/webapp/src/test/java/brooklyn/entity/dns/AbstractGeoDnsServiceTest.java
@@ -0,0 +1,166 @@
+package brooklyn.entity.dns;
+
+import static org.testng.Assert.assertTrue;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.ApplicationBuilder;
+import brooklyn.entity.basic.DynamicGroup;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.group.DynamicFabric;
+import brooklyn.entity.proxying.EntitySpecs;
+import brooklyn.location.Location;
+import brooklyn.location.basic.SimulatedLocation;
+import brooklyn.location.basic.SshMachineLocation;
+import brooklyn.location.geo.HostGeoInfo;
+import brooklyn.test.entity.TestApplication;
+import brooklyn.test.entity.TestEntity;
+import brooklyn.util.MutableMap;
+import brooklyn.util.internal.Repeater;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+public class AbstractGeoDnsServiceTest {
+    public static final Logger log = LoggerFactory.getLogger(AbstractGeoDnsServiceTest.class);
+
+    private static final String WEST_IP = "208.95.232.123";
+    private static final String EAST_IP = "216.150.144.82";
+    private static final double WEST_LATITUDE = 37.43472, WEST_LONGITUDE = -121.89500;
+    private static final double EAST_LATITUDE = 41.10361, EAST_LONGITUDE = -73.79583;
+    
+    private static SimulatedLocation newSimulatedLocation(String name, double lat, double lon) {
+        return new SimulatedLocation(MutableMap.of("name", name, "latitude", lat, "longitude", lon));
+    }
+    
+    private static Location newSshMachineLocation(String name, String address, Location parent) {
+        return new SshMachineLocation(MutableMap.of("name", name, "address", address, "parentLocation", parent)); 
+    }
+    
+    private static Location newSshMachineLocation(String name, String address, Location parent, double lat, double lon) {
+        return new SshMachineLocation(MutableMap.of("name", name, "address", address, "parentLocation", parent, "latitude", lat, "longitude", lon)); 
+    }
+    
+    private static final Location WEST_PARENT = newSimulatedLocation("West parent", WEST_LATITUDE, WEST_LONGITUDE);
+    
+    private static final Location WEST_CHILD = newSshMachineLocation("West child", WEST_IP, WEST_PARENT);
+    private static final Location WEST_CHILD_WITH_LOCATION = newSshMachineLocation("West child with location", WEST_IP, WEST_PARENT, WEST_LATITUDE, WEST_LONGITUDE); 
+    
+    private static final Location EAST_PARENT = newSimulatedLocation("East parent", EAST_LATITUDE, EAST_LONGITUDE);
+    private static final Location EAST_CHILD = newSshMachineLocation("East child", EAST_IP, EAST_PARENT); 
+    private static final Location EAST_CHILD_WITH_LOCATION = newSshMachineLocation("East child with location", EAST_IP, EAST_PARENT, EAST_LATITUDE, EAST_LONGITUDE); 
+    
+    private TestApplication app;
+    private DynamicFabric fabric;
+    private DynamicGroup testEntities;
+    private GeoDnsTestService geoDns;
+    
+
+    @BeforeMethod(alwaysRun=true)
+    public void setup() {
+        app = ApplicationBuilder.newManagedApp(TestApplication.class);
+        fabric = app.createAndManageChild(EntitySpecs.spec(DynamicFabric.class)
+            .configure(DynamicFabric.MEMBER_SPEC, EntitySpecs.spec(TestEntity.class)));
+        
+        testEntities = app.createAndManageChild(EntitySpecs.spec(DynamicGroup.class)
+            .configure(DynamicGroup.ENTITY_FILTER, Predicates.instanceOf(TestEntity.class)));
+        geoDns = new GeoDnsTestService(MutableMap.of("pollPeriod", 10), app);
+        geoDns.setTargetEntityProvider(testEntities);
+        Entities.startManagement(geoDns);
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void shutdown() {
+        if (app != null) Entities.destroy(app);
+    }
+
+    
+    @Test
+    public void testGeoInfoOnLocation() {
+        app.start( ImmutableList.of(WEST_CHILD_WITH_LOCATION, EAST_CHILD_WITH_LOCATION) );
+        
+        waitForTargetHosts(geoDns);
+        assertTrue(geoDns.targetHostsByName.containsKey("West child with location"), "targets="+geoDns.targetHostsByName);
+        assertTrue(geoDns.targetHostsByName.containsKey("East child with location"), "targets="+geoDns.targetHostsByName);
+    }
+    
+    @Test
+    public void testGeoInfoOnParentLocation() {
+        app.start( ImmutableList.of(WEST_CHILD, EAST_CHILD) );
+        
+        waitForTargetHosts(geoDns);
+        assertTrue(geoDns.targetHostsByName.containsKey("West child"), "targets="+geoDns.targetHostsByName);
+        assertTrue(geoDns.targetHostsByName.containsKey("East child"), "targets="+geoDns.targetHostsByName);
+    }
+    
+    //TODO
+//    @Test
+//    public void testMissingGeoInfo() {
+//    }
+//    
+//    @Test
+//    public void testEmptyGroup() {
+//    }
+    
+    private static void waitForTargetHosts(final GeoDnsTestService service) {
+        new Repeater("Wait for target hosts")
+            .repeat()
+            .every(500, TimeUnit.MILLISECONDS)
+            .until(new Callable<Boolean>() {
+                public Boolean call() {
+                    return service.targetHostsByName.size() == 2;
+                }})
+            .limitIterationsTo(20)
+            .run();
+    }
+    
+    
+    private static class GeoDnsTestService extends AbstractGeoDnsServiceImpl {
+        public Map<String, HostGeoInfo> targetHostsByName = new LinkedHashMap<String, HostGeoInfo>();
+
+        public GeoDnsTestService(Entity parent) {
+            super(MutableMap.of(), parent);
+        }
+
+        public GeoDnsTestService(Map properties, Entity parent) {
+            super(properties, parent);
+        }
+        
+        @Override
+        protected boolean addTargetHost(Entity e) {
+            //ignore geo lookup, override parent menu
+            log.info("TestService adding target host $e");
+            Location l = Iterables.getOnlyElement(e.getLocations());
+            HostGeoInfo geoInfo = new HostGeoInfo("127.0.0.1", l.getName(), 
+                (Double) l.findLocationProperty("latitude"), (Double) l.findLocationProperty("longitude"));
+            targetHosts.put(e, geoInfo);
+            return true;
+        }
+        
+        @Override
+        protected void reconfigureService(Collection<HostGeoInfo> targetHosts) {
+            targetHostsByName.clear();
+            for (HostGeoInfo host : targetHosts) {
+                if (host != null) targetHostsByName.put(host.displayName, host);
+            }
+        }
+
+        @Override
+        public String getHostname() {
+            return "localhost";
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/8d1b5d2b/software/webapp/src/test/java/brooklyn/entity/dns/geoscaling/GeoscalingIntegrationTest.groovy
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/brooklyn/entity/dns/geoscaling/GeoscalingIntegrationTest.groovy b/software/webapp/src/test/java/brooklyn/entity/dns/geoscaling/GeoscalingIntegrationTest.groovy
deleted file mode 100644
index bae975f..0000000
--- a/software/webapp/src/test/java/brooklyn/entity/dns/geoscaling/GeoscalingIntegrationTest.groovy
+++ /dev/null
@@ -1,67 +0,0 @@
-package brooklyn.entity.dns.geoscaling
-
-import static java.util.concurrent.TimeUnit.*
-import static org.testng.Assert.*
-
-import org.testng.annotations.Test
-
-import brooklyn.entity.basic.ApplicationBuilder
-import brooklyn.entity.basic.Attributes
-import brooklyn.entity.basic.DynamicGroup
-import brooklyn.entity.proxying.EntitySpecs
-import brooklyn.location.basic.SshMachineLocation
-import brooklyn.location.geo.HostGeoInfo
-import brooklyn.test.entity.TestApplication
-import brooklyn.test.entity.TestEntity
-import brooklyn.util.internal.Repeater
-import brooklyn.util.internal.TimeExtras
-
-import com.google.common.base.Predicates
-
-/**
- * {@link GeoscalingScriptGenerator} unit tests.
- */
-class GeoscalingIntegrationTest {
-    static { TimeExtras.init() }
-
-    private final static Set<HostGeoInfo> HOSTS = [
-        new HostGeoInfo("1.2.3.100", "Server 1", 40.0, -80.0),
-        new HostGeoInfo("1.2.3.101", "Server 2", 30.0, 20.0)
-    ]
-
-    private final String primaryDomain = "geopaas.org"//"domain"+((int)(Math.random()*10000))+".test.org";
-    private final String subDomain = "subdomain"+((int)(Math.random()*10000));
-    private final InetAddress addr = InetAddress.localHost
-    private final SshMachineLocation loc = new SshMachineLocation(address:addr, name:'Edinburgh', latitude : 55.94944, longitude : -3.16028, iso3166 : ["GB-EDH"])
-    
-    @Test(groups=["Integration"])
-    public void testRoutesToExpectedLocation() {
-        TestApplication app = ApplicationBuilder.newManagedApp(TestApplication.class);
-        TestEntity target = app.createAndManageChild(EntitySpecs.spec(TestEntity.class));
-        target.setAttribute(Attributes.HOSTNAME,addr.getHostName())
-        
-        DynamicGroup group = app.createAndManageChild(EntitySpecs.spec(DynamicGroup.class)
-                .configure(DynamicGroup.ENTITY_FILTER, Predicates.instanceOf(TestEntity.class)));
-        
-        GeoscalingDnsService geoDns = app.createAndManageChild(EntitySpecs.spec(GeoscalingDnsService.class)
-                .displayName("Geo-DNS")
-                .configure("username", "cloudsoft")
-                .configure("password", "cl0uds0ft")
-                .configure("primaryDomainName", primaryDomain)
-                .configure("smartSubdomainName", subDomain)
-                .configure("targetEntityProvider", group));
-        
-        app.start([loc])
-        
-        println("geo-scaling test, using $subDomain.$primaryDomain; expect to be wired to $addr")
-        
-        new Repeater("Wait for target hosts")
-            .repeat()
-            .every(500 * MILLISECONDS)
-            .until { geoDns.getTargetHosts().size() == 1 }
-            .limitIterationsTo(20)
-            .run();
-        
-        assertEquals(geoDns.getTargetHosts().size(), 1);
-    }
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/8d1b5d2b/software/webapp/src/test/java/brooklyn/entity/dns/geoscaling/GeoscalingIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/brooklyn/entity/dns/geoscaling/GeoscalingIntegrationTest.java b/software/webapp/src/test/java/brooklyn/entity/dns/geoscaling/GeoscalingIntegrationTest.java
new file mode 100644
index 0000000..bfae0b5
--- /dev/null
+++ b/software/webapp/src/test/java/brooklyn/entity/dns/geoscaling/GeoscalingIntegrationTest.java
@@ -0,0 +1,86 @@
+package brooklyn.entity.dns.geoscaling;
+
+import static org.testng.Assert.assertEquals;
+
+import java.net.InetAddress;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.ApplicationBuilder;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.DynamicGroup;
+import brooklyn.entity.proxying.EntitySpecs;
+import brooklyn.location.basic.SshMachineLocation;
+import brooklyn.location.geo.HostGeoInfo;
+import brooklyn.test.entity.TestApplication;
+import brooklyn.test.entity.TestEntity;
+import brooklyn.util.MutableMap;
+import brooklyn.util.NetworkUtils;
+import brooklyn.util.internal.Repeater;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * {@link GeoscalingScriptGenerator} unit tests.
+ */
+public class GeoscalingIntegrationTest {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(GeoscalingIntegrationTest.class);
+
+    private final static Set<HostGeoInfo> HOSTS = ImmutableSet.of(
+        new HostGeoInfo("1.2.3.100", "Server 1", 40.0, -80.0),
+        new HostGeoInfo("1.2.3.101", "Server 2", 30.0, 20.0)
+    );
+
+    private final String primaryDomain = "geopaas.org";//"domain"+((int)(Math.random()*10000))+".test.org";
+    private final String subDomain = "subdomain"+((int)(Math.random()*10000));
+    private final InetAddress addr = NetworkUtils.getLocalHost();
+    private final SshMachineLocation loc = new SshMachineLocation(MutableMap.builder()
+            .put("address", addr)
+            .put("name", "Edinburgh")
+            .put("latitude", 55.94944)
+            .put("longitude", -3.16028)
+            .put("iso3166", ImmutableList.of("GB-EDH"))
+            .build());
+    
+    @Test(groups={"Integration"})
+    public void testRoutesToExpectedLocation() {
+        TestApplication app = ApplicationBuilder.newManagedApp(TestApplication.class);
+        TestEntity target = app.createAndManageChild(EntitySpecs.spec(TestEntity.class));
+        target.setAttribute(Attributes.HOSTNAME,addr.getHostName());
+        
+        DynamicGroup group = app.createAndManageChild(EntitySpecs.spec(DynamicGroup.class)
+                .configure(DynamicGroup.ENTITY_FILTER, Predicates.instanceOf(TestEntity.class)));
+        
+        final GeoscalingDnsService geoDns = app.createAndManageChild(EntitySpecs.spec(GeoscalingDnsService.class)
+                .displayName("Geo-DNS")
+                .configure("username", "cloudsoft")
+                .configure("password", "cl0uds0ft")
+                .configure("primaryDomainName", primaryDomain)
+                .configure("smartSubdomainName", subDomain)
+                .configure("targetEntityProvider", group));
+        
+        app.start(ImmutableList.of(loc));
+        
+        LOG.info("geo-scaling test, using {}.{}; expect to be wired to {}", new Object[] {subDomain, primaryDomain, addr});
+        
+        new Repeater("Wait for target hosts")
+            .repeat()
+            .every(500, TimeUnit.MILLISECONDS)
+            .until(new Callable<Boolean>() {
+                public Boolean call() {
+                    return geoDns.getTargetHosts().size() == 1;
+                }})
+            .limitIterationsTo(20)
+            .run();
+        
+        assertEquals(geoDns.getTargetHosts().size(), 1);
+    }
+}