0

Cancel job

by
Published today

Cancel a pending or running job or workflow job.

Script awx Verified

The script

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

3
/**
4
 * Cancel job
5
 * Cancel a pending or running job or workflow job. Checks can_cancel first: a job that already finished is left alone and returned with canceled false. Set job_type to workflow_job for a workflow job id.
6
 */
7
export async function main(
8
  auth: RT.Awx,
9
  job_id: number,
10
  job_type: "job" | "workflow_job" | undefined
11
) {
12
  const collection = job_type === "workflow_job" ? "workflow_jobs" : "jobs"
13
  const url = new URL(`${apiRoot(auth)}/${collection}/${job_id}/cancel/`)
14

15
  const check = await fetch(url, {
16
    headers: {
17
      Authorization: authorization(auth),
18
      Accept: "application/json",
19
    },
20
  })
21
  if (!check.ok) {
22
    throw new Error(`${check.status} ${await check.text()}`)
23
  }
24
  const { can_cancel } = (await check.json()) as { can_cancel: boolean }
25
  if (!can_cancel) {
26
    return { job_id, job_type: job_type || "job", canceled: false }
27
  }
28

29
  const response = await fetch(url, {
30
    method: "POST",
31
    headers: {
32
      Authorization: authorization(auth),
33
      "Content-Type": "application/json",
34
      Accept: "application/json",
35
    },
36
    body: JSON.stringify({}),
37
  })
38

39
  // 405: the job finished between the check and the cancel.
40
  if (response.status === 405) {
41
    return { job_id, job_type: job_type || "job", canceled: false }
42
  }
43
  if (!response.ok) {
44
    throw new Error(`${response.status} ${await response.text()}`)
45
  }
46

47
  return { job_id, job_type: job_type || "job", canceled: true }
48
}
49

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

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