How do I add value of "-" to pillar? - yaml

I have pillar that is supposed to have value of "-" (without the quotation).
I tried:
my_pillar: -
my_pillar: '-'
my_pillar: "-"
my_pillar: {% raw %}"-"{% endraw %}
{% raw %}my_pillar: "-"{% endraw %}
None of those worked and I am getting error: "block sequence entries are not allowed in this context".
I understand what the problem here is, Salt thinks that it is part of YAML definition of values, not the value itself, but how do I work around that?

As OrangeDog mentions, any type of quoting will work:
docker run --rm -it saltstack/salt /bin/sh
mkdir -p /srv/pillar
cat <<EOF>/srv/pillar/top.sls
base:
'*':
- stuff
EOF
echo "my_pillar: -" >/srv/pillar/stuff.sls
salt-call --local pillar.items -ldebug
# Error happens ^^^^^^^^^^^^^^^^^^^^^^
echo "my_pillar: '-'" >/srv/pillar/stuff.sls
salt-call pillar.items
The output for me:
local:
----------
my_pillar:
-

Related

Gomplate : bad character U+0022 '-'

I was trying out gomplate and encountered an error.
For context I've defined a template file, test.tmplt, and a datasource file, dev.yaml.
test.tmplt has the following content :
localAPIEndpoint:
advertiseAddress: {{ (datasource "k8s").api-advertise-ip }}
while dev.yaml contains the following :
api-advertise-ip: 192.168.0.1
If I try to fill in the content of test.tmplt using gomplate like so :
gomplate -d k8s=./dev.yaml -f ./test.tmplt -o test.conf
I get the following error :
09:42:44 FTL error="template: ./test.tmplt:2: bad character U+002D '-'"
Seems to me that it does not like the '-' symbol in the template file. Any workaround?Is it the intended behaviour?
Edit 1:
Thanks #icza for the answer which works correctly for the example above. Yet if I modify the yaml file to have nested fields it seems to break down.
For example
dev.yaml :
kubernetes:
api-advertise-ip: 192.168.0.0
test.tmplt :
localAPIEndpoint:
advertiseAddress: {{ index (datasource "k8s") "kubernetes.api-advertise-ip" }}
In this case the output of :
gomplate -d k8s=./dev.yaml -f ./test.tmplt -o test.conf
is :
localAPIEndpoint:
advertiseAddress: <no value>
Your "k8s" data source is a YAML config, and you want to access the api-advertise-ip property of it.
Since api-advertise-ip contains dashes, you can't use the name as-is in the template, because that's a syntax error: the template engine tries to use api as the property name, and the dash after that is a syntax error.
You have to put the property name in quotes that contains dashes: "api-advertise-ip", but this using the . selector is also invalid syntax.
Use the builtin index function to index the YAML datasource with this key:
localAPIEndpoint:
advertiseAddress: {{ index (datasource "k8s") "api-advertise-ip" }}
gomplate uses text/template under the hood, see a working example on the Go Playground.
When using index and you have multiple nested levels, provide each key as an additional parameter to index.
For example:
localAPIEndpoint:
advertiseAddress: {{ index (datasource "k8s") "kubernetes" "api-advertise-ip" }}
Try this one on the Go Playground.
For those landing here for accessing values from Kubernetes secret (with kubectl) whose keys have hyphen - in them, the solution as suggested by #icza is:
kubectl -n <namespace> \
get secret <secret-name> \
-ogo-template='{{ index .data "key-with-hyphens" | base64decode }}'

How can I convert a decimal string to an hexadecimal string?

I have a playbook that queries a server for it's SystemID which can be converted to a model number using a vendor-provided table that maps the id to a model. The server returns a decimal value but the table uses the hexadecimal equivalent.
What I want to do is to convert the decimal string to an hexadecimal string that can be matched with an entry in the vendor-provided table.
Example:
Server returns: SystemID = 1792
Matching entry in vendor table: 0x0700
I've searched in the Ansible documentation and Web searched for either a native Ansible command or jinja2 expression to do the conversion.
I've only found the int(value, base=x) jinja2 function that does the opposite of what I am trying to do.
The native python hex() command can do it. But I'd like to avoid that if possible.
Here is the playbook task that parses the servers stdout to get systemid value:
set_fact:
server_model: "{{ ( server_model_results.stdout_lines | select('match','SystemID' ) | list| first ).split('=')[1] | regex_replace('^\ |\ /$', '' ) }}"
Environment:
Ansible 2.9.7
Python 3.8.0
macOS 10.15.4
You can use a python format with the % operator inside a jinja2 template string:
$ ansible localhost -m debug -a msg="{{ '%#x' % 1792 }}"
localhost | SUCCESS => {
"msg": "0x700"
}
You will probably still have to deal with the leading 0 that is present in your file (i.e. 0x0700).
If all your values are padded to 4 hexa digits in your file (i.e. after the 0x prefix) a quick and dirty solution could be:
$ ansible localhost -m debug -a msg="0x{{ '%04x' % 1792 }}"
localhost | SUCCESS => {
"msg": "0x0700"
}
If not, you will have to implement some kind of dynamic 0 padding to the next odd number of chars yourself.
You might want to switch the 'x' type specifier to 'X' (see doc link above) if hexa digits above nine are uppercase in your vendor table
$ ansible localhost -m debug -a msg="0x{{ '%04x' % 2569 }}"
localhost | SUCCESS => {
"msg": "0x0a09"
}
$ ansible localhost -m debug -a msg="0x{{ '%04X' % 2569 }}"
localhost | SUCCESS => {
"msg": "0x0A09"
}

