| /* |
| * 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.apache.brooklyn.entity.dns.geoscaling; |
| |
| import static org.testng.Assert.assertEquals; |
| |
| import java.net.InetAddress; |
| |
| import org.apache.brooklyn.api.entity.EntitySpec; |
| import org.apache.brooklyn.api.location.LocationSpec; |
| import org.apache.brooklyn.api.mgmt.ManagementContext; |
| import org.apache.brooklyn.core.entity.Attributes; |
| import org.apache.brooklyn.core.internal.BrooklynProperties; |
| import org.apache.brooklyn.core.location.geo.HostGeoInfo; |
| import org.apache.brooklyn.core.location.geo.HostGeoLookup; |
| import org.apache.brooklyn.core.location.geo.MaxMind2HostGeoLookup; |
| import org.apache.brooklyn.core.location.geo.UtraceHostGeoLookup; |
| import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal; |
| import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport; |
| import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests; |
| import org.apache.brooklyn.core.test.entity.TestEntity; |
| import org.apache.brooklyn.entity.group.DynamicGroup; |
| import org.apache.brooklyn.test.Asserts; |
| import org.apache.brooklyn.util.collections.MutableMap; |
| import org.apache.brooklyn.util.exceptions.Exceptions; |
| import org.apache.brooklyn.util.internal.BrooklynSystemProperties; |
| import org.apache.brooklyn.util.net.Networking; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| import org.testng.SkipException; |
| import org.testng.annotations.AfterMethod; |
| import org.testng.annotations.BeforeMethod; |
| import org.testng.annotations.Test; |
| import org.apache.brooklyn.location.ssh.SshMachineLocation; |
| |
| import com.google.common.base.Predicates; |
| import com.google.common.collect.ImmutableList; |
| |
| /** |
| * {@link GeoscalingScriptGenerator} unit tests. |
| */ |
| public class GeoscalingIntegrationTest extends BrooklynAppUnitTestSupport { |
| |
| private static final Logger LOG = LoggerFactory.getLogger(GeoscalingIntegrationTest.class); |
| |
| 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 addrWithGeo = Networking.getReachableLocalHost(); |
| private final InetAddress addrWithoutGeo = Networking.getInetAddressWithFixedName(StubHostGeoLookup.HOMELESS_IP); |
| |
| private TestEntity target; |
| private DynamicGroup group; |
| private GeoscalingDnsService geoDns; |
| private String origGeoLookupImpl; |
| |
| private SshMachineLocation locWithGeo; |
| private SshMachineLocation locWithoutGeo; |
| |
| @Override |
| @BeforeMethod(alwaysRun=true) |
| public void setUp() throws Exception { |
| // Want to load username and password from user's properties. |
| mgmt = LocalManagementContextForTests.newInstance(BrooklynProperties.Factory.newDefault()); |
| super.setUp(); |
| |
| origGeoLookupImpl = BrooklynSystemProperties.HOST_GEO_LOOKUP_IMPL.getValue(); |
| HostGeoInfo.clearCachedLookup(); |
| |
| target = app.createAndManageChild(EntitySpec.create(TestEntity.class)); |
| group = app.createAndManageChild(EntitySpec.create(DynamicGroup.class) |
| .configure(DynamicGroup.ENTITY_FILTER, Predicates.instanceOf(TestEntity.class))); |
| |
| String username = getBrooklynProperty(mgmt, "brooklyn.geoscaling.username"); |
| String password = getBrooklynProperty(mgmt, "brooklyn.geoscaling.password"); |
| if (username == null || password == null) { |
| throw new SkipException("Set brooklyn.geoscaling.username and brooklyn.geoscaling.password in brooklyn.properties to enable test"); |
| } |
| |
| geoDns = app.createAndManageChild(EntitySpec.create(GeoscalingDnsService.class) |
| .displayName("Geo-DNS") |
| .configure(GeoscalingDnsService.GEOSCALING_USERNAME, username) |
| .configure(GeoscalingDnsService.GEOSCALING_PASSWORD, password) |
| .configure(GeoscalingDnsService.GEOSCALING_PRIMARY_DOMAIN_NAME, primaryDomain) |
| .configure(GeoscalingDnsService.GEOSCALING_SMART_SUBDOMAIN_NAME, subDomain) |
| .configure(GeoscalingDnsService.ENTITY_PROVIDER, group)); |
| |
| locWithGeo = mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class) |
| .configure("address", addrWithGeo) |
| .configure("name", "Edinburgh") |
| .configure("latitude", 55.94944) |
| .configure("longitude", -3.16028) |
| .configure("iso3166", ImmutableList.of("GB-EDH"))); |
| |
| locWithoutGeo = mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class) |
| .configure("address", addrWithoutGeo) |
| .configure("name", "Nowhere")); |
| } |
| |
| @Override |
| @AfterMethod(alwaysRun=true) |
| public void tearDown() throws Exception { |
| super.tearDown(); |
| if (origGeoLookupImpl != null) { |
| System.setProperty(BrooklynSystemProperties.HOST_GEO_LOOKUP_IMPL.getPropertyName(), origGeoLookupImpl); |
| } else { |
| System.clearProperty(BrooklynSystemProperties.HOST_GEO_LOOKUP_IMPL.getPropertyName()); |
| } |
| HostGeoInfo.clearCachedLookup(); |
| } |
| |
| private String getBrooklynProperty(ManagementContext mgmt, String property) { |
| return ((ManagementContextInternal) mgmt).getBrooklynProperties().getFirst(property); |
| } |
| |
| @Test(groups={"Integration"}) |
| public void testRoutesToExpectedLocation() { |
| // Without this config, running on a home network (i.e. no public IP) the entity will have a private IP and will be ignored |
| geoDns.config().set(GeoscalingDnsService.INCLUDE_HOMELESS_ENTITIES, true); |
| |
| target.sensors().set(Attributes.HOSTNAME,addrWithGeo.getHostName()); |
| |
| app.start(ImmutableList.of(locWithGeo)); |
| |
| LOG.info("geo-scaling test, using {}.{}; expect to be wired to {}", new Object[] {subDomain, primaryDomain, addrWithGeo}); |
| |
| assertTargetHostsEventually(geoDns, 1); |
| } |
| |
| @Test(groups={"Integration"}) |
| public void testIgnoresAddressWithoutGeography() throws Exception { |
| System.setProperty(BrooklynSystemProperties.HOST_GEO_LOOKUP_IMPL.getPropertyName(), StubHostGeoLookup.class.getName()); |
| geoDns.config().set(GeoscalingDnsService.INCLUDE_HOMELESS_ENTITIES, false); // false is default |
| |
| app.start(ImmutableList.of(locWithoutGeo)); |
| target.sensors().set(Attributes.HOSTNAME, StubHostGeoLookup.HOMELESS_IP); |
| |
| LOG.info("geo-scaling test, using {}.{}; expect not to be wired to {}", new Object[] {subDomain, primaryDomain, addrWithoutGeo}); |
| |
| Asserts.succeedsContinually(MutableMap.of("timeout", 10*1000), new Runnable() { |
| @Override public void run() { |
| assertEquals(geoDns.getTargetHosts().size(), 0, "targets="+geoDns.getTargetHosts()); |
| } |
| }); |
| } |
| |
| @Test(groups={"Integration"}) |
| public void testIncludesAddressWithoutGeography() { |
| System.setProperty(BrooklynSystemProperties.HOST_GEO_LOOKUP_IMPL.getPropertyName(), StubHostGeoLookup.class.getName()); |
| geoDns.config().set(GeoscalingDnsService.INCLUDE_HOMELESS_ENTITIES, true); |
| |
| app.start(ImmutableList.of(locWithoutGeo)); |
| target.sensors().set(Attributes.HOSTNAME, StubHostGeoLookup.HOMELESS_IP); |
| |
| LOG.info("geo-scaling test, using {}.{}; expect to be wired to {}", new Object[] {subDomain, primaryDomain, addrWithoutGeo}); |
| |
| assertTargetHostsEventually(geoDns, 1); |
| } |
| |
| private void assertTargetHostsEventually(final GeoscalingDnsService geoDns, final int numExpected) { |
| Asserts.succeedsEventually(new Runnable() { |
| @Override public void run() { |
| assertEquals(geoDns.getTargetHosts().size(), 1, "targets="+geoDns.getTargetHosts()); |
| } |
| }); |
| } |
| |
| public static class StubHostGeoLookup implements HostGeoLookup { |
| public static final String HOMELESS_IP = "1.2.3.4"; |
| private final HostGeoLookup delegate; |
| |
| public StubHostGeoLookup() throws Exception { |
| this(null); |
| } |
| |
| public StubHostGeoLookup(String delegateImpl) throws Exception { |
| if (delegateImpl == null) { |
| // don't just call HostGeoInfo.getDefaultLookup; this is the default lookup! |
| if (MaxMind2HostGeoLookup.getDatabaseReader()!=null) { |
| delegate = new MaxMind2HostGeoLookup(); |
| } else { |
| delegate = new UtraceHostGeoLookup(); |
| } |
| } else { |
| delegate = (HostGeoLookup) Class.forName(delegateImpl).newInstance(); |
| } |
| } |
| |
| @Override |
| public HostGeoInfo getHostGeoInfo(InetAddress address) throws Exception { |
| if (isHostGeoLookupGloballyDisabled()) return null; |
| // Saw strange test failure on jenkins: hence paranoid logging, just in case exception is swallowed somehow. |
| try { |
| HostGeoInfo result; |
| if (HOMELESS_IP.equals(address.getHostAddress())) { |
| result = null; |
| } else { |
| result = delegate.getHostGeoInfo(address); |
| } |
| LOG.info("StubHostGeoLookup.getHostGeoInfo queried: address="+address+"; hostAddress="+address.getHostAddress()+"; result="+result); |
| return result; |
| } catch (Throwable t) { |
| LOG.error("StubHostGeoLookup.getHostGeoInfo encountered problem (rethrowing): address="+address+"; hostAddress="+address.getHostAddress(), t); |
| throw Exceptions.propagate(t); |
| } |
| } |
| } |
| } |