New Juju Actions UX


#1

The UX around Juju Actions is undergoing a fairly radical re-design to address some long standing issues and deliver some nice usability improvements.

Key points:

  • terminology changes
  • running an action defaults to synchronous (block until done)
  • new ability to display progress log messages
  • cleaner plain text output option
  • stdout and stderr included in output
  • numeric ids instead of UUIDs
  • ability to list pending, running, completed actions
  • ability to watch progress of a running action

Getting Started

To use the new UX, the only thing you’ll need to do is enable the juju-v3 feature flag on the client. The backend controller infrastructure is compatible with both the old and new UX.

export JUJU_DEV_FEATURE_FLAGS=juju-v3

Terminology changes

The terminology around this feature changes as follows:

  • actions become functions
  • enqueued actions are called operations
  • juju run-action becomes juju call
  • juju run becomes juju exec
  • juju show-action-output becomes juju show-operation

Charm developer changes

As a charm developer, there’s a new hook command (and corresponding charm helpers API) to log action (function) progress messages.

Note: the terminology change from action->function is not yet implemented on the charming side.

$ action-log --help
Usage: action-log <message>

Summary:
record a progress message for the current action

Package charmhelpers.core

def action_log(message):
    """Write an action progress message"""

Feature walk through

We’ll deploy a charm with a sample action hacked together to try out some of the new features. It happens to be a k8s charm, to help show that actions now also work on k8s.

$ cat actions/hello
#!/bin/bash
action-set result-map.message="Hello $(action-get who)!"
action-set outcome="maybe"
echo Goodbye cruel world
echo This message goes to stderr >&2
echo Foo bar
for i in {1..5}
do
   action-log "Welcome $i times"
   sleep 1
done
exit 3
$ juju deploy mycharms/mariadb-k8s -n 2
$ juju functions mariadb-k8s
Function  Description
hello     Hello World.

$ juju show-function mariadb-k8s hello
Hello World.

Arguments
who:
  type: string
  description: The person to say hello to.

We’ll call the function with default behaviour - synchronous and plain text output.

$ juju call mariadb-k8s/0 hello who=world
Running Operation 1

09:39:43 Welcome 1 times
09:39:44 Welcome 2 times
09:39:45 Welcome 3 times
09:39:46 Welcome 4 times
09:39:47 Welcome 5 times

outcome: maybe
result-map:
  message: Hello world!

Goodbye cruel world
Foo bar
This message goes to stderr

Note that the plain text output omits tasks metadata like enqueue time etc and just shows progress logs, structured output data, and stdout/stderr.

YAML output shows everything. We can also choose to display timestamps in UTC.

$ juju call mariadb-k8s/0 hello who=world --format yaml --utc
Running Operation 2
Waiting for operation 2...
08:16:22 hello sailor
08:16:22 Welcome 1 times
08:16:23 Welcome 2 times
08:16:24 Welcome 3 times
08:16:25 Welcome 4 times
08:16:27 Welcome 5 times

mariadb-k8s/0:
  id: "2"
  log:
  - 2019-11-15 08:16:22 +0000 UTC hello sailor
  - 2019-11-15 08:16:22 +0000 UTC Welcome 1 times
  - 2019-11-15 08:16:23 +0000 UTC Welcome 2 times
  - 2019-11-15 08:16:24 +0000 UTC Welcome 3 times
  - 2019-11-15 08:16:25 +0000 UTC Welcome 4 times
  - 2019-11-15 08:16:27 +0000 UTC Welcome 5 times
  message: command terminated with exit code 3
  results:
    info:
      host: mariadb-k8s-0
      message: Hello world!
    return-code: 3
    stderr: |
      This message goes to stderr
    stdout: |
      Goodbye cruel world
      Foo bar
  status: failed
  timing:
    completed: 2019-11-15 08:16:28 +0000 UTC
    enqueued: 2019-11-15 08:16:21 +0000 UTC
    started: 2019-11-15 08:16:22 +0000 UTC
  unit: mariadb-k8s/0

To see a particular operation (whether completed or not), use the show-operation command. The command will return immediately with the current state of the operation, unless --watch is used which will block and report the progress of a running operation until it completes. The --wait X option is also supported, to allow an upper bound on how long to wait for the operation to complete.

The default plain text output is quite concise, and omits any progress log messages. As with other related commands, --utc can be used if desired.

$ juju show-operation 2
outcome: maybe
result-map:
  message: Hello world!

Goodbye cruel world
Foo bar
This message goes to stderr

The YAML output again shows everything, including log messages.

$ juju show-operation 2 --format yaml --utc
log:
- 2019-11-14 22:16:22 +0000 UTC hello sailor
- 2019-11-14 22:16:22 +0000 UTC Welcome 1 times
- 2019-11-14 22:16:23 +0000 UTC Welcome 2 times
- 2019-11-14 22:16:24 +0000 UTC Welcome 3 times
- 2019-11-14 22:16:25 +0000 UTC Welcome 4 times
- 2019-11-14 22:16:27 +0000 UTC Welcome 5 times
message: command terminated with exit code 3
results:
  info:
    host: mariadb-k8s-0
    message: Hello world!
  return-code: 3
  stderr: |
    This message goes to stderr
  stdout: |
    Goodbye cruel world
    Foo bar
