How to delete environment variables using Ansible - regex

I want to delete below environment variables from etc/environment using Ansible.
export http_proxy="http://194.138.0.25:9400/"
export https_proxy="http://194.138.0.25:9400/"
export ftp_proxy="http://194.138.0.25:9400/"
Below code deletes only one env variable.
name: Delete variables from etc/environment
replace:
path: /etc/environment
regexp: 'export http_proxy="http://194.138.0.25:9400/"'
replace: ''
How to delete all the 3 environment variables?
After deleting/replacing any one env variable, empty line is being added. how to avoid this?

Use lineinfile. For example, the task below will remove all lines starting export and including the address 194.138.0.25:9400/
- lineinfile:
path: /tmp/environment
regex: '^export.*194\.138\.0\.25:9400.*$'
state: absent
Given the file
shell> cat /tmp/environment
first line
export http_proxy="http://194.138.0.25:9400/"
export https_proxy="http://194.138.0.25:9400/"
export ftp_proxy="http://194.138.0.25:9400/"
last line
Running the playbook with options --check --diff gives (abridged)
TASK [lineinfile] ***************************************************
--- before: /tmp/environment (content)
+++ after: /tmp/environment (content)
## -1,5 +1,2 ##
first line
-export http_proxy="http://194.138.0.25:9400/"
-export https_proxy="http://194.138.0.25:9400/"
-export ftp_proxy="http://194.138.0.25:9400/"
last line

Related

Ansible: how to change/replace a port number in a configuration file

I am a newbie in the ansible world and one of the first thing I want to do is to change the default port in a configuration file: /etc/xrdp/xrdp.ini
Every time where value 3389 is found, I would like to replace it by a new value given by the variable xrdp_port
vars:
xrdp_port: 3391
I thought that something like the following declaration would work but unfortunately it doesn't
- name: tune /etc/xrdp/xrdp.ini
replace:
path: "/etc/xrdp/xrdp.ini"
regexp: '(.*)3389(.*)'
replace: '\1{{ xrdp_port }}\2'
I would strongly appreciate any help
Thank you
Q: "Where value 3389 is found replace it with a new value given by the variable xrdp_port."
A: Given the file xrdp.ini for testing
shell> cat xrdp.ini
port=3389
the task below does the job
- replace:
path: xrdp.ini
regexp: '^(\s*)port(\s*)=(\s*)3389(\s*?)$'
replace: '\1port={{ xrdp_port }}'
vars:
xrdp_port: 3391
Running the play with options --check --diff will display the difference
TASK [replace] ********************************************************
--- before: xrdp.ini
+++ after: xrdp.ini
## -1 +1 ##
-port=3389
+port=3391
changed: [localhost]
When the port is not set to default
shell> cat xrdp.ini
port=3999
the task will do nothing
TASK [replace] *****************************************************
ok: [localhost]
But, the limitation of replacing '3389' only doesn't make sense. '3389' is the default. No 'port' configuration or 'port=3389' is the same. It would make sense to add 'port={{ xrdp_port }}' always, e.g.
- replace:
path: xrdp.ini
regexp: '^(\s*)port(\s*)=(.*?)$'
replace: '\1port={{ xrdp_port }}'
vars:
xrdp_port: 3391
will replace any port's value by the value of xrdp_port
TASK [replace] *****************************************************
--- before: xrdp.ini
+++ after: xrdp.ini
## -1 +1 ##
-port=3999
+port=3391
changed: [localhost]
But, the line won't be added if the 'port' option is missing, e.g.
shell> cat xrdp.ini
security_layer=tls
the task will do nothing
TASK [replace] *****************************************************
ok: [localhost]
It would be better to use the module lineinfile instead of replace, e.g.
- lineinfile:
path: xrdp.ini
regexp: '^(\s*)port(\s*)=(.*)$'
line: 'port={{ xrdp_port }}'
vars:
xrdp_port: 3391
will add the line
TASK [lineinfile] **************************************************
--- before: xrdp.ini (content)
+++ after: xrdp.ini (content)
## -1 +1,2 ##
security_layer=tls
+port=3391
changed: [localhost]
If the option 'port' is present in the file the same task will also replace any port's value by the value of xrdp_port
shell> cat xrdp.ini
port=3999
TASK [lineinfile] **************************************************
--- before: xrdp.ini (content)
+++ after: xrdp.ini (content)
## -1 +1 ##
-port=3999
+port=3391
changed: [localhost]

