Actions: API, command, and jobspec docs (#19166)

* API command and jobspec docs

* PR comments addressed

* API docs for job/jobid/action socket

* Removing a perhaps incorrect origin of job_id across the jobs api doc

* PR comments addressed
This commit is contained in:
Phil Renaud
2023-11-30 14:13:37 -05:00
committed by GitHub
parent 67bbcc4a4f
commit d104432cd3
6 changed files with 452 additions and 40 deletions

View File

@@ -10,8 +10,6 @@ import (
"github.com/posener/complete"
)
const defaultEscapeChar = "~"
type ActionCommand struct {
Meta

View File

@@ -195,8 +195,8 @@ export default class JobAdapter extends WatchableNamespaceIDs {
)}/action` +
`?namespace=${job.get('namespace.id')}&action=${
action.name
}&allocID=${allocID}&task=${action.task.name}&group=${
action.task.taskGroup.name
}&allocID=${allocID}&task=${
action.task.name
}&tty=true&ws_handshake=true` +
(region ? `&region=${region}` : '');

View File

@@ -329,8 +329,8 @@ The table below shows this endpoint's support for
### Parameters
- `:job_id` `(string: <required>)` - Specifies the ID of the job (as specified in
the job file during submission). This is specified as part of the path.
- `:job_id` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
- `namespace` `(string: "default")` - Specifies the namespace of the job. If not specified,
defaults to "default". This is specified as a URL query parameter.
@@ -639,8 +639,8 @@ The table below shows this endpoint's support for
- `diffs` `(bool: false)` - Specifies if the Diffs field should be populated,
containing the structured diff between the current and last job version.
- `:job_id` `(string: <required>)` - Specifies the ID of the job (as specified in
the job file during submission). This is specified as part of the path.
- `:job_id` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
- `namespace` `(string: "default")` - Specifies the target namespace. If ACL is
enabled, this value must match a namespace that the token is allowed to
@@ -1235,8 +1235,8 @@ The table below shows this endpoint's support for
### Parameters
- `:job_id` `(string: <required>)` - Specifies the ID of the job (as specified in
the job file during submission). This is specified as part of the path.
- `:job_id` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
- `all` `(bool: false)` - Specifies whether the list of allocations should
include allocations from a previously registered job with the same ID. This is
@@ -1408,8 +1408,8 @@ The table below shows this endpoint's support for
### Parameters
- `:job_id` `(string: <required>)` - Specifies the ID of the job (as specified in
the job file during submission). This is specified as part of the path.
- `:job_id` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
- `namespace` `(string: "default")` - Specifies the target namespace. If ACL is
enabled, this value must match a namespace that the token is allowed to
@@ -1473,8 +1473,8 @@ The table below shows this endpoint's support for
### Parameters
- `:job_id` `(string: <required>)` - Specifies the ID of the job (as specified in
the job file during submission). This is specified as part of the path.
- `:job_id` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
- `all` `(bool: false)` - Specifies whether the list of deployments should
include deployments from a previously registered job with the same ID. This is
@@ -1565,8 +1565,8 @@ The table below shows this endpoint's support for
### Parameters
- `:job_id` `(string: <required>)` - Specifies the ID of the job (as specified in
the job file during submission). This is specified as part of the path.
- `:job_id` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
- `namespace` `(string: "default")` - Specifies the target namespace. If ACL is
enabled, this value must match a namespace that the token is allowed to
@@ -1628,8 +1628,8 @@ The table below shows this endpoint's support for
### Parameters
- `:job_id` `(string: <required>)` - Specifies the ID of the job (as specified in
the job file during submission). This is specified as part of the path.
- `:job_id` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
- `namespace` `(string: "default")` - Specifies the target namespace. If ACL is
enabled, this value must match a namespace that the token is allowed to
@@ -1685,8 +1685,8 @@ The table below shows this endpoint's support for
### Parameters
- `:job_id` `(string: <required>)` - Specifies the ID of the job (as specified in
the job file during submission). This is specified as part of the path.
- `:job_id` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
- `Job` `(Job: <required>)` - Specifies the JSON definition of the job.
@@ -1759,8 +1759,8 @@ The table below shows this endpoint's support for
### Parameters
- `:job_id` `(string: <required>)` - Specifies the ID of the job (as specified
in the job file during submission). This is specified as part of the path.
- `:job_id` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
- `IdempotencyToken` `(string: "")` - Optional identifier used to prevent more
than one instance of the job from being dispatched. This is specified as a
@@ -1829,8 +1829,8 @@ The table below shows this endpoint's support for
### Parameters
- `JobID` `(string: <required>)` - Specifies the ID of the job (as specified
in the job file during submission). This is specified as part of the path.
- `JobID` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
- `JobVersion` `(integer: 0)` - Specifies the job version to revert to.
@@ -1894,8 +1894,8 @@ The table below shows this endpoint's support for
### Parameters
- `JobID` `(string: <required>)` - Specifies the ID of the job (as specified
in the job file during submission). This is specified as part of the path.
- `JobID` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
- `JobVersion` `(integer: 0)` - Specifies the job version to set the stability on.
@@ -1954,8 +1954,8 @@ The table below shows this endpoint's support for
### Parameters
- `:job_id` `(string: <required>)` - Specifies the ID of the job (as specified in
the job file during submission). This is specified as part of the path.
- `:job_id` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
- `JobID` `(string: <required>)` - Specify the ID of the job in the JSON payload
@@ -2016,8 +2016,8 @@ The table below shows this endpoint's support for
### Parameters
- `:job_id` `(string: <required>)` - Specifies the ID of the job (as specified in
- the job file during submission). This is specified as part of the path.
- `:job_id` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
- `Job` `(string: <required>)` - Specifies the JSON definition of the job.
@@ -2227,8 +2227,8 @@ The table below shows this endpoint's support for
### Parameters
- `:job_id` `(string: <required>)` - Specifies the ID of the job (as specified in
the job file during submission). This is specified as part of the path.
- `:job_id` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
### Sample Request
@@ -2265,8 +2265,8 @@ The table below shows this endpoint's support for
### Parameters
- `:job_id` `(string: <required>)` - Specifies the ID of the job (as specified in
the job file during submission). This is specified as part of the path.
- `:job_id` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
- `eval_priority` `(int: 0)` - Override the priority of the evaluations produced
as a result of this job deregistration. By default, this is set to the priority
@@ -2324,8 +2324,8 @@ The table below shows this endpoint's support for
### Parameters
- `:job_id` `(string: <required>)` - Specifies the ID of the job (as specified in
the job file during submission). This is specified as part of the path.
- `:job_id` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
- `namespace` `(string: "default")` - Specifies the target namespace. If ACL is
enabled, this value must match a namespace that the token is allowed to
@@ -2380,8 +2380,8 @@ The table below shows this endpoint's support for
### Parameters
- `:job_id` `(string: <required>)` - Specifies the ID of the job (as specified in
the job file during submission). This is specified as part of the path.
- `:job_id` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
- `Count` `(int: <optional>)` - Specifies the new task group count.
@@ -2466,8 +2466,8 @@ The table below shows this endpoint's support for
### Parameters
- `:job_id` `(string: <required>)` - Specifies the ID of the job (as specified in
the job file during submission). This is specified as part of the path.
- `:job_id` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
- `namespace` `(string: "default")` - Specifies the target namespace.
@@ -2501,3 +2501,174 @@ $ curl \
}
]
```
## List Job Actions
This endpoint lists the actions available to tasks within a job.
| Method | Path | Produces |
| ------ | ------------------------- | ------------------ |
| `GET` | `/v1/job/:job_id/actions` | `application/json` |
The table below shows this endpoint's support for
[blocking queries](/nomad/api-docs#blocking-queries) and
[required ACLs](/nomad/api-docs#acls).
| Blocking Queries | ACL Required |
| ---------------- | -------------------- |
| `NO` | `namespace:read-job` |
### Parameters
- `:job_id` `(string: <required>)` - Specifies the ID of the job. This is
specified as part of the path.
### Sample Request
```shell-session
$ nomad operator api '/v1/job/my-job/actions'
```
### Sample Response
```json
[
{
"Args": [
"-s",
"wttr.in/Toronto?format=3"
],
"Command": "/usr/bin/curl",
"Name": "weather",
"TaskGroupName": "group1",
"TaskName": "task"
},
{
"Args": [
"-c",
"nomad alloc status ${NOMAD_ALLOC_ID}"
],
"Command": "/bin/sh",
"Name": "get-alloc-info",
"TaskGroupName": "group2",
"TaskName": "task"
},
]
```
## Run Action
This endpoint executes a predefined action from a job in the
context of a specific task within an allocation. It opens a WebSocket to
transmit output from the running action.
| Method | Path | Produces |
| ----------- | ------------------------ | ---------------------- |
| `WebSocket` | `/v1/job/:job_id/action` | WebSocket JSON streams |
The table below shows this endpoint's support for
[blocking queries](/nomad/api-docs#blocking-queries) and
[required ACLs](/nomad/api-docs#acls).
| Blocking Queries | ACL Required |
| ---------------- | -------------------------------------------------------------------------------------------- |
| `NO` | `namespace:alloc-exec` (and `namespace:alloc-node-exec` if task driver does not support [file system isolation](/nomad/docs/concepts/plugins/task-drivers#capabilities-capabilities-error)) |
### Parameters
- `:job_id` `(string: <required>)` - Specifies the ID of the job containing the
action. This is specified as part of the path.
- `action` `(string: <required>)` - Specifies the name of the action to be
executed, as defined within the job's task. Specified as a query parameter.
- `alloc_id` `(string: <required>)` - Specifies the UUID of the target
allocation. Specified as a query parameter.
- `task` `(string: <required>)` - Specifies the task where the action is
defined. Specified as a query parameter.
- `tty` `(bool: false)` - Specifies whether a TTY is allocated for this action.
Specified as a query parameter.
- `ws_handshake` `(bool: false)` - Specifies whether to expect the
authentication token in the first frame, as a query parameter.
### WebSocket Upgrade Request
Actions are executed with a WebSocket upgrade request. The request headers
must include the standard WebSocket upgrade parameters. Example:
```shell-session
$ curl \
-X GET \
-H 'Connection: Upgrade' \
-H 'Upgrade: websocket' \
-H 'Sec-Websocket-Version: 13' \
-H 'Sec-Websocket-Key: x3JJHMbDL1EzLkh9GBhXDw==' \
'http://127.0.0.1:4646/v1/job/actions-demo/action?action=weather&allocID=8614ed07-425f-889f-170d-dd2716e0e01f&task=task&tty=true'
```
or
```shell-session
$ nomad operator api \
-H "Connection: Upgrade" \
-H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==" \
'/v1/job/actions-demo/action?action=weather&allocID=8614ed07-425f-889f-170d-dd2716e0e01f&task=task&tty=true'
```
### Request Frames
Unlike [alloc exec](/nomad/api-docs/allocations#exec-allocation), Actions do
not take input in the form of request frames using `stdin`. Instead, the name
of the action is passed as a query parameter and the associated input is handled
on the allocation apart from the stream.
When `?ws_handshake=true`, the first request frame must contain the
authentication token. Similarly, when `?tty=true`, a `tty_size` frame may be
provided to indicate a resize.
The following are valid input frames:
```
# sending authentication token
{"version":1,"auth_token":"fc3c1968-8d31-5c50-9617-3db2e19ef32e"}
# indicating that TTY was resized
{"tty_size": {"height": <characters>, "width": <characters>}}
```
### Response Frames
Response frames represent `stdout` and `stderr` output from the command as well
as exit codes. Response frames encompass the full range of terminal emulator outputs, including
the control characters necessary to render interactive applications.
```
# transferring stdout data
{"stdout": {"data": "...base64 encoded string of bytes ..."}}
# signaling that host closed stdout
{"stdout": {"close": true}}
{"exited":true,"result":{}}
```
The stdout data returned in the response frames from the job action endpoint is
base64 encoded. This encoding is necessary to ensure that the data can be
transmitted over WebSocket connections without issues, regardless of its content.
### Sample Request and Response
This example response includes instances of the ANSI "control sequence
introducer" (CSI), which is ASCII code 27 followed by `[`. The second stdout
frame includes the desired output from the Action in question, which prints
the local weather.
```
# Sample WebSocket request to execute an action
WebSocket Request: /v1/job/actions-demo/action?action=weather&allocID=8614ed07-425f-889f-170d-dd2716e0e01f&task=task&tty=true
# "\x1b[H\x1b[2J$ ":
# CSI-H (move cursor to top left corner), CSI-2J (clear entire screen), print "$ "
{"stdout":{"data":"G1tIG1sySiQg"}}
# Toronto: ⛅️ -1°C
{"stdout":{"data":"VG9yb250bzog4puF77iPICAtMcKwQw0K"}}
```

View File

@@ -0,0 +1,107 @@
---
layout: docs
page_title: 'Commands: job action'
description: |
The job action command is used to execute predefined actions from a job
specification in a running task context
---
# Command: job action
**Alias: `nomad action`**
The `job action` command allows operators to execute predefined actions declared
in Nomad job specifications. These actions can be defined at task level and are
intended for specific operational tasks, such as clearing a cache, or migrating
a database.
An action may self-terminate upon completion (for example, echoing a string),
or run for an indeterminate amount of time (for example, watching a blocking
query). In the latter case, an action can be terminated via escape character
(such as cmd+c / ctrl+c)
When ACLs are enabled, this command requires a token with the `alloc-exec`,
`read-job`, and `list-jobs` capabilities for the allocation's namespace. If
the task driver does not have file system isolation (as with `raw_exec`),
this command requires the `alloc-node-exec`, `alloc-exec`, `read-job`, and
`list-jobs` capabilities for the allocation's namespace.
## Usage
```plaintext
nomad job action [options] <action>
```
The `job action` command requires an action name and accepts two ways of
specifying where it should run:
- by passing the job name and known allocation ID along with the name of the action
- by passing the job, task group, and task name along with the name of the action
(when the allocation ID is not known). A random allocation will be selected if
multiple are available.
The action name provided must be defined within a task in the [job specification]
provided. With sufficient privileges, an execution context will be opened and
the defined action command will be run. No further input is possible, save for
the escape character to terminate execution, so interactive commands are not
supported.
## General Options
@include 'general_options.mdx'
## Action Options
- `-job`: (Required) Specifies the job containing the predefined action.
- `-alloc`: Specifies the allocation within which the action is to be executed.
If omitted, `-group` and `-task` must be provided, and a random
allocation for the group will be selected.
- `-task`: Specifies the task within the job where the action is defined. This
is required either if `-alloc` provided and your group has multiple tasks,
or if you specify a `-group`.
- `-group`: Specifies the task group within the job. If present, a random
allocation is selected. If omitted, `-alloc` must be provided.
- `-i`: Pass stdin to the action, defaults to `true`. Pass `-i=false` to
disable explicitly.
- `-t`: Allocate a pseudo-tty, defaults to `true` if stdin is detected to be a tty
session. Pass `-t=false` to disable explicitly.
- `-e` <escape_char>: Sets the escape character for sessions with a pty,
defaults to '~'. The escape character is only recognized at the beginning of a
line. The escape character followed by a dot (`.`) closes the connection.
Setting the character to `none` disables any escapes and makes the session
fully transparent.
## Examples
Execute an action within a specific task in a job:
```shell-session
$ nomad action \
-group=my-group \
-task=my-task \
-job=my-job \
weather
Toronto: ☁️ +3°C
```
Execute an action within a specific allocation:
```shell-session
$ nomad action \
-alloc=f200a789-6da4-504c-d131-6181764f101e \
-job=actions-demo \
echo-time
Running for 0 seconds
Running for 1 seconds
Running for 2 seconds
Running for 3 seconds
```
[job specification]: /nomad/docs/job-specification

View File

@@ -0,0 +1,128 @@
---
layout: docs
page_title: action Block - Job Specification
description: The "action" block allows for executable commands that job authors can predefine for operators to subsequently run against their job.
---
# `action` Block
<Placement groups={['job', 'group', 'task', 'action']} />
The `action` block allows job authors to define custom commands. These commands
can be executed by operators with the necessary permissions on a running
allocation, offering a controlled way to interact with tasks.
## `action` Parameters
- `command` `(string: <required>)` - Specifies the command to be executed.
- `args` `(array<string>: [])` - Provides a list of arguments to pass to the command.
```hcl
job "my-job" {
group "my-group" {
task "my-task" {
action "get-changelog" {
command = "/usr/bin/curl"
args = [
"-s",
"https://raw.githubusercontent.com/hashicorp/nomad/main/CHANGELOG.md"
]
}
# ...
}
}
}
```
## `action` Examples
### Basic Action
This example demonstrates a simple action that prints the current date and time:
```hcl
job "example" {
# ...
group "demo" {
# ...
task "show-date" {
# ...
action "current-date" {
command = "/bin/date"
}
}
}
}
```
### Action with Arguments
Here, an action uses arguments to perform a specific task:
```hcl
job "example" {
# ...
group "demo" {
# ...
task "list-files" {
# ...
action "list-tmp" {
command = "/bin/ls"
args = ["-l", "/tmp"]
}
}
}
}
```
### Action with Template
This advanced example demonstrates an action that fetches and formats the latest
changelog from the Nomad GitHub repository using a shell script. It showcases
the use of templating with embedded environment variables and a multi-line script.
```hcl
action "fetch-latest-nomad-changelog" {
command = "/bin/sh"
args = ["-c",
<<EOT
curl -s https://raw.githubusercontent.com/hashicorp/nomad/main/CHANGELOG.md |
awk 'BEGIN{
# Setting record and field separators
RS="## "; FS="\n";
section=""; count=0
}
{
# Processing only the first 3 sections after the header
if (count < 3 && NR > 1){
# Splitting the version line into components
split($1, versionInfo, /[()]/);
version=versionInfo[1];
gsub(" ", "", version); # Removing spaces from version
releaseDate=versionInfo[2];
# Formatting URL components
urlVersion=version; gsub("\\.", "", urlVersion); # Remove dots from version
urlDate=releaseDate; gsub(" ", "-", urlDate); gsub(",", "", urlDate); # Replace spaces with hyphens and remove comma
# Counting items under each section
for(i=1; i<=NF; i++){
if($i ~ /^[A-Z ]+:$/){
gsub(":", "", $i);
section=$i;
itemCount[section]=0;
}
if(section && $i ~ /^\*/){
itemCount[section]++;
}
}
# Printing the extracted information
printf "Version: %s\nRelease Date: %s\n", version, releaseDate;
for (s in itemCount) {
printf "%d %s, ", itemCount[s], s;
}
printf "\nLink: https://github.com/hashicorp/nomad/blob/main/CHANGELOG.md#%s-%s\n\n", urlVersion, tolower(urlDate);
delete itemCount; # Clear the itemCount array for the next version
count++;
}
}'
EOT
]
}
```

View File

@@ -514,6 +514,10 @@
"title": "Overview",
"path": "commands/job"
},
{
"title": "action",
"path": "commands/job/action"
},
{
"title": "allocs",
"path": "commands/job/allocs"
@@ -1596,6 +1600,10 @@
}
]
},
{
"title": "action",
"path": "job-specification/action"
},
{
"title": "artifact",
"path": "job-specification/artifact"