Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master 946b5dcf7 -> 05b95f377


Support softwareProcess config open/stop iptables

And also dontRequireTtyForSudo


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/90f18811
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/90f18811
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/90f18811

Branch: refs/heads/master
Commit: 90f18811328752fa99dad4af9f71a53135942f32
Parents: 42d6091
Author: Aled Sage <[email protected]>
Authored: Sat Jul 25 15:00:57 2015 +0100
Committer: Aled Sage <[email protected]>
Committed: Mon Jul 27 13:50:00 2015 +0100

----------------------------------------------------------------------
 .../brooklyn/entity/basic/SoftwareProcess.java  |  16 ++
 .../entity/software/MachineInitTasks.java       | 172 +++++++++++++++++++
 .../software/MachineLifecycleEffectorTasks.java |  41 ++++-
 .../webapp/tomcat/TomcatServerEc2LiveTest.java  |   1 +
 4 files changed, 222 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/90f18811/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java 
b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java
index 1de84de..1570355 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java
@@ -122,6 +122,22 @@ public interface SoftwareProcess extends Entity, Startable 
{
     @Deprecated
     ConfigKey<String> SUGGESTED_RUN_DIR = BrooklynConfigKeys.SUGGESTED_RUN_DIR;
 
+    public static final ConfigKey<Boolean> OPEN_IPTABLES = 
ConfigKeys.newBooleanConfigKey("openIptables", 
+            "Whether to open the INBOUND_PORTS via iptables rules; " +
+            "if true then ssh in to run iptables commands, as part of machine 
provisioning", false);
+
+    public static final ConfigKey<Boolean> STOP_IPTABLES = 
ConfigKeys.newBooleanConfigKey("stopIptables", 
+            "Whether to stop iptables entirely; " +
+            "if true then ssh in to stop the iptables service, as part of 
machine provisioning", false);
+
+    public static final ConfigKey<Boolean> DONT_REQUIRE_TTY_FOR_SUDO = 
ConfigKeys.newBooleanConfigKey("dontRequireTtyForSudo", 
+            "Whether to explicitly set /etc/sudoers, so don't need tty (will 
leave unchanged if 'false'); " +
+            "some machines require a tty for sudo; brooklyn by default does 
not use a tty " +
+            "(so that it can get separate error+stdout streams); you can 
enable a tty as an " +
+            "option to every ssh command, or you can do it once and " +
+            "modify the machine so that a tty is not subsequently required.",
+            false);
+    
     /**
      * Files to be copied to the server before pre-install.
      * <p>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/90f18811/software/base/src/main/java/brooklyn/entity/software/MachineInitTasks.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/software/MachineInitTasks.java 
b/software/base/src/main/java/brooklyn/entity/software/MachineInitTasks.java
new file mode 100644
index 0000000..dfcb61d
--- /dev/null
+++ b/software/base/src/main/java/brooklyn/entity/software/MachineInitTasks.java
@@ -0,0 +1,172 @@
+/*
+ * 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 brooklyn.entity.software;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import brooklyn.entity.basic.BrooklynTaskTags;
+import brooklyn.entity.basic.EntityInternal;
+import brooklyn.location.basic.SshMachineLocation;
+import brooklyn.management.Task;
+import brooklyn.util.net.Protocol;
+import brooklyn.util.ssh.BashCommands;
+import brooklyn.util.ssh.IptablesCommands;
+import brooklyn.util.ssh.IptablesCommands.Chain;
+import brooklyn.util.ssh.IptablesCommands.Policy;
+import brooklyn.util.task.DynamicTasks;
+import brooklyn.util.task.Tasks;
+import brooklyn.util.task.ssh.SshTasks;
+import brooklyn.util.text.Strings;
+
+/**
+ * 
+ */
+@Beta
+public class MachineInitTasks {
+
+    // TODO Move somewhere so code can also be called by JcloudsLocation!
+    
+    private static final Logger log = 
LoggerFactory.getLogger(MachineInitTasks.class);
+
+    protected EntityInternal entity() {
+        return (EntityInternal) 
BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
+    }
+
+    /**
+     * Returns a queued {@link Task} which opens the given ports in iptables 
on the given machine.
+     */
+    public Task<Void> openIptablesAsync(final Iterable<Integer> inboundPorts, 
final SshMachineLocation machine) {
+        return DynamicTasks.queue("open iptables 
"+toTruncatedString(inboundPorts, 6), new Callable<Void>() {
+            public Void call() {
+                openIptablesImpl(inboundPorts, machine);
+                return null;
+            }
+        });
+    }
+
+    /**
+     * Returns a queued {@link Task} which stops iptables on the given machine.
+     */
+    public Task<Void> stopIptablesAsync(final SshMachineLocation machine) {
+        return DynamicTasks.queue("stop iptables", new Callable<Void>() {
+            public Void call() {
+                stopIptablesImpl(machine);
+                return null;
+            }
+        });
+    }
+
+    /**
+     * See docs in {@link BashCommands#dontRequireTtyForSudo()}
+     */
+    public Task<Boolean> dontRequireTtyForSudoAsync(final SshMachineLocation 
machine) {
+        return SshTasks.dontRequireTtyForSudo(machine, 
true).newTask().asTask();
+    }
+
+    protected void openIptablesImpl(Iterable<Integer> inboundPorts, 
SshMachineLocation machine) {
+        if (inboundPorts == null || Iterables.isEmpty(inboundPorts)) {
+            log.info("No ports to open in iptables (no inbound ports) for {} 
at {}", machine, this);
+        } else {
+            log.info("Opening ports in iptables for {} at {}", entity(), 
machine);
+
+            List<String> iptablesRules = Lists.newArrayList();
+
+            if (isLocationFirewalldEnabled(machine)) {
+                for (Integer port : inboundPorts) {
+                    
iptablesRules.add(IptablesCommands.addFirewalldRule(Chain.INPUT, Protocol.TCP, 
port, Policy.ACCEPT));
+                 }
+            } else {
+                iptablesRules = 
createIptablesRulesForNetworkInterface(inboundPorts);
+                iptablesRules.add(IptablesCommands.saveIptablesRules());
+            }
+            List<String> batch = Lists.newArrayList();
+            // Some entities, such as Riak (erlang based) have a huge range of 
ports, which leads to a script that
+            // is too large to run (fails with a broken pipe). Batch the rules 
into batches of 50
+            for (String rule : iptablesRules) {
+                batch.add(rule);
+                if (batch.size() == 50) {
+                    machine.execCommands("Inserting iptables rules, 50 command 
batch", batch);
+                    batch.clear();
+                }
+            }
+            if (batch.size() > 0) {
+                machine.execCommands("Inserting iptables rules", batch);
+            }
+            machine.execCommands("List iptables rules", 
ImmutableList.of(IptablesCommands.listIptablesRule()));
+        }
+    }
+
+    protected void stopIptablesImpl(SshMachineLocation machine) {
+        log.info("Stopping iptables for {} at {}", entity(), machine);
+
+        List<String> cmds = ImmutableList.<String>of();
+        if (isLocationFirewalldEnabled(machine)) {
+            cmds = ImmutableList.of(IptablesCommands.firewalldServiceStop(), 
IptablesCommands.firewalldServiceStatus());
+        } else {
+            cmds = ImmutableList.of(IptablesCommands.iptablesServiceStop(), 
IptablesCommands.iptablesServiceStatus());
+        }
+        machine.execCommands("Stopping iptables", cmds);
+    }
+    
+    private List<String> 
createIptablesRulesForNetworkInterface(Iterable<Integer> ports) {
+        List<String> iptablesRules = Lists.newArrayList();
+        for (Integer port : ports) {
+           iptablesRules.add(IptablesCommands.insertIptablesRule(Chain.INPUT, 
Protocol.TCP, port, Policy.ACCEPT));
+        }
+        return iptablesRules;
+     }
+
+    public boolean isLocationFirewalldEnabled(SshMachineLocation location) {
+        int result = location.execCommands("checking if firewalld is active", 
+                ImmutableList.of(IptablesCommands.firewalldServiceIsActive()));
+        if (result == 0) {
+            return true;
+        }
+        
+        return false;
+    }
+    
+    protected String toTruncatedString(Iterable<?> vals, int maxShown) {
+        StringBuilder result = new StringBuilder("[");
+        int shown = 0;
+        for (Object val : (vals == null ? ImmutableList.of() : vals)) {
+            if (shown != 0) {
+                result.append(", ");
+            }
+            if (shown < maxShown) {
+                result.append(Strings.toString(val));
+                shown++;
+            } else {
+                result.append("...");
+                break;
+            }
+        }
+        result.append("]");
+        return result.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/90f18811/software/base/src/main/java/brooklyn/entity/software/MachineLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/software/MachineLifecycleEffectorTasks.java
 
b/software/base/src/main/java/brooklyn/entity/software/MachineLifecycleEffectorTasks.java
index 2ba42f7..ec3ae1c 100644
--- 
a/software/base/src/main/java/brooklyn/entity/software/MachineLifecycleEffectorTasks.java
+++ 
b/software/base/src/main/java/brooklyn/entity/software/MachineLifecycleEffectorTasks.java
@@ -25,11 +25,19 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
+
 import javax.annotation.Nullable;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.Effector;
 import brooklyn.entity.Entity;
@@ -62,6 +70,7 @@ import 
brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 import brooklyn.location.basic.Locations;
 import brooklyn.location.basic.Machines;
 import brooklyn.location.basic.SshMachineLocation;
+import brooklyn.location.cloud.CloudLocationConfig;
 import brooklyn.management.Task;
 import brooklyn.management.TaskFactory;
 import brooklyn.util.collections.MutableMap;
@@ -77,13 +86,6 @@ import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 
-import com.google.common.annotations.Beta;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-
 /**
  * Default skeleton for start/stop/restart tasks on machines.
  * <p>
@@ -116,6 +118,8 @@ public abstract class MachineLifecycleEffectorTasks {
     public static final ConfigKey<Duration> STOP_PROCESS_TIMEOUT = 
ConfigKeys.newConfigKey(Duration.class,
             "process.stop.timeout", "How long to wait for the processes to be 
stopped; use null to mean forever", Duration.TWO_MINUTES);
 
+    protected final MachineInitTasks machineInitTasks = new MachineInitTasks();
+    
     /** Attaches lifecycle effectors (start, restart, stop) to the given 
entity post-creation. */
     public void attachLifecycleEffectors(Entity entity) {
         ((EntityInternal) 
entity).getMutableEntityType().addEffector(newStartEffector());
@@ -344,6 +348,28 @@ public abstract class MachineLifecycleEffectorTasks {
                 entity().setAttribute(Attributes.SSH_ADDRESS, sshAddress);
             }
 
+            if 
(Boolean.TRUE.equals(entity().getConfig(SoftwareProcess.OPEN_IPTABLES))) {
+                if (machine instanceof SshMachineLocation) {
+                    Iterable<Integer> inboundPorts = (Iterable<Integer>) 
machine.config().get(CloudLocationConfig.INBOUND_PORTS);
+                    machineInitTasks.openIptablesAsync(inboundPorts, 
(SshMachineLocation)machine);
+                } else {
+                    log.warn("Ignoring flag OPEN_IPTABLES on non-ssh location 
{}", machine);
+                }
+            }
+            if 
(Boolean.TRUE.equals(entity().getConfig(SoftwareProcess.STOP_IPTABLES))) {
+                if (machine instanceof SshMachineLocation) {
+                    
machineInitTasks.stopIptablesAsync((SshMachineLocation)machine);
+                } else {
+                    log.warn("Ignoring flag STOP_IPTABLES on non-ssh location 
{}", machine);
+                }
+            }
+            if 
(Boolean.TRUE.equals(entity().getConfig(SoftwareProcess.DONT_REQUIRE_TTY_FOR_SUDO)))
 {
+                if (machine instanceof SshMachineLocation) {
+                    
machineInitTasks.dontRequireTtyForSudoAsync((SshMachineLocation)machine);
+                } else {
+                    log.warn("Ignoring flag DONT_REQUIRE_TTY_FOR_SUDO on 
non-ssh location {}", machine);
+                }
+            }
             resolveOnBoxDir(entity(), machine);
             preStartCustom(machine);
         }});
@@ -761,5 +787,4 @@ public abstract class MachineLifecycleEffectorTasks {
         }
         return new StopMachineDetails<Integer>("Decommissioned "+machine, 1);
     }
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/90f18811/software/webapp/src/test/java/brooklyn/entity/webapp/tomcat/TomcatServerEc2LiveTest.java
----------------------------------------------------------------------
diff --git 
a/software/webapp/src/test/java/brooklyn/entity/webapp/tomcat/TomcatServerEc2LiveTest.java
 
b/software/webapp/src/test/java/brooklyn/entity/webapp/tomcat/TomcatServerEc2LiveTest.java
index ec7f0a1..e0775b7 100644
--- 
a/software/webapp/src/test/java/brooklyn/entity/webapp/tomcat/TomcatServerEc2LiveTest.java
+++ 
b/software/webapp/src/test/java/brooklyn/entity/webapp/tomcat/TomcatServerEc2LiveTest.java
@@ -47,6 +47,7 @@ public class TomcatServerEc2LiveTest extends 
AbstractEc2LiveTest {
     @Override
     protected void doTest(Location loc) throws Exception {
         final TomcatServer server = 
app.createAndManageChild(EntitySpec.create(TomcatServer.class)
+                .configure(TomcatServer.OPEN_IPTABLES, true)
                 .configure("war", getTestWar()));
         
         app.start(ImmutableList.of(loc));

Reply via email to