/* * 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; import java.net.InetAddress; import java.util.Collection; import java.util.Iterator; import java.util.Set; 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.core.entity.Attributes; import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation; import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation.LocalhostMachine; import org.apache.brooklyn.location.ssh.SshMachineLocation; import org.apache.brooklyn.util.guava.Maybe; import org.apache.brooklyn.util.net.HasNetworkAddresses; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Iterables; /** utilities for working with MachineLocations */ public class Machines { private static final Logger log = LoggerFactory.getLogger(Machines.class); public static Maybe<String> getSubnetHostname(Location where) { // TODO Should we look at HasNetworkAddresses? But that's not a hostname. String hostname = null; if (where instanceof HasSubnetHostname) { hostname = ((HasSubnetHostname) where).getSubnetHostname(); } if (hostname == null && where instanceof MachineLocation) { InetAddress addr = ((MachineLocation) where).getAddress(); if (addr != null) hostname = addr.getHostAddress(); } log.debug("computed subnet hostname {} for {}", hostname, where); // TODO if Maybe.absent(message) appears, could/should use that // TODO If no machine available, should we throw new IllegalStateException("Cannot find hostname for "+where); return Maybe.fromNullable(hostname); } public static Maybe<String> getSubnetIp(Location where) { // TODO Too much duplication between the ip and hostname methods String result = null; if (where instanceof HasSubnetHostname) { result = ((HasSubnetHostname) where).getSubnetIp(); } if (where instanceof HasNetworkAddresses) { Set<String> privateAddrs = ((HasNetworkAddresses) where).getPrivateAddresses(); if (privateAddrs.size() > 0) { result = Iterables.get(privateAddrs, 0); } } if (result == null && where instanceof MachineLocation) { InetAddress addr = ((MachineLocation) where).getAddress(); if (addr != null) result = addr.getHostAddress(); } log.debug("computed subnet host ip {} for {}", result, where); return Maybe.fromNullable(result); } @SuppressWarnings("unchecked") public static <T> Maybe<T> findUniqueElement(Iterable<?> items, Class<T> type) { if (items==null) return null; Iterator<?> i = items.iterator(); T result = null; while (i.hasNext()) { Object candidate = i.next(); if (type.isInstance(candidate)) { if (result==null) result = (T)candidate; else { if (log.isTraceEnabled()) log.trace("Multiple instances of "+type+" in "+items+"; ignoring"); return Maybe.absent(new IllegalStateException("Multiple instances of "+type+" in "+items+"; expected a single one")); } } } if (result==null) return Maybe.absent(new IllegalStateException("No instances of "+type+" available (in "+items+")")); return Maybe.of(result); } /** * @deprecated since 0.9.0; see {@link #findUniqueMachineLocation(Iterable, Class)}, * e.g. {@code findUniqueMachineLocation(locations, SshMachineLocation.class)} */ @Deprecated public static Maybe<SshMachineLocation> findUniqueSshMachineLocation(Iterable<? extends Location> locations) { return findUniqueMachineLocation(locations, SshMachineLocation.class); } public static Maybe<MachineLocation> findUniqueMachineLocation(Iterable<? extends Location> locations) { return findUniqueMachineLocation(locations, MachineLocation.class); } public static <T extends MachineLocation> Maybe<T> findUniqueMachineLocation(Iterable<? extends Location> locations, Class<T> clazz) { return findUniqueElement(locations, clazz); } public static Maybe<String> findSubnetHostname(Iterable<? extends Location> ll) { Maybe<MachineLocation> l = findUniqueMachineLocation(ll); if (!l.isPresent()) { return Maybe.absent(); // throw new IllegalStateException("Cannot find hostname for among "+ll); } return Machines.getSubnetHostname(l.get()); } public static Maybe<String> findSubnetHostname(Entity entity) { String sh = entity.getAttribute(Attributes.SUBNET_HOSTNAME); if (sh!=null) return Maybe.of(sh); return findSubnetHostname(entity.getLocations()); } public static Maybe<String> findSubnetOrPublicHostname(Entity entity) { String hn = entity.getAttribute(Attributes.HOSTNAME); if (hn!=null) { // attributes already set, see if there was a SUBNET_HOSTNAME set // note we rely on (public) hostname being set _after_ subnet_hostname, // to prevent tiny possibility of races resulting in hostname being returned // becasue subnet is still being looked up -- see MachineLifecycleEffectorTasks Maybe<String> sn = findSubnetHostname(entity); if (sn.isPresent()) return sn; // short-circuit discovery if attributes have been set already return Maybe.of(hn); } Maybe<MachineLocation> l = findUniqueMachineLocation(entity.getLocations()); if (!l.isPresent()) return Maybe.absent(); InetAddress addr = l.get().getAddress(); if (addr==null) return Maybe.absent(); return Maybe.fromNullable(addr.getHostName()); } public static Maybe<String> findSubnetOrPrivateIp(Entity entity) { // see comments in findSubnetOrPrivateHostname String hn = entity.getAttribute(Attributes.ADDRESS); if (hn!=null) { Maybe<String> sn = findSubnetIp(entity); if (sn.isPresent()) return sn; return Maybe.of(hn); } Maybe<MachineLocation> l = findUniqueMachineLocation(entity.getLocations()); if (!l.isPresent()) return Maybe.absent(); InetAddress addr = l.get().getAddress(); if (addr==null) return Maybe.absent(); return Maybe.fromNullable(addr.getHostAddress()); } public static Maybe<String> findSubnetIp(Entity entity) { String sh = entity.getAttribute(Attributes.SUBNET_ADDRESS); if (sh!=null) return Maybe.of(sh); return findSubnetIp(entity.getLocations()); } public static Maybe<String> findSubnetIp(Iterable<? extends Location> ll) { // TODO Or if can't find MachineLocation, should we throw new IllegalStateException("Cannot find hostname for among "+ll); Maybe<MachineLocation> l = findUniqueMachineLocation(ll); return (l.isPresent()) ? Machines.getSubnetIp(l.get()) : Maybe.<String>absent(); } /** returns whether it is localhost (and has warned) */ public static boolean warnIfLocalhost(Collection<? extends Location> locations, String message) { if (locations.size()==1) { Location l = locations.iterator().next(); if (l instanceof LocalhostMachineProvisioningLocation || l instanceof LocalhostMachine) { log.warn(message); return true; } } return false; } }