how to replace a value in yaml file - bash

The yaml file is like this:
settings:
clusterName: dev
dbServer: test.db.com
dcsHostName: dev
overrideDevRepo: "true"
globalSuspend: "true"
sharedConfig: "true"
I want to pass globalSuspend as a toggle variable, update true to false or false to true, but as helm need the quote, so quote are needed, also yaml is format sensitive, the leading spaces must be kept as same. Need a way to do it saltstack simple cmd.run or state playbook. Or at least please help on how to do in bash. But I find my command works in bash does not work in saltstack as : colon is a trouble in salt. thanks.
"toggle the suspend value":
cmd.run:
- name: sed -i '/globalSuspend/!b;c \ \ globalSuspend: "{{suspend}}"' settings.yaml
- runas: vagrant
The above does not work because of the colon and also does not keep the leading spaces.

Colon is a special character in YAML. Use a literal block scalar to treat everything as content:
"toggle the suspend value":
cmd.run:
- name: |-
sed -i '/globalSuspend/!b;c \ \ globalSuspend: "{{suspend}}"' settings.yaml
- runas: vagrant
| starts a literal block scalar. Each following line that is more indented is part of the scalar. The - means that the final line break is not part of the scalar (wich it would otherwise be).

The simplest way to do this is with a file.serialize state.
toggle the suspend value:
file.serialize:
- name: settings.yaml
- dataset:
settings:
globalSuspend: "{{ suspend }}"
- serializer: yaml
- merge_if_exists: true
More specific states are always preferred to a generic cmd.run, as they are state-aware and more efficient to run.

Related

Ansible 2.9 - Escape a single "\" backslash being passed into win_command from variable

