Ansible - Read subkey from dict entries and concat to string - ansible

I'm pretty new to Ansible, coming from Puppet I really like it.
I'm trying to get a string compiled from server admin_port.
Vars file:
webservers:
ws1:
listen_address: "webserver1.mydomain"
admin_port: "7779"
http_port: "7777"
ssl_port: "4443"
ws2:
listen_address: "webserver2.mydomain"
admin_port: "7779"
http_port: "7777"
ssl_port: "4443"
I'm templating quite a customised set of config files so I'm trying to get the two listen ports into this format:
ports=7779,7779
I've tried:
vars:
webserver_admin_ports: "{{lookup('subelements', webservers, 'admin_port', {'skip_missing': True})}}"
But I run into the issue:
Error was a <class 'ansible.errors.AnsibleError'>, original message: the key admin_port should point to a list, got '7779'"}
I'm sure this isn't too tricky and the data structure is simple enough, there could be 1 or 10 servers.
In Puppet I'd do this in the template, but it seems with ansible its better to pass a var.
Thanks,

For anyone with a similar question, this is my solution.
In the template, do the lookup, it keeps the code cleaner:
{%- set serverNames = [] -%}
{%- set adminPorts = [] -%}
{%- set listenAddresses = [] -%}
{%- set httpPorts = [] -%}
{%- for server in webserver_meta -%}
{{- serverNames.append(server) -}}
{{- adminPorts.append(webserver_meta[server].admin_port) -}}
{{- listenAddresses.append(webserver_meta[server].listen_address) -}}
{{- httpPorts.append(webserver_meta[server].http_port) -}}
{%- endfor %}
serverNames={{ serverNames|join(',') }}
serverAdminPorts={{ adminPorts|join(',') }}
serverListenAddress={{ listenAddresses|join(',') }}
serverHttpPorts={{ httpPorts|join(',') }}

Related

alertmanager gotemplate function contains is not found

I'm trying to exclude certain labels from the list to be added in the URL.
However alertmanager complains about the following template with the error:
ts=2023-02-08T23:25:31.016Z caller=coordinator.go:132 component=configuration msg="one or more config change subscribers failed to apply new config" file=/etc/alertmanager/alertmanager.yml err="failed to parse templates: template: notifications.tmpl:9: function \"contains\" not defined"
{{ define "alert_silencer_url" -}}
https://xxx.yyy/#/silences/new?filter=%7B
{{- range .CommonLabels.SortedPairs -}}
{{- if not contains .Name "alertname helm_sh_chart" -}}
{{- .Name }}%3D"{{- .Value -}}"%2C%20
{{- end -}}
{{- end -}}
alertname%3D"{{- .CommonLabels.alertname -}}"%7D
{{- end }}
what could be done. I have a list of keywords I need to drop from the URL.

With dbt. How do I use a jinja macro in a yaml file

I have a yaml file like this:
models:
- name: test_view
description: "test"
config:
meta:
database_tags:
ACCOUNT_OBJECTS.TAGS.ENV: DEV`
I am trying automatically change 'DEV' to PROD when it's in that environment. I have a macro that gets the variable from targets.name
This is the jinja code:
{% macro test_macro(target) %}
{%- if target.name == "dev" -%} DEV
{%- elif target.name == "prod" -%} PROD
{%- else -%} invalid
{%- endif -%}
{% endmacro %}`
However, when I try to use the macro I get 'test_macro is undefined'
eg. ACCOUNT_OBJECTS.TAGS.ENV: {{ test_macro(target)}}
Is it that custom macros still cannot be used in yaml files?
Macros are for templating the SQL queries DBT compiles from its models. The YAML files are for configuration; they are not themselves models and do not support macros.
I went looking, and there is an active discussion about whether this could be supported in future, but as of the end of 2022 it is not possible.
Have you considered using a config block inside your model in order to set these metadata?

Liquid syntax error: Tag was not properly terminated with regexp: /\%\}/