How to set variable inline in gitlab-ci.yaml based on regex matching?

I am trying to create a variable in gitlab-ci.yaml based on the name of the branch.
Suppose I am pushing to a branch named 3.2.7
Here is the situation:
include:
- template: "Workflows/Branch-Pipelines.gitlab-ci.yml"
variables:
PRODUCTION_BRANCH: "master"
STAGING_BRANCH: (\d)\.(\d)\.(\d)
.deploy_rules:
rules:
- if: '$CI_COMMIT_BRANCH =~ /$STAGING_BRANCH/'
variables:
SERVER_PORT: 3007 # TODO: should be 300d ; d is the second digit
I want to generate 3002 inline using regex matching.
How can I do this?
I have done some research and seems I have to use sed but I am not sure if it is the best way to do it and how to do it.
TO MAKE THE PROBLEM SIMPLER
include:
- template: "Workflows/Branch-Pipelines.gitlab-ci.yml"
variables:
TEST_VAR: sed -E 's/(\d)\.(\d)\.(\d)/300\2/gm;t;d' <<< $CI_COMMIT_BRANCH
stages:
- temp
temp:
stage: temp
script:
- echo $TEST_VAR
Should be echoing 3002 but it is echoing sed -E 's/(\d)\.(\d)\.(\d)/300\2/gm;t;d' <<< 3.2.7
You can't use variables in the regex pattern. You just have to write the regex verbatim, it cannot be directly parameterized. You also cannot use sed or other Linux utilities in variables: or other parts of your yaml. You're bound to the limitations of YAML specification and features provided by GitLab.
However, there is an option available to you that will fit your stated use case.
Dynamic variables
TEST_VAR: sed -E 's/(\d).(\d).(\d)/300\2/gm;t;d' <<< $CI_COMMIT_BRANCH
While you can't use sed or other utilities directly in variables: declarations, you can use dotenv artifacts via artifacts:reports:dotenv to set variables dynamically.
For example, a job can use sed or whatever other utilities you like to create variables which will be used by the rest of the pipeline.
stages:
- temp
create_variables:
stage: .pre
script:
- TEST_VAR="$(sed -E 's/(\d)\.(\d)\.(\d)/300\2/gm;t;d' <<< ${CI_COMMIT_BRANCH})"
- echo "TEST_VAR=${TEST_VAR}" >> dotenv.txt
artifacts:
reports:
dotenv: dotenv.txt
temp:
stage: temp
script:
- echo $TEST_VAR
Here, the .pre stage is used, which is a special stage that is always ordered before every other stage. The dotenv artifact from the create_variables job will dynamically create variables for the jobs in subsequent stages that receive the artifact.

Ansible lineinfile regexp to manage /etc/exports

