Return-Path: X-Original-To: apmail-brooklyn-commits-archive@minotaur.apache.org Delivered-To: apmail-brooklyn-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id CC3EC18C28 for ; Thu, 21 Jan 2016 10:57:50 +0000 (UTC) Received: (qmail 62156 invoked by uid 500); 21 Jan 2016 10:57:50 -0000 Delivered-To: apmail-brooklyn-commits-archive@brooklyn.apache.org Received: (qmail 62128 invoked by uid 500); 21 Jan 2016 10:57:50 -0000 Mailing-List: contact commits-help@brooklyn.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@brooklyn.apache.org Delivered-To: mailing list commits@brooklyn.apache.org Received: (qmail 62118 invoked by uid 99); 21 Jan 2016 10:57:50 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 21 Jan 2016 10:57:50 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 7170EDFF94; Thu, 21 Jan 2016 10:57:50 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: heneveld@apache.org To: commits@brooklyn.apache.org Date: Thu, 21 Jan 2016 10:57:50 -0000 Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: [1/4] incubator-brooklyn git commit: Better control over opening inbound ports Repository: incubator-brooklyn Updated Branches: refs/heads/master 511886099 -> b28ba027e Better control over opening inbound ports Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/6b43665f Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/6b43665f Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/6b43665f Branch: refs/heads/master Commit: 6b43665fa021e11447001d6d1f56eadae6a002ae Parents: ed289ec Author: Guglielmo Nigri Authored: Thu Jan 14 11:42:51 2016 +0100 Committer: Guglielmo Nigri Committed: Thu Jan 14 18:42:51 2016 +0100 ---------------------------------------------------------------------- .../entity/software/base/InboundPortsUtils.java | 98 ++++++++++++++++++++ .../SameServerDriverLifecycleEffectorTasks.java | 33 +++---- .../entity/software/base/SameServerEntity.java | 7 ++ .../entity/software/base/SoftwareProcess.java | 34 +++++-- .../software/base/SoftwareProcessImpl.java | 35 ++----- 5 files changed, 152 insertions(+), 55 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6b43665f/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/InboundPortsUtils.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/InboundPortsUtils.java b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/InboundPortsUtils.java new file mode 100644 index 0000000..adc7b58 --- /dev/null +++ b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/InboundPortsUtils.java @@ -0,0 +1,98 @@ +/* + * 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.software.base; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; +import com.google.common.reflect.TypeToken; +import org.apache.brooklyn.api.entity.Entity; +import org.apache.brooklyn.api.location.PortRange; +import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.util.collections.MutableSet; +import org.apache.brooklyn.util.core.flags.TypeCoercions; +import org.apache.brooklyn.util.guava.Maybe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.Set; +import java.util.regex.Pattern; + +public class InboundPortsUtils { + private static final Logger log = LoggerFactory.getLogger(InboundPortsUtils.class); + + /** + * Returns the required open inbound ports for an Entity. + * If {@code portsAutoInfer} is {@code true} then + * return the first value for each {@link org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey} + * config key {@link PortRange} plus any ports defined with a config key matching the provided regex. + * @param entity the Entity + * @param portsAutoInfer if {@code true} then also return the first value for each {@link org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey} + * config key {@link PortRange} plus any ports defined with a config keys matching the provided regex + * @param portRegex the regex to match config keys that define inbound ports + * @return a collection of port numbers + */ + public static Collection getRequiredOpenPorts(Entity entity, Boolean portsAutoInfer, String portRegex) { + return getRequiredOpenPorts(entity, ImmutableSet.>of(), portsAutoInfer, portRegex); + } + + /** + * Returns the required open inbound ports for an Entity. + * If {@code portsAutoInfer} is {@code true} then + * return the first value for each {@link org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey} + * config key {@link PortRange} plus any ports defined with a config key matching the provided regex. + * This method also accepts an extra set of config keys in addition to those that are defined in the EntityType of the entity itself. + * @param entity the Entity + * @param extraConfigKeys extra set of config key to inspect for inbound ports + * @param portsAutoInfer if {@code true} then return the first value for each {@link org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey} + * config key {@link PortRange} plus any ports defined with a config keys matching the provided regex + * @param portRegex the regex to match config keys that define inbound ports + * @return a collection of port numbers + */ + public static Collection getRequiredOpenPorts(Entity entity, Set> extraConfigKeys, Boolean portsAutoInfer, String portRegex) { + Set ports = MutableSet.of(); + + /* TODO: This won't work if there's a port collision, which will cause the corresponding port attribute + to be incremented until a free port is found. In that case the entity will use the free port, but the + firewall will open the initial port instead. Mostly a problem for SameServerEntity, localhost location. + */ + if (portsAutoInfer == null || portsAutoInfer.booleanValue()) { // auto-infer defaults to true if not specified + Set> configKeys = Sets.newHashSet(extraConfigKeys); + configKeys.addAll(entity.getEntityType().getConfigKeys()); + + if (portRegex == null) portRegex = ".*\\.port"; // defaults to legacy regex if not specified + Pattern portsPattern = Pattern.compile(portRegex); + for (ConfigKey k : configKeys) { + if (PortRange.class.isAssignableFrom(k.getType()) || portsPattern.matcher(k.getName()).matches()) { + Object value = entity.config().get(k); + Maybe maybePortRange = TypeCoercions.tryCoerce(value, new TypeToken() { + }); + if (maybePortRange.isPresentAndNonNull()) { + PortRange p = maybePortRange.get(); + if (p != null && !p.isEmpty()) + ports.add(p.iterator().next()); + } + } + } + } + + log.debug("getRequiredOpenPorts detected default {} for {}", ports, entity); + return ports; + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6b43665f/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SameServerDriverLifecycleEffectorTasks.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SameServerDriverLifecycleEffectorTasks.java b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SameServerDriverLifecycleEffectorTasks.java index 9cd6149..178f471 100644 --- a/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SameServerDriverLifecycleEffectorTasks.java +++ b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SameServerDriverLifecycleEffectorTasks.java @@ -57,6 +57,7 @@ public class SameServerDriverLifecycleEffectorTasks extends MachineLifecycleEffe /** * @return the ports that this entity wants to use, aggregated for all its child entities. + * @see InboundPortsUtils#getRequiredOpenPorts(Entity, Boolean, String) */ protected Collection getRequiredOpenPorts() { Set result = Sets.newLinkedHashSet(); @@ -67,31 +68,21 @@ public class SameServerDriverLifecycleEffectorTasks extends MachineLifecycleEffe /** @return the ports required for a specific child entity */ protected Collection getRequiredOpenPorts(Entity entity) { - Set ports = MutableSet.of(22); - /* TODO: This won't work if there's a port collision, which will cause the corresponding port attribute - to be incremented until a free port is found. In that case the entity will use the free port, but the - firewall will open the initial port instead. Mostly a problem for SameServerEntity, localhost location. - */ - // TODO: Remove duplication between this and SoftwareProcessImpl.getRequiredOpenPorts - final Set> configKeys = entity.getEntityType().getConfigKeys(); - for (ConfigKey k: configKeys) { - if (PortRange.class.isAssignableFrom(k.getType()) || k.getName().matches(".*\\.port")) { - Object value = entity.config().get(k); - Maybe maybePortRange = TypeCoercions.tryCoerce(value, new TypeToken() {}); - if (maybePortRange.isPresentAndNonNull()) { - PortRange p = maybePortRange.get(); - if (p != null && !p.isEmpty()) { - ports.add(p.iterator().next()); - } - } - } - } + Set ports = MutableSet.of(); + addRequiredOpenPortsRecursively(entity, ports); + return ports; + } + + private void addRequiredOpenPortsRecursively(Entity entity, Set ports) { + ports.addAll(entity.getConfig(SameServerEntity.REQUIRED_OPEN_LOGIN_PORTS)); + Boolean portsAutoInfer = entity.getConfig(SameServerEntity.INBOUND_PORTS_AUTO_INFER); + String portsRegex = entity.getConfig(SameServerEntity.INBOUND_PORTS_CONFIG_REGEX); + ports.addAll(InboundPortsUtils.getRequiredOpenPorts(entity, portsAutoInfer, portsRegex)); LOG.debug("getRequiredOpenPorts detected default {} for {}", ports, entity); for (Entity child : entity.getChildren()) { - ports.addAll(getRequiredOpenPorts(child)); + addRequiredOpenPortsRecursively(child, ports); } - return ports; } @SuppressWarnings("unchecked") http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6b43665f/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SameServerEntity.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SameServerEntity.java b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SameServerEntity.java index ea82b3d..6395350 100644 --- a/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SameServerEntity.java +++ b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SameServerEntity.java @@ -18,6 +18,7 @@ */ package org.apache.brooklyn.entity.software.base; +import java.util.Collection; import java.util.Map; import org.apache.brooklyn.api.entity.Entity; @@ -59,6 +60,12 @@ public interface SameServerEntity extends Entity, Startable { ConfigKey UP_QUORUM_CHECK = ComputeServiceIndicatorsFromChildrenAndMembers.UP_QUORUM_CHECK; ConfigKey RUNNING_QUORUM_CHECK = ComputeServiceIndicatorsFromChildrenAndMembers.RUNNING_QUORUM_CHECK; + ConfigKey> REQUIRED_OPEN_LOGIN_PORTS = SoftwareProcess.REQUIRED_OPEN_LOGIN_PORTS; + + ConfigKey INBOUND_PORTS_CONFIG_REGEX = SoftwareProcess.INBOUND_PORTS_CONFIG_REGEX; + + ConfigKey INBOUND_PORTS_AUTO_INFER = SoftwareProcess.INBOUND_PORTS_AUTO_INFER; + AttributeSensor SERVICE_STATE_ACTUAL = Attributes.SERVICE_STATE_ACTUAL; @SuppressWarnings("rawtypes") http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6b43665f/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java index b14d6d8..0478677 100644 --- a/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java +++ b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java @@ -20,14 +20,20 @@ package org.apache.brooklyn.entity.software.base; import java.util.Collection; import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; +import com.google.common.collect.Sets; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.location.MachineProvisioningLocation; +import org.apache.brooklyn.api.location.PortRange; import org.apache.brooklyn.api.sensor.AttributeSensor; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.annotation.Effector; import org.apache.brooklyn.core.config.ConfigKeys; +import org.apache.brooklyn.core.config.ConfigUtils; import org.apache.brooklyn.core.config.MapConfigKey; +import org.apache.brooklyn.core.entity.AbstractEntity; import org.apache.brooklyn.core.entity.Attributes; import org.apache.brooklyn.core.entity.BrooklynConfigKeys; import org.apache.brooklyn.core.entity.lifecycle.Lifecycle; @@ -36,7 +42,10 @@ import org.apache.brooklyn.core.entity.trait.Startable; import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey; import org.apache.brooklyn.core.sensor.Sensors; import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.collections.MutableSet; import org.apache.brooklyn.util.core.flags.SetFromFlag; +import org.apache.brooklyn.util.core.flags.TypeCoercions; +import org.apache.brooklyn.util.guava.Maybe; import org.apache.brooklyn.util.time.Duration; import com.google.common.annotations.Beta; @@ -50,13 +59,20 @@ public interface SoftwareProcess extends Entity, Startable { AttributeSensor SUBNET_HOSTNAME = Attributes.SUBNET_HOSTNAME; AttributeSensor SUBNET_ADDRESS = Attributes.SUBNET_ADDRESS; - @SuppressWarnings("serial") ConfigKey> REQUIRED_OPEN_LOGIN_PORTS = ConfigKeys.newConfigKey( new TypeToken>() {}, "requiredOpenLoginPorts", "The port(s) to be opened, to allow login", ImmutableSet.of(22)); + ConfigKey INBOUND_PORTS_CONFIG_REGEX = ConfigKeys.newStringConfigKey("inboundPorts.configRegex", + "Regex governing the opening of ports based on sensor names", + ".*\\.port"); + + ConfigKey INBOUND_PORTS_AUTO_INFER = ConfigKeys.newBooleanConfigKey("inboundPorts.autoInfer", + "If set to false turns off the opening of ports based on naming convention, and also those that are of type PortRange in Java entities", + true); + @SetFromFlag("startTimeout") ConfigKey START_TIMEOUT = BrooklynConfigKeys.START_TIMEOUT; @@ -300,12 +316,12 @@ public interface SoftwareProcess extends Entity, Startable { AttributeSensor PROVISIONING_LOCATION = Sensors.newSensor( MachineProvisioningLocation.class, "softwareservice.provisioningLocation", "Location used to provision a machine where this is running"); - AttributeSensor SERVICE_PROCESS_IS_RUNNING = Sensors.newBooleanSensor("service.process.isRunning", + AttributeSensor SERVICE_PROCESS_IS_RUNNING = Sensors.newBooleanSensor("service.process.isRunning", "Whether the process for the service is confirmed as running"); - + AttributeSensor SERVICE_STATE_ACTUAL = Attributes.SERVICE_STATE_ACTUAL; AttributeSensor SERVICE_STATE_EXPECTED = Attributes.SERVICE_STATE_EXPECTED; - + AttributeSensor PID_FILE = Sensors.newStringSensor("softwareprocess.pid.file", "PID file"); @Beta @@ -319,14 +335,14 @@ public interface SoftwareProcess extends Entity, Startable { "Whether to restart/replace the machine provisioned for this entity: 'true', 'false', or 'auto' are supported, " + "with the default being 'auto' which means to restart or reprovision the machine if there is no simpler way known to restart the entity " + "(for example, if the machine is unhealthy, it would not be possible to restart the process, not even via a stop-then-start sequence); " - + "if the machine was not provisioned for this entity, this parameter has no effect", + + "if the machine was not provisioned for this entity, this parameter has no effect", RestartMachineMode.AUTO.toString().toLowerCase()); - + // we supply a typed variant for retrieval; we want the untyped (above) to use lower case as the default in the GUI - // (very hard if using enum, since enum takes the name, and RendererHints do not apply to parameters) + // (very hard if using enum, since enum takes the name, and RendererHints do not apply to parameters) @Beta /** @since 0.7.0 semantics of parameters to restart being explored */ public static final ConfigKey RESTART_MACHINE_TYPED = ConfigKeys.newConfigKey(RestartMachineMode.class, "restartMachine"); - + public enum RestartMachineMode { TRUE, FALSE, AUTO } } @@ -349,7 +365,7 @@ public interface SoftwareProcess extends Entity, Startable { "IF_NOT_STOPPED stops the machine only if the entity is not marked as stopped, " + "NEVER doesn't stop the machine.", StopMode.IF_NOT_STOPPED); } - + // NB: the START, STOP, and RESTART effectors themselves are (re)defined by MachineLifecycleEffectorTasks /** http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6b43665f/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java index d3e6593..c62cc3d 100644 --- a/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java +++ b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java @@ -27,6 +27,7 @@ import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.EntityLocal; @@ -498,35 +499,19 @@ public abstract class SoftwareProcessImpl extends AbstractEntity implements Soft return result.getAllConfigMutable(); } - /** returns the ports that this entity wants to use; - * default implementation returns {@link SoftwareProcess#REQUIRED_OPEN_LOGIN_PORTS} plus first value - * for each {@link org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey} config key {@link PortRange} - * plus any ports defined with a config keys ending in {@code .port}. + /** + * Returns the ports that this entity wants to be opened. + * @see InboundPortsUtils#getRequiredOpenPorts(Entity, Set, Boolean, String) + * @see #REQUIRED_OPEN_LOGIN_PORTS + * @see #INBOUND_PORTS_AUTO_INFER + * @see #INBOUND_PORTS_CONFIG_REGEX */ @SuppressWarnings("serial") protected Collection getRequiredOpenPorts() { Set ports = MutableSet.copyOf(getConfig(REQUIRED_OPEN_LOGIN_PORTS)); - Map, ?> allConfig = config().getBag().getAllConfigAsConfigKeyMap(); - Set> configKeys = Sets.newHashSet(allConfig.keySet()); - configKeys.addAll(getEntityType().getConfigKeys()); - - /* TODO: This won't work if there's a port collision, which will cause the corresponding port attribute - to be incremented until a free port is found. In that case the entity will use the free port, but the - firewall will open the initial port instead. Mostly a problem for SameServerEntity, localhost location. - */ - for (ConfigKey k: configKeys) { - if (PortRange.class.isAssignableFrom(k.getType()) || k.getName().matches(".*\\.port")) { - Object value = config().get(k); - Maybe maybePortRange = TypeCoercions.tryCoerce(value, new TypeToken() {}); - if (maybePortRange.isPresentAndNonNull()) { - PortRange p = maybePortRange.get(); - if (p != null && !p.isEmpty()) - ports.add(p.iterator().next()); - } - } - } - - log.debug("getRequiredOpenPorts detected default {} for {}", ports, this); + Boolean portsAutoInfer = getConfig(INBOUND_PORTS_AUTO_INFER); + String portsRegex = getConfig(INBOUND_PORTS_CONFIG_REGEX); + ports.addAll(InboundPortsUtils.getRequiredOpenPorts(this, config().getBag().getAllConfigAsConfigKeyMap().keySet(), portsAutoInfer, portsRegex)); return ports; }