I have a an if condition in my liquid template like this
Username: {{user.email}}
{% if extras['password_to_be_sent'] %}
Password: {{extras['password_to_be_sent']}}
{% endif %}
Trial expiration: {{user.trial_expiration}}
However this is generating a line break when the if condition does not evaluate to true
so the above generated output like this
Username: Abc
Trail Expiration: 2019-11-10
I want to remove the additional line break when the if condition does not evaluate to true
i tried adding - as suggested here https://shopify.github.io/liquid/basics/whitespace/
so updated code to
Username: {{user.email}}
{%- if extras['password_to_be_sent'] -%}
Password: {{extras['password_to_be_sent']}}
{%- endif -%}
Trial expiration: {{user.trial_expiration}}
but this is giving an exception Liquid::SyntaxError (Liquid syntax error: Tag '{%- if extras['password_to_be_sent'] -%}' was not properly terminated with regexp: /\%\}/)
Additionally, I am saving the template code in database, if that helps.
Any help in this would be appreciated. Thanks.
Answered above in a comment, but here it is again:
I see you've also tagged Ruby on Rails — if your Rails app is consuming a version of Liquid earlier than 4.0.0, you won't be able to use the whitespace control tags. Those were added in Liquid 4.0.0.
Did you check to make sure extras['password_to_be_sent'] doesn't return a truthy but empty string? Maybe it should be:
Username: {{user.email}}
{%- if extras['password_to_be_sent'].present? -%}
Password: {{extras['password_to_be_sent']}}
{%- endif -%}
Trial expiration: {{user.trial_expiration}}
When I change line 134 from
int dis[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
to
int dis[4][2]={ {0,1},{0,-1},{1,0},{-1,0}};
It fixed !

Getting an "Liquid Exception: Liquid syntax error" while using Jekyll

I run bundle exec jekyll serve --trace on Windows 10. I got the following console message:
D:\MyPorfolio\perrot.github.io>bundle exec jekyll serve
Configuration file: D:/MyPorfolio/perrot.github.io/_config.yml
Source: D:/MyPorfolio/perrot.github.io
Destination: D:/MyPorfolio/perrot.github.io/_site
Incremental build: disabled. Enable with --incremental
Generating...
Liquid Exception: Liquid syntax error (line 8): Syntax Error in 'for loop' - Valid syntax: for [item] in [collection] in 2018-09-14-Rendering a python dict in jinja2.markdown
jekyll 3.7.3 | Error: Liquid syntax error (line 8): Syntax Error in 'for loop' - Valid syntax: for [item] in [collection]
Does anyone know how to fix that problem? Thanks in advance.
The file 2018-09-14-Rendering a python dict in jinja2.markdown content is:
---
layout: post
title: "Rendering a python dict in jinja2"
date: 2018-09-14 00:01:57 +0800
categories: python jinja2
---
```python
url_list = [{'target': 'http://10.58.48.103:5000/', 'clicks': '1'},
{'target': 'http://slash.org', 'clicks': '4'},
{'target': 'http://10.58.48.58:5000/', 'clicks': '1'},
{'target': 'http://de.com/a', 'clicks': '0'}]
#Python 2.7
{% for key, value in url_list.iteritems() %}
<li>{{ value["target"] }}</li>
{% endfor %}
#Python 3
{% for key, value in url_list.items() %}
<li>{{ value["target"] }}</li>
{% endfor %}
```
Liquid tries to process your source code, particularly the jinja2 control tags, for that you need to tell Liquid to avoid processing it with the raw tags:
{% highlight python %}
{% raw %}
url_list = [{'target': 'http://10.58.48.103:5000/', 'clicks': '1'},
{'target': 'http://slash.org', 'clicks': '4'},
{'target': 'http://10.58.48.58:5000/', 'clicks': '1'},
{'target': 'http://de.com/a', 'clicks': '0'}]
#Python 2.7
{% for key, value in url_list.iteritems() %}
<li>{{ value["target"] }}</li>
{% endfor %}
#Python 3
{% for key, value in url_list.items() %}
<li>{{ value["target"] }}</li>
{% endfor %}
{% endraw %}
{% endhighlight %}
1 - The {% raw %} tag is part of the solution for you python code in this post and this post.
2 - The other part of the solution can be a bug in the way Jekyll manages excerpts.
Remove empty lines in your code, and it will work.

Convert Unicode to String with Ansible and Jinja2

I need help with converting a Unicode variable to a string in order for the below Ansible construct to work.
In this particular case, I want to use the item.keys() method in order to get the current env name (i.e. uat) but I get [u'uat'] instead. I have been searching the Internet but could not find a way to convert [u'uat'] to a simple uat.
defaults/main.yml:
blablabla:
env:
- uat:
accounts:
- david:
email: david#example.com
- anna:
email: anna#example.com
- develop:
accounts:
- john:
email: john#example.com
tasks/main.yml:
- include_tasks: dosomething.yml
with_items:
- "{{ blablabla.env }}"
tasks/dosomething.yml:
- name: Get accounts
set_fact:
accounts: "{%- set tmp = [] -%}
{%- for account in item[item.keys()].accounts -%}
{{ tmp.append(account) }}
{%- endfor -%}
{{ tmp }}"
error message:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<failed value="True"/>
<msg value="The task includes an option with an undefined variable. The error was: dict object has no element [u'uat']
The error appears to have been in 'dosomething.yml': line 9, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- name: Get accounts
^ here
exception type: <class 'ansible.errors.AnsibleUndefinedVariable'>
exception: dict object has no element [u'uat']"/>
</root>
Alternatively, I would also welcome alternative approaches, as long the data structure (i.e. the defaults/main.yml file) remains unchanged.
I get [u'uat']
This is not a "Unicode string", this is a list ― pay attention to [ ].
As item.keys() returns a list, but you want to use it as an index to item[], you must select the element. So either use first filter or [0]:
- name: Get accounts
set_fact:
accounts: "{%- set tmp = [] -%}
{%- for account in item[item.keys()|first].accounts -%}
{{ tmp.append(account) }}
{%- endfor -%}
{{ tmp }}"

Resources