You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by ha...@apache.org on 2015/08/07 01:59:54 UTC

[3/6] incubator-brooklyn git commit: package rename to org.apache.brooklyn: sandbox

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/070b5ca7/sandbox/extra/src/main/resources/brooklyn/entity/salt/minion
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/main/resources/brooklyn/entity/salt/minion b/sandbox/extra/src/main/resources/brooklyn/entity/salt/minion
deleted file mode 100644
index cff42c7..0000000
--- a/sandbox/extra/src/main/resources/brooklyn/entity/salt/minion
+++ /dev/null
@@ -1,52 +0,0 @@
-[#ftl]
-##
-# 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.
-#
-# SaltStack Minion Configuration
-#
-# /etc/salt/minion
-##
-
-# The salt master server
-master: ${entity.master.hostname}
-ipv6: False
-retry_dns: 30
-master_port: ${entity.master.saltPort,c} # 4506
-acceptance_wait_time: 30
-acceptance_wait_time_max: 300
-
-# Minion configuration
-id: ${entity.id}
-user: root
-backup_mode: minion
-
-# Directory settings
-root_dir: /
-pidfile: ${runDir}/salt-minion.pid
-pki_dir: ${runDir}/pki
-cachedir: ${runDir}/cache
-log_file: ${runDir}/minion.log
-key_logfile: ${runDir}/key.log
-
-#verify_env: True
-#cache_jobs: True # Debugging
-
-output: nested
-color: False
-log_level: info
-log_level_logfile: debug # Debugging

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/070b5ca7/sandbox/extra/src/main/resources/org/apache/brooklyn/entity/salt/master
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/main/resources/org/apache/brooklyn/entity/salt/master b/sandbox/extra/src/main/resources/org/apache/brooklyn/entity/salt/master
new file mode 100644
index 0000000..72d7eb9
--- /dev/null
+++ b/sandbox/extra/src/main/resources/org/apache/brooklyn/entity/salt/master
@@ -0,0 +1,65 @@
+[#ftl]
+#
+# 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.
+#
+# /etc/salt/master
+##
+
+#interface: 0.0.0.0
+#ipv6: False
+#publish_port: ${entity.publishPort,c} # 4505
+
+#user: root
+#max_open_files: 100000
+#worker_threads: 5
+ret_port: ${entity.saltPort,c} # 4506
+
+root_dir: /
+pidfile: ${driver.pidFile}
+pki_dir: ${runDir}/pki
+cachedir: ${runDir}/cache
+log_file: ${driver.logFileLocation}
+key_logfile: ${runDir}/key.log
+
+#verify_env: True
+#keep_jobs: 24
+
+#timeout: 5
+#loop_interval: 60
+
+output: nested
+color: False
+log_level: info
+log_level_logfile: debug # Debugging
+
+#job_cache: True
+#minion_data_cache: True
+
+#open_mode: False
+#auto_accept: False
+#autosign_file: autosign.conf
+#permissive_pki_access: False
+
+fileserver_backend:
+  - git
+
+gitfs_remotes:
+  - git://github.com/saltstack/salt-states.git
+  - git://github.com/saltstack-formulas/postgres-formula.git
+  - ${entity.remoteUrl}
+  # TODO iterate through formula URLs

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/070b5ca7/sandbox/extra/src/main/resources/org/apache/brooklyn/entity/salt/masterless
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/main/resources/org/apache/brooklyn/entity/salt/masterless b/sandbox/extra/src/main/resources/org/apache/brooklyn/entity/salt/masterless
new file mode 100644
index 0000000..ba41c6e
--- /dev/null
+++ b/sandbox/extra/src/main/resources/org/apache/brooklyn/entity/salt/masterless
@@ -0,0 +1,53 @@
+[#ftl]
+##
+#
+# 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.
+#
+# SaltStack Masterless Minion Configuration
+#
+# /etc/salt/minion
+##
+
+# Minion configuration
+id: ${entity.id}
+user: root
+backup_mode: minion
+
+# Directory settings
+root_dir: /
+pidfile: ${runDir}/salt-minion.pid
+pki_dir: ${runDir}/pki
+cachedir: ${runDir}/cache
+log_file: ${runDir}/minion.log
+key_logfile: ${runDir}/key.log
+
+file_client: local
+file_roots:
+  base:
+    - ${runDir}/base
+[#list formulas?keys as formulaName]
+    - ${installDir}/${formulaName}
+[/#list]
+
+#verify_env: True
+#cache_jobs: True # Debugging
+
+output: nested
+color: False
+log_level: info
+log_level_logfile: debug # Debugging

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/070b5ca7/sandbox/extra/src/main/resources/org/apache/brooklyn/entity/salt/minion
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/main/resources/org/apache/brooklyn/entity/salt/minion b/sandbox/extra/src/main/resources/org/apache/brooklyn/entity/salt/minion
new file mode 100644
index 0000000..cff42c7
--- /dev/null
+++ b/sandbox/extra/src/main/resources/org/apache/brooklyn/entity/salt/minion
@@ -0,0 +1,52 @@
+[#ftl]
+##
+# 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.
+#
+# SaltStack Minion Configuration
+#
+# /etc/salt/minion
+##
+
+# The salt master server
+master: ${entity.master.hostname}
+ipv6: False
+retry_dns: 30
+master_port: ${entity.master.saltPort,c} # 4506
+acceptance_wait_time: 30
+acceptance_wait_time_max: 300
+
+# Minion configuration
+id: ${entity.id}
+user: root
+backup_mode: minion
+
+# Directory settings
+root_dir: /
+pidfile: ${runDir}/salt-minion.pid
+pki_dir: ${runDir}/pki
+cachedir: ${runDir}/cache
+log_file: ${runDir}/minion.log
+key_logfile: ${runDir}/key.log
+
+#verify_env: True
+#cache_jobs: True # Debugging
+
+output: nested
+color: False
+log_level: info
+log_level_logfile: debug # Debugging

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/070b5ca7/sandbox/extra/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlSaltLiveTest.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlSaltLiveTest.java b/sandbox/extra/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlSaltLiveTest.java
deleted file mode 100644
index a44efa9..0000000
--- a/sandbox/extra/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlSaltLiveTest.java
+++ /dev/null
@@ -1,109 +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 brooklyn.entity.database.postgresql;
-
-import java.util.Random;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.database.VogellaExampleAccess;
-import brooklyn.entity.effector.EffectorTasks;
-import brooklyn.entity.proxying.EntitySpec;
-import brooklyn.entity.salt.SaltConfig;
-import brooklyn.entity.salt.SaltLiveTestSupport;
-import brooklyn.entity.software.SshEffectorTasks;
-import brooklyn.location.PortRange;
-import brooklyn.location.basic.PortRanges;
-import brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.task.system.ProcessTaskWrapper;
-import brooklyn.util.time.Duration;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * Tests Salt installation of {@link PostgreSqlNode} entity.
- */
-public class PostgreSqlSaltLiveTest extends SaltLiveTestSupport {
-
-    private static final Logger log = LoggerFactory.getLogger(PostgreSqlSaltLiveTest.class);
-
-    private PostgreSqlNode psql;
-
-    @Override
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        try {
-            if (psql != null) psql.stop();
-        } finally {
-            super.tearDown();
-        }
-    }
-
-    @Test(groups="Live")
-    public void testPostgresStartsAndStops() throws Exception {
-        psql = app.createAndManageChild(EntitySpec.create(PostgreSqlNode.class, PostgreSqlNodeSaltImpl.class)
-                .configure(SaltConfig.MASTERLESS_MODE, true));
-
-        app.start(ImmutableList.of(targetLocation));
-
-        Entities.submit(psql, SshEffectorTasks.ssh("ps aux | grep [p]ostgres").requiringExitCodeZero());
-        SshMachineLocation targetMachine = EffectorTasks.getSshMachine(psql);
-
-        psql.stop();
-
-        try {
-            // if host is still contactable ensure postgres is not running
-            ProcessTaskWrapper<Integer> t = Entities.submit(app, SshEffectorTasks.ssh("ps aux | grep [p]ostgres").machine(targetMachine).allowingNonZeroExitCode());
-            t.getTask().blockUntilEnded(Duration.TEN_SECONDS);
-            if (!t.isDone()) {
-                Assert.fail("Task not finished yet: "+t.getTask());
-            }
-            Assert.assertNotEquals(t.get(), (Integer)0, "Task ended with code "+t.get()+"; output: "+t.getStdout() );
-        } catch (Exception e) {
-            // host has been killed, that is fine
-            log.info("Machine "+targetMachine+" destroyed on stop (expected - "+e+")");
-        }
-    }
-
-    @Test(groups="Live")
-    public void testPostgresScriptAndAccess() throws Exception {
-        SaltLiveTestSupport.createLocation(mgmt);
-        PortRange randomPort = PortRanges.fromString(""+(5420+new Random().nextInt(10))+"+");
-        psql = app.createAndManageChild(EntitySpec.create(PostgreSqlNode.class, PostgreSqlNodeSaltImpl.class)
-                .configure(SaltConfig.MASTERLESS_MODE, true)
-                .configure(PostgreSqlNode.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT)
-                .configure(PostgreSqlNode.POSTGRESQL_PORT, randomPort));
-
-        app.start(ImmutableList.of(targetLocation));
-
-        String url = psql.getAttribute(PostgreSqlNode.DATASTORE_URL);
-        log.info("Trying to connect to "+psql+" at "+url);
-        Assert.assertNotNull(url);
-        Assert.assertTrue(url.contains("542"));
-
-        new VogellaExampleAccess("org.postgresql.Driver", url).readModifyAndRevertDataBase();
-    }
-
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/070b5ca7/sandbox/extra/src/test/java/brooklyn/entity/salt/SaltConfigsTest.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/test/java/brooklyn/entity/salt/SaltConfigsTest.java b/sandbox/extra/src/test/java/brooklyn/entity/salt/SaltConfigsTest.java
deleted file mode 100644
index 6706748..0000000
--- a/sandbox/extra/src/test/java/brooklyn/entity/salt/SaltConfigsTest.java
+++ /dev/null
@@ -1,69 +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 brooklyn.entity.salt;
-
-import java.util.Map;
-import java.util.Set;
-
-import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.basic.ApplicationBuilder;
-import brooklyn.entity.basic.Entities;
-import brooklyn.test.entity.TestApplication;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-
-public class SaltConfigsTest {
-
-    private TestApplication app = null;
-
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() {
-        if (app!=null) Entities.destroyAll(app.getManagementContext());
-        app = null;
-    }
-
-    @Test
-    public void testAddToRunList() {
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
-        SaltConfigs.addToRunList(app, "a", "b");
-        Set<? extends String> runs = app.getConfig(SaltConfig.SALT_RUN_LIST);
-        Assert.assertEquals(runs, ImmutableSet.of("a", "b"));
-    }
-
-    @Test
-    public void testAddToFormulas() {
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
-        SaltConfigs.addToFormulas(app, "k1", "v1");
-        SaltConfigs.addToFormulas(app, "k2", "v2");
-        Map<String, String> formulas = app.getConfig(SaltConfig.SALT_FORMULAS);
-        Assert.assertEquals(formulas, ImmutableMap.of("k1", "v1", "k2", "v2"));
-    }
-
-    @Test
-    public void testAddLaunchAttributes() {
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
-        SaltConfigs.addLaunchAttributes(app, ImmutableMap.of("k1", "v1"));
-        Map<String, Object> attribs = app.getConfig(SaltConfig.SALT_LAUNCH_ATTRIBUTES);
-        Assert.assertEquals(attribs, ImmutableMap.of("k1", "v1"));
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/070b5ca7/sandbox/extra/src/test/java/brooklyn/entity/salt/SaltLiveTestSupport.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/test/java/brooklyn/entity/salt/SaltLiveTestSupport.java b/sandbox/extra/src/test/java/brooklyn/entity/salt/SaltLiveTestSupport.java
deleted file mode 100644
index 6cb7409..0000000
--- a/sandbox/extra/src/test/java/brooklyn/entity/salt/SaltLiveTestSupport.java
+++ /dev/null
@@ -1,68 +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 brooklyn.entity.salt;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.BeforeMethod;
-
-import brooklyn.entity.BrooklynAppLiveTestSupport;
-import brooklyn.location.Location;
-import brooklyn.location.MachineProvisioningLocation;
-import brooklyn.location.basic.SshMachineLocation;
-import brooklyn.management.ManagementContext;
-
-public class SaltLiveTestSupport extends BrooklynAppLiveTestSupport {
-
-    private static final Logger log = LoggerFactory.getLogger(SaltLiveTestSupport.class);
-
-    protected MachineProvisioningLocation<? extends SshMachineLocation> targetLocation;
-
-    @Override
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception {
-        super.setUp();
-
-        targetLocation = createLocation();
-    }
-
-    protected MachineProvisioningLocation<? extends SshMachineLocation> createLocation() {
-        return createLocation(mgmt);
-    }
-
-    /**
-     * Convenience for setting up a pre-built or fixed IP machine.
-     * <p>
-     * Useful if you are unable to set up Salt on localhost,
-     * and for ensuring tests against Salt always use the same
-     * configured location.
-     */
-    @SuppressWarnings("unchecked")
-    public static MachineProvisioningLocation<? extends SshMachineLocation> createLocation(ManagementContext mgmt) {
-        Location bestLocation = mgmt.getLocationRegistry().resolveIfPossible("named:SaltTests");
-        if (bestLocation==null) {
-            log.info("using AWS for salt tests because named:SaltTests does not exist");
-            bestLocation = mgmt.getLocationRegistry().resolveIfPossible("jclouds:aws-ec2:us-east-1");
-        }
-        if (bestLocation==null) {
-            throw new IllegalStateException("Need a location called named:SaltTests or AWS configured for these tests");
-        }
-        return (MachineProvisioningLocation<? extends SshMachineLocation>)bestLocation;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/070b5ca7/sandbox/extra/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSaltLiveTest.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSaltLiveTest.java b/sandbox/extra/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSaltLiveTest.java
new file mode 100644
index 0000000..250cc03
--- /dev/null
+++ b/sandbox/extra/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSaltLiveTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.database.postgresql;
+
+import java.util.Random;
+
+import org.apache.brooklyn.entity.database.postgresql.PostgreSqlNodeSaltImpl;
+import org.apache.brooklyn.entity.salt.SaltConfig;
+import org.apache.brooklyn.entity.salt.SaltLiveTestSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.database.VogellaExampleAccess;
+import brooklyn.entity.database.postgresql.PostgreSqlIntegrationTest;
+import brooklyn.entity.database.postgresql.PostgreSqlNode;
+import brooklyn.entity.effector.EffectorTasks;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.software.SshEffectorTasks;
+import brooklyn.location.PortRange;
+import brooklyn.location.basic.PortRanges;
+import brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.task.system.ProcessTaskWrapper;
+import brooklyn.util.time.Duration;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Tests Salt installation of {@link PostgreSqlNode} entity.
+ */
+public class PostgreSqlSaltLiveTest extends SaltLiveTestSupport {
+
+    private static final Logger log = LoggerFactory.getLogger(PostgreSqlSaltLiveTest.class);
+
+    private PostgreSqlNode psql;
+
+    @Override
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        try {
+            if (psql != null) psql.stop();
+        } finally {
+            super.tearDown();
+        }
+    }
+
+    @Test(groups="Live")
+    public void testPostgresStartsAndStops() throws Exception {
+        psql = app.createAndManageChild(EntitySpec.create(PostgreSqlNode.class, PostgreSqlNodeSaltImpl.class)
+                .configure(SaltConfig.MASTERLESS_MODE, true));
+
+        app.start(ImmutableList.of(targetLocation));
+
+        Entities.submit(psql, SshEffectorTasks.ssh("ps aux | grep [p]ostgres").requiringExitCodeZero());
+        SshMachineLocation targetMachine = EffectorTasks.getSshMachine(psql);
+
+        psql.stop();
+
+        try {
+            // if host is still contactable ensure postgres is not running
+            ProcessTaskWrapper<Integer> t = Entities.submit(app, SshEffectorTasks.ssh("ps aux | grep [p]ostgres").machine(targetMachine).allowingNonZeroExitCode());
+            t.getTask().blockUntilEnded(Duration.TEN_SECONDS);
+            if (!t.isDone()) {
+                Assert.fail("Task not finished yet: "+t.getTask());
+            }
+            Assert.assertNotEquals(t.get(), (Integer)0, "Task ended with code "+t.get()+"; output: "+t.getStdout() );
+        } catch (Exception e) {
+            // host has been killed, that is fine
+            log.info("Machine "+targetMachine+" destroyed on stop (expected - "+e+")");
+        }
+    }
+
+    @Test(groups="Live")
+    public void testPostgresScriptAndAccess() throws Exception {
+        SaltLiveTestSupport.createLocation(mgmt);
+        PortRange randomPort = PortRanges.fromString(""+(5420+new Random().nextInt(10))+"+");
+        psql = app.createAndManageChild(EntitySpec.create(PostgreSqlNode.class, PostgreSqlNodeSaltImpl.class)
+                .configure(SaltConfig.MASTERLESS_MODE, true)
+                .configure(PostgreSqlNode.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT)
+                .configure(PostgreSqlNode.POSTGRESQL_PORT, randomPort));
+
+        app.start(ImmutableList.of(targetLocation));
+
+        String url = psql.getAttribute(PostgreSqlNode.DATASTORE_URL);
+        log.info("Trying to connect to "+psql+" at "+url);
+        Assert.assertNotNull(url);
+        Assert.assertTrue(url.contains("542"));
+
+        new VogellaExampleAccess("org.postgresql.Driver", url).readModifyAndRevertDataBase();
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/070b5ca7/sandbox/extra/src/test/java/org/apache/brooklyn/entity/salt/SaltConfigsTest.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/test/java/org/apache/brooklyn/entity/salt/SaltConfigsTest.java b/sandbox/extra/src/test/java/org/apache/brooklyn/entity/salt/SaltConfigsTest.java
new file mode 100644
index 0000000..cf1a800
--- /dev/null
+++ b/sandbox/extra/src/test/java/org/apache/brooklyn/entity/salt/SaltConfigsTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.salt;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.entity.salt.SaltConfig;
+import org.apache.brooklyn.entity.salt.SaltConfigs;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.ApplicationBuilder;
+import brooklyn.entity.basic.Entities;
+import brooklyn.test.entity.TestApplication;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public class SaltConfigsTest {
+
+    private TestApplication app = null;
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() {
+        if (app!=null) Entities.destroyAll(app.getManagementContext());
+        app = null;
+    }
+
+    @Test
+    public void testAddToRunList() {
+        app = ApplicationBuilder.newManagedApp(TestApplication.class);
+        SaltConfigs.addToRunList(app, "a", "b");
+        Set<? extends String> runs = app.getConfig(SaltConfig.SALT_RUN_LIST);
+        Assert.assertEquals(runs, ImmutableSet.of("a", "b"));
+    }
+
+    @Test
+    public void testAddToFormulas() {
+        app = ApplicationBuilder.newManagedApp(TestApplication.class);
+        SaltConfigs.addToFormulas(app, "k1", "v1");
+        SaltConfigs.addToFormulas(app, "k2", "v2");
+        Map<String, String> formulas = app.getConfig(SaltConfig.SALT_FORMULAS);
+        Assert.assertEquals(formulas, ImmutableMap.of("k1", "v1", "k2", "v2"));
+    }
+
+    @Test
+    public void testAddLaunchAttributes() {
+        app = ApplicationBuilder.newManagedApp(TestApplication.class);
+        SaltConfigs.addLaunchAttributes(app, ImmutableMap.of("k1", "v1"));
+        Map<String, Object> attribs = app.getConfig(SaltConfig.SALT_LAUNCH_ATTRIBUTES);
+        Assert.assertEquals(attribs, ImmutableMap.of("k1", "v1"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/070b5ca7/sandbox/extra/src/test/java/org/apache/brooklyn/entity/salt/SaltLiveTestSupport.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/test/java/org/apache/brooklyn/entity/salt/SaltLiveTestSupport.java b/sandbox/extra/src/test/java/org/apache/brooklyn/entity/salt/SaltLiveTestSupport.java
new file mode 100644
index 0000000..8fbc14f
--- /dev/null
+++ b/sandbox/extra/src/test/java/org/apache/brooklyn/entity/salt/SaltLiveTestSupport.java
@@ -0,0 +1,68 @@
+/*
+ * 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.salt;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.BeforeMethod;
+
+import brooklyn.entity.BrooklynAppLiveTestSupport;
+import brooklyn.location.Location;
+import brooklyn.location.MachineProvisioningLocation;
+import brooklyn.location.basic.SshMachineLocation;
+import brooklyn.management.ManagementContext;
+
+public class SaltLiveTestSupport extends BrooklynAppLiveTestSupport {
+
+    private static final Logger log = LoggerFactory.getLogger(SaltLiveTestSupport.class);
+
+    protected MachineProvisioningLocation<? extends SshMachineLocation> targetLocation;
+
+    @Override
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        super.setUp();
+
+        targetLocation = createLocation();
+    }
+
+    protected MachineProvisioningLocation<? extends SshMachineLocation> createLocation() {
+        return createLocation(mgmt);
+    }
+
+    /**
+     * Convenience for setting up a pre-built or fixed IP machine.
+     * <p>
+     * Useful if you are unable to set up Salt on localhost,
+     * and for ensuring tests against Salt always use the same
+     * configured location.
+     */
+    @SuppressWarnings("unchecked")
+    public static MachineProvisioningLocation<? extends SshMachineLocation> createLocation(ManagementContext mgmt) {
+        Location bestLocation = mgmt.getLocationRegistry().resolveIfPossible("named:SaltTests");
+        if (bestLocation==null) {
+            log.info("using AWS for salt tests because named:SaltTests does not exist");
+            bestLocation = mgmt.getLocationRegistry().resolveIfPossible("jclouds:aws-ec2:us-east-1");
+        }
+        if (bestLocation==null) {
+            throw new IllegalStateException("Need a location called named:SaltTests or AWS configured for these tests");
+        }
+        return (MachineProvisioningLocation<? extends SshMachineLocation>)bestLocation;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/070b5ca7/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixFeed.java
----------------------------------------------------------------------
diff --git a/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixFeed.java b/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixFeed.java
deleted file mode 100644
index 5fe96cd..0000000
--- a/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixFeed.java
+++ /dev/null
@@ -1,463 +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 brooklyn.entity.monitoring.zabbix;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.net.URI;
-import java.net.URL;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.http.client.HttpClient;
-import org.apache.http.impl.NoConnectionReuseStrategy;
-import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.Entity;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.EntityFunctions;
-import brooklyn.entity.basic.EntityLocal;
-import brooklyn.event.feed.AbstractFeed;
-import brooklyn.event.feed.AttributePollHandler;
-import brooklyn.event.feed.PollHandler;
-import brooklyn.event.feed.Poller;
-import brooklyn.event.feed.http.HttpValueFunctions;
-import brooklyn.location.Location;
-import brooklyn.location.MachineLocation;
-import brooklyn.location.access.BrooklynAccessUtils;
-import brooklyn.location.basic.SupportsPortForwarding;
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
-import brooklyn.util.net.Cidr;
-
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-import com.google.common.base.Objects;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicates;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import com.google.common.net.HostAndPort;
-import com.google.common.reflect.TypeToken;
-import com.google.gson.JsonObject;
-
-public class ZabbixFeed extends AbstractFeed {
-
-    public static final Logger log = LoggerFactory.getLogger(ZabbixFeed.class);
-
-    public static final String JSON_ITEM_GET =
-            "{ \"jsonrpc\":\"2.0\",\"method\":\"item.get\"," +
-                "\"params\":{\"output\":\"extend\"," +
-                    "\"filter\":{\"hostid\":[\"{{hostId}}\"],\"key_\":\"{{itemKey}}\"}}," +
-                "\"auth\":\"{{token}}\",\"id\":{{id}}}";
-    public static final String JSON_USER_LOGIN =
-            "{ \"jsonrpc\":\"2.0\",\"method\":\"user.login\"," +
-                "\"params\":{\"user\":\"{{username}}\",\"password\":\"{{password}}\"}," +
-                "\"id\":0 }";
-    public static final String JSON_HOST_CREATE =
-            "{ \"jsonrpc\":\"2.0\",\"method\":\"host.create\"," +
-                "\"params\":{\"host\":\"{{host}}\"," +
-                    "\"interfaces\":[{\"type\":1,\"main\":1,\"useip\":1,\"ip\":\"{{ip}}\",\"dns\":\"\",\"port\":\"{{port}}\"}]," +
-                    "\"groups\":[{\"groupid\":\"{{groupId}}\"}]," +
-                    "\"templates\":[{\"templateid\":\"{{templateId}}\"}]}," +
-                "\"auth\":\"{{token}}\",\"id\":{{id}}}";
-
-    private static final AtomicInteger id = new AtomicInteger(0);
-
-    @SuppressWarnings("serial")
-    public static final ConfigKey<Set<ZabbixPollConfig<?>>> POLLS = ConfigKeys.newConfigKey(
-            new TypeToken<Set<ZabbixPollConfig<?>>>() {},
-            "polls");
-
-    @SuppressWarnings("serial")
-    public static final ConfigKey<Supplier<URI>> BASE_URI_PROVIDER = ConfigKeys.newConfigKey(
-            new TypeToken<Supplier<URI>>() {},
-            "baseUriProvider");
-    
-    public static final ConfigKey<Integer> GROUP_ID = ConfigKeys.newIntegerConfigKey("groupId");
-    
-    public static final ConfigKey<Integer> TEMPLATE_ID = ConfigKeys.newIntegerConfigKey("templateId");
-
-    @SuppressWarnings("serial")
-    public static final ConfigKey<Function<? super EntityLocal, String>> UNIQUE_HOSTNAME_GENERATOR = ConfigKeys.newConfigKey(
-            new TypeToken<Function<? super EntityLocal, String>>() {},
-            "uniqueHostnameGenerator");
-
-    public static Builder<ZabbixFeed, ?> builder() {
-        return new ConcreteBuilder();
-    }
-
-    private static class ConcreteBuilder extends Builder<ZabbixFeed, ConcreteBuilder> {
-    }
-
-    public static class Builder<T extends ZabbixFeed, B extends Builder<T,B>> {
-        private EntityLocal entity;
-        private Supplier<URI> baseUriProvider;
-        private long period = 500;
-        private TimeUnit periodUnits = TimeUnit.MILLISECONDS;
-        private List<ZabbixPollConfig<?>> polls = Lists.newArrayList();
-        private URI baseUri;
-        private boolean suspended = false;
-        private volatile boolean built;
-        private ZabbixServer server;
-        private String username;
-        private String password;
-        private Integer sessionTimeout;
-        private Integer groupId;
-        private Integer templateId;
-        private Function<? super EntityLocal, String> uniqueHostnameGenerator = Functions.compose(
-                EntityFunctions.id(), 
-                EntityFunctions.locationMatching(Predicates.instanceOf(MachineLocation.class)));
-        private String uniqueTag;
-
-        @SuppressWarnings("unchecked")
-        protected B self() {
-           return (B) this;
-        }
-
-        public B entity(EntityLocal val) {
-            this.entity = val;
-            return self();
-        }
-        public B baseUri(Supplier<URI> val) {
-            if (baseUri!=null && val!=null)
-                throw new IllegalStateException("Builder cannot take both a URI and a URI Provider");
-            this.baseUriProvider = val;
-            return self();
-        }
-        public B baseUri(URI val) {
-            if (baseUriProvider!=null && val!=null)
-                throw new IllegalStateException("Builder cannot take both a URI and a URI Provider");
-            this.baseUri = val;
-            return self();
-        }
-        public B baseUrl(URL val) {
-            return baseUri(URI.create(val.toString()));
-        }
-        public B baseUri(String val) {
-            return baseUri(URI.create(val));
-        }
-        public B period(long millis) {
-            return period(millis, TimeUnit.MILLISECONDS);
-        }
-        public B period(long val, TimeUnit units) {
-            this.period = val;
-            this.periodUnits = units;
-            return self();
-        }
-        public B poll(ZabbixPollConfig<?> config) {
-            polls.add(config);
-            return self();
-        }
-        public B suspended() {
-            return suspended(true);
-        }
-        public B suspended(boolean startsSuspended) {
-            this.suspended = startsSuspended;
-            return self();
-        }
-
-        public B server(final ZabbixServer server) {
-            this.server = server;
-            baseUri(URI.create(server.getConfig(ZabbixServer.ZABBIX_SERVER_API_URL)));
-            username(server.getConfig(ZabbixServer.ZABBIX_SERVER_USERNAME));
-            password(server.getConfig(ZabbixServer.ZABBIX_SERVER_PASSWORD));
-            sessionTimeout(server.getConfig(ZabbixServer.ZABBIX_SESSION_TIMEOUT));
-            return self();
-        }
-        public B username(String username) {
-            this.username = username;
-            return self();
-        }
-        public B password(String password) {
-            this.password = password;
-            return self();
-        }
-        public B sessionTimeout(Integer sessionTimeout) {
-            this.sessionTimeout = sessionTimeout;
-            return self();
-        }
-        public B groupId(Integer groupId) {
-            this.groupId = groupId;
-            return self();
-        }
-        public B templateId(Integer templateId) {
-            this.templateId = templateId;
-            return self();
-        }
-        public B register(Integer groupId, Integer templateId) {
-            this.groupId = groupId;
-            this.templateId = templateId;
-            return self();
-        }
-        /**
-         * For generating the name to be used when registering the zabbix agent with the zabbix server.
-         * When called, guarantees that the entity will have a {@link MachineLocation} (see {@link Entity#getLocations()}).
-         * Must return a non-empty string that will be unique across all machines where zabbix agents are installed.
-         */
-        public B uniqueHostnameGenerator(Function<? super EntityLocal, String> val) {
-            this.uniqueHostnameGenerator = checkNotNull(val, "uniqueHostnameGenerator");
-            return self();
-        }
-        
-        public Builder uniqueTag(String uniqueTag) {
-            this.uniqueTag = uniqueTag;
-            return this;
-        }
-        
-        @SuppressWarnings("unchecked")
-        public T build() {
-            // If server not set and other config not available, try to obtain from entity config
-            if (server == null
-                    && (baseUri == null || baseUriProvider == null)
-                    && username == null && password == null && sessionTimeout == null) {
-                ZabbixServer server = Preconditions.checkNotNull(entity.getConfig(ZabbixMonitored.ZABBIX_SERVER), "The ZABBIX_SERVER config key must be set on the entity");
-                server(server);
-            }
-            // Now create feed
-            T result = (T) new ZabbixFeed(this);
-            result.setEntity(checkNotNull(entity, "entity"));
-            built = true;
-            if (suspended) result.suspend();
-            result.start();
-            return result;
-        }
-        @Override
-        protected void finalize() {
-            if (!built) log.warn("ZabbixFeed.Builder created, but build() never called");
-        }
-    }
-
-    protected static class ZabbixPollIdentifier {
-        final String itemName;
-
-        protected ZabbixPollIdentifier(String itemName) {
-            this.itemName = checkNotNull(itemName, "itemName");
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hashCode(itemName);
-        }
-
-        @Override
-        public boolean equals(Object other) {
-            if (!(other instanceof ZabbixPollIdentifier)) {
-                return false;
-            }
-            ZabbixPollIdentifier o = (ZabbixPollIdentifier) other;
-            return Objects.equal(itemName, o.itemName);
-        }
-    }
-
-    // Flag set when the Zabbix agent is registered for a host
-    protected final AtomicBoolean registered = new AtomicBoolean(false);
-
-    /**
-     * For rebind; do not call directly; use builder
-     */
-    public ZabbixFeed() {
-    }
-    
-    protected ZabbixFeed(final Builder<? extends ZabbixFeed, ?> builder) {
-        setConfig(BASE_URI_PROVIDER, builder.baseUriProvider);
-        if (builder.baseUri != null) {
-            if (builder.baseUriProvider != null) {
-                throw new IllegalStateException("Not permitted to supply baseUri and baseUriProvider");
-            }
-            setConfig(BASE_URI_PROVIDER, Suppliers.ofInstance(builder.baseUri));
-        } else {
-            setConfig(BASE_URI_PROVIDER, checkNotNull(builder.baseUriProvider, "baseUriProvider and baseUri"));
-        }
-
-        setConfig(GROUP_ID, checkNotNull(builder.groupId, "Zabbix groupId must be set"));
-        setConfig(TEMPLATE_ID, checkNotNull(builder.templateId, "Zabbix templateId must be set"));
-        setConfig(UNIQUE_HOSTNAME_GENERATOR, checkNotNull(builder.uniqueHostnameGenerator, "uniqueHostnameGenerator"));
-
-        Set<ZabbixPollConfig<?>> polls = Sets.newLinkedHashSet();
-        for (ZabbixPollConfig<?> config : builder.polls) {
-            @SuppressWarnings({ "unchecked", "rawtypes" })
-            ZabbixPollConfig<?> configCopy = new ZabbixPollConfig(config);
-            if (configCopy.getPeriod() < 0) configCopy.period(builder.period, builder.periodUnits);
-            polls.add(configCopy);
-        }
-        setConfig(POLLS, polls);
-        initUniqueTag(builder.uniqueTag, polls);
-    }
-
-    @Override
-    protected void preStart() {
-        final Supplier<URI> baseUriProvider = getConfig(BASE_URI_PROVIDER);
-        final Function<? super EntityLocal, String> uniqueHostnameGenerator = getConfig(UNIQUE_HOSTNAME_GENERATOR);
-        final Integer groupId = getConfig(GROUP_ID);
-        final Integer templateId = getConfig(TEMPLATE_ID);
-        final Set<ZabbixPollConfig<?>> polls = getConfig(POLLS);
-        
-        log.info("starting zabbix feed for {}", entity);
-
-        // TODO if supplier returns null, we may wish to defer initialization until url available?
-        // TODO for https should we really trust all?
-        final HttpClient httpClient = HttpTool.httpClientBuilder()
-                .trustAll()
-                .clientConnectionManager(new ThreadSafeClientConnManager())
-                .reuseStrategy(new NoConnectionReuseStrategy())
-                .uri(baseUriProvider.get())
-                .build();
-
-        // Registration job, calls Zabbix host.create API
-        final Callable<HttpToolResponse> registerJob = new Callable<HttpToolResponse>() {
-            @Override
-            public HttpToolResponse call() throws Exception {
-                if (!registered.get()) {
-                    // Find the first machine, if available
-                    Optional<Location> location = Iterables.tryFind(entity.getLocations(), Predicates.instanceOf(MachineLocation.class));
-                    if (!location.isPresent()) {
-                        return null; // Do nothing until location is present
-                    }
-                    MachineLocation machine = (MachineLocation) location.get();
-
-                    String host = uniqueHostnameGenerator.apply(entity);
-                    
-                    // Select address and port using port-forwarding if available
-                    String address = entity.getAttribute(Attributes.ADDRESS);
-                    Integer port = entity.getAttribute(ZabbixMonitored.ZABBIX_AGENT_PORT);
-                    if (machine instanceof SupportsPortForwarding) {
-                        Cidr management = entity.getConfig(BrooklynAccessUtils.MANAGEMENT_ACCESS_CIDR);
-                        HostAndPort forwarded = ((SupportsPortForwarding) machine).getSocketEndpointFor(management, port);
-                        address = forwarded.getHostText();
-                        port = forwarded.getPort();
-                    }
-
-                    // Fill in the JSON template and POST it
-                    byte[] body = JSON_HOST_CREATE
-                            .replace("{{token}}", entity.getConfig(ZabbixMonitored.ZABBIX_SERVER).getAttribute(ZabbixServer.ZABBIX_TOKEN))
-                            .replace("{{host}}", host)
-                            .replace("{{ip}}", address)
-                            .replace("{{port}}", Integer.toString(port))
-                            .replace("{{groupId}}", Integer.toString(groupId))
-                            .replace("{{templateId}}", Integer.toString(templateId))
-                            .replace("{{id}}", Integer.toString(id.incrementAndGet()))
-                            .getBytes();
-                    
-                    return HttpTool.httpPost(httpClient, baseUriProvider.get(), ImmutableMap.of("Content-Type", "application/json"), body);
-                }
-                return null;
-            }
-        };
-
-        // The handler for the registration job
-        PollHandler<? super HttpToolResponse> registrationHandler = new PollHandler<HttpToolResponse>() {
-            @Override
-            public void onSuccess(HttpToolResponse val) {
-                if (registered.get() || val == null) {
-                    return; // Skip if we are registered already or no data from job
-                }
-                JsonObject response = HttpValueFunctions.jsonContents().apply(val).getAsJsonObject();
-                if (response.has("error")) {
-                    // Parse the JSON error object and log the message
-                    JsonObject error = response.get("error").getAsJsonObject();
-                    String message = error.get("message").getAsString();
-                    String data = error.get("data").getAsString();
-                    log.warn("zabbix failed registering host - {}: {}", message, data);
-                } else if (response.has("result")) {
-                    // Parse the JSON result object and save the hostId
-                    JsonObject result = response.get("result").getAsJsonObject();
-                    String hostId = result.get("hostids").getAsJsonArray().get(0).getAsString();
-                    // Update the registered status if not set
-                    if (registered.compareAndSet(false, true)) {
-                        entity.setAttribute(ZabbixMonitored.ZABBIX_AGENT_HOSTID, hostId);
-                        log.info("zabbix registered host as id {}", hostId);
-                    }
-                } else {
-                    throw new IllegalStateException(String.format("zabbix host registration returned invalid result: %s", response.toString()));
-                }
-            }
-            @Override
-            public boolean checkSuccess(HttpToolResponse val) {
-                return (val.getResponseCode() == 200);
-            }
-            @Override
-            public void onFailure(HttpToolResponse val) {
-                log.warn("zabbix sever returned failure code: {}", val.getResponseCode());
-            }
-            @Override
-            public void onException(Exception exception) {
-                log.warn("zabbix exception registering host", exception);
-            }
-            @Override
-            public String toString() {
-                return super.toString()+"["+getDescription()+"]";
-            }
-            @Override
-            public String getDescription() {
-                return "Zabbix rest poll";
-            }
-        };
-
-        // Schedule registration attempt once per second
-        getPoller().scheduleAtFixedRate(registerJob, registrationHandler, 1000l); // TODO make configurable
-
-        // Create a polling job for each Zabbix metric
-        for (final ZabbixPollConfig<?> config : polls) {
-            Callable<HttpToolResponse> pollJob = new Callable<HttpToolResponse>() {
-                @Override
-                public HttpToolResponse call() throws Exception {
-                    if (registered.get()) {
-                        if (log.isTraceEnabled()) log.trace("zabbix polling {} for {}", entity, config);
-                        byte[] body = JSON_ITEM_GET
-                                .replace("{{token}}", entity.getConfig(ZabbixMonitored.ZABBIX_SERVER).getAttribute(ZabbixServer.ZABBIX_TOKEN))
-                                .replace("{{hostId}}", entity.getAttribute(ZabbixMonitored.ZABBIX_AGENT_HOSTID))
-                                .replace("{{itemKey}}", config.getItemKey())
-                                .replace("{{id}}", Integer.toString(id.incrementAndGet()))
-                                .getBytes();
-                        
-                        return HttpTool.httpPost(httpClient, baseUriProvider.get(), ImmutableMap.of("Content-Type", "application/json"), body);
-                    } else {
-                        throw new IllegalStateException("zabbix agent not yet registered");
-                    }
-                }
-            };
-
-            // Schedule the Zabbix polling job
-            AttributePollHandler<? super HttpToolResponse> pollHandler = new AttributePollHandler<HttpToolResponse>(config, entity, this);
-            long minPeriod = Integer.MAX_VALUE; // TODO make configurable
-            if (config.getPeriod() > 0) minPeriod = Math.min(minPeriod, config.getPeriod());
-            getPoller().scheduleAtFixedRate(pollJob, pollHandler, minPeriod);
-        }
-
-    }
-
-    @SuppressWarnings("unchecked")
-    protected Poller<HttpToolResponse> getPoller() {
-        return (Poller<HttpToolResponse>) super.getPoller();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/070b5ca7/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixMonitored.java
----------------------------------------------------------------------
diff --git a/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixMonitored.java b/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixMonitored.java
deleted file mode 100644
index fbaab5d..0000000
--- a/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixMonitored.java
+++ /dev/null
@@ -1,38 +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 brooklyn.entity.monitoring.zabbix;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.event.AttributeSensor;
-import brooklyn.event.basic.BasicAttributeSensor;
-import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-import brooklyn.util.flags.SetFromFlag;
-
-public interface ZabbixMonitored {
-
-    /** The entity representing the Zabbix server monitoring an entity. */
-    @SetFromFlag("zabbixServer")
-    ConfigKey<ZabbixServer> ZABBIX_SERVER = new BasicConfigKey<ZabbixServer>(ZabbixServer.class, "zabbix.server.entity", "Zabbix server for this entity");
-
-    PortAttributeSensorAndConfigKey ZABBIX_AGENT_PORT = new PortAttributeSensorAndConfigKey("zabbix.agent.port", "The port the Zabbix agent is listening on", "10050+");
-
-    AttributeSensor<String> ZABBIX_AGENT_HOSTID = new BasicAttributeSensor<String>(String.class, "zabbix.agent.hostid", "The hostId for a Zabbix monitored agent");
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/070b5ca7/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixPollConfig.java
----------------------------------------------------------------------
diff --git a/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixPollConfig.java b/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixPollConfig.java
deleted file mode 100644
index 743df8b..0000000
--- a/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixPollConfig.java
+++ /dev/null
@@ -1,75 +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 brooklyn.entity.monitoring.zabbix;
-
-import javax.annotation.Nullable;
-
-import brooklyn.event.AttributeSensor;
-import brooklyn.event.feed.PollConfig;
-import brooklyn.event.feed.http.HttpValueFunctions;
-import brooklyn.event.feed.http.JsonFunctions;
-import brooklyn.util.collections.MutableList;
-import brooklyn.util.http.HttpToolResponse;
-
-import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
-import com.google.gson.JsonElement;
-
-public class ZabbixPollConfig<T> extends PollConfig<HttpToolResponse, T, ZabbixPollConfig<T>> {
-
-    private String itemKey;
-
-    public ZabbixPollConfig(AttributeSensor<T> sensor) {
-        super(sensor);
-        // Add onSuccess method to extract the last value of the item
-        // FIXME Fix generics
-        onSuccess((Function)HttpValueFunctions.chain(
-                HttpValueFunctions.jsonContents(),
-                new Function<JsonElement, JsonElement>() {
-                    @Override
-                    public JsonElement apply(@Nullable JsonElement input) {
-                        Preconditions.checkNotNull(input, "JSON input");
-                        return input.getAsJsonObject().get("result")
-                                .getAsJsonArray().get(0)
-                                .getAsJsonObject().get("lastvalue");
-                    }
-                },
-                JsonFunctions.cast(getSensor().getType())));
-    }
-
-    public ZabbixPollConfig(ZabbixPollConfig<T> other) {
-        super(other);
-        this.itemKey = other.getItemKey();
-    }
-
-    public String getItemKey() {
-        return itemKey;
-    }
-
-    public ZabbixPollConfig<T> itemKey(String val) {
-        this.itemKey = val;
-        return this;
-    }
-
-    @Override
-    protected MutableList<Object> equalsFields() {
-        return super.equalsFields().appendIfNotNull(itemKey);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/070b5ca7/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixServer.java
----------------------------------------------------------------------
diff --git a/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixServer.java b/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixServer.java
deleted file mode 100644
index b5987c5..0000000
--- a/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixServer.java
+++ /dev/null
@@ -1,52 +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 brooklyn.entity.monitoring.zabbix;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.Entity;
-import brooklyn.entity.proxying.ImplementedBy;
-import brooklyn.event.AttributeSensor;
-import brooklyn.event.basic.BasicAttributeSensor;
-import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.util.flags.SetFromFlag;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-
-@ImplementedBy(ZabbixServerImpl.class)
-public interface ZabbixServer extends Entity {
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @SetFromFlag("filter")
-    ConfigKey<Predicate<? super Entity>> ENTITY_FILTER = new BasicConfigKey(Predicate.class, "zabbix.server.filter", "Filter for entities which will automatically be monitored", Predicates.instanceOf(ZabbixMonitored.class));
-
-    @SetFromFlag("serverApiUrl")
-    ConfigKey<String> ZABBIX_SERVER_API_URL = new BasicConfigKey<String>(String.class, "zabbix.server.apiUrl", "Main Zabbix server API URL");
-
-    @SetFromFlag("username")
-    ConfigKey<String> ZABBIX_SERVER_USERNAME = new BasicConfigKey<String>(String.class, "zabbix.server.username", "Zabbix server API login user");
-
-    @SetFromFlag("password")
-    ConfigKey<String> ZABBIX_SERVER_PASSWORD = new BasicConfigKey<String>(String.class, "zabbix.server.password", "Zabbix server API login password");
-
-    ConfigKey<Integer> ZABBIX_SESSION_TIMEOUT = new BasicConfigKey<Integer>(Integer.class, "zabbix.server.sessionTimeout", "Zabbix server API session timeout period (seconds)", 3600);
-
-    AttributeSensor<String> ZABBIX_TOKEN = new BasicAttributeSensor<String>(String.class, "zabbix.server.token", "Zabbix server API authentication token");
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/070b5ca7/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixServerImpl.java
----------------------------------------------------------------------
diff --git a/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixServerImpl.java b/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixServerImpl.java
deleted file mode 100644
index 43d5f64..0000000
--- a/sandbox/monitoring/src/main/java/brooklyn/entity/monitoring/zabbix/ZabbixServerImpl.java
+++ /dev/null
@@ -1,143 +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 brooklyn.entity.monitoring.zabbix;
-
-import java.util.List;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.Entity;
-import brooklyn.entity.basic.AbstractEntity;
-import brooklyn.entity.basic.DynamicGroup;
-import brooklyn.entity.group.AbstractMembershipTrackingPolicy;
-import brooklyn.entity.proxying.EntitySpec;
-import brooklyn.entity.trait.Startable;
-import brooklyn.event.feed.http.HttpFeed;
-import brooklyn.event.feed.http.HttpPollConfig;
-import brooklyn.event.feed.http.HttpValueFunctions;
-import brooklyn.location.Location;
-import brooklyn.location.basic.SshMachineLocation;
-import brooklyn.policy.PolicySpec;
-
-import com.google.common.base.Functions;
-import com.google.common.base.Optional;
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Multimap;
-
-public class ZabbixServerImpl extends AbstractEntity implements ZabbixServer {
-
-    private static final Logger log = LoggerFactory.getLogger(ZabbixServerImpl.class);
-
-    private Object[] mutex = new Object[0];
-    private DynamicGroup monitoredEntities;
-    private AgentTrackingPolicy policy;
-    private Multimap<Location, Entity> entityLocations = HashMultimap.create();
-
-    private transient HttpFeed login;
-
-    @Override
-    public void init() {
-        super.init();
-        Predicate<? super Entity> filter = getConfig(ENTITY_FILTER);
-        monitoredEntities = addChild(EntitySpec.create(DynamicGroup.class)
-                .configure(DynamicGroup.ENTITY_FILTER, filter)
-                .displayName("agents"));
-    }
-
-    @Override
-    public void onManagementStarted() {
-        final byte[] jsonData = ZabbixFeed.JSON_USER_LOGIN
-                .replace("{{username}}", getConfig(ZABBIX_SERVER_USERNAME))
-                .replace("{{password}}", getConfig(ZABBIX_SERVER_PASSWORD))
-                .getBytes();
-        login = HttpFeed.builder()
-                .entity(this)
-                .baseUri(getConfig(ZABBIX_SERVER_API_URL))
-                .headers(ImmutableMap.of("Content-Type", "application/json"))
-                .poll(new HttpPollConfig<String>(ZABBIX_TOKEN)
-                        .method("POST")
-                        .body(jsonData)
-                        .onFailure(Functions.constant(""))
-                        .onSuccess(HttpValueFunctions.jsonContents("result", String.class)))
-                .build();
-
-        policy = addPolicy(PolicySpec.create(AgentTrackingPolicy.class)
-                .displayName("Zabbix Agent Tracker")
-                .configure("group", monitoredEntities));
-
-        for (Entity each : monitoredEntities.getMembers()) {
-            added(each);
-        }
-
-        setAttribute(Startable.SERVICE_UP, true);
-    }
-
-    public static class AgentTrackingPolicy extends AbstractMembershipTrackingPolicy {
-        @Override
-        protected void onEntityChange(Entity member) {
-            ((ZabbixServerImpl)entity).added(member); }
-        @Override
-        protected void onEntityAdded(Entity member) {
-        } // Ignore
-        @Override
-        protected void onEntityRemoved(Entity member) {
-            ((ZabbixServerImpl)entity).removed(member);
-        }
-    }
-    
-    public void added(Entity member) {
-        synchronized (mutex) {
-            Optional<Location> location = Iterables.tryFind(member.getLocations(), Predicates.instanceOf(SshMachineLocation.class));
-            if (location.isPresent() && member.getAttribute(Startable.SERVICE_UP)) {
-                SshMachineLocation machine = (SshMachineLocation) location.get();
-                if (!entityLocations.containsKey(machine)) {
-                    entityLocations.put(machine, member);
-                    // Configure the Zabbix agent
-                    List<String> commands = ImmutableList.<String>builder()
-                            .add("sed -i.bk 's/\\$HOSTNAME/" + machine.getDisplayName() + "/' /etc/zabbix/zabbix_agentd.conf")
-                            .add("zabbix_agentd")
-                            .build();
-                    int result = machine.execCommands("configuring zabbix_agentd", commands);
-                    if (result == 0) {
-                        log.info("zabbix_agentd configured on {} at {}", member, machine);
-                    } else {
-                        log.warn("failed to configure zabbix_agentd on {}, status {}", machine, result);
-                    }
-                }
-            } else {
-                log.warn("zabbix added({}) called but no location or service not started", member);
-            }
-        }
-    }
-
-    public void removed(Entity member) {
-        synchronized (mutex) {
-            for (Location location : member.getLocations()) {
-                entityLocations.remove(location, member);
-            }
-        }
-    }
-
-}