http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/location/dynamic/LocationOwner.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/location/dynamic/LocationOwner.java b/core/src/main/java/org/apache/brooklyn/core/location/dynamic/LocationOwner.java new file mode 100644 index 0000000..1d4d4c1 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/core/location/dynamic/LocationOwner.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.core.location.dynamic; + +import java.util.Map; + +import org.apache.brooklyn.api.entity.Entity; +import org.apache.brooklyn.api.location.Location; +import org.apache.brooklyn.api.location.LocationDefinition; +import org.apache.brooklyn.api.sensor.AttributeSensor; +import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.core.config.ConfigKeys; +import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey; +import org.apache.brooklyn.sensor.core.Sensors; +import org.apache.brooklyn.util.core.flags.SetFromFlag; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableMap; +import com.google.common.reflect.TypeToken; + +/** + * An entity that owns a particular location. + * <p> + * The entity should be able to dynamically create an instance of the required type of location, and will manage + * the lifecycle of the location in parallel with its own. + * + * @param L the location type + * @param E the entity type + */ +@Beta +public interface LocationOwner<L extends Location & DynamicLocation<E, L>, E extends Entity & LocationOwner<L, E>> { + + @SetFromFlag("locationPrefix") + ConfigKey<String> LOCATION_NAME_PREFIX = ConfigKeys.newStringConfigKey( + "entity.dynamicLocation.prefix", "The name prefix for the location owned by this entity", "dynamic"); + + @SetFromFlag("locationSuffix") + ConfigKey<String> LOCATION_NAME_SUFFIX = ConfigKeys.newStringConfigKey( + "entity.dynamicLocation.suffix", "The name suffix for the location owned by this entity"); + + @SetFromFlag("locationName") + BasicAttributeSensorAndConfigKey<String> LOCATION_NAME = new BasicAttributeSensorAndConfigKey<String>(String.class, + "entity.dynamicLocation.name", "The name of the location owned by this entity (default is auto-generated using prefix and suffix keys)"); + + ConfigKey<Map<String, Object>> LOCATION_FLAGS = ConfigKeys.newConfigKey(new TypeToken<Map<String, Object>>() { }, + "entity.dynamicLocation.flags", "Extra creation flags for the Location owned by this entity", + ImmutableMap.<String, Object>of()); + + AttributeSensor<Location> DYNAMIC_LOCATION = Sensors.newSensor(Location.class, + "entity.dynamicLocation", "The location owned by this entity"); + + AttributeSensor<String> LOCATION_SPEC = Sensors.newStringSensor( + "entity.dynamicLocation.spec", "The specification string for the location owned by this entity"); + + AttributeSensor<Boolean> DYNAMIC_LOCATION_STATUS = Sensors.newBooleanSensor( + "entity.dynamicLocation.status", "The status of the location owned by this entity"); + + AttributeSensor<LocationDefinition> LOCATION_DEFINITION = Sensors.newSensor( + LocationDefinition.class, "entity.dynamicLocation.definition", "The location definition for the location owned by this entity"); + + L getDynamicLocation(); + + L createLocation(Map<String, ?> flags); + + boolean isLocationAvailable(); + + void deleteLocation(); + +}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/location/geo/GeoBytesHostGeoLookup.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/location/geo/GeoBytesHostGeoLookup.java b/core/src/main/java/org/apache/brooklyn/core/location/geo/GeoBytesHostGeoLookup.java new file mode 100644 index 0000000..3e46720 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/core/location/geo/GeoBytesHostGeoLookup.java @@ -0,0 +1,104 @@ +/* + * 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.core.location.geo; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Properties; + +import org.apache.brooklyn.util.net.Networking; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** @deprecated Mar 2015 - the API has changed; GetLocation now discouraged for free access, and valuepairs.txt not supported */ +@Deprecated +public class GeoBytesHostGeoLookup implements HostGeoLookup { + + public static final Logger log = LoggerFactory.getLogger(GeoBytesHostGeoLookup.class); + + /* + curl "http://www.geobytes.com/IpLocator.htm?GetLocation&template=valuepairs.txt&IpAddress=geobytes.com" + known=1 + countryid=254 + country=United States + fips104=US + iso2=US + iso3=USA + ison=840 + internet=US + comment= + regionid=142 + region=Maryland + code=MD + adm1code= + cityid=8909 + city=Baltimore + latitude=39.2894 + longitude=-76.6384 + timezone=-05:00 + dmaid=512 + dma=512 + market=Baltimore + certainty=78 + isproxy=false + mapbytesremaining=Free + */ + + public String getPropertiesLookupUrlForPublicIp(String ip) { + return "http://www.geobytes.com/IpLocator.htm?GetLocation&template=valuepairs.txt&IpAddress="+ip.trim(); + } + + public String getPropertiesLookupUrlForLocalhost() { + return "http://www.geobytes.com/IpLocator.htm?GetLocation&template=valuepairs.txt"; + } + + /** returns URL to get properties for the given address (assuming localhost if address is on a subnet) */ + public String getPropertiesLookupUrlFor(InetAddress address) { + if (Networking.isPrivateSubnet(address)) return getPropertiesLookupUrlForLocalhost(); + return getPropertiesLookupUrlForPublicIp(address.getHostAddress()); + } + + private static boolean LOGGED_GEO_LOOKUP_UNAVAILABLE = false; + + public HostGeoInfo getHostGeoInfo(InetAddress address) throws MalformedURLException, IOException { + String url = getPropertiesLookupUrlFor(address); + if (log.isDebugEnabled()) + log.debug("Geo info lookup for "+address+" at "+url); + Properties props = new Properties(); + try { + props.load( new URL(url).openStream() ); + HostGeoInfo geo = new HostGeoInfo(address.getHostName(), props.getProperty("city")+" ("+props.getProperty("iso2")+")", + Double.parseDouble(props.getProperty("latitude")), Double.parseDouble(props.getProperty("longitude"))); + log.info("Geo info lookup for "+address+" returned: "+geo); + return geo; + } catch (Exception e) { + // may be web not available, or gateway giving us funny crap + if (log.isDebugEnabled()) + log.debug("Geo info lookup for "+address+" failed: "+e); + if (!LOGGED_GEO_LOOKUP_UNAVAILABLE) { + LOGGED_GEO_LOOKUP_UNAVAILABLE = true; + log.info("Geo info lookup unavailable (for "+address+"; cause "+e+")"); + } + return null; + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/location/geo/HasHostGeoInfo.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/location/geo/HasHostGeoInfo.java b/core/src/main/java/org/apache/brooklyn/core/location/geo/HasHostGeoInfo.java new file mode 100644 index 0000000..97e64d5 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/core/location/geo/HasHostGeoInfo.java @@ -0,0 +1,25 @@ +/* + * 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.core.location.geo; + +public interface HasHostGeoInfo { + + HostGeoInfo getHostGeoInfo(); + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/location/geo/HostGeoInfo.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/location/geo/HostGeoInfo.java b/core/src/main/java/org/apache/brooklyn/core/location/geo/HostGeoInfo.java new file mode 100644 index 0000000..7089de9 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/core/location/geo/HostGeoInfo.java @@ -0,0 +1,205 @@ +/* + * 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.core.location.geo; + +import java.io.Serializable; +import java.net.InetAddress; + +import javax.annotation.Nullable; + +import org.apache.brooklyn.api.entity.Entity; +import org.apache.brooklyn.api.location.AddressableLocation; +import org.apache.brooklyn.api.location.Location; +import org.apache.brooklyn.core.location.AbstractLocation; +import org.apache.brooklyn.core.location.LocationConfigKeys; +import org.apache.brooklyn.util.core.flags.TypeCoercions; +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.guava.Maybe; +import org.apache.brooklyn.util.internal.BrooklynSystemProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Objects; + +/** + * Encapsulates geo-IP information for a given host. + */ +public class HostGeoInfo implements Serializable { + + private static final long serialVersionUID = -5866759901535266181L; + + public static final Logger log = LoggerFactory.getLogger(HostGeoInfo.class); + + /** the IP address */ + public final String address; + + public final String displayName; + + public final double latitude; + public final double longitude; + + private static Maybe<HostGeoLookup> cachedLookup = null; + + public static HostGeoInfo create(String address, String displayName, double latitude, double longitude) { + return new HostGeoInfo(address, displayName, latitude, longitude); + } + + public static HostGeoInfo fromIpAddress(InetAddress address) { + try { + HostGeoLookup lookup = getDefaultLookup(); + if (lookup!=null) + return lookup.getHostGeoInfo(address); + } catch (Exception e) { + if (log.isDebugEnabled()) + log.debug("unable to look up geo DNS info for "+address, e); + } + return null; + } + + @Nullable + public static HostGeoLookup getDefaultLookup() throws InstantiationException, IllegalAccessException, ClassNotFoundException { + if (cachedLookup==null) { + cachedLookup = Maybe.of(findHostGeoLookupImpl()); + } + return cachedLookup.get(); + } + + public static void clearCachedLookup() { + cachedLookup = null; + } + + /** returns null if cannot be set */ + public static HostGeoInfo fromLocation(Location l) { + if (l==null) return null; + + Location la = l; + HostGeoInfo resultFromLocation = null; + while (la!=null) { + if (la instanceof HasHostGeoInfo) { + resultFromLocation = ((HasHostGeoInfo)l).getHostGeoInfo(); + if (resultFromLocation!=null) break; + } + la = la.getParent(); + } + if (resultFromLocation!=null && l==la) { + // from the location + return resultFromLocation; + } + // resultFromLocation may be inherited, in which case we will copy it later + + InetAddress address = findIpAddress(l); + Object latitude = l.getConfig(LocationConfigKeys.LATITUDE); + Object longitude = l.getConfig(LocationConfigKeys.LONGITUDE); + + if (resultFromLocation!=null && (latitude == null || longitude == null)) { + latitude = resultFromLocation.latitude; + longitude = resultFromLocation.longitude; + } + if (address!=null && (latitude == null || longitude == null)) { + HostGeoInfo geo = fromIpAddress(address); + if (geo==null) return null; + latitude = geo.latitude; + longitude = geo.longitude; + } + + if (latitude==null || longitude==null) + return null; + + Exception error=null; + try { + latitude = TypeCoercions.castPrimitive(latitude, Double.class); + longitude = TypeCoercions.castPrimitive(longitude, Double.class); + } catch (Exception e) { + Exceptions.propagateIfFatal(e); + error = e; + } + if (error!=null || !(latitude instanceof Double) || !(longitude instanceof Double)) + throw new IllegalArgumentException("Location "+l+" specifies invalid type of lat/long: " + + "lat="+latitude+" (type "+(latitude==null ? null : latitude.getClass())+"); " + + "lon="+longitude+" (type "+(longitude==null ? null : longitude.getClass())+")", error); + + HostGeoInfo result = new HostGeoInfo(address!=null ? address.getHostAddress() : null, l.getDisplayName(), (Double) latitude, (Double) longitude); + if (l instanceof AbstractLocation) { + ((AbstractLocation)l).setHostGeoInfo(result); + } + return result; + } + + private static HostGeoLookup findHostGeoLookupImpl() throws InstantiationException, IllegalAccessException, ClassNotFoundException { + String type = BrooklynSystemProperties.HOST_GEO_LOOKUP_IMPL.getValue(); + /* utrace seems more accurate than geobytes, and it gives a report of how many tokens are left; + * but maxmind if it's installed locally is even better (does not require remote lookup), + * so use it if available */ + if (type==null) { + if (MaxMind2HostGeoLookup.getDatabaseReader()!=null) + return new MaxMind2HostGeoLookup(); + log.debug("Using Utrace remote for geo lookup because MaxMind2 is not available"); + return new UtraceHostGeoLookup(); + } + if (type.isEmpty()) return null; + return (HostGeoLookup) Class.forName(type).newInstance(); + } + + public static HostGeoInfo fromEntity(Entity e) { + for (Location l : e.getLocations()) { + HostGeoInfo hgi = fromLocation(l); + if (hgi != null) + return hgi; + } + return null; + } + + public static InetAddress findIpAddress(Location l) { + if (l == null) + return null; + if (l instanceof AddressableLocation) + return ((AddressableLocation) l).getAddress(); + return findIpAddress(l.getParent()); + } + + public HostGeoInfo(String address, String displayName, double latitude, double longitude) { + this.address = address; + this.displayName = displayName==null ? "" : displayName; + this.latitude = latitude; + this.longitude = longitude; + } + + public String getAddress() { + return address; + } + + @Override + public String toString() { + return "HostGeoInfo["+displayName+": "+(address!=null ? address : "(no-address)")+" at ("+latitude+","+longitude+")]"; + } + + @Override + public boolean equals(Object o) { + // Slight cheat: only includes the address + displayName field (displayName to allow overloading localhost etc) + return (o instanceof HostGeoInfo) && Objects.equal(address, ((HostGeoInfo) o).address) + && Objects.equal(displayName, ((HostGeoInfo) o).displayName); + } + + @Override + public int hashCode() { + // Slight cheat: only includes the address + displayName field (displayName to allow overloading localhost etc) + return Objects.hashCode(address, displayName); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/location/geo/HostGeoLookup.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/location/geo/HostGeoLookup.java b/core/src/main/java/org/apache/brooklyn/core/location/geo/HostGeoLookup.java new file mode 100644 index 0000000..ec25e07 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/core/location/geo/HostGeoLookup.java @@ -0,0 +1,27 @@ +/* + * 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.core.location.geo; + +import java.net.InetAddress; + +public interface HostGeoLookup { + + public HostGeoInfo getHostGeoInfo(InetAddress address) throws Exception; + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/location/geo/LocalhostExternalIpLoader.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/location/geo/LocalhostExternalIpLoader.java b/core/src/main/java/org/apache/brooklyn/core/location/geo/LocalhostExternalIpLoader.java new file mode 100644 index 0000000..fd95585 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/core/location/geo/LocalhostExternalIpLoader.java @@ -0,0 +1,177 @@ +/* + * 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.core.location.geo; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.brooklyn.util.core.ResourceUtils; +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.text.StringPredicates; +import org.apache.brooklyn.util.time.Duration; +import org.apache.brooklyn.util.time.Durations; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Predicates; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +public class LocalhostExternalIpLoader { + + public static final Logger LOG = LoggerFactory.getLogger(LocalhostExternalIpLoader.class); + + private static final AtomicBoolean retrievingLocalExternalIp = new AtomicBoolean(false); + private static final CountDownLatch triedLocalExternalIp = new CountDownLatch(1); + private static volatile String localExternalIp; + + private static class IpLoader implements Callable<String> { + private static final Pattern ipPattern = Pattern.compile( + "\\b((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\b"); + final String url; + + protected IpLoader(String url) { + this.url = url; + } + + @Override + public String call() { + String response = ResourceUtils.create(LocalhostExternalIpLoader.class) + .getResourceAsString(url).trim(); + return postProcessResponse(response); + } + + String postProcessResponse(String response) { + Matcher matcher = ipPattern.matcher(response); + boolean matched = matcher.find(); + if (!matched) { + LOG.error("No IP address matched in output from {}: {}", url, response); + return null; + } else { + return matcher.group(); + } + } + } + + @VisibleForTesting + static List<String> getIpAddressWebsites() { + String file = new ResourceUtils(LocalhostExternalIpLoader.class) + .getResourceAsString("classpath://org/apache/brooklyn/location/geo/external-ip-address-resolvers.txt"); + Iterable<String> lines = Splitter.on('\n') + .omitEmptyStrings() + .trimResults() + .split(file); + List<String> urls = Lists.newArrayList(Iterables.filter(lines, Predicates.not(StringPredicates.startsWith("#")))); + Collections.shuffle(urls); + return urls; + } + + @VisibleForTesting + static String getIpAddressFrom(String url) { + return new IpLoader(url).call(); + } + + /** As {@link #getLocalhostIpWithin(Duration)} but returning 127.0.0.1 if not accessible */ + public static String getLocalhostIpQuicklyOrDefault() { + String result = doLoad(Duration.seconds(2)); + if (result==null) return "127.0.0.1"; + return result; + } + + /** As {@link #getLocalhostIpWithin(Duration)} but without the time limit cut-off, failing if the load gives an error. */ + public static String getLocalhostIpWaiting() { + return getLocalhostIpWithin(null); + } + + /** + * Attempts to load the public IP address of localhost, failing if the load + * does not complete within the given duration. + * @return The public IP address of localhost + */ + public static String getLocalhostIpWithin(Duration timeout) { + String result = doLoad(timeout); + if (result == null) { + throw new IllegalStateException("Unable to retrieve external IP for localhost; network may be down or slow or remote service otherwise not responding"); + } + return result; + } + + /** + * Requests URLs returned by {@link #getIpAddressWebsites()} until one returns an IP address. + * The address is assumed to be the external IP address of localhost. + * @param blockFor The maximum duration to wait for the IP address to be resolved. + * An indefinite way if null. + * @return A string in IPv4 format, or null if no such address could be ascertained. + */ + private static String doLoad(Duration blockFor) { + if (localExternalIp != null) { + return localExternalIp; + } + + final List<String> candidateUrls = getIpAddressWebsites(); + if (candidateUrls.isEmpty()) { + LOG.debug("No candidate URLs to use to determine external IP of localhost"); + return null; + } + + // do in private thread, otherwise blocks for 30s+ on dodgy network! + // (we can skip it if someone else is doing it, we have synch lock so we'll get notified) + if (retrievingLocalExternalIp.compareAndSet(false, true)) { + new Thread() { + public void run() { + for (String url : candidateUrls) { + try { + LOG.debug("Looking up external IP of this host from {} in private thread {}", url, Thread.currentThread()); + localExternalIp = new IpLoader(url).call(); + LOG.debug("Finished looking up external IP of this host from {} in private thread, result {}", url, localExternalIp); + break; + } catch (Throwable t) { + LOG.debug("Unable to look up external IP of this host from {}, probably offline {})", url, t); + } finally { + retrievingLocalExternalIp.set(false); + triedLocalExternalIp.countDown(); + } + } + } + }.start(); + } + + try { + if (blockFor!=null) { + Durations.await(triedLocalExternalIp, blockFor); + } else { + triedLocalExternalIp.await(); + } + } catch (InterruptedException e) { + throw Exceptions.propagate(e); + } + if (localExternalIp == null) { + return null; + } + return localExternalIp; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/location/geo/MaxMind2HostGeoLookup.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/location/geo/MaxMind2HostGeoLookup.java b/core/src/main/java/org/apache/brooklyn/core/location/geo/MaxMind2HostGeoLookup.java new file mode 100644 index 0000000..1880441 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/core/location/geo/MaxMind2HostGeoLookup.java @@ -0,0 +1,114 @@ +/* + * 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.core.location.geo; + +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.MalformedURLException; + +import org.apache.brooklyn.util.internal.BrooklynSystemProperties; +import org.apache.brooklyn.util.net.Networking; +import org.apache.brooklyn.util.text.Strings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Throwables; +import com.google.common.collect.Lists; +import com.maxmind.geoip2.DatabaseReader; +import com.maxmind.geoip2.model.CityResponse; +import com.maxmind.geoip2.record.Subdivision; + +public class MaxMind2HostGeoLookup implements HostGeoLookup { + + public static final Logger log = LoggerFactory.getLogger(MaxMind2HostGeoLookup.class); + + static final String MAXMIND_DB_URL = "http://dev.maxmind.com/geoip/geoip2/geolite2/#Downloads"; + // TODO this should be configurable from system property or brooklyn.properties + // TODO and should use properties BrooklynServerConfig.MGMT_BASE_DIR (but hard to get mgmt properties here!) + static final String MAXMIND_DB_PATH = System.getProperty("user.home")+"/"+".brooklyn/"+"GeoLite2-City.mmdb"; + + static boolean lookupFailed = false; + static DatabaseReader databaseReader = null; + + public static synchronized DatabaseReader getDatabaseReader() { + if (databaseReader!=null) return databaseReader; + try { + File f = new File(MAXMIND_DB_PATH); + databaseReader = new DatabaseReader.Builder(f).build(); + } catch (IOException e) { + lookupFailed = true; + log.debug("MaxMind geo lookup unavailable; either download and unpack the latest "+ + "binary from "+MAXMIND_DB_URL+" into "+MAXMIND_DB_PATH+", "+ + "or specify a different HostGeoLookup implementation with the key "+ + BrooklynSystemProperties.HOST_GEO_LOOKUP_IMPL.getPropertyName()+" (error trying to read: "+e+")"); + } + return databaseReader; + } + + public HostGeoInfo getHostGeoInfo(InetAddress address) throws MalformedURLException, IOException { + if (lookupFailed) return null; + + DatabaseReader ll = getDatabaseReader(); + if (ll==null) return null; + + InetAddress extAddress = address; + if (Networking.isPrivateSubnet(extAddress)) extAddress = InetAddress.getByName(LocalhostExternalIpLoader.getLocalhostIpQuicklyOrDefault()); + + try { + CityResponse l = ll.city(extAddress); + if (l==null) { + if (log.isDebugEnabled()) log.debug("Geo info failed to find location for address {}, using {}", extAddress, ll); + return null; + } + + StringBuilder name = new StringBuilder(); + + if (l.getCity()!=null && l.getCity().getName()!=null) name.append(l.getCity().getName()); + + if (l.getSubdivisions()!=null) { + for (Subdivision subd: Lists.reverse(l.getSubdivisions())) { + if (name.length()>0) name.append(", "); + // prefer e.g. USA state codes over state names + if (!Strings.isBlank(subd.getIsoCode())) + name.append(subd.getIsoCode()); + else + name.append(subd.getName()); + } + } + + if (l.getCountry()!=null) { + if (name.length()==0) { + name.append(l.getCountry().getName()); + } else { + name.append(" ("); name.append(l.getCountry().getIsoCode()); name.append(")"); + } + } + + + HostGeoInfo geo = new HostGeoInfo(address.getHostName(), name.toString(), l.getLocation().getLatitude(), l.getLocation().getLongitude()); + log.debug("Geo info lookup (MaxMind DB) for "+address+" returned: "+geo); + return geo; + } catch (Exception e) { + if (log.isDebugEnabled()) + log.debug("Geo info lookup failed: "+e); + throw Throwables.propagate(e); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/location/geo/UtraceHostGeoLookup.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/location/geo/UtraceHostGeoLookup.java b/core/src/main/java/org/apache/brooklyn/core/location/geo/UtraceHostGeoLookup.java new file mode 100644 index 0000000..5026ac4 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/core/location/geo/UtraceHostGeoLookup.java @@ -0,0 +1,209 @@ +/* + * 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.core.location.geo; + +import groovy.util.Node; +import groovy.util.NodeList; +import groovy.util.XmlParser; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.util.concurrent.atomic.AtomicReference; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.javalang.JavaClassNames; +import org.apache.brooklyn.util.net.Networking; +import org.apache.brooklyn.util.time.Duration; +import org.apache.brooklyn.util.time.Durations; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Throwables; + +public class UtraceHostGeoLookup implements HostGeoLookup { + + + /* + * +http://xml.utrace.de/?query=88.198.156.18 +(IP address or hostname) + +The XML result is as follows: + +<?xml version="1.0" encoding="iso-8869-1"?> +<results> +<result> +<ip>88.198.156.18</ip> +<host>utrace.de</host> +<isp>Hetzner Online AG</isp> +<org>Pagedesign GmbH</org> +<region>Hamburg</region> +<countrycode>DE</countrycode> +<latitude>53.5499992371</latitude> +<longitude>10</longitude> +<queries>10</queries> +</result> +</results> + +Note the queries count field -- you are permitted 100 per day. +Beyond this you get blacklisted and requests may time out, or return none. +(This may last for several days once blacklisting, not sure how long.) + */ + + /** after failures, subsequent retries within this time interval are blocked */ + private static final Duration RETRY_INTERVAL = Duration.FIVE_MINUTES; + /** requests taking longer than this period are deemed to have timed out and failed; + * set reasonably low so that if we are blacklisted for making too many requests, + * the call to get geo info does not take very long */ + private static final Duration REQUEST_TIMEOUT = Duration.seconds(3); + + public static final Logger log = LoggerFactory.getLogger(UtraceHostGeoLookup.class); + + public String getLookupUrlForPublicIp(String ip) { + return "http://xml.utrace.de/?query="+ip.trim(); + } + + /** + * @deprecated since 0.7.0. Use {@link LocalhostExternalIpLoader} instead. + */ + @Deprecated + public static String getLocalhostExternalIp() { + return LocalhostExternalIpLoader.getLocalhostIpWithin(Duration.seconds(2)); + } + + /** + * @deprecated since 0.7.0. Use {@link LocalhostExternalIpLoader} instead. + */ + @Deprecated + public static String getLocalhostExternalIpImpl() { + return LocalhostExternalIpLoader.getLocalhostIpWithin(Duration.seconds(2)); + } + + public String getLookupUrlForLocalhost() { + return getLookupUrlForPublicIp(LocalhostExternalIpLoader.getLocalhostIpQuicklyOrDefault()); + } + + /** returns URL to get properties for the given address (assuming localhost if address is on a subnet) */ + public String getLookupUrlFor(InetAddress address) { + if (Networking.isPrivateSubnet(address)) return getLookupUrlForLocalhost(); + return getLookupUrlForPublicIp(address.getHostAddress()); + } + + private static boolean LOGGED_GEO_LOOKUP_UNAVAILABLE = false; + private static long LAST_FAILURE_UTC = -1; + + /** does the {@link #retrieveHostGeoInfo(InetAddress)}, but in the background with a default timeout */ + public HostGeoInfo getHostGeoInfo(InetAddress address) throws MalformedURLException, IOException { + if (Duration.sinceUtc(LAST_FAILURE_UTC).compareTo(RETRY_INTERVAL) < 0) { + // wait at least 60s since a failure + return null; + } + return getHostGeoInfo(address, REQUEST_TIMEOUT); + } + + /** does a {@link #retrieveHostGeoInfo(InetAddress)} with a timeout (returning null, interrupting, and setting failure time) */ + public HostGeoInfo getHostGeoInfo(final InetAddress address, Duration timeout) throws MalformedURLException, IOException { + final AtomicReference<HostGeoInfo> result = new AtomicReference<HostGeoInfo>(); + Thread lt = new Thread() { + public void run() { + try { + result.set(retrieveHostGeoInfo(address)); + } catch (Exception e) { + log.warn("Error computing geo info for "+address+"; internet issues or too many requests to (free) servers for "+JavaClassNames.simpleClassName(UtraceHostGeoLookup.this)+": "+e); + log.debug("Detail of host geo error: "+e, e); + } + } + }; + lt.start(); + + try { + Durations.join(lt, timeout); + } catch (InterruptedException e) { + throw Exceptions.propagate(e); + } + + if (lt.isAlive()) { + // interrupt and set the failure time so that subsequent attempts do not face this timeout + lt.interrupt(); + LAST_FAILURE_UTC = System.currentTimeMillis(); + log.debug("Geo info lookup for "+address+" timed out after "+timeout); + } + + return result.get(); + } + + public HostGeoInfo retrieveHostGeoInfo(InetAddress address) throws MalformedURLException, IOException { + String url = getLookupUrlFor(address); + if (log.isDebugEnabled()) + log.debug("Geo info lookup for "+address+" at "+url); + Node xml; + try { + xml = new XmlParser().parse(getLookupUrlFor(address)); + } catch (Exception e) { + LAST_FAILURE_UTC = System.currentTimeMillis(); + if (log.isDebugEnabled()) + log.debug("Geo info lookup for "+address+" failed: "+e); + if (!LOGGED_GEO_LOOKUP_UNAVAILABLE) { + LOGGED_GEO_LOOKUP_UNAVAILABLE = true; + log.info("Geo info lookup unavailable (for "+address+"; cause "+e+")"); + } + return null; + } + try { + String org = getXmlResultsField(xml, "org").trim(); + if (org.isEmpty()) org = getXmlResultsField(xml, "isp").trim(); + String region = getXmlResultsField(xml, "region").trim(); + if (!org.isEmpty()) { + if (!region.isEmpty()) region = org+", "+region; + else region = org; + } + if (region.isEmpty()) region = getXmlResultsField(xml, "isp").trim(); + if (region.isEmpty()) region = address.toString(); + HostGeoInfo geo = new HostGeoInfo(address.getHostName(), + region+ + " ("+getXmlResultsField(xml, "countrycode")+")", + Double.parseDouble(""+getXmlResultsField(xml, "latitude")), + Double.parseDouble(""+getXmlResultsField(xml, "longitude"))); + log.info("Geo info lookup for "+address+" returned: "+geo); + return geo; + } catch (Exception e) { + if (log.isDebugEnabled()) + log.debug("Geo info lookup failed, for "+address+" at "+url+", due to "+e+"; response is "+xml); + throw Throwables.propagate(e); + } + } + + @Nullable + private static Node getFirstChild(Node xml, String field) { + if (xml==null) return null; + NodeList nl = (NodeList)xml.get(field); + if (nl==null || nl.isEmpty()) return null; + return (Node)nl.get(0); + } + @Nonnull + private static String getXmlResultsField(Node xml, String field) { + Node f1 = getFirstChild(getFirstChild(xml, "result"), field); + if (f1==null) return ""; + return f1.text(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationDynamicType.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationDynamicType.java b/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationDynamicType.java new file mode 100644 index 0000000..59f0d34 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationDynamicType.java @@ -0,0 +1,40 @@ +/* + * 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.core.location.internal; + +import org.apache.brooklyn.core.location.AbstractLocation; +import org.apache.brooklyn.core.objs.BrooklynDynamicType; +import org.apache.brooklyn.api.location.Location; +import org.apache.brooklyn.api.location.LocationType; + +public class LocationDynamicType extends BrooklynDynamicType<Location, AbstractLocation> { + + public LocationDynamicType(AbstractLocation location) { + super(location); + } + + public LocationType getSnapshot() { + return (LocationType) super.getSnapshot(); + } + + @Override + protected LocationTypeSnapshot newSnapshot() { + return new LocationTypeSnapshot(name, value(configKeys)); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationInternal.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationInternal.java b/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationInternal.java new file mode 100644 index 0000000..18bceef --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationInternal.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.apache.brooklyn.core.location.internal; + +import java.util.Map; + +import org.apache.brooklyn.api.location.Location; +import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.api.mgmt.rebind.RebindSupport; +import org.apache.brooklyn.api.mgmt.rebind.mementos.LocationMemento; +import org.apache.brooklyn.config.ConfigInheritance; +import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.core.config.ConfigKeys; +import org.apache.brooklyn.core.objs.BrooklynObjectInternal; +import org.apache.brooklyn.util.core.config.ConfigBag; + +import com.google.common.annotations.Beta; + +/** + * Information about locations private to Brooklyn. + */ +public interface LocationInternal extends BrooklynObjectInternal, Location { + + @Beta + public static final ConfigKey<String> ORIGINAL_SPEC = ConfigKeys.newStringConfigKey("spec.original", "The original spec used to instantiate a location"); + @Beta + public static final ConfigKey<String> FINAL_SPEC = ConfigKeys.newStringConfigKey("spec.final", "The actual spec (in a chain) which instantiates a location"); + @Beta + public static final ConfigKey<String> NAMED_SPEC_NAME = ConfigKeys.newStringConfigKey("spec.named.name", "The name on the (first) named spec in a chain"); + + /** + * Registers the given extension for the given type. If an extension already existed for + * this type, then this will override it. + * + * @throws NullPointerException if extensionType or extension are null + * @throws IllegalArgumentException if extension does not implement extensionType + */ + <T> void addExtension(Class<T> extensionType, T extension); + + /** + * Get a record of the metadata of this location. + * <p/> + * <p>Metadata records are used to record an audit trail of events relating to location usage + * (for billing purposes, for example). Implementations (and subclasses) should override this + * method to return information useful for this purpose.</p> + * + * @return + */ + public Map<String, String> toMetadataRecord(); + + /** + * @deprecated since 0.7.0; use {@link #config()}, such as {@code ((LocationInternal)location).config().getLocalBag()} + */ + @Deprecated + ConfigBag getLocalConfigBag(); + + /** + * Returns all config, including that inherited from parents. + * + * This method does not respect {@link ConfigInheritance} and so usage is discouraged. + * + * @deprecated since 0.7.0; use {@link #config()}, such as {@code ((LocationInternal)location).config().getBag()} + */ + @Deprecated + ConfigBag getAllConfigBag(); + + /** + * Users are strongly discouraged from calling or overriding this method. + * It is for internal calls only, relating to persisting/rebinding entities. + * This method may change (or be removed) in a future release without notice. + */ + @Override + @Beta + RebindSupport<LocationMemento> getRebindSupport(); + + ManagementContext getManagementContext(); +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationTypeSnapshot.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationTypeSnapshot.java b/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationTypeSnapshot.java new file mode 100644 index 0000000..1c45da2 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationTypeSnapshot.java @@ -0,0 +1,40 @@ +/* + * 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.core.location.internal; + +import java.util.Map; + +import org.apache.brooklyn.api.sensor.EnricherType; +import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.core.objs.BrooklynTypeSnapshot; + +public class LocationTypeSnapshot extends BrooklynTypeSnapshot implements EnricherType { + + private static final long serialVersionUID = 9150132836104748237L; + + LocationTypeSnapshot(String name, Map<String, ConfigKey<?>> configKeys) { + super(name, configKeys); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + return (obj instanceof LocationTypeSnapshot) && super.equals(obj); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java index d49397b..163ccc6 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java @@ -63,13 +63,13 @@ import org.apache.brooklyn.core.internal.storage.DataGrid; import org.apache.brooklyn.core.internal.storage.DataGridFactory; import org.apache.brooklyn.core.internal.storage.impl.BrooklynStorageImpl; import org.apache.brooklyn.core.internal.storage.impl.inmemory.InMemoryDataGridFactory; +import org.apache.brooklyn.core.location.BasicLocationRegistry; import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext; import org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext; import org.apache.brooklyn.core.mgmt.entitlement.Entitlements; import org.apache.brooklyn.core.mgmt.ha.HighAvailabilityManagerImpl; import org.apache.brooklyn.core.mgmt.rebind.RebindManagerImpl; -import org.apache.brooklyn.location.core.BasicLocationRegistry; import org.apache.brooklyn.util.GroovyJavaMethods; import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.collections.MutableMap; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalLocationManager.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalLocationManager.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalLocationManager.java index d07b6ea..dcd1b43 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalLocationManager.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalLocationManager.java @@ -35,12 +35,12 @@ import org.apache.brooklyn.core.BrooklynLogging.LoggingLevel; import org.apache.brooklyn.core.config.ConfigKeys; import org.apache.brooklyn.core.entity.lifecycle.Lifecycle; import org.apache.brooklyn.core.internal.storage.BrooklynStorage; +import org.apache.brooklyn.core.location.AbstractLocation; +import org.apache.brooklyn.core.location.internal.LocationInternal; import org.apache.brooklyn.core.mgmt.entitlement.Entitlements; import org.apache.brooklyn.core.objs.proxy.InternalLocationFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.apache.brooklyn.location.core.AbstractLocation; -import org.apache.brooklyn.location.core.internal.LocationInternal; import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.core.task.Tasks; import org.apache.brooklyn.util.exceptions.Exceptions; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalUsageManager.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalUsageManager.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalUsageManager.java index b25803d..ba47c02 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalUsageManager.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalUsageManager.java @@ -39,6 +39,9 @@ import org.apache.brooklyn.core.entity.Entities; import org.apache.brooklyn.core.entity.EntityInternal; import org.apache.brooklyn.core.entity.lifecycle.Lifecycle; import org.apache.brooklyn.core.internal.storage.BrooklynStorage; +import org.apache.brooklyn.core.location.AbstractLocation; +import org.apache.brooklyn.core.location.LocationConfigKeys; +import org.apache.brooklyn.core.location.internal.LocationInternal; import org.apache.brooklyn.core.mgmt.ManagementContextInjectable; import org.apache.brooklyn.core.mgmt.entitlement.Entitlements; import org.apache.brooklyn.core.mgmt.usage.ApplicationUsage; @@ -46,9 +49,6 @@ import org.apache.brooklyn.core.mgmt.usage.LocationUsage; import org.apache.brooklyn.core.mgmt.usage.UsageManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.apache.brooklyn.location.core.AbstractLocation; -import org.apache.brooklyn.location.core.LocationConfigKeys; -import org.apache.brooklyn.location.core.internal.LocationInternal; import org.apache.brooklyn.util.core.flags.TypeCoercions; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.javalang.Reflections; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicLocationRebindSupport.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicLocationRebindSupport.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicLocationRebindSupport.java index c3b657d..b789501 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicLocationRebindSupport.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicLocationRebindSupport.java @@ -27,10 +27,10 @@ import org.apache.brooklyn.api.location.Location; import org.apache.brooklyn.api.mgmt.rebind.RebindContext; import org.apache.brooklyn.api.mgmt.rebind.mementos.LocationMemento; import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.core.location.AbstractLocation; import org.apache.brooklyn.core.mgmt.rebind.dto.MementosGenerators; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.apache.brooklyn.location.core.AbstractLocation; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.flags.FlagUtils; import org.apache.brooklyn.util.core.flags.TypeCoercions; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ImmediateDeltaChangeListener.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ImmediateDeltaChangeListener.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ImmediateDeltaChangeListener.java index 81785bc..6252d28 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ImmediateDeltaChangeListener.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ImmediateDeltaChangeListener.java @@ -21,6 +21,7 @@ package org.apache.brooklyn.core.mgmt.rebind; import java.util.Collection; import java.util.Map; +import org.apache.brooklyn.core.location.internal.LocationInternal; import org.apache.brooklyn.core.objs.BrooklynObjectInternal; import org.apache.brooklyn.api.catalog.CatalogItem; import org.apache.brooklyn.api.entity.Entity; @@ -37,7 +38,6 @@ import org.apache.brooklyn.api.mgmt.rebind.mementos.PolicyMemento; import org.apache.brooklyn.api.objs.BrooklynObject; import org.apache.brooklyn.api.policy.Policy; import org.apache.brooklyn.api.sensor.Enricher; -import org.apache.brooklyn.location.core.internal.LocationInternal; import com.google.common.collect.Maps; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java index c481ade..e6d030d 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java @@ -67,6 +67,8 @@ import org.apache.brooklyn.core.catalog.internal.CatalogUtils; import org.apache.brooklyn.core.entity.AbstractApplication; import org.apache.brooklyn.core.entity.AbstractEntity; import org.apache.brooklyn.core.entity.EntityInternal; +import org.apache.brooklyn.core.location.AbstractLocation; +import org.apache.brooklyn.core.location.internal.LocationInternal; import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext; import org.apache.brooklyn.core.mgmt.internal.BrooklynObjectManagementMode; import org.apache.brooklyn.core.mgmt.internal.BrooklynObjectManagerInternal; @@ -82,8 +84,6 @@ import org.apache.brooklyn.core.objs.proxy.InternalEntityFactory; import org.apache.brooklyn.core.objs.proxy.InternalFactory; import org.apache.brooklyn.core.objs.proxy.InternalLocationFactory; import org.apache.brooklyn.core.objs.proxy.InternalPolicyFactory; -import org.apache.brooklyn.location.core.AbstractLocation; -import org.apache.brooklyn.location.core.internal.LocationInternal; import org.apache.brooklyn.policy.core.AbstractPolicy; import org.apache.brooklyn.sensor.enricher.AbstractEnricher; import org.apache.brooklyn.sensor.feed.AbstractFeed; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java index 53892c4..3710cfb 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java @@ -51,11 +51,11 @@ import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.catalog.internal.CatalogItemDo; import org.apache.brooklyn.core.entity.EntityDynamicType; import org.apache.brooklyn.core.entity.EntityInternal; +import org.apache.brooklyn.core.location.internal.LocationInternal; import org.apache.brooklyn.core.mgmt.persist.BrooklynPersistenceUtils; import org.apache.brooklyn.core.mgmt.rebind.AbstractBrooklynObjectRebindSupport; import org.apache.brooklyn.core.mgmt.rebind.TreeUtils; import org.apache.brooklyn.core.objs.BrooklynTypes; -import org.apache.brooklyn.location.core.internal.LocationInternal; import org.apache.brooklyn.policy.core.AbstractPolicy; import org.apache.brooklyn.sensor.enricher.AbstractEnricher; import org.apache.brooklyn.sensor.feed.AbstractFeed; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java index e66c8b3..9391a57 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java @@ -26,10 +26,10 @@ import org.apache.brooklyn.api.location.Location; import org.apache.brooklyn.api.location.LocationSpec; import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.core.location.AbstractLocation; +import org.apache.brooklyn.core.location.internal.LocationInternal; import org.apache.brooklyn.core.mgmt.internal.LocalLocationManager; import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal; -import org.apache.brooklyn.location.core.AbstractLocation; -import org.apache.brooklyn.location.core.internal.LocationInternal; import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.core.flags.FlagUtils; import org.apache.brooklyn.util.exceptions.Exceptions; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/effector/core/EffectorTasks.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/EffectorTasks.java b/core/src/main/java/org/apache/brooklyn/effector/core/EffectorTasks.java index 4f1b8d5..249da53 100644 --- a/core/src/main/java/org/apache/brooklyn/effector/core/EffectorTasks.java +++ b/core/src/main/java/org/apache/brooklyn/effector/core/EffectorTasks.java @@ -29,11 +29,11 @@ import org.apache.brooklyn.api.mgmt.Task; import org.apache.brooklyn.api.mgmt.TaskAdaptable; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.config.ConfigKeys; +import org.apache.brooklyn.core.location.Machines; import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; import org.apache.brooklyn.core.mgmt.internal.EffectorUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.apache.brooklyn.location.core.Machines; import org.apache.brooklyn.location.ssh.SshMachineLocation; import org.apache.brooklyn.location.winrm.WinRmMachineLocation; import org.apache.brooklyn.util.core.config.ConfigBag; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java index 67b2b91..7a0c31b 100644 --- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java +++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java @@ -48,12 +48,12 @@ import org.apache.brooklyn.core.entity.lifecycle.QuorumCheck.QuorumChecks; import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceProblemsLogic; import org.apache.brooklyn.core.entity.trait.Startable; import org.apache.brooklyn.core.entity.trait.StartableMethods; +import org.apache.brooklyn.core.location.Locations; +import org.apache.brooklyn.core.location.cloud.AvailabilityZoneExtension; import org.apache.brooklyn.effector.core.Effectors; import org.apache.brooklyn.entity.stock.DelegateEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.apache.brooklyn.location.cloud.AvailabilityZoneExtension; -import org.apache.brooklyn.location.core.Locations; import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.flags.TypeCoercions; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/entity/stock/BasicStartable.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/entity/stock/BasicStartable.java b/core/src/main/java/org/apache/brooklyn/entity/stock/BasicStartable.java index 2607d53..2e56fab 100644 --- a/core/src/main/java/org/apache/brooklyn/entity/stock/BasicStartable.java +++ b/core/src/main/java/org/apache/brooklyn/entity/stock/BasicStartable.java @@ -26,7 +26,7 @@ import org.apache.brooklyn.api.location.Location; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.config.ConfigKeys; import org.apache.brooklyn.core.entity.trait.Startable; -import org.apache.brooklyn.location.core.Locations; +import org.apache.brooklyn.core.location.Locations; import com.google.common.collect.ImmutableList; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/entity/stock/BasicStartableImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/entity/stock/BasicStartableImpl.java b/core/src/main/java/org/apache/brooklyn/entity/stock/BasicStartableImpl.java index 70f071a..4906839 100644 --- a/core/src/main/java/org/apache/brooklyn/entity/stock/BasicStartableImpl.java +++ b/core/src/main/java/org/apache/brooklyn/entity/stock/BasicStartableImpl.java @@ -33,7 +33,7 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle; import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic; import org.apache.brooklyn.core.entity.trait.Startable; import org.apache.brooklyn.core.entity.trait.StartableMethods; -import org.apache.brooklyn.location.core.Locations; +import org.apache.brooklyn.core.location.Locations; import org.apache.brooklyn.util.exceptions.Exceptions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/538324e1/core/src/main/java/org/apache/brooklyn/location/access/BrooklynAccessUtils.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/location/access/BrooklynAccessUtils.java b/core/src/main/java/org/apache/brooklyn/location/access/BrooklynAccessUtils.java deleted file mode 100644 index c2eb7b7..0000000 --- a/core/src/main/java/org/apache/brooklyn/location/access/BrooklynAccessUtils.java +++ /dev/null @@ -1,154 +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.apache.brooklyn.location.access; - -import java.util.Collection; - -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.location.Location; -import org.apache.brooklyn.api.location.MachineLocation; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.config.BasicConfigKey; -import org.apache.brooklyn.core.entity.Attributes; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.apache.brooklyn.location.core.Machines; -import org.apache.brooklyn.location.core.SupportsPortForwarding; -import org.apache.brooklyn.location.ssh.SshMachineLocation; -import org.apache.brooklyn.util.core.task.DynamicTasks; -import org.apache.brooklyn.util.core.task.Tasks; -import org.apache.brooklyn.util.core.task.ssh.SshTasks; -import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper; -import org.apache.brooklyn.util.exceptions.Exceptions; -import org.apache.brooklyn.util.guava.Maybe; -import org.apache.brooklyn.util.net.Cidr; -import org.apache.brooklyn.util.text.Strings; -import org.python.google.common.base.Predicates; -import org.python.google.common.collect.Iterables; - -import com.google.common.base.Supplier; -import com.google.common.net.HostAndPort; - -public class BrooklynAccessUtils { - - private static final Logger log = LoggerFactory.getLogger(BrooklynAccessUtils.class); - - public static final ConfigKey<PortForwardManager> PORT_FORWARDING_MANAGER = new BasicConfigKey<PortForwardManager>( - PortForwardManager.class, "brooklyn.portforwarding.manager", "A port-forwarding manager to use at an entity " - + "or a location, where supported; note this should normally be a serializable client instance to prevent " - + "the creation of multiple disconnected instances via config duplication"); - - public static final ConfigKey<Cidr> MANAGEMENT_ACCESS_CIDR = new BasicConfigKey<Cidr>( - Cidr.class, "brooklyn.portforwarding.management.cidr", "CIDR to enable by default for port-forwarding for management", - null); // TODO should be a list - - public static HostAndPort getBrooklynAccessibleAddress(Entity entity, int port) { - String host; - - // look up port forwarding - PortForwardManager pfw = entity.getConfig(PORT_FORWARDING_MANAGER); - if (pfw!=null) { - Collection<Location> ll = entity.getLocations(); - - synchronized (BrooklynAccessUtils.class) { - // TODO finer-grained synchronization - - for (MachineLocation machine : Iterables.filter(ll, MachineLocation.class)) { - HostAndPort hp = pfw.lookup(machine, port); - if (hp!=null) { - log.debug("BrooklynAccessUtils found port-forwarded address {} for entity {}, port {}, using machine {}", - new Object[] {hp, entity, port, machine}); - return hp; - } - } - - Maybe<SupportsPortForwarding> supportPortForwardingLoc = Machines.findUniqueElement(ll, SupportsPortForwarding.class); - if (supportPortForwardingLoc.isPresent()) { - Cidr source = entity.getConfig(MANAGEMENT_ACCESS_CIDR); - SupportsPortForwarding loc = supportPortForwardingLoc.get(); - if (source!=null) { - log.debug("BrooklynAccessUtils requesting new port-forwarding rule to access "+port+" on "+entity+" (at "+loc+", enabled for "+source+")"); - // TODO discuss, is this the best way to do it - // (will probably _create_ the port forwarding rule!) - HostAndPort hp = loc.getSocketEndpointFor(source, port); - if (hp!=null) { - log.debug("BrooklynAccessUtils created port-forwarded address {} for entity {}, port {}, using {}", - new Object[] {hp, entity, port, loc}); - return hp; - } - } else { - log.warn("No "+MANAGEMENT_ACCESS_CIDR.getName()+" configured for "+entity+", so cannot forward " - +"port "+port+" "+"even though "+PORT_FORWARDING_MANAGER.getName()+" was supplied, and " - +"have location supporting port forwarding "+loc); - } - } - } - } - - host = entity.getAttribute(Attributes.HOSTNAME); - if (host!=null) return HostAndPort.fromParts(host, port); - - throw new IllegalStateException("Cannot find way to access port "+port+" on "+entity+" from Brooklyn (no host.name)"); - } - - /** attempts to resolve hostnameTarget from origin - * @return null if it definitively can't be resolved, - * best-effort IP address if possible, or blank if we could not run ssh or make sense of the output */ - public static String getResolvedAddress(Entity entity, SshMachineLocation origin, String hostnameTarget) { - ProcessTaskWrapper<Integer> task = SshTasks.newSshExecTaskFactory(origin, "ping -c 1 -t 1 "+hostnameTarget) - .summary("checking resolution of "+hostnameTarget).allowingNonZeroExitCode().newTask(); - DynamicTasks.queueIfPossible(task).orSubmitAndBlock(entity).asTask().blockUntilEnded(); - if (task.asTask().isError()) { - log.warn("ping could not be run, at "+entity+" / "+origin+": "+Tasks.getError(task.asTask())); - return ""; - } - if (task.getExitCode()==null || task.getExitCode()!=0) { - if (task.getExitCode()!=null && task.getExitCode()<10) { - // small number means ping failed to resolve or ping the hostname - log.debug("not able to resolve "+hostnameTarget+" from "+origin+" for "+entity+" because exit code was "+task.getExitCode()); - return null; - } - // large number means ping probably did not run - log.warn("ping not run as expected, at "+entity+" / "+origin+" (code "+task.getExitCode()+"):\n"+task.getStdout().trim()+" --- "+task.getStderr().trim()); - return ""; - } - String out = task.getStdout(); - try { - String line1 = Strings.getFirstLine(out); - String ip = Strings.getFragmentBetween(line1, "(", ")"); - if (Strings.isNonBlank(ip)) - return ip; - } catch (Exception e) { - Exceptions.propagateIfFatal(e); - /* ignore non-parseable output */ - } - if (out.contains("127.0.0.1")) return "127.0.0.1"; - return ""; - } - - public static Supplier<String> resolvedAddressSupplier(final Entity entity, final SshMachineLocation origin, final String hostnameTarget) { - return new Supplier<String>() { - @Override - public String get() { - return getResolvedAddress(entity, origin, hostnameTarget); - } - }; - } - -}
