示例#1
0
def template_from_string(basedir, data, vars, fail_on_undefined=False):
    ''' run a string through the (Jinja2) templating engine '''

    try:
        if type(data) == str:
            data = unicode(data, 'utf-8')

        def my_finalize(thing):
            return thing if thing is not None else ''

        environment = jinja2.Environment(trim_blocks=True,
                                         undefined=StrictUndefined,
                                         extensions=_get_extensions(),
                                         finalize=my_finalize)
        environment.filters.update(_get_filters())
        environment.template_class = J2Template

        if '_original_file' in vars:
            basedir = os.path.dirname(vars['_original_file'])
            filesdir = os.path.abspath(os.path.join(basedir, '..', 'files'))
            if os.path.exists(filesdir):
                basedir = filesdir

        data = data.decode('utf-8')
        try:
            t = environment.from_string(data)
        except Exception, e:
            if 'recursion' in str(e):
                raise errors.AnsibleError(
                    "recursive loop detected in template string: %s" % data)
            elif isinstance(e, TemplateSyntaxError):
                raise errors.AnsibleError(
                    "there was an error in the template: %s" % data)
            else:
                return data

        def my_lookup(*args, **kwargs):
            kwargs['vars'] = vars
            return lookup(*args, basedir=basedir, **kwargs)

        t.globals['lookup'] = my_lookup
        t.globals['finalize'] = my_finalize
        jvars = _jinja2_vars(basedir, vars, t.globals, fail_on_undefined)
        new_context = t.new_context(jvars, shared=True)
        rf = t.root_render_func(new_context)
        try:
            res = jinja2.utils.concat(rf)
        except TypeError, te:
            if 'StrictUndefined' in str(te):
                raise errors.AnsibleUndefinedVariable(
                    "unable to look up a name or access an attribute in template string"
                )
            else:
                raise errors.AnsibleError(
                    "an unexpected type error occured. Error was %s" % te)
示例#2
0
 def _lookup_variables(self, terms):
     results = []
     for x in terms:
         try:
             intermediate = listify_lookup_plugin_terms(
                 x, templar=self._templar, loader=self._loader)
         except UndefinedError as e:
             raise errors.AnsibleUndefinedVariable(
                 "One of the nested variables was undefined. The error was: %s"
                 % e)
         results.append(intermediate)
     return results
示例#3
0
def lookup(name, *args, **kwargs):
    from ansible import utils
    instance = utils.plugins.lookup_loader.get(name.lower(), basedir=kwargs.get('basedir',None))
    tvars = kwargs.get('vars', None)

    wantlist = kwargs.pop('wantlist', False)

    if instance is not None:
        try:
            ran = instance.run(*args, inject=tvars, **kwargs)
        except errors.AnsibleError:
            raise
        except jinja2.exceptions.UndefinedError, e:
            raise errors.AnsibleUndefinedVariable("One or more undefined variables: %s" % str(e))
        except Exception, e:
            raise errors.AnsibleError('Unexpected error in during lookup: %s' % e)
def template_from_string(basedir, data, vars, fail_on_undefined=False):
    ''' run a string through the (Jinja2) templating engine '''

    try:
        if type(data) == str:
            data = unicode(data, 'utf-8')
        environment = jinja2.Environment(trim_blocks=True,
                                         undefined=StrictUndefined,
                                         extensions=_get_extensions())
        environment.filters.update(_get_filters())
        environment.template_class = J2Template

        if '_original_file' in vars:
            basedir = os.path.dirname(vars['_original_file'])
            filesdir = os.path.abspath(os.path.join(basedir, '..', 'files'))
            if os.path.exists(filesdir):
                basedir = filesdir

        # TODO: may need some way of using lookup plugins here seeing we aren't calling
        # the legacy engine, lookup() as a function, perhaps?

        data = data.decode('utf-8')
        try:
            t = environment.from_string(data)
        except Exception, e:
            if 'recursion' in str(e):
                raise errors.AnsibleError(
                    "recursive loop detected in template string: %s" % data)
            else:
                return data

        def my_lookup(*args, **kwargs):
            kwargs['vars'] = vars
            return lookup(*args, basedir=basedir, **kwargs)

        t.globals['lookup'] = my_lookup
        jvars = _jinja2_vars(basedir, vars, t.globals, fail_on_undefined)
        new_context = t.new_context(jvars, shared=True)
        rf = t.root_render_func(new_context)
        try:
            res = jinja2.utils.concat(rf)
        except TypeError, te:
            if 'StrictUndefined' in str(te):
                raise errors.AnsibleUndefinedVariable(
                    "unable to look up a name or access an attribute in template string"
                )
