chen
chen

Reputation: 4490

How can escape colon in a string within an Ansible YAML file?

I want to change one line of my code in file /var/www/kibana/config.js during installation from

elasticsearch: "http://"+window.location.hostname+":9200"

to

elasticsearch: "http://192.168.1.200:9200"

Here I tried to use lineinfile to do that as show below

- name: Comment out elasticsearch the config.js to ElasticSearch server
  lineinfile:
    dest=/var/www/kibana/config.js
    backrefs=true
    regexp="(elasticsearch.* \"http.*)$"
    line="elasticsearch\: \" {{ elasticsearch_URL }}:{{ elasticsearch_port }} \" "
    state=present

I have set variables of {{elasticsearch_URL}} and {{elasticsearch_port}} to http://192.168.1.200 and 9200, respectively.

Here is the error message I met:

ERROR: Syntax Error while loading YAML script, /Users/shuoy/devops_workspace/ansible_work/logging-for-openstack/roles/kibana/tasks/Debian.yml
Note: The error may actually appear before this position: line 29, column 25

regexp="(elasticsearch.* \"http.*)$"
line="elasticsearch\: \" {{ elasticsearch_URL }}:{{ elasticsearch_port }} \" "
                    ^

Upvotes: 32

Views: 92160

Answers (6)

udondan
udondan

Reputation: 59979

The solution that will work in any case no matter how many nested quotes you might have and without forcing you to add more quotes around the whole thing (which can get tricky to impossible depending on the line you want to write) is to output the colon through a Jinja2 expression, which simply returns the colon as a string:

{{ ":" }}

Or in your complete line:

line="elasticsearch\: \" {{ elasticsearch_URL }}{{ ":" }}{{ elasticsearch_port }} \" "

Credit to this goes to github user drewp.

Another option is to use a mutiline string. But instead of quoting the whole string, I suggest to make use of YAMLs multiline feature. For this specific case:

- name: Comment out elasticsearch the config.js to ElasticSearch server
  lineinfile: >
    dest=/var/www/kibana/config.js
    backrefs=true
    regexp="(elasticsearch.* \"http.*)$"
    line="elasticsearch\: \" {{ elasticsearch_URL }}:{{ elasticsearch_port }} \" "
    state=present

The key is the > behind lineinfile:

But let's keep in mind that this question is from 2014 and you just don't do this string soup anymore in modern ansible. Instead the ideal solution would look like this, which is much more readable and does not require to escape all the quotes etc:

- name: Comment out elasticsearch the config.js to ElasticSearch server
  lineinfile:
    dest: /var/www/kibana/config.js
    backrefs: true
    line: >
      elasticsearch: {{ elasticsearch_URL }}:{{ elasticsearch_port }}
    state: present
    regexp: (elasticsearch.* "http.*)$

Here we have the the > behind line: , so we don't need to escape anything in the value.

Other suggestions: Remove backrefs, as it is not used and state: present is default so can be removed

Upvotes: 30

bviktor
bviktor

Reputation: 1526

What I've found to be working consistently in all cases is a variable. For example, vars/main.yml:

fw_zone_str: 'Error: NAME_CONFLICT: new_zone():'

In tasks/foo.yml:

failed_when: fw_zone_str not in fw_new_zone.stderr

Upvotes: 0

Chris
Chris

Reputation: 2290

foo=bar is the more suitable format for a one-line directive, but as you're already spanning several lines with your parameters anyway, just change the = to :, and it won't fuss about having a colon in your string.

- name: Comment out elasticsearch the config.js to ElasticSearch server
  lineinfile:
    dest:     /var/www/kibana/config.js
    backrefs: true
    regexp:   'elasticsearch.* "http.*$'
    line:     'elasticsearch: "{{ elasticsearch_URL }}:{{ elasticsearch_port }}"'
    state:    present

Upvotes: 1

sunbabaphu
sunbabaphu

Reputation: 1493

you need to enclose the entire line in ", where : appears.

lineinfile:
'dest=/var/www/kibana/config.js
backrefs=true
regexp="(elasticsearch.* \"http.*)$"
line="elasticsearch\: \ {{ elasticsearch_URL }}:{{ elasticsearch_port }} \ "
state=present'  

See these pages:
Link-1 Link-2 Link-3

Upvotes: 24

theharshest
theharshest

Reputation: 7867

Just keep the colon in quotes separately -

regexp="(elasticsearch.* \"http.*)$" line="elasticsearch':' \" {{ elasticsearch_URL }}:{{ elasticsearch_port }} \" "

Upvotes: 11

Ry-
Ry-

Reputation: 224856

It’s a string already; you don’t have to (and can’t, as seen here) escape colons inside it.

line="elasticsearch: \" {{ elasticsearch_URL }}:{{ elasticsearch_port }} \" "

Upvotes: 0

Related Questions