Extract substring from variable in Ansible - regex

Edited:
I wrote this playbook but it does not show the extracted variable:
---
- hosts: fppc
gather_facts: false
remote_user: xyz
connection: local
tasks:
- name: N1
ios_command:
commands:
- sh run | i bann
register: sr
- debug: msg="{{ sr.stdout}}"
- set_fact:
rid: "{{ sr.stdout | regex_search('.*ID: (..)') }}"
- debug: msg="{{ rid }}"
Execution:
ansible#Ansible:~$ ansible-playbook pb1.yml
PLAY [fppc] *************************************************************************
TASK [N1] ***************************************************************************
ok: [192.168.250.161]
TASK [debug] ************************************************************************
ok: [192.168.250.161] => {
"msg": [
"banner login ^CID: A4"
]
}
TASK [set_fact] *********************************************************************
fatal: [192.168.250.161]: FAILED! => {"failed": true, "msg": "Unexpected templating type error occurred on ({{ sr.stdout | regex_search('.*ID: (..)') }}): expected string or buffer"}
to retry, use: --limit #/home/ansible/pb1.retry
PLAY RECAP **************************************************************************
192.168.250.161 : ok=2 changed=0 unreachable=0 failed=1
ansible#Ansible:~$

I found the solution:
---
- hosts: fppc
gather_facts: false
remote_user: xyz
connection: local
tasks:
- name: N1
ios_command:
commands:
- sh run
register: sr
- set_fact:
temp: "{{ sr.stdout_lines | join }}"
- set_fact:
rid: "{{ temp | regex_replace('.*ID: (..).*', '\\1') }}"
- debug: msg="{{ rid }}"
Execution:
ansible#Ansible:~$ ansible-playbook pb1.yml
PLAY [fppc] ********************************************************************
TASK [N1] **********************************************************************
ok: [192.168.250.161]
TASK [set_fact] ****************************************************************
ok: [192.168.250.161]
TASK [set_fact] ****************************************************************
ok: [192.168.250.161]
TASK [debug] *******************************************************************
ok: [192.168.250.161] => {
"msg": "A4"
}
PLAY RECAP *********************************************************************
192.168.250.161 : ok=4 changed=0 unreachable=0 failed=0

Other solution, more logical:
---
- hosts: fppc
gather_facts: false
remote_user: xyz
connection: local
tasks:
- name: N1
ios_command:
commands:
- sh run
register: sr
- set_fact:
rid: "{{ sr.stdout | regex_search('(?<=ID:)\\s+\\S+', multiline=True) | trim }}"
- debug: msg="{{ rid }}"
Execution:
ansible#Ansible:~$ ansible-playbook pb1.yml
PLAY [fppc] ********************************************************************
TASK [N1] **********************************************************************
ok: [192.168.250.161]
TASK [set_fact] ****************************************************************
ok: [192.168.250.161]
TASK [debug] *******************************************************************
ok: [192.168.250.161] => {
"msg": "A4"
}
PLAY RECAP *********************************************************************
192.168.250.161 : ok=3 changed=0 unreachable=0 failed=0

Related

Access element of list as dict

I'm trying to access the elements of a list, but whenever I try to access it's elements they are treated as text (see the debug output).
How can I loop over the elements of content[0]?
ansible version: 2.5.1
playbook.yml:
- hosts: localhost
gather_facts: no
vars:
content: []
tasks:
- name: Call the Consul API to get all registered services
uri:
url: "https://{{API_URL}}/v1/health/service/{{item}}?Status=critical"
headers:
Authorization: "Bearer {{TOKEN}}"
method: GET
return_content: yes
status_code: 200
body_format: json
force: yes
register: r
with_items:
- service1
- service2
- set_fact:
content: "{{ lookup('flattened', r | json_query('results[*].content')) }}"
- debug:
msg: "{{ content[0][0] | type_debug }}"
- debug:
msg: "{{ item | type_debug }}"
with_items: "{{ content[0] }}"
debug output:
TASK [debug]
ok: [127.0.0.1] => {
"msg": "dict"
}
TASK [debug]
ok: [127.0.0.1] => (item=None) => {
"msg": "AnsibleUnsafeText"
}
I'm hoping this question and answer will help you. I think the approach you are taking is the problem.

