Ansible 2.4 check for match "word" in output - regex

I would like to use ansible to check if a package name exist in an output of a command. if not exist do something.
for example :
I'm looking for the package "zip" but the problem is that it return "gzip" "zip" "unzip" and I'm looking to find only "zip" ,how to do it in a when condition
How can I use regex to match the {{ item.name }} exactly and not words that contains part of {{ item.name }}
- name: Check if Package is installed
shell: dpkg-query -f '${binary:Package}\n' -W
register: is_installed
- name: Install apt dependencies
apt:
name: "{{item.name}}{{item.version}}"
state: present
allow_unauthenticated: yes
force: yes
with_items:
- { name: 'python2.7', version: '' }
- { name: 'ruby', version: '' }
- { name: 'postgresql-9.5', version: '' }
- { name: 'postgresql-contrib-9.5', version: '' }
- { name: 'libpq-dev', version: '' }
- { name: 'nodejs', version: '=9.*' }
- { name: 'python-setuptools', version: '' }
- { name: 'python-pip', version: '' }
- { name: 'python-pkg-resources', version: '' }
- { name: 'sshpass', version: '' }
- { name: 'zip', version: '' }
- { name: 'mongodb-org', version: '=4.0.0' }
- { name: 'libfontconfig', version: '' }
- { name: 'ntp', version: '' }
- { name: 'fio', version: '' }
when: not "{{item.name}}" in is_installed.stdout

