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); - } - } - } - -}