status: failed
timing:
  completed: 2019-11-14 22:16:28 +0000 UTC
  enqueued: 2019-11-14 22:16:21 +0000 UTC
  started: 2019-11-14 22:16:22 +0000 UTC
unit: mariadb-k8s/0

You can call a function and have it run in the background.

$ juju call mariadb-k8s/0 hello who=world --background
Scheduled Operation 3
Check status with 'juju show-operation 3'

To see progress of a running operation:

$ juju show-operation 3 --watch
10:03:19 Welcome 1 times
10:03:20 Welcome 2 times
10:03:21 Welcome 3 times
10:03:22 Welcome 4 times
10:03:23 Welcome 5 times

outcome: maybe
result-map:
  message: Hello world!

Goodbye cruel world
Foo bar
This message goes to stderr

The default behaviour to run an operation synchronously and display progress messages until it completes is only applicable if a single operation is queued. It’s possible to call a function against several units.

$ juju call mariadb-k8s/0 mariadb-k8s/1 hello who=world
Scheduled Operations:
mariadb-k8s/0:
  id: "14"
mariadb-k8s/1:
  id: "15"
Check status with 'juju show-operation <id>'

Functions which have been called are enqueued as operation, stay pending until they are run, and then complete (successfully or not). The new operations (list-operations) command can be used to see what operations exist, optionally filtered by:

  • unit
  • application
  • function name
  • status (pending, running, completed)

show-operation can then be used to inspect a particular operation in more detail.

When both unit(s) and application(s) are specified, operations for any of the individual units and any unit of the applications are included.

$ juju operations --status=running,completed --functions=hello --apps=mariadb-k8s
Id  Task   Status      Unit           Time                 
 8  hello  failed      mariadb-k8s/0  2019-10-21T09:38:44   
 9  hello  running     mariadb-k8s/0  2019-10-21T09:40:05   
10  hello  failed      mariadb-k8s/0  2019-10-21T09:43:35  
11  hello  failed      mariadb-k8s/0  2019-10-21T10:03:40  
12  hello  completed   mariadb-k8s/0  2019-10-21T10:10:11  
13  hello  completed   mariadb-k8s/1  2019-10-21T10:10:42  
15  hello  failed      mariadb-k8s/1  2019-10-21T10:11:13  
14  hello  completed   mariadb-k8s/0  2019-10-21T10:11:35  

Use YAML to see more information about each task. --utc works as well.

$ juju operations --status=running,completed --functions=hello --units=mariadb-k8s/1 --format yaml --utc
"13":
  log:
  - 2019-11-14 22:16:22 +0000 UTC hello sailor
  - 2019-11-14 22:16:22 +0000 UTC Welcome 1 times
  - 2019-11-14 22:16:23 +0000 UTC Welcome 2 times
  - 2019-11-14 22:16:24 +0000 UTC Welcome 3 times
  - 2019-11-14 22:16:25 +0000 UTC Welcome 4 times
  - 2019-11-14 22:16:27 +0000 UTC Welcome 5 times
  message: command terminated with exit code 3
results:
  info:
    host: mariadb-k8s-0
    message: Hello world!
  return-code: 3
  stderr: |
    This message goes to stderr
  stdout: |
    Goodbye cruel world
    Foo bar
status: failed
timing:
  completed: 2019-11-14 22:16:28 +0000 UTC
  enqueued: 2019-11-14 22:16:21 +0000 UTC
  started: 2019-11-14 22:16:22 +0000 UTC
unit: mariadb-k8s/1
"15":
  log:
  - 2019-11-14 22:16:22 +0000 UTC hello sailor
  - 2019-11-14 22:16:22 +0000 UTC Welcome 1 times
  - 2019-11-14 22:16:23 +0000 UTC Welcome 2 times
  - 2019-11-14 22:16:24 +0000 UTC Welcome 3 times
  - 2019-11-14 22:16:25 +0000 UTC Welcome 4 times
  - 2019-11-14 22:16:27 +0000 UTC Welcome 5 times
  message: command terminated with exit code 3
results:
  info:
    host: mariadb-k8s-0
    message: Hello world!
  return-code: 3
  stderr: |
    This message goes to stderr
  stdout: |
    Goodbye cruel world
    Foo bar
status: failed
timing:
  completed: 2019-11-14 22:16:28 +0000 UTC
  enqueued: 2019-11-14 22:16:21 +0000 UTC
  started: 2019-11-14 22:16:22 +0000 UTC
unit: mariadb-k8s/1

Any Advice on Using Juju for Regular Websites?
Call for Testing: Preparing for the upcoming 2.7.0 Release
New Features and Changes in Juju 2.7
#3

This is awesome Ian - I’ve been using the juju-v3 flag for a little while now and love the changes.

As additional feedback, and if part of this work unblocks being able to pass files back from the units via the controller as the result of actions, that would improve UX as well IMO. I have often needed to have a function return a file back to the CLI (such as backing up data or certificates stored in the unit).


#4

Glad you like the new UX. We have plans next cycle to introduce the concept of sub-tasks. The top level function invocation is an operation and operations can spawn tasks which are grouped under the top level operation. Details are still in flux. Note that the next 2.7 rc5 will use list-operations and show-operation.

We also will be introducing the ability to cancel running operations.

Unfortunately, there’s no immediate plans to be able to stream files resulting from running a function. This is something we definitely need to (and want to) do but for next cycle our todo list is somewhat overflowing. If there’s time, we can try to squeeze it in but can’t make any promises.