示例#5
0
    def run(self, terms, variables=None, **kwargs):
        if variables is not None:
            self._templar.set_available_variables(variables)
        myvars = getattr(self._templar, '_available_variables', {})

        for term in terms:
            if not isinstance(term, string_types):
                raise errors.AnsibleError('Invalid setting identifier, "%s" '
                                          'is not a string, its a %s' %
                                          (term, type(term)))

            if term in myvars:
                value = myvars[term]
            elif 'hostvars' in myvars and term in myvars['hostvars']:
                # maybe it is a host var?
                value = myvars['hostvars'][term]
            else:
                continue
            result = self._templar.template(value, fail_on_undefined=True)
            return [result]

        raise errors.AnsibleUndefinedVariable('No variable found with name: '
                                              '%s' % term)
示例#6
0
        host = vars['template_host'],
        uid  = vars['template_uid'],
        file = to_bytes(vars['template_path'])
    )
    vars['ansible_managed'] = time.strftime(
        managed_str,
        time.localtime(os.path.getmtime(realpath))
    )

    # This line performs deep Jinja2 magic that uses the _jinja2_vars object for vars
    # Ideally, this could use some API where setting shared=True and the object won't get
    # passed through dict(o), but I have not found that yet.
    try:
        res = jinja2.utils.concat(t.root_render_func(t.new_context(_jinja2_vars(basedir, vars, t.globals, fail_on_undefined), shared=True)))
    except jinja2.exceptions.UndefinedError, e:
        raise errors.AnsibleUndefinedVariable("One or more undefined variables: %s" % str(e))
    except jinja2.exceptions.TemplateNotFound, e:
        # Throw an exception which includes a more user friendly error message
        # This likely will happen for included sub-template. Not that besides
        # pure "file not found" it may happen due to Jinja2's "security"
        # checks on path.
        values = {'name': realpath, 'subname': str(e)}
        msg = 'file: %(name)s, error: Cannot find/not allowed to load (include) template %(subname)s' % \
               values
        error = errors.AnsibleError(msg)
        raise error

    # The low level calls above do not preserve the newline
    # characters at the end of the input data, so we use the
    # calculate the difference in newlines and append them 
    # to the resulting output for parity
示例#7
0
        except errors.AnsibleConnectionFailed, e:
            result = dict(failed=True, msg="FAILED: %s" % str(e))
            return ReturnData(host=host, comm_ok=False, result=result)

        tmp = ''
        # all modules get a tempdir, action plugins get one unless they have NEEDS_TMPPATH set to False
        if getattr(handler, 'NEEDS_TMPPATH', True):
            tmp = self._make_tmp_path(conn)

        # render module_args and complex_args templates
        try:
            module_args = template.template(self.basedir, module_args, inject, fail_on_undefined=self.error_on_undefined_vars)
            complex_args = template.template(self.basedir, complex_args, inject, fail_on_undefined=self.error_on_undefined_vars)
        except jinja2.exceptions.UndefinedError, e:
            raise errors.AnsibleUndefinedVariable("One or more undefined variables: %s" % str(e))


        result = handler.run(conn, tmp, module_name, module_args, inject, complex_args)
        # Code for do until feature
        until = self.module_vars.get('until', None)
        if until is not None and result.comm_ok:
            inject[self.module_vars.get('register')] = result.result
            cond = template.template(self.basedir, until, inject, expand_lists=False)
            if not utils.check_conditional(cond,  self.basedir, inject, fail_on_undefined=self.error_on_undefined_vars):
                retries = self.module_vars.get('retries')
                delay   = self.module_vars.get('delay')
                for x in range(1, retries + 1):
                    time.sleep(delay)
                    tmp = ''
                    if getattr(handler, 'NEEDS_TMPPATH', True):
