diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampInternalUtils.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampInternalUtils.java index c2c6c401dc..8c9bf6357d 100644 --- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampInternalUtils.java +++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampInternalUtils.java @@ -37,6 +37,7 @@ import org.apache.brooklyn.api.policy.Policy; import org.apache.brooklyn.api.policy.PolicySpec; import org.apache.brooklyn.api.typereg.RegisteredType; +import org.apache.brooklyn.api.typereg.RegisteredTypeLoadingContext; import org.apache.brooklyn.camp.CampPlatform; import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants; import org.apache.brooklyn.camp.brooklyn.BrooklynCampReservedKeys; @@ -47,6 +48,7 @@ import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog; import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog.BrooklynLoaderTracker; import org.apache.brooklyn.core.objs.BasicSpecParameter; +import org.apache.brooklyn.core.typereg.RegisteredTypeLoadingContexts; import org.apache.brooklyn.entity.stock.BasicApplicationImpl; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.exceptions.Exceptions; @@ -208,7 +210,8 @@ private static PolicySpec resolvePolicySpec( PolicySpec spec; RegisteredType item = loader.getManagementContext().getTypeRegistry().get(versionedId); if (item != null && !encounteredCatalogTypes.contains(item.getSymbolicName())) { - return loader.getManagementContext().getTypeRegistry().createSpec(item, null, PolicySpec.class); + RegisteredTypeLoadingContext context = RegisteredTypeLoadingContexts.alreadyEncountered(encounteredCatalogTypes); + return loader.getManagementContext().getTypeRegistry().createSpec(item, context, PolicySpec.class); } else { // TODO-type-registry pass the loader in to the above, and allow it to load with the loader spec = PolicySpec.create(loader.loadClass(versionedId, Policy.class)); diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java index b1db078b2d..a67d89ec6f 100644 --- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java +++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java @@ -45,6 +45,7 @@ import org.apache.brooklyn.core.mgmt.persist.DeserializingClassRenamesProvider; import org.apache.brooklyn.core.sensor.DependentConfiguration; import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.core.ClassLoaderUtils; import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.core.flags.ClassCoercionException; import org.apache.brooklyn.util.core.flags.FlagUtils; @@ -129,9 +130,10 @@ public static BrooklynDslDeferredSupplier> sensor(String sensorName) { @SuppressWarnings({ "unchecked", "rawtypes" }) public static Sensor sensor(String clazzName, String sensorName) { try { - // TODO Should use catalog's classloader, rather than Class.forName; how to get that? Should we return a future?! + // TODO Should use catalog's classloader, rather than ClassLoaderUtils; how to get that? Should we return a future?! + // Should have the catalog's loader at this point in a thread local String mappedClazzName = DeserializingClassRenamesProvider.findMappedName(clazzName); - Class clazz = Class.forName(mappedClazzName); + Class clazz = new ClassLoaderUtils(BrooklynDslCommon.class).loadClass(mappedClazzName); Sensor sensor; if (Entity.class.isAssignableFrom(clazz)) { @@ -170,9 +172,9 @@ public static Object object(Map arguments) { Map objectFields = (Map) config.getStringKeyMaybe("object.fields").or(MutableMap.of()); Map brooklynConfig = (Map) config.getStringKeyMaybe(BrooklynCampReservedKeys.BROOKLYN_CONFIG).or(MutableMap.of()); try { - // TODO Should use catalog's classloader, rather than Class.forName; how to get that? Should we return a future?! + // TODO Should use catalog's classloader, rather than ClassLoaderUtils; how to get that? Should we return a future?! String mappedTypeName = DeserializingClassRenamesProvider.findMappedName(typeName); - Class type = Class.forName(mappedTypeName); + Class type = new ClassLoaderUtils(BrooklynDslCommon.class).loadClass(mappedTypeName); if (!Reflections.hasNoArgConstructor(type)) { throw new IllegalStateException(String.format("Cannot construct %s bean: No public no-arg constructor available", type)); diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java index 484c160b3a..60eed64a87 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java @@ -868,6 +868,30 @@ public void testItemWithBrooklynParameters() throws Exception { mgmt().getCatalog().deleteCatalogItem(id, version); } + @Test + public void testCreateOsgiSpecFromRegistry() throws Exception { + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH); + + String symbolicName = "my.catalog.app.id.registry.spec"; + addCatalogItems( + "brooklyn.catalog:", + " id: " + symbolicName, + " name: My Catalog App", + " description: My description", + " icon_url: classpath://path/to/myicon.jpg", + " version: " + TEST_VERSION, + " libraries:", + " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL, + " item: " + SIMPLE_ENTITY_TYPE); + + BrooklynTypeRegistry registry = mgmt().getTypeRegistry(); + RegisteredType item = registry.get(symbolicName, TEST_VERSION); + AbstractBrooklynObjectSpec spec = registry.createSpec(item, null, null); + assertEquals(spec.getCatalogItemId(), ver(symbolicName)); + + deleteCatalogEntity(symbolicName); + } + private void registerAndLaunchAndAssertSimpleEntity(String symbolicName, String serviceType) throws Exception { addCatalogOSGiEntity(symbolicName, serviceType); String yaml = "name: simple-app-yaml\n" + diff --git a/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java b/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java index 48418a34ba..f2e8a0ac2d 100644 --- a/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java +++ b/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java @@ -111,6 +111,13 @@ public class BrooklynFeatureEnablement { public static final String FEATURE_VALIDATE_LOCATION_SSH_KEYS = "brooklyn.validate.locationSshKeys"; + /** + * Whether to scan newly loaded bundles for catalog.bom and load it. + * + * The functionality loads catalog items regardless of the persistence state so best used with persistence disabled. + */ + public static final String FEATURE_LOAD_BUNDLE_CATALOG_BOM = FEATURE_PROPERTY_PREFIX+".osgi.catalog_bom"; + /** * Values explicitly set by Java calls. */ @@ -146,6 +153,7 @@ static void setDefaults() { setDefault(FEATURE_AUTO_FIX_CATALOG_REF_ON_REBIND, false); setDefault(FEATURE_SSH_ASYNC_EXEC, false); setDefault(FEATURE_VALIDATE_LOCATION_SSH_KEYS, true); + setDefault(FEATURE_LOAD_BUNDLE_CATALOG_BOM, false); } static { diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java index ae2885a0ed..b7e0041cc0 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java @@ -23,6 +23,7 @@ import com.google.common.collect.Iterables; import org.apache.brooklyn.api.catalog.CatalogItem; import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.core.BrooklynFeatureEnablement; import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.stream.Streams; @@ -60,21 +61,29 @@ public class CatalogBomScanner { private CatalogPopulator catalogTracker; public void bind(ServiceReference managementContext) throws Exception { - LOG.debug("Binding management context with whiteList [{}] and blacklist [{}]", - Strings.join(getWhiteList(), "; "), - Strings.join(getBlackList(), "; ")); - catalogTracker = new CatalogPopulator(managementContext); + if (isEnabled()) { + LOG.debug("Binding management context with whiteList [{}] and blacklist [{}]", + Strings.join(getWhiteList(), "; "), + Strings.join(getBlackList(), "; ")); + catalogTracker = new CatalogPopulator(managementContext); + } } public void unbind(ServiceReference managementContext) throws Exception { - LOG.debug("Unbinding management context"); - if (null != catalogTracker) { - CatalogPopulator temp = catalogTracker; - catalogTracker = null; - temp.close(); + if (isEnabled()) { + LOG.debug("Unbinding management context"); + if (null != catalogTracker) { + CatalogPopulator temp = catalogTracker; + catalogTracker = null; + temp.close(); + } } } + private boolean isEnabled() { + return BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_LOAD_BUNDLE_CATALOG_BOM); + } + private String[] bundleIds(Bundle bundle) { return new String[] { String.valueOf(bundle.getBundleId()), bundle.getSymbolicName(), bundle.getVersion().toString() diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java b/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java index d35068f573..ba8d679046 100644 --- a/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java +++ b/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java @@ -20,6 +20,7 @@ import java.util.Map; +import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.EntityInitializer; import org.apache.brooklyn.api.entity.EntityLocal; import org.apache.brooklyn.api.sensor.AttributeSensor; @@ -27,6 +28,7 @@ import org.apache.brooklyn.core.config.ConfigKeys; import org.apache.brooklyn.core.entity.EntityInternal; import org.apache.brooklyn.core.sensor.Sensors; +import org.apache.brooklyn.util.core.ClassLoaderUtils; import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.guava.Maybe; import org.apache.brooklyn.util.javalang.Boxing; @@ -54,7 +56,7 @@ public class AddSensor implements EntityInitializer { protected final String name; protected final Duration period; protected final String type; - protected final AttributeSensor sensor; + protected AttributeSensor sensor; public AddSensor(Map params) { this(ConfigBag.newInstance(params)); @@ -64,27 +66,28 @@ public AddSensor(final ConfigBag params) { this.name = Preconditions.checkNotNull(params.get(SENSOR_NAME), "Name must be supplied when defining a sensor"); this.period = params.get(SENSOR_PERIOD); this.type = params.get(SENSOR_TYPE); - this.sensor = newSensor(); } @Override public void apply(EntityLocal entity) { + sensor = newSensor(entity); ((EntityInternal) entity).getMutableEntityType().addSensor(sensor); } - private AttributeSensor newSensor() { + private AttributeSensor newSensor(Entity entity) { String className = getFullClassName(type); - Class clazz = getType(className); + Class clazz = getType(entity, className); return Sensors.newSensor(clazz, name); } @SuppressWarnings("unchecked") - protected Class getType(String className) { + protected Class getType(Entity entity, String className) { try { // TODO use OSGi loader (low priority however); also ensure that allows primitives Maybe> primitive = Boxing.getPrimitiveType(className); if (primitive.isPresent()) return (Class) primitive.get(); - return (Class) Class.forName(className); + + return (Class) new ClassLoaderUtils(this, entity).loadClass(className); } catch (ClassNotFoundException e) { if (!className.contains(".")) { // could be assuming "java.lang" package; try again with that diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/drivers/ReflectiveEntityDriverFactory.java b/core/src/main/java/org/apache/brooklyn/core/entity/drivers/ReflectiveEntityDriverFactory.java index f9cf5a707e..a2d6722b66 100644 --- a/core/src/main/java/org/apache/brooklyn/core/entity/drivers/ReflectiveEntityDriverFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/entity/drivers/ReflectiveEntityDriverFactory.java @@ -26,12 +26,14 @@ import org.apache.brooklyn.api.entity.drivers.DriverDependentEntity; import org.apache.brooklyn.api.entity.drivers.EntityDriver; import org.apache.brooklyn.api.location.Location; +import org.apache.brooklyn.core.BrooklynVersion; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.brooklyn.location.paas.PaasLocation; import org.apache.brooklyn.location.ssh.SshMachineLocation; import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.core.ClassLoaderUtils; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.exceptions.ReferenceWithError; import org.apache.brooklyn.util.text.Strings; @@ -193,7 +195,8 @@ public String inferDriverClassName(DriverDependentEntit String driverInterfaceName = driverInterface.getName(); // TODO: use a proper registry later on try { - if (!Class.forName("org.apache.brooklyn.location.winrm.WinRmMachineLocation").isInstance(location)) return null; + Class winRmLocationClass = new ClassLoaderUtils(this, entity).loadClass("org.apache.brooklyn.software-winrm", BrooklynVersion.get(), "org.apache.brooklyn.location.winrm.WinRmMachineLocation"); + if (!winRmLocationClass.isInstance(location)) return null; } catch (ClassNotFoundException ex) { return null; } diff --git a/core/src/main/java/org/apache/brooklyn/core/location/geo/HostGeoInfo.java b/core/src/main/java/org/apache/brooklyn/core/location/geo/HostGeoInfo.java index f99b41d498..ced6b7ce97 100644 --- a/core/src/main/java/org/apache/brooklyn/core/location/geo/HostGeoInfo.java +++ b/core/src/main/java/org/apache/brooklyn/core/location/geo/HostGeoInfo.java @@ -28,6 +28,7 @@ import org.apache.brooklyn.api.location.Location; import org.apache.brooklyn.core.location.AbstractLocation; import org.apache.brooklyn.core.location.LocationConfigKeys; +import org.apache.brooklyn.util.core.ClassLoaderUtils; import org.apache.brooklyn.util.core.flags.TypeCoercions; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.guava.Maybe; @@ -164,7 +165,7 @@ private static HostGeoLookup findHostGeoLookupImpl() throws InstantiationExcepti return new UtraceHostGeoLookup(); } if (type.isEmpty()) return null; - return (HostGeoLookup) Class.forName(type).newInstance(); + return (HostGeoLookup) new ClassLoaderUtils(HostGeoInfo.class).loadClass(type).newInstance(); } public static HostGeoInfo fromEntity(Entity e) { diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/JavaBrooklynClassLoadingContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/JavaBrooklynClassLoadingContext.java index 064ba033e3..e89501e637 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/JavaBrooklynClassLoadingContext.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/JavaBrooklynClassLoadingContext.java @@ -29,6 +29,7 @@ import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.core.entity.AbstractEntity; import org.apache.brooklyn.core.mgmt.persist.DeserializingClassRenamesProvider; +import org.apache.brooklyn.util.core.ClassLoaderUtils; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.guava.Maybe; import org.slf4j.Logger; @@ -81,9 +82,24 @@ private ClassLoader getClassLoader() { if (mgmt!=null) return mgmt.getCatalogClassLoader(); return JavaBrooklynClassLoadingContext.class.getClassLoader(); } - + @SuppressWarnings({ "rawtypes", "unchecked" }) public Maybe> tryLoadClass(String className) { + Maybe> cls = tryLoadClass0(className); + if (cls.isPresent()) { + return cls; + } + try { + return (Maybe) Maybe.of(new ClassLoaderUtils(this, mgmt).loadClass(className)); + } catch (Exception e) { + Exceptions.propagateIfFatal(e); + // return original error + return cls; + } + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private Maybe> tryLoadClass0(String className) { try { className = DeserializingClassRenamesProvider.findMappedName(className); return (Maybe) Maybe.of(getClassLoader().loadClass(className)); diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java index 7199267359..e867c76038 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java @@ -21,7 +21,6 @@ import java.util.Arrays; import java.util.List; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.apache.brooklyn.api.entity.Entity; @@ -35,8 +34,8 @@ import org.apache.brooklyn.core.config.Sanitizer; import org.apache.brooklyn.core.internal.BrooklynProperties; import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; -import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal; import org.apache.brooklyn.core.mgmt.persist.DeserializingClassRenamesProvider; +import org.apache.brooklyn.util.core.ClassLoaderUtils; import org.apache.brooklyn.util.core.task.Tasks; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.javalang.Reflections; @@ -455,10 +454,7 @@ public static EntitlementManager load(@Nullable ManagementContext mgmt, Brooklyn } if (Strings.isNonBlank(type)) { try { - ClassLoader cl = mgmt != null - ? mgmt.getCatalogClassLoader() - : Entitlements.class.getClassLoader(); - Class clazz = cl.loadClass(DeserializingClassRenamesProvider.findMappedName(type)); + Class clazz = new ClassLoaderUtils(Entitlements.class, mgmt).loadClass(DeserializingClassRenamesProvider.findMappedName(type)); return (EntitlementManager) instantiate(clazz, ImmutableList.of( new Object[] {mgmt, brooklynProperties}, new Object[] {mgmt}, diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java index da2f30cffe..67bcd11119 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java @@ -73,6 +73,7 @@ import org.apache.brooklyn.core.typereg.BasicBrooklynTypeRegistry; import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.core.ClassLoaderUtils; import org.apache.brooklyn.util.core.ResourceUtils; import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.core.task.BasicExecutionContext; @@ -99,7 +100,7 @@ private static DataGridFactory loadDataGridFactory(BrooklynProperties properties Class clazz; try{ //todo: which classloader should we use? - clazz = LocalManagementContext.class.getClassLoader().loadClass(clazzName); + clazz = new ClassLoaderUtils(AbstractManagementContext.class).loadClass(clazzName); }catch(ClassNotFoundException e){ throw new IllegalStateException(format("Could not load class [%s]",clazzName),e); } diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerLoader.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerLoader.java index 79653271fc..37f2cae3f5 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerLoader.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerLoader.java @@ -23,6 +23,7 @@ import java.util.Map.Entry; import org.apache.brooklyn.core.mgmt.rebind.transformer.CompoundTransformer.Builder; +import org.apache.brooklyn.util.core.ClassLoaderUtils; import org.apache.brooklyn.util.core.ResourceUtils; import org.apache.brooklyn.util.core.text.TemplateProcessor; import org.apache.brooklyn.util.exceptions.Exceptions; @@ -89,7 +90,7 @@ private static void addRule(Builder builder, String name, Map args) { } else if (name.equals("rawDataTransformer")) { String type = (String) args.get("type"); try { - Class clazz = CompoundTransformerLoader.class.getClassLoader().loadClass(type); + Class clazz = new ClassLoaderUtils(CompoundTransformer.class).loadClass(type); builder.rawDataTransformer((RawDataTransformer) clazz.newInstance()); } catch (Exception e) { throw Exceptions.propagate(e); diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynTypes.java b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynTypes.java index 41706133a6..fa8d60774e 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynTypes.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynTypes.java @@ -30,6 +30,7 @@ import org.apache.brooklyn.core.enricher.EnricherDynamicType; import org.apache.brooklyn.core.entity.EntityDynamicType; import org.apache.brooklyn.core.policy.PolicyDynamicType; +import org.apache.brooklyn.util.core.ClassLoaderUtils; import org.apache.brooklyn.util.exceptions.Exceptions; import com.google.common.collect.Maps; @@ -110,7 +111,7 @@ public static Map> getDefinedConfigKeys(Class> getDefinedConfigKeys(String brooklynTypeName) { try { - return getDefinedConfigKeys((Class) Class.forName(brooklynTypeName)); + return getDefinedConfigKeys((Class) new ClassLoaderUtils(BrooklynTypes.class).loadClass(brooklynTypeName)); } catch (ClassNotFoundException e) { throw Exceptions.propagate(e); } @@ -123,7 +124,7 @@ public static Map> getDefinedSensors(Class e @SuppressWarnings("unchecked") public static Map> getDefinedSensors(String entityTypeName) { try { - return getDefinedSensors((Class) Class.forName(entityTypeName)); + return getDefinedSensors((Class) new ClassLoaderUtils(BrooklynTypes.class).loadClass(entityTypeName)); } catch (ClassNotFoundException e) { throw Exceptions.propagate(e); } diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/DurationSinceSensor.java b/core/src/main/java/org/apache/brooklyn/core/sensor/DurationSinceSensor.java index 4be57d85a6..b26af561f4 100644 --- a/core/src/main/java/org/apache/brooklyn/core/sensor/DurationSinceSensor.java +++ b/core/src/main/java/org/apache/brooklyn/core/sensor/DurationSinceSensor.java @@ -39,6 +39,7 @@ public class DurationSinceSensor extends AddSensor { private static final Supplier CURRENT_TIME_SUPPLIER = new CurrentTimeSupplier(); + @SuppressWarnings("serial") public static final ConfigKey> EPOCH_SUPPLIER = ConfigKeys.builder(new TypeToken>() {}) .name("duration.since.epochsupplier") .description("The source of time from which durations are measured. Defaults to System.currentTimeMillis when " + @@ -46,6 +47,7 @@ public class DurationSinceSensor extends AddSensor { .defaultValue(CURRENT_TIME_SUPPLIER) .build(); + @SuppressWarnings("serial") public static final ConfigKey> TIME_SUPPLIER = ConfigKeys.builder(new TypeToken>() {}) .name("duration.since.timesupplier") .description("The source of the current time. Defaults to System.currentTimeMillis if unconfigured or the " + @@ -55,19 +57,20 @@ public class DurationSinceSensor extends AddSensor { private final Supplier epochSupplier; private final Supplier timeSupplier; - private final AttributeSensor epochSensor; + private AttributeSensor epochSensor; public DurationSinceSensor(ConfigBag params) { super(params); epochSupplier = params.get(EPOCH_SUPPLIER); timeSupplier = params.get(TIME_SUPPLIER); - epochSensor = Sensors.newLongSensor(sensor.getName() + ".epoch"); } @Override public void apply(final EntityLocal entity) { super.apply(entity); + epochSensor = Sensors.newLongSensor(sensor.getName() + ".epoch"); + if (entity.sensors().get(epochSensor) == null) { Long epoch = epochSupplier.get(); if (epoch == null) { diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensor.java b/core/src/main/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensor.java index 839448eafc..25ae2b5f3a 100644 --- a/core/src/main/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensor.java +++ b/core/src/main/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensor.java @@ -105,7 +105,7 @@ public String get() { .onSuccess(Functions.compose(new Function() { @Override public T apply(String input) { - return TypeCoercions.coerce(Strings.trimEnd(input), getType(type)); + return TypeCoercions.coerce(Strings.trimEnd(input), getType(entity, type)); }}, SshValueFunctions.stdout())); SshFeed.builder() diff --git a/core/src/main/java/org/apache/brooklyn/location/byon/ByonLocationResolver.java b/core/src/main/java/org/apache/brooklyn/location/byon/ByonLocationResolver.java index 58b4989056..ca478fd872 100644 --- a/core/src/main/java/org/apache/brooklyn/location/byon/ByonLocationResolver.java +++ b/core/src/main/java/org/apache/brooklyn/location/byon/ByonLocationResolver.java @@ -35,6 +35,7 @@ import org.apache.brooklyn.core.location.AbstractLocationResolver; import org.apache.brooklyn.core.mgmt.internal.LocalLocationManager; import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.core.ClassLoaderUtils; import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.core.flags.TypeCoercions; import org.apache.brooklyn.util.net.UserAndHostAndPort; @@ -212,7 +213,8 @@ protected LocationSpec parseMachine(Map va private Class getLocationClass(String osFamily) { try { if (osFamily != null) { - return Class.forName(OS_TO_MACHINE_LOCATION_TYPE.get(osFamily.toLowerCase(Locale.ENGLISH))).asSubclass(MachineLocation.class); + String className = OS_TO_MACHINE_LOCATION_TYPE.get(osFamily.toLowerCase(Locale.ENGLISH)); + return new ClassLoaderUtils(this, managementContext).loadClass(className).asSubclass(MachineLocation.class); } } catch (ClassNotFoundException ex) {} return null; diff --git a/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java b/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java index b66c94c5aa..de7b7a880f 100644 --- a/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java +++ b/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java @@ -72,6 +72,7 @@ import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; import org.apache.brooklyn.core.mgmt.internal.LocalLocationManager; import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.core.ClassLoaderUtils; import org.apache.brooklyn.util.core.ResourceUtils; import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.core.crypto.SecureKeys; @@ -688,7 +689,7 @@ protected SshTool connectSsh(Map props) { } } if (sshToolClass==null) sshToolClass = SshjTool.class.getName(); - SshTool ssh = (SshTool) Class.forName(sshToolClass).getConstructor(Map.class).newInstance(args.getAllConfig()); + SshTool ssh = (SshTool) new ClassLoaderUtils(this, getManagementContext()).loadClass(sshToolClass).getConstructor(Map.class).newInstance(args.getAllConfig()); if (LOG.isTraceEnabled()) LOG.trace("using ssh-tool {} (of type {}); props ", ssh, sshToolClass); diff --git a/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java b/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java new file mode 100644 index 0000000000..5bbce8d44f --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java @@ -0,0 +1,249 @@ +/* + * Copyright 2016 The Apache Software Foundation. + * + * Licensed 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.util.core; + +import java.util.List; +import java.util.regex.Pattern; + +import javax.annotation.Nullable; + +import org.apache.brooklyn.api.catalog.CatalogItem; +import org.apache.brooklyn.api.entity.Entity; +import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext; +import org.apache.brooklyn.core.BrooklynVersion; +import org.apache.brooklyn.core.catalog.internal.CatalogUtils; +import org.apache.brooklyn.core.entity.EntityInternal; +import org.apache.brooklyn.core.mgmt.ha.OsgiManager; +import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal; +import org.apache.brooklyn.util.core.osgi.Osgis; +import org.apache.brooklyn.util.core.osgi.SystemFrameworkLoader; +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.guava.Maybe; +import org.apache.brooklyn.util.osgi.SystemFramework; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.launch.Framework; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Predicate; + +public class ClassLoaderUtils { + /** + * White list format should be + * [:] + */ + private static final String WHITE_LIST_DEFAULT = "org\\.apache\\.brooklyn\\..*:" + BrooklynVersion.get().replaceFirst("-", "."); + private static final String WHITE_LIST_KEY = "org.apache.brooklyn.classloader.fallback.bundles"; + private static final String CLASS_NAME_DELIMITER = ":"; + private static final Logger log = LoggerFactory.getLogger(ClassLoaderUtils.class); + + // Class.forName gets the class loader from the calling class. + // We don't have access to the same reflection API so need to pass it explicitly. + private final Class callingClass; + private final Entity entity; + private final ManagementContext mgmt; + + public ClassLoaderUtils(Object callingObj, Entity entity) { + this(callingObj.getClass(), entity); + } + public ClassLoaderUtils(Object callingObj, @Nullable ManagementContext mgmt) { + this(callingObj.getClass(), mgmt); + } + + public ClassLoaderUtils(Class callingClass) { + this.callingClass = callingClass; + this.entity = null; + this.mgmt = null; + } + + public ClassLoaderUtils(Class callingClass, Entity entity) { + this.callingClass = callingClass; + this.entity = entity; + this.mgmt = ((EntityInternal)entity).getManagementContext(); + } + + public ClassLoaderUtils(Class callingClass, @Nullable ManagementContext mgmt) { + this.callingClass = callingClass; + this.entity = null; + this.mgmt = mgmt; + } + + public Class loadClass(String name) throws ClassNotFoundException { + if (looksLikeBundledClassName(name)) { + String[] arr = name.split(CLASS_NAME_DELIMITER); + String symbolicName; + String version; + String className; + if (arr.length > 3) { + throw new IllegalStateException("'" + name + "' doesn't look like a class name and contains too many colons to be parsed as bundle:version:class triple."); + } else if (arr.length == 3) { + symbolicName = arr[0]; + version = arr[1]; + className = arr[2]; + } else if (arr.length == 2) { + symbolicName = arr[0]; + version = null; + className = arr[1]; + } else { + throw new IllegalStateException("'" + name + "' contains a bundle:version:class delimiter, but only one of those specified"); + } + return loadClass(symbolicName, version, className); + } + + if (entity != null && mgmt != null) { + String catalogItemId = entity.getCatalogItemId(); + if (catalogItemId != null) { + CatalogItem item = CatalogUtils.getCatalogItemOptionalVersion(mgmt, catalogItemId); + if (item != null) { + BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(mgmt, item); + try { + return loader.loadClass(name); + } catch (IllegalStateException e) { + ClassNotFoundException cnfe = Exceptions.getFirstThrowableOfType(e, ClassNotFoundException.class); + NoClassDefFoundError ncdfe = Exceptions.getFirstThrowableOfType(e, NoClassDefFoundError.class); + if (cnfe == null && ncdfe == null) { + throw e; + } else { + // ignore, fall back to Class.forName(...) + } + } + } else { + log.warn("Entity " + entity + " refers to non-existent catalog item " + catalogItemId + ". Trying to load class " + name); + } + } + } + + try { + // Used instead of callingClass.getClassLoader() as it could be null (only for bootstrap classes) + return Class.forName(name, true, callingClass.getClassLoader()); + } catch (ClassNotFoundException e) { + } + + if (mgmt != null) { + try { + return mgmt.getCatalogClassLoader().loadClass(name); + } catch (ClassNotFoundException e) { + } + } + + Class cls = tryLoadFromBundleWhiteList(name); + if (cls != null) { + return cls; + } else { + throw new ClassNotFoundException("Class " + name + " not found on the application class path, nor in the bundle white list."); + } + } + + public Class loadClass(String symbolicName, @Nullable String version, String className) throws ClassNotFoundException { + Framework framework = getFramework(); + if (framework != null) { + Maybe bundle = Osgis.bundleFinder(framework) + .symbolicName(symbolicName) + .version(version) + .find(); + if (bundle.isAbsent() && version != null) { + bundle = Osgis.bundleFinder(framework) + .symbolicName(symbolicName) + // Convert X.X.X-SNAPSHOT to X.X.X.SNAPSHOT. Any better way to do it? + .version(version.replace("-", ".")) + .find(); + } + if (bundle.isAbsent()) { + throw new IllegalStateException("Bundle " + symbolicName + ":" + (version != null ? version : "any") + " not found to load class " + className); + } + return SystemFrameworkLoader.get().loadClassFromBundle(className, bundle.get()); + } else { + return Class.forName(className); + } + } + + protected Framework getFramework() { + if (mgmt != null) { + Maybe osgiManager = ((ManagementContextInternal)mgmt).getOsgiManager(); + if (osgiManager.isPresent()) { + OsgiManager osgi = osgiManager.get(); + return osgi.getFramework(); + } + } + + // Requires that caller code is executed AFTER loading bundle brooklyn-core + Bundle bundle = FrameworkUtil.getBundle(ClassLoaderUtils.class); + if (bundle != null) { + BundleContext bundleContext = bundle.getBundleContext(); + return (Framework) bundleContext.getBundle(0); + } else { + return null; + } + } + + private boolean looksLikeBundledClassName(String name) { + return name.indexOf(CLASS_NAME_DELIMITER) != -1; + } + + + private static class WhiteListBundlePredicate implements Predicate { + private Pattern symbolicName; + private Pattern version; + + private WhiteListBundlePredicate(String symbolicName, String version) { + this.symbolicName = Pattern.compile(symbolicName); + this.version = version != null ? Pattern.compile(version) : null; + } + + @Override + public boolean apply(Bundle input) { + return symbolicName.matcher(input.getSymbolicName()).matches() && + (version == null || version.matcher(input.getVersion().toString()).matches()); + } + + } + + private Class tryLoadFromBundleWhiteList(String name) { + Framework framework = getFramework(); + if (framework == null) { + return null; + } + List bundles = Osgis.bundleFinder(framework) + .satisfying(createBundleMatchingPredicate()) + .findAll(); + SystemFramework bundleLoader = SystemFrameworkLoader.get(); + for (Bundle b : bundles) { + try { + return bundleLoader.loadClassFromBundle(name, b); + } catch (Exception e) { + Exceptions.propagateIfFatal(e); + } + } + return null; + } + + protected WhiteListBundlePredicate createBundleMatchingPredicate() { + String whiteList = System.getProperty(WHITE_LIST_KEY, WHITE_LIST_DEFAULT); + String[] arr = whiteList.split(":"); + String symbolicName = arr[0]; + String version = null; + if (arr.length > 2) { + throw new IllegalStateException("Class loading fallback bundle white list '" + whiteList + "' not in the expected format [:]."); + } else if (arr.length == 2) { + version = arr[1]; + } + return new WhiteListBundlePredicate(symbolicName, version); + } + +} diff --git a/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java b/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java index 65f85d61ca..94a0991a7a 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java @@ -18,9 +18,6 @@ */ package org.apache.brooklyn.util.core.flags; -import groovy.lang.Closure; -import groovy.time.TimeDuration; - import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -56,6 +53,7 @@ import org.apache.brooklyn.util.collections.MutableSet; import org.apache.brooklyn.util.collections.QuorumCheck; import org.apache.brooklyn.util.collections.QuorumCheck.QuorumChecks; +import org.apache.brooklyn.util.core.ClassLoaderUtils; import org.apache.brooklyn.util.core.task.Tasks; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.guava.Maybe; @@ -89,6 +87,9 @@ import com.google.common.primitives.Primitives; import com.google.common.reflect.TypeToken; +import groovy.lang.Closure; +import groovy.time.TimeDuration; + @SuppressWarnings("rawtypes") public class TypeCoercions { @@ -773,7 +774,7 @@ public Date apply(final String input) { @Override public Class apply(final String input) { try { - return Class.forName(input); + return new ClassLoaderUtils(this.getClass()).loadClass(input); } catch (ClassNotFoundException e) { throw Exceptions.propagate(e); } diff --git a/core/src/test/java/org/apache/brooklyn/core/objs/BasicSpecParameterFromClassTest.java b/core/src/test/java/org/apache/brooklyn/core/objs/BasicSpecParameterFromClassTest.java index be91c27b6b..13c3977157 100644 --- a/core/src/test/java/org/apache/brooklyn/core/objs/BasicSpecParameterFromClassTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/objs/BasicSpecParameterFromClassTest.java @@ -23,7 +23,6 @@ import java.util.List; import java.util.Map; -import java.util.Set; import org.apache.brooklyn.api.catalog.CatalogConfig; import org.apache.brooklyn.api.entity.Entity; @@ -35,9 +34,9 @@ import org.apache.brooklyn.core.entity.AbstractEntity; import org.apache.brooklyn.core.entity.BrooklynConfigKeys; import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests; +import org.apache.brooklyn.util.core.ClassLoaderUtils; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import org.testng.collections.Sets; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableMap; @@ -94,7 +93,7 @@ public void testFullDefinition() { @Test public void testDebug() throws ClassNotFoundException { - System.out.println(BasicSpecParameter.fromClass(mgmt, Class.forName("org.apache.brooklyn.entity.stock.BasicApplication"))); + System.out.println(BasicSpecParameter.fromClass(mgmt, new ClassLoaderUtils(this.getClass()).loadClass("org.apache.brooklyn.entity.stock.BasicApplication"))); } @Test diff --git a/karaf/apache-brooklyn/pom.xml b/karaf/apache-brooklyn/pom.xml index 1851e3fd8c..d1d23bef1f 100755 --- a/karaf/apache-brooklyn/pom.xml +++ b/karaf/apache-brooklyn/pom.xml @@ -89,6 +89,15 @@ + + org.apache.rat + apache-rat-plugin + + + **/*.bom + + + org.apache.karaf.tooling karaf-maven-plugin diff --git a/karaf/apache-brooklyn/src/main/resources/etc/default.catalog.bom b/karaf/apache-brooklyn/src/main/resources/etc/default.catalog.bom index 6902a1fa51..8184c6e101 100644 --- a/karaf/apache-brooklyn/src/main/resources/etc/default.catalog.bom +++ b/karaf/apache-brooklyn/src/main/resources/etc/default.catalog.bom @@ -1,54 +1,370 @@ -# 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. +# this catalog bom is an illustration supplying a few useful sample items +# and templates to get started using Brooklyn brooklyn.catalog: - version: "0.10.0-SNAPSHOT" # BROOKLYN_VERSION - items: - - id: server-template - itemType: template - name: "Template: Server" - description: | - Sample YAML to provision a server in a cloud with illustrative VM properties - item: - name: Server (Brooklyn Example) - - # this basic example shows how Brooklyn can provision a single raw VM - # in the cloud or location of your choice - - services: - - type: org.apache.brooklyn.entity.software.base.EmptySoftwareProcess - name: My VM - - # location can be e.g. `softlayer` or `jclouds:openstack-nova:https://9.9.9.9:9999/v2.0/`, - # or `localhost` or `byon:(hosts="10.9.1.1,10.9.1.2,produser2@10.9.2.{10,11,20-29}")` - location: - jclouds:aws-ec2: - # edit these to use your credential (or delete if credentials specified in brooklyn.properties) - identity: - credential: - - region: eu-central-1 - - # we want Ubuntu, with a lot of RAM - osFamily: ubuntu - minRam: 8gb - - # set up this user and password (default is to authorize a public key) - user: sample - password: s4mpl3 + version: "0.10.0-SNAPSHOT" # BROOKLYN_VERSION + items: + - brooklyn.libraries: + - name: org.apache.brooklyn.karaf-init + version: 0.10.0.SNAPSHOT # BROOKLYN_VERSION + include: classpath://catalog-classes.bom + - id: server + itemType: entity + description: | + Provision a server, with customizable provisioning.properties and credentials installed, + but no other special software process or scripts executed. + item: + type: org.apache.brooklyn.entity.software.base.EmptySoftwareProcess + name: Server + + - id: vanilla-bash-server + itemType: entity + description: | + Provision a server, with customizable provisioning.properties and credentials installed, + but no other special software process or scripts executed. + The script should be supplied in "launch.command" as per docs on + org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess. + item: + type: org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess + name: Server with Launch Script (bash) + + - id: load-balancer + itemType: entity + description: | + Create a load balancer which will point at members in the group entity + referred to by the config key "serverPool". + The sensor advertising the port can be configured with the "member.sensor.portNumber" config key, + defaulting to `http.port`; all member entities which have published "service.up" will then be picked up. + item: + type: org.apache.brooklyn.entity.proxy.nginx.NginxController + name: Load Balancer (nginx) + + - id: cluster + itemType: entity + description: | + Create a cluster of entities, resizable, with starting size "initialSize", + and using a spec supplied in the "memberSpec" key. + item: + type: org.apache.brooklyn.entity.group.DynamicCluster + + - id: 1-server-template + itemType: template + name: "Template 1: Server" + description: | + Sample YAML to provision a server in a cloud with illustrative VM properties + item: + name: Server (Brooklyn Example) + + # this basic example shows how Brooklyn can provision a single raw VM + # in the cloud or location of your choice + + services: + - type: server + name: My VM + + # location can be e.g. `softlayer` or `jclouds:openstack-nova:https://9.9.9.9:9999/v2.0/`, + # or `localhost` or `byon:(hosts="10.9.1.1,10.9.1.2,produser2@10.9.2.{10,11,20-29}")` + location: + jclouds:aws-ec2: + # edit these to use your credential (or delete if credentials specified in brooklyn.properties) + identity: + credential: + + region: eu-central-1 + + # we want Ubuntu, with a lot of RAM + osFamily: ubuntu + minRam: 8gb + + # set up this user and password (default is to authorize a public key) + user: sample + password: s4mpl3 + + - id: 2-bash-web-server-template + itemType: template + name: "Template 2: Bash Web Server" + description: | + Sample YAML building on Template 1, + adding bash commands to launch a Python-based web server + on port 8020 + item: + name: Python Web Server (Brooklyn Example) + + # this example builds on the previous one, + # adding some scripts to initialize the VM + + services: + - type: vanilla-bash-server + name: My Bash Web Server VM + brooklyn.config: + install.command: | + # install python if not present + which python || \ + { sudo apt-get update && sudo apt-get install python ; } || \ + { sudo yum update && sudo yum install python ; } || \ + { echo WARNING: cannot install python && exit 1 ; } + + customize.command: | + # create the web page to serve + cat > index.html << EOF + + Hello world. +

+ I am ${ENTITY_INFO}, ${MESSAGE:-a Brooklyn sample}. +

+ Created at: `date` +

+ I am running at ${HOSTNAME}, with on-box IP configuration: +

+            `ifconfig | grep inet`
+            
+ + EOF + + launch.command: | + # launch in background (ensuring no streams open), and record PID to file + nohup python -m SimpleHTTPServer ${PORT:-8020} < /dev/null > output.txt 2>&1 & + echo $! > ${PID_FILE:-pid.txt} + sleep 5 + ps -p `cat ${PID_FILE:-pid.txt}` + if [ $? -ne 0 ] ; then + cat output.txt + echo WARNING: python web server not running + exit 1 + fi + + shell.env: + HOSTNAME: $brooklyn:attributeWhenReady("host.name") + PORT: $brooklyn:config("my.app.port") + ENTITY_INFO: $brooklyn:component("this", "") + MESSAGE: $brooklyn:config("my.message") + + # custom + my.app.port: 8020 + my.message: "good to meet you" + + brooklyn.enrichers: + # publish the URL as a sensor; the GUI will pick this up (main.uri) + - type: org.apache.brooklyn.enricher.stock.Transformer + brooklyn.config: + uniqueTag: url-generator + enricher.sourceSensor: host.subnet.hostname + # use the definition from Attributes class, as it has a RendererHint so GUI makes it a link + enricher.targetSensor: $brooklyn:sensor("org.apache.brooklyn.core.entity.Attributes", "main.uri") + enricher.targetValue: + $brooklyn:formatString: + - "http://%s:%s/" + - $brooklyn:attributeWhenReady("host.subnet.hostname") + - $brooklyn:config("my.app.port") + + location: + jclouds:aws-ec2: + region: eu-central-1 + # edit these (or delete if credentials specified in brooklyn.properties) + identity: + credential: + + - id: 3-bash-web-and-riak-template + itemType: template + name: "Template 3: Bash Web Server and Scaling Riak Cluster" + description: | + Sample YAML building on Template 2, + composing that blueprint with a Riak cluster and injecting the URL + item: + name: Bash Web Server and Riak Cluster (Brooklyn Example) + + # this example *references* the previous one, + # combining it with a stock blueprint for a Riak cluster, + # and shows how a sensor from the latter can be injected + + services: + + # reference template 2, overriding message to point at riak + - type: 2-bash-web-server-template + brooklyn.config: + my.message: $brooklyn:formatString("connected to Riak at %s", + $brooklyn:entity("riak-cluster").attributeWhenReady("main.uri")) + # and clear the location defined there so it is taken from this template + locations: [] + + # use the off-the-shelf Riak cluster + - type: org.apache.brooklyn.entity.nosql.riak.RiakCluster + id: riak-cluster + initialSize: 3 + # and add a policy to scale based on ops per minute + brooklyn.policies: + - type: org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy + brooklyn.config: + metric: riak.node.ops.1m.perNode + # more than 100 ops per second (6k/min) scales out, less than 50 scales back + # up to a max of 8 riak nodes here (can be changed in GUI / REST API afterwards) + metricLowerBound: 3000 + metricUpperBound: 6000 + minPoolSize: 3 + maxPoolSize: 8 + resizeUpStabilizationDelay: 30s + resizeDownStabilizationDelay: 5m + + location: + jclouds:aws-ec2: + region: eu-central-1 + # edit these (or delete if credentials specified in brooklyn.properties) + identity: + credential: + + - id: 4-resilient-bash-web-cluster-template + itemType: template + name: "Template 4: Resilient Load-Balanced Bash Web Cluster with Sensors" + description: | + Sample YAML to provision a cluster of the bash/python web server nodes, + with sensors configured, and a load balancer pointing at them, + and resilience policies for node replacement and scaling + item: + name: Resilient Load-Balanced Bash Web Cluster (Brooklyn Example) + + # this final example shows some of the advanced functionality: + # defining custom sensors, and a cluster with a "spec", + # policies for resilience and scaling based on that sensor, + # and wiring a load balancer in front of the cluster + + # combining this with the riak cluster in the previous example + # is left as a suggested exercise for the user + + services: + + # define a cluster of the web nodes + - type: cluster + name: Cluster of Bash Web Nodes + id: my-web-cluster + brooklyn.config: + initialSize: 1 + memberSpec: + $brooklyn:entitySpec: + # template 2 is used as the spec for items in this cluster + # with a new message overwriting the previous, + # and a lot of sensors defined + type: 2-bash-web-server-template + name: My Bash Web Server VM with Sensors + # and clear the location defined there so it is taken from this template + locations: [] + + brooklyn.config: + my.message: "part of the cluster" + + brooklyn.initializers: + # make a simple request-count sensor, by counting the number of 200 responses in output.txt + - type: org.apache.brooklyn.core.sensor.ssh.SshCommandSensor + brooklyn.config: + name: reqs.count + targetType: int + period: 5s + command: "cat output.txt | grep HTTP | grep 200 | wc | awk '{print $1}'" + # and publish the port as a sensor so the load-balancer can pick it up + - type: org.apache.brooklyn.core.sensor.StaticSensor + brooklyn.config: + name: app.port + targetType: int + static.value: $brooklyn:config("my.app.port") + + brooklyn.enrichers: + # derive reqs.per_sec from reqs.count + - type: org.apache.brooklyn.enricher.stock.YamlTimeWeightedDeltaEnricher + brooklyn.config: + enricher.sourceSensor: reqs.count + enricher.targetSensor: reqs.per_sec + enricher.delta.period: 1s + # and take an average over 30s for reqs.per_sec into reqs.per_sec.windowed_30s + - type: org.apache.brooklyn.enricher.stock.YamlRollingTimeWindowMeanEnricher + brooklyn.config: + enricher.sourceSensor: reqs.per_sec + enricher.targetSensor: reqs.per_sec.windowed_30s + enricher.window.duration: 30s + + # emit failure sensor if a failure connecting to the service is sustained for 30s + - type: org.apache.brooklyn.policy.ha.ServiceFailureDetector + brooklyn.config: + entityFailed.stabilizationDelay: 30s + + brooklyn.policies: + # restart if a failure is detected (with a max of one restart in 2m, sensor will propagate otherwise) + - type: org.apache.brooklyn.policy.ha.ServiceRestarter + brooklyn.config: + failOnRecurringFailuresInThisDuration: 2m + + # back at the cluster, create a total per-sec and some per-node average + brooklyn.enrichers: + - type: org.apache.brooklyn.enricher.stock.Aggregator + brooklyn.config: + enricher.sourceSensor: reqs.per_sec + enricher.targetSensor: reqs.per_sec + transformation: sum + - type: org.apache.brooklyn.enricher.stock.Aggregator + brooklyn.config: + enricher.sourceSensor: reqs.per_sec + enricher.targetSensor: reqs.per_sec.per_node + transformation: average + - type: org.apache.brooklyn.enricher.stock.Aggregator + brooklyn.config: + enricher.sourceSensor: reqs.per_sec.windowed_30s + enricher.targetSensor: reqs.per_sec.windowed_30s.per_node + transformation: average + + brooklyn.policies: + # resilience: if a per-node restart policy fails, + # just throw that node away and create a new one + - type: org.apache.brooklyn.policy.ha.ServiceReplacer + + # and scale based on reqs/sec + - type: org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy + brooklyn.config: + # scale based on reqs/sec (though in a real-world situation, + # reqs.per_sec.windowed_30s.per_node might be a better choice) + metric: reqs.per_sec.per_node + + # really low numbers, so you can trigger a scale-out just by hitting reload a lot + metricUpperBound: 3 + metricLowerBound: 1 + + # sustain 3 reqs/sec for 2s and it will scale out + resizeUpStabilizationDelay: 2s + # only scale down when sustained for 1m + resizeDownStabilizationDelay: 1m + + maxPoolSize: 10 + + # and add a load-balancer pointing at the cluster + - type: load-balancer + id: load-bal + brooklyn.config: + # point this load balancer at the cluster, specifying port to forward to + loadbalancer.serverpool: $brooklyn:entity("my-web-cluster") + member.sensor.portNumber: app.port + # disable sticky sessions to allow easy validation of balancing via browser refresh + nginx.sticky: false + + brooklyn.enrichers: + # publish a few useful info sensors and KPI's to the root of the app + - type: org.apache.brooklyn.enricher.stock.Propagator + brooklyn.config: + uniqueTag: propagate-load-balancer-url + producer: $brooklyn:entity("load-bal") + propagating: + - main.uri + - type: org.apache.brooklyn.enricher.stock.Propagator + brooklyn.config: + uniqueTag: propagate-reqs-per-sec + producer: $brooklyn:entity("my-web-cluster") + propagating: + - reqs.per_sec + - reqs.per_sec.windowed_30s.per_node + + location: + jclouds:aws-ec2: + # edit these (or delete if credentials specified in brooklyn.properties) + identity: + credential: + + region: eu-central-1 + minRam: 2gb diff --git a/karaf/features/src/main/feature/feature.xml b/karaf/features/src/main/feature/feature.xml index b1d7923856..5473151a68 100644 --- a/karaf/features/src/main/feature/feature.xml +++ b/karaf/features/src/main/feature/feature.xml @@ -332,9 +332,24 @@ mvn:com.google.guava/guava/${guava.version} + + + brooklyn-software-base + brooklyn-jmxmp-agent + brooklyn-jmxrmi-agent + brooklyn-software-network + brooklyn-software-cm + brooklyn-software-osgi + brooklyn-software-database + brooklyn-software-webapp + brooklyn-software-messaging + brooklyn-software-nosql + brooklyn-software-monitoring + + brooklyn-core - brooklyn-software-base + brooklyn-software-all brooklyn-locations-jclouds mvn:org.apache.brooklyn/brooklyn-launcher-common/${project.version} mvn:org.apache.brooklyn/brooklyn-karaf-init/${project.version} diff --git a/karaf/init/src/main/resources/catalog-classes.bom b/karaf/init/src/main/resources/catalog-classes.bom new file mode 100644 index 0000000000..82a4b9567e --- /dev/null +++ b/karaf/init/src/main/resources/catalog-classes.bom @@ -0,0 +1,507 @@ +# 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. +# +brooklyn.catalog: + version: "0.10.0-SNAPSHOT" # BROOKLYN_VERSION + items: + - brooklyn.libraries: + - name: org.apache.brooklyn.core + version: "0.10.0.SNAPSHOT" # BROOKLYN_VERSION + itemType: entity + items: + - id: org.apache.brooklyn.entity.group.QuarantineGroup + item: + type: org.apache.brooklyn.entity.group.QuarantineGroup + - id: org.apache.brooklyn.entity.group.BasicGroup + item: + type: org.apache.brooklyn.entity.group.BasicGroup + - id: org.apache.brooklyn.entity.stock.BasicEntity + item: + type: org.apache.brooklyn.entity.stock.BasicEntity + - id: org.apache.brooklyn.entity.stock.DataEntity + item: + type: org.apache.brooklyn.entity.stock.DataEntity + - id: org.apache.brooklyn.entity.group.DynamicGroup + item: + type: org.apache.brooklyn.entity.group.DynamicGroup + - id: org.apache.brooklyn.entity.stock.DelegateEntity + item: + type: org.apache.brooklyn.entity.stock.DelegateEntity + - id: org.apache.brooklyn.entity.group.DynamicRegionsFabric + item: + type: org.apache.brooklyn.entity.group.DynamicRegionsFabric + - id: org.apache.brooklyn.core.server.entity.BrooklynMetrics + item: + type: org.apache.brooklyn.core.server.entity.BrooklynMetrics + - id: org.apache.brooklyn.entity.stock.BasicApplication + item: + type: org.apache.brooklyn.entity.stock.BasicApplication + - id: org.apache.brooklyn.entity.stock.BasicStartable + item: + type: org.apache.brooklyn.entity.stock.BasicStartable + - id: org.apache.brooklyn.entity.group.DynamicCluster + item: + type: org.apache.brooklyn.entity.group.DynamicCluster + - id: org.apache.brooklyn.entity.group.DynamicMultiGroup + item: + type: org.apache.brooklyn.entity.group.DynamicMultiGroup + - id: org.apache.brooklyn.entity.group.DynamicFabric + item: + type: org.apache.brooklyn.entity.group.DynamicFabric + + - brooklyn.libraries: + - name: org.apache.brooklyn.policy + version: "0.10.0.SNAPSHOT" # BROOKLYN_VERSION + items: + - id: org.apache.brooklyn.policy.ha.ConnectionFailureDetector + itemType: policy + item: + type: org.apache.brooklyn.policy.ha.ConnectionFailureDetector + name: Connection Failure Detector + description: HA policy for monitoring a host:port, + - id: org.apache.brooklyn.policy.ha.ServiceRestarter + itemType: policy + item: + type: org.apache.brooklyn.policy.ha.ServiceRestarter + name: Service Restarter + description: HA policy for restarting a service automatically, + - id: org.apache.brooklyn.policy.ha.SshMachineFailureDetector + itemType: policy + item: + type: org.apache.brooklyn.policy.ha.SshMachineFailureDetector + name: Ssh Connectivity Failure Detector + description: HA policy for monitoring an SshMachine, +# removed from catalog because it cannot currently be configured via catalog mechanisms +# - id: org.apache.brooklyn.policy.followthesun.FollowTheSunPool +# item: +# type: org.apache.brooklyn.policy.followthesun.FollowTheSunPool + - id: org.apache.brooklyn.policy.loadbalancing.BalanceableWorkerPool + itemType: entity + item: + type: org.apache.brooklyn.policy.loadbalancing.BalanceableWorkerPool + - id: org.apache.brooklyn.policy.ha.ServiceReplacer + itemType: policy + item: + type: org.apache.brooklyn.policy.ha.ServiceReplacer + name: Service Replacer + description: HA policy for replacing a failed member of a group + - id: org.apache.brooklyn.policy.loadbalancing.ItemsInContainersGroup + itemType: entity + item: + type: org.apache.brooklyn.policy.loadbalancing.ItemsInContainersGroup + - id: org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy + itemType: policy + item: + type: org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy + name: Auto-scaler + description: Policy that is attached to a Resizable entity and dynamically + + - brooklyn.libraries: + - name: org.apache.brooklyn.software-base + version: "0.10.0.SNAPSHOT" # BROOKLYN_VERSION + itemType: entity + items: + - id: org.apache.brooklyn.entity.machine.MachineEntity + item: + type: org.apache.brooklyn.entity.machine.MachineEntity + name: Machine Entity + description: Represents a machine, providing metrics about it (e.g. obtained from ssh) + - id: org.apache.brooklyn.entity.software.base.SameServerEntity + item: + type: org.apache.brooklyn.entity.software.base.SameServerEntity + - id: org.apache.brooklyn.entity.chef.ChefEntity + item: + type: org.apache.brooklyn.entity.chef.ChefEntity + - id: org.apache.brooklyn.entity.brooklynnode.BrooklynEntityMirror + item: + type: org.apache.brooklyn.entity.brooklynnode.BrooklynEntityMirror + name: Brooklyn Entity Mirror + description: Provides an entity which can sit in one brooklyn + - id: org.apache.brooklyn.entity.software.base.EmptySoftwareProcess + item: + type: org.apache.brooklyn.entity.software.base.EmptySoftwareProcess + - id: org.apache.brooklyn.entity.software.base.EmptyWindowsProcess + item: + type: org.apache.brooklyn.entity.software.base.EmptyWindowsProcess + - id: org.apache.brooklyn.entity.software.base.VanillaWindowsProcess + item: + type: org.apache.brooklyn.entity.software.base.VanillaWindowsProcess + name: Vanilla Windows Process + description: A basic Windows entity configured with scripts, e.g. for launch, check-running and stop + - id: org.apache.brooklyn.entity.java.VanillaJavaApp + item: + type: org.apache.brooklyn.entity.java.VanillaJavaApp + - id: org.apache.brooklyn.entity.brooklynnode.BrooklynNode + item: + type: org.apache.brooklyn.entity.brooklynnode.BrooklynNode + name: Brooklyn Node + description: Deploys a Brooklyn management server + - id: org.apache.brooklyn.entity.brooklynnode.BrooklynCluster + item: + type: org.apache.brooklyn.entity.brooklynnode.BrooklynCluster + - id: org.apache.brooklyn.entity.brooklynnode.LocalBrooklynNode + item: + type: org.apache.brooklyn.entity.brooklynnode.LocalBrooklynNode + - id: org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess + item: + type: org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess + name: Vanilla Software Process + description: A software process configured with scripts, e.g. for launch, check-running and stop + - id: org.apache.brooklyn.entity.machine.pool.ServerPool + item: + type: org.apache.brooklyn.entity.machine.pool.ServerPool + name: Server Pool + description: Creates a pre-allocated server pool, which other applications can deploy to + + - brooklyn.libraries: + - name: org.apache.brooklyn.software-webapp + version: "0.10.0.SNAPSHOT" # BROOKLYN_VERSION + itemType: entity + items: + - id: org.apache.brooklyn.entity.webapp.nodejs.NodeJsWebAppService + item: + type: org.apache.brooklyn.entity.webapp.nodejs.NodeJsWebAppService + name: Node.JS Application + - id: org.apache.brooklyn.entity.webapp.jboss.JBoss7Server + item: + type: org.apache.brooklyn.entity.webapp.jboss.JBoss7Server + name: JBoss Application Server 7 + description: AS7 - an open source Java application server from JBoss + - id: org.apache.brooklyn.entity.proxy.nginx.UrlMapping + item: + type: org.apache.brooklyn.entity.proxy.nginx.UrlMapping + - id: org.apache.brooklyn.entity.webapp.DynamicWebAppFabric + item: + type: org.apache.brooklyn.entity.webapp.DynamicWebAppFabric + - id: org.apache.brooklyn.entity.proxy.nginx.NginxController + item: + type: org.apache.brooklyn.entity.proxy.nginx.NginxController + name: Nginx Server + description: A single Nginx server. Provides HTTP and reverse proxy services + - id: org.apache.brooklyn.entity.webapp.jboss.JBoss6Server + item: + type: org.apache.brooklyn.entity.webapp.jboss.JBoss6Server + name: JBoss Application Server 6 + description: AS6 - an open source Java application server from JBoss + - id: org.apache.brooklyn.entity.webapp.tomcat.Tomcat8Server + item: + type: org.apache.brooklyn.entity.webapp.tomcat.Tomcat8Server + name: Tomcat Server + - id: org.apache.brooklyn.entity.proxy.LoadBalancerCluster + item: + type: org.apache.brooklyn.entity.proxy.LoadBalancerCluster + - id: org.apache.brooklyn.entity.webapp.jetty.Jetty6Server + item: + type: org.apache.brooklyn.entity.webapp.jetty.Jetty6Server + name: Jetty6 Server + description: Old version (v6 @ Mortbay) of the popular Jetty webapp container + - id: org.apache.brooklyn.entity.webapp.DynamicWebAppCluster + item: + type: org.apache.brooklyn.entity.webapp.DynamicWebAppCluster + name: Dynamic Web-app Cluster + description: A cluster of web-apps, which can be dynamically re-sized; this does not include a load-balancer + - id: org.apache.brooklyn.entity.webapp.tomcat.TomcatServer + item: + type: org.apache.brooklyn.entity.webapp.tomcat.TomcatServer + name: Tomcat Server + - id: org.apache.brooklyn.entity.dns.geoscaling.GeoscalingDnsService + item: + type: org.apache.brooklyn.entity.dns.geoscaling.GeoscalingDnsService + - id: org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster + item: + type: org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster + name: Controlled Dynamic Web-app Cluster + description: A cluster of load-balanced web-apps, which can be dynamically re-sized + + - brooklyn.libraries: + - name: org.apache.brooklyn.software-osgi + version: "0.10.0.SNAPSHOT" # BROOKLYN_VERSION + itemType: entity + items: + - id: org.apache.brooklyn.entity.osgi.karaf.KarafContainer + item: + type: org.apache.brooklyn.entity.osgi.karaf.KarafContainer + name: Karaf + description: Apache Karaf is a small OSGi based runtime which provides a lightweight container onto which various components and applications can be deployed. + + - brooklyn.libraries: + - name: org.apache.brooklyn.software-nosql + version: "0.10.0.SNAPSHOT" # BROOKLYN_VERSION + itemType: entity + items: + - id: org.apache.brooklyn.entity.nosql.redis.RedisStore + item: + type: org.apache.brooklyn.entity.nosql.redis.RedisStore + name: Redis Server + description: Redis is an open-source, networked, in-memory, key-value data store with optional durability + - id: org.apache.brooklyn.entity.nosql.mongodb.sharding.MongoDBRouterCluster + item: + type: org.apache.brooklyn.entity.nosql.mongodb.sharding.MongoDBRouterCluster + - id: org.apache.brooklyn.entity.nosql.cassandra.CassandraDatacenter + item: + type: org.apache.brooklyn.entity.nosql.cassandra.CassandraDatacenter + name: Apache Cassandra Datacenter Cluster + description: Cassandra is a highly scalable, eventually + - id: org.apache.brooklyn.entity.nosql.solr.SolrServer + item: + type: org.apache.brooklyn.entity.nosql.solr.SolrServer + name: Apache Solr Node + description: Solr is the popular, blazing fast open source enterprise search + - id: org.apache.brooklyn.entity.nosql.couchdb.CouchDBNode + item: + type: org.apache.brooklyn.entity.nosql.couchdb.CouchDBNode + name: CouchDB Node + - id: org.apache.brooklyn.entity.nosql.redis.RedisShard + item: + type: org.apache.brooklyn.entity.nosql.redis.RedisShard + - id: org.apache.brooklyn.entity.nosql.redis.RedisCluster + item: + type: org.apache.brooklyn.entity.nosql.redis.RedisCluster + name: Redis Cluster + description: Redis is an open-source, networked, in-memory, key-value data store with optional durability + - id: org.apache.brooklyn.entity.nosql.hazelcast.HazelcastCluster + item: + type: org.apache.brooklyn.entity.nosql.hazelcast.HazelcastCluster + name: Hazelcast Cluster + description: Hazelcast is a clustering and highly scalable data distribution platform for Java. + - id: org.apache.brooklyn.entity.nosql.couchdb.CouchDBCluster + item: + type: org.apache.brooklyn.entity.nosql.couchdb.CouchDBCluster + - id: org.apache.brooklyn.entity.nosql.couchbase.CouchbaseNode + item: + type: org.apache.brooklyn.entity.nosql.couchbase.CouchbaseNode + name: CouchBase Node + description: Couchbase Server is an open source, distributed (shared-nothing architecture) + - id: org.apache.brooklyn.entity.nosql.mongodb.sharding.MongoDBShardedDeployment + item: + type: org.apache.brooklyn.entity.nosql.mongodb.sharding.MongoDBShardedDeployment + name: MongoDB Sharded Deployment + - id: org.apache.brooklyn.entity.nosql.cassandra.CassandraNode + item: + type: org.apache.brooklyn.entity.nosql.cassandra.CassandraNode + name: Apache Cassandra Node + description: Cassandra is a highly scalable, eventually + - id: org.apache.brooklyn.entity.nosql.riak.RiakNode + item: + type: org.apache.brooklyn.entity.nosql.riak.RiakNode + name: Riak Node + description: Riak is a distributed NoSQL key-value data store that offers + - id: org.apache.brooklyn.entity.nosql.mongodb.sharding.MongoDBConfigServerCluster + item: + type: org.apache.brooklyn.entity.nosql.mongodb.sharding.MongoDBConfigServerCluster + - id: org.apache.brooklyn.entity.nosql.mongodb.MongoDBServer + item: + type: org.apache.brooklyn.entity.nosql.mongodb.MongoDBServer + name: MongoDB Server + - id: org.apache.brooklyn.entity.nosql.mongodb.sharding.MongoDBRouter + item: + type: org.apache.brooklyn.entity.nosql.mongodb.sharding.MongoDBRouter + name: MongoDB Router + - id: org.apache.brooklyn.entity.nosql.mongodb.MongoDBReplicaSet + item: + type: org.apache.brooklyn.entity.nosql.mongodb.MongoDBReplicaSet + - id: org.apache.brooklyn.entity.nosql.mongodb.sharding.MongoDBShardCluster + item: + type: org.apache.brooklyn.entity.nosql.mongodb.sharding.MongoDBShardCluster + - id: org.apache.brooklyn.entity.nosql.mongodb.MongoDBClient + item: + type: org.apache.brooklyn.entity.nosql.mongodb.MongoDBClient + - id: org.apache.brooklyn.entity.nosql.elasticsearch.ElasticSearchNode + item: + type: org.apache.brooklyn.entity.nosql.elasticsearch.ElasticSearchNode + name: Elastic Search Node + description: Elasticsearch is an open-source search server based on Lucene. + - id: org.apache.brooklyn.entity.nosql.cassandra.CassandraFabric + item: + type: org.apache.brooklyn.entity.nosql.cassandra.CassandraFabric + name: Apache Cassandra Database Fabric + description: Cassandra is a highly scalable, eventually + - id: org.apache.brooklyn.entity.nosql.elasticsearch.ElasticSearchCluster + item: + type: org.apache.brooklyn.entity.nosql.elasticsearch.ElasticSearchCluster + name: Elastic Search Cluster + description: Elasticsearch is an open-source search server based on Lucene. + - id: org.apache.brooklyn.entity.nosql.cassandra.CassandraCluster + item: + type: org.apache.brooklyn.entity.nosql.cassandra.CassandraCluster + - id: org.apache.brooklyn.entity.nosql.redis.RedisSlave + item: + type: org.apache.brooklyn.entity.nosql.redis.RedisSlave + - id: org.apache.brooklyn.entity.nosql.mongodb.sharding.MongoDBConfigServer + item: + type: org.apache.brooklyn.entity.nosql.mongodb.sharding.MongoDBConfigServer + - id: org.apache.brooklyn.entity.nosql.couchbase.CouchbaseCluster + item: + type: org.apache.brooklyn.entity.nosql.couchbase.CouchbaseCluster + name: CouchBase Cluster + description: Couchbase is an open source, distributed (shared-nothing architecture) + - id: org.apache.brooklyn.entity.nosql.couchbase.CouchbaseSyncGateway + item: + type: org.apache.brooklyn.entity.nosql.couchbase.CouchbaseSyncGateway + - id: org.apache.brooklyn.entity.nosql.hazelcast.HazelcastNode + item: + type: org.apache.brooklyn.entity.nosql.hazelcast.HazelcastNode + name: Hazelcast Node + description: Hazelcast is a clustering and highly scalable data distribution platform for Java. + - id: org.apache.brooklyn.entity.nosql.riak.RiakCluster + item: + type: org.apache.brooklyn.entity.nosql.riak.RiakCluster + name: Riak Cluster + description: Riak is a distributed NoSQL key-value data store that offers + - id: org.apache.brooklyn.entity.nosql.mongodb.sharding.CoLocatedMongoDBRouter + item: + type: org.apache.brooklyn.entity.nosql.mongodb.sharding.CoLocatedMongoDBRouter + + - brooklyn.libraries: + - name: org.apache.brooklyn.software-network + version: "0.10.0.SNAPSHOT" # BROOKLYN_VERSION + itemType: entity + items: + - id: org.apache.brooklyn.entity.network.bind.BindDnsServer + description: BIND is an Internet Domain Name Server. + item: + type: org.apache.brooklyn.entity.network.bind.BindDnsServer + name: BIND + + - brooklyn.libraries: + - name: org.apache.brooklyn.software-monitoring + version: "0.10.0.SNAPSHOT" # BROOKLYN_VERSION + itemType: entity + items: + - id: org.apache.brooklyn.entity.monitoring.monit.MonitNode + item: + type: org.apache.brooklyn.entity.monitoring.monit.MonitNode + name: Monit Node + description: Monit is a free open source utility for managing and monitoring, processes, programs, files, directories and filesystems on a UNIX system + + - brooklyn.libraries: + - name: org.apache.brooklyn.software-messaging + version: "0.10.0.SNAPSHOT" # BROOKLYN_VERSION + itemType: entity + items: + - id: org.apache.brooklyn.entity.messaging.activemq.ActiveMQBroker + item: + type: org.apache.brooklyn.entity.messaging.activemq.ActiveMQBroker + name: ActiveMQ Broker + description: ActiveMQ is an open source message broker which fully implements the Java Message Service 1.1 (JMS) + - id: org.apache.brooklyn.entity.messaging.qpid.QpidBroker + item: + type: org.apache.brooklyn.entity.messaging.qpid.QpidBroker + name: Qpid Broker + description: Apache Qpid is an open-source messaging system, implementing the Advanced Message Queuing Protocol (AMQP) + - id: org.apache.brooklyn.entity.messaging.storm.Storm + item: + type: org.apache.brooklyn.entity.messaging.storm.Storm + name: Storm Node + description: Apache Storm is a distributed realtime computation system. + - id: org.apache.brooklyn.entity.messaging.kafka.KafkaCluster + item: + type: org.apache.brooklyn.entity.messaging.kafka.KafkaCluster + name: Kafka + description: Apache Kafka is a distributed publish-subscribe messaging system + - id: org.apache.brooklyn.entity.messaging.activemq.ActiveMQQueue + item: + type: org.apache.brooklyn.entity.messaging.activemq.ActiveMQQueue + - id: org.apache.brooklyn.entity.zookeeper.ZooKeeperEnsemble + item: + type: org.apache.brooklyn.entity.zookeeper.ZooKeeperEnsemble + name: ZooKeeper ensemble + description: A cluster of ZooKeeper servers. + - id: org.apache.brooklyn.entity.messaging.kafka.KafkaZooKeeper + item: + type: org.apache.brooklyn.entity.messaging.kafka.KafkaZooKeeper + - id: org.apache.brooklyn.entity.messaging.activemq.ActiveMQTopic + item: + type: org.apache.brooklyn.entity.messaging.activemq.ActiveMQTopic + - id: org.apache.brooklyn.entity.messaging.qpid.QpidQueue + item: + type: org.apache.brooklyn.entity.messaging.qpid.QpidQueue + - id: org.apache.brooklyn.entity.zookeeper.ZooKeeperNode + item: + type: org.apache.brooklyn.entity.zookeeper.ZooKeeperNode + name: ZooKeeper Node + description: Apache ZooKeeper is a server which enables + - id: org.apache.brooklyn.entity.messaging.rabbit.RabbitBroker + item: + type: org.apache.brooklyn.entity.messaging.rabbit.RabbitBroker + name: RabbitMQ Broker + description: RabbitMQ is an open source message broker software (i.e. message-oriented middleware) that implements the Advanced Message Queuing Protocol (AMQP) standard + - id: org.apache.brooklyn.entity.messaging.kafka.KafkaBroker + item: + type: org.apache.brooklyn.entity.messaging.kafka.KafkaBroker + - id: org.apache.brooklyn.entity.messaging.qpid.QpidTopic + item: + type: org.apache.brooklyn.entity.messaging.qpid.QpidTopic + - id: org.apache.brooklyn.entity.messaging.storm.StormDeployment + item: + type: org.apache.brooklyn.entity.messaging.storm.StormDeployment + name: Storm Deployment + description: A Storm cluster. Apache Storm is a distributed realtime computation system. + + - brooklyn.libraries: + - name: org.apache.brooklyn.software-database + version: "0.10.0.SNAPSHOT" # BROOKLYN_VERSION + itemType: entity + items: + - id: org.apache.brooklyn.entity.database.crate.CrateNode + item: + type: org.apache.brooklyn.entity.database.crate.CrateNode + - id: org.apache.brooklyn.entity.database.mysql.MySqlNode + item: + type: org.apache.brooklyn.entity.database.mysql.MySqlNode + name: MySql Node + description: MySql is an open source relational database management system (RDBMS) + - id: org.apache.brooklyn.entity.database.mysql.MySqlCluster + item: + type: org.apache.brooklyn.entity.database.mysql.MySqlCluster + name: MySql Master-Slave cluster + description: Sets up a cluster of MySQL nodes using master-slave relation and binary logging + - id: org.apache.brooklyn.entity.database.postgresql.PostgreSqlNode + item: + type: org.apache.brooklyn.entity.database.postgresql.PostgreSqlNode + name: PostgreSQL Node + description: PostgreSQL is an object-relational database management system (ORDBMS) + - id: org.apache.brooklyn.entity.database.rubyrep.RubyRepNode + item: + type: org.apache.brooklyn.entity.database.rubyrep.RubyRepNode + - id: org.apache.brooklyn.entity.database.mariadb.MariaDbNode + item: + type: org.apache.brooklyn.entity.database.mariadb.MariaDbNode + name: MariaDB Node + description: MariaDB is an open source relational database management system (RDBMS) + + - brooklyn.libraries: + - name: org.apache.brooklyn.software-cm-salt + version: "0.10.0.SNAPSHOT" # BROOKLYN_VERSION + itemType: entity + items: + - id: org.apache.brooklyn.entity.cm.salt.SaltEntity + item: + type: org.apache.brooklyn.entity.cm.salt.SaltEntity + name: SaltEntity + description: Software managed by Salt CM + + - brooklyn.libraries: + - name: org.apache.brooklyn.software-cm-ansible + version: "0.10.0.SNAPSHOT" # BROOKLYN_VERSION + itemType: entity + items: + - id: org.apache.brooklyn.entity.cm.ansible.AnsibleEntity + item: + type: org.apache.brooklyn.entity.cm.ansible.AnsibleEntity + name: AnsibleEntity + description: Software managed by Ansible CM diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java index 2696440c72..0b8d2c25c3 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java @@ -21,7 +21,9 @@ import java.util.List; import java.util.Map; +import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.policy.Policy; @@ -35,6 +37,7 @@ import org.apache.brooklyn.rest.transform.ApplicationTransformer; import org.apache.brooklyn.rest.transform.PolicyTransformer; import org.apache.brooklyn.rest.util.WebResourceUtils; +import org.apache.brooklyn.util.core.ClassLoaderUtils; import org.apache.brooklyn.util.exceptions.Exceptions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,8 +45,6 @@ import com.google.common.base.Function; import com.google.common.collect.FluentIterable; import com.google.common.collect.Maps; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.UriInfo; @HaHotStateRequired public class PolicyResource extends AbstractBrooklynRestResource implements PolicyApi { @@ -86,7 +87,7 @@ public PolicySummary addPolicy( String application,String entityToken, String po Entity entity = brooklyn().getEntity(application, entityToken); Class policyType; try { - policyType = (Class) Class.forName(policyTypeName); + policyType = (Class) new ClassLoaderUtils(this, mgmt()).loadClass(policyTypeName); } catch (ClassNotFoundException e) { throw WebResourceUtils.badRequest("No policy with type %s found", policyTypeName); } catch (ClassCastException e) { diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/security/provider/DelegatingSecurityProvider.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/security/provider/DelegatingSecurityProvider.java index ca7fdf128c..b374189dc3 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/security/provider/DelegatingSecurityProvider.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/security/provider/DelegatingSecurityProvider.java @@ -24,13 +24,14 @@ import javax.servlet.http.HttpSession; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.config.StringConfigMap; import org.apache.brooklyn.core.internal.BrooklynProperties; import org.apache.brooklyn.rest.BrooklynWebConfig; +import org.apache.brooklyn.util.core.ClassLoaderUtils; import org.apache.brooklyn.util.text.Strings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class DelegatingSecurityProvider implements SecurityProvider { @@ -85,15 +86,16 @@ private synchronized SecurityProvider loadDelegate() { log.info("REST using security provider " + className); try { + ClassLoaderUtils clu = new ClassLoaderUtils(this, mgmt); Class clazz; try { - clazz = (Class) Class.forName(className); + clazz = (Class) clu.loadClass(className); } catch (Exception e) { String oldPackage = "brooklyn.web.console.security."; if (className.startsWith(oldPackage)) { className = Strings.removeFromStart(className, oldPackage); className = DelegatingSecurityProvider.class.getPackage().getName() + "." + className; - clazz = (Class) Class.forName(className); + clazz = (Class) clu.loadClass(className); log.warn("Deprecated package " + oldPackage + " detected; please update security provider to point to " + className); } else throw e; } diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogEntitySpecResolver.java b/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogEntitySpecResolver.java index 7d48643f70..e5a8b92d0f 100644 --- a/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogEntitySpecResolver.java +++ b/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogEntitySpecResolver.java @@ -24,12 +24,14 @@ import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext; +import org.apache.brooklyn.core.BrooklynVersion; import org.apache.brooklyn.core.resolve.entity.AbstractEntitySpecResolver; import org.apache.brooklyn.entity.brooklynnode.BrooklynNode; import org.apache.brooklyn.entity.group.DynamicCluster; import org.apache.brooklyn.entity.group.DynamicRegionsFabric; import org.apache.brooklyn.entity.java.VanillaJavaApp; import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess; +import org.apache.brooklyn.util.core.ClassLoaderUtils; import com.google.common.base.CaseFormat; import com.google.common.base.Converter; @@ -38,14 +40,17 @@ public class HardcodedCatalogEntitySpecResolver extends AbstractEntitySpecResolver { private static final String RESOLVER_NAME = "catalog"; - private static final Map CATALOG_TYPES = ImmutableMap.builder() - .put("cluster", DynamicCluster.class.getName()) - .put("fabric", DynamicRegionsFabric.class.getName()) - .put("vanilla", VanillaSoftwareProcess.class.getName()) - .put("software-process", VanillaSoftwareProcess.class.getName()) - .put("java-app", VanillaJavaApp.class.getName()) - .put("brooklyn-node", BrooklynNode.class.getName()) - .put("web-app-cluster","org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster") + private static final Map> CATALOG_CLASS_TYPES = ImmutableMap.>builder() + .put("cluster", DynamicCluster.class) + .put("fabric", DynamicRegionsFabric.class) + .put("vanilla", VanillaSoftwareProcess.class) + .put("software-process", VanillaSoftwareProcess.class) + .put("java-app", VanillaJavaApp.class) + .put("brooklyn-node", BrooklynNode.class) + .build(); + + private static final Map CATALOG_STRING_TYPES = ImmutableMap.builder() + .put("web-app-cluster","org.apache.brooklyn.software-webapp:" + BrooklynVersion.get() + ":org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster") .build(); // Allow catalog-type or CatalogType as service type string @@ -58,39 +63,47 @@ public HardcodedCatalogEntitySpecResolver() { @Override protected boolean canResolve(String type, BrooklynClassLoadingContext loader) { String localType = getLocalType(type); - String specType = getImplementation(localType); - return specType != null; + return getImplementation(CATALOG_CLASS_TYPES, localType) != null || + getImplementation(CATALOG_STRING_TYPES, localType) != null; } @Override public EntitySpec resolve(String type, BrooklynClassLoadingContext loader, Set encounteredTypes) { String localType = getLocalType(type); - String specType = getImplementation(localType); - if (specType != null) { - return buildSpec(specType); - } else { - return null; + Class specClassType = getImplementation(CATALOG_CLASS_TYPES, localType); + if (specClassType != null) { + return buildSpec(specClassType); } + String specStringType = getImplementation(CATALOG_STRING_TYPES, localType); + if (specStringType != null) { + return buildSpec(specStringType); + } + return null; } - private String getImplementation(String type) { - String specType = CATALOG_TYPES.get(type); + private T getImplementation(Map types, String type) { + T specType = types.get(type); if (specType != null) { return specType; } else { - return CATALOG_TYPES.get(FMT.convert(type)); + return types.get(FMT.convert(type)); } } - private EntitySpec buildSpec(String specType) { + private EntitySpec buildSpec(String specTypName) { // TODO is this hardcoded list deprecated? If so log a warning. try { - @SuppressWarnings("unchecked") - Class specClass = (Class)mgmt.getCatalogClassLoader().loadClass(specType); - return EntitySpec.create(specClass); + Class specType = new ClassLoaderUtils(this.getClass()).loadClass(specTypName); + return buildSpec(specType); } catch (ClassNotFoundException e) { - throw new IllegalStateException("Unable to load hardcoded catalog type " + specType, e); + throw new IllegalStateException("Unable to load hardcoded catalog type " + specTypName, e); } } + protected EntitySpec buildSpec(Class specType) { + @SuppressWarnings("unchecked") + Class specClass = (Class)specType; + return EntitySpec.create(specClass); + } + } diff --git a/software/winrm/src/main/java/org/apache/brooklyn/location/winrm/WinRmMachineLocation.java b/software/winrm/src/main/java/org/apache/brooklyn/location/winrm/WinRmMachineLocation.java index 7a5b638c15..8d537acd0c 100644 --- a/software/winrm/src/main/java/org/apache/brooklyn/location/winrm/WinRmMachineLocation.java +++ b/software/winrm/src/main/java/org/apache/brooklyn/location/winrm/WinRmMachineLocation.java @@ -18,6 +18,9 @@ */ package org.apache.brooklyn.location.winrm; +import static org.apache.brooklyn.core.config.ConfigKeys.newConfigKeyWithPrefix; +import static org.apache.brooklyn.core.config.ConfigKeys.newStringConfigKey; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -29,7 +32,6 @@ import javax.annotation.Nullable; -import com.google.common.annotations.Beta; import org.apache.brooklyn.api.location.MachineDetails; import org.apache.brooklyn.api.location.MachineLocation; import org.apache.brooklyn.api.location.OsDetails; @@ -42,6 +44,7 @@ import org.apache.brooklyn.core.location.AbstractLocation; import org.apache.brooklyn.core.location.access.PortForwardManager; import org.apache.brooklyn.core.location.access.PortForwardManagerLocationResolver; +import org.apache.brooklyn.util.core.ClassLoaderUtils; import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.core.internal.ssh.SshTool; import org.apache.brooklyn.util.core.internal.winrm.WinRmTool; @@ -55,6 +58,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.annotations.Beta; import com.google.common.base.Charsets; import com.google.common.base.Function; import com.google.common.base.Joiner; @@ -66,9 +70,6 @@ import com.google.common.net.HostAndPort; import com.google.common.reflect.TypeToken; -import static org.apache.brooklyn.core.config.ConfigKeys.newConfigKeyWithPrefix; -import static org.apache.brooklyn.core.config.ConfigKeys.newStringConfigKey; - public class WinRmMachineLocation extends AbstractLocation implements MachineLocation { private static final Logger LOG = LoggerFactory.getLogger(WinRmMachineLocation.class); @@ -353,7 +354,7 @@ protected WinRmTool newWinRmTool(Map props) { // look up tool class String toolClass = args.get(WINRM_TOOL_CLASS); if (toolClass == null) toolClass = Winrm4jTool.class.getName(); - WinRmTool tool = (WinRmTool) Class.forName(toolClass).getConstructor(Map.class).newInstance(args.getAllConfig()); + WinRmTool tool = (WinRmTool) new ClassLoaderUtils(this, getManagementContext()).loadClass(toolClass).getConstructor(Map.class).newInstance(args.getAllConfig()); if (LOG.isTraceEnabled()) LOG.trace("using ssh-tool {} (of type {}); props ", tool, toolClass);