class_docstr: Resource Spec.
  
  Contains node and SSH information found by parsing a `resource_spec.yml`.
  
  # TODO: Make it a real Graph (a clique), with edge weights being network bandwidth.
      This would allow for even more intelligent strategy generation.
class_docstr_tok: ["Resource","Spec",".","Contains","node","and","SSH","information","found","by","parsing","a","`","resource_spec.yml","`",".","#","TODO",":","Make","it","a","real","Graph","(","a","clique",")",",","with","edge","weights","being","network","bandwidth",".","This","would","allow","for","even","more","intelligent","strategy","generation","."]
code: def _parse_node(self, node, num_nodes):
      host_address = node["address"]
      if is_loopback_address(host_address) and num_nodes > 1:
          raise ValueError(
              "Can't (currently) use a loopback address when there are multiple nodes."
          )
      if node.get("chief") or num_nodes == 1:
          # 2 cases for marking this node as chief:
          # 1) The node was marked as chief
          # 2) If there is only one node, it is chief by default
          logging.info("Chief: %s" % host_address)
          self.__chief_address = host_address
      host_cpu = DeviceSpec(host_address, device_index=0)
      self._add_device(host_cpu)
      # handle any other CPUs when GPU is unavailable
      if len(node.get("gpus", [])) == 0:
          for cpu_index in set(sorted(node.get("cpus", []))) - {0}:
              cpu = DeviceSpec(
                  host_address, host_cpu, DeviceType.CPU, cpu_index
              )
              self._add_device(cpu)
      # handle GPUs
      for gpu_index in set(sorted(node.get("gpus", []))):
          gpu = DeviceSpec(
              host_address, host_cpu, DeviceType.GPU, gpu_index
          )
          self._add_device(gpu)
      self.__ssh_group[host_address] = node.get("ssh_config")
      if (
          self.__ssh_group[host_address] is None
          and self.__chief_address != host_address
      ):
          raise ValueError(
              "Need to define SSH groups for all non-chief nodes."
          )
      # handle network bandwidth (optional)
      if node.get("network_bandwidth"):
          self.__network_bandwidth[host_address] = node.get(
              "network_bandwidth"
          )
      else:
          logging.debug(
              "The bandwidth for {} is undefined and set as default (1 GBE). "
              "Caution: AutoStrategy might be inaccurate.".format(
                  host_address
              )
          )
          self.__network_bandwidth[host_address] = 1
  
imports: import os
  import re
  from enum import Enum
  from typing import NamedTuple, Optional, Dict
  import yaml
  import paramiko
  from autodist.utils import logging
  from autodist.utils.network import is_loopback_address, is_local_address
label_desc: Use image node_id 16 for calling the ResourceSpec obj's underlying member method code with example usage: obj._parse_node(node, num_nodes) without return types