docs: def cloud_config(path=None, env_var='SALT_CLOUD_CONFIG', defaults=None,
                   master_config_path=None, master_config=None,
                   providers_config_path=None, providers_config=None,
                   profiles_config_path=None, profiles_config=None):
      '''
      Read in the Salt Cloud config and return the dict
      '''
      if path:
          config_dir = os.path.dirname(path)
      else:
          config_dir = salt.syspaths.CONFIG_DIR
  
      # Load the cloud configuration
      overrides = load_config(
          path,
          env_var,
          os.path.join(config_dir, 'cloud')
      )
  
      if defaults is None:
          defaults = DEFAULT_CLOUD_OPTS.copy()
  
      # Set defaults early to override Salt Master's default config values later
      defaults.update(overrides)
      overrides = defaults
  
      # Load cloud configuration from any default or provided includes
      overrides.update(
          salt.config.include_config(overrides['default_include'], config_dir, verbose=False)
      )
      include = overrides.get('include', [])
      overrides.update(
          salt.config.include_config(include, config_dir, verbose=True)
      )
  
      # The includes have been evaluated, let's see if master, providers and
      # profiles configuration settings have been included and if not, set the
      # default value
      if 'master_config' in overrides and master_config_path is None:
          # The configuration setting is being specified in the main cloud
          # configuration file
          master_config_path = overrides['master_config']
      elif 'master_config' not in overrides and not master_config \
              and not master_config_path:
          # The configuration setting is not being provided in the main cloud
          # configuration file, and
          master_config_path = os.path.join(config_dir, 'master')
  
      # Convert relative to absolute paths if necessary
      master_config_path = _absolute_path(master_config_path, config_dir)
  
      if 'providers_config' in overrides and providers_config_path is None:
          # The configuration setting is being specified in the main cloud
          # configuration file
          providers_config_path = overrides['providers_config']
      elif 'providers_config' not in overrides and not providers_config \
              and not providers_config_path:
          providers_config_path = os.path.join(config_dir, 'cloud.providers')
  
      # Convert relative to absolute paths if necessary
      providers_config_path = _absolute_path(providers_config_path, config_dir)
  
      if 'profiles_config' in overrides and profiles_config_path is None:
          # The configuration setting is being specified in the main cloud
          # configuration file
          profiles_config_path = overrides['profiles_config']
      elif 'profiles_config' not in overrides and not profiles_config \
              and not profiles_config_path:
          profiles_config_path = os.path.join(config_dir, 'cloud.profiles')
  
      # Convert relative to absolute paths if necessary
      profiles_config_path = _absolute_path(profiles_config_path, config_dir)
  
      # Prepare the deploy scripts search path
      deploy_scripts_search_path = overrides.get(
          'deploy_scripts_search_path',
          defaults.get('deploy_scripts_search_path', 'cloud.deploy.d')
      )
      if isinstance(deploy_scripts_search_path, six.string_types):
          deploy_scripts_search_path = [deploy_scripts_search_path]
  
      # Check the provided deploy scripts search path removing any non existing
      # entries.
      for idx, entry in enumerate(deploy_scripts_search_path[:]):
          if not os.path.isabs(entry):
              # Let's try adding the provided path's directory name turns the
              # entry into a proper directory
              entry = os.path.join(config_dir, entry)
  
          if os.path.isdir(entry):
              # Path exists, let's update the entry (its path might have been
              # made absolute)
              deploy_scripts_search_path[idx] = entry
              continue
  
          # It's not a directory? Remove it from the search path
          deploy_scripts_search_path.pop(idx)
  
      # Add the built-in scripts directory to the search path (last resort)
      deploy_scripts_search_path.append(
          os.path.abspath(
              os.path.join(
                  os.path.dirname(__file__),
                  '..',
                  'cloud',
                  'deploy'
              )
          )
      )
  
      # Let's make the search path a tuple and add it to the overrides.
      overrides.update(
          deploy_scripts_search_path=tuple(deploy_scripts_search_path)
      )
  
      # Grab data from the 4 sources
      # 1st - Master config
      if master_config_path is not None and master_config is not None:
          raise salt.exceptions.SaltCloudConfigError(
              'Only pass `master_config` or `master_config_path`, not both.'
          )
      elif master_config_path is None and master_config is None:
          master_config = salt.config.master_config(
              overrides.get(
                  # use the value from the cloud config file
                  'master_config',
                  # if not found, use the default path
                  os.path.join(salt.syspaths.CONFIG_DIR, 'master')
              )
          )
      elif master_config_path is not None and master_config is None:
          master_config = salt.config.master_config(master_config_path)
  
      # cloud config has a separate cachedir
      del master_config['cachedir']
  
      # 2nd - salt-cloud configuration which was loaded before so we could
      # extract the master configuration file if needed.
  
      # Override master configuration with the salt cloud(current overrides)
      master_config.update(overrides)
      # We now set the overridden master_config as the overrides
      overrides = master_config
  
      if providers_config_path is not None and providers_config is not None:
          raise salt.exceptions.SaltCloudConfigError(
              'Only pass `providers_config` or `providers_config_path`, '
              'not both.'
          )
      elif providers_config_path is None and providers_config is None:
          providers_config_path = overrides.get(
              # use the value from the cloud config file
              'providers_config',
              # if not found, use the default path
              os.path.join(salt.syspaths.CONFIG_DIR, 'cloud.providers')
          )
  
      if profiles_config_path is not None and profiles_config is not None:
          raise salt.exceptions.SaltCloudConfigError(
              'Only pass `profiles_config` or `profiles_config_path`, not both.'
          )
      elif profiles_config_path is None and profiles_config is None:
          profiles_config_path = overrides.get(
              # use the value from the cloud config file
              'profiles_config',
              # if not found, use the default path
              os.path.join(salt.syspaths.CONFIG_DIR, 'cloud.profiles')
          )
  
      # Apply the salt-cloud configuration
      opts = apply_cloud_config(overrides, defaults)
  
      # 3rd - Include Cloud Providers
      if 'providers' in opts:
          if providers_config is not None:
              raise salt.exceptions.SaltCloudConfigError(
                  'Do not mix the old cloud providers configuration with '
                  'the passing a pre-configured providers configuration '
                  'dictionary.'
              )
  
          if providers_config_path is not None:
              providers_confd = os.path.join(
                  os.path.dirname(providers_config_path),
                  'cloud.providers.d', '*'
              )
  
              if (os.path.isfile(providers_config_path) or
                      glob.glob(providers_confd)):
                  raise salt.exceptions.SaltCloudConfigError(
                      'Do not mix the old cloud providers configuration with '
                      'the new one. The providers configuration should now go '
                      'in the file `{0}` or a separate `*.conf` file within '
                      '`cloud.providers.d/` which is relative to `{0}`.'.format(
                          os.path.join(salt.syspaths.CONFIG_DIR, 'cloud.providers')
                      )
                  )
          # No exception was raised? It's the old configuration alone
          providers_config = opts['providers']
  
      elif providers_config_path is not None:
          # Load from configuration file, even if that files does not exist since
          # it will be populated with defaults.
          providers_config = cloud_providers_config(providers_config_path)
  
      # Let's assign back the computed providers configuration
      opts['providers'] = providers_config
  
      # 4th - Include VM profiles config
      if profiles_config is None:
          # Load profiles configuration from the provided file
          profiles_config = vm_profiles_config(profiles_config_path,
                                               providers_config)
      opts['profiles'] = profiles_config
  
      # recurse opts for sdb configs
      apply_sdb(opts)
  
      # prepend root_dir
      prepend_root_dirs = ['cachedir']
      if 'log_file' in opts and urlparse(opts['log_file']).scheme == '':
          prepend_root_dirs.append(opts['log_file'])
      prepend_root_dir(opts, prepend_root_dirs)
  
      # Return the final options
      return opts