/*
* 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.monitoring.monit;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotEquals;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.concurrent.Callable;
import org.apache.brooklyn.api.entity.EntitySpec;
import org.apache.brooklyn.api.location.MachineDetails;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.sensor.DependentConfiguration;
import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
import org.apache.brooklyn.entity.database.mysql.MySqlNode;
import org.apache.brooklyn.entity.software.base.SameServerEntity;
import org.apache.brooklyn.entity.software.base.SoftwareProcess;
import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
import org.apache.brooklyn.test.Asserts;
import org.apache.brooklyn.test.EntityTestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.Files;
public class MonitIntegrationTest extends BrooklynAppLiveTestSupport {
private static final Logger LOG = LoggerFactory.getLogger(MonitIntegrationTest.class);
LocalhostMachineProvisioningLocation loc;
Process testProcess;
@BeforeMethod(alwaysRun=true)
public void setUp() throws Exception {
super.setUp();
loc = app.newLocalhostProvisioningLocation();
testProcess = (new ProcessBuilder()).command("vi", "monittest").start();
}
@AfterMethod(alwaysRun = true)
@Override
public void tearDown() throws Exception {
try {
super.tearDown();
} finally {
if (testProcess != null) {
testProcess.destroy();
}
}
}
@Test(groups = "Integration")
public void test_localhost() throws Exception {
final MonitNode monitNode = app.createAndManageChild(EntitySpec.create(MonitNode.class)
.configure(MonitNode.CONTROL_FILE_URL, "classpath:///org/apache/brooklyn/entity/monitoring/monit/monit.monitrc"));
app.start(ImmutableSet.of(loc));
LOG.info("Monit started");
EntityTestUtils.assertAttributeEqualsEventually(monitNode, MonitNode.MONIT_TARGET_PROCESS_STATUS, "Running");
}
@Test(groups = "Integration")
public void test_monitorMySql() throws Exception {
SameServerEntity sameServerEntity = app.createAndManageChild(EntitySpec.create(SameServerEntity.class));
MySqlNode mySqlNode = sameServerEntity.addChild(EntitySpec.create(MySqlNode.class));
Function<String, Map<String, Object>> controlFileSubstitutionsFunction = new Function<String, Map<String, Object>>() {
public Map<String, Object> apply(String input) {
return ImmutableMap.<String, Object>of("targetPidFile", input);
}
};
EntitySpec<MonitNode> monitSpec = EntitySpec.create(MonitNode.class)
.configure(MonitNode.CONTROL_FILE_URL, "classpath:///org/apache/brooklyn/entity/monitoring/monit/monitmysql.monitrc")
.configure(MonitNode.CONTROL_FILE_SUBSTITUTIONS, DependentConfiguration.valueWhenAttributeReady(mySqlNode,
SoftwareProcess.PID_FILE, controlFileSubstitutionsFunction));
final MonitNode monitNode = sameServerEntity.addChild(monitSpec);
app.start(ImmutableSet.of(loc));
LOG.info("Monit and MySQL started");
EntityTestUtils.assertAttributeEqualsEventually(monitNode, MonitNode.MONIT_TARGET_PROCESS_STATUS, "Running");
mySqlNode.stop();
Asserts.succeedsEventually(new Runnable() {
@Override
public void run() {
String targetStatus = monitNode.getAttribute(MonitNode.MONIT_TARGET_PROCESS_STATUS);
LOG.debug("MonitNode target status: {}", targetStatus);
assertNotEquals(targetStatus, "Running");
}
});
mySqlNode.restart();
EntityTestUtils.assertAttributeEqualsEventually(monitNode, MonitNode.MONIT_TARGET_PROCESS_STATUS, "Running");
}
@Test(groups = "Integration")
public void test_monitorMySqlAutoRestart() throws Exception {
// This runs on localhost; free to obtain another machine with impunity.
final String osFlavor;
MachineDetails machineDetails = app.getExecutionContext().submit(new Callable<MachineDetails>() {
public MachineDetails call() throws Exception {
return loc.obtain().getMachineDetails();
}}).get();
if (machineDetails.getOsDetails().isMac()) {
osFlavor = "osx10.6-x86_64";
} else if (machineDetails.getOsDetails().isWindows()) {
throw new UnsupportedOperationException("Windows not supported for test_monitorMySqlAutoRestart");
} else {
osFlavor = "linux2.6-x86_64"; // assume 64 bit linux
}
// The monit node needs to know the installation and run directory of the mysql dir, so we need to specify it explicitly
File tempDir = Files.createTempDir();
tempDir.deleteOnExit();
final String mySqlInstallDir = tempDir.getAbsolutePath() + "/install";
final String mySqlRunDir = tempDir.getAbsolutePath() + "/run";
final String mySqlDataDir = tempDir.getAbsolutePath() + "/data";
final String mySqlVersion = MySqlNode.SUGGESTED_VERSION.getDefaultValue();
SameServerEntity sameServerEntity = app.createAndManageChild(EntitySpec.create(SameServerEntity.class));
final MySqlNode mySqlNode = sameServerEntity.addChild(EntitySpec.create(MySqlNode.class)
.configure(MySqlNode.INSTALL_DIR, mySqlInstallDir)
.configure(MySqlNode.RUN_DIR, mySqlRunDir)
.configure(MySqlNode.DATA_DIR, mySqlDataDir));
Function<String, Map<String, Object>> controlFileSubstitutionsFunction = new Function<String, Map<String, Object>>() {
public Map<String, Object> apply(String input) {
return ImmutableMap.<String, Object>of(
"targetPidFile", input,
"mySqlInstallDir", mySqlInstallDir,
"mySqlRunDir", mySqlRunDir,
"mySqlVersion", mySqlVersion,
"mySqlOsFlavor", osFlavor
);
}
};
final MonitNode monitNode = sameServerEntity.addChild(EntitySpec.create(MonitNode.class)
.configure(MonitNode.CONTROL_FILE_URL, "classpath:///org/apache/brooklyn/entity/monitoring/monit/monitmysqlwithrestart.monitrc")
.configure(MonitNode.CONTROL_FILE_SUBSTITUTIONS, DependentConfiguration.valueWhenAttributeReady(mySqlNode,
SoftwareProcess.PID_FILE, controlFileSubstitutionsFunction)));
app.start(ImmutableSet.of(loc));
LOG.info("Monit and MySQL started");
final String[] initialPid = {""};
Asserts.succeedsEventually(new Runnable() {
@Override
public void run() {
String targetStatus = monitNode.getAttribute(MonitNode.MONIT_TARGET_PROCESS_STATUS);
LOG.debug("MonitNode target status: {}", targetStatus);
assertEquals(targetStatus, "Running");
try {
initialPid[0] = Files.readFirstLine(new File(mySqlNode.getAttribute(SoftwareProcess.PID_FILE)), Charset.defaultCharset());
LOG.debug("Initial PID: {}", initialPid[0]);
} catch (IOException e) {
Asserts.fail("Could not read PID file: " + e);
}
}
});
mySqlNode.stop();
EntityTestUtils.assertAttributeEqualsEventually(monitNode, MonitNode.MONIT_TARGET_PROCESS_STATUS, "Running");
// NOTE: Do not manually restart the mySqlNode, it should be restarted by monit
Asserts.succeedsEventually(new Runnable() {
@Override
public void run() {
try {
String pidFileLocation = mySqlNode.getAttribute(SoftwareProcess.PID_FILE);
String newPid = Files.readFirstLine(new File(pidFileLocation), Charset.defaultCharset());
LOG.debug("Old PID: {}, New PID: {} read from PID file: {}", new String[] {initialPid[0], newPid, pidFileLocation});
assertNotEquals(initialPid[0], newPid, "Process PID has not changed");
} catch (IOException e) {
Asserts.fail("Could not read PID file: " + e);
}
String targetStatus = monitNode.getAttribute(MonitNode.MONIT_TARGET_PROCESS_STATUS);
LOG.debug("MonitNode target status: {}", targetStatus);
assertEquals(targetStatus, "Running");
}
});
}
}