class_docstr: AutoscalingConfig is the helper class to provide autoscaling
  related configs.
  
  # TODO(rickyx):
      1. Move the config validation logic here.
      2. Deprecate the ray-schema.json for validation because it's
      static thus not possible to validate the config with interdependency
      of each other.
class_docstr_tok: ["AutoscalingConfig","is","the","helper","class","to","provide","autoscaling","related","configs",".","#","TODO","(","rickyx",")",":","1",".","Move","the","config","validation","logic","here",".","2",".","Deprecate","the","ray-schema.json","for","validation","because","it's","static","thus","not","possible","to","validate","the","config","with","interdependency","of","each","other","."]
docstr: Return the docker config for the specified node type.
      If it's a head node, the image will be chosen in the following order:
          1. Node specific docker image.
          2. The 'docker' config's 'head_image' field.
          3. The 'docker' config's 'image' field.
      If it's a worker node, the image will be chosen in the following order:
          1. Node specific docker image.
          2. The 'docker' config's 'worker_image' field.
          3. The 'docker' config's 'image' field.
code: def get_docker_config(
      self, ray_node_type: NodeType
  ) -> Dict[str, Any]:
      """
      Return the docker config for the specified node type.
          If it's a head node, the image will be chosen in the following order:
              1. Node specific docker image.
              2. The 'docker' config's 'head_image' field.
              3. The 'docker' config's 'image' field.
          If it's a worker node, the image will be chosen in the following order:
              1. Node specific docker image.
              2. The 'docker' config's 'worker_image' field.
              3. The 'docker' config's 'image' field.
      """
      # TODO(rickyx): It's unfortunate we have multiple fields in ray-schema.json
      #  that can specify docker images. We should consolidate them.
      docker_config = copy.deepcopy(self._configs.get("docker", {}))
      node_specific_docker_config = self._configs[
          "available_node_types"
      ][ray_node_type].get("docker", {})
      # Override the global docker config with node specific docker config.
      docker_config.update(node_specific_docker_config)
  
      if self._configs.get("head_node_type") == ray_node_type:
          if "head_image" in docker_config:
              logger.info(
                  "Overwriting image={} by head_image({}) for head node docker.".format(  # noqa: E501
                      docker_config["image"],
                      docker_config["head_image"],
                  )
              )
              docker_config["image"] = docker_config["head_image"]
      else:
          if "worker_image" in docker_config:
              logger.info(
                  "Overwriting image={} by worker_image({}) for worker node docker.".format(  # noqa: E501
                      docker_config["image"],
                      docker_config["worker_image"],
                  )
              )
              docker_config["image"] = docker_config["worker_image"]
  
      # These fields should be merged.
      docker_config.pop("head_image", None)
      docker_config.pop("worker_image", None)
      return docker_config
  
imports: import copy
  import logging
  from abc import ABC, abstractmethod
  from dataclasses import dataclass, field
  from enum import Enum
  from pathlib import Path
  from typing import Any, Dict, List, Optional
  import yaml
  from ray.autoscaler._private.util import hash_runtime_conf, prepare_config, validate_config
  from ray.autoscaler.v2.schema import NodeType
label_desc: Use image node_id 5 for calling the AutoscalingConfig obj's underlying member method code with example usage: obj.get_docker_config(ray_node_type) and returns: docker_config