text: # SHORT_TIMEOUT creates a consistent short timeout of the wait_for condition.
  SHORT_TIMEOUT=5
  
  # wait_for defines the ability to wait for a given condition to happen in a
  # juju status output. The output is JSON, so everything that the API server
  # knows about should be valid.
  # The query argument is a jq query.
  #
  # ```
  # wait_for <model name> <query>
  # ```
  wait_for() {
      local name query
  
      name=${1}
      query=${2}
  
      attempt=0
      # shellcheck disable=SC2046,SC2143
      until [ "$(juju status --format=json 2> /dev/null | jq -S "${query}" | grep "${name}")" ]; do
          echo "[+] (attempt ${attempt}) polling status for" "${name}"
          juju status --relations 2>&1 | sed 's/^/    | /g'
          sleep "${SHORT_TIMEOUT}"
          attempt=$((attempt+1))
      done
  
      if [ "${attempt}" -gt 0 ]; then
          echo "[+] $(green 'Completed polling status for')" "$(green "${name}")"
          juju status --relations 2>&1 | sed 's/^/    | /g'
          # Although juju reports as an idle condition, some charms require a
          # breathe period to ensure things have actually settled.
          sleep "${SHORT_TIMEOUT}"
      fi
  }
  
  idle_condition() {
      local name app_index unit_index
  
      name=${1}
      app_index=${2:-0}
      unit_index=${3:-0}
  
      path=".[\"$name\"] | .units | .[\"$name/$unit_index\"]"
  
      echo ".applications | select(($path | .[\"juju-status\"] | .current == \"idle\") and ($path | .[\"workload-status\"] | .current != \"error\")) | keys[$app_index]"
  }
  
  idle_subordinate_condition() {
      local name parent unit_index
  
      name=${1}
      parent=${2}
      unit_index=${3:-0}
  
      path=".[\"$parent\"] | .units | .[] | .subordinates | .[\"$name/$unit_index\"]"
  
      # Print the *subordinate* name if it has an idle status in parent application
      echo ".applications | select(($path | .[\"juju-status\"] | .current == \"idle\") and ($path | .[\"workload-status\"] | .current != \"error\")) | \"$name\""
  }
  
  active_condition() {
      local name app_index unit_index
  
      name=${1}
      app_index=${2:-0}
      unit_index=${3:-0}
  
      echo ".applications | select(.[\"$name\"] | .[\"application-status\"] | .current == \"active\") | keys[$app_index]"
  }
  
  # workload_status gets the workload-status object for the unit - use
  # .current or .message to select the actual field you need.
  workload_status() {
      local app unit
  
      app=$1
      unit=$2
  
      echo ".applications[\"$app\"].units[\"$app/$unit\"][\"workload-status\"]"
  }
  
  # agent_status gets the juju-status object for the unit - use
  # .current or .message to select the actual field you need.
  agent_status() {
      local app unit
  
      app=$1
      unit=$2
  
      echo ".applications[\"$app\"].units[\"$app/$unit\"][\"juju-status\"]"
  }
  
  # charm_rev gets the current juju-status object for the application and uses it
  # to find the application charm-rev.
  charm_rev() {
      local app rev
  
      app=$1
      rev=${2:-0}
  
      echo ".applications | select(.[\"$app\"] | .[\"charm-rev\"] == $rev)"
  }
  
  # wait_for_machine_agent_status blocks until the machine agent for the specified
  # machine instance ID reports the requested status.
  #
  # ```
  # wait_for_machine_agent_status <instance-id> <status>
  #
  # example:
  # wait_for_machine_agent_status "i-1234" "started"
  # ```
  wait_for_machine_agent_status() {
      local inst_id status
  
      inst_id=${1}
      status=${2}
  
      attempt=0
      # shellcheck disable=SC2046,SC2143
      until [ $(juju show-machine --format json | jq -r ".[\"machines\"] | .[\"${inst_id}\"] | .[\"juju-status\"] | .[\"current\"]" | grep "${status}") ]; do
          echo "[+] (attempt ${attempt}) polling machines"
          juju machines | grep "$inst_id" 2>&1 | sed 's/^/    | /g'
          sleep "${SHORT_TIMEOUT}"
          attempt=$((attempt+1))
      done
  
      if [ "${attempt}" -gt 0 ]; then
          echo "[+] $(green 'Completed polling machines')"
          juju machines | grep "$inst_id" 2>&1 | sed 's/^/    | /g'
          sleep "${SHORT_TIMEOUT}"
      fi
  }
  
  # wait_for_machine_netif_count blocks until the number of detected network
  # interfaces for the requested machine instance ID becomes equal to the desired
  # value.
  #
  # ```
  # wait_for_machine_netif_count <instance-id> <count>
  #
  # example:
  # wait_for_machine_netif_count "i-1234" "42"
  # ```
  wait_for_machine_netif_count() {
      local inst_id count
  
      inst_id=${1}
      count=${2}
  
      attempt=0
      # shellcheck disable=SC2046,SC2143
      until [ $(juju show-machine --format json | jq -r ".[\"machines\"] | .[\"${inst_id}\"] | .[\"network-interfaces\"] | length" | grep "${count}") ]; do
          # shellcheck disable=SC2046,SC2143
          echo "[+] (attempt ${attempt}) network interface count for instance ${inst_id} = "$(juju show-machine --format json | jq -r ".[\"machines\"] | .[\"${inst_id}\"] | .[\"network-interfaces\"] | length")
          sleep "${SHORT_TIMEOUT}"
          attempt=$((attempt+1))
      done
  }
  
  # wait_for_model blocks until a model appears
  # interfaces for the requested machine instance ID becomes equal to the desired
  # value.
  #
  # ```
  # wait_for_model <name>
  #
  # example:
  # wait_for_model "default"
  # ```
  wait_for_model() {
      local name
  
      name=${1}
  
      attempt=0
      # shellcheck disable=SC2046,SC2143
      until [ $(juju models --format=json | jq -r ".models | .[] | select(.[\"short-name\"] == \"${name}\") | .[\"short-name\"]" | grep "${name}") ]; do
          echo "[+] (attempt ${attempt}) polling models"
          juju models | sed 's/^/    | /g'
          sleep "${SHORT_TIMEOUT}"
          attempt=$((attempt+1))
      done
  
      if [ "${attempt}" -gt 0 ]; then
          echo "[+] $(green 'Completed polling models')"
          juju models | sed 's/^/    | /g'
          sleep "${SHORT_TIMEOUT}"
      fi
  }
  