code: def get_loader(templates_dir, os_release):
      
      tmpl_dirs = [(rel, os.path.join(templates_dir, rel))
                   for rel in six.itervalues(OPENSTACK_CODENAMES)]
  
      if not os.path.isdir(templates_dir):
          log('Templates directory not found @ %s.' % templates_dir,
              level=ERROR)
          raise OSConfigException
  
      # the bottom contains tempaltes_dir and possibly a common templates dir
      # shipped with the helper.
      loaders = [FileSystemLoader(templates_dir)]
      helper_templates = os.path.join(os.path.dirname(__file__), 'templates')
      if os.path.isdir(helper_templates):
          loaders.append(FileSystemLoader(helper_templates))
  
      for rel, tmpl_dir in tmpl_dirs:
          if os.path.isdir(tmpl_dir):
              loaders.insert(0, FileSystemLoader(tmpl_dir))
          if rel == os_release:
              break
      # demote this log to the lowest level; we don't really need to see these
      # lots in production even when debugging.
      log('Creating choice loader with dirs: %s' %
          [l.searchpath for l in loaders], level=TRACE)
      return ChoiceLoader(loaders)
docs: Create a jinja2.ChoiceLoader containing template dirs up to
      and including os_release.  If directory template directory
      is missing at templates_dir, it will be omitted from the loader.
      templates_dir is added to the bottom of the search list as a base
      loading dir.
  
      A charm may also ship a templates dir with this module
      and it will be appended to the bottom of the search list, eg::
  
          hooks/charmhelpers/contrib/openstack/templates
  
      :param templates_dir (str): Base template directory containing release
          sub-directories.
      :param os_release (str): OpenStack release codename to construct template
          loader.
      :returns: jinja2.ChoiceLoader constructed with a list of
          jinja2.FilesystemLoaders, ordered in descending
          order by OpenStack release.