1 | |
2 |
|
3 | |
4 | * List tasks |
5 | * List provisioning tasks (legacy Network Provisioning API), pending ones by default. Each task has its workOrderId, the device it targets and its workOrderUserDefinedStatus (Pending, Completed, Failed, Cancelled). CloudVision pages them by index: end_index 0 returns all of them. |
6 | */ |
7 | export async function main( |
8 | auth: RT.AristaCloudvision, |
9 | status: "Pending" | "Completed" | "Failed" | "Cancelled" | "All" = "Pending", |
10 | start_index: number = 0, |
11 | end_index: number = 0 |
12 | ) { |
13 | const query = status === "All" ? "" : status || "Pending" |
14 | return await cv( |
15 | auth, |
16 | `/cvpservice/task/getTasks.do?queryparam=${encodeURIComponent(query)}&startIndex=${start_index ?? 0}&endIndex=${end_index ?? 0}` |
17 | ) |
18 | } |
19 |
|
20 | |
21 | |
22 | async function cv( |
23 | auth: RT.AristaCloudvision, |
24 | path: string, |
25 | options: { body?: unknown; notFound?: string; optional?: boolean } = {} |
26 | ): Promise<any> { |
27 | const url = new URL(path, auth.base_url) |
28 | |
29 | |
30 | |
31 | const cvaas = auth.deployment |
32 | ? auth.deployment === "cvaas" |
33 | : /(^|\.)arista\.io\.?$/i.test(url.hostname) |
34 | if (!cvaas && url.pathname.startsWith("/cvpservice/")) { |
35 | url.pathname = url.pathname.replace(/^\/cvpservice\//, "/web/") |
36 | } |
37 | const response = await fetch(url, { |
38 | method: options.body === undefined ? "GET" : "POST", |
39 | headers: { |
40 | Authorization: `Bearer ${auth.token}`, |
41 | ...(options.body === undefined |
42 | ? {} |
43 | : { "Content-Type": "application/json" }), |
44 | Accept: "application/json", |
45 | }, |
46 | body: options.body === undefined ? undefined : JSON.stringify(options.body), |
47 | }) |
48 | const text = await response.text() |
49 | if ( |
50 | response.status === 401 || |
51 | response.status === 403 || |
52 | (!response.ok && text.includes("User is unauthorized")) |
53 | ) { |
54 | throw new Error( |
55 | `CloudVision refused the token (HTTP ${response.status}): check that the service-account token is valid, not expired, and that its role allows this call. ${text}` |
56 | ) |
57 | } |
58 | const data = |
59 | text.trim() === "" |
60 | ? {} |
61 | : /^\s*[[{]/.test(text) |
62 | ? JSON.parse(text) |
63 | : undefined |
64 | const error = findError(data) |
65 | if (response.ok && data !== undefined && !error) return data |
66 | const detail = error |
67 | ? `${error.errorCode} ${error.errorMessage ?? (error.errors ?? []).join("; ")}` |
68 | : `HTTP ${response.status} ${text.slice(0, 500)}` |
69 | |
70 | |
71 | if ( |
72 | response.status === 404 || |
73 | (error && (options.optional || options.notFound)) |
74 | ) { |
75 | if (options.optional) return undefined |
76 | if (options.notFound) throw new Error(`${options.notFound} (${detail})`) |
77 | } |
78 | if (response.ok && !error) { |
79 | throw new Error( |
80 | `CloudVision returned a non-JSON response for ${url.pathname}: check that base_url is the CloudVision address. ${detail}` |
81 | ) |
82 | } |
83 | throw new Error(`CloudVision ${url.pathname} failed: ${detail}`) |
84 | } |
85 |
|
86 | function findError(value: any): any { |
87 | if (!value || typeof value !== "object") return undefined |
88 | |
89 | if (!Array.isArray(value) && value.errorCode) return value |
90 | for (const item of Object.values(value)) { |
91 | const error = findError(item) |
92 | if (error) return error |
93 | } |
94 | return undefined |
95 | } |
96 |
|