Edits history of script submission #24191 for ' Get zone (infoblox_nios)'

  • bunnative
    One script reply has been approved by the moderators
    Ap­pro­ved
    //native
    
    function wapiUrl(auth: RT.InfobloxNios, path: string) {
      const host = auth.host
        .trim()
        .replace(/^https?:\/\//, "")
        .replace(/\/+$/, "")
      const version = auth.wapi_version.trim().replace(/^v/, "")
      return new URL(`https://${host}/wapi/v${version}/${path}`)
    }
    
    function basicAuth(auth: RT.InfobloxNios) {
      const bytes = new TextEncoder().encode(`${auth.username}:${auth.password}`)
      return `Basic ${btoa(String.fromCharCode(...bytes))}`
    }
    
    async function wapiError(response: Response) {
      const text = await response.text()
      if (response.status === 401) {
        return new Error(
          "401 Unauthorized: wrong username or password, or the user's admin group has no API access"
        )
      }
      try {
        // WAPI errors are JSON: {"Error": "AdmConDataNotFoundError: ...", "code": "Client.Ibap.Data.NotFound", "text": "..."}
        const { Error: error, code, text: detail } = JSON.parse(text)
        if (error) {
          const message =
            detail && !error.includes(detail) ? `${error}: ${detail}` : error
          return new Error(
            `${response.status} ${message}${code ? ` (${code})` : ""}`
          )
        }
      } catch {}
      return new Error(`${response.status} ${text}`)
    }
    
    /**
     * Get zone
     * Return the authoritative zone (zone_auth) that contains a DNS name: the zone named fqdn itself, or else its closest parent zone (app.prod.example.com → prod.example.com → example.com). Fails when Infoblox is authoritative for none of them. Forward names only: reverse zones are listed by CIDR in List zones. Set view when the zone exists in several DNS views.
     */
    export async function main(
      auth: RT.InfobloxNios,
      fqdn: string,
      view: string | undefined
    ) {
      const name = fqdn.trim().toLowerCase().replace(/\.$/, "")
      if (!name) throw new Error("fqdn is required")
      if (/\.(in-addr|ip6)\.arpa$/.test(name)) {
        throw new Error(
          "Reverse zones are named by CIDR in NIOS (e.g. 10.20.0.0/24): use List zones with zone_format IPV4 or IPV6"
        )
      }
      const labels = name.split(".")
    
      // Walk up one label at a time; the first hit is the closest enclosing zone.
      for (let i = 0; i < labels.length; i++) {
        const candidate = labels.slice(i).join(".")
        const url = wapiUrl(auth, "zone_auth")
        url.searchParams.append("fqdn", candidate)
        if (view) url.searchParams.append("view", view)
        url.searchParams.append(
          "_return_fields+",
          "zone_format,comment,disable,ns_group,extattrs"
        )
        url.searchParams.append("_return_as_object", "1")
    
        const response = await fetch(url, {
          headers: {
            Authorization: basicAuth(auth),
            Accept: "application/json",
          },
        })
        if (!response.ok) {
          throw await wapiError(response)
        }
        const { result } = (await response.json()) as {
          result: { _ref: string; fqdn: string; view: string }[]
        }
        if (result.length > 1) {
          throw new Error(
            `Zone ${candidate} exists in several DNS views (${result.map((z) => z.view).join(", ")}); set view`
          )
        }
        if (result.length === 1) return result[0]
      }
    
      throw new Error(
        `No authoritative zone found for ${fqdn}${view ? ` in view ${view}` : ""}`
      )
    }
    

    Submitted by hugo989 3 hours ago