Am only partially able to test as don't have a Debian based machine in front of me.
You didn't update your Q to show the exact format of the output, so I am not sure if the command is outputting all the packages on a single line, or is outputting one per line.
If one per line, try this:
- name: Install apt dependencies
apt:
name: "{{item.name}}{{item.version}}"
state: present
allow_unauthenticated: yes
force: yes
with_items:
- { name: 'python2.7', version: '' }
- { name: 'ruby', version: '' }
when: not (is_installed.stdout_lines| map('regex_search', '^' + item.name + '$') | select('string') | list | length)
If on multiple lines, then is_installed.stdout_lines will be a list, with one package per item. Therefore we search the list for exact matches, and output the total count of matches. >0 = true.
If all on the same line, then try this instead:
- name: Install apt dependencies
apt:
name: "{{item.name}}{{item.version}}"
state: present
allow_unauthenticated: yes
force: yes
with_items:
- { name: 'python2.7', version: '' }
- { name: 'ruby', version: '' }
when: not (is_installed.stdout | search('(^| )' + item.name + '( |$)')
In this case, we need to search for the name either at the beginning of the line or preceded by a space, and then followed by a space or the end of the line, for an exact match.

Try modifying your regex like below
when: not (?<![\w\d]){{item.name}}(?![\w\d]) in is_installed.stdout

Related

How do I add to my existing Ansible Dictionary by looking something up from another dictionary?

Been at this about a week and I think it's time to post this. I'm pretty decent at ansible but clearly terrible at dictionaries.
How do I add a sub-key to a dictionary using update_list?
Alright so I have two dictionaries, one is the output of a command to pull AD Creds, the dictionary looks like this called userresult:
{
"objects": [
{
"Name" : "Administrator"
"objectSid": {
"Name" : "DOMAIN\\Administrator"
"Sid": "S-1-5-21"
}
},
{
"Name" : "Guest"
"objectSid": {
"Name" : "DOMAIN\\Guest"
"Sid": "S-1-5-22"
}
]
}
Now, I've got a dictionary that has the names and info I want to lookup (inputdictionary.yml):
dictionary:
users:
Nonexistentuser:
old_sid: 1-1-1-1
domain: nonexistentdomain
Administrator:
old_sid: 2-2-2-2
domain: DOMAIN
What I've tried:
---
- name: Update dictionary
hosts: myhosts
gather_facts: no
tasks:
- name: Get SID for user - you can ignore this part it just gets userresult
community.windows.win_domain_object_info:
filter: ObjectClass -eq 'user' -and objectCategory -eq 'Person'
properties:
- objectSid
register: userresult
- name: ready yaml dictionary
delegate_to: localhost
slurp:
path: '/home/inputdictionary.yml'
register: SourceInfo
- name: extract dictionary
set_fact:
myinfo: "{{SourceInfo['content'}] | b64decode | from_yaml ))"
- name: build a list of updates for dictionary
set_fact:
update_list: "{{ update list + update }}"
loop: "{{ myinfo.dictionary.users | dict2items }}"
loop_control:
index_var: idx
vars:
update_list: []
update:
- path: myinfo.dictonary.users[{{idx}}].new_sid
value: "TEST"
- debug:
var: update_list
Expected output:
dictionary:
users:
Nonexistentuser:
old_sid: 1-1-1-1
domain: nonexistentdomain
new_sid: TEST
Administrator:
old_sid: 2-2-2-2
domain: DOMAIN
new_sid: TEST
Current output:
TASK [build a list of updates for dictinoary]
FAILED! -> {
"msg": "template error while templating string: expected token 'end of print statement', got 'list. String: {{update list + update}}"
}
Test needs to be replaced with the new SID eventually, but I just want this step to work first..
Been trying to follow this but no avail: https://docs.ansible.com/ansible/latest/collections/ansible/utils/update_fact_module.html
Any help would be appreciated while I continue to try to fix this..
TEST needs to be replaced with the new SID eventually, but I just want this step to work first
- name: "make this working"
hosts: localhost
vars:
dictionary:
users:
Nonexistentuser:
old_sid: 1-1-1-1
domain: nonexistentdomain
Administrator:
old_sid: 2-2-2-2
domain: DOMAIN
tasks:
- name: build a list of updates for dictionary
set_fact:
update_list: "{{ update_list | d({}) | combine({ item.key: _v}) }}"
loop: "{{ dictionary.users | dict2items }}"
vars:
_k: "{{ item.key }}"
_v: "{{ item.value | combine({'new_sid': newsid}) }}"
newsid: "TEST"
- debug:
msg: '{{ update_list }}'
result:
ok: [localhost] => {
"msg": {
"Administrator": {
"domain": "DOMAIN",
"new_sid": "TEST",
"old_sid": "2-2-2-2"
},
"Nonexistentuser": {
"domain": "nonexistentdomain",
"new_sid": "TEST",
"old_sid": "1-1-1-1"
}
}
}

Access yaml list of dictionaries file with ansible

So I am trying take values from file, let's call it "test.yaml"
file looks like this (sorry for long output, but it is the shortest cut containing all patterns and structure):
---
results:
- failed: false
item: XXX.XX.XX.XX
invocation:
module_args:
validate_certs: false
vm_type: vm
show_tag: false
username: DOMAIN\domain-user
proxy_host:
proxy_port:
show_attribute: false
password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER
port: XXX
folder:
hostname: XXX.XX.XX.XX
changed: false
virtual_machines:
- ip_address: XXX.XX.XX.XX
mac_address:
- XX:XX:XX:aa:XX:XX
uuid: XXXX-XX-XX-XXXX-XXXXX
guest_fullname: Red Hat Enterprise Linux X (XX-bit)
moid: vm-XXX
folder: "/DOMAIN-INTERXION/vm"
cluster:
attributes: {}
power_state: poweredOn
esxi_hostname: esx.hostname
tags: []
guest_name: VMnameXX
vm_network:
XX:XX:XX:aa:XX:XX:
ipv6:
- XX::XXX:XX:XXXX
ipv4:
- XXX.XX.XX.XX
I would like, for example to have something like:
results.invocation.virtual_machines.ip_address
results.invocation.module_args.user_name
I tried all kind of stuff but it doesn't work :)
last attempt is this:
---
- name: demo how register works
hosts: localhost
tasks:
- name: Include all .json and .jsn files in vars/all and all nested directories (2.3)
include_vars:
file: test.yml
name: vm
- name: debug
debug:
msg: "{{ item.0.item }}"
with_subelements:
- "{{ vm.results }}"
- virtual_machines
register: subelement
following your structure and after fixing some errors:
results.invocation.virtual_machines.ip_address is results[0].virtual_machines[0].ip_address
and
results.invocation.module_args.user_name is results[0].invocation.module_args.username
(results and virtual_machines are arrays, write results[0] or results.0 is same)
so a sample of playbook doing job:
- name: vartest
hosts: localhost
tasks:
- name: Include all .json and .jsn files in vars/all and all nested directories (2.3)
include_vars:
file: test.yml
name: vm
- name: ip
set_fact:
ipadress: "{{ vm.results[0].virtual_machines[0].ip_address }}"
- name: username
set_fact:
username: "{{ vm.results[0].invocation.module_args.username }}"
- name: display
debug:
msg: "ip: {{ ipadress }} and username: {{ username }}"
result:
ok: [localhost] =>
msg: 'ip: XXX.XX.XX.XX and username: DOMAIN\domain-user'

Ansible jinja2 templating

In Ansible, I currently have vars set out like this
container_a_version: 1
container_b_version: 6
container_c_version: 3
container_d_version: 2
...
containers:
- container_a
- container_b
- container_c
- container_d
...
Each container has its own template file which has a line like this
image: registry.sportpesa.com/sportpesa/global/container-a:{{ container_a_version }}
My playbook
- name: Copy templates
template:
src: templates/docker-compose-{{ item }}.yml
dest: /srv/docker-compose-{{ item }}.yml
loop: "{{ containers }}"
If I want to deploy only container a and c. I change my variable to this
containers:
- container_a
# - container_b
- container_c
# - container_d
What I want to do condense my variables to just have 1 var like this
containers:
- { name: a, version: 1 }
- { name: b, version: 6 }
- { name: c, version: 3 }
- { name: d, version: 2 }
However I'm not sure how I can call the container version in my template. Is this possible?
For example, the playbook
shell> cat pb.yml
- hosts: localhost
vars:
containers:
- {name: a, version: 1}
- {name: b, version: 2}
tasks:
- template:
src: containers.txt.j2
dest: containers.txt
and the template
shell> cat containers.txt.j2
{% for item in containers %}
name: {{ item.name }} version {{ item.version }}
{% endfor %}
give
shell> cat containers.txt
name: a version 1
name: b version 2
It's possible to iterate the list
- debug:
msg: "image: registry.example.com/container-{{ item.name }}:container_{{ item.version }}_version"
loop: "{{ containers }}"
gives
msg: 'image: registry.example.com/container-a:container_1_version'
msg: 'image: registry.example.com/container-b:container_2_version'
Since you want two different templates, each with it's respective container name and version without looping the containers variable. You can use a playbook that renders two templates. In my example I will call the templates:
container-a
container-b
The template container-a.j2:
image: registry.example.com/container-{{ containers[0]['name'] }}:{{ containers[0]['version'] }}
The template container-b.j2:
image: registry.example.com/container-{{ containers[1]['name'] }}:{{ containers[1]['version'] }}
Then my playbook will have below tasks:
vars:
containers:
- { name: a, version: 1 }
- { name: b, version: 2 }
tasks:
- template:
src: "container-{{ containers[0]['name'] }}.j2"
dest: "/tmp/container-{{ containers[0]['name'] }}"
- template:
src: "container-{{ containers[1]['name'] }}.j2"
dest: "/tmp/container-{{ containers[1]['name'] }}"
When this playbook is run, it renders /tmp/container-a:
image: registry.example.com/container-a:1
and /tmp/container-b:
image: registry.example.com/container-b:2

Azure devops: pass variable group as parameter to Template

I am using Azure devops yml pipeline at code base.
I have created Variable Group at pipeline (pipeline > Library > variable group > called 'MY_VG')
In my pipeline (yml) file i want to send this variable group MY_VG to template my_template.yml as parameter.
But this parameter MY_VG is not being expanded when i use it under 'Variable' (though while printing it gives me value)
How to access the value of this MY_VG in the template here group: ${{parameters.variable_group}} shown below?
(I am calling a template file my_template_iterator.yml which iterates the environments and call the my_template.yml)
azure-pipelines.yml
resources:
repositories:
- repository: templates
type: git
name: MY_PROJECT/GIT_REPO_FOR_TEMPLATE
stages:
- stage: "CheckOut"
displayName: Checkout
jobs:
- job: Checkout
displayName: Checkout Application
pool:
name: $(my_pool_name)
workspace:
clean: all
steps:
- checkout: self
- template: folder_name/my_template_iterator.yml#templates
parameters:
agent_pool_name: $(my_pool)
db_resource_path: $(System.DefaultWorkingDirectory)/src/main/resources/db
envs:
- env:
env_name: 'dev'
variable_group: MY_VG
pipeline_environment_name: DEV_ENV
is_master: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
## Iterator: my_template_iterator.yml
parameters:
agent_pool_name: ''
db_resource_path: ''
envs: {}
stages:
- ${{ each env in parameters.envs }}:
- template: my_template.yml
parameters:
agent_pool_name: ${{ parameters.agent_pool_name }}
db_resource_path: ${{ parameters.db_resource_path }}
env_name: ${{ env.env_name }}
variable_group: ${{ env.variable_group }}
pipeline_environment_name: ${{ env.pipeline_environment_name }}
is_master: ${{ env.is_master }}
## my_template.yml
parameters:
- name: 'variable_group'
type: string
default: 'default_variable_group'
stages:
- stage:
displayName: Read Parameters
jobs:
- job: READ
displayName: Reading Parameters
steps:
- script: |
echo variable_group: ${{parameters.variable_group}}
- stage:
displayName: Deployment
variables:
group: ${{parameters.variable_group}}
condition: ${{parameters.is_master}}
I tested with above your yaml files. It seems fine. However i found a small mistake that you missed a - when you define a variable group in my_template.yml of yours. Maybe that is the reason the variable group didnot expand for you.
variables:
# a variable group
- group: myvariablegroup
I modified your my_template.yml file a little bit. And i got it working. See below:
parameters:
- name: 'variable_group'
type: string
default: 'default_variable_group'
- name: agent_pool_name
default: ""
- name: env_name
default: ""
- name: db_resource_path
default: ""
- name: pipeline_environment_name
default: ""
- name: is_master
default: ""
stages:
- stage:
displayName: ${{parameters.env_name}}
## i changed here add '-' to group
variables:
- group: ${{parameters.variable_group}}
jobs:
- job: READ
displayName: Reading Parameters
steps:
- script: |
echo variable_group: ${{parameters.variable_group}}
- powershell: echo "$(variableName-in-variablegroup)"
Ok. I'm not sure if this doable in a way how you are trying. But I tried another approach which seems to be working.
First let's define template for simple stage:
parameters:
- name: env_name
type: string
default: 'dev'
- name: variable_group
type: string
default: 'MY_VG'
- name: pipeline_environment_name
type: string
default: 'DEV_ENV'
stages:
- stage: ${{ parameters.env_name }}
jobs:
- job: angularinstall
steps:
- script: echo "${{ parameters.env_name }}"
- script: echo "${{ parameters.variable_group }}"
- script: echo "${{ parameters.pipeline_environment_name }}"
then template for main build:
parameters:
- name: stages # the name of the parameter is stageList
type: stageList # data type is stageList
default: [] # default value of stageList
stages: ${{ parameters.stages }}
and then we can combine them together in main build file:
extends:
template: template.yaml
parameters:
stages:
- template: stageTemplate.yaml
parameters:
env_name: 'dev'
variable_group: 'MY_VG'
pipeline_environment_name: 'DEV_ENV'
- template: stageTemplate.yaml
parameters:
env_name: 'stage'
variable_group: 'MY_STAGE'
pipeline_environment_name: 'STAGE_ENV'
And for that I got:
Does it sth what bring you closer to your solution?

CloudBuild Bash-style string manipulation

I need to extract a string from the TAG_NAME default variable. but i could not get this to work.
- name: 'gcr.io/cloud-builders/git'
id: find-folder-name
dir: ${_DIR}
entrypoint: 'bash'
args:
- '-c'
- |
if [ ${_STRATEGY} = "tag" ]; echo "tag name " $TAG_NAME; echo ${TAG_NAME%\.np\.v\.*};fi
volumes:
- name: 'ssh'
path: /root/.ssh
secretEnv: ['GCLOUD_SERVICE_KEY']
The regex works perfect fine if i just run it in gitbash locally.
The output is follow, i am expecting it will also print "test" as well, but it is empty. here is the output
tag name test.np.v.1.1.7
Fixed by assigning to a variable
release=$TAG_NAME;echo ${release%\.np\.v\.*}