How to generate a script with salt-stack with newlines - jinja2

I am trying to build a script using salt-stack and jinja. It is a result which I want to get:
#!/bin/bash
echo 1 &&
echo 2 &&
echo 3 &&
echo 4
I have script:
init.sls
{% set cmds = [] %}
{% for id in [1, 2, 3, 4] %}
{% do cmds.append("echo " ~ id) %}
{% endfor %}
/tmp/test.sh:
file.managed:
- source: salt://test.sh.jinja
- template: jinja
- mode: 0775
- require:
- file: /tmp
- context:
cmds : '{{ cmds | join(" &&\n") }}'
test.sh.jinja
#!/bin/bash
{{ cmds }}
RESULT
cat /tmp/test.sh
#!/bin/bash
echo 1 && echo 2 && echo 3 && echo 4
So newlines were removed. How to fix it? Thank you.

Quick look at: https://docs.saltstack.com/en/latest/topics/jinja/index.html#list-files
Reveals:
- context:
cmds : {{ cmds | join(' && \n') }}

Related

How to use the third variable in range?

There are variables in values.yaml of my Helm Chart:
stand: dev-gfdz-loader
ingress1:
entrypoints: pdu
In Helm Chart I have:
{{- range $key, $value := $.Values.secretObjects }}
- secretKey: {{ $key | quote}}
objectName: {{ $value | quote }}
secretPath: "pdu/data/dev-gfdz-loader"
{{- end }}
This example is working.
In the line "pdu/data/dev-gfdz-loader" I need:
replace pdu with ingress1.entrypoints and
replace dev-gfdz-loader with stand
Finally, if I do this:
{{- range $key, $value := $.Values.secretObjects }}
- secretKey: {{ $key | quote}}
objectName: {{ $value | quote }}
secretPath: "{{ .Values.ingress1.entrypoints }}/data/{{ .Values.stand }}"
{{- end }}
Then I get an error:
Error: template: app/charts/rr/templates/secretproviderclass.yaml:23:31: executing "app/charts/rr/templates/secretproviderclass.yaml" at <.Values.ingress1.entrypoints>: can't evaluate field Values in type interface {} Use --debug flag to render out invalid YAML
My solution:
{{- $entrypoints := .Values.ingress1.entrypoints -}}
{{- $stand := .Values.stand -}}
{{- range $key, $value := $.Values.secretObjects }}
- secretKey: "{{ $key }}"
objectName: "{{ $value }}"
secretPath: "{{ $entrypoints }}/data/{{ $stand }}"
{{- end }}

Concatenate optional variables in Jinja without duplicating whitespace

Question
I want to concatenate variables in Jinja by separating them with exactly one space (' ') where some of the variables might be undefined (not known to the template which ones).
import jinja2
template = jinja2.Template('{{ title }} {{ first }} {{ middle }} {{ last }}')
result = template.render(first='John', last='Doe') # result == ' John Doe'
I've been searching for a template string alternative that returns 'John Doe' instead of ' John Doe' in this case.
First attempt
Use
{{ [title, first, middle, last]|reject("undefined")|join(" ") }}
as template (which actually works), however
it's confusing
once I want to use a macro on one of the arguments (that e.g. puts middle in brackets if it is not undefined) and therefore return an empty string instead of Undefined this stops working.
2nd attempt
Replace multiple spaces with one space
{% filter replace(" ", " ") -%}
{{ title }} {{ first }} {{ middle }} {{ last }}
{%- endfilter %}
which actually only would work in all cases with a regular expression search/replace like
{% filter regex_replace(" +", " ") -%}
{{ title }} {{ first }} {{ middle }} {{ last }}
{%- endfilter %}
but regex_replace is not built-in (but could be provided by a custom regular expression filter).
Still I would not consider this to be optimal as double spaces in the content of variables would be replaced as well.
you dont use the power of jinja2/python, use the if else and test if a variable is defined:
import jinja2
template = "{{ title ~ ' ' if title is defined else '' }}"
template += "{{first ~ ' ' if first is defined else '' }}"
template += "{{ middle ~ ' ' if middle is defined else '' }}"
template += "{{ last if last is defined else '' }}"
template = jinja2.Template(template)
result = template.render(first='John', last='Doe')
print("----------")
print(result)
print("----------")
result:
----------
John Doe
----------
if you want to use regex, use :
import re
:
:
template = jinja2.Template("{{ title }} {{ first }} {{ middle }} {{ last }}")
result = template.render(first='John', last='Doe')
result = re.sub(" +", " ", result.strip())
strip() deletes any leading and trailing whitespaces including tabs (\t)
or a mixed of both solutions to avoid to suppress spaces not wanted
import jinja2
template = "{{ title ~ ' ' if title is defined else '' }}"
template += "{{first ~ ' ' if first is defined else '' }}"
template += "{{ middle ~ ' ' if middle is defined else '' }}"
template += "{{ last if last is defined else '' }}"
template = jinja2.Template(template)
result = template.render(first='John', last='Doe').strip()
A variant of the accepted answer is to use a joiner in the Jinja template:
{%- set space = joiner(" ") %}
{%- if title %}{{ space() }}{{ title }}{% endif %}
{%- if first %}{{ space() }}{{ first }}{% endif %}
{%- if middle %}{{ space() }}{{ middle }}{% endif %}
{%- if last %}{{ space() }}{{ last }}{% endif %}
This works without any extensions, custom filters or post-processing but is relatively verbose.