Ansible won't let me add quotes to my variables when I try to use "blockinfile" and "block"

Using containers, I'm trying to create a .bashrc file with Python3 Ansible v0.2.4.2.0. I'm also using Ansible roles.
- name: Adding environment vars to .bashrc file
blockinfile:
path=/.bashrc
insertafter: EOF
block: |
export VAR1={{ var1 }}
export VAR2={{ var2 }}
export VAR3={{ var3 }}
Where all 3 variables are defined in my main file, play.yml. So, let's say var1 is equal to "-a -b -c" (including the quotes), var2 is equal to "d" and var3 is equal to "e"
Then after I run play.yml, my .bashrc file looks like:
export VAR1=-a -b -c
export VAR2=d
export VAR3=e
But what I really want is
export VAR1="-a -b -c"
export VAR2="d"
export VAR3="e"
If I don't have the quotes for VAR1, then running source /.bashrc gives me:
bash: export: `-a: not a valid identifier
bash: export: `-b: not a valid identifier
bash: export: `-c: not a valid identifier
I've tried this:
- name: Creating .bashrc file
blockinfile:
path=/.bashrc
insertafter: EOF
block: |
export VAR1=\"{{ var1 }}\"
export VAR2=\"{{ var2 }}\"
export VAR3=\"{{ var3 }}\"
but that does not add quotes to my .bashrc file. I still get the same results. What can I do to add quotes? I've also tried adding \"\", which adds exactly \"\" to the beginning of each line. So that doesn't work either when I try to run source /.bashrc
Set your variables like this:
var1: '"fred"'
var2: '"barney"'
var3: '"wilma"'

Jekyll extracting filename from url with Ruby

I'm trying to extract the file name from a url on Jekyll using this ruby snippet:
{% assign filename = page.url.split('/')[-1] | replace: '.html', '.md' %}
If I just use:
{% assign filename = page.url | replace: '.html', '.md' %}
I get back the url with the replaced file type but my .split('/')[-1] doesn't seem to work.
I tried running the following in standalone ruby to ensure my syntax was right, and it returned bird as expected:
"cat/dog/b­ird".split­('/')[-1]
Why doesn't the same syntax work in my Jekyll instance? Is it that page.url isn't a string, or something else?
The problem is mixing ruby code with Liquid tags.
To extract the filename from a url in Jekyll you can use just pure Liquid template filters, using the equivalents of what you tried:
.split­('/') -> | split: '/'
[-1] -> | last
As an example with a custom URL:
{% assign url_example = "cat/dog/bird.html" %}
{% assign filename = url_example | split: '/' | last | replace: '.html', '.md' %}
{{filename}}
outputs:
bird.md

yaml multi line syntax without newline to space conversion

I have something like this dictionary:
env: qat
target_host: >
{%if env in ['prd'] %}one
{%elif env in ['qat','stg'] %}two
{%else%}three
{%endif%}
when I print it I get:
ok: [localhost] => {
"var": {
"target_host": "two "
} }
So it is converting the \n at the end of the line to a space. Which is exactly what it is supposed to do. However in this case I am just trying to spread out the lines to make the structure of the if/else more readable and I don't want the extra space. It works as expected if I put it all on one line without the > but I would like to be able to make it multiline just so its easier to read.
I found this question
Is there a way to represent a long string that doesnt have any whitespace on multiple lines in a YAML document?
So I could do:
env: qat
target_host: "{%if env in ['prd'] %}one\
{%elif env in ['qat','stg'] %}two\
{%else%}three\
{%endif%}"
And that gives the desired result.
Is there anyway to accomplish this without cluttering it up even more?
In Jinja* you can strip whitespaces/newlines by adding a minus sign to the start/end of a block. This should do the trick:
env: qat
target_host: >
{%if env in ['prd'] -%}one
{%- elif env in ['qat','stg'] -%}two
{%- else -%}three
{%- endif%}
* Jinja 2 is the templating engine used by Ansible.
Maybe what you need is the | literal?
env: qat
target_host: |
{%if env in ['prd'] %}one
{%elif env in ['qat','stg'] %}two
{%else%}three
{%endif%}
This will not 'fold' newlines into spaces, as oposed to >

Resources