docs: def call_id_function(opts):
      '''
      Evaluate the function that determines the ID if the 'id_function'
      option is set and return the result
      '''
      if opts.get('id'):
          return opts['id']
  
      # Import 'salt.loader' here to avoid a circular dependency
      import salt.loader as loader
  
      if isinstance(opts['id_function'], six.string_types):
          mod_fun = opts['id_function']
          fun_kwargs = {}
      elif isinstance(opts['id_function'], dict):
          mod_fun, fun_kwargs = six.next(six.iteritems(opts['id_function']))
          if fun_kwargs is None:
              fun_kwargs = {}
      else:
          log.error('\'id_function\' option is neither a string nor a dictionary')
          sys.exit(salt.defaults.exitcodes.EX_GENERIC)
  
      # split module and function and try loading the module
      mod, fun = mod_fun.split('.')
      if not opts.get('grains'):
          # Get grains for use by the module
          opts['grains'] = loader.grains(opts)
  
      try:
          id_mod = loader.raw_mod(opts, mod, fun)
          if not id_mod:
              raise KeyError
          # we take whatever the module returns as the minion ID
          newid = id_mod[mod_fun](**fun_kwargs)
          if not isinstance(newid, six.string_types) or not newid:
              log.error(
                  'Function %s returned value "%s" of type %s instead of string',
                  mod_fun, newid, type(newid)
              )
              sys.exit(salt.defaults.exitcodes.EX_GENERIC)
          log.info('Evaluated minion ID from module: %s', mod_fun)
          return newid
      except TypeError:
          log.error(
              'Function arguments %s are incorrect for function %s',
              fun_kwargs, mod_fun
          )
          sys.exit(salt.defaults.exitcodes.EX_GENERIC)
      except KeyError:
          log.error('Failed to load module %s', mod_fun)
          sys.exit(salt.defaults.exitcodes.EX_GENERIC)