0

List configlets

by
Published today

List the provisioning configlets (legacy Network Provisioning API) with their key, name, type and config. CloudVision pages them by index: end_index 0 returns all of them.

Script arista_cloudvision Verified

The script

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

3
/**
4
 * List configlets
5
 * List the provisioning configlets (legacy Network Provisioning API) with their key, name, type and config. 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/configlet/getConfiglets.do?startIndex=${start_index ?? 0}&endIndex=${end_index ?? 0}`
15
  )
16
}
17

18
// Calls CloudVision and turns its failures into readable errors. Legacy
19
// endpoints report errors as HTTP 200 with an errorCode field.
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
  // cvprac sends legacy endpoints to /cvpservice on CVaaS and /web on
27
  // on-premises CVP. Its is_cvaas flag is the resource's deployment field;
28
  // when that is unset, a host under arista.io is taken as CVaaS.
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
  // Legacy lookups answer an unknown name or ID with an errorCode (cvprac
68
  // treats any error from getTaskById and getImageBundleByName that way).
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
  // Like cvprac, only a truthy errorCode counts, at any depth.
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