Ansible - Check if string exists in file with regex

I need to validate that the PermitRootLogin parameter is equal to "no", for example:
PermitRootLogin no
But sometimes between these words there is more than one space. For this reason I use a regex, but apparently I do it wrong. This is the line that seems to be bad:
when: check_config.stdout.find('PermitRootLogin\s+no') != -1
Any idea how to fix this?
- hosts: redhat
tasks:
- name: check file
shell: cat /etc/ssh/sshd_config
register: check_config
- name: compare string
when: check_config.stdout.find('PermitRootLogin\s+no') != -1
debug: msg="this server is ok"
Q: "Validate that the PermitRootLogin parameter is equal to no."
A: Put the below declaration into the vars
match_lines: "{{ check_config.stdout_lines|
map('regex_search', '^\\s*PermitRootLogin\\s+no$')|
select }}"
and test the length of the list
- debug:
msg: this server is OK
when: match_lines|length > 0
Example of a complete playbook for testing
- hosts: localhost
vars:
match_lines: "{{ check_config.stdout_lines|
map('regex_search', '^\\s*PermitRootLogin\\s+no$')|
select }}"
tasks:
- command: cat /etc/ssh/sshd_config
register: check_config
- debug:
var: match_lines
- debug:
msg: This server is OK
when: match_lines|length > 0
gives, for example (abridged)
TASK [debug] *******************************************
ok: [localhost] =>
match_lines:
- PermitRootLogin no
TASK [debug] *******************************************
ok: [localhost] =>
msg: This server is OK
Given the inventory below set hosts -hosts: rehat
shell> cat hosts
[redhat]
test_11
test_12
test_13
The playbook gives, for example (abridged)
TASK [debug] *******************************************
ok: [test_11] =>
match_lines:
- PermitRootLogin no
ok: [test_12] =>
match_lines: []
ok: [test_13] =>
match_lines: []
TASK [debug] *******************************************
skipping: [test_12]
ok: [test_11] =>
msg: This server is OK
skipping: [test_13]
You can use lookup to simplify the task if the play is running at the localhost only. For example, the playbook below gives the same result
- hosts: localhost
tasks:
- debug:
msg: This server is OK
when: match_lines|length > 0
vars:
match_lines: "{{ lookup('file', '/etc/ssh/sshd_config').splitlines()|
map('regex_search', '^\\s*PermitRootLogin\\s+no$')|
select }}"
If you want to put/replace the line in the config use lineinfile. For example,
- lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PermitRootLogin(.*)$'
line: 'PermitRootLogin no'

Ansible - how to split a list into two lists?

