Java tutorial
/* * 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.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.apache.brooklyn.core.location.Machines; import org.apache.brooklyn.core.location.SupportsPortForwarding; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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 com.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); } }; } }