blob: a149f1808c74b67b1656257cd9b5a32bb0560e95 [file] [log] [blame]
/*
* 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.camp.brooklyn;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import java.io.StringReader;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.location.MachineProvisioningLocation;
import org.apache.brooklyn.api.mgmt.HasTaskChildren;
import org.apache.brooklyn.api.mgmt.Task;
import org.apache.brooklyn.core.entity.Attributes;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
import org.apache.brooklyn.entity.software.base.SoftwareProcess;
import org.apache.brooklyn.entity.software.base.VanillaWindowsProcess;
import org.apache.brooklyn.entity.software.base.test.location.WindowsTestFixture;
import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
import org.apache.brooklyn.test.EntityTestUtils;
import org.apache.brooklyn.util.core.task.TaskPredicates;
import org.apache.brooklyn.util.text.StringPredicates;
import org.apache.brooklyn.util.text.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
/**
* Tests Windows YAML blueprint features.
*/
@Test
public class WindowsYamlLiveTest extends AbstractYamlTest {
// TODO Remove duplication of assertStreams and VanillaWindowsProcessWinrmStreamsLiveTest.assertStreams
private static final Logger log = LoggerFactory.getLogger(WindowsYamlLiveTest.class);
/**
* Maps from the task names that are used to the names used in log/exception messages.
*/
private static final Map<String, String> TASK_REGEX_TO_COMMAND = ImmutableMap.<String, String>builder()
.put("winrm: pre-install-command.*", "pre-install-command")
.put("winrm: install.*", "install-command")
.put("winrm: post-install-command.*", "post-install-command")
.put("winrm: customize.*", "customize-command")
.put("winrm: pre-launch-command.*", "pre-launch-command")
.put("winrm: launch.*", "launch-command")
.put("winrm: post-launch-command.*", "post-launch-command")
.put("winrm: stop-command.*", "stop-command")
.put("winrm: is-running-command.*", "is-running-command")
.build();
protected List<String> yamlLocation;
protected MachineProvisioningLocation<WinRmMachineLocation> location;
protected WinRmMachineLocation machine;
protected Entity app;
@BeforeClass(alwaysRun = true)
public void setUpClass() throws Exception {
super.setUp();
location = WindowsTestFixture.setUpWindowsLocation(mgmt());
machine = (WinRmMachineLocation) location.obtain(ImmutableMap.of());
String ip = machine.getAddress().getHostAddress();
String password = machine.config().get(WinRmMachineLocation.PASSWORD);
yamlLocation = ImmutableList.of(
"location:",
" byon:",
" hosts:",
" - winrm: "+ip+":5985",
" password: "+password,
" user: Administrator",
" osFamily: windows");
}
@AfterClass(alwaysRun = true)
public void tearDownClass() {
try {
if (location != null) location.release(machine);
} catch (Throwable t) {
log.error("Caught exception in tearDownClass method", t);
} finally {
super.tearDown();
}
}
@BeforeMethod(alwaysRun = true)
@Override
public void setUp() {
// no-op; everything done @BeforeClass
}
@AfterMethod(alwaysRun = true)
@Override
public void tearDown() {
try {
if (app != null) Entities.destroy(app);
} catch (Throwable t) {
log.error("Caught exception in tearDown method", t);
} finally {
app = null;
}
}
@Override
protected ManagementContextInternal mgmt() {
return (ManagementContextInternal) super.mgmt();
}
@Test(groups="Live")
public void testPowershellMinimalist() throws Exception {
Map<String, String> cmds = ImmutableMap.<String, String>builder()
.put("myarg", "myval")
.put("launch.powershell.command", "\"& c:\\\\exit0.ps1\"")
.put("checkRunning.powershell.command", "\"& c:\\\\exit0.bat\"")
.build();
Map<String, List<String>> stdouts = ImmutableMap.of();
runWindowsApp(cmds, stdouts, null);
}
@Test(groups="Live")
public void testPowershell() throws Exception {
Map<String, String> cmds = ImmutableMap.<String, String>builder()
.put("myarg", "myval")
.put("pre.install.powershell.command", "\"& c:\\\\exit0.ps1\"")
.put("install.powershell.command", "\"& c:\\\\echoMyArg.ps1 -myarg myInstall\"")
.put("post.install.powershell.command", "\"& c:\\\\echoArg.bat myPostInstall\"")
.put("customize.powershell.command", "\"& c:\\\\echoFreemarkerMyarg.bat\"")
.put("pre.launch.powershell.command", "\"& c:\\\\echoFreemarkerMyarg.ps1\"")
.put("launch.powershell.command", "\"& c:\\\\exit0.ps1\"")
.put("post.launch.powershell.command", "\"& c:\\\\exit0.ps1\"")
.put("checkRunning.powershell.command", "\"& c:\\\\exit0.ps1\"")
.put("stop.powershell.command", "\"& c:\\\\exit0.ps1\"")
.build();
Map<String, List<String>> stdouts = ImmutableMap.<String, List<String>>builder()
.put("winrm: install.*", ImmutableList.of("myInstall"))
.put("winrm: post-install-command.*", ImmutableList.of("myPostInstall"))
.put("winrm: customize.*", ImmutableList.of("myval"))
.put("winrm: pre-launch-command.*", ImmutableList.of("myval"))
.build();
runWindowsApp(cmds, stdouts, null);
}
@Test(groups="Live")
public void testBatch() throws Exception {
Map<String, String> cmds = ImmutableMap.<String, String>builder()
.put("myarg", "myval")
.put("pre.install.command", "\"PowerShell -NonInteractive -NoProfile -Command c:\\\\exit0.ps1\"")
.put("install.command", "\"PowerShell -NonInteractive -NoProfile -Command c:\\\\echoMyArg.ps1 -myarg myInstall\"")
.put("post.install.command", "\"c:\\\\echoArg.bat myPostInstall\"")
.put("customize.command", "\"c:\\\\echoFreemarkerMyarg.bat\"")
.put("pre.launch.command", "\"PowerShell -NonInteractive -NoProfile -Command c:\\\\echoFreemarkerMyarg.ps1\"")
.put("launch.command", "\"PowerShell -NonInteractive -NoProfile -Command c:\\\\exit0.ps1\"")
.put("post.launch.command", "\"PowerShell -NonInteractive -NoProfile -Command c:\\\\exit0.ps1\"")
.put("checkRunning.command", "\"PowerShell -NonInteractive -NoProfile -Command c:\\\\exit0.ps1\"")
.put("stop.command", "\"PowerShell -NonInteractive -NoProfile -Command c:\\\\exit0.ps1\"")
.build();
Map<String, List<String>> stdouts = ImmutableMap.<String, List<String>>builder()
.put("winrm: install.*", ImmutableList.of("myInstall"))
.put("winrm: post-install-command.*", ImmutableList.of("myPostInstall"))
.put("winrm: customize.*", ImmutableList.of("myval"))
.put("winrm: pre-launch-command.*", ImmutableList.of("myval"))
.build();
runWindowsApp(cmds, stdouts, null);
}
@Test(groups="Live")
public void testPowershellExit1() throws Exception {
Map<String, String> cmds = ImmutableMap.<String, String>builder()
.put("myarg", "myval")
.put("pre.install.powershell.command", "\"& c:\\\\exit1.ps1\"")
.put("install.powershell.command", "\"& c:\\\\echoMyArg.ps1 -myarg myInstall\"")
.put("post.install.powershell.command", "\"& c:\\\\echoArg.bat myPostInstall\"")
.put("customize.powershell.command", "\"& c:\\\\echoFreemarkerMyarg.bat\"")
.put("pre.launch.powershell.command", "\"& c:\\\\echoFreemarkerMyarg.ps1\"")
.put("launch.powershell.command", "\"& c:\\\\exit0.ps1\"")
.put("post.launch.powershell.command", "\"& c:\\\\exit0.ps1\"")
.put("checkRunning.powershell.command", "\"& c:\\\\exit0.ps1\"")
.put("stop.powershell.command", "\"& c:\\\\exit0.ps1\"")
.build();
Map<String, List<String>> stdouts = ImmutableMap.of();
runWindowsApp(cmds, stdouts, "winrm: pre-install-command.*");
}
// FIXME Failing to match the expected exception, but looks fine! Needs more investigation.
@Test(groups="Live")
public void testPowershellCheckRunningExit1() throws Exception {
Map<String, String> cmds = ImmutableMap.<String, String>builder()
.put("myarg", "myval")
.put("pre.install.powershell.command", "\"& c:\\\\exit0.ps1\"")
.put("install.powershell.command", "\"& c:\\\\echoMyArg.ps1 -myarg myInstall\"")
.put("post.install.powershell.command", "\"& c:\\\\echoArg.bat myPostInstall\"")
.put("customize.powershell.command", "\"& c:\\\\echoFreemarkerMyarg.bat\"")
.put("pre.launch.powershell.command", "\"& c:\\\\echoFreemarkerMyarg.ps1\"")
.put("launch.powershell.command", "\"& c:\\\\exit0.ps1\"")
.put("post.launch.powershell.command", "\"& c:\\\\exit0.ps1\"")
.put("checkRunning.powershell.command", "\"& c:\\\\exit1.ps1\"")
.put("stop.powershell.command", "\"& c:\\\\exit0.ps1\"")
.build();
Map<String, List<String>> stdouts = ImmutableMap.of();
runWindowsApp(cmds, stdouts, "winrm: is-running-command.*");
}
// FIXME Needs more work to get the stop's task that failed, so can assert got the right error message
@Test(groups="Live")
public void testPowershellStopExit1() throws Exception {
Map<String, String> cmds = ImmutableMap.<String, String>builder()
.put("myarg", "myval")
.put("pre.install.powershell.command", "\"& c:\\\\exit0.ps1\"")
.put("install.powershell.command", "\"& c:\\\\echoMyArg.ps1 -myarg myInstall\"")
.put("post.install.powershell.command", "\"& c:\\\\echoArg.bat myPostInstall\"")
.put("customize.powershell.command", "\"& c:\\\\echoFreemarkerMyarg.bat\"")
.put("pre.launch.powershell.command", "\"& c:\\\\echoFreemarkerMyarg.ps1\"")
.put("launch.powershell.command", "\"& c:\\\\exit0.ps1\"")
.put("post.launch.powershell.command", "\"& c:\\\\exit0.ps1\"")
.put("checkRunning.powershell.command", "\"& c:\\\\exit0.ps1\"")
.put("stop.powershell.command", "\"& c:\\\\exit1.ps1\"")
.build();
Map<String, List<String>> stdouts = ImmutableMap.of();
runWindowsApp(cmds, stdouts, "winrm: stop-command.*");
}
protected void runWindowsApp(Map<String, String> commands, Map<String, List<String>> stdouts, String taskRegexFailed) throws Exception {
String cmdFailed = (taskRegexFailed == null) ? null : TASK_REGEX_TO_COMMAND.get(taskRegexFailed);
List<String> yaml = Lists.newArrayList();
yaml.addAll(yamlLocation);
yaml.addAll(ImmutableList.of(
"services:",
"- type: org.apache.brooklyn.entity.software.base.VanillaWindowsProcess",
" brooklyn.config:",
" onbox.base.dir.skipResolution: true",
" templates.preinstall:",
" classpath://org/apache/brooklyn/camp/brooklyn/echoFreemarkerMyarg.bat: c:\\echoFreemarkerMyarg.bat",
" classpath://org/apache/brooklyn/camp/brooklyn/echoFreemarkerMyarg.ps1: c:\\echoFreemarkerMyarg.ps1",
" files.preinstall:",
" classpath://org/apache/brooklyn/camp/brooklyn/echoArg.bat: c:\\echoArg.bat",
" classpath://org/apache/brooklyn/camp/brooklyn/echoMyArg.ps1: c:\\echoMyArg.ps1",
" classpath://org/apache/brooklyn/camp/brooklyn/exit0.bat: c:\\exit0.bat",
" classpath://org/apache/brooklyn/camp/brooklyn/exit1.bat: c:\\exit1.bat",
" classpath://org/apache/brooklyn/camp/brooklyn/exit0.ps1: c:\\exit0.ps1",
" classpath://org/apache/brooklyn/camp/brooklyn/exit1.ps1: c:\\exit1.ps1",
""));
for (Map.Entry<String, String> entry : commands.entrySet()) {
yaml.add(" "+entry.getKey()+": "+entry.getValue());
}
if (Strings.isBlank(cmdFailed)) {
app = createAndStartApplication(new StringReader(Joiner.on("\n").join(yaml)));
waitForApplicationTasks(app);
log.info("App started:");
Entities.dumpInfo(app);
VanillaWindowsProcess entity = (VanillaWindowsProcess) app.getChildren().iterator().next();
EntityTestUtils.assertAttributeEqualsEventually(entity, Attributes.SERVICE_UP, true);
assertStreams(entity, stdouts);
} else if (cmdFailed.equals("stop-command")) {
app = createAndStartApplication(new StringReader(Joiner.on("\n").join(yaml)));
waitForApplicationTasks(app);
log.info("App started:");
Entities.dumpInfo(app);
VanillaWindowsProcess entity = (VanillaWindowsProcess) app.getChildren().iterator().next();
EntityTestUtils.assertAttributeEqualsEventually(entity, Attributes.SERVICE_UP, true);
entity.stop();
assertSubTaskFailures(entity, ImmutableMap.of(taskRegexFailed, StringPredicates.containsLiteral("for "+cmdFailed)));
} else {
try {
app = createAndStartApplication(new StringReader(Joiner.on("\n").join(yaml)));
fail("start should have failed for app="+app);
} catch (Exception e) {
if (e.toString().contains("invalid result") && e.toString().contains("for "+cmdFailed)) throw e;
}
}
}
protected void assertStreams(SoftwareProcess entity, Map<String, List<String>> stdouts) {
Set<Task<?>> tasks = BrooklynTaskTags.getTasksInEntityContext(mgmt().getExecutionManager(), entity);
for (Map.Entry<String, List<String>> entry : stdouts.entrySet()) {
String taskNameRegex = entry.getKey();
List<String> expectedOuts = entry.getValue();
Task<?> subTask = findTaskOrSubTask(tasks, TaskPredicates.displayNameSatisfies(StringPredicates.matchesRegex(taskNameRegex))).get();
String stdin = getStreamOrFail(subTask, BrooklynTaskTags.STREAM_STDIN);
String stdout = getStreamOrFail(subTask, BrooklynTaskTags.STREAM_STDOUT);
String stderr = getStreamOrFail(subTask, BrooklynTaskTags.STREAM_STDERR);
String env = getStream(subTask, BrooklynTaskTags.STREAM_ENV);
String msg = "stdin="+stdin+"; stdout="+stdout+"; stderr="+stderr+"; env="+env;
for (String expectedOut : expectedOuts) {
assertTrue(stdout.contains(expectedOut), msg);
}
}
}
protected void assertSubTaskFailures(SoftwareProcess entity, Map<String, Predicate<CharSequence>> taskErrs) throws Exception {
Set<Task<?>> tasks = BrooklynTaskTags.getTasksInEntityContext(mgmt().getExecutionManager(), entity);
for (Map.Entry<String, Predicate<CharSequence>> entry : taskErrs.entrySet()) {
String taskNameRegex = entry.getKey();
Predicate<? super String> errChecker = entry.getValue();
Task<?> subTask = findTaskOrSubTask(tasks, TaskPredicates.displayNameSatisfies(StringPredicates.matchesRegex(taskNameRegex))).get();
String msg = "regex="+taskNameRegex+"; task="+subTask;
assertNotNull(subTask, msg);
assertTrue(subTask.isDone(), msg);
assertTrue(subTask.isError(), msg);
try {
subTask.get();
fail();
} catch (Exception e) {
if (!errChecker.apply(e.toString())) {
throw e;
}
}
}
}
public static String getStreamOrFail(Task<?> task, String streamType) {
String msg = "task="+task+"; stream="+streamType;
BrooklynTaskTags.WrappedStream stream = checkNotNull(BrooklynTaskTags.stream(task, streamType), "Stream null: " + msg);
return checkNotNull(stream.streamContents.get(), "Contents null: "+msg);
}
public static String getStream(Task<?> task, String streamType) {
BrooklynTaskTags.WrappedStream stream = BrooklynTaskTags.stream(task, streamType);
return (stream != null) ? stream.streamContents.get() : null;
}
protected Optional<Task<?>> findTaskOrSubTask(Iterable<? extends Task<?>> tasks, Predicate<? super Task<?>> matcher) {
List<String> taskNames = Lists.newArrayList();
Optional<Task<?>> result = findTaskOrSubTaskImpl(tasks, matcher, taskNames);
if (!result.isPresent() && log.isDebugEnabled()) {
log.debug("Task not found matching "+matcher+"; contender names were "+taskNames);
}
return result;
}
protected Optional<Task<?>> findTaskOrSubTaskImpl(Iterable<? extends Task<?>> tasks, Predicate<? super Task<?>> matcher, List<String> taskNames) {
for (Task<?> task : tasks) {
if (matcher.apply(task)) return Optional.<Task<?>>of(task);
if (!(task instanceof HasTaskChildren)) {
return Optional.absent();
} else {
Optional<Task<?>> subResult = findTaskOrSubTask(((HasTaskChildren) task).getChildren(), matcher);
if (subResult.isPresent()) return subResult;
}
}
return Optional.<Task<?>>absent();
}
@Override
protected Logger getLogger() {
return log;
}
}