0

Get configlet

by
Published today

Get one provisioning configlet (legacy Network Provisioning API) by name, with its key and config.

Script arista_cloudvision Verified

The script

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

3
/**
4
 * Get configlet
5
 * Get one provisioning configlet (legacy Network Provisioning API) by name, with its key and config.
6
 */
7
export async function main(auth: RT.AristaCloudvision, name: string) {
8
  return await cv(
9
    auth,
10
    `/cvpservice/configlet/getConfigletByName.do?name=${encodeURIComponent(name)}`,
11
    { notFound: `Configlet ${name} not found` }
12
  )
13
}
14

15
// Calls CloudVision and turns its failures into readable errors. Legacy
16
// endpoints report errors as HTTP 200 with an errorCode field.
17
async function cv(
18
  auth: RT.AristaCloudvision,
19
  path: string,
20
  options: { body?: unknown; notFound?: string; optional?: boolean } = {}
21
): Promise<any> {
22
  const url = new URL(path, auth.base_url)
23
  // cvprac sends legacy endpoints to /cvpservice on CVaaS and /web on
24
  // on-premises CVP. Its is_cvaas flag is the resource's deployment field;
25
  // when that is unset, a host under arista.io is taken as CVaaS.
26
  const cvaas = auth.deployment
27
    ? auth.deployment === "cvaas"
28
    : /(^|\.)arista\.io\.?$/i.test(url.hostname)
29
  if (!cvaas && url.pathname.startsWith("/cvpservice/")) {
30
    url.pathname = url.pathname.replace(/^\/cvpservice\//, "/web/")
31
  }
32
  const response = await fetch(url, {
33
    method: options.body === undefined ? "GET" : "POST",
34
    headers: {
35
      Authorization: `Bearer ${auth.token}`,
36
      ...(options.body === undefined
37
        ? {}
38
        : { "Content-Type": "application/json" }),
39
      Accept: "application/json",
40
    },
41
    body: options.body === undefined ? undefined : JSON.stringify(options.body),
42
  })
43
  const text = await response.text()
44
  if (
45
    response.status === 401 ||
46
    response.status === 403 ||
47
    (!response.ok && text.includes("User is unauthorized"))
48
  ) {
49
    throw new Error(
50
      `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}`
51
    )
52
  }
53
  const data =
54
    text.trim() === ""
55
      ? {}
56
      : /^\s*[[{]/.test(text)
57
        ? JSON.parse(text)
58
        : undefined
59
  const error = findError(data)
60
  if (response.ok && data !== undefined && !error) return data
61
  const detail = error
62
    ? `${error.errorCode} ${error.errorMessage ?? (error.errors ?? []).join("; ")}`
63
    : `HTTP ${response.status} ${text.slice(0, 500)}`
64
  // Legacy lookups answer an unknown name or ID with an errorCode (cvprac
65
  // treats any error from getTaskById and getImageBundleByName that way).
66
  if (
67
    response.status === 404 ||
68
    (error && (options.optional || options.notFound))
69
  ) {
70
    if (options.optional) return undefined
71
    if (options.notFound) throw new Error(`${options.notFound} (${detail})`)
72
  }
73
  if (response.ok && !error) {
74
    throw new Error(
75
      `CloudVision returned a non-JSON response for ${url.pathname}: check that base_url is the CloudVision address. ${detail}`
76
    )
77
  }
78
  throw new Error(`CloudVision ${url.pathname} failed: ${detail}`)
79
}
80

81
function findError(value: any): any {
82
  if (!value || typeof value !== "object") return undefined
83
  // Like cvprac, only a truthy errorCode counts, at any depth.
84
  if (!Array.isArray(value) && value.errorCode) return value
85
  for (const item of Object.values(value)) {
86
    const error = findError(item)
87
    if (error) return error
88
  }
89
  return undefined
90
}
91