How can I use {{this}} as a parameter in a dbt jinja macro? - jinja2

How can I pass the name of the current model using {{this}} as a parameter for a macro in a config function?
I have tried a couple of options and none of them works.
model/Table1.sql
{{ config(post_hook= calculate_test("{{this}}") ) }}
macro/calculate_test.sql
{% macro calculate_test(tableN) %}
{%- set tableName = tableN -%}
{% set sql %}
SELECT
COUNT(*) as cnt
FROM {{ tableName }}
{% endset %}
{% set results = run_query(sql) %}
{% endmacro %}
The error is:

You’re almost there! Only thing is that you’ve got extra curly brackets and misplaced quotes. The entire config block is Jinja so you don’t need the curly brackets around ‘this’.
{{ config(post_hook= “calculate_test(this)” ) }}

Related

How to dynamically call dbt macros using jinja?

I have a use case where I would like to define the name of a macro and then apply it to one column.
A simplified example could be as follows. I have two macros defined that I want to call dynamically in my model (both take one column as an input):
cast_to_string
convert_empty_string_to_null_value
Now, I want to call them dynamically. See the example below
{%- set macro_names = ["cast_to_string", "convert_empty_string_to_null_value"] -%}
select
{% for macro_name in macro_names %}
-- this should dynamically be evaluated to `{{ cast_to_string(my_column) }}`
-- and `{{ convert_empty_string_to_null_value(my_column) }}`
{{ macro_name(my_column) }}
{% endfor %}
from my_model
However, this will throw an error saying that a string is not callable.
I also tried using {% raw %} {{ {% endraw %} to escape brackets, but that didn’t work either.
So, my question is, if there is a way to dynamically call macros in jinja/dbt?
I think it should work if you remove the quotes :
{%- set macro_names = [cast_to_string, convert_empty_string_to_null_value] -%}
So that jinja doesn't interpret it as string and you can use it as a Callable
I achieve it using this example :
{%- set macro_names = [print_lower, print_upper] -%}
{% for macro_name in macro_names %}
{{ macro_name("test") }}
{% endfor %}
and
{% macro print_lower(string) %}
{{ print(string|lower) }}
{% endmacro %}
{% macro print_upper(string) %}
{{ print(string|upper) }}
{% endmacro %}

Configuring a Jinja template in Cisco DNAC Template editor

I am configuring a Jinja template in Cisco DNAC Template editor to provision new switches. The problem I am having is getting Jinja to split the string variable within the Cisco Template tool. I tried using this split command.
{% set list1 = variable1.split(';') %}
This works fine if I hard code in the {{ HOSTNAME }} variable, for example using ABC-DEF-111-AS-10-11-12-13
{# {% set hname = '{{ HOSTNAME }}' %} #}
{% set hname = 'ABC-DEF-111-AS-10-11-12-13' %}
Device name is {{ hname }}
{% set list1 = hname.split('-') %}
{% for list in list1 %}
<p>{{ list }}</p>
{% endfor %}
The campus is {{ list1[0] }}
The building is {{ list1[1] }}
Room number is {{ list1[2] }}
Switch type is {{ list1[3] }}
IP address is {{ list1[4] }}.{{ list1[5] }}.{{ list1[6] }}.{{ list1[7] }}
However, when I use the {{ HOSTNAME }} variable to input the hostname, the split command will not split the hostname, instead it passes the hostname through in its entirity within {{ list1[0] }}. This happens even if I use the variable directly within the split command, for example.
{% set list1 = '{{ HOSTNAME }}'.split('-') %}
I have also tried splitting the resultant {{ list1[0] }} but it too just passes the hostname on through in its entirety.
I am not sure if this is a problem with the version of Jinja used in the Template Editor because I get a systax error when ever I tried using this split command:
{% set item1, item2 = variable1.split(';') %}
Is there away to get {{ HOSTNAME }} split? What am I missing?
The solution is that I should change the variable into a statement like this:
{% set list1 = **HOSTNAME**.split('-') %}

Jinja variables in function

I have defined a variable in jinja by using:
{% set my_var = 10 %}
And a macro by doing:
{% macro my_function(my_var) %}
where my_col > my_var
{% endmacro %}
I want to call the macro on the variable I've set in order to obtain the string:
where my_col > 10
I've tried with
{{my_function(my_var)}}
but it doesn't work. I'm not sure if I have to change the call or the macro. Do you know how can I achieve this?
Thanks in advance!
There was a bug in the function definition, it needs to be defined like:
{% macro my_function(my_var) %}
where my_col > {{ my_var }}
{% endmacro %}

Passing list of Relation object to dbt_utils.union_relation macro fails

Related to dbt and jinja2
I am using union_relations from dbt_utils package (0.5.0).
I created my macro which takes list of fully qualified name (like database.schema.identifier) splits it and uses api.Relations.create (link) to create a relation and append each relation to a list.
{{ list_of_relation }} is given to dbt_utils.union_relations(as relations=my_macro([list of fully qualified names])), it's giving me an _is_relation error, I did use log to debug and see if it actually creates a relation and it does. What could be wrong?
It sounds like you have a macro written something like this:
{% macro my_macro(names) %}
{% set list_of_relations = [] %}
{% for name in names %}
{% set relation = something(name) %}
{% do list_of_relations.append(relation) %}
{% endfor %}
{{ list_of_relations }}
{% endmacro %}
Instead of using {{ list_of_relation }}, you’ll want {{ return(list_of_relation) }} or {% do return(list_of_relation) %}. The problem is that {{ ... }} turns things into strings in jinja macros, and macros by default return strings.
The documentation on return is here.

ansible jinja2 concatenate IP addresses

I would like to cocatenate a group of ips into a string.
example ip1:2181,ip2:2181,ip3:2181,etc
{% for host in groups['zookeeper'] %}
{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}
{% endfor %}
I have the above code, but can't seem to quite figure out how to concatenate into a string.
searching for "Jinja2 concatenate" doesn't give me the info I need.
Updated this answer, because I think I misunderstood your question.
If you want to concatenate the IP's of each host with some string, you can work with the loop controls, to check if you're in the last iteration:
{% for host in groups['zookeeper'] -%}
{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}
{%- if not loop.last %}, {% endif -%}
{%- endfor %}
Old answer:
The word you're looking for is join:
{{ hostvars[host]['ansible_eth0']['ipv4']['address'] | join(", ") }}
You can use the 'extract' filter for this (provided you use ansible>=2.1):
{{ groups['zookeeper'] | map('extract', hostvars, ['ansible_eth0', 'ipv4', 'address']) | join(',') }}
More info:
http://docs.ansible.com/ansible/playbooks_filters.html#extracting-values-from-containers
Found a similar solution at https://adamj.eu/tech/2014/10/02/merging-groups-and-hostvars-in-ansible-variables/ .
I did a set_fact using a groups variable as suggested in the post:
- hosts: all
connection: local
tasks:
- set_fact:
fqdn_list: |
{% set comma = joiner(",") %}
{% for item in play_hosts -%}
{{ comma() }}{{ hostvars[item].ansible_default_ipv4.address }}
{%- endfor %}
This relies on joiner, which has the advantage of not having to worry about the last loop conditional. Then with set_fact I can make use of the new string in later tasks.