I've been hitting a wall trying to get /etc/exports managed via Ansible.
I've got a role that installs a piece of software on a VM, and I want to then add an entry ot /etc/exports on the NFS server, for that specific VM, so it's able to access the NFS shares needed.
Lineinfile sounds like the way to go, but sofar I can't figure out how to properly write this.
I want this to:
not modify if the host is in the line, no matter where
add the NFS share and the host if there's no line for the NFS share
add the host to the share in case it isn't in there.
The latest installment of my 'add to /etc/exports' that thought should work, but doesn't, is:
- name: Add hosts to mountpoint line
ansible.builtin.lineinfile:
path: /etc/exports
line: '\1 {{ host_ip }}(root_squash,no_subtree_check)'
regex: '^((?!{{ volume_mountpoint }}.*{{ host_ip }}\(root_squash,no_subtree_check\).*).*)$'
backrefs: yes
but i'm still getting all kinds of weird side effects. I've used backreferences etc before, but somehow this one keeps tripping me up.
Anyone who sees what's gong wrong?
Typical /etc/exports entry:
/srv/files 172.16.0.14(rw,no_root_squash,no_subtree_check)
It's not possible in one step to modify a line using backreferences or add the line if missing. To modify the existing mount point the back-references are needed. For example, given the files for testing
shell> cat etc/export1
/srv/files 172.16.0.14(rw,no_root_squash,no_subtree_check)
shell> cat etc/export2
/srv/files 172.16.0.15(rw,no_root_squash,no_subtree_check)
shell> cat etc/export3
/srv/download 172.16.0.14(rw,no_root_squash,no_subtree_check)
the task
tasks:
- lineinfile:
path: "etc/{{ item }}"
regex: '^{{ mount }}(\s+)({{ ipr }})*({{ optionsr }})*(\s*)(.*)$'
line: '{{ mount }}\g<1>{{ ip }}{{ options }} \g<5>'
backrefs: true
vars:
mount: /srv/files
ipr: '172\.16\.0\.14'
ip: '172.16.0.14'
optionsr: '\(.*?\)'
options: '(root_squash,no_subtree_check)'
loop:
- export1
- export2
- export3
gives
--- before: etc/export1 (content)
+++ after: etc/export1 (content)
## -1 +1 ##
-/srv/files 172.16.0.14(rw,no_root_squash,no_subtree_check)
+/srv/files 172.16.0.14(root_squash,no_subtree_check)
changed: [localhost] => (item=export1)
--- before: etc/export2 (content)
+++ after: etc/export2 (content)
## -1 +1 ##
-/srv/files 172.16.0.15(rw,no_root_squash,no_subtree_check)
+/srv/files 172.16.0.14(root_squash,no_subtree_check) 172.16.0.15(rw,no_root_squash,no_subtree_check)
changed: [localhost] => (item=export2)
ok: [localhost] => (item=export3)
The first two files are all right. The problem is the third file. The line hasn't been added to the file. Quoting from backrefs
"... if the regexp does not match anywhere in the file, the file will be left unchanged."
The explanation is simple. There are no groups if the regex doesn't match. If there are no groups the line can't be created.
On the other hand, quoting from regexp
"... If the regular expression is not matched, the line will be added to the file ..."
As a result, it's not possible to ask lineinfile to add a line if the regexp does not match and, at the same time, to do nothing if the regexp is matched. If the regexp is matched you need back-references. If you use back-references you can't add a missing line.
To solve this problem read the content of the files and create a dictionary
- command: "cat etc/{{ item }}"
register: result
loop: [export1, export2, export3]
- set_fact:
content: "{{ dict(_files|zip(_lines)) }}"
vars:
_lines: "{{ result.results|map(attribute='stdout_lines')|list }}"
_files: "{{ result.results|map(attribute='item')|list }}"
gives
content:
export1:
- /srv/files 172.16.0.14(rw,no_root_squash,no_subtree_check)
export2:
- /srv/files 172.16.0.15(rw,no_root_squash,no_subtree_check)
export3:
- /srv/download 172.16.0.14(rw,no_root_squash,no_subtree_check)
Now add the line only if missing, i.e. do not replace the line if the mount point is already there
- lineinfile:
path: "etc/{{ item }}"
line: '{{ mount }} {{ ip }}{{ options }}'
vars:
mount: /srv/files
ip: '172.16.0.14'
options: '(root_squash,no_subtree_check)'
loop: "{{ content|list }}"
when: content[item]|select('search', mount)|length == 0
gives
skipping: [localhost] => (item=export1)
skipping: [localhost] => (item=export2)
--- before: etc/export3 (content)
+++ after: etc/export3 (content)
## -1 +1,2 ##
/srv/download 172.16.0.14(rw,no_root_squash,no_subtree_check)
+/srv/files 172.16.0.14(root_squash,no_subtree_check)

