0

Get device

by
Published today

Get one device from the CloudVision inventory (resource API inventory.v1) by its device ID, which is its serial number: model, EOS version, hostname, system MAC address, boot time and telemetry streaming status.

Script arista_cloudvision Verified

The script

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

3
/**
4
 * Get device
5
 * Get one device from the CloudVision inventory (resource API inventory.v1) by its device ID, which is its serial number: model, EOS version, hostname, system MAC address, boot time and telemetry streaming status.
6
 */
7
export async function main(auth: RT.AristaCloudvision, device_id: string) {
8
  const result = await cv(
9
    auth,
10
    `/api/resources/inventory/v1/Device?key.deviceId=${encodeURIComponent(device_id)}`,
11
    { notFound: `Device ${device_id} not found in CloudVision inventory` }
12
  )
13
  return result.value
14
}
15

16
// Calls CloudVision and turns its failures into readable errors.
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
  const response = await fetch(url, {
24
    method: options.body === undefined ? "GET" : "POST",
25
    headers: {
26
      Authorization: `Bearer ${auth.token}`,
27
      ...(options.body === undefined
28
        ? {}
29
        : { "Content-Type": "application/json" }),
30
      Accept: "application/json",
31
    },
32
    body: options.body === undefined ? undefined : JSON.stringify(options.body),
33
  })
34
  const text = await response.text()
35
  if (
36
    response.status === 401 ||
37
    response.status === 403 ||
38
    (!response.ok && text.includes("User is unauthorized"))
39
  ) {
40
    throw new Error(
41
      `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}`
42
    )
43
  }
44
  const data =
45
    text.trim() === ""
46
      ? {}
47
      : /^\s*[[{]/.test(text)
48
        ? JSON.parse(text)
49
        : undefined
50
  const error = findError(data)
51
  if (response.ok && data !== undefined && !error) return data
52
  const detail = error
53
    ? `${error.errorCode} ${error.errorMessage ?? (error.errors ?? []).join("; ")}`
54
    : `HTTP ${response.status} ${text.slice(0, 500)}`
55
  // Legacy lookups answer an unknown name or ID with an errorCode (cvprac
56
  // treats any error from getTaskById and getImageBundleByName that way).
57
  if (
58
    response.status === 404 ||
59
    (error && (options.optional || options.notFound))
60
  ) {
61
    if (options.optional) return undefined
62
    if (options.notFound) throw new Error(`${options.notFound} (${detail})`)
63
  }
64
  if (response.ok && !error) {
65
    throw new Error(
66
      `CloudVision returned a non-JSON response for ${url.pathname}: check that base_url is the CloudVision address. ${detail}`
67
    )
68
  }
69
  throw new Error(`CloudVision ${url.pathname} failed: ${detail}`)
70
}
71

72
function findError(value: any): any {
73
  if (!value || typeof value !== "object") return undefined
74
  // Like cvprac, only a truthy errorCode counts, at any depth.
75
  if (!Array.isArray(value) && value.errorCode) return value
76
  for (const item of Object.values(value)) {
77
    const error = findError(item)
78
    if (error) return error
79
  }
80
  return undefined
81
}
82