DBT using macros within external schema yml file

We define external redshift spectrum table using an yml file. Like the one below.
- name: visitor
description: 'visitor data'
external:
location: "s3://{{ env_var('ENV') }}-temp-raw-s3/{{ s3_prefix({{ env_var('ENV') }}) }}/Visitor"
file_format: parquet
partitions:
- name: year
data_type: VARCHAR(10)
vals: # macro w/ keyword args to generate list of values
macro: dbt.dates_in_range
args:
start_date_str: '{{ var("START_DT") }}'
end_date_str: '{{ var("START_DT") }}'
in_fmt: '%Y-%m-%d'
out_fmt: '%Y'
I would like to change the prefix of the s3 bucket based on the environment variable.
Here is the macro I have tried to change the prefix. I am calling that macro in in the yml file above in line 4 (location).
{% macro s3_prefix(env_var) %}
{% if env_var == "prod" %}
prefix_string = "prefix_prod"
{% else %}
prefix_string = "prefix_non_prod"
{% endif %}
{{ return(prefix_string) }}
{% endmacro %}
I am getting some compilation errors. Is there an easier way to achieve this? Any help would be really appreciated.

Unable to get partial to return images generated from title - Hugo

Based on this blogpost, I am trying to generate a pseudo-random thumbnail for each new post. First, in my data folder I have a bg.json which contains information about the colours and SVGs like so:
{
"colours": [
"#dfe6e9",
"#00b894"
],
"patterns": [
"data:image/svg+xml..."
]
}
Next, in the partials folder, I created a new partial called thumbnail.html which contains the following code:
{{ $hash := split (md5 .Title) "" }}
{{ $totalColours := len .Site.Data.bg.colours }}
{{ $primaryIndex := index $hash 1 }}
{{ $basedPrimaryIndex := printf "%x" $primaryIndex }}
{{ $modIndex := mod $basedPrimaryIndex $totalColours }}
{{ $primary := index .Site.Data.bg.colours $modIndex }}
{{ $secondaryIndex := index $hash 2 }}
{{ $basedSecondaryIndex := printf "%x" $secondaryIndex }}
{{ $modIndex := mod $basedSecondaryIndex $totalColours }}
{{ $secondary := index .Site.Data.bg.colours $modIndex }}
{{ $bgIndex := mod (printf "%x" (index $hash 0)) (len .Site.Data.bg.patterns) }}
{{ $bg := replace (replace (replace (replace (index .Site.Data.bg.patterns $bgIndex) "%3C" "<") "%3E" ">") "%23" "" | safeHTML) "data:image/svg+xml," "" }}
{{ $colouredBg := replace $bg "9C92AC" $secondary }}
<style>
.post__header {
--color: {{ $primary }};
--bg: url("data:image/svg+xml;charset=utf-8;base64,{{ base64Encode $colouredBg }}");
}
</style>
My theme generates portfolio cards in another partial called portfolio.html. I looked through the file and replaced the original img src with a path to my partial like so:
<div class="box-masonry">
{{ if and (isset .Params "image") .Params.image }}
{{ if eq .Params.showonlyimage true }}
<a href="{{ .Permalink }}" title="" class="box-masonry-image with-hover-overlay">
{{ else }}
<a href="{{ .Permalink }}" title="" class="box-masonry-image with-hover-overlay with-hover-icon">
{{ end }}
<img src="{{ partial "thumbnail.html" . }}" alt="" class="img-responsive">
</a>
(...)
However, I am not seeing any images when I run my hugo server. I thought this would be the neatest way to approach things, but I think the post title (which is hashed to pick a random palette/pattern) is not being passed. How can I fix this?
My repo is hosted here: https://github.com/thedivtagguy/archives
The repo for the original blogpost's code is hosted here: https://github.com/trys/random-to-a-point

importing mysql dumping file to vagrant with salt

I am using vagrant with salt to setup a dev environment but I can't find the way to import the mysql script with in the salt configuration
I've re-used an example from this script to solve it. Once the SQL is applied, a marker file is created with touch that is later checked with test:
{% for file in [
'/usr/share/zabbix-server-mysql/salt-provided-schema.sql',
'/usr/share/zabbix-server-mysql/salt-provided-images.sql',
'/usr/share/zabbix-server-mysql/salt-provided-data.sql'
] %}
{{ file }}:
file:
- managed
- makedirs: True
- source: {{ files_switch('zabbix', [ file ]) }}
cmd:
- run
- name: /usr/bin/mysql -h {{ dbhost }} -u {{ dbuser }} --password={{ dbpass }} {{ dbname }} < {{ file }} && touch {{ file }}.applied
- unless: test -f {{ file }}.applied
- require:
- file: {{ file }}
- pkg: mysql-client
{% endfor %}