Repository: incubator-brooklyn Updated Branches: refs/heads/master d2a5d4b09 -> b2986e724
Fix VanillaSoftwareProcess install Previously, if download and install-cmd were supplied, only the download would be executed. Previously if two VanillaSoftwareProcesses were used on the same machine where neither had a downloadUrl, it would have skipped the install of the second (sharing the same install folder). Previously there was poor test coverage of VanillaSoftwareProcess. Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/3e2d01e6 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/3e2d01e6 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/3e2d01e6 Branch: refs/heads/master Commit: 3e2d01e66cdd4c60b665b052c00111f0aeda559c Parents: 8636eb3 Author: Aled Sage <[email protected]> Authored: Fri Oct 2 10:56:58 2015 +0100 Committer: Aled Sage <[email protected]> Committed: Thu Oct 8 00:27:52 2015 +0100 ---------------------------------------------------------------------- .../core/test/BrooklynAppLiveTestSupport.java | 8 +- .../base/VanillaSoftwareProcessSshDriver.java | 20 +- .../AbstractSoftwareProcessStreamsTest.java | 36 ++-- .../VanillaSoftwareProcessIntegrationTest.java | 209 +++++++++++++++++++ 4 files changed, 244 insertions(+), 29 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3e2d01e6/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppLiveTestSupport.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppLiveTestSupport.java b/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppLiveTestSupport.java index d165eda..b986fed 100644 --- a/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppLiveTestSupport.java +++ b/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppLiveTestSupport.java @@ -18,6 +18,7 @@ */ package org.apache.brooklyn.core.test; +import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.core.entity.Entities; import org.apache.brooklyn.core.entity.factory.ApplicationBuilder; import org.apache.brooklyn.core.internal.BrooklynProperties; @@ -45,10 +46,10 @@ public class BrooklynAppLiveTestSupport { @BeforeMethod(alwaysRun=true) public void setUp() throws Exception { if (mgmt!=null) { - app = ApplicationBuilder.newManagedApp(TestApplication.class, mgmt); + app = ApplicationBuilder.newManagedApp(newAppSpec(), mgmt); } else { mgmt = new LocalManagementContextForTests(BrooklynProperties.Factory.newDefault()); - app = ApplicationBuilder.newManagedApp(TestApplication.class, mgmt); + app = ApplicationBuilder.newManagedApp(newAppSpec(), mgmt); } } @@ -63,4 +64,7 @@ public class BrooklynAppLiveTestSupport { } } + protected EntitySpec<? extends TestApplication> newAppSpec() { + return EntitySpec.create(TestApplication.class); + } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3e2d01e6/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcessSshDriver.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcessSshDriver.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcessSshDriver.java index 42a6999..dd01a69 100644 --- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcessSshDriver.java +++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcessSshDriver.java @@ -21,6 +21,7 @@ package org.apache.brooklyn.entity.software.base; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; import org.apache.brooklyn.api.entity.EntityLocal; import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolver; @@ -36,6 +37,8 @@ import org.apache.brooklyn.util.ssh.BashCommands; import org.apache.brooklyn.util.text.Identifiers; import org.apache.brooklyn.util.text.Strings; +import com.google.common.collect.ImmutableMap; + public class VanillaSoftwareProcessSshDriver extends AbstractSoftwareProcessSshDriver implements VanillaSoftwareProcessDriver { public VanillaSoftwareProcessSshDriver(EntityLocal entity, SshMachineLocation machine) { @@ -44,13 +47,20 @@ public class VanillaSoftwareProcessSshDriver extends AbstractSoftwareProcessSshD String downloadedFilename = null; - /** needed because the download url might be different! */ + /** + * Needed because the download url and install commands are likely different for different VanillaSoftwareProcesses! + * This is particularly true for YAML entities. We take a hash of the download_url, install_command and environment variables. + * We thus assume any templating of the script has already been done by this point. + */ @Override protected String getInstallLabelExtraSalt() { + Maybe<Object> url = getEntity().getConfigRaw(SoftwareProcess.DOWNLOAD_URL, true); - if (url.isAbsent()) return null; + String installCommand = getEntity().getConfig(VanillaSoftwareProcess.INSTALL_COMMAND); + Map<String, Object> shellEnv = getEntity().getConfig(VanillaSoftwareProcess.SHELL_ENVIRONMENT); + // TODO a user-friendly hash would be nice, but tricky since we don't want it to be too long or contain path chars - return Identifiers.makeIdFromHash( url.get().hashCode() ); + return Identifiers.makeIdFromHash(Objects.hash(url.or(null), installCommand, shellEnv)); } @Override @@ -65,7 +75,7 @@ public class VanillaSoftwareProcessSshDriver extends AbstractSoftwareProcessSshD commands.addAll(BashCommands.commandsToDownloadUrlsAs(urls, downloadedFilename)); commands.addAll(ArchiveUtils.installCommands(downloadedFilename)); - int result = newScript(INSTALLING) + int result = newScript(ImmutableMap.of(INSTALL_INCOMPLETE, true), INSTALLING) .failOnNonZeroResultCode(false) .body.append(commands) .execute(); @@ -82,7 +92,9 @@ public class VanillaSoftwareProcessSshDriver extends AbstractSoftwareProcessSshD } } + // If downloadUrl did partial install (see INSTALL_INCOMPLETE above) then always execute install so mark it as completed. String installCommand = getEntity().getConfig(VanillaSoftwareProcess.INSTALL_COMMAND); + if (url.isPresentAndNonNull() && Strings.isBlank(installCommand)) installCommand = "# mark as complete"; if (Strings.isNonBlank(installCommand)) { newScript(INSTALLING) http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3e2d01e6/software/base/src/test/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessStreamsTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessStreamsTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessStreamsTest.java index 78f991d..cfc4826 100644 --- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessStreamsTest.java +++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessStreamsTest.java @@ -18,31 +18,28 @@ */ package org.apache.brooklyn.entity.software.base; -import com.google.common.base.Optional; -import com.google.common.base.Predicate; -import com.google.common.collect.Lists; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.testng.Assert.assertTrue; + +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.api.mgmt.HasTaskChildren; import org.apache.brooklyn.api.mgmt.Task; import org.apache.brooklyn.core.entity.BrooklynConfigKeys; -import org.apache.brooklyn.core.entity.factory.ApplicationBuilder; -import org.apache.brooklyn.core.internal.BrooklynProperties; import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport; -import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests; import org.apache.brooklyn.core.test.entity.TestApplication; import org.apache.brooklyn.util.core.task.TaskPredicates; import org.apache.brooklyn.util.text.StringPredicates; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.testng.annotations.BeforeMethod; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static com.google.common.base.Preconditions.checkNotNull; -import static org.testng.Assert.assertTrue; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.Lists; public abstract class AbstractSoftwareProcessStreamsTest extends BrooklynAppLiveTestSupport { private static final Logger log = LoggerFactory.getLogger(AbstractSoftwareProcessStreamsTest.class); @@ -51,16 +48,9 @@ public abstract class AbstractSoftwareProcessStreamsTest extends BrooklynAppLive protected abstract Map<String, String> getCommands(); - @BeforeMethod(alwaysRun=true) - public void setUp() throws Exception { - if (mgmt!=null) { - app = ApplicationBuilder.newManagedApp(TestApplication.class, mgmt); - } else { - mgmt = new LocalManagementContextForTests(BrooklynProperties.Factory.newDefault()); - EntitySpec<TestApplication> appSpec = EntitySpec.create(TestApplication.class) - .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, true); - app = ApplicationBuilder.newManagedApp(appSpec, mgmt); - } + protected EntitySpec<? extends TestApplication> newAppSpec() { + return EntitySpec.create(TestApplication.class) + .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, true); } public static String getStreamOrFail(Task<?> task, String streamType) { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3e2d01e6/software/base/src/test/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcessIntegrationTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcessIntegrationTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcessIntegrationTest.java new file mode 100644 index 0000000..141945b --- /dev/null +++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcessIntegrationTest.java @@ -0,0 +1,209 @@ +/* + * 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.software.base; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import org.apache.brooklyn.api.entity.EntitySpec; +import org.apache.brooklyn.api.location.Location; +import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableList; + +public class VanillaSoftwareProcessIntegrationTest extends BrooklynAppLiveTestSupport { + + private Location localhost; + private Path runRecord; + + @BeforeMethod(alwaysRun=true) + @Override + public void setUp() throws Exception { + super.setUp(); + localhost = app.getManagementContext().getLocationRegistry().resolve("localhost"); + + runRecord = Files.createTempFile("testVanillaSoftwareProcess-runRecord", ".txt"); + } + + @Override + public void tearDown() throws Exception { + if (runRecord != null) Files.delete(runRecord); + super.tearDown(); + } + + @Test(groups = "Integration") + public void testAllCmds() throws Exception { + app.createAndManageChild(EntitySpec.create(VanillaSoftwareProcess.class) + .configure(VanillaSoftwareProcess.PRE_INSTALL_COMMAND, "echo preInstallCommand >> "+runRecord.toAbsolutePath()) + .configure(VanillaSoftwareProcess.INSTALL_COMMAND, "echo installCommand >> "+runRecord.toAbsolutePath()) + .configure(VanillaSoftwareProcess.POST_INSTALL_COMMAND, "echo postInstallCommand >> "+runRecord.toAbsolutePath()) + .configure(VanillaSoftwareProcess.CUSTOMIZE_COMMAND, "echo customizeCommand >> "+runRecord.toAbsolutePath()) + .configure(VanillaSoftwareProcess.PRE_LAUNCH_COMMAND, "echo preLaunchCommand >> "+runRecord.toAbsolutePath()) + .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "echo launchCommand >> "+runRecord.toAbsolutePath()) + .configure(VanillaSoftwareProcess.POST_LAUNCH_COMMAND, "echo postLaunchCommand >> "+runRecord.toAbsolutePath()) + .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "echo checkRunningCommand >> "+runRecord.toAbsolutePath()) + .configure(VanillaSoftwareProcess.STOP_COMMAND, "echo stopCommand >> "+runRecord.toAbsolutePath())); + app.start(ImmutableList.of(localhost)); + + String record = new String(Files.readAllBytes(runRecord)); + List<String> lines = ImmutableList.copyOf(Splitter.on("\n").omitEmptyStrings().split(record)); + + assertEquals(lines.get(0), "preInstallCommand", "lines="+lines); + assertEquals(lines.get(1), "installCommand", "lines="+lines); + assertEquals(lines.get(2), "postInstallCommand", "lines="+lines); + assertEquals(lines.get(3), "customizeCommand", "lines="+lines); + assertEquals(lines.get(4), "preLaunchCommand", "lines="+lines); + assertEquals(lines.get(5), "launchCommand", "lines="+lines); + assertEquals(lines.get(6), "postLaunchCommand", "lines="+lines); + assertEquals(lines.get(7), "checkRunningCommand", "lines="+lines); + + app.stop(); + + String record2 = new String(Files.readAllBytes(runRecord)); + List<String> lines2 = ImmutableList.copyOf(Splitter.on("\n").omitEmptyStrings().split(record2)); + + assertEquals(lines2.get(lines2.size()-1), "stopCommand", "lines="+lines2); + } + + @Test(groups = "Integration") + public void testDownloadOnlyCmd() throws Exception { + Path downloadArtifact = Files.createTempFile("testVanillaSoftwareProcess-downloadArtifact", ".txt"); + Files.write(downloadArtifact, "my download artifact".getBytes()); + + try { + VanillaSoftwareProcess entity = app.createAndManageChild(EntitySpec.create(VanillaSoftwareProcess.class) + .configure(VanillaSoftwareProcess.DOWNLOAD_URL, downloadArtifact.toUri().toString()) + .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "echo launched") + .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "echo running")); + app.start(ImmutableList.of(localhost)); + + Path installedArtifact = FileSystems.getDefault().getPath(entity.getAttribute(VanillaSoftwareProcess.INSTALL_DIR), downloadArtifact.getFileName().toString()); + assertEquals(new String(Files.readAllBytes(installedArtifact)), "my download artifact"); + + Path installCompletionMarker = FileSystems.getDefault().getPath(entity.getAttribute(VanillaSoftwareProcess.INSTALL_DIR), "BROOKLYN"); + assertTrue(Files.isRegularFile(installCompletionMarker), "file="+installCompletionMarker); + + } finally { + Files.delete(downloadArtifact); + } + } + + @Test(groups = "Integration") + public void testInstallOnlyCmd() throws Exception { + VanillaSoftwareProcess entity = app.createAndManageChild(EntitySpec.create(VanillaSoftwareProcess.class) + .configure(VanillaSoftwareProcess.INSTALL_COMMAND, "echo installCommand >> "+runRecord.toAbsolutePath()) + .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "echo launching") + .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "echo running")); + app.start(ImmutableList.of(localhost)); + + Path installCompletionMarker = FileSystems.getDefault().getPath(entity.getAttribute(VanillaSoftwareProcess.INSTALL_DIR), "BROOKLYN"); + assertTrue(Files.isRegularFile(installCompletionMarker), "file="+installCompletionMarker); + + assertEquals(new String(Files.readAllBytes(runRecord)).trim(), "installCommand"); + } + + @Test(groups = "Integration") + public void testDownloadAndInstallCmds() throws Exception { + Path downloadArtifact = Files.createTempFile("testVanillaSoftwareProcess-downloadArtifact", ".txt"); + Files.write(downloadArtifact, "my download artifact".getBytes()); + + try { + VanillaSoftwareProcess entity = app.createAndManageChild(EntitySpec.create(VanillaSoftwareProcess.class) + .configure(VanillaSoftwareProcess.DOWNLOAD_URL, downloadArtifact.toUri().toString()) + .configure(VanillaSoftwareProcess.INSTALL_COMMAND, "echo installCommand >> "+runRecord.toAbsolutePath()) + .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "echo launched") + .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "echo running")); + app.start(ImmutableList.of(localhost)); + + Path installedArtifact = FileSystems.getDefault().getPath(entity.getAttribute(VanillaSoftwareProcess.INSTALL_DIR), downloadArtifact.getFileName().toString()); + assertEquals(new String(Files.readAllBytes(installedArtifact)), "my download artifact"); + + Path installCompletionMarker = FileSystems.getDefault().getPath(entity.getAttribute(VanillaSoftwareProcess.INSTALL_DIR), "BROOKLYN"); + assertTrue(Files.isRegularFile(installCompletionMarker), "file="+installCompletionMarker); + + assertEquals(new String(Files.readAllBytes(runRecord)).trim(), "installCommand"); + + } finally { + Files.delete(downloadArtifact); + } + } + + @Test(groups = "Integration") + public void testShellEnv() throws Exception { + VanillaSoftwareProcess entity = app.createAndManageChild(EntitySpec.create(VanillaSoftwareProcess.class) + .configure(VanillaSoftwareProcess.SHELL_ENVIRONMENT.subKey("RUN_RECORD"), runRecord.toAbsolutePath()) + .configure(VanillaSoftwareProcess.INSTALL_COMMAND, "echo installCommand >> $RUN_RECORD") + .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "echo launching") + .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "echo running")); + app.start(ImmutableList.of(localhost)); + + Path installCompletionMarker = FileSystems.getDefault().getPath(entity.getAttribute(VanillaSoftwareProcess.INSTALL_DIR), "BROOKLYN"); + assertTrue(Files.isRegularFile(installCompletionMarker), "file="+installCompletionMarker); + + assertEquals(new String(Files.readAllBytes(runRecord)).trim(), "installCommand"); + } + + @Test(groups = "Integration") + public void testInstallExecutedOnlyOnce() throws Exception { + VanillaSoftwareProcess entity = app.createAndManageChild(EntitySpec.create(VanillaSoftwareProcess.class) + .configure(VanillaSoftwareProcess.INSTALL_COMMAND, "echo installCommand >> "+runRecord.toAbsolutePath()) + .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "echo launching") + .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "echo running")); + VanillaSoftwareProcess entity2 = app.createAndManageChild(EntitySpec.create(VanillaSoftwareProcess.class) + .configure(VanillaSoftwareProcess.INSTALL_COMMAND, "echo installCommand >> "+runRecord.toAbsolutePath()) + .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "echo launching") + .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "echo running")); + app.start(ImmutableList.of(localhost)); + + Path installCompletionMarker = FileSystems.getDefault().getPath(entity.getAttribute(VanillaSoftwareProcess.INSTALL_DIR), "BROOKLYN"); + assertTrue(Files.isRegularFile(installCompletionMarker), "file="+installCompletionMarker); + + Path installCompletionMarker2 = FileSystems.getDefault().getPath(entity2.getAttribute(VanillaSoftwareProcess.INSTALL_DIR), "BROOKLYN"); + assertEquals(installCompletionMarker, installCompletionMarker2); + + assertEquals(new String(Files.readAllBytes(runRecord)).trim(), "installCommand"); + } + + // Installation creates a installs/VanillaSoftwareProcess_0.0.0_XXXX/BROOKLYN marker file. + // It indicates that installation has already been done successfully, so it is skipped the second time. + // Assert it respects different values for the install script, to ensure each different VanillaSoftwareProcess + // does get installed! + @Test(groups = "Integration", dependsOnMethods="testShellEnv") + public void testShellEnvUsedInHashForInstallCompletion() throws Exception { + testShellEnv(); + } + + @Test(groups = "Integration", dependsOnMethods="testDownloadOnlyCmd") + public void testDownloadUrlUsedInHashForInstallCompletion() throws Exception { + testDownloadOnlyCmd();; + } + + @Test(groups = "Integration", dependsOnMethods="testInstallOnlyCmd") + public void testInstallCmdUsedInHashForInstallCompletion() throws Exception { + testInstallOnlyCmd(); + } +}