Cloudbuild.yaml command with nested quotes

I am trying to run the following command found at http://blog.wrouesnel.com/articles/Totally%20static%20Go%20builds/:
CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' .
The two inner layers of quotes are tripping me up. How to deal with this in a cloudbuild.yaml file?
Escaping quotes don't seem to work:
steps:
- name: 'gcr.io/cloud-builders/go'
args: ['build', '-o', 'main', '-ldflags', "'-extldflags \"-static\"'", '.']
env:
- 'GOOS=linux'
Update:
There is no need for such quotes. See comment in Github here: https://github.com/GoogleCloudPlatform/cloud-builders/issues/146#issuecomment-337890587
===
Original Answer
Well, to quote ' within '-quoted strings, use '' as per YAML specification:
http://yaml.org/spec/current.html#id2534365
e.g. 'here''s to a toast!'
For the above args, it would be:
['build', '-o', 'main', '-ldflags', '''-extldflags "-static"''', '.']
Whether or not the command works within Cloud Builder is beyond the scope of this question.

Ansible "lineinfile": add new line (with PATH=) or append to existing line (with PATH=)

I am trying to replace or append a path part to the path definition in /etc/environment on a linux box.
Here's what I have:
//all.yml
my_path: "/usr/bin:/usr/sbin"
my_extra_path: "/usr/extra/path"
In my role-file:
//updatePath.yml
- name: update /etc/environment
lineinfile:
dest=/etc/environment
state=present
backrefs=yes
regexp='PATH=({{ my_path }}:?)?({{ my_extra_path }}:?)?(.*)'
line='PATH={{ my_extra_path }}:{{ my_extra_path }}:\3'
Now when I run the role, it works fine updating an existing PATH-line, but not creating duplicates within the line or even duplicate lines. So far so good.
When there is no line with "PATH=" present, I would expect it to add a new one. But it doesn't.
Is my expectation wrong or where lies the problem?
You are using the backrefs: true flag, which prevents lineinfile from changing the file if the line does not already exist. From the docs:
Used with state=present. If set, line can contain backreferences (both
positional and named) that will get populated if the regexp matches.
This flag changes the operation of the module slightly; insertbefore
and insertafter will be ignored, and if the regexp doesn't match
anywhere in the file, the file will be left unchanged. If the regexp
does match, the last matching line will be replaced by the expanded
line parameter.
Since you need to create the line if it does not exist, you should use:
- name: Check whether /etc/environment contains PATH
command: grep -Fxq "PATH=" /etc/environment
register: checkpath
ignore_errors: True
changed_when: False
//updatePath.yml
- name: Add path to /etc/environment
lineinfile:
dest=/etc/environment
state=present
regexp='^PATH='
line='PATH={{ my_extra_path }}'
when: not checkpath.rc == 0
- name: update /etc/environment
lineinfile:
dest=/etc/environment
state=present
backrefs=yes
regexp='PATH=({{ my_path }}:?)?({{ my_extra_path }}:?)?(.*)'
line='PATH={{ my_extra_path }}:{{ my_extra_path }}:\3'
when: checkpath.rc == 0
Same idea as here : https://stackoverflow.com/a/40890850/7231194 or here : https://stackoverflow.com/a/40891927/7231194
Steps are:
Try to replace the line.
If replace mod change it. Cool, it's over !
If replace mod doesn't change, add the line
Example
# Vars
- name: Set parameters
set_fact:
my_path: "/usr/bin:/usr/sbin"
my_extra_path: "/usr/extra/path"
# Tasks
- name: Try to replace the line if it exists
replace:
dest : /dir/file
replace : 'PATH={{ my_extra_path }}'
regexp : '^PATH=.*'
backup : yes
register : tryToReplace
# If the line not is here, I add it
- name: Add line
lineinfile:
state : present
dest : /dir/file
line : '{{ my_extra_path }}'
regexp : ''
insertafter: EOF
when: tryToReplace.changed == false