I'm formatting & appending strings to a list but the ref() function (used in dbt) isn't a string so I need to remove the outside quotes while retaining the inner single quotes.
I've attempted to chain strip() and replace() but neither are solving the problem.
Current code:
{% for result in results_list %}
{% set result = "ref('{}')".format(result) %}
{{ ref_format_results.append(result) }}
{% endfor %}
{% do log(ref_format_results, info=true) %}
Current output:
["ref('model_a')","ref('model_b')","ref('model_c')"]
Desired output:
[ref('model_a'),ref('model_b'),ref('model_c')]
You're creating a string, which needs to be delimited somehow, and will always show outer quotes when printed/logged.
If you're templating those values into another file or string, then you'll already have what you want.
{% for r in ref_format_results %}
select * from {{ "{{" ~ r ~ "}}" }};
{% endfor %}
will produce:
select * from {{ ref('model_a') }};
select * from {{ ref('model_b') }};
select * from {{ ref('model_c') }};
But more importantly, why set result to a string in the first place? Are you trying to delay the execution of the ref() macro? If not, this will work just fine, to give you a list of evaluated refs (which are Relations):
{% for result in results_list %}
{% set result = ref(result) %}
{{ ref_format_results.append(result) }}
{% endfor %}
{% do log(ref_format_results, info=true) %}
Outputs:
['"my_db"."my_schema"."model_a"', '"my_db"."my_schema"."model_b"', '"my_db"."my_schema"."model_c"']
Related
I want to use the n values in the next for statement and I expect output as router_0, router_1. But any optisons like router_[n], router_{{ n }}, router_(n) etc didnt work. How can we do this?
{% for n in range(0, 2) %}
{% for rtr in web.router_[n] %}
{% if rtr.interface.type == 'lacp' %}
interface Port-Channel{{ rtr.interface.id }}
.
{% endif %}
{% endfor %}
{% endfor %}
In vars.yaml, there are variables for paired routers, router_0 and router_1. I want to generate the config template for both routers at the same time.
Thanks,
Concatenate the name of the attribute
{% for rtr in web['router_' ~ n] %}
This question already has an answer here:
Pushing items to a var while looping over another var in Ansible Jinja2 template
(1 answer)
Closed 4 years ago.
I'm trying to calculate the needed space based on the longest word in a dictionary.
It seems though that the variable num doesn't transfer it's value to the second inner loop.
I'm basically trying to caculate the amount of spaces to align the columns correctly.
{% for module in modules %}
module "{{ module.name }}" {
source = "{{ module.source }}"
{% set num = 1 %}
{% for n in module.vars.keys() %}
{% if num < n|length %}
{% set num = n|length %}
{% endif %}
{{ num }}: {{ n }}
{% endfor %}
{% for m in module.vars %}
{{ num }}
{{ m }} {{ '= "' + module.vars[m]|indent(width=num) }}"
{% endfor %}
}
You're right, you can't get variables out of loops this way. See "Scoping behavior" in the docs.
One option is to use what they suggest and create a namespace:
{% set ns = namespace(num=0) %}
{% for n in module.vars.keys() %}
{% if ns.num < n|length %}
{% set ns.num = n|length %}
{% endif %}
{{ ns.num }}: {{ n }}
{% endfor %}
In your case, there is an easier and cleaner solution though: you can calculate the maximum width in an expression. Use map() to get a list of lengths, and use max filter to get the biggest one:
{% set indent_width = module.vars.keys() | map("length") | max %}
{% for m in module.vars %}
{{ m }} {{ '= "' + module.vars[m]|indent(width=indent_width) }}"
{% endfor %}
Let's say I have the following Jinja2 variables:
'dev_ami' = 'ami-123456'
'dev_located_ami' = 'ami-123456'
'prod_ami' = 'ami-654321'
'prod_located_ami' = 'ami-654321'
I would like to set a condition upon when the 'dev_ami' variable is equal to the 'dev_located_ami' variable. This would easily be done as shown in the following statement:
{% if dev_ami == dev_located_ami %}
... do some stuff
{% else %}
... do some other stuff
{% endif %}
But I would like to dynamically compare amis based on the deployment environment contained in a list ['dev','prod', etc...]. The following contains a templating error since there is an expression within a statement as such - {% {{ .. }} %}:
{% for env_type in ['dev','prod'] %}
{% if {{ env_type }}_ami == {{ env_type }}_located_ami %}
... do stuff
{% else %}
... do other stuff
{% endif %}
{% endfor %}
I have tried to set variables to represent the expressions I would like in the following code but unfortunately they are compiled literally as 'dev_ami' and 'dev_located_ami' whereas I would like them compiled to their corresponding variable values 'ami-123456' and 'ami-123456':
{% for env_type in ['dev','prod'] %}
{% set ami = "%s_ami"|format(env_type) %}
{% set located_ami = "%s_located_ami"|format(env_type) %}
{% if ami == located_ami %}
... do stuff
{% else %}
... do other stuff
{% endif %}
{% endfor %}
I have checked through various filters and so far have had no success. Would appreciate advice on getting this specific implementation to work properly. Thank you in advance.
I think you might be approaching the problem with the wrong datastructure in mind.
Dynamically generating variable names in order to compare amis in different environemts sounds like a massive overkill to me. Are you familiar with lists & dictionaries?
Try to start from something like this (pseudocode):
dict = { environments:
prod:
ami1: foo
ami1_located: foo
dev:
ami1: bar
ami1_located:baz
}
for env in dict[environments]:
if env[ami1] == env[ami1_located]:
[...]
I am trying to generate some config using Jinja2 templating and Ansible variables. The framework under which I am currently working does not allow me to perform the following operation in Ansible and thus I was hoping to achieve the same results in Jinja2.
My Ansible variables are as follows:
---
Top:
inner:
type: type1
other_random_variable:
- random: 1
inner2:
type: type2
inner3:
type: type1
The above structure works well when I am iterating over a loop and forming a configuration file as follows:
{% if Top is defined %}
{% for inner_vars in Top %}
# perform substitution here
{% endfor %}
{% endif %}
What I would like to do is to form a set of types such that I can generate another configuration for each unique type.
Is there any way for me to iterate through Top and add an item to a set?
I think I have a solution that could work:
{% set types = [] %}
{% if Top is defined%}
{% for inner_var in Top %}
{% if types.append(Top[inner_var].type) %}{% endif %}
{% endfor %}
{% endif %}
{{ types|unique }}
I was wondering what is the proper way of finding the index of an item in an array is in a Liquid template, and selected related items based off of the index. Currently I'm able to calculate the value, but it seems to be a string and I can't then find other items in the array with the string. For example in a CMS:
{% for site_page in site.pages.all %}
{% if site_page.id == page.id %}
{% assign page_index = forloop.index0 %}
{% capture previous_page_index %}
{{ page_index | minus: 1 }}
{% endcapture %}
{% break %}
{% endif %}
{% endfor %}
The expected value can be found in previous_page_index (in this case 0) however, if i try to do something like site.pages.all[previous_page_index] I receive no output. If I do the same thing with a hardcoded index value: site.pages.all[0] it does yield an output. Does anyone have an idea/example on how this is supposed to be done in liquid?
Best I can figure is to use {% for item in array limit:1 offset:forloop.index0 %}. For example:
require 'liquid'
chars = %w[a b c]
names = %w[alpha bravo charlie]
puts Liquid::Template.parse(<<DONE).render( 'chars'=>chars, 'names'=>names )
{% for c in chars %}
{{c}} is
{% for n in names limit:1 offset:forloop.index0 %}{{n}}{% endfor %}
{% endfor %}
DONE
…which produces…
a is
alpha
b is
bravo
c is
charlie
Editorial aside: ouch. What an ugly tempting language. I understand its goals, but the burden it places on users is heinous.