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