I searched and tried every way to split a list into two lists.
There were no conventional filters or anything supported.
There were examples and posts about combining lists into one, but not the other way around.
I developed below code but it does not work with very strange reason, list does not have attribute 0?
---
- hosts: localhost
gather_facts: no
vars:
- listA: ['a','b','c','d']
- listB: []
- listC: []
tasks:
- block:
- debug:
var: listA[0]
- debug:
var: listB
- debug:
var: listC
- set_fact:
listB: "{{ listB + [listA[item]] }}"
with_sequence: start=0 end=3 stride=2
- set_fact:
listC: "{{ listC + [listA[item]] }}"
with_sequence: start=1 end=3 stride=2
- block:
- debug:
var: listA
- debug:
var: listB
- debug:
var: listC
This is the test run outcome with Ansible 2.1.1.0
$ ansible-playbook test_sequenceeasy.yml
[WARNING]: log file at '{{planfile | dirname}}/AnsibleLog.txt' is not writeable and we cannot create it, aborting
PLAY [localhost] ***************************************************************
TASK [debug] *******************************************************************
ok: [localhost] => {
"listA[0]": "a"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"listB": []
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"listC": []
}
TASK [set_fact] ****************************************************************
fatal: [localhost]: FAILED! => {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'list object' has no attribute u'0'\n\nThe error appears to have been in '/apps/infra/Tools/Ansible_WLNMiddleware/test_sequenceeasy.yml': line 17, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n var: listC\n - set_fact:\n ^ here\n"}
NO MORE HOSTS LEFT *************************************************************
[WARNING]: Could not create retry file 'test_sequenceeasy.retry'. [Errno 2] No such file or directory: ''
I found the cause.
The problem about the error message "'list object' has no attribute u'0'" was that Ansible is not recognizing 0 as number, but it think 0 is string.
What? How can Ansible iterate start, end and stride and store the value into "String"? - That I don't know.
But the problem solved with below code update:
---
- hosts: localhost
gather_facts: no
vars:
- listA: ['a','b','c','d']
- listB: []
- listC: []
tasks:
- block:
- debug:
var: listA[0]
- debug:
var: listB
- debug:
var: listC
- set_fact:
listB: "{{ listB + [ listA[item|int] ] }}"
with_sequence: start=0 end=3 stride=2
- set_fact:
listC: "{{ listC + [ listA[item|int] ] }}"
with_sequence: start=1 end=3 stride=2
- block:
- debug:
var: listA
- debug:
var: listB
- debug:
var: listC
And the result is:
$ ansible-playbook test_sequenceeasy.yml
[WARNING]: log file at '{{planfile | dirname}}/AnsibleLog.txt' is not writeable and we cannot create it, aborting
PLAY [localhost] ***************************************************************
TASK [debug] *******************************************************************
ok: [localhost] => {
"listA[0]": "a"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"listB": []
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"listC": []
}
TASK [set_fact] ****************************************************************
ok: [localhost] => (item=0)
ok: [localhost] => (item=2)
TASK [set_fact] ****************************************************************
ok: [localhost] => (item=1)
ok: [localhost] => (item=3)
TASK [debug] *******************************************************************
ok: [localhost] => {
"listA": [
"a",
"b",
"c",
"d"
]
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"listB": [
"a",
"c"
]
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"listC": [
"b",
"d"
]
}
PLAY RECAP *********************************************************************
localhost : ok=8 changed=0 unreachable=0 failed=0

AWS provision with ansible

I am getting and error when I want to provision an ec2. This is how i set up my environment.
I put my aws credentials in ~/.boto
cat /etc/ansible/hosts
[local]
localhost
cat /etc/ansible/ec2-vars/testserver.yml
ec2_keypair: "ansible"
ec2_security_group: "sg-*******"
ec2_instance_type: "t2.micro"
ec2_image: "ami-********"
ec2_subnet_ids: ['subnet-*******','subnet-REDACTED','subnet-REDACTED']
ec2_region: "us-east-1"
ec2_tag_Name: "testserver"
ec2_tag_Type: "testserver"
ec2_tag_Environment: "development"
ec2_volume_size: 8
cat /etc/ansible/provision-ec2.yml
---
- hosts: localhost
connection: local
gather_facts: false
user: root
pre_tasks:
- include_vars: ec2_vars/{{type}}.yml
roles:
- provision-ec2
cat /etc/ansible/roles/provision-ec2/tasks/main.yml
---
- name: Provision EC2 Box
local_action:
module: ec2
key_name: "{{ ec2_keypair }}"
group_id: "{{ ec2_security_group }}"
instance_type: "{{ ec2_instance_type }}"
image: "{{ ec2_image }}"
vpc_subnet_id: "{{ ec2_subnet_ids|random }}"
region: "{{ ec2_region }}"
instance_tags: '{"Name":"{{ec2_tag_Name}}","Type":" {{ec2_tag_Type}}","Environment":"{{ec2_tag_Environment}}"}'
assign_public_ip: yes
wait: true
count: 1
volumes:
- device_name: /dev/sda1
device_type: gp2
volume_size: "{{ ec2_volume_size }}"
delete_on_termination: true
register: ec2
- debug: var=item
with_items: ec2.instances
- add_host: name={{ item.public_ip }} >
groups=tag_Type_{{ec2_tag_Type}},tag_Environment_{{ec2_tag_Environment}}
ec2_region={{ec2_region}}
ec2_tag_Name={{ec2_tag_Name}}
ec2_tag_Type={{ec2_tag_Type}}
ec2_tag_Environment={{ec2_tag_Environment}}
ec2_ip_address={{item.public_ip}}
with_items: ec2.instances
- name: Wait for the instances to boot by checking the ssh port
wait_for: host={{item.public_ip}} port=22 delay=60 timeout=320 state=started
with_items: ec2.instances
Now I run the following command and this is what i get.
[root#ip-**-**-*** ansible]# ansible-playbook -vv -i localhost, -e "type=testservers" provision-ec2.yml
Using /etc/ansible/ansible.cfg as config file
PLAYBOOK: provision-ec2.yml ****************************************************
1 plays in provision-ec2.yml
PLAY [localhost] ***************************************************************
TASK [include_vars] ************************************************************
task path: /etc/ansible/provision-ec2.yml:7
fatal: [localhost]: FAILED! => {"changed": false, "failed": true, "file": "/etc/ansible/ec2_vars/testservers.yml", "msg": "Source file not found."}
NO MORE HOSTS LEFT *************************************************************
to retry, use: --limit #provision-ec2.retry
PLAY RECAP *********************************************************************
localhost : ok=0 changed=0 unreachable=0 failed=1
please help.
New error:
TASK [provision-ec2 : Provision EC2 Box] ***************************************
task path: /etc/ansible/roles/provision-ec2/tasks/main.yml:2
fatal: [localhost -> localhost]: FAILED! => {"changed": false, "failed": true, "msg": "No handler was ready to authenticate. 1 handlers were checked. ['HmacAuthV4Handler'] Check your credentials"}
NO MORE HOSTS LEFT *************************************************************
to retry, use: --limit #provision-ec2.retry
PLAY RECAP *********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=1
You are mixing underscore and hyphen.
cat /etc/ansible/ec2-vars/testserver.yml
include_vars: ec2_vars/{{type}}.yml

'ansible_date_time' is undefined

Trying to register an ec2 instance in AWS with Ansible's ec2_ami module, and using current date/time as version (we'll end up making a lot of AMIs in the future).
This is what I have:
- name: Create new AMI
hosts: localhost
connection: local
gather_facts: false
vars:
tasks:
- include_vars: ami_vars.yml
- debug: var=ansible_date_time
- name: Register ec2 instance as AMI
ec2_ami: aws_access_key={{ ec2_access_key }}
aws_secret_key={{ ec2_secret_key }}
instance_id={{ temp_instance.instance_ids[0] }}
region={{ region }}
wait=yes
name={{ ami_name }}
with_items: temp_instance
register: new_ami
From ami_vars.yml:
ami_version: "{{ ansible_date_time.iso8601 }}"
ami_name: ami_test_{{ ami_version }}
When I run the full playbook, I get this error message:
fatal: [localhost]: FAILED! => {"failed": true, "msg": "ERROR! ERROR! ERROR! 'ansible_date_time' is undefined"}
However, when run the debug command separately, from a separate playbook, it works fine:
- name: Test date-time lookup
hosts: localhost
connection: local
tasks:
- include_vars: ami_vars.yml
- debug: msg="ami version is {{ ami_version }}"
- debug: msg="ami name is {{ ami_name }}"
Result:
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "ami version is 2016-02-05T19:32:24Z"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "ami name is ami_test_2016-02-05T19:32:24Z"
}
Any idea what's going on?
Remove this:
gather_facts: false
ansible_date_time is part of the facts and you are not gathering it.
> cat tasks/test.yml
---
- hosts: node
gather_facts: no
tasks:
- setup:
gather_subset:
- min
- name: q
debug: var=ansible_date_time.epoch
and run
> ansible-playbook -i conf/share_var.conf tasks/test.yml --private-key=/root/.ssh/id_rsa -u ${USER} -b --become-method=sudo
PLAY [node] ********************************************************************************************************************************************************************************************************************************
TASK [setup] *******************************************************************************************************************************************************************************************************************************
ok: [xxxx.94.182]
ok: [xxxx.94.183]
ok: [xxxx.94.181]
TASK [q] ***********************************************************************************************************************************************************************************************************************************
ok: [xxxx.94.181] => {
"ansible_date_time.epoch": "1636712223"
}
ok: [xxxx.94.182] => {
"ansible_date_time.epoch": "1636712223"
}
ok: [xxxx.94.183] => {
"ansible_date_time.epoch": "1636712223"
}
PLAY RECAP *********************************************************************************************************************************************************************************************************************************
xxxx.94.181 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
xxxx.94.182 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
xxxx.94.183 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0