Skip to content
Permalink
Browse files
Merge apache-brooklyn/master as at commit 84156e3
  • Loading branch information
richardcloudsoft committed Feb 26, 2021
2 parents 06230ce + 84156e3 commit 28a107aab570431ac4bb62f6d0bcd44c2f4b90f3
Show file tree
Hide file tree
Showing 11 changed files with 277 additions and 46 deletions.
@@ -62,16 +62,18 @@ These fields can be supplied as `key: value` entries
where either the `<catalog-metadata>` or `<additional-catalog-metadata>` placeholders are in the examples above,
with the latter overriding the former unless otherwise specified below.

The following metadata is *required* for all items:

###### Required Metadata
###### Definitional Metadata

**`id`**
A human-friendly unique identifier for how this catalog item will be referenced from blueprints.
This is required.

**`version`**
Multiple versions of a blueprint can be installed and used simultaneously;
this field disambiguates between blueprints of the same `id`.
This can be omitted where the `version` is defined at an ancestor node, and in
practice it usually is, so that all items in a bundle take the same version.
Note that this is typically *not* the version of the software being installed,
but rather the version of the blueprint. For more information on versioning, see [Versioning]({{book.path.docs}}/blueprints/catalog/versioning.md).
(Also note YAML treats numbers differently to Strings. Explicit quotes are recommended, to avoid
@@ -87,9 +89,22 @@ services:
~~~

**`itemType`**
The type of the item being defined. The supported item types are: `entity`, `template`, `policy`, and `location`.

In addition to `id`, `version`, and `itemType`, exactly **one** of `item` and `items` is also required:
The type of the item being defined. The supported common spec item types are: `application`, `entity`, `policy`, and `location`.
Two additional item types are `template`, which is a not-necessarily-deployable application for use as a starting
point in composer (the YAML can even be invalid); and `bean` which defines types for use in config, initializers,
and elsewhere. If the type can be inferred from the definition this can be omitted.

**`format`**
The schema format used for the item definitions.
This determines the transformer to use; if omitted at a level it is inherited from ancestors,
and if `auto` (or omitted on ancestors) then the format is autodetected.
Transformer formats that ship with Apache Brooklyn include:
`brooklyn-camp` (the primary format used throughout, where a key `type: <parent-spec-type>` identifies the parent spec
for entities, policies, etc, and config under `brooklyn.config`)
and `bean-with-type` (where a key `type: <parent-type>` is used to define a bean and fields as siblings).
Extensions may provide additional formats.

Exactly **one** of `item` and `items` is also required:

**`item`**
The YAML for an entity, or policy, or location specification
@@ -226,7 +226,9 @@ before the policy restarts it.

For an even more interesting way to test it, look at the blueprint defining
[a netcat server and client](example_yaml/vanilla-bash-netcat-w-client.yaml).
This uses `brooklyn.initializers` to define an effector to `sayHiNetcat` on the `Simple Pinger` client,
This uses `brooklyn.initializers`
(see in the [YAML reference](yaml-reference.md))
to define an effector to `sayHiNetcat` on the `Simple Pinger` client,
using `env` variables to inject the `netcat-server` location and
`parameters` to pass in per-effector data:

@@ -81,6 +81,18 @@ An example usage of this toy example, once added to the catalog, is shown below:
!CODEFILE "example_yaml/entity-constraint-app.yaml"


### Complex Types in Configuration

Often configuration objects will be "primitives" -- `string`, `integer`, `boolean`, `char`.
But they can be more sophisticated:

* `list` and `map` are supported, and can be declared with generics, e.g. `type: map<string,boolean>`
* a `value-wrapper` that can be a value or can be a Brooklyn DSL expression
* a `port` which allows specifying a range or set of values, eg `8080+` or `80,443,[8000-8999]`
* a `duration` which recognises textual input, eg `2 minutes`
* any type registered with the catalog as a `bean` using `bean-with-type`
(see [Catalog]({{book.path.docs}}/blueprints/catalog/index.md))

### Inheriting Configuration

Configuration can be inherited from a super-type, and from a parent entity in the runtime
File renamed without changes.
@@ -3,26 +3,6 @@ title: Policies
layout: website-normal
---

Policies perform the active management enabled by Brooklyn.
They can subscribe to entity sensors and be triggered by them (or they can run periodically,
or be triggered by external systems).

Policies can add subscriptions to sensors on any entity. Normally a policy will subscribe to sensors on
either its associated entity, that entity's children and/or to the members of a "group" entity.

Common uses of a policy include the following:

* perform calculations,
* look up other values,
* invoke effectors (management policies) or,
* cause the entity associated with the policy to emit sensor values (enricher policies).

Entities can have zero or more `Policy` instances attached to them.


Off-the-Shelf Policies
----------------------

Policies are highly reusable as their inputs, thresholds and targets are customizable.
Config key details for each policy can be found in the Catalog in the Brooklyn UI.

@@ -0,0 +1,21 @@
---
title: Policies
partial-summary-depth: 1
---

Policies perform the active management enabled by Brooklyn.
They can subscribe to entity sensors and be triggered by them (or they can run periodically,
or be triggered by external systems).

Policies can add subscriptions to sensors on any entity. Normally a policy will subscribe to sensors on
either its associated entity, that entity's children and/or to the members of a "group" entity.

Common uses of a policy include the following:

* perform calculations,
* look up other values,
* invoke effectors (management policies) or,
* cause the entity associated with the policy to emit sensor values (enricher policies).

Entities can have zero or more `Policy` instances attached to them.

@@ -0,0 +1,76 @@
---
title: Writing a Policy
---

### Your First Policy

Policies perform the active management enabled by Brooklyn.
Each policy instance is associated with an entity,
and at runtime it will typically subscribe to sensors on that entity or children,
performing some computation and optionally actions when a subscribed sensor event occurs.
This action might be invoking an effector or emitting a new sensor,
depending the desired behavior is.

Writing a policy is straightforward.
Simply extend [``AbstractPolicy``]({{book.url.brooklyn_javadoc}}/org/apache/brooklyn/core/policy/AbstractPolicy.html),
overriding the [``setEntity``]({{book.url.brooklyn_javadoc}}/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.html#setEntity-org.apache.brooklyn.api.entity.EntityLocal-) method to supply any subscriptions desired:

```java
@Override
public void setEntity(EntityLocal entity) {
super.setEntity(entity)
subscribe(entity, TARGET_SENSOR, this)
}
```

and supply the computation and/or activity desired whenever that event occurs:

```java
@Override
public void onEvent(SensorEvent<Integer> event) {
int val = event.getValue()
if (val % 2 == 1)
entity.sayYoureOdd();
}
```


You'll want to do more complicated things, no doubt,
like access other entities, perform multiple subscriptions,
and emit other sensors -- and you can.
See the best practices below and source code for some commonly used policies and enrichers,
such as ``AutoScalerPolicy`` and ``RollingMeanEnricher``.

One rule of thumb, to close on:
try to keep policies simple, and compose them together at runtime;
for instance, if a complex computation triggers an action,
define one **enricher** policy to aggregate other sensors and emit a new sensor,
then write a second policy to perform that action.


### Best Practice

The following recommendations should be considered when designing policies:

#### Management should take place as "low" as possible in the hierarchy
* place management responsibility in policies at the entity, as much as possible ideally management should take run as a policy on the relevant entity

* place escalated management responsibility at the parent entity. Where this is impractical, perhaps because two aspects of an entity are best handled in two different places, ensure that the separation of responsibilities is documented and there is a group membership relationship between secondary/aspect managers.


#### Policies should be small and composable

e.g. one policy which takes a sensor and emits a different, enriched sensor, and a second policy which responds to the enriched sensor of the first (e.g. a policy detects a process is maxed out and emits a TOO_HOT sensor; a second policy responds to this by scaling up the VM where it is running, requesting more CPU)

#### Where a policy cannot resolve a situation at an entity, the issue should be escalated to a manager with a compatible policy.

Typically escalation will go to the entity parent, and then cascade up.
e.g. if the earlier VM CPU cannot be increased, the TOO_HOT event may go to the parent, a cluster entity, which attempts to balance. If the cluster cannot balance, then to another policy which attempts to scale out the cluster, and should the cluster be unable to scale, to a third policy which emits TOO_HOT for the cluster.

#### Management escalation should be carefully designed so that policies are not incompatible

Order policies carefully, and mark sensors as "handled" (or potentially "swallow" them locally), so that subsequent policies and parent entities do not take superfluous (or contradictory) corrective action.

### Implementation Classes

Extend [`AbstractPolicy`]({{book.url.brooklyn_javadoc}}/org/apache/brooklyn/core/policy/AbstractPolicy.html), or override an existing policy.
@@ -31,7 +31,8 @@ the entity being defined, with these being the most common:

* `location` (or `locations`): as defined in the root element

* `brooklyn.config`: configuration key-value pairs passed to the service entity being created
* `brooklyn.config`: configuration key-value pairs passed to the service entity being created;
complex values are supported if they are JSON-deserializable beans that have been added as registered types

* `brooklyn.children`: a list of `ServiceSpecifications` which will be configured as children of this entity

@@ -43,10 +44,11 @@ the entity being defined, with these being the most common:
<!-- TODO assert that this yaml maches the yaml we test against -->

* `brooklyn.initializers`: a list of `EntityInitializer` instances to be constructed and run against the entity,
each as a map described with their `type` and their `brooklyn.config` as keys.
An `EntityInitiailzer` can perform arbitrary customization to an entity whilst it is being constructed,
such as adding dynamic sensors and effectors. These classes must expose a public constructor taking
a single `Map` where the `brooklyn.config` is passed in.
each as a map described with their `type` (Java or a registered type in the catalog) and JSON-serializable fields.

An `EntityInitializer` can perform arbitrary customization to an entity whilst it is being constructed,
such as adding dynamic sensors and effectors.

Some common initializers are:

* `org.apache.brooklyn.core.effector.ssh.SshCommandEffector`: takes a `name` and `command`,
@@ -62,6 +64,24 @@ the entity being defined, with these being the most common:
and optionally a `period` and `executionDir`, to create a sensor feed which populates the sensor with
the given name by running the given command (on an entity which as an WinRM-able machine).<br/>
_`"~"` will use the default execution directory for the WinRm session which is usually `%USERPROFILE%`_

When specifying the type of an initializer, registered types (added to the catalog) are preferred,
but Java types are permitted.

Advanced note: When implementing an initializer in Java, it is preferred to rely on standard Jackson serialization techniques to initialize fields,
i.e. have a no-arg constructor and fields which can be specified in YAML.
However it is permitted for backwards compatibility, to supply configuration under a `brooklyn.config` key;
via a public constructor taking a single `ConfigBag` (or sometimes a `Map`)
where the `brooklyn.config` key-values are passed in.
This approach has several constraints however.
The config inheritance modes which are used on entities and other spec types are not recognised here.
If the type is added to the catalog and referred to by its registered type name,
or if registered types are being passed as config,
the class must support JSON deserialization of `brooklyn.config`,
and that is strongly recommended since Apache Brooklyn v1.1.
This can be done by ensuring a no-arg constructor is defined and
supplying a `@JsonSetter("brooklyn.config") initializeConfig(Map<String,Object)` method.
There are convenience abstract classes in `EntityInitializers` which can be useful for more complicated configurations.

* `brooklyn.parameters`: documents a list of typed parameters the entity accepts.
These define config keys exposed on the type, including metadata for prompting a user to supply them.
@@ -106,16 +126,23 @@ the entity being defined, with these being the most common:
- displayName
~~~

Entities, policies, and initializers may accept additional key-value pairs,
usually documented in their documentation (e.g. javadoc), or in the case of Java
often as static fields in the underlying Java class.
Often there are config keys or flags (indicated by `@SetFromFlag`) declared on the class;
these declared flags and config keys may be passed in at the root of the `ServiceSpecification` or in `brooklyn.config`.
(Undeclared config is only accepted in the `brooklyn.config` map.)
Referencing the parameters from within java classes is identical to using config keys. In yaml it's
usually referenced using `$brooklyn:scopeRoot().config("displayName")`. See below for more details on scopes.

* `brooklyn.tags`: documents a list of tag objects which should be assigned to the entity.
* `brooklyn.tags`: a list of tag objects which should be attached to the entity.

Entities (and policies and enrichers) will typically accept additional key-value pairs
as per the config keys (parameters) they expose. In some cases they may accept other fields
(where fields in a Java class are annotated `@SetFromFlag` although this is discouraged),
but undeclared config is only accepted in the `brooklyn.config` map.
Global config can be passed in either at the root of the `ServiceSpecification`
or in a root `brooklyn.config` section.

Initializers and custom types used as config/parameters are treated as beans, with fields at the root.
However in many cases initializers also accept configuration passed in a `brooklyn.config` section.
To accept expressions using the Brooklyn DSL (`$brooklyn:xxx`) in fields of beans,
the field type should be declared as a `WrappedValue<T>`, where `T` is the desired type.
(Config key values will always accept the Brooklyn DSL without this, but fields will not.)


## Location Specification Elements

0 comments on commit 28a107a

Please sign in to comment.