vars:
- windowsLogonAccount: NT AUTHORITY\SYSTEM
tasks:
- name: Install Agent via CMD
win_command: "config.cmd --windowsLogonAccount '{{ windowsLogonAccount }}'"
args:
chdir: "c:/agent"
I'm attempting to get just a single backslash to pass via Ansible to Windows. I've tried double backslashes "\\" and I've tried {{ var | safe }}, but without luck. I'm hoping somebody in the community can point me in the right direction. I can't believe it is as complicated as some of the other examples I've seen using replace and regex...
Everything I try I keep getting a double backslash:
2021-10-19T04:45:52.8643709Z TASK [Get Variable Output to Screen] *******************************************
2021-10-19T04:45:52.9042957Z "msg": "My Variable Test Area 'NT AUTHORITY\\SYSTEM'"
I came here having not the exact same problem, but a similar one (passing an escaped backslash (\\) to the command), and my solution might also help here. When inserting variables into the command for command or win_command, it is always good to pipe the variable to the quote filter to preserve the content of the variable as is. In your case:
win_command: "config.cmd --windowsLogonAccount {{ windowsLogonAccount | quote }}"
----Resolved----
So this is a unique thing with Ansible Outputs to Terminal. They write output in valid JSON and thus "auto" escape special characters like backslashes in the output. But the actual value passed during run-time does not contain both back slashes. I'm posting this in case any other Ansible noobs run into this surprise.
Example output to screen:
2021-10-19T04:46:11.6003956Z: [COMPUTERNAME]: CHANGED! => {"changed": true, "cmd": "config.cmd --unattended --windowsLogonAccount 'NT AUTHORITY\SYSTEM'
Actual output to host:
config.cmd --unattended --windowsLogonAccount 'NT AUTHORITY\SYSTEM'

Ansible: Use newline character in multiline string

I'm using a win_lineinfile module and trying to use manual newline characters. It works just fine if the line argument of the module is only on one line but the moment I use multiline it breaks.
I'm trying to do this
- name: Something
win_lineinfile:
path: some_path
line: |
firstline\r\n
secondline
but it doesn't work.
This does but I lose the ability of using multiline string.
- name: Something
win_lineinfile:
path: some_path
line: firstline\r\nsecondline

Ansible/Jinja2 asterisk conditional

Trying to update a LDAP entry via Ansible, but I want to make sure that the LDAP host wildcard ("*") is not in the host list. If I use "*" not in hosts or '*' not in hosts, Ansible does not like those. I've also tried Jinja2 search filters. Any help would be great!
The problem has nothing to do with the asterisk. It is a pure yaml syntax problem
In yaml, if you quote a variable, the representation of the value will start with a single or double quote, then you get the value itself and the closing quote. After that, the yaml parser is expecting a yank <block end>, in your specific case a new line to move on to the next value definition.
In your example, your when clause value starts with a quote. So you have to quote your entire value:
when: '"*" not in hosts'
# or
when: "'*' not in hosts"
# even
when: "\"*\" not in hosts"
A good and more readable alternative IMO is to use a yaml scalar block marker:
when: >-
"*" not in hosts
Figured this out. Was trying to do it with pipes and didn't need to.
when:
- var is not regex("\\*")

Anisble Yaml file formating for quotes

I'm running an ansible playbook that allows me to (or should allow me to) replace two lines in a configuration file for a remote server. Most of the file replacements are dictionary style entries where neither the key nor the value have quotes. But there is one replacement where the name needs to be quoted. Here is the task from the ansible playbook:
- name: Enable traefikExporter within vars.jsonnet configuration file.
ansible.builtin.replace:
path: /home/bill/cluster-monitoring/vars.jsonnet
regexp: "name: 'traefikExporter',[\n\r].*[\n\r]"
replace: |6
name: 'traefikExporter',
enabled: true,
The error thrown is:
The offending line appears to be
replace: |6
name: 'traefikExporter'
^ here
and it notes that it is a mismatched quote. But I've tried changing the yaml replace parameter to > and using \n for line breaks on a single line as well as the | with quoted lines. They all throw versions of the mismatched quote error.
For reference, the following task, which is immediately above this task, runs correctly without errors:
- name: Enable k3s Monitoring within vars.jsonnet configuration file.
ansible.builtin.replace:
path: /home/bill/cluster-monitoring/vars.jsonnet
regexp: "\ k3s: {[^}]*},"
replace: |2
k3s: {
enabled: true,
master_ip: ['192.168.2.139'],
},
The closest thing I could find is here, but this didn't work. In both cases the regexp covers multiple lines and the replace covers the same lines identified by the regexp. What am I missing?
update
I also tried replacing the replacement text and now believe that the actual formatting issue is in the regexp: "name: 'traefikExporter',[\n\r].*[\n\r]" line. No matter what I place in the replace line it throws the error. I think the quotes in the regexp are the issue.
work around
I came up with a work around but it still isn't right. The following is very close to what I'd like - but a bit frustrated that it isn't exactly what I expected:
- name: Enable traefikExporter within vars.jsonnet configuration file.
ansible.builtin.replace:
path: /home/bill/cluster-monitoring/vars.jsonnet
regexp: "name: 'traefikExporter',[\n\r].*"
replace: >4
name: 'traefikExporter',
enabled: true,
The |6 or >6 was the problem - but not sure why. My expected behavior was to have a 6 space indent. But this is the thing throwing the error. When I put it to 4 there is no quote error. But as you can see - to get the formatting right I have to do some weird spacing (the name: is the correct indentation with the 4, but I have to add 6 actual spaces to get the next line to align. Not part of this question - but neither the | nor the > seems to impact the trailing return in both cases there is an extra line after the replacement.
YAML processes escape sequences in double-quoted scalars, so you should use
regexp: "name: 'traefikExporter',[\\n\\r].*[\\n\\r]"
I suggest however to use a block scalar to avoid escaping hell:
regexp: >-
name: 'traefikExporter',[\n\r].*[\n\r]
Regarding the indentation indicator, this cannot work:
replace: |6
name: 'traefikExporter',
enabled: true,
You are basically saying „the following block scalar has 6 spaces indentation in addition to the indentation of the replace: key“. However, it only has two, which makes the YAML parser immediately drop out of block scalar parsing mode. The following error results from the YAML parser trying to interpret what you intend to be the block scalar's content as part of the YAML structure.
I suggest doing:
replace: |-2
name: 'traefikExporter',
enabled: true,
to give the block scalar 2 space in front of each line (which seems to be what you want) and also to remove the trailing newline (with the -).

How do I convert a bash command for connect a docker registry to a yaml config file?

Following this tutorial to connect a local docker registry to the KIND cluster there's the below chunk of code in the bash script. I want to use my config file, but I don't know how the below chunk fits in (there's a lot of dashes and pipes in the syntax).
cat <<EOF | kind create cluster --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
containerdConfigPatches:
- |-
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:${reg_port}"]
endpoint = ["http://${reg_name}:${reg_port}"]
EOF
My config file:
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 8080
hostPort: 80
protocol: TCP
- role: worker
- role: worker
- role: worker
- role: worker
In the shell fragment you show, everything between the first and last lines, including the dashes and pipes, is a valid YAML file; the only processing the shell does is replacing ${reg_name} and ${reg_port} with the values of the corresponding environment variables.
If you want to merge this with your existing kind config file, you should be able to just combine the top-level keys:
apiVersion: kind.x-k8s.io/v1alpha4
kind: Cluster
nodes:
- role: control-plane
et: cetera
containerdConfigPatches:
- |-
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:5000"]
endpoint = ["http://kind-registry:5000"]
If you had other containerdConfigPatches, the sequence of items starting with - on each line is a YAML list (like you have in nodes:) and you could add this patch to the end of the list. (This is a little unlikely since this option isn't documented in the kind Configuration documentation.)
Here documents in YAML are problematic anyway. Try using e.g. printf instead, maybe?
printf '%s\n' \
'kind: Cluster' \
'apiVersion: kind.x-k8s.io/v1alpha4' \
'containerdConfigPatches:' \
'- |-' \
' [plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:${reg_port}"]' \
' endpoint = ["http://${reg_name}:${reg_port}"]' |
kind create cluster --config=-
Lucky your string doesn't contain any single quotes, so we can safely use those for wrapping. Also lucky your data doesn't contain any shell variable expansions or command substitutions, so we can use single (verbatim) quotes.
For the record, if you need to embed a literal single quote,
'you can'"'"'t get there from here'
produces the literal quoted string
you can't get there from here
(look closely; that's a single-quoted string, adjacent to a double-quoted literal single quote "'", adjacent to another single-quoted string) and if you need to expand variables or command substitutions, you will need to switch to double quotes around those strings. Example:
printf '%s\n' \
'literal $dollar sign in single quotes, the shell won'"'"'t touch it' \
"inside double quotes, $HOME expands to your home directory" \
'you can combine the two, like '"$(echo '"this"')"', too!'

Resources