Repository: brooklyn-server Updated Branches: refs/heads/master 1aeb0f57e -> 660ebbb4e
CLI args: support catalogAdd with multiple URIs Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/6df6c765 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/6df6c765 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/6df6c765 Branch: refs/heads/master Commit: 6df6c7658258f50b375dcdbdc413be8edae792ef Parents: 0c03691 Author: Aled Sage <aled.s...@gmail.com> Authored: Sat Mar 26 21:24:35 2016 +0000 Committer: Aled Sage <aled.s...@gmail.com> Committed: Sat Mar 26 21:48:07 2016 +0000 ---------------------------------------------------------------------- .../catalog/internal/CatalogInitialization.java | 31 ++++--- .../LocalManagementContextRegistry.java | 32 ++++++++ .../main/java/org/apache/brooklyn/cli/Main.java | 22 +++-- .../java/org/apache/brooklyn/cli/CliTest.java | 86 +++++++++++++++++++- 4 files changed, 145 insertions(+), 26 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6df6c765/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java index 37783cd..b8fdb9f 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java @@ -22,8 +22,6 @@ import java.io.File; import java.util.Collection; import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.apache.brooklyn.api.catalog.CatalogItem; import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState; @@ -41,12 +39,15 @@ import org.apache.brooklyn.util.guava.Maybe; import org.apache.brooklyn.util.javalang.JavaClassNames; import org.apache.brooklyn.util.os.Os; import org.apache.brooklyn.util.text.Strings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.annotations.Beta; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; @Beta public class CatalogInitialization implements ManagementContextInjectable { @@ -75,7 +76,7 @@ public class CatalogInitialization implements ManagementContextInjectable { private String initialUri; private boolean reset; - private String additionsUri; + private List<String> additionsUris; private boolean force; private boolean disallowLocal = false; @@ -96,17 +97,17 @@ public class CatalogInitialization implements ManagementContextInjectable { private Object populatingCatalogMutex = new Object(); - public CatalogInitialization(String initialUri, boolean reset, String additionUri, boolean force) { + public CatalogInitialization() { + this(null, false, ImmutableList.<String>of(), false); + } + + public CatalogInitialization(String initialUri, boolean reset, Iterable<String> additionUris, boolean force) { this.initialUri = initialUri; this.reset = reset; - this.additionsUri = additionUri; + this.additionsUris = (additionUris != null) ? ImmutableList.copyOf(additionUris) : ImmutableList.<String>of(); this.force = force; } - public CatalogInitialization() { - this(null, false, null, false); - } - @Override public void setManagementContext(ManagementContext managementContext) { Preconditions.checkNotNull(managementContext, "management context"); @@ -350,7 +351,7 @@ public class CatalogInitialization implements ManagementContextInjectable { boolean hasRunAdditions = false; protected void populateAdditions(BasicBrooklynCatalog catalog) { - if (Strings.isNonBlank(additionsUri)) { + if (!additionsUris.isEmpty()) { if (disallowLocal) { if (!hasRunAdditions) { log.warn("CLI additions supplied but not supported when catalog load mode disallows local loads; ignoring."); @@ -358,11 +359,15 @@ public class CatalogInitialization implements ManagementContextInjectable { return; } if (!hasRunAdditions) { - log.debug("Adding to catalog from CLI: "+additionsUri+" (force: "+force+")"); + log.debug("Adding to catalog from CLI: "+additionsUris+" (force: "+force+")"); } - Iterable<? extends CatalogItem<?, ?>> items = catalog.addItems( - new ResourceUtils(this).getResourceAsString(additionsUri), force); + List<CatalogItem<?,?>> items = Lists.newArrayList(); + for (String additionsUri : additionsUris) { + List<? extends CatalogItem<?, ?>> addedItems = catalog.addItems( + new ResourceUtils(this).getResourceAsString(additionsUri), force); + items.addAll(addedItems); + } if (!hasRunAdditions) log.debug("Added to catalog from CLI: "+items); else http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6df6c765/core/src/test/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContextRegistry.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContextRegistry.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContextRegistry.java new file mode 100644 index 0000000..2ff4305 --- /dev/null +++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContextRegistry.java @@ -0,0 +1,32 @@ +/* + * 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.core.mgmt.internal; + +import java.util.Set; + +import com.google.common.annotations.VisibleForTesting; + +@VisibleForTesting +public class LocalManagementContextRegistry { + + @VisibleForTesting + public static Set<LocalManagementContext> getInstances() { + return LocalManagementContext.getInstances(); + } +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6df6c765/server-cli/src/main/java/org/apache/brooklyn/cli/Main.java ---------------------------------------------------------------------- diff --git a/server-cli/src/main/java/org/apache/brooklyn/cli/Main.java b/server-cli/src/main/java/org/apache/brooklyn/cli/Main.java index 03be76e..3c3fa16 100644 --- a/server-cli/src/main/java/org/apache/brooklyn/cli/Main.java +++ b/server-cli/src/main/java/org/apache/brooklyn/cli/Main.java @@ -19,12 +19,6 @@ package org.apache.brooklyn.cli; import static com.google.common.base.Preconditions.checkNotNull; -import groovy.lang.GroovyClassLoader; -import groovy.lang.GroovyShell; -import io.airlift.command.Cli; -import io.airlift.command.Cli.CliBuilder; -import io.airlift.command.Command; -import io.airlift.command.Option; import java.io.Console; import java.io.IOException; @@ -33,6 +27,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.Collection; +import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; @@ -98,6 +93,13 @@ import com.google.common.base.Stopwatch; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; +import groovy.lang.GroovyClassLoader; +import groovy.lang.GroovyShell; +import io.airlift.command.Cli; +import io.airlift.command.Cli.CliBuilder; +import io.airlift.command.Command; +import io.airlift.command.Option; + /** * This class is the primary CLI for brooklyn. * Run with the `help` argument for help. @@ -230,8 +232,9 @@ public class Main extends AbstractMain { description = "Specifies that any catalog items which have been persisted should be cleared") public boolean catalogReset; - @Option(name = { "--catalogAdd" }, title = "catalog bom URI to add", - description = "Specifies a catalog.bom to be added to the catalog") + // Unfortunately does not support arity of 1 or more; only exactly n + @Option(name = { "--catalogAdd" }, title = "catalog bom URIs to add", + description = "Specifies one or more catalog.bom URIs (or files) to be added to the catalog, as a comma-separated list") public String catalogAdd; @Option(name = { "--catalogForce" }, @@ -415,7 +418,8 @@ public class Main extends AbstractMain { launcher = createLauncher(); - CatalogInitialization catInit = new CatalogInitialization(catalogInitial, catalogReset, catalogAdd, catalogForce); + List<String> catalogsAdd = Strings.isBlank(catalogAdd) ? ImmutableList.<String>of() : JavaStringEscapes.unwrapJsonishListIfPossible(catalogAdd); + CatalogInitialization catInit = new CatalogInitialization(catalogInitial, catalogReset, catalogsAdd, catalogForce); catInit.addPopulationCallback(new Function<CatalogInitialization,Void>() { @Override public Void apply(CatalogInitialization catInit) { http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6df6c765/server-cli/src/test/java/org/apache/brooklyn/cli/CliTest.java ---------------------------------------------------------------------- diff --git a/server-cli/src/test/java/org/apache/brooklyn/cli/CliTest.java b/server-cli/src/test/java/org/apache/brooklyn/cli/CliTest.java index 5e38a3e..947c541 100644 --- a/server-cli/src/test/java/org/apache/brooklyn/cli/CliTest.java +++ b/server-cli/src/test/java/org/apache/brooklyn/cli/CliTest.java @@ -20,12 +20,9 @@ package org.apache.brooklyn.cli; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; -import groovy.lang.GroovyClassLoader; -import io.airlift.command.Cli; -import io.airlift.command.Command; -import io.airlift.command.ParseException; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -34,6 +31,7 @@ import java.io.InputStream; import java.io.PrintStream; import java.util.Collection; import java.util.List; +import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -42,9 +40,11 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; +import org.apache.brooklyn.api.catalog.CatalogItem; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.ImplementedBy; import org.apache.brooklyn.api.location.Location; +import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.cli.AbstractMain.BrooklynCommand; import org.apache.brooklyn.cli.AbstractMain.BrooklynCommandCollectingArgs; import org.apache.brooklyn.cli.AbstractMain.DefaultInfoCommand; @@ -52,6 +52,7 @@ import org.apache.brooklyn.cli.AbstractMain.HelpCommand; import org.apache.brooklyn.cli.Main.AppShutdownHandler; import org.apache.brooklyn.cli.Main.GeneratePasswordCommand; import org.apache.brooklyn.cli.Main.LaunchCommand; +import org.apache.brooklyn.core.catalog.internal.CatalogUtils; import org.apache.brooklyn.core.entity.AbstractApplication; import org.apache.brooklyn.core.entity.AbstractEntity; import org.apache.brooklyn.core.entity.Entities; @@ -59,6 +60,8 @@ import org.apache.brooklyn.core.entity.StartableApplication; import org.apache.brooklyn.core.entity.factory.ApplicationBuilder; import org.apache.brooklyn.core.entity.trait.Startable; import org.apache.brooklyn.core.location.SimulatedLocation; +import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext; +import org.apache.brooklyn.core.mgmt.internal.LocalManagementContextRegistry; import org.apache.brooklyn.core.objs.proxy.EntityProxy; import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests; import org.apache.brooklyn.test.Asserts; @@ -67,6 +70,8 @@ import org.apache.brooklyn.util.core.ResourceUtils; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.exceptions.FatalConfigurationRuntimeException; import org.apache.brooklyn.util.exceptions.UserFacingException; +import org.apache.brooklyn.util.os.Os; +import org.apache.brooklyn.util.text.Identifiers; import org.apache.brooklyn.util.time.Duration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -75,11 +80,19 @@ import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import com.google.common.base.Joiner; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import com.google.common.io.Files; +import groovy.lang.GroovyClassLoader; +import io.airlift.command.Cli; +import io.airlift.command.Command; +import io.airlift.command.ParseException; + public class CliTest { private static final Logger LOG = LoggerFactory.getLogger(CliTest.class); @@ -89,6 +102,8 @@ public class CliTest { private ExecutorService executor; private StartableApplication app; + private List<File> filesToDelete; + private static volatile ExampleEntity exampleEntity; // static so that they can be set from the static classes ExampleApp and ExampleEntity @@ -98,6 +113,7 @@ public class CliTest { @BeforeMethod(alwaysRun=true) public void setUp() throws Exception { + filesToDelete = Lists.newArrayList(); executor = Executors.newCachedThreadPool(); exampleAppConstructed = false; exampleAppRunning = false; @@ -109,6 +125,11 @@ public class CliTest { if (executor != null) executor.shutdownNow(); if (app != null) Entities.destroyAll(app.getManagementContext()); if (exampleEntity != null && exampleEntity.getApplication() != null) Entities.destroyAll(exampleEntity.getApplication().getManagementContext()); + if (filesToDelete != null) { + for (File file : filesToDelete) { + file.delete(); + } + } } @Test @@ -396,6 +417,63 @@ public class CliTest { } @Test + public void testAddBomToCatalog() throws Exception { + runAddBomToCatalog(1); + } + + @Test + public void testAddMultipleBomsToCatalog() throws Exception { + runAddBomToCatalog(3); + } + + protected void runAddBomToCatalog(int numBoms) throws Exception { + final List<String> bomFiles = Lists.newArrayList(); + final List<String> itemSymbolicNames = Lists.newArrayList(); + for (int i = 0; i < numBoms; i++) { + String itemName = "testAddToCatalog."+i+"."+Identifiers.makeRandomId(8); + String itemVersion = "1.2."+i; + File bomFile = generateSimpleBomFile(itemName, itemVersion); + bomFiles.add(bomFile.getAbsolutePath()); + itemSymbolicNames.add(itemName+":"+itemVersion); + } + + final Set<LocalManagementContext> origMgmts = LocalManagementContextRegistry.getInstances(); + + Cli<BrooklynCommand> cli = buildCli(); + BrooklynCommand command = cli.parse("launch", "--noConsole", "--catalogAdd", Joiner.on(",").join(bomFiles)); + submitCommandAndAssertRunnableSucceeds(command, new Runnable() { + public void run() { + ManagementContext mgmt = assertMgmtStartedEventually(); + for (String itemName : itemSymbolicNames) { + CatalogItem<?, ?> item = mgmt.getCatalog().getCatalogItem(CatalogUtils.getSymbolicNameFromVersionedId(itemName), CatalogUtils.getVersionFromVersionedId(itemName)); + assertNotNull(item); + } + } + private ManagementContext assertMgmtStartedEventually() { + return Asserts.succeedsEventually(new Callable<ManagementContext>() { + public ManagementContext call() { + ManagementContext mgmt = Iterables.getOnlyElement(Sets.difference(LocalManagementContextRegistry.getInstances(), origMgmts)); + assertTrue(mgmt.isStartupComplete()); + return mgmt; + }}); + } + }); + } + + private File generateSimpleBomFile(String itemName, String itemVersion) { + String catalogContents = Joiner.on("\n").join( + "brooklyn.catalog:", + " id: "+itemName, + " version: "+itemVersion, + " item:", + " services:", + " - type: org.apache.brooklyn.entity.stock.BasicApplication"); + File bomFile = Os.writeToTempFile(new ByteArrayInputStream(catalogContents.getBytes()), "testAddToCatalog", ".bom"); + filesToDelete.add(bomFile); + return bomFile; + } + + @Test public void testGeneratePasswordCommandParsed() throws Exception { Cli<BrooklynCommand> cli = buildCli(); BrooklynCommand command = cli.parse("generate-password", "--user", "myname");