Actions for the charm author
Actions are executables associated with a charm that may be invoked by the user.
For example, the charm author might include a snapshot
action on a database
charm. See Juju Actions on how to use actions.
The user may pass arguments when invoking the action. The charm uses an
actions.yaml
file to specify the parameter type for the arguments. In the
Juju GUI, the invocation of an action will be
automatically built based on actions.yaml
.
Action tools may be used by the author to define how actions interact with Juju. Actions can retrieve parameters passed by the user, set responses in a map, or set a failure status with a message.
Implementing actions
Every implemented action must include:
- its executable (script, binary, etc.) in the charm's
/actions
directory. - the executable's name as a top-level key in a YAML map in the
actions.yaml
file.
Note: Action names must start and end with lowercase alphanumeric characters, and only contain lowercase alphanumeric characters, the hyphen "-" or full stop"." characters.
Here is a sample partial layout of a charm's root directory that shows actions called 'pause', 'resume', and 'snapshot':
├── actions
│ ├── pause
│ ├── resume
│ └── snapshot
├── actions.yaml
...
Below is an actions.yaml
file that shows the three executables as "top-level
keys":
pause:
resume:
snapshot:
That is a "barebones" configuration. As the next section will make clear, there is a lot more that can, and should, be placed in this file.
Options and format: actions.yaml
Here is a list of options that can be used in actions.yaml
along with their
respective format.
- Each action is defined as a top-level key of a YAML map, with the same name as its corresponding executable.
- The value of each action should include a
description
key and may include aparams
key. If no description is given, an empty description will be used. - The value of the
params
key is also a YAML map where each key is a string whose value is a 'JSON Schema' transformed to a YAML map. The 'JSON Schema' itself, may, in turn, be nested. - The 'JSON Schema' keys
required
andadditionalProperties
can be used under the action key (parallel todescription
andparams
) but they can also be used anywhere within a nested schema. - Use
additionalProperties: false
under the action key to reject additional parameters passed by the user. - At this time, the
$schema
and$ref
keys are not supported by Juju, as they may trigger resolution of remote objects and other issues.
Detailed example
Using the above information the previous example can be extended with the
description
key:
pause:
description: Pause the database.
resume:
description: Resume a paused database.
snapshot:
description: Take a snapshot of the database.
The snapshot
action can be enriched with the params
key:
...
snapshot:
description: Take a snapshot of the database.
params:
outfile:
type: string
description: The filename to write to.
...
A sample complete actions.yaml
file after extending the snapshot action and
adding the required
and additionalProperties
keys:
pause:
description: Pause the database.
resume:
description: Resume a paused database.
snapshot:
description: Take a snapshot of the database.
params:
filename:
type: string
description: The name of the snapshot file.
compression:
type: object
description: The type of compression to use.
properties:
kind:
type: string
enum: [gzip, bzip2, xz]
quality:
description: Compression quality
type: integer
minimum: 0
maximum: 9
required: [filename]
additionalProperties: false
This action would support a call such as:
juju run-action mysql/0 snapshot filename=out.tar.gz compression.type=gzip
Action tools
Three tools are provided to the action author for the action to interact with Juju:
action-get
retrieves the params passed when invoking the action.action-set
sets values in a map to be returned after the action finishes.action-fail
sets the action status tofailed
when it finishes, with a message to be returned to the user. The results set byaction-set
are preserved.
Use juju help-tool <tool name>
to see more detail on each tool.
action-get
action-get
prints the value of the parameter at the given key, serialized
according to the --format
option. If multiple keys are passed, action-get
will recurse into the parameter map as needed.
For example, if an action named snapshot
was defined on a MySQL charm, and
was invoked by the user as follows:
juju run-action mysql/0 snapshot outfile="foo"
then the snapshot
could use action-get
to retrieve the filename:
#!/bin/bash
# An action named "snapshot"
action-get outfile
# "foo" will be printed
action-set
action-set
permits the action to set results in a map to be returned at the
completion of the action. Here is an example:
#!/bin/bash
# An action named "report"
action-set result-map.time-completed="$(date)" result-map.message="Hello world!"
action-set outcome="success"
Using the above action ('report'), the command
juju action fetch <ID>
will produce output similar to:
# ...
message: "" # No error message.
results:
result-map:
time-completed: <some date>
message: Hello world!
outcome: success
status: completed
action-fail
action-fail
causes the action to finish as failed
upon completion. For
instance, this might be used to indicate a full disk if a database dump was
attempted, or to indicate that a remote service was unable to be resolved. The
results set by action-set
before or after failure are retained, and an action
fail status cannot be unset.
Example:
#!/bin/bash
# An action named "sayhello"
command=$(action-get command)
action-set received.value="$command"
if [ "$command" != "hello" ];
then
action-fail "I only know one command."
action-set received.known="no"
else
action-set received.known="yes"
fi
action-set timestamp="$(date)"
Using the above action ('sayhello'), the command
juju run-action <unit> sayhello command="greetme"
# ...
will produce output similar to:
message: I only know one command.
results:
received:
known: no
value: greetme
timestamp: Thu Jan 15 13:28:25 EST 2015
status: failed
Params transformation
This section covers the transformation from params
to JSON-Schema. This is
meant as an aid to creating more complex schemas and should not be necessary
for most actions.
The transformation to JSON-Schema is as follows:
# actions.yaml
<string A>:
[description: <string AB>]
[params:
<string PAA>:
<YAML map YAA>
<string PAB>:
<YAML map YAB>]
[string C]: X
[string D]: Y
[string ...]: Z
<string B>:
...
The above, which defines an action for <A>
(and <B>
, <C>
, and so on),
becomes the following in JSON-Schema format:
{
"description": "<AB>",
"title": "<A>",
"type": "object",
"properties": {
"<PAA>": {YAA as JSON},
"<PAB>": {YAB as JSON}
},
"required": ["filename"],
"<C>": X,
"<D>": Y,
...
}
For example, a simple YAML file such as:
# actions.yaml
snapshot:
description: Take a snapshot of the database.
params:
outfile:
type: string
will be transformed to this:
{
"description": "Take a snapshot of the database.",
"title": "snapshot",
"type": "object",
"properties": {
"outfile": {
"type": "string"
}
}
}
A complex YAML transform example
Here we transform the example given at the top of this page:
# actions.yaml
pause:
description: Pause the database.
resume:
description: Resume a paused database.
snapshot:
description: Take a snapshot of the database.
params:
filename:
type: string
description: The name of the snapshot file.
compression:
type: object
description: The type of compression to use.
properties:
kind:
type: string
enum: [gzip, bzip2, xz]
quality:
description: Compression quality
type: integer
minimum: 0
maximum: 9
required: [filename]
additionalProperties: false
It becomes three actions, with respective JSON-Schema:
pause:
{
"description": "Pause the database.",
"title": "pause",
"type": "object",
"properties": {}
}
resume:
{
"description": "Resume a paused database.",
"title": "resume",
"type": "object",
"properties": {}
}
snapshot:
{
"description": "Take a snapshot of the database.",
"title": "snapshot",
"type": "object",
"properties": {
"filename": {
"type": "string",
"description": "The name of the snapshot file."
},
"compression": {
"type": "object",
"description": "The type of compression to use.",
"properties": {
"kind": {
"type": "string",
"enum": ["gzip", "bzip2", "xz"]
},
"description": {
"type": "integer",
"description": "Compression quality",
"minimum": 0,
"maximum": 9
}
}
}
},
"required": ["filename"],
"additionalProperties": "false"
}