示例#8
0
def template_from_file(basedir, path, vars):
    ''' run a file through the templating engine '''

    fail_on_undefined = C.DEFAULT_UNDEFINED_VAR_BEHAVIOR

    from ansible import utils
    realpath = utils.path_dwim(basedir, path)
    loader = jinja2.FileSystemLoader([basedir, os.path.dirname(realpath)])

    def my_lookup(*args, **kwargs):
        kwargs['vars'] = vars
        return lookup(*args, basedir=basedir, **kwargs)

    environment = jinja2.Environment(loader=loader,
                                     trim_blocks=True,
                                     extensions=_get_extensions())
    environment.filters.update(_get_filters())
    environment.globals['lookup'] = my_lookup
    if fail_on_undefined:
        environment.undefined = StrictUndefined

    try:
        data = codecs.open(realpath, encoding="utf8").read()
    except UnicodeDecodeError:
        raise errors.AnsibleError("unable to process as utf-8: %s" % realpath)
    except:
        raise errors.AnsibleError("unable to read %s" % realpath)


# Get jinja env overrides from template
    if data.startswith(JINJA2_OVERRIDE):
        eol = data.find('\n')
        line = data[len(JINJA2_OVERRIDE):eol]
        data = data[eol + 1:]
        for pair in line.split(','):
            (key, val) = pair.split(':')
            setattr(environment, key.strip(), ast.literal_eval(val.strip()))

    environment.template_class = J2Template
    t = environment.from_string(data)
    vars = vars.copy()
    try:
        template_uid = pwd.getpwuid(os.stat(realpath).st_uid).pw_name
    except:
        template_uid = os.stat(realpath).st_uid
    vars['template_host'] = os.uname()[1]
    vars['template_path'] = realpath
    vars['template_mtime'] = datetime.datetime.fromtimestamp(
        os.path.getmtime(realpath))
    vars['template_uid'] = template_uid
    vars['template_fullpath'] = os.path.abspath(realpath)
    vars['template_run_date'] = datetime.datetime.now()

    managed_default = C.DEFAULT_MANAGED_STR
    managed_str = managed_default.format(host=vars['template_host'],
                                         uid=vars['template_uid'],
                                         file=vars['template_path'])
    vars['ansible_managed'] = time.strftime(
        managed_str, time.localtime(os.path.getmtime(realpath)))

    # This line performs deep Jinja2 magic that uses the _jinja2_vars object for vars
    # Ideally, this could use some API where setting shared=True and the object won't get
    # passed through dict(o), but I have not found that yet.
    try:
        res = jinja2.utils.concat(
            t.root_render_func(
                t.new_context(_jinja2_vars(basedir, vars, t.globals,
                                           fail_on_undefined),
                              shared=True)))
    except jinja2.exceptions.UndefinedError, e:
        raise errors.AnsibleUndefinedVariable(
            "One or more undefined variables: %s" % str(e))
