0

Get job stdout

by
Published today

Get the Ansible output of a job as text or JSON.

Script awx Verified

The script

Submitted by hugo989 Typescript (fetch-only)
Verified 3 hours ago
1
//native
2

3
/**
4
 * Get job stdout
5
 * Get the Ansible output of a job. txt_download (default) returns the full plain text at any size; ansi_download keeps the color codes. txt, ansi and json return a "Standard Output too large to display" message instead of the output above the controller's display limit. json returns { range, content } and is the only format that applies start_line and end_line.
6
 */
7
export async function main(
8
  auth: RT.Awx,
9
  job_id: number,
10
  format:
11
    | "txt_download"
12
    | "txt"
13
    | "ansi"
14
    | "ansi_download"
15
    | "json"
16
    | undefined,
17
  start_line: number | undefined,
18
  end_line: number | undefined
19
) {
20
  const outputFormat = format || "txt_download"
21
  const url = new URL(`${apiRoot(auth)}/jobs/${job_id}/stdout/`)
22
  url.searchParams.append("format", outputFormat)
23
  // The controller reads start_line/end_line only for the json format.
24
  if (outputFormat === "json" && start_line != null) {
25
    url.searchParams.append("start_line", String(start_line))
26
  }
27
  if (outputFormat === "json" && end_line != null) {
28
    url.searchParams.append("end_line", String(end_line))
29
  }
30

31
  const response = await fetch(url, {
32
    headers: {
33
      Authorization: authorization(auth),
34
      Accept: outputFormat === "json" ? "application/json" : "text/plain",
35
    },
36
  })
37

38
  if (!response.ok) {
39
    throw new Error(`${response.status} ${await response.text()}`)
40
  }
41

42
  return outputFormat === "json" ? await response.json() : await response.text()
43
}
44

45
function apiRoot(auth: RT.Awx) {
46
  const path = (auth.api_path || "/api/v2").replace(/^\/+|\/+$/g, "")
47
  // Tolerate a base_url pasted with the API path already on it.
48
  const base = auth.base_url
49
    .replace(/\/+$/, "")
50
    .replace(new RegExp(`/${path}$`), "")
51
  return `${base}/${path}`
52
}
53

54
function authorization(auth: RT.Awx) {
55
  if (auth.token) {
56
    return `Bearer ${auth.token}`
57
  }
58
  if (auth.username) {
59
    const bytes = new TextEncoder().encode(
60
      `${auth.username}:${auth.password ?? ""}`
61
    )
62
    return `Basic ${btoa(String.fromCharCode(...bytes))}`
63
  }
64
  throw new Error(
65
    "The AWX resource needs either a token or a username and password"
66
  )
67
}
68