This is an automated email from the ASF dual-hosted git repository.
heneveld pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-docs.git
The following commit(s) were added to refs/heads/master by this push:
new 13a62c01 add docs for add'l model-manipulation workflow steps
13a62c01 is described below
commit 13a62c01f2c84b7dc9dce94006376b195bc7d088
Author: Alex Heneveld <[email protected]>
AuthorDate: Mon Nov 28 12:59:04 2022 +0000
add docs for add'l model-manipulation workflow steps
---
guide/blueprints/workflow/nested-workflow.md | 41 +++++++++++++++++
guide/blueprints/workflow/settings.md | 14 ++++--
guide/blueprints/workflow/steps/index.md | 17 +++++++
guide/blueprints/workflow/steps/steps.yaml | 66 ++++++++++++++++++++++++++++
guide/blueprints/workflow/variables.md | 6 ++-
5 files changed, 139 insertions(+), 5 deletions(-)
diff --git a/guide/blueprints/workflow/nested-workflow.md
b/guide/blueprints/workflow/nested-workflow.md
index f961a014..fd52ead4 100644
--- a/guide/blueprints/workflow/nested-workflow.md
+++ b/guide/blueprints/workflow/nested-workflow.md
@@ -160,3 +160,44 @@ This is a trivial single-step example but shows the power
of creating custom wor
especially with parameters and shorthand templates.
The [examples](examples/) and the [workflow settings](settings.md) include
more realistic
illustrations of custom workflow steps.
+
+
+#### Writing Workflow Steps in Java
+
+The most common way to define custom workflow types is as workflow, using the
primitives defined here,
+and delegating to custom containers where the logic is best done in a
higher-level programming language.
+This avoids any language bias and the need to learn Brooklyn interfaces.
+However it is supported to provide custom workflow step types as Java classes
in a bundle.
+
+To write a Java workflow step type, provide a class extending
`WorkflowStepDefinition`,
+providing implementations for the following methods:
+
+```
+Object doTaskBody(WorkflowStepInstanceExecutionContext context);
+void populateFromShorthand(String value);
+boolean isDefaultIdempotent();
+```
+
+The first of these does the work of the step, resolving inputs and accessing
context as needed via `context`.
+The second handles providing a cusotm shorthand, as described above;
+it can call to a superclass method `populateFromShorthandTemplate(TEMPLATE,
value)`
+with the `TEMPLATE` for the class, if shorthand is to be supported.
+Finally, the third returns whether the step is idempotent, that is if the
custom step is interrupted,
+can Brooklyn safely recover simply by rerunning it with the same inputs.
+As described [here](settings.md), it is recommended to write the step so that
it is idempotent if possible.
+
+Once written, the class should be added to the Brooklyn Catalog,
+e.g. for a custom java step called `com.acme.YourJavaWorkflowStep` with
shorthand name `your-step`,
+create a `catalog.bom` such as the following, and `br catalog add catalog.bom`:
+
+```
+brooklyn.catalog:
+ bundle: your-step-bundle
+ version: "1.0.0-SNAPSHOT"
+ items:
+ - id: your-step
+ format: java-type-name
+ itemType: bean
+ item:
+ type: com.acme.YourJavaWorkflowStep
+```
diff --git a/guide/blueprints/workflow/settings.md
b/guide/blueprints/workflow/settings.md
index 421323be..6e0b5d92 100644
--- a/guide/blueprints/workflow/settings.md
+++ b/guide/blueprints/workflow/settings.md
@@ -165,8 +165,9 @@ uncertainty about whether the step completed or not can be
ignored, and the step
as "sleep", "set-config", or "wait for sensor X to be true" are obviously
idempotent; it also applies to `let` because
Brooklyn records a copy of the value of workflow variables on entry to each
step and will restore them on a replay.
-However, for some step types, it is impossible for Brooklyn to infer whether
they are idempotent: this applies to "
-external" steps such as `http` and `ssh`. It can also be the case that even
where individual steps are idempotent, a
+However, for some step types, it is impossible for Brooklyn to infer whether
they are idempotent: this applies to
+"external" steps such as `http` and `ssh`, and some `invoke-effector` steps.
+It can also be the case that even where individual steps are idempotent, a
sequence of steps is not. In either of these cases the workflow author should
give instructions to Brooklyn about how
to "replay".
@@ -201,6 +202,11 @@ Where an external step is known to be idempotent -- such
as a `describe-instance
read-only step -- the step can be marked `idempotent: yes` and Brooklyn will
support replay resuming at that step. (
However here, and often, this is unnecessary, if the nearest "replay point" is
good enough.)
+The internal steps `workflow` and `invoke-effector` are by default considered
idempotent
+if Brooklyn can tell they are running nested workflows at idempotent step.
+All other internal steps are idempotent.
+Actions such as `deploy-application` use special techniques internally to
guarantee idempotency.
+
In some cases, it can be convenient to indicate default replayable/idempotency
instructions when defining a workflow. As
part of any workflow definition, such as `workflow-effector` or a nested
`type: workflow` step, the
entry `idempotent: all` indicates that all external steps in the workflow are
idempotent; `replayable: automatically`
@@ -220,7 +226,9 @@ extra attention. The following is a summary of the common
settings used:
when defining a workflow
* **`replayable: from start`** to indicate that the start of the workflow is
a valid replay point
* **`replayable: automatically`** to indicate that on an unhandled Brooklyn
failover (DanglingWorkflowException), the workflow should attempt to "replay
resuming", either from the last executed step if it is resumable, or from the
last replay point
- * **`idempotent: all`** to indicate that external steps such as `http` and
`container` in the workflow are resumable unless explicitly indicated otherwise
(by default these are not; only internal steps known to be safely re-runnable
are resumable)
+ * **`idempotent: all`** to indicate that all steps are idempotent and if
interrupted there, the workflow can resume there,
+ unless explicitly indicated otherwise
+ (by default steps such as `http` and `container` are not; only internal
steps known to be safely re-runnable are resumable)
Finally, it is worth elaborating the differences between the three types of
retry behavior, as described on the `retry` step:
diff --git a/guide/blueprints/workflow/steps/index.md
b/guide/blueprints/workflow/steps/index.md
index 458d1d74..073c265e 100644
--- a/guide/blueprints/workflow/steps/index.md
+++ b/guide/blueprints/workflow/steps/index.md
@@ -9,6 +9,23 @@ children:
- { section: Index of Step Types }
---
+Apache Brooklyn workflow supports a range of step types covering the most
common activities
+commonly done as part of application management.
+These are divided into the following groups:
+
+* [Workflow Control](#workflow_control): use local variables and control flow,
+ with step types such as `let`, `return`, and `retry`
+* [External Actions](#external_actions): interact with external systems
+ using step types such as `container`, `ssh`, `winrm`, and `http`
+* [Application Models](#application_models): work with the models stored in
Brooklyn,
+ doing things such as `invoke-effector`, `set-sensor`, `deploy-application`,
and `add-entity`
+* [General Purpose](#general_purpose): miscellaneous step types such as `log`
and `sleep`
+
+Custom step types can be written and added to the catalog, either written as
workflow using these primitives
+(including doing virtually anything in a container) or by implementing a Java
type, both [as described here](../nested-workflow.md).
+An index of all out-of-the-box step types is included at the [end of this
section](#index_of_step_types).
+
+
{% jsonball steps from yaml file steps.yaml %}
{% assign step_summaries = "" | split: ", " %}
diff --git a/guide/blueprints/workflow/steps/steps.yaml
b/guide/blueprints/workflow/steps/steps.yaml
index ad327ad3..1d29a955 100644
--- a/guide/blueprints/workflow/steps/steps.yaml
+++ b/guide/blueprints/workflow/steps/steps.yaml
@@ -365,6 +365,72 @@
optionally the `entity` where the sensor should be cleared
(defaulting to the entity where the workflow is running)
output: the output from the previous step, or null if this is the first
step
+ - name: deploy-application
+ summary: Deploys an application from a registered type or a blueprint
+ shorthand: '`deploy-application [TYPE]`'
+ input: |
+ * `type`: a registered type to deploy as a root application, without
any configuration; exactly one of this and `blueprint` is required
+ * `blueprint`: the blueprint to deploy
+ * `format`: optional format specifier for the blueprint
+ output:
+ * `app`: the application instance deployed
+
+ - name: add-entity
+ summary: Deploys an application from a registered type or a blueprint
+ shorthand: '`add-entity [TYPE]`'
+ input: |
+ * `type`: a registered type to add as a child here, without any
configuration; exactly one of this and `blueprint` is required
+ * `blueprint`: the blueprint of the entity, or a list of such
blueprints, to be added at the current entity
+ * `format`: optional format specifier for the blueprint
+ output:
+ * `entities`: a list of entities added
+ * `entity`: if a single entity was added, that entity, otherwise unset
+
+ - name: delete-entity
+ summary: Deploys an application from a registered type or a blueprint
+ shorthand: '`delete-entity ENTITY`'
+ input: |
+ * `entity`: the entity or entity ID to delete (unmanage)
+ output: the output from the previous step, or null if this is the first
step
+
+ - name: reparent-entity
+ summary: Moves an entity to be under a new parent
+ shorthand: '`reparent-entity child CHILD under PARENT`'
+ input: |
+ * `child`: the entity or entity ID to be moved
+ * `parent`: the entity or entity ID of the new parent
+ output: the output from the previous step, or null if this is the first
step
+
+ - name: apply-initializer
+ summary: Moves an entity to be under a new parent
+ shorthand: '`apply-initializer [TYPE [at ENTITY]]`'
+ input: |
+ * `type`: a registered type to add as a child here, without any
configuration; exactly one of this and `blueprint` is required
+ * `blueprint`: the blueprint of the entity, or a list of such
blueprints, to be added at the current entity
+ * `entity`: the entity or entity ID where the initializer should be
run, defaulting to the current entity
+ output: the output from the previous step, or null if this is the first
step
+
+ - name: add-policy
+ summary: Adds a policy or other adjunct from a registered type or a
blueprint
+ shorthand: '`add-policy [TYPE] [at ENTITY] [unique-tag UNIQUE_TAG]`'
+ input: |
+ * `type`: a registered type for a policy or other adjunct, to be
attached to this entity, without any configuration; exactly one of this and
`blueprint` is required
+ * `blueprint`: the blueprint for a policy, enricher, feed, or other
adjunct, to be added at the current entity
+ * `entity`: the entity or entity ID where the adjunct should be added,
defaulting to the current entity
+ * `unique-tag`: a tag to uniquely identify this adjunct, defaulting to
the workflow step; this will replace any instance with the same unique-tag at
the entity
+ (to make the operation idempotent)
+ output:
+ * `adjunct`: the policy or other adjunct added
+ * `policy` or `enricher` or `feed`: as above, depending on the type of
the adjunct
+
+ - name: delete-policy
+ summary: Removes a policy or other adjunct at an entity
+ shorthand: '`delete-policy POLICY [at ENTITY]`'
+ input: |
+ * `policy`: the policy or adjunct to be removed, or the unique tag or
ID of such an adjunct
+ * `entity`: the entity or entity ID where the adjunct should be
removed, defaulting to the current entity
+ output: the output from the previous step, or null if this is the first
step
+
-
section_name: General Purpose
diff --git a/guide/blueprints/workflow/variables.md
b/guide/blueprints/workflow/variables.md
index 82d7e184..8065dae4 100644
--- a/guide/blueprints/workflow/variables.md
+++ b/guide/blueprints/workflow/variables.md
@@ -144,8 +144,8 @@ because the string `3+1` will not be coercible to an
integer.
The reason `let` is the only place operations is allowed is because Brooklyn
is able to restore local variables
if a workflow is replayed from that step.
-This ensures that all the internal steps (excluding steps that act externally
such as `ssh` or `container`)
-are individually idempotent, so if interrupted at the step can be safely
resumed from that step.
+This ensures that most steps are individually idempotent,
+so if interrupted at the step can be safely resumed from that step.
For example, if the following were allowed:
@@ -166,6 +166,8 @@ The following sequence of steps (which is permitted) can
always safely be replay
Where workflows need to be resumed on interruption or might replay steps to
recover from other errors,
idempotency is an important part of reliable workflow design.
+External actions such as `http` and `container` are not guaranteed to be
idempotent,
+and neither are some `invoke-effector` calls, so care must be taken here for
workflows to be replayable.
Good practice and the settings available for resilient workflows are covered
in [Workflow Settings](settings.md).