示例#9
0
def _deprecated(new_var,
                old_var=None,
                old_var_name=None,
                new_var_name=None,
                removed_in=None,
                fatal=False):
    """Provide a deprecation warning on deprecated variables.

    This filter will return the old_var value if defined along with a
    deprecation warning that will inform the user that the old variable
    should no longer be used.

    In order to use this filter the old and new variable names must be provided
    to the filter as a string which is used to render the warning message. The
    removed_in option is used to give a date or release name where the old
    option will be removed. Optionally, if fatal is set to True, the filter
    will raise an exception if the old variable is used.

    USAGE: {{ new_var | deprecated(old_var,
                                   "old_var_name",
                                   "new_var_name",
                                   "removed_in",
                                   false) }}

    :param new_var: ``object``
    :param old_var: ``object``
    :param old_var_name: ``str``
    :param new_var_name: ``str``
    :param removed_in: ``str``
    :param fatal: ``bol``
    """
    _usage = (
        'USAGE: '
        '{{ new_var | deprecated(old_var=old_var, old_var_name="old_var_name",'
        ' new_var_name="new_var_name", removed_in="removed_in",'
        ' fatal=false) }}')

    if not old_var_name:
        raise errors.AnsibleUndefinedVariable(
            'To use this filter you must provide the "old_var_name" option'
            ' with the string name of the old variable that will be'
            ' replaced. ' + _usage)
    if not new_var_name:
        raise errors.AnsibleUndefinedVariable(
            'To use this filter you must provide the "new_var_name" option'
            ' with the string name of the new variable that will replace the'
            ' deprecated one. ' + _usage)
    if not removed_in:
        raise errors.AnsibleUndefinedVariable(
            'To use this filter you must provide the "removed_in" option with'
            ' the string name of the release where the old_var will be'
            ' removed. ' + _usage)

    # If old_var is undefined or has a None value return the new_var value
    if isinstance(old_var, Undefined) or not old_var:
        return new_var

    name = 'Ansible-Warning| '
    log = logging.getLogger(name)
    for handler in log.handlers:
        if name == handler.name:
            break
    else:
        stream_handler = logging.StreamHandler()
        stream_handler.setLevel(logging.DEBUG)
        stream_handler.name = name
        stream_format = logging.Formatter(
            '%(asctime)s - %(name)s%(levelname)s => %(message)s')
        stream_handler.setFormatter(stream_format)

        log.setLevel(logging.DEBUG)
        log.addHandler(stream_handler)

    message = (
        'Deprecated Option provided: Deprecated variable: "%(old)s", Removal'
        ' timeframe: "%(removed_in)s", Future usage: "%(new)s"' % {
            'old': old_var_name,
            'new': new_var_name,
            'removed_in': removed_in
        })

    if str(fatal).lower() in ['yes', 'true']:
        message = 'Fatally %s' % message
        log.fatal(message)
        raise RuntimeError(message)
    else:
        log.warn(message)
        return old_var
示例#10
0
def template_from_file(basedir, path, vars):
    ''' run a file through the templating engine '''

    fail_on_undefined = C.DEFAULT_UNDEFINED_VAR_BEHAVIOR

    realpath = filesystem.path_dwim(basedir, path)
    loader = jinja2.FileSystemLoader([basedir, os.path.dirname(realpath)])

    def my_lookup(*args, **kwargs):
        kwargs['vars'] = vars
        return lookup(*args, basedir=basedir, **kwargs)

    environment = jinja2.Environment(loader=loader,
                                     trim_blocks=True,
                                     extensions=_get_extensions())
    environment.filters.update(_get_filters())
    environment.globals['lookup'] = my_lookup
    if fail_on_undefined:
        environment.undefined = StrictUndefined

    try:
        data = codecs.open(realpath, encoding="utf8").read()
    except UnicodeDecodeError:
        raise errors.AnsibleError("unable to process as utf-8: %s" % realpath)
    except:
        raise errors.AnsibleError("unable to read %s" % realpath)

    # Get jinja env overrides from template
    if data.startswith(JINJA2_OVERRIDE):
        eol = data.find('\n')
        line = data[len(JINJA2_OVERRIDE):eol]
        data = data[eol + 1:]
        for pair in line.split(','):
            (key, val) = pair.split(':')
            setattr(environment, key.strip(), ast.literal_eval(val.strip()))

    vars = vars.copy()
    try:
        template_uid = pwd.getpwuid(os.stat(realpath).st_uid).pw_name
    except:
        template_uid = os.stat(realpath).st_uid

    vars.update(
        dict(
            template_host=os.uname()[1],
            template_path=realpath,
            template_mtime=datetime.datetime.fromtimestamp(
                os.path.getmtime(realpath)),
            template_uid=template_uid,
            template_fullpath=os.path.abspath(realpath),
            template_run_date=datetime.datetime.now(),
        ))

    managed_default = C.DEFAULT_MANAGED_STR
    managed_str = managed_default.format(host=vars['template_host'],
                                         uid=vars['template_uid'],
                                         file=vars['template_path'])
    vars['ansible_managed'] = time.strftime(
        managed_str, time.localtime(os.path.getmtime(realpath)))

    # this double template pass is here to detect errors while we still have context
    # actual recursion is handled by the mainline template function further down
    try:
        t = environment.from_string(data)
        res = t.render(vars)
    except jinja2.exceptions.UndefinedError, e:
        raise errors.AnsibleUndefinedVariable(
            "One or more undefined variables: %s" % str(e))