Edits history of script submission #24083 for ' List active sessions (f5_bigip)'

  • bunnative
    One script reply has been approved by the moderators
    Ap­pro­ved
    //native
    
    async function connect(auth: RT.F5Bigip): Promise<{
      base: string
      headers: { [key: string]: string }
      release: () => Promise<void>
    }> {
      const base = auth.base_url.replace(/\/+$/, "")
      if (auth.auth_method === "basic") {
        return {
          base,
          headers: {
            Authorization: `Basic ${btoa(`${auth.username}:${auth.password}`)}`,
          },
          release: async () => {},
        }
      }
      const login = await fetch(`${base}/mgmt/shared/authn/login`, {
        method: "POST",
        headers: { "Content-Type": "application/json", Accept: "application/json" },
        body: JSON.stringify({
          username: auth.username,
          password: auth.password,
          loginProviderName: auth.login_provider_name || "tmos",
        }),
      })
      if (!login.ok) {
        throw new Error(`${login.status} ${await login.text()}`)
      }
      const token: string = (await login.json()).token.token
      return {
        base,
        headers: { "X-F5-Auth-Token": token },
        release: async () => {
          await fetch(
            `${base}/mgmt/shared/authz/tokens/${encodeURIComponent(token)}`,
            {
              method: "DELETE",
              headers: { "X-F5-Auth-Token": token },
            }
          )
        },
      }
    }
    
    /**
     * List active sessions
     * List active APM access sessions (session id, logon user, client IP) from /mgmt/tm/apm/access-info. BIG-IP returns every session in one stats document; filtering by user or client IP and the limit/offset window are applied by the script.
     */
    export async function main(
      auth: RT.F5Bigip,
      logon_user: string | undefined,
      client_ip: string | undefined,
      limit: number | undefined,
      offset: number | undefined
    ) {
      const f5 = await connect(auth)
      try {
        const response = await fetch(`${f5.base}/mgmt/tm/apm/access-info`, {
          headers: { ...f5.headers, Accept: "application/json" },
        })
    
        if (!response.ok) {
          throw new Error(`${response.status} ${await response.text()}`)
        }
    
        // entries: { "https://localhost/mgmt/tm/apm/access-info/<session id>": { nestedStats: { entries: { clientIp: { description }, logonUser: { description } } } } }
        const stats = await response.json()
        const all = Object.entries(stats.entries ?? {}).map(
          ([link, value]: [string, any]) => {
            const fields = value?.nestedStats?.entries ?? {}
            return {
              session_id: new URL(link).pathname.split("/").pop() as string,
              logon_user: fields.logonUser?.description ?? null,
              client_ip: fields.clientIp?.description ?? null,
            }
          }
        )
        // Older releases list an empty placeholder entry (bug 713389); keep real sessions only.
        const sessions = all.filter(
          (s) =>
            (s.logon_user || s.client_ip) &&
            (!logon_user || s.logon_user === logon_user) &&
            (!client_ip || s.client_ip === client_ip)
        )
    
        const start = offset || 0
        const end = start + (limit || 100)
        return {
          total: sessions.length,
          sessions: sessions.slice(start, end),
          next_offset: end < sessions.length ? end : null,
        }
      } finally {
        await f5.release()
      }
    }
    

    Submitted by hugo989 7 hours ago