Skip to content
Permalink
Browse files
This closes #1130
  • Loading branch information
aledsage committed Jan 15, 2016
2 parents 38d3102 + 6e84d00 commit e431e6ad3f47378c9e1c1e035654ed65fc4b4964
Showing 2 changed files with 149 additions and 12 deletions.
@@ -24,7 +24,9 @@
import java.io.StringReader;
import java.util.Map;

import com.google.common.collect.Iterables;
import org.apache.brooklyn.api.catalog.CatalogItem;
import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle;
import org.apache.brooklyn.api.catalog.CatalogItem.CatalogItemType;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.mgmt.ExecutionContext;
import org.apache.brooklyn.api.mgmt.ManagementContext;
@@ -33,7 +35,6 @@
import org.apache.brooklyn.core.config.external.AbstractExternalConfigSupplier;
import org.apache.brooklyn.core.config.external.ExternalConfigSupplier;
import org.apache.brooklyn.core.internal.BrooklynProperties;
import org.apache.brooklyn.core.location.AbstractLocation;
import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
import org.apache.brooklyn.core.mgmt.internal.CampYamlParser;
import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
@@ -48,10 +49,17 @@
import org.testng.annotations.Test;

import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;

@Test
public class ExternalConfigYamlTest extends AbstractYamlTest {
private static final Logger log = LoggerFactory.getLogger(ExternalConfigYamlTest.class);

// Choose a small jar; it is downloaded in some tests.
// Pick an OSGi bundle that is not part of core brooklyn.
private static final String LIBRARY_URL = "https://repository.apache.org/content/groups/public/org/apache/logging/log4j/log4j-api/2.5/log4j-api-2.5.jar";
private static final String LIBRARY_SYMBOLIC_NAME = "org.apache.logging.log4j.api";
private static final String LIBRARY_VERSION = "2.5.0";

@Override
protected LocalManagementContext newTestManagementContext() {
@@ -60,8 +68,19 @@ protected LocalManagementContext newTestManagementContext() {
props.put("brooklyn.external.myprovider.mykey", "myval");
props.put("brooklyn.external.myproviderWithoutMapArg", MyExternalConfigSupplierWithoutMapArg.class.getName());

props.put("brooklyn.external.myprovider.myCatalogId", "myId");
props.put("brooklyn.external.myprovider.myCatalogItemType", "template");
props.put("brooklyn.external.myprovider.myCatalogVersion", "1.2");
props.put("brooklyn.external.myprovider.myCatalogDescription", "myDescription");
props.put("brooklyn.external.myprovider.myCatalogDisplayName", "myDisplayName");
props.put("brooklyn.external.myprovider.myCatalogIconUrl", "classpath:///myIconUrl.png");
props.put("brooklyn.external.myprovider.myCatalogLibraryUrl", LIBRARY_URL);
props.put("brooklyn.external.myprovider.myCatalogLibraryName", LIBRARY_SYMBOLIC_NAME);
props.put("brooklyn.external.myprovider.myCatalogLibraryVersion", LIBRARY_VERSION);

return LocalManagementContextForTests.builder(true)
.useProperties(props)
.disableOsgi(false)
.build();
}

@@ -108,6 +127,97 @@ public void testExternalisedLocationConfigReferencedFromYaml() throws Exception
assertEquals(Iterables.getOnlyElement( app.getLocations() ).config().get(MY_CONFIG_KEY), "myval");
}

// Will download the given catalog library jar
@Test(groups="Integration")
public void testExternalisedCatalogConfigReferencedFromYaml() throws Exception {
String yaml = Joiner.on("\n").join(
"brooklyn.catalog:",
" id: $brooklyn:external(\"myprovider\", \"myCatalogId\")",
" itemType: $brooklyn:external(\"myprovider\", \"myCatalogItemType\")",
" version: $brooklyn:external(\"myprovider\", \"myCatalogVersion\")",
" description: $brooklyn:external(\"myprovider\", \"myCatalogDescription\")",
" displayName: $brooklyn:external(\"myprovider\", \"myCatalogDisplayName\")",
" iconUrl: $brooklyn:external(\"myprovider\", \"myCatalogIconUrl\")",
" brooklyn.libraries:",
" - $brooklyn:external(\"myprovider\", \"myCatalogLibraryUrl\")",
"",
" item:",
" services:",
" - type: brooklyn.entity.database.mysql.MySqlNode");

catalog.addItems(yaml);

CatalogItem<Object, Object> item = Iterables.getOnlyElement(catalog.getCatalogItems());
CatalogBundle bundle = Iterables.getOnlyElement(item.getLibraries());
assertEquals(item.getId(), "myId:1.2");
assertEquals(item.getCatalogItemType(), CatalogItemType.TEMPLATE);
assertEquals(item.getVersion(), "1.2");
assertEquals(item.getDescription(), "myDescription");
assertEquals(item.getDisplayName(), "myDisplayName");
assertEquals(item.getIconUrl(), "classpath:///myIconUrl.png");
assertEquals(bundle.getUrl(), LIBRARY_URL);
}

// Will download the given catalog library jar
@Test(groups="Integration")
public void testExternalisedCatalogConfigReferencedFromYamlWithLibraryMap() throws Exception {
String yaml = Joiner.on("\n").join(
"brooklyn.catalog:",
" id: myid",
" itemType: template",
" version: 1.2",
" description: myDescription",
" displayName: myDisplayName",
" iconUrl: classpath:///myIconUrl.png",
" brooklyn.libraries:",
" - name: $brooklyn:external(\"myprovider\", \"myCatalogLibraryName\")",
" version: $brooklyn:external(\"myprovider\", \"myCatalogLibraryVersion\")",
" url: $brooklyn:external(\"myprovider\", \"myCatalogLibraryUrl\")",
"",
" item:",
" services:",
" - type: brooklyn.entity.database.mysql.MySqlNode");

catalog.addItems(yaml);

CatalogItem<Object, Object> item = Iterables.getOnlyElement(catalog.getCatalogItems());
CatalogBundle bundle = Iterables.getOnlyElement(item.getLibraries());
assertEquals(bundle.getUrl(), LIBRARY_URL);
assertEquals(bundle.getSymbolicName(), LIBRARY_SYMBOLIC_NAME);
assertEquals(bundle.getVersion(), LIBRARY_VERSION);
}

// Will download the given catalog library jar
// Confirms "normal" behaviour, when all values in the catalog are hard-coded rather than using external config.
@Test(groups="Integration")
public void testNonExternalisedCatalogConfigReferencedFromYaml() throws Exception {
String yaml = Joiner.on("\n").join(
"brooklyn.catalog:",
" id: osgi.test",
" itemType: template",
" version: 1.3",
" description: CentOS 6.6 With GUI - 1.3",
" displayName: CentOS 6.6",
" iconUrl: classpath:///centos.png",
" brooklyn.libraries:",
" - " + LIBRARY_URL,
"",
" item:",
" services:",
" - type: brooklyn.entity.database.mysql.MySqlNode");

catalog.addItems(yaml);

CatalogItem<Object, Object> item = Iterables.getOnlyElement(catalog.getCatalogItems());
assertEquals(item.getId(), "osgi.test:1.3");
assertEquals(item.getCatalogItemType(), CatalogItemType.TEMPLATE);
assertEquals(item.getVersion(), "1.3");
assertEquals(item.getDescription(), "CentOS 6.6 With GUI - 1.3");
assertEquals(item.getDisplayName(), "CentOS 6.6");
assertEquals(item.getIconUrl(), "classpath:///centos.png");
assertEquals(Iterables.getOnlyElement(item.getLibraries()).getUrl(), LIBRARY_URL);
}

@Test(groups="Integration")
public void testExternalisedLocationConfigSetViaProvisioningPropertiesReferencedFromYaml() throws Exception {
String yaml = Joiner.on("\n").join(
@@ -41,12 +41,14 @@
import org.apache.brooklyn.core.catalog.CatalogPredicates;
import org.apache.brooklyn.core.catalog.internal.CatalogClasspathDo.CatalogScanningModes;
import org.apache.brooklyn.core.location.BasicLocationRegistry;
import org.apache.brooklyn.core.mgmt.internal.CampYamlParser;
import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
import org.apache.brooklyn.core.typereg.BrooklynTypePlanTransformer;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.collections.MutableSet;
import org.apache.brooklyn.util.core.flags.TypeCoercions;
import org.apache.brooklyn.util.core.task.Tasks;
import org.apache.brooklyn.util.exceptions.Exceptions;
import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.javalang.AggregateClassLoader;
@@ -395,14 +397,39 @@ private void collectCatalogItems(String sourceYaml, Map<?,?> itemMetadata, List<

if (sourceYaml==null) sourceYaml = new Yaml().dump(itemMetadata);

Map<Object,Object> catalogMetadata = MutableMap.builder().putAll(parentMetadata).putAll(itemMetadata).build();
Map<?, ?> itemMetadataWithoutItemDef = MutableMap.builder()
.putAll(itemMetadata)
.remove("item")
.remove("items")
.build();

// Parse CAMP-YAML DSL in item metadata (but not in item or items - those will be parsed only when used).
CampYamlParser parser = mgmt.getConfig().getConfig(CampYamlParser.YAML_PARSER_KEY);
if (parser != null) {
itemMetadataWithoutItemDef = parser.parse((Map<String, Object>) itemMetadataWithoutItemDef);
try {
itemMetadataWithoutItemDef = (Map<String, Object>) Tasks.resolveDeepValue(itemMetadataWithoutItemDef, Object.class, mgmt.getServerExecutionContext());
} catch (Exception e) {
throw Exceptions.propagate(e);
}

} else {
log.info("No Camp-YAML parser regsitered for parsing catalog item DSL; skipping DSL-parsing");
}

Map<Object,Object> catalogMetadata = MutableMap.<Object, Object>builder()
.putAll(parentMetadata)
.putAll(itemMetadataWithoutItemDef)
.putIfNotNull("item", itemMetadata.get("item"))
.putIfNotNull("items", itemMetadata.get("items"))
.build();

// brooklyn.libraries we treat specially, to append the list, with the child's list preferred in classloading order
// `libraries` is supported in some places as a legacy syntax; it should always be `brooklyn.libraries` for new apps
// TODO in 0.8.0 require brooklyn.libraries, don't allow "libraries" on its own
List<?> librariesNew = MutableList.copyOf(getFirstAs(itemMetadata, List.class, "brooklyn.libraries", "libraries").orNull());
List<?> librariesNew = MutableList.copyOf(getFirstAs(itemMetadataWithoutItemDef, List.class, "brooklyn.libraries", "libraries").orNull());
Collection<CatalogBundle> libraryBundlesNew = CatalogItemDtoAbstract.parseLibraries(librariesNew);

List<?> librariesCombined = MutableList.copyOf(librariesNew)
.appendAll(getFirstAs(parentMetadata, List.class, "brooklyn.libraries", "libraries").orNull());
if (!librariesCombined.isEmpty())
@@ -413,7 +440,7 @@ private void collectCatalogItems(String sourceYaml, Map<?,?> itemMetadata, List<
// (this load is required for the scan below and I think also for yaml resolution)
CatalogUtils.installLibraries(mgmt, libraryBundlesNew);

Boolean scanJavaAnnotations = getFirstAs(itemMetadata, Boolean.class, "scanJavaAnnotations", "scan_java_annotations").orNull();
Boolean scanJavaAnnotations = getFirstAs(itemMetadataWithoutItemDef, Boolean.class, "scanJavaAnnotations", "scan_java_annotations").orNull();
if (scanJavaAnnotations==null || !scanJavaAnnotations) {
// don't scan
} else {
@@ -433,8 +460,8 @@ private void collectCatalogItems(String sourceYaml, Map<?,?> itemMetadata, List<
if (items!=null) {
int count = 0;
for (Map<?,?> i: ((List<Map<?,?>>)items)) {
collectCatalogItems(Yamls.getTextOfYamlAtPath(sourceYaml, "items", count).getMatchedYamlTextOrWarn(),
i, result, catalogMetadata);
collectCatalogItems(Yamls.getTextOfYamlAtPath(sourceYaml, "items", count).getMatchedYamlTextOrWarn(),
i, result, catalogMetadata);
count++;
}
}
@@ -584,12 +611,12 @@ private String setFromItemIfUnset(String oldValue, Map<?,?> item, String fieldAt
return oldValue;
}

private Collection<CatalogItemDtoAbstract<?, ?>> scanAnnotationsFromLocal(ManagementContext mgmt, Map<Object, Object> catalogMetadata) {
private Collection<CatalogItemDtoAbstract<?, ?>> scanAnnotationsFromLocal(ManagementContext mgmt, Map<?, ?> catalogMetadata) {
CatalogDto dto = CatalogDto.newNamedInstance("Local Scanned Catalog", "All annotated Brooklyn entities detected in the classpath", "scanning-local-classpath");
return scanAnnotationsInternal(mgmt, new CatalogDo(dto), catalogMetadata);
}

private Collection<CatalogItemDtoAbstract<?, ?>> scanAnnotationsFromBundles(ManagementContext mgmt, Collection<CatalogBundle> libraries, Map<Object, Object> catalogMetadata) {
private Collection<CatalogItemDtoAbstract<?, ?>> scanAnnotationsFromBundles(ManagementContext mgmt, Collection<CatalogBundle> libraries, Map<?, ?> catalogMetadata) {
CatalogDto dto = CatalogDto.newNamedInstance("Bundles Scanned Catalog", "All annotated Brooklyn entities detected in bundles", "scanning-bundles-classpath-"+libraries.hashCode());
List<String> urls = MutableList.of();
for (CatalogBundle b: libraries) {
@@ -610,7 +637,7 @@ private String setFromItemIfUnset(String oldValue, Map<?,?> item, String fieldAt
return scanAnnotationsInternal(mgmt, subCatalog, catalogMetadata);
}

private Collection<CatalogItemDtoAbstract<?, ?>> scanAnnotationsInternal(ManagementContext mgmt, CatalogDo subCatalog, Map<Object, Object> catalogMetadata) {
private Collection<CatalogItemDtoAbstract<?, ?>> scanAnnotationsInternal(ManagementContext mgmt, CatalogDo subCatalog, Map<?, ?> catalogMetadata) {
// TODO this does java-scanning only;
// the call when scanning bundles should use the CatalogItem instead and use OSGi when loading for scanning
// (or another scanning mechanism). see comments on CatalogClasspathDo.load
@@ -991,7 +1018,7 @@ public CatalogItem<T,SpecT> apply(@Nullable CatalogItemDo<T,SpecT> item) {
};
}

private static <T,SpecT> Function<CatalogItemDo<T, SpecT>, CatalogItem<T,SpecT>> itemDoToDtoAddingSelectedMetadataDuringScan(final Map<Object, Object> catalogMetadata) {
private static <T,SpecT> Function<CatalogItemDo<T, SpecT>, CatalogItem<T,SpecT>> itemDoToDtoAddingSelectedMetadataDuringScan(final Map<?, ?> catalogMetadata) {
return new Function<CatalogItemDo<T,SpecT>, CatalogItem<T,SpecT>>() {
@Override
public CatalogItem<T,SpecT> apply(@Nullable CatalogItemDo<T,SpecT> item) {

0 comments on commit e431e6a

Please sign in to comment.