You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2016/02/19 11:07:38 UTC
[1/7] brooklyn-library git commit: Moving Ansible as a module so it
matches the new CM structure
Repository: brooklyn-library
Updated Branches:
refs/heads/master 9fdf1dbf6 -> b8395ff30
Moving Ansible as a module so it matches the new CM structure
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-library/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-library/commit/c1a87838
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-library/tree/c1a87838
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-library/diff/c1a87838
Branch: refs/heads/master
Commit: c1a87838197f172ec5179831ba3824f0ead117a4
Parents: 121db32
Author: Yavor Yanchev <ya...@yanchev.com>
Authored: Tue Feb 16 11:10:07 2016 +0200
Committer: Yavor Yanchev <ya...@yanchev.com>
Committed: Wed Feb 17 11:43:03 2016 +0200
----------------------------------------------------------------------
software/cm/ansible/pom.xml | 84 ++++++++
.../entity/cm/ansible/AnsibleBashCommands.java | 38 ++++
.../entity/cm/ansible/AnsibleConfig.java | 66 ++++++
.../entity/cm/ansible/AnsibleEntity.java | 40 ++++
.../entity/cm/ansible/AnsibleEntityImpl.java | 61 ++++++
.../ansible/AnsibleLifecycleEffectorTasks.java | 203 +++++++++++++++++++
.../entity/cm/ansible/AnsiblePlaybookTasks.java | 109 ++++++++++
.../ansible/AnsibleEntityIntegrationTest.java | 116 +++++++++++
software/cm/pom.xml | 53 +----
.../entity/cm/ansible/AnsibleBashCommands.java | 38 ----
.../entity/cm/ansible/AnsibleConfig.java | 66 ------
.../entity/cm/ansible/AnsibleEntity.java | 40 ----
.../entity/cm/ansible/AnsibleEntityImpl.java | 61 ------
.../ansible/AnsibleLifecycleEffectorTasks.java | 203 -------------------
.../entity/cm/ansible/AnsiblePlaybookTasks.java | 109 ----------
.../ansible/AnsibleEntityIntegrationTest.java | 116 -----------
16 files changed, 718 insertions(+), 685 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/c1a87838/software/cm/ansible/pom.xml
----------------------------------------------------------------------
diff --git a/software/cm/ansible/pom.xml b/software/cm/ansible/pom.xml
new file mode 100644
index 0000000..028d73d
--- /dev/null
+++ b/software/cm/ansible/pom.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>brooklyn-software-cm-ansible</artifactId>
+ <packaging>jar</packaging>
+ <name>Brooklyn CM Ansible</name>
+ <description>Brooklyn entities for Configuration Management using Ansible</description>
+
+
+ <parent>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-library</artifactId>
+ <version>0.9.0-SNAPSHOT</version> <!-- BROOKLYN_VERSION -->
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-software-base</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-camp</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-test-support</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-core</artifactId>
+ <version>${project.version}</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-software-base</artifactId>
+ <version>${project.version}</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <version>${assertj.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/c1a87838/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleBashCommands.java
----------------------------------------------------------------------
diff --git a/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleBashCommands.java b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleBashCommands.java
new file mode 100644
index 0000000..e22ee34
--- /dev/null
+++ b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleBashCommands.java
@@ -0,0 +1,38 @@
+/*
+ * 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.cm.ansible;
+
+import static org.apache.brooklyn.util.ssh.BashCommands.INSTALL_CURL;
+import static org.apache.brooklyn.util.ssh.BashCommands.INSTALL_TAR;
+import static org.apache.brooklyn.util.ssh.BashCommands.INSTALL_UNZIP;
+import static org.apache.brooklyn.util.ssh.BashCommands.installExecutable;
+import static org.apache.brooklyn.util.ssh.BashCommands.sudo;
+
+import org.apache.brooklyn.util.ssh.BashCommands;
+
+public class AnsibleBashCommands {
+
+ public static final String INSTALL_ANSIBLE =
+ BashCommands.chain(
+ sudo("apt-add-repository -y ppa:ansible/ansible"),
+ INSTALL_CURL,
+ INSTALL_TAR,
+ INSTALL_UNZIP,
+ installExecutable("ansible"));
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/c1a87838/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java
----------------------------------------------------------------------
diff --git a/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java
new file mode 100644
index 0000000..d63c2c6
--- /dev/null
+++ b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java
@@ -0,0 +1,66 @@
+/*
+ * 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.cm.ansible;
+
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.util.core.flags.SetFromFlag;
+
+import com.google.common.annotations.Beta;
+
+/** {@link ConfigKey}s used to configure Ansible */
+@Beta
+public interface AnsibleConfig {
+
+ enum AnsibleModes {
+ PLAYBOOK
+ };
+
+ @SetFromFlag("playbook")
+ ConfigKey<String> ANSIBLE_PLAYBOOK = ConfigKeys.newStringConfigKey("brooklyn.ansible.playbook",
+ "Playbook to be execute by Ansible");
+
+ @SetFromFlag("playbook.yaml")
+ ConfigKey<String> ANSIBLE_PLAYBOOK_YAML = ConfigKeys.newStringConfigKey("brooklyn.ansible.playbookYaml",
+ "Playbook to be execute by Ansible");
+
+ @SetFromFlag("playbook.url")
+ ConfigKey<String> ANSIBLE_PLAYBOOK_URL = ConfigKeys.newStringConfigKey("brooklyn.ansible.playbookUrl");
+
+ @SetFromFlag("ansible.service.start")
+ ConfigKey<String> ANSIBLE_SERVICE_START = ConfigKeys.newStringConfigKey("ansible.service.start",
+ "Default start command used with conjunction with the Ansible's service module",
+ "sudo ansible localhost -c local -m service -a \"name=%s state=started\"");
+
+ @SetFromFlag("ansible.service.stop")
+ ConfigKey<String> ANSIBLE_SERVICE_STOP = ConfigKeys.newStringConfigKey("ansible.service.stop",
+ "Default stop command used with conjunction with the Ansible's service module",
+ "sudo ansible localhost -c local -m service -a \"name=%s state=stopped\"");
+
+ @SetFromFlag("ansible.service.checkPort")
+ ConfigKey<Integer> ANSIBLE_SERVICE_CHECK_PORT = ConfigKeys.newIntegerConfigKey("ansible.service.check.port");
+
+ @SetFromFlag("service.name")
+ ConfigKey<String> SERVICE_NAME = ConfigKeys.newStringConfigKey("brooklyn.ansible.serviceName",
+ "Name of OS service this will run as, for use in checking running and stopping");
+
+ @SetFromFlag("ansible.vars")
+ ConfigKey<Object> ANSIBLE_VARS = ConfigKeys.newConfigKey(Object.class, "brooklyn.ansible.vars",
+ "Ansible 'extra-vars' variable configuration values");
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/c1a87838/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntity.java
----------------------------------------------------------------------
diff --git a/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntity.java b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntity.java
new file mode 100644
index 0000000..a2c9676
--- /dev/null
+++ b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntity.java
@@ -0,0 +1,40 @@
+/*
+ * 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.cm.ansible;
+
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.core.annotation.Effector;
+import org.apache.brooklyn.core.annotation.EffectorParam;
+import org.apache.brooklyn.core.effector.MethodEffector;
+import org.apache.brooklyn.entity.software.base.SoftwareProcess;
+
+@ImplementedBy(AnsibleEntityImpl.class)
+public interface AnsibleEntity extends SoftwareProcess, AnsibleConfig {
+
+ MethodEffector<String> ANSIBLE_COMMAND = new MethodEffector<>(AnsibleEntity.class, "ansibleCommand");
+
+ @Effector(description = "Invoke an arbitrary Ansible command, optionally specifying the module (default is 'command')")
+ String ansibleCommand(
+ @EffectorParam(name="module", description = "Name of the Ansible module to invoke", defaultValue = "command")
+ String module,
+ @EffectorParam(name="args", description = "Arguments for the ansible command")
+ String args
+ );
+
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/c1a87838/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
----------------------------------------------------------------------
diff --git a/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
new file mode 100644
index 0000000..c2635ca
--- /dev/null
+++ b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
@@ -0,0 +1,61 @@
+/*
+ * 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.cm.ansible;
+
+import org.apache.brooklyn.entity.stock.EffectorStartableImpl;
+import org.apache.brooklyn.util.core.task.DynamicTasks;
+import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.util.text.Strings;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class AnsibleEntityImpl extends EffectorStartableImpl implements AnsibleEntity {
+
+ private AnsibleLifecycleEffectorTasks lifecycleTasks;
+
+ public void init() {
+ checkNotNull(getConfig(SERVICE_NAME), "service name is missing. it has to be provided by the user");
+ String playbookName = getConfig(ANSIBLE_PLAYBOOK);
+ if (!Strings.isBlank(playbookName)) setDefaultDisplayName(playbookName + " (ansible)");
+
+ super.init();
+
+ lifecycleTasks = new AnsibleLifecycleEffectorTasks();
+
+ lifecycleTasks.attachLifecycleEffectors(this);
+ }
+
+ @Override
+ public void populateServiceNotUpDiagnostics() {
+ // TODO no-op currently; should check ssh'able etc
+ }
+
+ @Override
+ public String ansibleCommand(String module, String args) {
+ final ProcessTaskWrapper<Integer> command = DynamicTasks.queue(
+ AnsiblePlaybookTasks.moduleCommand(module, config().get(ANSIBLE_VARS), lifecycleTasks.getRunDir(), args));
+ command.asTask().blockUntilEnded();
+ if (0 == command.getExitCode()) {
+ return command.getStdout();
+ } else {
+ throw new RuntimeException("Command (" + args + ") in module " + module
+ + " failed with stderr:\n" + command.getStderr() + "\n");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/c1a87838/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java
new file mode 100644
index 0000000..e1a8622
--- /dev/null
+++ b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java
@@ -0,0 +1,203 @@
+/*
+ * 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.cm.ansible;
+
+import com.google.common.base.Supplier;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.location.Locations;
+import org.apache.brooklyn.core.location.Machines;
+import org.apache.brooklyn.entity.software.base.SoftwareProcess;
+import org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks;
+import org.apache.brooklyn.feed.ssh.SshFeed;
+import org.apache.brooklyn.feed.ssh.SshPollConfig;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.core.task.DynamicTasks;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.net.Urls;
+import org.apache.brooklyn.util.text.Strings;
+import org.apache.brooklyn.util.time.Duration;
+import org.apache.brooklyn.util.time.Time;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AnsibleLifecycleEffectorTasks extends MachineLifecycleEffectorTasks implements AnsibleConfig {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AnsibleLifecycleEffectorTasks.class);
+
+ protected String serviceName;
+ protected SshFeed serviceSshFeed;
+
+ protected Object extraVars;
+ protected String baseDir;
+ protected String runDir;
+
+ public AnsibleLifecycleEffectorTasks() {
+ }
+
+ public String getServiceName() {
+ if (serviceName!=null) return serviceName;
+ return serviceName = entity().config().get(AnsibleConfig.SERVICE_NAME);
+ }
+
+ public Object getExtraVars() {
+ if (extraVars != null) return extraVars;
+ return extraVars = entity().config().get(ANSIBLE_VARS);
+ }
+
+ public String getBaseDir() {
+ if (null != baseDir) return baseDir;
+ return baseDir = MachineLifecycleEffectorTasks.resolveOnBoxDir(entity(),
+ Machines.findUniqueMachineLocation(entity().getLocations(), SshMachineLocation.class).get());
+ }
+
+ public String getRunDir() {
+ if (null != runDir) return runDir;
+ return runDir = Urls.mergePaths(getBaseDir(), "apps/"+entity().getApplicationId()+"/ansible/playbooks/"
+ +entity().getEntityType().getSimpleName()+"_"+entity().getId());
+ }
+
+ @Override
+ public void attachLifecycleEffectors(Entity entity) {
+ if (getServiceName()==null && getClass().equals(AnsibleLifecycleEffectorTasks.class)) {
+ // warn on incorrect usage
+ LOG.warn("Uses of "+getClass()+" must define a PID file or a service name (or subclass and override {start,stop} methods as per javadoc) " +
+ "in order for check-running and stop to work");
+ }
+ super.attachLifecycleEffectors(entity);
+ }
+
+ @Override
+ protected String startProcessesAtMachine(Supplier<MachineLocation> machineS) {
+ startWithAnsibleAsync();
+
+ return "ansible start tasks submitted";
+ }
+
+ protected String getPlaybookName() {
+ return entity().config().get(ANSIBLE_PLAYBOOK);
+ }
+
+ protected void startWithAnsibleAsync() {
+ String installDir = Urls.mergePaths(getBaseDir(), "installs/ansible");
+
+ String playbookUrl = entity().config().get(ANSIBLE_PLAYBOOK_URL);
+ String playbookYaml = entity().config().get(ANSIBLE_PLAYBOOK_YAML);
+
+ if (Strings.isNonBlank(playbookUrl) && Strings.isNonBlank(playbookYaml)) {
+ throw new IllegalArgumentException("You can specify " + AnsibleConfig.ANSIBLE_PLAYBOOK_URL.getName()
+ + " or " + AnsibleConfig.ANSIBLE_PLAYBOOK_YAML.getName() + " but not both of them!");
+ }
+
+ DynamicTasks.queue(AnsiblePlaybookTasks.installAnsible(installDir, false));
+
+ if (getExtraVars() != null) {
+ DynamicTasks.queue(AnsiblePlaybookTasks.configureExtraVars(getRunDir(), extraVars, false));
+ }
+
+ if (Strings.isNonBlank(playbookUrl)) {
+ DynamicTasks.queue(AnsiblePlaybookTasks.installPlaybook(getRunDir(), getPlaybookName(), playbookUrl));
+ }
+
+ if (Strings.isNonBlank(playbookYaml)) {
+ DynamicTasks.queue(AnsiblePlaybookTasks.buildPlaybookFile(getRunDir(), getPlaybookName()));
+ }
+ DynamicTasks.queue(AnsiblePlaybookTasks.runAnsible(getRunDir(), getExtraVars(), getPlaybookName()));
+ }
+
+
+ protected void postStartCustom() {
+ boolean result = false;
+ result |= tryCheckStartService();
+
+ if (!result) {
+ LOG.warn("No way to check whether "+entity()+" is running; assuming yes");
+ }
+ entity().sensors().set(SoftwareProcess.SERVICE_UP, true);
+
+ Maybe<SshMachineLocation> machine = Locations.findUniqueSshMachineLocation(entity().getLocations());
+
+ if (machine.isPresent()) {
+
+ String serviceName = String.format("[%s]%s", entity().config().get(SERVICE_NAME).substring(0, 1),
+ entity().config().get(SERVICE_NAME).substring(1));
+ String checkCmd = String.format("ps -ef | grep %s", serviceName);
+
+ Integer serviceCheckPort = entity().config().get(ANSIBLE_SERVICE_CHECK_PORT);
+
+ if (serviceCheckPort != null) {
+ checkCmd = String.format("sudo ansible localhost -c local -m wait_for -a \"host=0.0.0.0 port=%d\"", serviceCheckPort);
+ }
+ serviceSshFeed = SshFeed.builder()
+ .entity(entity())
+ .period(Duration.ONE_MINUTE)
+ .machine(machine.get())
+ .poll(new SshPollConfig<Boolean>(Startable.SERVICE_UP)
+ .command(checkCmd)
+ .setOnSuccess(true)
+ .setOnFailureOrException(false))
+ .build();
+
+ entity().feeds().addFeed(serviceSshFeed);
+ } else {
+ LOG.warn("Location(s) {} not an ssh-machine location, so not polling for status; setting serviceUp immediately", entity().getLocations());
+ }
+ }
+
+ protected boolean tryCheckStartService() {
+ if (getServiceName()==null) return false;
+
+ // if it's still up after 5s assume we are good (default behaviour)
+ Time.sleep(Duration.FIVE_SECONDS);
+ if (!((Integer)0).equals(DynamicTasks.queue(SshEffectorTasks.ssh(String.format(entity().config().get(AnsibleConfig.ANSIBLE_SERVICE_START), getServiceName()))).get())) {
+ throw new IllegalStateException("The process for "+entity()+" appears not to be running (service "+getServiceName()+")");
+ }
+
+ return true;
+ }
+
+ @Override
+ protected String stopProcessesAtMachine() {
+ boolean result = false;
+ result |= tryStopService();
+ if (!result) {
+ throw new IllegalStateException("The process for "+entity()+" could not be stopped (no impl!)");
+ }
+ return "stopped";
+ }
+
+ @Override
+ protected StopMachineDetails<Integer> stopAnyProvisionedMachines() {
+ return super.stopAnyProvisionedMachines();
+ }
+
+ protected boolean tryStopService() {
+ if (getServiceName()==null) return false;
+ int result = DynamicTasks.queue(SshEffectorTasks.ssh(String.format(entity().config().get(AnsibleConfig.ANSIBLE_SERVICE_STOP), getServiceName()))).get();
+ if (0 == result) return true;
+ if (entity().getAttribute(Attributes.SERVICE_STATE_ACTUAL) != Lifecycle.RUNNING)
+ return true;
+
+ throw new IllegalStateException("The process for "+entity()+" appears could not be stopped (exit code "+result+" to service stop)");
+ }
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/c1a87838/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
----------------------------------------------------------------------
diff --git a/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
new file mode 100644
index 0000000..36076a1
--- /dev/null
+++ b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
@@ -0,0 +1,109 @@
+/*
+ * 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.cm.ansible;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.mgmt.TaskFactory;
+import org.apache.brooklyn.core.effector.EffectorTasks;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
+import org.apache.brooklyn.util.core.ResourceUtils;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.core.task.system.ProcessTaskFactory;
+import org.apache.brooklyn.util.net.Urls;
+import org.apache.brooklyn.util.ssh.BashCommands;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+import static org.apache.brooklyn.util.ssh.BashCommands.sudo;
+
+public class AnsiblePlaybookTasks {
+ private static final Logger LOG = LoggerFactory.getLogger(AnsiblePlaybookTasks.class);
+ private static final String EXTRA_VARS_FILENAME = "extra_vars.yaml";
+
+ public static TaskFactory<?> installAnsible(String ansibleDirectory, boolean force) {
+ String installCmd = cdAndRun(ansibleDirectory, AnsibleBashCommands.INSTALL_ANSIBLE);
+ if (!force) installCmd = BashCommands.alternatives("which ansible", installCmd);
+ return SshEffectorTasks.ssh(installCmd).summary("install ansible");
+ }
+
+ public static TaskFactory<?> installPlaybook(final String ansibleDirectory, final String playbookName, final String playbookUrl) {
+ return Tasks.sequential("build ansible playbook file for "+playbookName,
+ SshEffectorTasks.put(ansibleDirectory + "/" + playbookName + ".yaml")
+ .contents(ResourceUtils.create().getResourceFromUrl(playbookUrl))
+ .createDirectory());
+ }
+
+ protected static String cdAndRun(String targetDirectory, String command) {
+ return BashCommands.chain("mkdir -p "+targetDirectory,
+ "cd "+targetDirectory,
+ command);
+ }
+
+ public static TaskFactory<?> buildPlaybookFile(final String ansibleDirectory, String playbook) {
+ Entity entity = EffectorTasks.findEntity();
+ String yaml = entity.config().get(AnsibleConfig.ANSIBLE_PLAYBOOK_YAML);
+
+ return Tasks.sequential("build ansible playbook file for "+ playbook,
+ SshEffectorTasks.put(Urls.mergePaths(ansibleDirectory) + "/" + playbook + ".yaml")
+ .contents(yaml).createDirectory());
+ }
+
+ public static TaskFactory<?> runAnsible(final String dir, Object extraVars, String playbookName) {
+ String cmd = String.format("sudo ansible-playbook -i \"localhost,\" -c local "
+ + optionalExtraVarsParameter(extraVars)
+ + " -s %s.yaml", playbookName);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Ansible command: {}", cmd);
+ }
+
+ return SshEffectorTasks.ssh(cdAndRun(dir, cmd)).
+ summary("run ansible playbook for " + playbookName).requiringExitCodeZero();
+ }
+
+ public static ProcessTaskFactory<Integer> moduleCommand(String module, Object extraVars, String root, String args) {
+ final String command = "ansible localhost "
+ + optionalExtraVarsParameter(extraVars)
+ + " -m '" + module + "' -a '" + args + "'";
+ return SshEffectorTasks.ssh(sudo(BashCommands.chain("cd " + root, command)))
+ .summary("ad-hoc: " + command).requiringExitCodeZero();
+ }
+
+ public static TaskFactory<?> configureExtraVars(String dir, Object extraVars, boolean force) {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
+ Yaml asYaml = new Yaml(options);
+ final String varsYaml = asYaml.dump(extraVars);
+ return SshEffectorTasks.put(Urls.mergePaths(dir, EXTRA_VARS_FILENAME))
+ .contents(varsYaml)
+ .summary("install extra vars")
+ .createDirectory();
+ }
+
+ private static String optionalExtraVarsParameter(Object extraVars) {
+ if (null == extraVars || Strings.isBlank(extraVars.toString())) {
+ return "";
+ }
+ return " --extra-vars \"@" + EXTRA_VARS_FILENAME + "\" ";
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/c1a87838/software/cm/ansible/src/test/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/cm/ansible/src/test/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityIntegrationTest.java b/software/cm/ansible/src/test/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityIntegrationTest.java
new file mode 100644
index 0000000..76e993d
--- /dev/null
+++ b/software/cm/ansible/src/test/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityIntegrationTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.cm.ansible;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.MachineDetails;
+import org.apache.brooklyn.api.location.OsDetails;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityAsserts;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.location.BasicMachineDetails;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+
+public class AnsibleEntityIntegrationTest {
+ protected TestApplication app;
+ protected LocalhostMachineProvisioningLocation testLocation;
+ protected AnsibleEntity ansible;
+ protected SshMachineLocation sshHost;
+
+ String playbookYaml = Joiner.on("\n").join(
+ "---",
+ "- hosts: localhost",
+ " sudo: True",
+ "",
+ " tasks:",
+ " - apt: name=apache2 state=latest",
+ " when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'",
+ "",
+ " - yum: name=httpd state=latest",
+ " when: ansible_distribution == 'CentOS' or ansible_distribution == 'Red Hat Enterprise Linux'",
+ "",
+ " - service: name=apache2 state=started enabled=no",
+ " when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'",
+ "",
+ " - service: name=httpd state=started enabled=no",
+ " when: ansible_distribution == 'CentOS' or ansible_distribution == 'Red Hat Enterprise Linux'");
+
+ @BeforeMethod(alwaysRun = true)
+ public void setup() throws Exception {
+ app = TestApplication.Factory.newManagedInstanceForTests();;
+ testLocation = new LocalhostMachineProvisioningLocation();
+ sshHost = testLocation.obtain();
+ }
+
+ @AfterMethod(alwaysRun = true)
+ public void shutdown() {
+ Entities.destroyAll(app.getManagementContext());
+ }
+
+ @Test(groups = {"Integration"})
+ public void testAnsible() {
+ Task<BasicMachineDetails> detailsTask = app.getExecutionContext().submit(
+ BasicMachineDetails.taskForSshMachineLocation(sshHost));
+ MachineDetails machine = detailsTask.getUnchecked();
+
+
+ OsDetails details = machine.getOsDetails();
+
+ String osName = details.getName();
+ String playbookServiceName = getPlaybookServiceName(osName);
+ ansible = app.createAndManageChild(EntitySpec.create(AnsibleEntity.class)
+ .configure("playbook.yaml", playbookYaml)
+ .configure("playbook", playbookServiceName)
+ .configure("service.name", playbookServiceName));
+
+ app.start(ImmutableList.of(testLocation));
+ EntityAsserts.assertAttributeEqualsEventually(ansible, Startable.SERVICE_UP, true);
+
+ ansible.stop();
+ EntityAsserts.assertAttributeEqualsEventually(ansible, Startable.SERVICE_UP, false);
+ }
+
+ private String getPlaybookServiceName(String os) {
+ String name;
+
+ switch (os.toLowerCase()) {
+ case "fedora":
+ name = "httpd";
+ break;
+ case "centos":
+ name = "httpd";
+ break;
+ default:
+ name = "apache2";
+ }
+ return name;
+ }
+}
+
+
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/c1a87838/software/cm/pom.xml
----------------------------------------------------------------------
diff --git a/software/cm/pom.xml b/software/cm/pom.xml
index ea17774..8a86fb7 100644
--- a/software/cm/pom.xml
+++ b/software/cm/pom.xml
@@ -70,61 +70,10 @@
</mailingList>
</mailingLists>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.brooklyn</groupId>
- <artifactId>brooklyn-api</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.brooklyn</groupId>
- <artifactId>brooklyn-software-base</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.brooklyn</groupId>
- <artifactId>brooklyn-software-database</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.brooklyn</groupId>
- <artifactId>brooklyn-camp</artifactId>
- <version>${project.version}</version>
- </dependency>
-
- <dependency>
- <groupId>org.apache.brooklyn</groupId>
- <artifactId>brooklyn-test-support</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.brooklyn</groupId>
- <artifactId>brooklyn-core</artifactId>
- <version>${project.version}</version>
- <classifier>tests</classifier>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.brooklyn</groupId>
- <artifactId>brooklyn-software-base</artifactId>
- <version>${project.version}</version>
- <classifier>tests</classifier>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.assertj</groupId>
- <artifactId>assertj-core</artifactId>
- <version>${assertj.version}</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
<modules>
<module>salt</module>
+ <module>ansible</module>
</modules>
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/c1a87838/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleBashCommands.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleBashCommands.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleBashCommands.java
deleted file mode 100644
index e22ee34..0000000
--- a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleBashCommands.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 org.apache.brooklyn.entity.cm.ansible;
-
-import static org.apache.brooklyn.util.ssh.BashCommands.INSTALL_CURL;
-import static org.apache.brooklyn.util.ssh.BashCommands.INSTALL_TAR;
-import static org.apache.brooklyn.util.ssh.BashCommands.INSTALL_UNZIP;
-import static org.apache.brooklyn.util.ssh.BashCommands.installExecutable;
-import static org.apache.brooklyn.util.ssh.BashCommands.sudo;
-
-import org.apache.brooklyn.util.ssh.BashCommands;
-
-public class AnsibleBashCommands {
-
- public static final String INSTALL_ANSIBLE =
- BashCommands.chain(
- sudo("apt-add-repository -y ppa:ansible/ansible"),
- INSTALL_CURL,
- INSTALL_TAR,
- INSTALL_UNZIP,
- installExecutable("ansible"));
-}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/c1a87838/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java
deleted file mode 100644
index d63c2c6..0000000
--- a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java
+++ /dev/null
@@ -1,66 +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 org.apache.brooklyn.entity.cm.ansible;
-
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.util.core.flags.SetFromFlag;
-
-import com.google.common.annotations.Beta;
-
-/** {@link ConfigKey}s used to configure Ansible */
-@Beta
-public interface AnsibleConfig {
-
- enum AnsibleModes {
- PLAYBOOK
- };
-
- @SetFromFlag("playbook")
- ConfigKey<String> ANSIBLE_PLAYBOOK = ConfigKeys.newStringConfigKey("brooklyn.ansible.playbook",
- "Playbook to be execute by Ansible");
-
- @SetFromFlag("playbook.yaml")
- ConfigKey<String> ANSIBLE_PLAYBOOK_YAML = ConfigKeys.newStringConfigKey("brooklyn.ansible.playbookYaml",
- "Playbook to be execute by Ansible");
-
- @SetFromFlag("playbook.url")
- ConfigKey<String> ANSIBLE_PLAYBOOK_URL = ConfigKeys.newStringConfigKey("brooklyn.ansible.playbookUrl");
-
- @SetFromFlag("ansible.service.start")
- ConfigKey<String> ANSIBLE_SERVICE_START = ConfigKeys.newStringConfigKey("ansible.service.start",
- "Default start command used with conjunction with the Ansible's service module",
- "sudo ansible localhost -c local -m service -a \"name=%s state=started\"");
-
- @SetFromFlag("ansible.service.stop")
- ConfigKey<String> ANSIBLE_SERVICE_STOP = ConfigKeys.newStringConfigKey("ansible.service.stop",
- "Default stop command used with conjunction with the Ansible's service module",
- "sudo ansible localhost -c local -m service -a \"name=%s state=stopped\"");
-
- @SetFromFlag("ansible.service.checkPort")
- ConfigKey<Integer> ANSIBLE_SERVICE_CHECK_PORT = ConfigKeys.newIntegerConfigKey("ansible.service.check.port");
-
- @SetFromFlag("service.name")
- ConfigKey<String> SERVICE_NAME = ConfigKeys.newStringConfigKey("brooklyn.ansible.serviceName",
- "Name of OS service this will run as, for use in checking running and stopping");
-
- @SetFromFlag("ansible.vars")
- ConfigKey<Object> ANSIBLE_VARS = ConfigKeys.newConfigKey(Object.class, "brooklyn.ansible.vars",
- "Ansible 'extra-vars' variable configuration values");
-}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/c1a87838/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntity.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntity.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntity.java
deleted file mode 100644
index a2c9676..0000000
--- a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntity.java
+++ /dev/null
@@ -1,40 +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 org.apache.brooklyn.entity.cm.ansible;
-
-import org.apache.brooklyn.api.entity.ImplementedBy;
-import org.apache.brooklyn.core.annotation.Effector;
-import org.apache.brooklyn.core.annotation.EffectorParam;
-import org.apache.brooklyn.core.effector.MethodEffector;
-import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-
-@ImplementedBy(AnsibleEntityImpl.class)
-public interface AnsibleEntity extends SoftwareProcess, AnsibleConfig {
-
- MethodEffector<String> ANSIBLE_COMMAND = new MethodEffector<>(AnsibleEntity.class, "ansibleCommand");
-
- @Effector(description = "Invoke an arbitrary Ansible command, optionally specifying the module (default is 'command')")
- String ansibleCommand(
- @EffectorParam(name="module", description = "Name of the Ansible module to invoke", defaultValue = "command")
- String module,
- @EffectorParam(name="args", description = "Arguments for the ansible command")
- String args
- );
-
-}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/c1a87838/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
deleted file mode 100644
index c2635ca..0000000
--- a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
+++ /dev/null
@@ -1,61 +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 org.apache.brooklyn.entity.cm.ansible;
-
-import org.apache.brooklyn.entity.stock.EffectorStartableImpl;
-import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
-import org.apache.brooklyn.util.text.Strings;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-public class AnsibleEntityImpl extends EffectorStartableImpl implements AnsibleEntity {
-
- private AnsibleLifecycleEffectorTasks lifecycleTasks;
-
- public void init() {
- checkNotNull(getConfig(SERVICE_NAME), "service name is missing. it has to be provided by the user");
- String playbookName = getConfig(ANSIBLE_PLAYBOOK);
- if (!Strings.isBlank(playbookName)) setDefaultDisplayName(playbookName + " (ansible)");
-
- super.init();
-
- lifecycleTasks = new AnsibleLifecycleEffectorTasks();
-
- lifecycleTasks.attachLifecycleEffectors(this);
- }
-
- @Override
- public void populateServiceNotUpDiagnostics() {
- // TODO no-op currently; should check ssh'able etc
- }
-
- @Override
- public String ansibleCommand(String module, String args) {
- final ProcessTaskWrapper<Integer> command = DynamicTasks.queue(
- AnsiblePlaybookTasks.moduleCommand(module, config().get(ANSIBLE_VARS), lifecycleTasks.getRunDir(), args));
- command.asTask().blockUntilEnded();
- if (0 == command.getExitCode()) {
- return command.getStdout();
- } else {
- throw new RuntimeException("Command (" + args + ") in module " + module
- + " failed with stderr:\n" + command.getStderr() + "\n");
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/c1a87838/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java
deleted file mode 100644
index e1a8622..0000000
--- a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java
+++ /dev/null
@@ -1,203 +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 org.apache.brooklyn.entity.cm.ansible;
-
-import com.google.common.base.Supplier;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.location.MachineLocation;
-import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
-import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
-import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.core.location.Locations;
-import org.apache.brooklyn.core.location.Machines;
-import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks;
-import org.apache.brooklyn.feed.ssh.SshFeed;
-import org.apache.brooklyn.feed.ssh.SshPollConfig;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.guava.Maybe;
-import org.apache.brooklyn.util.net.Urls;
-import org.apache.brooklyn.util.text.Strings;
-import org.apache.brooklyn.util.time.Duration;
-import org.apache.brooklyn.util.time.Time;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class AnsibleLifecycleEffectorTasks extends MachineLifecycleEffectorTasks implements AnsibleConfig {
-
- private static final Logger LOG = LoggerFactory.getLogger(AnsibleLifecycleEffectorTasks.class);
-
- protected String serviceName;
- protected SshFeed serviceSshFeed;
-
- protected Object extraVars;
- protected String baseDir;
- protected String runDir;
-
- public AnsibleLifecycleEffectorTasks() {
- }
-
- public String getServiceName() {
- if (serviceName!=null) return serviceName;
- return serviceName = entity().config().get(AnsibleConfig.SERVICE_NAME);
- }
-
- public Object getExtraVars() {
- if (extraVars != null) return extraVars;
- return extraVars = entity().config().get(ANSIBLE_VARS);
- }
-
- public String getBaseDir() {
- if (null != baseDir) return baseDir;
- return baseDir = MachineLifecycleEffectorTasks.resolveOnBoxDir(entity(),
- Machines.findUniqueMachineLocation(entity().getLocations(), SshMachineLocation.class).get());
- }
-
- public String getRunDir() {
- if (null != runDir) return runDir;
- return runDir = Urls.mergePaths(getBaseDir(), "apps/"+entity().getApplicationId()+"/ansible/playbooks/"
- +entity().getEntityType().getSimpleName()+"_"+entity().getId());
- }
-
- @Override
- public void attachLifecycleEffectors(Entity entity) {
- if (getServiceName()==null && getClass().equals(AnsibleLifecycleEffectorTasks.class)) {
- // warn on incorrect usage
- LOG.warn("Uses of "+getClass()+" must define a PID file or a service name (or subclass and override {start,stop} methods as per javadoc) " +
- "in order for check-running and stop to work");
- }
- super.attachLifecycleEffectors(entity);
- }
-
- @Override
- protected String startProcessesAtMachine(Supplier<MachineLocation> machineS) {
- startWithAnsibleAsync();
-
- return "ansible start tasks submitted";
- }
-
- protected String getPlaybookName() {
- return entity().config().get(ANSIBLE_PLAYBOOK);
- }
-
- protected void startWithAnsibleAsync() {
- String installDir = Urls.mergePaths(getBaseDir(), "installs/ansible");
-
- String playbookUrl = entity().config().get(ANSIBLE_PLAYBOOK_URL);
- String playbookYaml = entity().config().get(ANSIBLE_PLAYBOOK_YAML);
-
- if (Strings.isNonBlank(playbookUrl) && Strings.isNonBlank(playbookYaml)) {
- throw new IllegalArgumentException("You can specify " + AnsibleConfig.ANSIBLE_PLAYBOOK_URL.getName()
- + " or " + AnsibleConfig.ANSIBLE_PLAYBOOK_YAML.getName() + " but not both of them!");
- }
-
- DynamicTasks.queue(AnsiblePlaybookTasks.installAnsible(installDir, false));
-
- if (getExtraVars() != null) {
- DynamicTasks.queue(AnsiblePlaybookTasks.configureExtraVars(getRunDir(), extraVars, false));
- }
-
- if (Strings.isNonBlank(playbookUrl)) {
- DynamicTasks.queue(AnsiblePlaybookTasks.installPlaybook(getRunDir(), getPlaybookName(), playbookUrl));
- }
-
- if (Strings.isNonBlank(playbookYaml)) {
- DynamicTasks.queue(AnsiblePlaybookTasks.buildPlaybookFile(getRunDir(), getPlaybookName()));
- }
- DynamicTasks.queue(AnsiblePlaybookTasks.runAnsible(getRunDir(), getExtraVars(), getPlaybookName()));
- }
-
-
- protected void postStartCustom() {
- boolean result = false;
- result |= tryCheckStartService();
-
- if (!result) {
- LOG.warn("No way to check whether "+entity()+" is running; assuming yes");
- }
- entity().sensors().set(SoftwareProcess.SERVICE_UP, true);
-
- Maybe<SshMachineLocation> machine = Locations.findUniqueSshMachineLocation(entity().getLocations());
-
- if (machine.isPresent()) {
-
- String serviceName = String.format("[%s]%s", entity().config().get(SERVICE_NAME).substring(0, 1),
- entity().config().get(SERVICE_NAME).substring(1));
- String checkCmd = String.format("ps -ef | grep %s", serviceName);
-
- Integer serviceCheckPort = entity().config().get(ANSIBLE_SERVICE_CHECK_PORT);
-
- if (serviceCheckPort != null) {
- checkCmd = String.format("sudo ansible localhost -c local -m wait_for -a \"host=0.0.0.0 port=%d\"", serviceCheckPort);
- }
- serviceSshFeed = SshFeed.builder()
- .entity(entity())
- .period(Duration.ONE_MINUTE)
- .machine(machine.get())
- .poll(new SshPollConfig<Boolean>(Startable.SERVICE_UP)
- .command(checkCmd)
- .setOnSuccess(true)
- .setOnFailureOrException(false))
- .build();
-
- entity().feeds().addFeed(serviceSshFeed);
- } else {
- LOG.warn("Location(s) {} not an ssh-machine location, so not polling for status; setting serviceUp immediately", entity().getLocations());
- }
- }
-
- protected boolean tryCheckStartService() {
- if (getServiceName()==null) return false;
-
- // if it's still up after 5s assume we are good (default behaviour)
- Time.sleep(Duration.FIVE_SECONDS);
- if (!((Integer)0).equals(DynamicTasks.queue(SshEffectorTasks.ssh(String.format(entity().config().get(AnsibleConfig.ANSIBLE_SERVICE_START), getServiceName()))).get())) {
- throw new IllegalStateException("The process for "+entity()+" appears not to be running (service "+getServiceName()+")");
- }
-
- return true;
- }
-
- @Override
- protected String stopProcessesAtMachine() {
- boolean result = false;
- result |= tryStopService();
- if (!result) {
- throw new IllegalStateException("The process for "+entity()+" could not be stopped (no impl!)");
- }
- return "stopped";
- }
-
- @Override
- protected StopMachineDetails<Integer> stopAnyProvisionedMachines() {
- return super.stopAnyProvisionedMachines();
- }
-
- protected boolean tryStopService() {
- if (getServiceName()==null) return false;
- int result = DynamicTasks.queue(SshEffectorTasks.ssh(String.format(entity().config().get(AnsibleConfig.ANSIBLE_SERVICE_STOP), getServiceName()))).get();
- if (0 == result) return true;
- if (entity().getAttribute(Attributes.SERVICE_STATE_ACTUAL) != Lifecycle.RUNNING)
- return true;
-
- throw new IllegalStateException("The process for "+entity()+" appears could not be stopped (exit code "+result+" to service stop)");
- }
-}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/c1a87838/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
deleted file mode 100644
index 36076a1..0000000
--- a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.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 org.apache.brooklyn.entity.cm.ansible;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.mgmt.TaskFactory;
-import org.apache.brooklyn.core.effector.EffectorTasks;
-import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
-import org.apache.brooklyn.util.core.ResourceUtils;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.core.task.system.ProcessTaskFactory;
-import org.apache.brooklyn.util.net.Urls;
-import org.apache.brooklyn.util.ssh.BashCommands;
-import org.apache.brooklyn.util.text.Strings;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.yaml.snakeyaml.DumperOptions;
-import org.yaml.snakeyaml.Yaml;
-
-import static org.apache.brooklyn.util.ssh.BashCommands.sudo;
-
-public class AnsiblePlaybookTasks {
- private static final Logger LOG = LoggerFactory.getLogger(AnsiblePlaybookTasks.class);
- private static final String EXTRA_VARS_FILENAME = "extra_vars.yaml";
-
- public static TaskFactory<?> installAnsible(String ansibleDirectory, boolean force) {
- String installCmd = cdAndRun(ansibleDirectory, AnsibleBashCommands.INSTALL_ANSIBLE);
- if (!force) installCmd = BashCommands.alternatives("which ansible", installCmd);
- return SshEffectorTasks.ssh(installCmd).summary("install ansible");
- }
-
- public static TaskFactory<?> installPlaybook(final String ansibleDirectory, final String playbookName, final String playbookUrl) {
- return Tasks.sequential("build ansible playbook file for "+playbookName,
- SshEffectorTasks.put(ansibleDirectory + "/" + playbookName + ".yaml")
- .contents(ResourceUtils.create().getResourceFromUrl(playbookUrl))
- .createDirectory());
- }
-
- protected static String cdAndRun(String targetDirectory, String command) {
- return BashCommands.chain("mkdir -p "+targetDirectory,
- "cd "+targetDirectory,
- command);
- }
-
- public static TaskFactory<?> buildPlaybookFile(final String ansibleDirectory, String playbook) {
- Entity entity = EffectorTasks.findEntity();
- String yaml = entity.config().get(AnsibleConfig.ANSIBLE_PLAYBOOK_YAML);
-
- return Tasks.sequential("build ansible playbook file for "+ playbook,
- SshEffectorTasks.put(Urls.mergePaths(ansibleDirectory) + "/" + playbook + ".yaml")
- .contents(yaml).createDirectory());
- }
-
- public static TaskFactory<?> runAnsible(final String dir, Object extraVars, String playbookName) {
- String cmd = String.format("sudo ansible-playbook -i \"localhost,\" -c local "
- + optionalExtraVarsParameter(extraVars)
- + " -s %s.yaml", playbookName);
-
- if (LOG.isDebugEnabled()) {
- LOG.debug("Ansible command: {}", cmd);
- }
-
- return SshEffectorTasks.ssh(cdAndRun(dir, cmd)).
- summary("run ansible playbook for " + playbookName).requiringExitCodeZero();
- }
-
- public static ProcessTaskFactory<Integer> moduleCommand(String module, Object extraVars, String root, String args) {
- final String command = "ansible localhost "
- + optionalExtraVarsParameter(extraVars)
- + " -m '" + module + "' -a '" + args + "'";
- return SshEffectorTasks.ssh(sudo(BashCommands.chain("cd " + root, command)))
- .summary("ad-hoc: " + command).requiringExitCodeZero();
- }
-
- public static TaskFactory<?> configureExtraVars(String dir, Object extraVars, boolean force) {
- DumperOptions options = new DumperOptions();
- options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
- Yaml asYaml = new Yaml(options);
- final String varsYaml = asYaml.dump(extraVars);
- return SshEffectorTasks.put(Urls.mergePaths(dir, EXTRA_VARS_FILENAME))
- .contents(varsYaml)
- .summary("install extra vars")
- .createDirectory();
- }
-
- private static String optionalExtraVarsParameter(Object extraVars) {
- if (null == extraVars || Strings.isBlank(extraVars.toString())) {
- return "";
- }
- return " --extra-vars \"@" + EXTRA_VARS_FILENAME + "\" ";
- }
-}
-
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/c1a87838/software/cm/src/test/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/cm/src/test/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityIntegrationTest.java b/software/cm/src/test/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityIntegrationTest.java
deleted file mode 100644
index 76e993d..0000000
--- a/software/cm/src/test/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityIntegrationTest.java
+++ /dev/null
@@ -1,116 +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 org.apache.brooklyn.entity.cm.ansible;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.location.MachineDetails;
-import org.apache.brooklyn.api.location.OsDetails;
-import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.EntityAsserts;
-import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.core.location.BasicMachineDetails;
-import org.apache.brooklyn.core.test.entity.TestApplication;
-
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-
-public class AnsibleEntityIntegrationTest {
- protected TestApplication app;
- protected LocalhostMachineProvisioningLocation testLocation;
- protected AnsibleEntity ansible;
- protected SshMachineLocation sshHost;
-
- String playbookYaml = Joiner.on("\n").join(
- "---",
- "- hosts: localhost",
- " sudo: True",
- "",
- " tasks:",
- " - apt: name=apache2 state=latest",
- " when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'",
- "",
- " - yum: name=httpd state=latest",
- " when: ansible_distribution == 'CentOS' or ansible_distribution == 'Red Hat Enterprise Linux'",
- "",
- " - service: name=apache2 state=started enabled=no",
- " when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'",
- "",
- " - service: name=httpd state=started enabled=no",
- " when: ansible_distribution == 'CentOS' or ansible_distribution == 'Red Hat Enterprise Linux'");
-
- @BeforeMethod(alwaysRun = true)
- public void setup() throws Exception {
- app = TestApplication.Factory.newManagedInstanceForTests();;
- testLocation = new LocalhostMachineProvisioningLocation();
- sshHost = testLocation.obtain();
- }
-
- @AfterMethod(alwaysRun = true)
- public void shutdown() {
- Entities.destroyAll(app.getManagementContext());
- }
-
- @Test(groups = {"Integration"})
- public void testAnsible() {
- Task<BasicMachineDetails> detailsTask = app.getExecutionContext().submit(
- BasicMachineDetails.taskForSshMachineLocation(sshHost));
- MachineDetails machine = detailsTask.getUnchecked();
-
-
- OsDetails details = machine.getOsDetails();
-
- String osName = details.getName();
- String playbookServiceName = getPlaybookServiceName(osName);
- ansible = app.createAndManageChild(EntitySpec.create(AnsibleEntity.class)
- .configure("playbook.yaml", playbookYaml)
- .configure("playbook", playbookServiceName)
- .configure("service.name", playbookServiceName));
-
- app.start(ImmutableList.of(testLocation));
- EntityAsserts.assertAttributeEqualsEventually(ansible, Startable.SERVICE_UP, true);
-
- ansible.stop();
- EntityAsserts.assertAttributeEqualsEventually(ansible, Startable.SERVICE_UP, false);
- }
-
- private String getPlaybookServiceName(String os) {
- String name;
-
- switch (os.toLowerCase()) {
- case "fedora":
- name = "httpd";
- break;
- case "centos":
- name = "httpd";
- break;
- default:
- name = "apache2";
- }
- return name;
- }
-}
-
-
[3/7] brooklyn-library git commit: Initial Ansible support
Posted by he...@apache.org.
Initial Ansible support
- Ansible install for Ubuntu and CentOS
- Playbooks can be specified via URL or directly as a YAML
- Support for custom start/stop commands
- Support for command to support setting a useful value for the
service.isUp sensor
- Generic check for a running service based on the provided serviceName
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-library/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-library/commit/373c598a
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-library/tree/373c598a
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-library/diff/373c598a
Branch: refs/heads/master
Commit: 373c598afe05a81adbc317088b166b734a04472a
Parents: 9fdf1db
Author: Yavor Yanchev <ya...@yanchev.com>
Authored: Fri Feb 5 10:05:41 2016 +0200
Committer: Yavor Yanchev <ya...@yanchev.com>
Committed: Wed Feb 17 11:43:03 2016 +0200
----------------------------------------------------------------------
software/cm/pom.xml | 51 ++++++
.../entity/cm/ansible/AnsibleBashCommands.java | 38 ++++
.../entity/cm/ansible/AnsibleConfig.java | 62 +++++++
.../entity/cm/ansible/AnsibleEntity.java | 26 +++
.../entity/cm/ansible/AnsibleEntityImpl.java | 41 +++++
.../ansible/AnsibleLifecycleEffectorTasks.java | 180 +++++++++++++++++++
.../entity/cm/ansible/AnsiblePlaybookTasks.java | 72 ++++++++
7 files changed, 470 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/373c598a/software/cm/pom.xml
----------------------------------------------------------------------
diff --git a/software/cm/pom.xml b/software/cm/pom.xml
index 90af5b4..ea17774 100644
--- a/software/cm/pom.xml
+++ b/software/cm/pom.xml
@@ -71,6 +71,57 @@
</mailingLists>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-software-base</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-software-database</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-camp</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-test-support</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-core</artifactId>
+ <version>${project.version}</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-software-base</artifactId>
+ <version>${project.version}</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <version>${assertj.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
<modules>
<module>salt</module>
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/373c598a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleBashCommands.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleBashCommands.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleBashCommands.java
new file mode 100644
index 0000000..e22ee34
--- /dev/null
+++ b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleBashCommands.java
@@ -0,0 +1,38 @@
+/*
+ * 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.cm.ansible;
+
+import static org.apache.brooklyn.util.ssh.BashCommands.INSTALL_CURL;
+import static org.apache.brooklyn.util.ssh.BashCommands.INSTALL_TAR;
+import static org.apache.brooklyn.util.ssh.BashCommands.INSTALL_UNZIP;
+import static org.apache.brooklyn.util.ssh.BashCommands.installExecutable;
+import static org.apache.brooklyn.util.ssh.BashCommands.sudo;
+
+import org.apache.brooklyn.util.ssh.BashCommands;
+
+public class AnsibleBashCommands {
+
+ public static final String INSTALL_ANSIBLE =
+ BashCommands.chain(
+ sudo("apt-add-repository -y ppa:ansible/ansible"),
+ INSTALL_CURL,
+ INSTALL_TAR,
+ INSTALL_UNZIP,
+ installExecutable("ansible"));
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/373c598a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java
new file mode 100644
index 0000000..b201294
--- /dev/null
+++ b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java
@@ -0,0 +1,62 @@
+/*
+ * 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.cm.ansible;
+
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.util.core.flags.SetFromFlag;
+
+import com.google.common.annotations.Beta;
+
+/** {@link ConfigKey}s used to configure Ansible */
+@Beta
+public interface AnsibleConfig {
+
+ public static enum AnsibleModes {
+ PLAYBOOK
+ };
+
+ @SetFromFlag("playbook")
+ public static final ConfigKey<String> ANSIBLE_PLAYBOOK = ConfigKeys.newStringConfigKey("brooklyn.ansible.playbook",
+ "Playbook to be execute by Ansible");
+
+ @SetFromFlag("playbook.yaml")
+ public static final ConfigKey<String> ANSIBLE_PLAYBOOK_YAML = ConfigKeys.newStringConfigKey("brooklyn.ansible.playbookYaml",
+ "Playbook to be execute by Ansible");
+
+ @SetFromFlag("playbook.url")
+ public static final ConfigKey<String> ANSIBLE_PLAYBOOK_URL = ConfigKeys.newStringConfigKey("brooklyn.ansible.playbookUrl");
+
+ @SetFromFlag("ansible.service.start")
+ public static final ConfigKey<String> ANSIBLE_SERVICE_START = ConfigKeys.newStringConfigKey("ansible.service.start",
+ "Default start command used with conjunction with the Ansible's service module",
+ "sudo ansible localhost -c local -m service -a \"name=%s state=started\"");
+
+ @SetFromFlag("ansible.service.stop")
+ public static final ConfigKey<String> ANSIBLE_SERVICE_STOP = ConfigKeys.newStringConfigKey("ansible.service.stop",
+ "Default stop command used with conjunction with the Ansible's service module",
+ "sudo ansible localhost -c local -m service -a \"name=%s state=stopped\"");
+
+ @SetFromFlag("ansible.service.checkPort")
+ public static final ConfigKey<Integer> ANSIBLE_SERVICE_CHECK_PORT = ConfigKeys.newIntegerConfigKey("ansible.service.check.port");
+
+ @SetFromFlag("service.name")
+ public static final ConfigKey<String> SERVICE_NAME = ConfigKeys.newStringConfigKey("brooklyn.ansible.serviceName",
+ "Name of OS service this will run as, for use in checking running and stopping");
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/373c598a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntity.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntity.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntity.java
new file mode 100644
index 0000000..0124854
--- /dev/null
+++ b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntity.java
@@ -0,0 +1,26 @@
+/*
+ * 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.cm.ansible;
+
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.entity.software.base.SoftwareProcess;
+
+@ImplementedBy(AnsibleEntityImpl.class)
+public interface AnsibleEntity extends SoftwareProcess, AnsibleConfig {
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/373c598a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
new file mode 100644
index 0000000..bd797e6
--- /dev/null
+++ b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
@@ -0,0 +1,41 @@
+/*
+ * 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.cm.ansible;
+
+import org.apache.brooklyn.entity.stock.EffectorStartableImpl;
+import org.apache.brooklyn.util.text.Strings;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class AnsibleEntityImpl extends EffectorStartableImpl implements AnsibleEntity {
+
+ public void init() {
+ checkNotNull(getConfig(SERVICE_NAME), "service name is missing. it has to be provided by the user");
+ String playbookName = getConfig(ANSIBLE_PLAYBOOK);
+ if (!Strings.isBlank(playbookName)) setDefaultDisplayName(playbookName + " (ansible)");
+
+ super.init();
+ new AnsibleLifecycleEffectorTasks().attachLifecycleEffectors(this);
+ }
+
+ @Override
+ public void populateServiceNotUpDiagnostics() {
+ // TODO no-op currently; should check ssh'able etc
+ }
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/373c598a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java
new file mode 100644
index 0000000..0262af3
--- /dev/null
+++ b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java
@@ -0,0 +1,180 @@
+/*
+ * 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.cm.ansible;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.location.Locations;
+import org.apache.brooklyn.core.location.Machines;
+import org.apache.brooklyn.entity.software.base.SoftwareProcess;
+import org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks;
+import org.apache.brooklyn.feed.ssh.SshFeed;
+import org.apache.brooklyn.feed.ssh.SshPollConfig;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.brooklyn.util.core.task.DynamicTasks;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.net.Urls;
+import org.apache.brooklyn.util.text.Strings;
+import org.apache.brooklyn.util.time.Duration;
+import org.apache.brooklyn.util.time.Time;
+
+import com.google.common.base.Supplier;
+
+public class AnsibleLifecycleEffectorTasks extends MachineLifecycleEffectorTasks implements AnsibleConfig {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AnsibleLifecycleEffectorTasks.class);
+
+ protected String serviceName;
+ protected SshFeed serviceSshFeed;
+
+ public AnsibleLifecycleEffectorTasks() {
+ }
+
+ public String getServiceName() {
+ if (serviceName!=null) return serviceName;
+ return serviceName = entity().config().get(AnsibleConfig.SERVICE_NAME);
+ }
+
+ @Override
+ public void attachLifecycleEffectors(Entity entity) {
+ if (getServiceName()==null && getClass().equals(AnsibleLifecycleEffectorTasks.class)) {
+ // warn on incorrect usage
+ LOG.warn("Uses of "+getClass()+" must define a PID file or a service name (or subclass and override {start,stop} methods as per javadoc) " +
+ "in order for check-running and stop to work");
+ }
+ super.attachLifecycleEffectors(entity);
+ }
+
+ @Override
+ protected String startProcessesAtMachine(Supplier<MachineLocation> machineS) {
+ startWithAnsibleAsync();
+
+ return "ansible start tasks submitted";
+ }
+
+ protected String getPlaybookName() {
+ return entity().config().get(ANSIBLE_PLAYBOOK);
+ }
+
+ protected void startWithAnsibleAsync() {
+ String baseDir = MachineLifecycleEffectorTasks.resolveOnBoxDir(entity(), Machines.findUniqueMachineLocation(entity().getLocations(), SshMachineLocation.class).get());
+ String installDir = Urls.mergePaths(baseDir, "installs/ansible");
+
+ String playbookUrl = entity().config().get(ANSIBLE_PLAYBOOK_URL);
+ String playbookYaml = entity().config().get(ANSIBLE_PLAYBOOK_YAML);
+
+ if (Strings.isNonBlank(playbookUrl) && Strings.isNonBlank(playbookYaml)) {
+ throw new IllegalArgumentException("You can specify " + AnsibleConfig.ANSIBLE_PLAYBOOK_URL.getName() + " or " + AnsibleConfig.ANSIBLE_PLAYBOOK_YAML.getName() + " but not both of them!");
+ }
+
+ DynamicTasks.queue(AnsiblePlaybookTasks.installAnsible(installDir, false));
+
+ String runDir = Urls.mergePaths(baseDir, "apps/"+entity().getApplicationId()+"/ansible/playbooks/"+entity().getEntityType().getSimpleName()+"_"+entity().getId());
+
+ if (Strings.isNonBlank(playbookUrl)) {
+ DynamicTasks.queue(AnsiblePlaybookTasks.installPlaybook(runDir, getPlaybookName(), playbookUrl));
+ }
+
+ if (Strings.isNonBlank(playbookYaml)) {
+ DynamicTasks.queue(AnsiblePlaybookTasks.buildPlaybookFile(runDir, getPlaybookName()));
+ }
+ DynamicTasks.queue(AnsiblePlaybookTasks.runAnsible(runDir, getPlaybookName()));
+ }
+
+ protected void postStartCustom() {
+ boolean result = false;
+ result |= tryCheckStartService();
+
+ if (!result) {
+ LOG.warn("No way to check whether "+entity()+" is running; assuming yes");
+ }
+ entity().sensors().set(SoftwareProcess.SERVICE_UP, true);
+
+ Maybe<SshMachineLocation> machine = Locations.findUniqueSshMachineLocation(entity().getLocations());
+
+ if (machine.isPresent()) {
+
+ String serviceName = String.format("[%s]%s", entity().config().get(SERVICE_NAME).substring(0, 1),
+ entity().config().get(SERVICE_NAME).substring(1));
+ String checkCmd = String.format("ps -ef | grep %s", serviceName);
+
+ Integer serviceCheckPort = entity().config().get(ANSIBLE_SERVICE_CHECK_PORT);
+
+ if (serviceCheckPort != null) {
+ checkCmd = String.format("sudo ansible localhost -c local -m wait_for -a \"host=0.0.0.0 port=%d\"", serviceCheckPort);
+ }
+ serviceSshFeed = SshFeed.builder()
+ .entity(entity())
+ .period(Duration.ONE_MINUTE)
+ .machine(machine.get())
+ .poll(new SshPollConfig<Boolean>(Startable.SERVICE_UP)
+ .command(checkCmd)
+ .setOnSuccess(true)
+ .setOnFailureOrException(false))
+ .build();
+
+ entity().feeds().addFeed(serviceSshFeed);
+ } else {
+ LOG.warn("Location(s) {} not an ssh-machine location, so not polling for status; setting serviceUp immediately", entity().getLocations());
+ }
+ }
+
+ protected boolean tryCheckStartService() {
+ if (getServiceName()==null) return false;
+
+ // if it's still up after 5s assume we are good (default behaviour)
+ Time.sleep(Duration.FIVE_SECONDS);
+ if (!((Integer)0).equals(DynamicTasks.queue(SshEffectorTasks.ssh(String.format(entity().config().get(AnsibleConfig.ANSIBLE_SERVICE_START), getServiceName()))).get())) {
+ throw new IllegalStateException("The process for "+entity()+" appears not to be running (service "+getServiceName()+")");
+ }
+
+ return true;
+ }
+
+ @Override
+ protected String stopProcessesAtMachine() {
+ boolean result = false;
+ result |= tryStopService();
+ if (!result) {
+ throw new IllegalStateException("The process for "+entity()+" could not be stopped (no impl!)");
+ }
+ return "stopped";
+ }
+
+ @Override
+ protected StopMachineDetails<Integer> stopAnyProvisionedMachines() {
+ return super.stopAnyProvisionedMachines();
+ }
+
+ protected boolean tryStopService() {
+ if (getServiceName()==null) return false;
+ int result = DynamicTasks.queue(SshEffectorTasks.ssh(String.format(entity().config().get(AnsibleConfig.ANSIBLE_SERVICE_STOP), getServiceName()))).get();
+ if (0 == result) return true;
+ if (entity().getAttribute(Attributes.SERVICE_STATE_ACTUAL) != Lifecycle.RUNNING)
+ return true;
+
+ throw new IllegalStateException("The process for "+entity()+" appears could not be stopped (exit code "+result+" to service stop)");
+ }
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/373c598a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
new file mode 100644
index 0000000..1579e2d
--- /dev/null
+++ b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
@@ -0,0 +1,72 @@
+/*
+ * 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.cm.ansible;
+
+import org.apache.brooklyn.api.entity.Entity;
+
+import org.apache.brooklyn.api.mgmt.TaskFactory;
+import org.apache.brooklyn.core.effector.EffectorTasks;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
+import org.apache.brooklyn.util.core.ResourceUtils;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.net.Urls;
+import org.apache.brooklyn.util.ssh.BashCommands;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AnsiblePlaybookTasks {
+ private static final Logger LOG = LoggerFactory.getLogger(AnsiblePlaybookTasks.class);
+
+ public static TaskFactory<?> installAnsible(String ansibleDirectory, boolean force) {
+ String installCmd = cdAndRun(ansibleDirectory, AnsibleBashCommands.INSTALL_ANSIBLE);
+ if (!force) installCmd = BashCommands.alternatives("which ansible", installCmd);
+ return SshEffectorTasks.ssh(installCmd).summary("install ansible");
+ }
+
+ public static TaskFactory<?> installPlaybook(final String ansibleDirectory, final String playbookName, final String playbookUrl) {
+ return Tasks.sequential("build ansible playbook file for "+playbookName,
+ SshEffectorTasks.put(ansibleDirectory + "/" + playbookName + ".yaml").contents(ResourceUtils.create().getResourceFromUrl(playbookUrl)).createDirectory());
+ }
+
+ protected static String cdAndRun(String targetDirectory, String command) {
+ return BashCommands.chain("mkdir -p "+targetDirectory,
+ "cd "+targetDirectory,
+ command);
+ }
+
+ public static TaskFactory<?> buildPlaybookFile(final String ansibleDirectory, String playbook) {
+ Entity entity = EffectorTasks.findEntity();
+ String yaml = entity.config().get(AnsibleConfig.ANSIBLE_PLAYBOOK_YAML);
+
+ return Tasks.sequential("build ansible playbook file for "+ playbook,
+ SshEffectorTasks.put(Urls.mergePaths(ansibleDirectory) + "/" + playbook + ".yaml").contents(yaml).createDirectory());
+ }
+
+ public static TaskFactory<?> runAnsible(final String ansibleDirectory, String playbookName) {
+ String cmd = String.format("sudo ansible-playbook -i \"localhost,\" -c local -s %s.yaml", playbookName);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Ansible command: {}", cmd);
+ }
+
+ return SshEffectorTasks.ssh(cdAndRun(ansibleDirectory, cmd)).
+ summary("run ansible playbook for " + playbookName).requiringExitCodeZero();
+ }
+
+}
[5/7] brooklyn-library git commit: Add effector for ad-hoc ansible
commands.
Posted by he...@apache.org.
Add effector for ad-hoc ansible commands.
For example (using the command line):
br app utest ent apc effector ansibleCommand invoke -P module=shell -P args='curl http://myhost:8080/additional.html > /var/www/html/additional.html'
This invokes the ad-hoc ansible command to add a file to an Apache documents folder.
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-library/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-library/commit/8de0e9fd
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-library/tree/8de0e9fd
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-library/diff/8de0e9fd
Branch: refs/heads/master
Commit: 8de0e9fdf1c894da6c949ccfd75c77e9d24badf4
Parents: d5026df
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Tue Feb 9 17:28:44 2016 +0000
Committer: Yavor Yanchev <ya...@yanchev.com>
Committed: Wed Feb 17 11:43:03 2016 +0200
----------------------------------------------------------------------
.../brooklyn/entity/cm/ansible/AnsibleEntity.java | 14 ++++++++++++++
.../entity/cm/ansible/AnsibleEntityImpl.java | 16 +++++++++++++++-
.../entity/cm/ansible/AnsiblePlaybookTasks.java | 14 ++++++++++++--
3 files changed, 41 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/8de0e9fd/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntity.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntity.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntity.java
index 0124854..a2c9676 100644
--- a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntity.java
+++ b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntity.java
@@ -19,8 +19,22 @@
package org.apache.brooklyn.entity.cm.ansible;
import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.core.annotation.Effector;
+import org.apache.brooklyn.core.annotation.EffectorParam;
+import org.apache.brooklyn.core.effector.MethodEffector;
import org.apache.brooklyn.entity.software.base.SoftwareProcess;
@ImplementedBy(AnsibleEntityImpl.class)
public interface AnsibleEntity extends SoftwareProcess, AnsibleConfig {
+
+ MethodEffector<String> ANSIBLE_COMMAND = new MethodEffector<>(AnsibleEntity.class, "ansibleCommand");
+
+ @Effector(description = "Invoke an arbitrary Ansible command, optionally specifying the module (default is 'command')")
+ String ansibleCommand(
+ @EffectorParam(name="module", description = "Name of the Ansible module to invoke", defaultValue = "command")
+ String module,
+ @EffectorParam(name="args", description = "Arguments for the ansible command")
+ String args
+ );
+
}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/8de0e9fd/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
index bd797e6..b34603e 100644
--- a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
+++ b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
@@ -19,6 +19,8 @@
package org.apache.brooklyn.entity.cm.ansible;
import org.apache.brooklyn.entity.stock.EffectorStartableImpl;
+import org.apache.brooklyn.util.core.task.DynamicTasks;
+import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
import org.apache.brooklyn.util.text.Strings;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -37,5 +39,17 @@ public class AnsibleEntityImpl extends EffectorStartableImpl implements AnsibleE
@Override
public void populateServiceNotUpDiagnostics() {
// TODO no-op currently; should check ssh'able etc
- }
+ }
+
+ @Override
+ public String ansibleCommand(String module, String args) {
+ final ProcessTaskWrapper<Integer> command = DynamicTasks.queue(AnsiblePlaybookTasks.moduleCommand(module, args));
+ command.asTask().blockUntilEnded();
+ if (0 == command.getExitCode()) {
+ return command.getStdout();
+ } else {
+ throw new RuntimeException("Command (" + args + ") in module " + module
+ + " failed with stderr:\n" + command.getStderr() + "\n");
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/8de0e9fd/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
index 1579e2d..29924d4 100644
--- a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
+++ b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
@@ -19,17 +19,21 @@
package org.apache.brooklyn.entity.cm.ansible;
import org.apache.brooklyn.api.entity.Entity;
-
import org.apache.brooklyn.api.mgmt.TaskFactory;
import org.apache.brooklyn.core.effector.EffectorTasks;
import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
import org.apache.brooklyn.util.core.ResourceUtils;
import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.core.task.system.ProcessTaskFactory;
import org.apache.brooklyn.util.net.Urls;
import org.apache.brooklyn.util.ssh.BashCommands;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.Map;
+
+import static org.apache.brooklyn.util.ssh.BashCommands.sudo;
+
public class AnsiblePlaybookTasks {
private static final Logger LOG = LoggerFactory.getLogger(AnsiblePlaybookTasks.class);
@@ -68,5 +72,11 @@ public class AnsiblePlaybookTasks {
return SshEffectorTasks.ssh(cdAndRun(ansibleDirectory, cmd)).
summary("run ansible playbook for " + playbookName).requiringExitCodeZero();
}
-
+
+ public static ProcessTaskFactory<Integer> moduleCommand(String module, String args) {
+ final String command = "ansible localhost -m '" + module + "' -a '" + args + "'";
+ return SshEffectorTasks.ssh(sudo(command))
+ .summary("ad-hoc: " + command).requiringExitCodeZero();
+ }
}
+
[7/7] brooklyn-library git commit: This closes #5
Posted by he...@apache.org.
This closes #5
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-library/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-library/commit/b8395ff3
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-library/tree/b8395ff3
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-library/diff/b8395ff3
Branch: refs/heads/master
Commit: b8395ff302a805fef161ea1079794ebaa9cd1810
Parents: 9fdf1db a01cba0
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Feb 19 10:07:28 2016 +0000
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Feb 19 10:07:28 2016 +0000
----------------------------------------------------------------------
software/cm/ansible/pom.xml | 84 +++++++
.../entity/cm/ansible/AnsibleBashCommands.java | 39 ++++
.../entity/cm/ansible/AnsibleConfig.java | 70 ++++++
.../entity/cm/ansible/AnsibleEntity.java | 40 ++++
.../entity/cm/ansible/AnsibleEntityImpl.java | 59 +++++
.../ansible/AnsibleLifecycleEffectorTasks.java | 227 +++++++++++++++++++
.../entity/cm/ansible/AnsiblePlaybookTasks.java | 109 +++++++++
.../ansible/AnsibleEntityIntegrationTest.java | 116 ++++++++++
software/cm/pom.xml | 2 +-
9 files changed, 745 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
[2/7] brooklyn-library git commit: Ansible Integration test
Posted by he...@apache.org.
Ansible Integration test
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-library/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-library/commit/d5026df1
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-library/tree/d5026df1
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-library/diff/d5026df1
Branch: refs/heads/master
Commit: d5026df1da2df5bb9d375a82babfed5d1f1b0c3f
Parents: 373c598
Author: Yavor Yanchev <ya...@yanchev.com>
Authored: Thu Feb 11 12:14:10 2016 +0200
Committer: Yavor Yanchev <ya...@yanchev.com>
Committed: Wed Feb 17 11:43:03 2016 +0200
----------------------------------------------------------------------
.../ansible/AnsibleEntityIntegrationTest.java | 116 +++++++++++++++++++
1 file changed, 116 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/d5026df1/software/cm/src/test/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/cm/src/test/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityIntegrationTest.java b/software/cm/src/test/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityIntegrationTest.java
new file mode 100644
index 0000000..76e993d
--- /dev/null
+++ b/software/cm/src/test/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityIntegrationTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.cm.ansible;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.MachineDetails;
+import org.apache.brooklyn.api.location.OsDetails;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityAsserts;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.location.BasicMachineDetails;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+
+public class AnsibleEntityIntegrationTest {
+ protected TestApplication app;
+ protected LocalhostMachineProvisioningLocation testLocation;
+ protected AnsibleEntity ansible;
+ protected SshMachineLocation sshHost;
+
+ String playbookYaml = Joiner.on("\n").join(
+ "---",
+ "- hosts: localhost",
+ " sudo: True",
+ "",
+ " tasks:",
+ " - apt: name=apache2 state=latest",
+ " when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'",
+ "",
+ " - yum: name=httpd state=latest",
+ " when: ansible_distribution == 'CentOS' or ansible_distribution == 'Red Hat Enterprise Linux'",
+ "",
+ " - service: name=apache2 state=started enabled=no",
+ " when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'",
+ "",
+ " - service: name=httpd state=started enabled=no",
+ " when: ansible_distribution == 'CentOS' or ansible_distribution == 'Red Hat Enterprise Linux'");
+
+ @BeforeMethod(alwaysRun = true)
+ public void setup() throws Exception {
+ app = TestApplication.Factory.newManagedInstanceForTests();;
+ testLocation = new LocalhostMachineProvisioningLocation();
+ sshHost = testLocation.obtain();
+ }
+
+ @AfterMethod(alwaysRun = true)
+ public void shutdown() {
+ Entities.destroyAll(app.getManagementContext());
+ }
+
+ @Test(groups = {"Integration"})
+ public void testAnsible() {
+ Task<BasicMachineDetails> detailsTask = app.getExecutionContext().submit(
+ BasicMachineDetails.taskForSshMachineLocation(sshHost));
+ MachineDetails machine = detailsTask.getUnchecked();
+
+
+ OsDetails details = machine.getOsDetails();
+
+ String osName = details.getName();
+ String playbookServiceName = getPlaybookServiceName(osName);
+ ansible = app.createAndManageChild(EntitySpec.create(AnsibleEntity.class)
+ .configure("playbook.yaml", playbookYaml)
+ .configure("playbook", playbookServiceName)
+ .configure("service.name", playbookServiceName));
+
+ app.start(ImmutableList.of(testLocation));
+ EntityAsserts.assertAttributeEqualsEventually(ansible, Startable.SERVICE_UP, true);
+
+ ansible.stop();
+ EntityAsserts.assertAttributeEqualsEventually(ansible, Startable.SERVICE_UP, false);
+ }
+
+ private String getPlaybookServiceName(String os) {
+ String name;
+
+ switch (os.toLowerCase()) {
+ case "fedora":
+ name = "httpd";
+ break;
+ case "centos":
+ name = "httpd";
+ break;
+ default:
+ name = "apache2";
+ }
+ return name;
+ }
+}
+
+
[4/7] brooklyn-library git commit: Addition of Ansible extra vars
from Brooklyn config.
Posted by he...@apache.org.
Addition of Ansible extra vars from Brooklyn config.
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-library/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-library/commit/121db325
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-library/tree/121db325
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-library/diff/121db325
Branch: refs/heads/master
Commit: 121db3252a606aebdd9fc7a038f9920f082fdd8a
Parents: 8de0e9f
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Wed Feb 10 14:44:54 2016 +0000
Committer: Yavor Yanchev <ya...@yanchev.com>
Committed: Wed Feb 17 11:43:03 2016 +0200
----------------------------------------------------------------------
.../entity/cm/ansible/AnsibleConfig.java | 20 ++++----
.../entity/cm/ansible/AnsibleEntityImpl.java | 24 ++++++----
.../ansible/AnsibleLifecycleEffectorTasks.java | 49 ++++++++++++++------
.../entity/cm/ansible/AnsiblePlaybookTasks.java | 47 +++++++++++++++----
4 files changed, 100 insertions(+), 40 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/121db325/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java
index b201294..d63c2c6 100644
--- a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java
+++ b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java
@@ -28,35 +28,39 @@ import com.google.common.annotations.Beta;
@Beta
public interface AnsibleConfig {
- public static enum AnsibleModes {
+ enum AnsibleModes {
PLAYBOOK
};
@SetFromFlag("playbook")
- public static final ConfigKey<String> ANSIBLE_PLAYBOOK = ConfigKeys.newStringConfigKey("brooklyn.ansible.playbook",
+ ConfigKey<String> ANSIBLE_PLAYBOOK = ConfigKeys.newStringConfigKey("brooklyn.ansible.playbook",
"Playbook to be execute by Ansible");
@SetFromFlag("playbook.yaml")
- public static final ConfigKey<String> ANSIBLE_PLAYBOOK_YAML = ConfigKeys.newStringConfigKey("brooklyn.ansible.playbookYaml",
+ ConfigKey<String> ANSIBLE_PLAYBOOK_YAML = ConfigKeys.newStringConfigKey("brooklyn.ansible.playbookYaml",
"Playbook to be execute by Ansible");
@SetFromFlag("playbook.url")
- public static final ConfigKey<String> ANSIBLE_PLAYBOOK_URL = ConfigKeys.newStringConfigKey("brooklyn.ansible.playbookUrl");
+ ConfigKey<String> ANSIBLE_PLAYBOOK_URL = ConfigKeys.newStringConfigKey("brooklyn.ansible.playbookUrl");
@SetFromFlag("ansible.service.start")
- public static final ConfigKey<String> ANSIBLE_SERVICE_START = ConfigKeys.newStringConfigKey("ansible.service.start",
+ ConfigKey<String> ANSIBLE_SERVICE_START = ConfigKeys.newStringConfigKey("ansible.service.start",
"Default start command used with conjunction with the Ansible's service module",
"sudo ansible localhost -c local -m service -a \"name=%s state=started\"");
@SetFromFlag("ansible.service.stop")
- public static final ConfigKey<String> ANSIBLE_SERVICE_STOP = ConfigKeys.newStringConfigKey("ansible.service.stop",
+ ConfigKey<String> ANSIBLE_SERVICE_STOP = ConfigKeys.newStringConfigKey("ansible.service.stop",
"Default stop command used with conjunction with the Ansible's service module",
"sudo ansible localhost -c local -m service -a \"name=%s state=stopped\"");
@SetFromFlag("ansible.service.checkPort")
- public static final ConfigKey<Integer> ANSIBLE_SERVICE_CHECK_PORT = ConfigKeys.newIntegerConfigKey("ansible.service.check.port");
+ ConfigKey<Integer> ANSIBLE_SERVICE_CHECK_PORT = ConfigKeys.newIntegerConfigKey("ansible.service.check.port");
@SetFromFlag("service.name")
- public static final ConfigKey<String> SERVICE_NAME = ConfigKeys.newStringConfigKey("brooklyn.ansible.serviceName",
+ ConfigKey<String> SERVICE_NAME = ConfigKeys.newStringConfigKey("brooklyn.ansible.serviceName",
"Name of OS service this will run as, for use in checking running and stopping");
+
+ @SetFromFlag("ansible.vars")
+ ConfigKey<Object> ANSIBLE_VARS = ConfigKeys.newConfigKey(Object.class, "brooklyn.ansible.vars",
+ "Ansible 'extra-vars' variable configuration values");
}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/121db325/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
index b34603e..c2635ca 100644
--- a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
+++ b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
@@ -27,13 +27,18 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class AnsibleEntityImpl extends EffectorStartableImpl implements AnsibleEntity {
+ private AnsibleLifecycleEffectorTasks lifecycleTasks;
+
public void init() {
checkNotNull(getConfig(SERVICE_NAME), "service name is missing. it has to be provided by the user");
String playbookName = getConfig(ANSIBLE_PLAYBOOK);
if (!Strings.isBlank(playbookName)) setDefaultDisplayName(playbookName + " (ansible)");
super.init();
- new AnsibleLifecycleEffectorTasks().attachLifecycleEffectors(this);
+
+ lifecycleTasks = new AnsibleLifecycleEffectorTasks();
+
+ lifecycleTasks.attachLifecycleEffectors(this);
}
@Override
@@ -43,13 +48,14 @@ public class AnsibleEntityImpl extends EffectorStartableImpl implements AnsibleE
@Override
public String ansibleCommand(String module, String args) {
- final ProcessTaskWrapper<Integer> command = DynamicTasks.queue(AnsiblePlaybookTasks.moduleCommand(module, args));
- command.asTask().blockUntilEnded();
- if (0 == command.getExitCode()) {
- return command.getStdout();
- } else {
- throw new RuntimeException("Command (" + args + ") in module " + module
- + " failed with stderr:\n" + command.getStderr() + "\n");
- }
+ final ProcessTaskWrapper<Integer> command = DynamicTasks.queue(
+ AnsiblePlaybookTasks.moduleCommand(module, config().get(ANSIBLE_VARS), lifecycleTasks.getRunDir(), args));
+ command.asTask().blockUntilEnded();
+ if (0 == command.getExitCode()) {
+ return command.getStdout();
+ } else {
+ throw new RuntimeException("Command (" + args + ") in module " + module
+ + " failed with stderr:\n" + command.getStderr() + "\n");
+ }
}
}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/121db325/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java
index 0262af3..e1a8622 100644
--- a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java
+++ b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java
@@ -18,6 +18,7 @@
*/
package org.apache.brooklyn.entity.cm.ansible;
+import com.google.common.base.Supplier;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.location.MachineLocation;
import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
@@ -31,16 +32,14 @@ import org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffect
import org.apache.brooklyn.feed.ssh.SshFeed;
import org.apache.brooklyn.feed.ssh.SshPollConfig;
import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.apache.brooklyn.util.core.task.DynamicTasks;
import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.net.Urls;
import org.apache.brooklyn.util.text.Strings;
import org.apache.brooklyn.util.time.Duration;
import org.apache.brooklyn.util.time.Time;
-
-import com.google.common.base.Supplier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class AnsibleLifecycleEffectorTasks extends MachineLifecycleEffectorTasks implements AnsibleConfig {
@@ -48,7 +47,11 @@ public class AnsibleLifecycleEffectorTasks extends MachineLifecycleEffectorTasks
protected String serviceName;
protected SshFeed serviceSshFeed;
-
+
+ protected Object extraVars;
+ protected String baseDir;
+ protected String runDir;
+
public AnsibleLifecycleEffectorTasks() {
}
@@ -57,6 +60,23 @@ public class AnsibleLifecycleEffectorTasks extends MachineLifecycleEffectorTasks
return serviceName = entity().config().get(AnsibleConfig.SERVICE_NAME);
}
+ public Object getExtraVars() {
+ if (extraVars != null) return extraVars;
+ return extraVars = entity().config().get(ANSIBLE_VARS);
+ }
+
+ public String getBaseDir() {
+ if (null != baseDir) return baseDir;
+ return baseDir = MachineLifecycleEffectorTasks.resolveOnBoxDir(entity(),
+ Machines.findUniqueMachineLocation(entity().getLocations(), SshMachineLocation.class).get());
+ }
+
+ public String getRunDir() {
+ if (null != runDir) return runDir;
+ return runDir = Urls.mergePaths(getBaseDir(), "apps/"+entity().getApplicationId()+"/ansible/playbooks/"
+ +entity().getEntityType().getSimpleName()+"_"+entity().getId());
+ }
+
@Override
public void attachLifecycleEffectors(Entity entity) {
if (getServiceName()==null && getClass().equals(AnsibleLifecycleEffectorTasks.class)) {
@@ -79,30 +99,33 @@ public class AnsibleLifecycleEffectorTasks extends MachineLifecycleEffectorTasks
}
protected void startWithAnsibleAsync() {
- String baseDir = MachineLifecycleEffectorTasks.resolveOnBoxDir(entity(), Machines.findUniqueMachineLocation(entity().getLocations(), SshMachineLocation.class).get());
- String installDir = Urls.mergePaths(baseDir, "installs/ansible");
+ String installDir = Urls.mergePaths(getBaseDir(), "installs/ansible");
String playbookUrl = entity().config().get(ANSIBLE_PLAYBOOK_URL);
String playbookYaml = entity().config().get(ANSIBLE_PLAYBOOK_YAML);
if (Strings.isNonBlank(playbookUrl) && Strings.isNonBlank(playbookYaml)) {
- throw new IllegalArgumentException("You can specify " + AnsibleConfig.ANSIBLE_PLAYBOOK_URL.getName() + " or " + AnsibleConfig.ANSIBLE_PLAYBOOK_YAML.getName() + " but not both of them!");
+ throw new IllegalArgumentException("You can specify " + AnsibleConfig.ANSIBLE_PLAYBOOK_URL.getName()
+ + " or " + AnsibleConfig.ANSIBLE_PLAYBOOK_YAML.getName() + " but not both of them!");
}
DynamicTasks.queue(AnsiblePlaybookTasks.installAnsible(installDir, false));
- String runDir = Urls.mergePaths(baseDir, "apps/"+entity().getApplicationId()+"/ansible/playbooks/"+entity().getEntityType().getSimpleName()+"_"+entity().getId());
-
+ if (getExtraVars() != null) {
+ DynamicTasks.queue(AnsiblePlaybookTasks.configureExtraVars(getRunDir(), extraVars, false));
+ }
+
if (Strings.isNonBlank(playbookUrl)) {
- DynamicTasks.queue(AnsiblePlaybookTasks.installPlaybook(runDir, getPlaybookName(), playbookUrl));
+ DynamicTasks.queue(AnsiblePlaybookTasks.installPlaybook(getRunDir(), getPlaybookName(), playbookUrl));
}
if (Strings.isNonBlank(playbookYaml)) {
- DynamicTasks.queue(AnsiblePlaybookTasks.buildPlaybookFile(runDir, getPlaybookName()));
+ DynamicTasks.queue(AnsiblePlaybookTasks.buildPlaybookFile(getRunDir(), getPlaybookName()));
}
- DynamicTasks.queue(AnsiblePlaybookTasks.runAnsible(runDir, getPlaybookName()));
+ DynamicTasks.queue(AnsiblePlaybookTasks.runAnsible(getRunDir(), getExtraVars(), getPlaybookName()));
}
+
protected void postStartCustom() {
boolean result = false;
result |= tryCheckStartService();
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/121db325/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
----------------------------------------------------------------------
diff --git a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
index 29924d4..36076a1 100644
--- a/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
+++ b/software/cm/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
@@ -27,15 +27,17 @@ import org.apache.brooklyn.util.core.task.Tasks;
import org.apache.brooklyn.util.core.task.system.ProcessTaskFactory;
import org.apache.brooklyn.util.net.Urls;
import org.apache.brooklyn.util.ssh.BashCommands;
+import org.apache.brooklyn.util.text.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
-import java.util.Map;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
import static org.apache.brooklyn.util.ssh.BashCommands.sudo;
public class AnsiblePlaybookTasks {
private static final Logger LOG = LoggerFactory.getLogger(AnsiblePlaybookTasks.class);
+ private static final String EXTRA_VARS_FILENAME = "extra_vars.yaml";
public static TaskFactory<?> installAnsible(String ansibleDirectory, boolean force) {
String installCmd = cdAndRun(ansibleDirectory, AnsibleBashCommands.INSTALL_ANSIBLE);
@@ -45,7 +47,9 @@ public class AnsiblePlaybookTasks {
public static TaskFactory<?> installPlaybook(final String ansibleDirectory, final String playbookName, final String playbookUrl) {
return Tasks.sequential("build ansible playbook file for "+playbookName,
- SshEffectorTasks.put(ansibleDirectory + "/" + playbookName + ".yaml").contents(ResourceUtils.create().getResourceFromUrl(playbookUrl)).createDirectory());
+ SshEffectorTasks.put(ansibleDirectory + "/" + playbookName + ".yaml")
+ .contents(ResourceUtils.create().getResourceFromUrl(playbookUrl))
+ .createDirectory());
}
protected static String cdAndRun(String targetDirectory, String command) {
@@ -59,24 +63,47 @@ public class AnsiblePlaybookTasks {
String yaml = entity.config().get(AnsibleConfig.ANSIBLE_PLAYBOOK_YAML);
return Tasks.sequential("build ansible playbook file for "+ playbook,
- SshEffectorTasks.put(Urls.mergePaths(ansibleDirectory) + "/" + playbook + ".yaml").contents(yaml).createDirectory());
+ SshEffectorTasks.put(Urls.mergePaths(ansibleDirectory) + "/" + playbook + ".yaml")
+ .contents(yaml).createDirectory());
}
- public static TaskFactory<?> runAnsible(final String ansibleDirectory, String playbookName) {
- String cmd = String.format("sudo ansible-playbook -i \"localhost,\" -c local -s %s.yaml", playbookName);
+ public static TaskFactory<?> runAnsible(final String dir, Object extraVars, String playbookName) {
+ String cmd = String.format("sudo ansible-playbook -i \"localhost,\" -c local "
+ + optionalExtraVarsParameter(extraVars)
+ + " -s %s.yaml", playbookName);
if (LOG.isDebugEnabled()) {
LOG.debug("Ansible command: {}", cmd);
}
- return SshEffectorTasks.ssh(cdAndRun(ansibleDirectory, cmd)).
+ return SshEffectorTasks.ssh(cdAndRun(dir, cmd)).
summary("run ansible playbook for " + playbookName).requiringExitCodeZero();
}
- public static ProcessTaskFactory<Integer> moduleCommand(String module, String args) {
- final String command = "ansible localhost -m '" + module + "' -a '" + args + "'";
- return SshEffectorTasks.ssh(sudo(command))
+ public static ProcessTaskFactory<Integer> moduleCommand(String module, Object extraVars, String root, String args) {
+ final String command = "ansible localhost "
+ + optionalExtraVarsParameter(extraVars)
+ + " -m '" + module + "' -a '" + args + "'";
+ return SshEffectorTasks.ssh(sudo(BashCommands.chain("cd " + root, command)))
.summary("ad-hoc: " + command).requiringExitCodeZero();
}
+
+ public static TaskFactory<?> configureExtraVars(String dir, Object extraVars, boolean force) {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
+ Yaml asYaml = new Yaml(options);
+ final String varsYaml = asYaml.dump(extraVars);
+ return SshEffectorTasks.put(Urls.mergePaths(dir, EXTRA_VARS_FILENAME))
+ .contents(varsYaml)
+ .summary("install extra vars")
+ .createDirectory();
+ }
+
+ private static String optionalExtraVarsParameter(Object extraVars) {
+ if (null == extraVars || Strings.isBlank(extraVars.toString())) {
+ return "";
+ }
+ return " --extra-vars \"@" + EXTRA_VARS_FILENAME + "\" ";
+ }
}
[6/7] brooklyn-library git commit: Addressing PR comments
Posted by he...@apache.org.
Addressing PR comments
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-library/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-library/commit/a01cba0c
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-library/tree/a01cba0c
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-library/diff/a01cba0c
Branch: refs/heads/master
Commit: a01cba0cabb8b3b980c51cd8b90bf9b2b715fe32
Parents: c1a8783
Author: Yavor Yanchev <ya...@yanchev.com>
Authored: Wed Feb 17 11:36:39 2016 +0200
Committer: Yavor Yanchev <ya...@yanchev.com>
Committed: Thu Feb 18 12:54:51 2016 +0200
----------------------------------------------------------------------
.../entity/cm/ansible/AnsibleBashCommands.java | 3 +-
.../entity/cm/ansible/AnsibleConfig.java | 8 +++-
.../entity/cm/ansible/AnsibleEntityImpl.java | 2 -
.../ansible/AnsibleLifecycleEffectorTasks.java | 48 +++++++++++++++-----
.../entity/cm/ansible/AnsiblePlaybookTasks.java | 4 +-
5 files changed, 46 insertions(+), 19 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/a01cba0c/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleBashCommands.java
----------------------------------------------------------------------
diff --git a/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleBashCommands.java b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleBashCommands.java
index e22ee34..ffe74e4 100644
--- a/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleBashCommands.java
+++ b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleBashCommands.java
@@ -22,6 +22,7 @@ import static org.apache.brooklyn.util.ssh.BashCommands.INSTALL_CURL;
import static org.apache.brooklyn.util.ssh.BashCommands.INSTALL_TAR;
import static org.apache.brooklyn.util.ssh.BashCommands.INSTALL_UNZIP;
import static org.apache.brooklyn.util.ssh.BashCommands.installExecutable;
+import static org.apache.brooklyn.util.ssh.BashCommands.ifExecutableElse0;
import static org.apache.brooklyn.util.ssh.BashCommands.sudo;
import org.apache.brooklyn.util.ssh.BashCommands;
@@ -30,7 +31,7 @@ public class AnsibleBashCommands {
public static final String INSTALL_ANSIBLE =
BashCommands.chain(
- sudo("apt-add-repository -y ppa:ansible/ansible"),
+ ifExecutableElse0("apt-add-repository",sudo("apt-add-repository -y ppa:ansible/ansible")),
INSTALL_CURL,
INSTALL_TAR,
INSTALL_UNZIP,
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/a01cba0c/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java
----------------------------------------------------------------------
diff --git a/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java
index d63c2c6..a47ffeb 100644
--- a/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java
+++ b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleConfig.java
@@ -46,12 +46,16 @@ public interface AnsibleConfig {
@SetFromFlag("ansible.service.start")
ConfigKey<String> ANSIBLE_SERVICE_START = ConfigKeys.newStringConfigKey("ansible.service.start",
"Default start command used with conjunction with the Ansible's service module",
- "sudo ansible localhost -c local -m service -a \"name=%s state=started\"");
+ "ansible localhost -c local -m service -a \"name=%s state=started\"");
@SetFromFlag("ansible.service.stop")
ConfigKey<String> ANSIBLE_SERVICE_STOP = ConfigKeys.newStringConfigKey("ansible.service.stop",
"Default stop command used with conjunction with the Ansible's service module",
- "sudo ansible localhost -c local -m service -a \"name=%s state=stopped\"");
+ "ansible localhost -c local -m service -a \"name=%s state=stopped\"");
+
+ @SetFromFlag("ansible.service.checkHost")
+ ConfigKey<String> ANSIBLE_SERVICE_CHECK_HOST = ConfigKeys.newStringConfigKey("ansible.service.check.host",
+ "IP to be checked. Default: All IPs ", "0.0.0.0");
@SetFromFlag("ansible.service.checkPort")
ConfigKey<Integer> ANSIBLE_SERVICE_CHECK_PORT = ConfigKeys.newIntegerConfigKey("ansible.service.check.port");
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/a01cba0c/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
----------------------------------------------------------------------
diff --git a/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
index c2635ca..43fcd72 100644
--- a/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
+++ b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleEntityImpl.java
@@ -41,12 +41,10 @@ public class AnsibleEntityImpl extends EffectorStartableImpl implements AnsibleE
lifecycleTasks.attachLifecycleEffectors(this);
}
- @Override
public void populateServiceNotUpDiagnostics() {
// TODO no-op currently; should check ssh'able etc
}
- @Override
public String ansibleCommand(String module, String args) {
final ProcessTaskWrapper<Integer> command = DynamicTasks.queue(
AnsiblePlaybookTasks.moduleCommand(module, config().get(ANSIBLE_VARS), lifecycleTasks.getRunDir(), args));
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/a01cba0c/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java
index e1a8622..e51d9e9 100644
--- a/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java
+++ b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsibleLifecycleEffectorTasks.java
@@ -35,6 +35,8 @@ import org.apache.brooklyn.location.ssh.SshMachineLocation;
import org.apache.brooklyn.util.core.task.DynamicTasks;
import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.net.Urls;
+
+import static org.apache.brooklyn.util.ssh.BashCommands.sudo;
import org.apache.brooklyn.util.text.Strings;
import org.apache.brooklyn.util.time.Duration;
import org.apache.brooklyn.util.time.Time;
@@ -99,14 +101,20 @@ public class AnsibleLifecycleEffectorTasks extends MachineLifecycleEffectorTasks
}
protected void startWithAnsibleAsync() {
+
String installDir = Urls.mergePaths(getBaseDir(), "installs/ansible");
String playbookUrl = entity().config().get(ANSIBLE_PLAYBOOK_URL);
String playbookYaml = entity().config().get(ANSIBLE_PLAYBOOK_YAML);
- if (Strings.isNonBlank(playbookUrl) && Strings.isNonBlank(playbookYaml)) {
- throw new IllegalArgumentException("You can specify " + AnsibleConfig.ANSIBLE_PLAYBOOK_URL.getName()
- + " or " + AnsibleConfig.ANSIBLE_PLAYBOOK_YAML.getName() + " but not both of them!");
+ if (playbookUrl != null && playbookYaml != null) {
+ throw new IllegalArgumentException( "You can not specify both "+ AnsibleConfig.ANSIBLE_PLAYBOOK_URL.getName() +
+ " and " + AnsibleConfig.ANSIBLE_PLAYBOOK_YAML.getName() + " as arguments.");
+ }
+
+ if (playbookUrl == null && playbookYaml == null) {
+ throw new IllegalArgumentException("You have to specify either " + AnsibleConfig.ANSIBLE_PLAYBOOK_URL.getName() +
+ " or " + AnsibleConfig.ANSIBLE_PLAYBOOK_YAML.getName() + " as arguments.");
}
DynamicTasks.queue(AnsiblePlaybookTasks.installAnsible(installDir, false));
@@ -138,15 +146,21 @@ public class AnsibleLifecycleEffectorTasks extends MachineLifecycleEffectorTasks
Maybe<SshMachineLocation> machine = Locations.findUniqueSshMachineLocation(entity().getLocations());
if (machine.isPresent()) {
-
- String serviceName = String.format("[%s]%s", entity().config().get(SERVICE_NAME).substring(0, 1),
- entity().config().get(SERVICE_NAME).substring(1));
- String checkCmd = String.format("ps -ef | grep %s", serviceName);
+ // For example “ps -f| grep httpd” matches for any process including the text “httpd”,
+ // which includes the grep command itself, whereas “ps | grep [h]ttpd” matches only processes
+ // including the text “httpd” (doesn’t include the grep) and additionally
+ // provides a correct return code
+ //
+ // The command constructed bellow will look like - ps -ef |grep [h]ttpd
+ String serviceNameCheck = getServiceName().replaceFirst("^(.)(.*)", "[$1]$2");
+ String checkCmd = String.format("ps -ef | grep %s", serviceNameCheck);
Integer serviceCheckPort = entity().config().get(ANSIBLE_SERVICE_CHECK_PORT);
if (serviceCheckPort != null) {
- checkCmd = String.format("sudo ansible localhost -c local -m wait_for -a \"host=0.0.0.0 port=%d\"", serviceCheckPort);
+ checkCmd = sudo(String.format("ansible localhost -c local -m wait_for -a \"host=" +
+ entity().config().get(ANSIBLE_SERVICE_CHECK_HOST) +
+ "\" port=%d\"", serviceCheckPort));
}
serviceSshFeed = SshFeed.builder()
.entity(entity())
@@ -160,7 +174,8 @@ public class AnsibleLifecycleEffectorTasks extends MachineLifecycleEffectorTasks
entity().feeds().addFeed(serviceSshFeed);
} else {
- LOG.warn("Location(s) {} not an ssh-machine location, so not polling for status; setting serviceUp immediately", entity().getLocations());
+ LOG.warn("Location(s) {} not an ssh-machine location, so not polling for status; "
+ + "setting serviceUp immediately", entity().getLocations());
}
}
@@ -169,7 +184,8 @@ public class AnsibleLifecycleEffectorTasks extends MachineLifecycleEffectorTasks
// if it's still up after 5s assume we are good (default behaviour)
Time.sleep(Duration.FIVE_SECONDS);
- if (!((Integer)0).equals(DynamicTasks.queue(SshEffectorTasks.ssh(String.format(entity().config().get(AnsibleConfig.ANSIBLE_SERVICE_START), getServiceName()))).get())) {
+ int result = DynamicTasks.queue(SshEffectorTasks.ssh(sudo(getServiveStartCommand()))).get();
+ if (0 != result) {
throw new IllegalStateException("The process for "+entity()+" appears not to be running (service "+getServiceName()+")");
}
@@ -193,11 +209,19 @@ public class AnsibleLifecycleEffectorTasks extends MachineLifecycleEffectorTasks
protected boolean tryStopService() {
if (getServiceName()==null) return false;
- int result = DynamicTasks.queue(SshEffectorTasks.ssh(String.format(entity().config().get(AnsibleConfig.ANSIBLE_SERVICE_STOP), getServiceName()))).get();
+ int result = DynamicTasks.queue(SshEffectorTasks.ssh(sudo(getServiveStopCommand()))).get();
if (0 == result) return true;
if (entity().getAttribute(Attributes.SERVICE_STATE_ACTUAL) != Lifecycle.RUNNING)
return true;
-
+
throw new IllegalStateException("The process for "+entity()+" appears could not be stopped (exit code "+result+" to service stop)");
}
+
+ private String getServiveStartCommand() {
+ return String.format(entity().config().get(AnsibleConfig.ANSIBLE_SERVICE_START), getServiceName());
+ }
+
+ private String getServiveStopCommand() {
+ return String.format(entity().config().get(AnsibleConfig.ANSIBLE_SERVICE_STOP), getServiceName());
+ }
}
http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/a01cba0c/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
----------------------------------------------------------------------
diff --git a/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
index 36076a1..152bc61 100644
--- a/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
+++ b/software/cm/ansible/src/main/java/org/apache/brooklyn/entity/cm/ansible/AnsiblePlaybookTasks.java
@@ -68,9 +68,9 @@ public class AnsiblePlaybookTasks {
}
public static TaskFactory<?> runAnsible(final String dir, Object extraVars, String playbookName) {
- String cmd = String.format("sudo ansible-playbook -i \"localhost,\" -c local "
+ String cmd = sudo(String.format("ansible-playbook -i \"localhost,\" -c local "
+ optionalExtraVarsParameter(extraVars)
- + " -s %s.yaml", playbookName);
+ + " -s %s.yaml", playbookName));
if (LOG.isDebugEnabled()) {
LOG.debug("Ansible command: {}", cmd);